import { d } from '../kit'; import { KitComputePipeline } from '../compute'; import { TgpuRoot } from 'typegpu'; /** A 2D-dispatched cell kernel over a grid. */ export type GridKernel = (cx: number, cy: number) => void; /** * One kernel as a guarded compute pass. The general form of `createFluidKernelPass`: `size` is * optional (a dynamically-dispatched pass passes none and drives `dispatchThreads` itself), and * non-square grids are allowed. */ export declare function createGridKernelPass(root: TgpuRoot, kernel: GridKernel, opts?: { size?: [number, number]; bindGroup?: unknown; }): KitComputePipeline; /** * Per-cell drive from a sampled texture (the "style map"): the texture's luminance — shaped by * contrast/threshold/invert and weighted by alpha coverage — shifts the reaction's operating point * per cell. Ranges clamp the shifted point inside the caller's stable band. */ export interface ReactionDriveOptions { /** Contrast slider 0..1 → luma gain 1..(1+contrastMax). */ contrastMax: number; /** Max feed shift the drive can apply. */ dFeed: number; /** Max kill shift the drive can apply. */ dKill: number; feedMin: number; feedMax: number; killMin: number; killMax: number; } export interface GrayScottOptions { /** Grid resolution per axis (the kernel is dispatched 2D over n×n). */ n: number; namePrefix: string; /** Spatially bias feed/kill from a sampled drive texture (adds `driveTex` to the layout). */ drive?: ReactionDriveOptions; } declare const grayScottParamsSchema: () => d.WgslStruct<{ feed: d.F32; kill: d.F32; dv: d.F32; brushRadSq: d.F32; brushStrength: d.F32; cursorX: d.F32; cursorY: d.F32; cursorActive: d.F32; driveInfluence: d.F32; driveContrast: d.F32; driveThreshold: d.F32; driveInvert: d.F32; driveMapX: d.F32; driveMapY: d.F32; _pad0: d.F32; _pad1: d.F32; }>; type GrayScottParamsSchema = ReturnType; declare const makeGrayScottPlainLayout: (n: number, Params: GrayScottParamsSchema) => import('typegpu').TgpuBindGroupLayout<{ readBuf: { storage: d.WgslArray; access: "readonly"; }; writeBuf: { storage: d.WgslArray; access: "mutable"; }; params: { uniform: d.WgslStruct<{ feed: d.F32; kill: d.F32; dv: d.F32; brushRadSq: d.F32; brushStrength: d.F32; cursorX: d.F32; cursorY: d.F32; cursorActive: d.F32; driveInfluence: d.F32; driveContrast: d.F32; driveThreshold: d.F32; driveInvert: d.F32; driveMapX: d.F32; driveMapY: d.F32; _pad0: d.F32; _pad1: d.F32; }>; }; }>; declare const makeGrayScottDriveLayout: (n: number, Params: GrayScottParamsSchema) => import('typegpu').TgpuBindGroupLayout<{ readBuf: { storage: d.WgslArray; access: "readonly"; }; writeBuf: { storage: d.WgslArray; access: "mutable"; }; params: { uniform: d.WgslStruct<{ feed: d.F32; kill: d.F32; dv: d.F32; brushRadSq: d.F32; brushStrength: d.F32; cursorX: d.F32; cursorY: d.F32; cursorActive: d.F32; driveInfluence: d.F32; driveContrast: d.F32; driveThreshold: d.F32; driveInvert: d.F32; driveMapX: d.F32; driveMapY: d.F32; _pad0: d.F32; _pad1: d.F32; }>; }; driveTex: { texture: d.WgslTexture2d; }; }>; export type GrayScottPlainLayout = ReturnType; export type GrayScottDriveLayout = ReturnType; /** * The Gray-Scott reaction + brush-injection step over a vec2f (U,V) cell state. * * 9-point weighted Laplacian (0.2 orthogonal, 0.05 diagonal, −1 centre) with reflective NO-FLUX * boundaries via clamp-to-edge neighbour fetch. Du folds to 1 (the stability ceiling for this * explicit scheme), dt folds to 1 (evolution speed is the per-frame iteration count); Dv arrives * as the `dv` uniform. A soft Gaussian brush ADDS V around the cursor while `cursorActive > 0` * (a uniform → coherent branch, no divergence). With `drive`, the drive texture's shaped luminance * shifts feed up / kill down along the density axis per cell. * * The uniform struct is written IN FULL each frame (16 f32 — trailing pads keep it at a multiple * of 16 bytes). The drive members are dead-but-present in the driveless variant so one write path * serves both. */ export declare function buildGrayScottStep(opts: GrayScottOptions & { drive: ReactionDriveOptions; }): { layout: GrayScottDriveLayout; Params: GrayScottParamsSchema; kernel: GridKernel; }; export declare function buildGrayScottStep(opts: GrayScottOptions & { drive?: undefined; }): { layout: GrayScottPlainLayout; Params: GrayScottParamsSchema; kernel: GridKernel; }; /** * Scatter seed for a vec2f (U,V) cell state: U=1 everywhere, a hash-scattered V=1 seed at * `density`. Integer bitcast hash — cell coords reach large-grid extents, where the classic * sin-fract hash streaks on iOS Metal. */ export declare function buildScatterSeedKernel(opts: { n: number; density: number; namePrefix: string; }): { layout: import('typegpu').TgpuBindGroupLayout<{ stateBuf: { storage: d.WgslArray; access: "mutable"; }; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; }; /** Publish a vec2f cell state into a sampled texture (`.rg` = the pair) the fragment reads. */ export declare function buildPairPublishKernel(opts: { n: number; format: 'rgba16float' | 'rgba32float'; namePrefix: string; }): { layout: import('typegpu').TgpuBindGroupLayout<{ srcBuf: { storage: d.WgslArray; access: "readonly"; }; outTex: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; }; /** * Aspect-corrected radial brush weight over an n-cell grid: 1 at the cursor centre → 0 past the * radius, with `falloff` softening the edge. Memoized per grid size (one WGSL fn per n). */ export declare function makeAspectBrushWeight(n: number): import('typegpu').TgpuFn<(cxf: d.F32, cyf: d.F32, mouseX: d.F32, mouseY: d.F32, radius: d.F32, falloff: d.F32, aspect: d.F32) => d.F32>; export interface OddEvenSortOptions { /** Grid resolution per axis. */ n: number; format: 'rgba16float' | 'rgba32float'; namePrefix: string; /** Sort along the vertical axis (columns) instead of horizontal (rows). */ vertical: boolean; /** Sort order along the axis: +1 ascending key, −1 descending. */ direction: 1 | -1; } /** * The odd-even transposition sort kernel set over a persistent per-cell DISPLACEMENT map. * * State is a per-cell f32 offset from identity along the sort axis (so `decay` can melt cells back * home); the sort key is cached once per frame by the `key` prepass (input luminance, unpremultiplied) * and lerped at fractional coordinates (luma is linear in RGB → lerp-of-luma == luma-of-lerp). Each * compare-swap pass alternates parity; both members of a pair derive the same exchange decision from * the same two cached keys → lock-free consistent swap. Swaps are gated by an aspect-corrected brush * around the cursor, dithered per cell for a soft edge. The publish kernel writes the normalised * source coordinate along the axis into the state texture the fragment remaps with. */ export declare function buildOddEvenSortSet(opts: OddEvenSortOptions): { lumaLayout: import('typegpu').TgpuBindGroupLayout<{ input: { texture: d.WgslTexture2d; }; lumaBuf: { storage: d.WgslArray; access: "mutable"; }; params: { uniform: d.WgslStruct<{ inputWidth: d.F32; inputHeight: d.F32; }>; }; }>; LumaParams: d.WgslStruct<{ inputWidth: d.F32; inputHeight: d.F32; }>; swapLayout: import('typegpu').TgpuBindGroupLayout<{ readBuf: { storage: d.WgslArray; access: "readonly"; }; writeBuf: { storage: d.WgslArray; access: "mutable"; }; lumaBuf: { storage: d.WgslArray; access: "readonly"; }; params: { uniform: d.WgslStruct<{ mouseX: d.F32; mouseY: d.F32; radius: d.F32; falloff: d.F32; decay: d.F32; aspect: d.F32; seed: d.F32; }>; }; }>; SwapParams: d.WgslStruct<{ mouseX: d.F32; mouseY: d.F32; radius: d.F32; falloff: d.F32; decay: d.F32; aspect: d.F32; seed: d.F32; }>; outputLayout: import('typegpu').TgpuBindGroupLayout<{ srcBuf: { storage: d.WgslArray; access: "readonly"; }; stateTex: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; }>; key: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; swap0: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; swap1: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; output: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; }; /** * Frame-difference motion mask: how much a pixel changed since last frame, smoothstepped over * [threshold, 2·threshold] into a 0–1 stamp weight. Premultiplied RGB luma difference + alpha * difference, so both colour motion (opaque footage) and coverage motion (moving shapes) trigger. */ export declare const frameDiffMask: import('typegpu').TgpuFn<(live: d.Vec4f, prev: d.Vec4f, threshold: d.F32) => d.F32>; /** Rotate an RGB colour's hue by `amount` turns (via HSL). */ export declare const hueRotateTurns: import('typegpu').TgpuFn<(rgb: d.Vec3f, amount: d.F32) => d.Vec3f>; export interface FeedbackTrailOptions { /** State resolution per axis. */ res: number; format: 'rgba16float' | 'rgba32float'; namePrefix: string; /** What sheds the trail: frame-difference motion, or the live frame's alpha coverage. */ source: 'motion' | 'alpha'; /** Rotate the decayed trail's hue a touch each frame (compounds → a spectrum down the trail). */ hueCycle: boolean; /** Tent-blur half-offset in UV at diffusion 1 (small — it compounds every frame). */ diffuseHalfUv: number; /** Drift prop (−1..1) → UV per second before the dt scale. */ driftScale: number; } /** * One feedback-trail state step: advect the previous accumulation (zoom about centre + drift), * soften it with a four-tap bilinear tent, fade it by `persistence`, optionally hue-cycle it, then * stamp the live frame back on top (source-over alpha; screen/add RGB variants for light-painting). * * Motion source gates the stamp by the frame-difference mask and writes the display copy BEFORE * the stamp (ghosts only — the fragment lays them over the live frame); it ping-pongs a prev-live * copy through `prevLive`/`prevLiveOut`. Alpha source stamps unconditionally, publishes the * stamped state, and never touches the prev-live pair (bind 1×1 stubs). * * Params ABI (runtime surface): persistence, diffusion, driftX, driftY, dt, zoom, hueRate, * blendMode (0 normal · 1 screen · 2 add), motionThreshold. */ export declare function buildFeedbackTrailStep(opts: FeedbackTrailOptions): { layout: import('typegpu').TgpuBindGroupLayout<{ src: { texture: d.WgslTexture2d; }; prev: { texture: d.WgslTexture2d; }; next: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; display: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; prevLive: { texture: d.WgslTexture2d; }; prevLiveOut: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; samp: { sampler: "filtering"; }; params: { uniform: d.WgslStruct<{ persistence: d.F32; diffusion: d.F32; driftX: d.F32; driftY: d.F32; dt: d.F32; zoom: d.F32; hueRate: d.F32; blendMode: d.F32; motionThreshold: d.F32; }>; }; }>; Params: d.WgslStruct<{ persistence: d.F32; diffusion: d.F32; driftX: d.F32; driftY: d.F32; dt: d.F32; zoom: d.F32; hueRate: d.F32; blendMode: d.F32; motionThreshold: d.F32; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; }; export interface MacroblockAdvectOptions { /** State resolution per axis. */ res: number; format: 'rgba16float' | 'rgba32float'; namePrefix: string; /** Coarse-lattice block scale multiplier and the hash fraction picked coarse. */ blockMix?: { coarseScale: number; coarsePick: number; }; /** Held-pixel generation loss: quantize levels, quantize blend amount, per-frame energy decay. */ generationLoss?: { levels: number; amount: number; decay: number; }; } /** * One decode step of a macroblock hold/refresh advection — what a video decoder does when P-frame * motion vectors keep arriving after the I-frame was dropped. Each state texel picks its * macroblock (two mixed scales re-rolled on a slow lattice clock), advances the block's OWN * hash-phased epoch clock (no global heartbeat — blocks lock, drift and recover independently), * decides held vs fresh against a drifting product-wave corruption field, then either advects the * previous state along the block's flow-field motion vector (bilinear, with subtle generation * loss + residual re-key back toward the live source) or re-keys from the live input (bilinear). * Off-canvas advection sources re-key (a clamped source would conveyor-belt the border colour). * * The block hash chain is a ladder of shared intermediates read by every later stage — it does not * split into smaller parts without recomputing rungs. Params ABI: time, dt, seed, intensity, * blockSize, drift, churn. */ export declare function buildMacroblockAdvectKernel(opts: MacroblockAdvectOptions): { layout: import('typegpu').TgpuBindGroupLayout<{ src: { texture: d.WgslTexture2d; }; prev: { texture: d.WgslTexture2d; }; next: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; display: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; params: { uniform: d.WgslStruct<{ time: d.F32; dt: d.F32; seed: d.F32; intensity: d.F32; blockSize: d.F32; drift: d.F32; churn: d.F32; }>; }; }>; Params: d.WgslStruct<{ time: d.F32; dt: d.F32; seed: d.F32; intensity: d.F32; blockSize: d.F32; drift: d.F32; churn: d.F32; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; }; /** * The JPEG block colour for one cell: forward separable DCT (rows→columns) over a 64-sample RGB * block → IJG-table quantize at `quality` (the IJG curve `qScale = q<50 ? 5000/q : 200−2q`) → * inverse DCT at `(localX, localY)`, keeping `nLuma` low-frequency luma coefficients; chroma is * DC-only (a flat colour per block). Pure — the caller samples the block. Memoized per nLuma. */ export declare function makeJpegBlockRgb(nLuma: number): import('typegpu').TgpuFn<(block: d.WgslArray, localX: d.F32, localY: d.F32, quality: d.F32) => d.Vec3f>; export interface BlockQuantizeOptions { /** Low-frequency luma coefficients kept per channel. */ nLuma: number; /** Device pixels per cell (the 8×8 block spans 8·scaleN px, sampled at stride scaleN). */ scaleN: number; format: 'rgba16float' | 'rgba32float'; namePrefix: string; } /** * The block-quantize pass: one thread per scaleN×scaleN device-pixel cell samples its 8×8 block * from the input texture (point `textureLoad`, unpremultiplied), runs the DCT block colour, and * writes it into the cell texture. Dispatch the active cell grid dynamically; the guarded pipeline * bounds-checks. Params ABI: inputWidth, inputHeight, quality. */ export declare function buildBlockQuantizeGraph(opts: BlockQuantizeOptions): { layout: import('typegpu').TgpuBindGroupLayout<{ input: { texture: d.WgslTexture2d; }; cellTex: { storageTexture: d.WgslStorageTexture2d<"rgba16float" | "rgba32float", string>; }; params: { uniform: d.WgslStruct<{ inputWidth: d.F32; inputHeight: d.F32; quality: d.F32; }>; }; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; Params: d.WgslStruct<{ inputWidth: d.F32; inputHeight: d.F32; quality: d.F32; }>; }; /** * Colour a packed flow field by direction: five smoothing-cross taps (r,g = flow vector, b = * density) → a blend of the four per-direction colours weighted by the smoothed flow direction, * faded to `base` where flow is weak and to transparent where density is low. */ export declare const flowDirectionColor: import('typegpu').TgpuFn<(s0: d.Vec4f, s1: d.Vec4f, s2: d.Vec4f, s3: d.Vec4f, s4: d.Vec4f, base: d.Vec4f, up: d.Vec4f, down: d.Vec4f, left: d.Vec4f, right: d.Vec4f) => d.Vec4f>; export {}; //# sourceMappingURL=gridKernels.d.ts.map