import { TgpuBindGroupLayout, TgpuFragmentFn } from 'typegpu'; import { BlendMode } from './kit/blend'; import { MaskType } from './kit/mask'; import { ToneMappingMode } from './kit/tonemap'; import { ComputeStep } from './compute'; import { Expr, GpuMediaTexture, RegistryView } from './contract'; export declare const SHARED_SAMPLER_LAYOUT: TgpuBindGroupLayout<{ linearClamp: { sampler: "filtering"; }; nearestClamp: { sampler: "filtering"; }; linearRepeat: { sampler: "filtering"; }; nearestRepeat: { sampler: "filtering"; }; }>; /** Group indices the composer pins. uniforms=0, textures=1, samplers=2, external=3. */ export declare const BIND_GROUPS: { readonly uniforms: 0; readonly textures: 1; readonly samplers: 2; readonly external: 3; }; /** A raw WGSL fragment (identifier / literal / pre-formed expression). */ export declare function expr(wgsl: string): Expr; /** A WGSL float literal Expr (decimal-safe). */ export declare function floatE(n: number): Expr; /** A call to a `tgpu.fn` external: `(arg0, arg1, …)`. Dedupes the fn by identity. */ export declare function call(fn: unknown, hint: string, args: Expr[]): Expr; /** `vec4f(rgb, a)` or `vec4f(x, y, z, w)`. */ export declare function vec4(...parts: (Expr | number)[]): Expr; /** `mix(a, b, t)` — WGSL built-in, no external. */ export declare function mixExpr(a: Expr, b: Expr, t: Expr | number): Expr; /** * A WGSL fixed-size array constructor `array(e0, e1, …)`, for passing a run of * builder-computed scalar/vec Exprs into a `tgpu.fn` that takes a `d.arrayOf(...)` param. Used * by Dither's Floyd-Steinberg block diffusion (64 RTT-sampled luminances → the diffusion body's * `array` param). `elemType` is the WGSL element type (e.g. `f32`, `vec2f`). */ export declare function arrayExpr(elemType: string, elems: Expr[]): Expr; export declare function asLocal(e: Expr, hint: string): Expr; /** Transparent-black `vec4f(0.0, 0.0, 0.0, 0.0)`. */ export declare const ZERO: Expr; /** `vec4f(1.0, 1.0, 1.0, 0.0)` — the first-child blend base. */ export declare const WHITE0: Expr; /** `blendModes[mode](base, overlay, opacity)`. */ export declare function applyBlend(base: Expr, overlay: Expr, mode: BlendMode, opacity: Expr): Expr; /** `maskFunctions[type](target, mask)`. */ export declare function applyMaskFn(target: Expr, mask: Expr, type: MaskType): Expr; /** A built fragment entry + its resolvable form (for GPU-free snapshots) + texture reads. */ export interface FragmentSpec { /** The raw-WGSL body block (`{ …statements… return …; }`). */ body: string; /** The `$uses` externals map (fn objects + bind-group layouts). */ externals: Record; /** The built `tgpu.fragmentFn` entry (GPU-free to build + resolve). */ entry: TgpuFragmentFn; /** Composition texture keys this pass samples (NEVER its own RTT output — no r/w hazard). */ reads: string[]; /** External (video/webcam) texture keys this pass samples. */ externalReads: string[]; /** Whether this pass binds the shared sampler group. */ usesSamplers: boolean; /** This pass's OWN texture bind-group layout (only its `reads` keys), pinned to group 1. */ textureLayout?: TgpuBindGroupLayout; /** This pass's OWN external-texture layout (only its `externalReads` keys), group 3. */ externalLayout?: TgpuBindGroupLayout; } /** An RTT pass: render `fragment` into the texture bound at `textureKey`. */ export interface RttPassSpec { textureKey: string; fragment: FragmentSpec; } /** A registered texture the composition needs bound (RTT target or shader-owned media). */ export interface TextureBinding { key: string; kind: 'rtt' | 'media' | 'compute'; /** For media/compute textures: the shader-provided resource passManager binds. Absent for RTT. */ resource?: unknown; } /** A registered external texture (video/webcam) — per-frame re-import. */ export interface ExternalTextureBinding { key: string; /** Returns the live source each frame (HTMLVideoElement / VideoFrame). */ getSource: () => unknown; } /** A compute step provider for one node (drained per frame by frame.ts / passManager). */ export interface ComputeSpec { nodeId: string; getComputeNodes: (frameParams: unknown) => ComputeStep[] | null; /** * (Re)bind this compute pass's RTT-boundary inputs once the pass manager has * allocated them (see contract `GpuComputeNode.bindInputs`). Called in `setComposition`. */ bindInputs?: (resolve: (key: string) => { texture: unknown; } | undefined) => void; } export interface CompositionIR { /** Compute passes, in registry order (dispatched first each frame). */ computeSteps: ComputeSpec[]; /** RTT passes, leaves→root (a valid topological order by construction). */ rttPasses: RttPassSpec[]; /** The final fullscreen pass → canvas view (tonemap + sRGB OETF tail). */ finalPass: FragmentSpec; /** All texture bindings (RTT targets + shader-owned media/compute textures). */ textures: TextureBinding[]; /** External (video/webcam) texture bindings. */ externalTextures: ExternalTextureBinding[]; /** * Composition-wide bind-group layouts. `uniforms` (group 0) + `samplers` (group 2) are * shared across all passes; texture (group 1) + external (group 3) layouts are per-pass * and live on each `FragmentSpec` (only the keys that pass reads — never its own output). */ layouts: { uniforms?: TgpuBindGroupLayout; samplers: TgpuBindGroupLayout; }; /** Lifecycle callbacks collected during composition (frame.ts drains these). */ onBeforeRender: ((p: unknown) => void)[]; onAfterRender: ((p: unknown) => void)[]; onResize: ((p: unknown) => void)[]; onCleanup: (() => void)[]; /** The set of node ids included in this composition (opacity-transition tracking). */ composedNodeIds: Set; } export interface ComposeOptions { /** Tone mapping curve applied at the final-pass tail (part of the structural hash). */ toneMapping?: ToneMappingMode; /** * Flip the fragment UV's Y once, globally. Default TRUE: typegpu's `fullScreenTriangle` uv * is top-left origin (uv.y=0 at top) while shader math is written against a bottom-left * origin. Flipping once here makes `ctx.uv` bottom-left, so shaders need zero Y changes, and * RTT write/sample round-trips stay self-consistent (both sides use the same flipped * coordinate). */ flipY?: boolean; /** * Premultiply RGB by alpha at the final tail. Default OFF; shaders emit straight alpha and * the canvas is `premultiplied`, so the renderer enables it. */ premultiplyAlpha?: boolean; /** Canvas element / dimensions / gpu — threaded to fragment builders' params. */ canvas?: HTMLCanvasElement; dimensions?: { width: number; height: number; }; gpu?: { device: GPUDevice; root: import('typegpu').TgpuRoot; }; /** * Write a node's `extraFields` value on its live uniform handle. The composer has no * store-write access (only `gpuAccessor`), so the renderer injects this; `params.setExtraField` * routes through it. `null`/absent → `setExtraField` is a harmless no-op (tests that never * render). Not part of the structural hash (a function identity). */ writeExtraField?: (nodeId: string, name: string, value: number | number[]) => void; /** * Create a shader-owned media texture. The renderer injects its TextureManager's * `createMediaTexture` (the composer has no texture-manager access); `params.createMediaTexture` * routes here. Absent → `params.createMediaTexture` throws (no media shader can compose without a * device — tests that never render also never call it). */ createMediaTexture?: (options: import('./contract').GpuMediaTextureOptions) => GpuMediaTexture; /** * Create a shader-owned DATA texture (r16float/r32float) via the renderer's TextureManager * — the raw-float upload sibling of `createMediaTexture` (SVG-SDF field textures). Absent → * `params.createDataTexture` throws (no SVG-SDF shader can compose without a device). */ createDataTexture?: (options: import('./contract').GpuDataTextureOptions) => GpuMediaTexture; /** * Resolve the LIVE remap window (post dynamic-bound resolution) of a node's map-driven * prop — the same five values the renderer writes into the `_map__*` synthetic uniforms * each frame. The composer has no access to the renderer's resolved `mapValues`, so the renderer * injects this; `params.getMapInfo(prop).window()` routes through it. Absent → `window()` falls * back to the raw driver-config numbers (correct for static maps). Not part of the structural * hash (a function identity). */ resolveMapWindow?: (nodeId: string, prop: string) => import('./contract').GpuMapWindow | undefined; /** * Resolve the LIVE driver-resolved CPU value of a mouse-position / mouse / auto-animate driven * prop — the same value the fragment reads from the `_smoothed_` synthetic field. A COMPUTE * hook reads its driven props through `params.getCpuValue(prop)`; a maps-routed prop's static * handle never moves, so without this the compute sim (e.g. Smoke's emitter) is frozen at the * default while the fragment path animates. The renderer injects this from its per-frame CPU * driver state; absent, or the prop has no such driver → undefined and `getCpuValue` falls back to * the static handle (correct for GPU-free tests / static maps). Also resolves the synthetic * `_animTime` / `_animTime_` fields (the node's animated-time accumulator this frame) so * per-frame CPU work can share the fragment's clock. Not part of the structural hash. */ resolveDriverCpuValue?: (nodeId: string, prop: string) => unknown; } /** * Compose a registry into a CompositionIR. */ export declare function composeNodeTree(registry: RegistryView, options?: ComposeOptions): CompositionIR; /** * Collect the exact recompile-trigger set, in registry order. pipelineCache digests this into * the cache key. Any change here that alters emitted WGSL MUST change the hash (that is the * invariant the cache tests assert). * * The walk is pre-order, and pre-order ALONE does not identify a tree — `parent > [A > [B], C]` * and `parent > [A > [B, C]]` visit the same four nodes in the same sequence, with the same * renderOrder on each. That is a real editing move (drag a layer into a filter, below its existing * child): every line would be byte-identical, the cache would serve the pre-move composition, and * the dragged layer would keep rendering as if it were still outside. So each line names its own * PARENT — with that, the sequence plus the parent links pin the tree exactly. */ export declare function collectStructuralHashInputs(registry: RegistryView, options?: ComposeOptions): string[]; //# sourceMappingURL=composer.d.ts.map