import { Expr, GpuFragmentParams, GpuMapSampleUVs } from '../../gpu/contract'; import { RttFilterParams } from '../../gpu/scaffolds/rttFilter'; import { GatherEffect } from '../types'; import { PropRef } from '../values'; /** * A pattern value: something you place in `paint:` or hand to another pattern word, yielding * a color or a mask per pixel. */ export type PatternPaint = (params: GpuFragmentParams) => Expr; /** What a pattern slot accepts: a prop `p('name')` or another pattern value. */ export type PaintSlot = PropRef | PatternPaint; /** * Which way a lattice's rows and rotation run. * * `'flippedY'` counts rows up from the bottom and rotates counter-clockwise (grids, * triangles). `'clockwise'` counts rows down from the top and rotates clockwise (hexagons, * truchet, cubes). `'plain'` counts down from the top and rotates counter-clockwise (weave). * Use the one named in the line word's example; the others still work but shift the look. */ export type CellFrameConvention = 'flippedY' | 'clockwise' | 'plain'; /** * The shared coordinate system of a tiled pattern: how many cells fit down the canvas * height and how far the whole lattice is rotated. * * `cells` counts cells along the canvas height, so cells stay square as the canvas resizes. * `rotation` is in degrees about the canvas centre. Pass the result as the `frame` of * `gridLines`, `hexLines`, `triangleLines`, `truchetArcs`, `weaveThreads` or `isoCubeFaces`. * * @example * ```ts * const field = gridLines({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'flippedY'}), thickness: p('thickness'), softness: p('softness'), variation: p('variation')}) * ``` * @tip One frame can feed several line words. It is evaluated once however many read it. * @see gridLines, hexLines, triangleLines, truchetArcs, weaveThreads, isoCubeFaces */ export declare function cellFrame(slots: { cells: PropRef; rotation: PropRef; convention: CellFrameConvention; }): PatternPaint; /** * A color lightened or darkened per cell by a shade factor, alpha untouched. * * `factor` is the `shade` output of a lattice word: 1 keeps the color, above 1 brightens, * below 1 darkens. Use it on the cell fill so every tile reads slightly different. * * @example * ```ts * paint: strokeOver({fill: vary(p('cellColor'), field.shade), stroke: p('color'), mask: field.lines, space: p('colorSpace')}) * ``` * @see gridLines, hexLines, brickCourses, strokeOver */ export declare function vary(color: PaintSlot, factor: PaintSlot): PatternPaint; /** * Two colors mixed through a mask: `fill` where the mask is 0, `stroke` where it is 1. * * The everyday way to color a pattern. `space` is a color-space prop (`'linear'`, `'oklch'`, * `'oklab'`, `'hsl'`, `'hsv'`, `'lch'`); leave it out for a linear mix. Alpha interpolates * too, so a transparent fill gives a lines-only pattern. * * @example * ```ts * paint: strokeOver({fill: p('colorA'), stroke: p('colorB'), mask: checkerCells({cells: p('cells'), softness: p('softness')}), space: p('colorSpace')}) * ``` * @tip The `space` prop must be `compileTime: true`. Changing it recompiles the shader. * @see withAlpha, mixOf, vary */ export declare function strokeOver(layers: { fill: PaintSlot; stroke: PaintSlot; mask: PaintSlot; space?: PropRef; }): PatternPaint; /** * Makes map-driven props change per whole cell instead of per pixel, so a mapped dot size or * line thickness grows cell by cell rather than being cut off mid-cell. * * Set it on the definition's `mapSampleUVs` field, not in `paint:`. Give it the same `cells` * count and `rotation` (degrees) the pattern uses so the snapping matches the lattice. * `props` lists the prop names to snap. * * @example * ```ts * mapSampleUVs: sampleMapsAtCellCentres({cells: p('cells'), rotation: p('rotation'), props: ['thickness', 'softness']}) * ``` * @tip Only matters when a prop is driven by a map (an image or another layer). Plain values are unaffected. * @see cellFrame, dotLattice, gridLines */ export declare function sampleMapsAtCellCentres(slots: { cells: PropRef; rotation?: PropRef; props: string[]; }): GpuMapSampleUVs; /** * One random point in each cell of a square grid: the classic scatter for glitter, stars, * dust and sparkles. * * `coord` is the pixel's position in any unit (CSS pixels via `uv × logicalViewportSize` * keeps the spacing steady across screens); `cellSize` is the grid spacing in that unit. * `jitter` is how far the point wanders from the cell's centre, 0 (dead centre) to 1 (anywhere * in the cell). `seed` re-rolls every point. Returns the cell's `point` and this pixel's * `offset` from it (both in `coord`'s unit), plus `random`, three independent 0–1 values for * the cell (`.x` and `.y` already place the point; use `.z` and the others to vary brightness, * timing or size). * * @example * ```ts * const {offset, random} = scatterPoint(px, {cellSize: 30, jitter: 0.6, seed: params.uniforms.seed}) * ``` * @tip A pixel only sees its own cell's point, so keep anything drawn around it smaller than * half a cell or it gets clipped at the cell edge. Use `scatterPoints` for larger shapes. * @see scatterPoints, cellFrame, pointStars */ export declare function scatterPoint(coord: Expr, opts: ScatterOptions): ScatteredPoint; /** * The scattered points of the four grid cells nearest the pixel, so anything drawn up to half * a cell from its point shows whole, never clipped at a cell edge. * * Same options and same points as `scatterPoint` (one random point per cell); returns four of * them instead of one. Draw something around each and add the results. Costs four times * `scatterPoint`. * * @example * ```ts * const glints = scatterPoints(px, {cellSize: 60, jitter: 0.6, seed: params.uniforms.seed}) * .map(({offset}) => starGlint(offset, {core: 0.9, rayLength: 0.1, rayWidth: 1.6, rays: 0.25, reach: 30})) * ``` * @tip Pair with `starGlint`'s `reach` set to half the cell size, so a glint has faded out * before it could reach a cell this pixel doesn't look at. * @see scatterPoint, starGlint */ export declare function scatterPoints(coord: Expr, opts: ScatterOptions): ScatteredPoint[]; /** What `scatterPoint` and `scatterPoints` take. */ export interface ScatterOptions { cellSize: Expr | number; jitter: Expr | number; seed: Expr | number; } /** One scattered point: where it sits, the pixel's offset from it, and three random 0–1 values for its cell. */ export interface ScatteredPoint { point: Expr; offset: Expr; random: Expr; } /** * A color with its alpha replaced by a separately built mask. * * The usual way to hang a pattern under one color: the mask becomes the coverage and the * color's own alpha is dropped. * * @example * ```ts * paint: withAlpha(p('color'), dotLattice({density: p('density'), dotSize: p('dotSize'), offset: p('offset'), speedVariance: p('speedVariance'), twinkle: p('twinkle')})) * ``` * @tip To keep the color's own alpha as well, multiply it in: `withAlpha(color, times(alphaOf(color), mask))`. * @see alphaOf, times, opaque */ export declare function withAlpha(color: PaintSlot, alpha: PaintSlot): PatternPaint; /** * The alpha channel of a color, as a number per pixel. * * @example * ```ts * paint: withAlpha(streakColor, times(alphaOf(streakColor), streaks.mask)) * ``` * @see rgbOf, withAlpha */ export declare function alphaOf(color: PaintSlot): PatternPaint; /** * The RGB channels of a color, without its alpha. * * Finish it with `opaque` or `withAlpha` to make a color again. * * @example * ```ts * paint: opaque(mixOf(times(rgbOf(cubeColor), faces.tone), rgbOf(p('lineColor')), faces.wire)) * ``` * @see alphaOf, opaque */ export declare function rgbOf(color: PaintSlot): PatternPaint; /** * The product of two values: a mask scaled by a prop, an RGB dimmed by a shade, two masks * combined. * * @example * ```ts * mask: times(faces.random, p('colorVariation')) * ``` * @see mixOf, vary */ export declare function times(a: PaintSlot, b: PaintSlot): PatternPaint; /** * A straight blend from one value to another by an amount from 0 to 1. * * Works on colors, RGB and single numbers alike, channel by channel with no color-space * handling. For a color mix in a chosen color space use `strokeOver`. * * @example * ```ts * mixOf(alphaOf(p('colorA')), alphaOf(p('colorB')), bands) * ``` * @see strokeOver, times */ export declare function mixOf(from: PaintSlot, to: PaintSlot, amount: PaintSlot): PatternPaint; /** * An RGB value finished as a fully opaque color. * * @example * ```ts * paint: opaque(mixOf(times(rgbOf(cubeColor), faces.tone), rgbOf(p('lineColor')), faces.wire)) * ``` * @see rgbOf, withAlpha */ export declare function opaque(rgb: PaintSlot): PatternPaint; /** * A checkerboard mask: 1 on one set of squares, 0 on the other, with clean edges at any size. * * `cells` counts squares along the canvas height (squares stay square as the canvas * resizes). `softness` 0–1 blurs the edges; 0 is crisp. Color it with `strokeOver`. * * @example * ```ts * paint: strokeOver({fill: p('colorA'), stroke: p('colorB'), mask: checkerCells({cells: p('cells'), softness: p('softness')}), space: p('colorSpace')}) * ``` * @tip Stays sharp inside a distortion, which makes it a good test pattern for warps. * @see stripeBands, gridLines, strokeOver */ export declare function checkerCells(slots: { cells: PropRef; softness: PropRef; }): PatternPaint; /** * A mask of straight parallel stripes that scroll with the layer's clock. * * `angle` is in degrees. `density` is the number of stripe pairs across the canvas height. * `balance` 0–1 is how much of each pair is the 0 side (the fill in `strokeOver`). * `softness` 0–1 blurs the edges. `offset` shifts the phase; 1 is one whole pair. Declare * `animatedTime: {speed: 'speed'}` on the definition; speed 0 holds the stripes still. * * @example * ```ts * paint: strokeOver({fill: p('colorA'), stroke: p('colorB'), mask: stripeBands({angle: p('angle'), density: p('density'), balance: p('balance'), softness: p('softness'), offset: p('offset')}), space: p('colorSpace')}) * ``` * @see zigzagBands, checkerCells, ringWaves */ export declare function stripeBands(slots: { angle: PropRef; density: PropRef; balance: PropRef; softness: PropRef; offset: PropRef; }): PatternPaint; /** * A mask of chevron (zigzag) stripes that scroll with the layer's clock. * * `count` is the number of stripe pairs across the canvas. `angle` is in degrees. `balance` * 0–1 is how much of each pair is the 0 side. `softness` 0–1 blurs the edges. `offset` shifts * the phase; 1 is one whole pair. Declare `animatedTime: {speed: 'speed'}` on the definition. * * @example * ```ts * const bands = zigzagBands({count: p('count'), angle: p('angle'), balance: p('balance'), softness: p('softness'), offset: p('offset')}) * ``` * @tip Reuse one `bands` value for both the color mix and an alpha mix. It is evaluated once. * @see stripeBands, checkerCells */ export declare function zigzagBands(slots: { count: PropRef; angle: PropRef; balance: PropRef; softness: PropRef; offset: PropRef; }): PatternPaint; /** * A mask of concentric rings spreading out from a point, animated by the layer's clock. * * `center` is a position prop. `frequency` sets how tightly the rings pack; higher is more * rings. `thickness` 0–1 is how much of each ring period is ring (0.5 is even bands, 1 is * solid). `softness` 0–3 blurs the ring edges. `phase` is in radians. Declare * `animatedTime: {speed: 'speed'}` on the definition; positive speed moves the rings outward. * * @example * ```ts * paint: strokeOver({fill: p('colorB'), stroke: p('colorA'), mask: ringWaves({center: p('center'), frequency: p('frequency'), thickness: p('thickness'), softness: p('softness'), phase: p('phase')})}) * ``` * @tip Keep `softness` above 0. At exactly 0 the edge is an undefined hard step rather than a crisp one. * @see stripeBands, dotLattice */ export declare function ringWaves(slots: { center: PropRef; frequency: PropRef; thickness: PropRef; softness: PropRef; phase: PropRef; }): PatternPaint; /** * Streaks that fall across the canvas in columns, each column at its own random speed. * * Returns two values: `mask` is the streak coverage, and `fade` runs from 0 at the tail to 1 * at the leading edge, for a color ramp along each streak. `angle` is in degrees (90 falls * down, 0 moves right). `density` is the number of columns across the canvas. * `speedVariance` 0–1 spreads the per-column speeds. `trailLength` 0–1 is the streak length * as a fraction of the spacing. `strokeWidth` 0–1 is the width as a fraction of a column. * `rounding` 0–1 rounds the leading cap. `balance` 0–1 moves the midpoint of `fade`. Declare * `animatedTime: {speed: 'speed'}` on the definition. * * @example * ```ts * const streaks = fallingStreaks({angle: p('angle'), density: p('density'), speedVariance: p('speedVariance'), trailLength: p('trailLength'), strokeWidth: p('strokeWidth'), rounding: p('rounding'), balance: p('balance')}) * const streakColor = strokeOver({fill: p('trailColor'), stroke: p('leadColor'), mask: streaks.fade, space: p('colorSpace')}) * // paint: withAlpha(streakColor, times(alphaOf(streakColor), streaks.mask)) * ``` * @see stripeBands, dotLattice, withAlpha */ export declare function fallingStreaks(slots: { angle: PropRef; density: PropRef; speedVariance: PropRef; trailLength: PropRef; strokeWidth: PropRef; rounding: PropRef; balance: PropRef; }): { mask: PatternPaint; fade: PatternPaint; }; /** * A mask of round dots on a square grid, with optional row stagger, drift and twinkle. * * `density` counts dots along the canvas height. `dotSize` 0–1 is the dot diameter as a * fraction of a cell; 1 touches the neighbours. `offset` 0–1 shifts every other row (0.5 is * the polka-dot stagger). `speedVariance` 0–1 gives rows different drift speeds. `twinkle` * 0–1 pulses each dot on its own phase. Declare `animatedTime: {speed: 'speed'}` on the * definition; the drift follows that clock while the twinkle keeps running at speed 0. * * @example * ```ts * paint: withAlpha(p('color'), dotLattice({density: p('density'), dotSize: p('dotSize'), offset: p('offset'), speedVariance: p('speedVariance'), twinkle: p('twinkle')})) * ``` * @tip Add `sampleMapsAtCellCentres` when `dotSize` or `twinkle` is map-driven, so dots grow whole instead of being clipped. * @see sampleMapsAtCellCentres, gridLines, ringWaves */ export declare function dotLattice(slots: { density: PropRef; dotSize: PropRef; offset: PropRef; speedVariance: PropRef; twinkle: PropRef; }): PatternPaint; /** * Square grid lines drawn in a `cellFrame`, plus a per-cell shade for the fill. * * Returns `lines` (1 on a line, 0 inside a cell) and `shade` (a brightness factor around 1 * for `vary`). `thickness` 1 draws lines about 2% of a cell wide; 0 draws none. `softness` * 0–1 blurs the lines. `variation` 0–1 sets how far `shade` strays from 1. Draw it with the * `'flippedY'` convention. * * @example * ```ts * const field = gridLines({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'flippedY'}), thickness: p('thickness'), softness: p('softness'), variation: p('variation')}) * // paint: strokeOver({fill: vary(p('cellColor'), field.shade), stroke: p('color'), mask: field.lines, space: p('colorSpace')}) * ``` * @tip Rotate the frame 45 degrees for a diamond crosshatch. * @see cellFrame, hexLines, triangleLines, vary */ export declare function gridLines(slots: { frame: PatternPaint; thickness: PropRef; softness: PropRef; variation: PropRef; }): { lines: PatternPaint; shade: PatternPaint; }; /** * Honeycomb lines (pointy-top hexagons) drawn in a `cellFrame`, plus a per-cell shade. * * Returns `lines` (1 on a line) and `shade` (a brightness factor around 1 for `vary`). * `thickness` 1 draws lines about 2% of a cell wide; 0 draws none. `softness` 0–1 blurs the * lines. `variation` 0–1 sets how far `shade` strays from 1. Draw it with the `'clockwise'` * convention. * * @example * ```ts * const field = hexLines({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'clockwise'}), thickness: p('thickness'), softness: p('softness'), variation: p('variation')}) * ``` * @see cellFrame, gridLines, isoCubeFaces, vary */ export declare function hexLines(slots: { frame: PatternPaint; thickness: PropRef; softness: PropRef; variation: PropRef; }): { lines: PatternPaint; shade: PatternPaint; }; /** * A lattice of equilateral triangles drawn in a `cellFrame`, with rows that can drift. * * Returns `lines` (1 on a line) and `shade` (a brightness factor around 1 per triangle for * `vary`). `thickness` 1 draws lines about 4% of a cell wide; 0 draws none. `softness` 0–1 * blurs the lines. `variation` 0–1 sets how far `shade` strays from 1. `speedVariance` 0–1 * gives rows different drift speeds. Declare `animatedTime: {speed: 'speed'}` on the * definition; speed 0 holds still. Draw it with the `'flippedY'` convention. * * @example * ```ts * const field = triangleLines({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'flippedY'}), thickness: p('thickness'), softness: p('softness'), variation: p('variation'), speedVariance: p('speedVariance')}) * ``` * @see cellFrame, gridLines, hexLines, vary */ export declare function triangleLines(slots: { frame: PatternPaint; thickness: PropRef; softness: PropRef; variation: PropRef; speedVariance: PropRef; }): { lines: PatternPaint; shade: PatternPaint; }; /** * A brick wall: staggered rows with mortar gaps, optional rotation and per-row drift. * * Returns `bricks` (1 on a brick, 0 in the mortar) and `shade` (a brightness factor around 1 * per brick for `vary`). `cellsX` is bricks per row across the canvas width and `cellsY` the * number of rows down its height. `mortar` 0–1 widens the gaps (1 is 30% of a brick), equal * in pixels both ways. `softness` 0–1 blurs the edges. `variation` 0–1 sets how far `shade` * strays from 1. `rotation` is in degrees. `offset` slides the rows; 1 is one brick. * `speedVariance` 0–1 and `seed` randomise the per-row drift. Declare * `animatedTime: {speed: 'speed'}` on the definition. It brings its own frame, so there is * no `frame` slot. * * @example * ```ts * const field = brickCourses({cellsX: p('cellsX'), cellsY: p('cellsY'), mortar: p('mortar'), softness: p('softness'), variation: p('variation'), rotation: p('rotation'), offset: p('offset'), speedVariance: p('speedVariance'), seed: p('seed')}) * // paint: strokeOver({fill: p('colorMortar'), stroke: vary(p('colorBrick'), field.shade), mask: field.bricks, space: p('colorSpace')}) * ``` * @see gridLines, cellFrame, vary */ export declare function brickCourses(slots: { cellsX: PropRef; cellsY: PropRef; mortar: PropRef; softness: PropRef; variation: PropRef; rotation: PropRef; offset: PropRef; speedVariance: PropRef; seed: PropRef; }): { bricks: PatternPaint; shade: PatternPaint; }; /** * A maze of quarter-circle arcs, two per tile, flipped at random so they join into flowing * curves. * * Returns the arc mask (1 on an arc). `thickness` 2 draws arcs about 2% of a tile wide; 0 * draws none. `softness` 0–1 blurs the edges. `seed` picks a different set of flips. Draw it * in a `'clockwise'` `cellFrame`. * * @example * ```ts * paint: strokeOver({fill: p('colorA'), stroke: p('colorB'), mask: truchetArcs({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'clockwise'}), thickness: p('thickness'), softness: p('softness'), seed: p('seed')}), space: p('colorSpace')}) * ``` * @see cellFrame, gridLines, weaveThreads */ export declare function truchetArcs(slots: { frame: PatternPaint; thickness: PropRef; softness: PropRef; seed: PropRef; }): PatternPaint; /** * Two sets of threads woven over and under each other, returned as a finished color. * * `gap` 0–0.5 is the empty margin on each side of a thread, as a fraction of a cell; 0 packs * them tight. `colors` is `[horizontal, vertical]`. The gaps are transparent, so this goes * straight into `paint:`. Draw it in a `'plain'` `cellFrame`. * * @example * ```ts * paint: weaveThreads({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'plain'}), gap: p('gap'), colors: [p('colorA'), p('colorB')]}) * ``` * @see cellFrame, gridLines, truchetArcs */ export declare function weaveThreads(slots: { frame: PatternPaint; gap: PropRef; /** `[horizontal, vertical]` thread colors. */ colors: [PropRef, PropRef]; }): PatternPaint; /** * Tumbling blocks: three shaded rhombus faces per hexagon that read as a field of 3D cubes. * * Returns three values. `tone` is the face shading (1 on top, 0.74 on the right, 0.5 on the * left) to multiply into the cube color. `random` is a 0–1 value per cube for varying cube * colors. `wire` is the edge-line mask (1 on an edge). `thickness` 1 draws edges about 4% of * a cell wide; 0 draws none. `softness` 0–1 blurs them. Draw it in a `'clockwise'` * `cellFrame`. * * @example * ```ts * const faces = isoCubeFaces({frame: cellFrame({cells: p('cells'), rotation: p('rotation'), convention: 'clockwise'}), thickness: p('thickness'), softness: p('softness')}) * // paint: opaque(mixOf(times(rgbOf(cubeColor), faces.tone), rgbOf(p('lineColor')), faces.wire)) * ``` * @see cellFrame, hexLines, times, opaque */ export declare function isoCubeFaces(slots: { frame: PatternPaint; thickness: PropRef; softness: PropRef; }): { random: PatternPaint; tone: PatternPaint; wire: PatternPaint; }; /** * The dot coverage of one halftone screen: 1 inside a dot, 0 between, with the dot size set * by an ink amount. * * A raw building block for a custom press inside a gather `build`. `uv` is the pixel's uv * and `aspect` the canvas aspect (`ctx.uv`, `ctx.aspect`). `angle` is the screen angle in * degrees. `intensity` 0–1 is the ink amount at this pixel; 0 leaves no dot. `frequency` is * the number of dots down the canvas height. * * @example * ```ts * const dots = dotScreenMask(ctx.uv, ctx.aspect, uniforms.angle, intensity, uniforms.frequency) * ``` * @see inkTransmission, cmykPress, dotScreen */ export declare function dotScreenMask(uv: Expr, aspect: Expr, angle: Expr, intensity: Expr, frequency: Expr): Expr; /** * How much light passes one ink plate: white where the dot mask is 0, the ink color where * it is 1. * * Returns RGB. Multiply the plates together over a paper color to lay the inks down in * order. The ink's alpha scales its strength. * * @example * ```ts * printed = printed.mul(inkTransmission(uniforms.cyanColor, dotScreenMask(ctx.uv, ctx.aspect, uniforms.cyanAngle, cyan, uniforms.frequency))) * ``` * @see dotScreenMask, cmykPress */ export declare function inkTransmission(inkColor: Expr, inkMask: Expr): Expr; /** * A classic halftone filter: the layer inside it redrawn as a grid of dots that grow where * it is bright. * * Goes in `effect:`. `angle` is the screen angle in degrees (45 is the print default). * `frequency` is the number of dots down the canvas height. The dots keep the child's own * color; between dots the output is transparent. * * @example * ```ts * effect: dotScreen({angle: p('angle'), frequency: p('frequency')}) * ``` * @see cmykPress, chosenBy, quantise */ export declare function dotScreen(slots: { angle: PropRef; frequency: PropRef; }): GatherEffect; /** * One ink plate of a `cmykPress`: which channel it prints, its screen-angle prop (degrees) * and its ink-color prop. */ export interface InkPlateSpec { readonly channel: 'cyan' | 'magenta' | 'yellow' | 'black'; readonly screenAngle: PropRef; readonly ink: PropRef; } /** * Declares one ink plate for `cmykPress`. * * `channel` is `'cyan'`, `'magenta'`, `'yellow'` or `'black'`. `screenAngle` is an angle prop * in degrees and `ink` a color prop. Plates print in the order you list them. * * @example * ```ts * inkPlate({channel: 'cyan', screenAngle: p('cyanAngle'), ink: p('cyanColor')}) * ``` * @see cmykPress */ export declare function inkPlate(spec: InkPlateSpec): InkPlateSpec; /** * A four-color print filter: the layer inside it separated into ink plates, each screened * into dots at its own angle and laid down on paper in order. * * Goes in `effect:`. `paper` is the color shown where no ink lands. `frequency` is the number * of dots down the canvas height. `misprint` offsets each plate in uv (0 is perfect * registration, 0.005 is visible fringing), in a direction that turns a quarter turn per * plate starting from `misprintAngle` (degrees). `plates` is a list from `inkPlate`; the * standard screen angles are cyan 15, magenta 75, yellow 0, black 45. The result keeps the * child's alpha. * * @example * ```ts * effect: cmykPress({paper: p('paperColor'), frequency: p('frequency'), misprint: p('misprint'), misprintAngle: p('misprintAngle'), plates: [inkPlate({channel: 'cyan', screenAngle: p('cyanAngle'), ink: p('cyanColor')}), inkPlate({channel: 'black', screenAngle: p('blackAngle'), ink: p('blackColor')})]}) * ``` * @tip Any subset of the four plates works. Two plates give a duotone or risograph look. * @see inkPlate, dotScreen, dotScreenMask, inkTransmission */ export declare function cmykPress(slots: { paper: PropRef; frequency: PropRef; misprint: PropRef; misprintAngle: PropRef; plates: InkPlateSpec[]; }): GatherEffect; /** * Picks one whole effect recipe from a select prop, decided when the shader compiles. * * `prop` must be a `compileTime: true` prop. `read` turns its raw value into one of the keys * of `recipes`; accept both the option string and its transformed value. Every recipe must * be a gather effect with the same alpha handling and no setup step, or this throws as soon * as it is called. * * @example * ```ts * effect: chosenBy(p('style'), (raw) => (raw === 'cmyk' || raw === 1 ? 'cmyk' : 'classic'), {classic: dotScreen({angle: p('angle'), frequency: p('frequency')}), cmyk: cmykPress({paper: p('paperColor'), frequency: p('frequency'), misprint: p('misprint'), misprintAngle: p('misprintAngle'), plates})}) * ``` * @tip Changing the prop recompiles the shader, which is the point: each style pays only for its own code. * @see dotScreen, cmykPress */ export declare function chosenBy(prop: PropRef, read: (raw: unknown) => K, recipes: Record): GatherEffect; /** A value computed per pixel from the layer inside a gather effect, such as a dither level. */ export type GatherStage = (params: RttFilterParams) => Expr; /** * The pixel grid a dither works on, from `pixelGrid`: the cell `size` prop, the cell * coordinate `coord`, and `source`, the child's color sampled once per cell. */ export interface PixelGrid { readonly size: PropRef; readonly coord: GatherStage; readonly source: GatherStage; } /** * The pixel grid of a dither: the layer inside it chopped into square cells of a given size. * * `size` is a prop in pixels of the authored frame, so the cell count stays the same when the * canvas renders at a higher resolution. Build it once and pass the same grid to `quantise` * and `ditherInks`. * * @example * ```ts * const grid = pixelGrid({size: p('pixelSize')}) * ``` * @see quantise, ditherInks */ export declare function pixelGrid(slots: { size: PropRef; }): PixelGrid; /** @internal */ export declare function orderedThreshold(pattern: number, coord: Expr): Expr; /** * Reduces each grid cell of the layer inside to 0 or 1 using a dither pattern. * * Returns a per-pixel level for `ditherInks`. `pattern` is a `compileTime: true` select prop * with one of `bayer2`, `bayer4`, `bayer8`, `clusteredDot`, `blueNoise`, `whiteNoise` or * `floydSteinberg`. `threshold` 0–1 shifts the cut point; 0.5 is neutral. `spread` 0–1 is * how much of the brightness range dithers; lower leaves more solid areas. * * @example * ```ts * const levels = quantise({grid, pattern: p('pattern'), threshold: p('threshold'), spread: p('spread')}) * ``` * @tip Floyd–Steinberg is the costliest pattern: it re-reads 64 cells per pixel. Bayer 4 is the cheap default. * @see pixelGrid, ditherInks */ export declare function quantise(slots: { grid: PixelGrid; pattern: PropRef; threshold: PropRef; spread: PropRef; }): GatherStage; /** * A dither filter: colors the 0/1 levels from `quantise`, either with two colors of your own * or with darkened and brightened versions of the layer's own pixels. * * Goes in `effect:`. `mode` is a `compileTime: true` select prop, `'custom'` or `'source'`. * `colors` is `[dark, light]` for custom mode; a transparent dark color lets the background * show through. * * @example * ```ts * effect: ditherInks({grid, levels: quantise({grid, pattern: p('pattern'), threshold: p('threshold'), spread: p('spread')}), mode: p('colorMode'), colors: [p('colorA'), p('colorB')]}) * ``` * @see pixelGrid, quantise, dotScreen */ export declare function ditherInks(slots: { grid: PixelGrid; levels: GatherStage; mode: PropRef; colors: [PropRef, PropRef]; }): GatherEffect; //# sourceMappingURL=patterns.d.ts.map