import { Expr, GpuComputeNode, GpuFragmentParams } from '../../gpu/contract'; import { motionBlur as motionBlurKit, d } from '../../gpu/kit/index'; import { RttFilterParams } from '../../gpu/scaffolds/rttFilter'; import { ArgSpec } from '../invoke'; import { GatherEffect } from '../types'; import { PropRef } from '../values'; /** The sampling stage: produce the initial colour from the child RTT. */ export type SampleStage = (params: RttFilterParams) => Expr; /** One post-sample overlay stage: colour in → colour out. */ export type OverlayStage = (color: Expr, params: RttFilterParams) => Expr; /** Compose a gather effect from a sampling stage and an ordered list of overlays. */ export declare function gatherStack(sample: SampleStage, overlays: OverlayStage[], opts?: { resultAlpha?: 'premultiplied' | 'straight'; }): GatherEffect; /** * A shared geometry frame: one Expr (usually an `asLocal` struct) that several stages of a * recipe read. The producer is memoized per composition, so every stage sees the same local. */ export type GatherFrame = (params: RttFilterParams) => Expr; /** * RGB split: sample the child at ±`amount·0.002` horizontal offsets and take red from the +tap, * green from the centre, blue from the −tap. */ export declare function rgbSplit(opts: { amount: ArgSpec; }): SampleStage; /** VHS tape-warp UVs: vec4(lumaUV.xy, chromaUV.zw) from the wobble/jitter tape geometry, driven by * the global clock × speed. Feed into {@link chromaSmearTaps}. */ export declare function tapeWarp(opts: { wobble: ArgSpec; jitter: ArgSpec; speed: ArgSpec; }): (params: RttFilterParams) => Expr; /** * Chroma smear: one sharp luma tap + 5 chroma taps trailing by `smear·0.0075` each, recombined * through YIQ (sharp Y, smeared I/Q). Alpha comes from the luma tap. */ export declare function chromaSmearTaps(opts: { warp: (params: RttFilterParams) => Expr; smear: ArgSpec; }): SampleStage; /** Brightness/contrast adjustment around mid-grey. */ export declare function adjust(opts: { brightness: ArgSpec; contrast: ArgSpec; }): OverlayStage; /** Sinusoidal scanlines over uv.y. */ export declare function scanlines(opts: { frequency: ArgSpec; intensity: ArgSpec; }): OverlayStage; /** Subtle RGB phosphor mask; `pitch` is the phosphor cell size. */ export declare function phosphorMask(opts: { pitch: ArgSpec; }): OverlayStage; /** Aspect-corrected circular vignette darkening. */ export declare function vignetteOverlay(opts: { radius: ArgSpec; intensity: ArgSpec; }): OverlayStage; /** Finish a vec3 colour stack as an opaque vec4 (alpha 1). */ export declare function opaque(): OverlayStage; /** AC beat: a very subtle brightness pulse from the global clock, clamped to [0,1]. */ export declare function beatPulse(opts: { wobble: ArgSpec; speed: ArgSpec; }): OverlayStage; /** A motion-blur tap trajectory: the path kind plus the prop that anchors it. */ export interface BlurPathSpec { readonly kind: motionBlurKit.MotionBlurPathKind; readonly focus: PropRef; } /** The tap trajectories {@link motionBlur} can follow. */ export declare const blurPath: { /** Straight-line smear along a fixed direction (an angle prop, in degrees). */ linear: (angle: PropRef) => BlurPathSpec; /** Arc smear rotating around a center point (a position prop). */ orbit: (center: PropRef) => BlurPathSpec; /** Radial smear streaking outward from a center point (a position prop). */ zoom: (center: PropRef) => BlurPathSpec; }; /** * Motion blur: 32 Gaussian-weighted samples of the child gathered along a tap trajectory — * `blurPath.linear` (directional), `blurPath.orbit` (rotational), or `blurPath.zoom` (radial). */ export declare function motionBlur(opts: { path: BlurPathSpec; amount: ArgSpec; }): GatherEffect; /** * Scatter: displace every pixel by a per-pixel random offset of up to `amount` pixels — a * grain-like diffusion, not a Gaussian blur. `edges` binds a structural edge-mode prop * ('stretch' | 'transparent' | 'mirror' | 'wrap'). */ export declare function scatter(opts: { amount: ArgSpec; edges: PropRef; }): GatherEffect; /** * Sharpen: a 5-tap unsharp-mask convolution — centre × (1 + 4·amount) minus the four orthogonal * one-pixel neighbours × amount. At `amount` 0 the kernel is the identity. */ export declare function sharpen(amount: ArgSpec): GatherEffect; /** * Pixelate: quantise the child to a grid of `scale` cells along the longest edge, sampling each * cell once, and cut each cell to a rounded rectangle via `gap` (spacing) and `roundness` * (0 = square, 1 = circle) — the cut is an alpha mask, not a coordinate bend. */ export declare function pixelate(opts: { scale: ArgSpec; gap: ArgSpec; roundness: ArgSpec; }): GatherEffect; /** Sphere-bulge geometry: bulged UV + boundary coverage + surface normal. */ export declare function sphereFrame(opts: { center: ArgSpec; radius: ArgSpec; depth: ArgSpec; }): GatherFrame; /** * One Catmull-Rom tap at the frame's warped UV, unpremultiplied. Catmull-Rom, not bilinear: a * magnifying warp blows up its centre, and one bilinear tap turns any hard edge underneath * (text, a logo) into visible facets. */ export declare function crispTap(frame: GatherFrame): SampleStage; /** * Directional fresnel rim over the frame's surface normal — the tinted rim is ADDED and the * alpha gated by the frame's boundary coverage. Added colour is what a uv+mask analytic fold * can't carry, so a recipe with this stage stays on the RTT fragment path. */ export declare function rimLit(frame: GatherFrame, opts: { position: ArgSpec; intensity: ArgSpec; softness: ArgSpec; color: PropRef; }): OverlayStage; /** * The shared glitch geometry: burst pulse, jitter bands, block shifts, and mirror flips — its * burst/band hashes feed the split, fills, and scanlines. Animated by the GLOBAL clock scaled * by `speed` (not a per-node animated time). */ export declare function glitchFrame(opts: { intensity: ArgSpec; speed: ArgSpec; blockDensity: ArgSpec; mirrorAmount: ArgSpec; }): GatherFrame; /** * RGB-split sampling around the frame's mirrored coordinate. Alpha comes from the centred green * tap, so a transparent child stays transparent through the glitch. */ export declare function glitchRgbSplit(frame: GatherFrame, opts: { shift: ArgSpec; }): SampleStage; /** Vivid colour-bar fills in the frame's active glitch blocks. */ export declare function colorBarFills(frame: GatherFrame, opts: { intensity: ArgSpec; }): OverlayStage; /** CRT-style scanlines confined to the frame's distorted regions. */ export declare function distortedScanlines(frame: GatherFrame, opts: { intensity: ArgSpec; }): OverlayStage; /** The two halves a compute-backed blur contributes to a custom-tier definition. */ export interface ComputeBackedEffect { compute: GpuComputeNode; gpu: { fragment: (params: GpuFragmentParams) => Expr; }; } /** * Gaussian blur: a 2-pass separable Gaussian at fixed compute resolution (decoupled from canvas). * A static/mouse/auto intensity runs the fixed-kernel path with a live per-frame radius read; an * intensity bound to a map fills a per-pixel radius map from the map source and runs the variable * Gaussian. Colour comes from the blurred buffer, alpha from the sharp child. */ export declare function gaussianBlur(opts: { intensity: PropRef; }): ComputeBackedEffect; /** * Channel blur: one fixed Gaussian at the MAX per-channel radius, with each channel mixed between * the sharp source and the blurred buffer by `channelRadius / maxRadius` — the max-intensity * channel takes the full blur, a zero channel stays exactly sharp. */ export declare function channelBlur(opts: { red: PropRef; green: PropRef; blue: PropRef; }): ComputeBackedEffect; /** * Progressive blur: a variable-radius Gaussian whose per-pixel radius ramps directionally from * `center` along `angle` over `falloff`, up to the intensity's max radius. A map-driven intensity * samples the per-pixel max radius from the map source instead. */ export declare function progressiveBlur(opts: { intensity: PropRef; angle: PropRef; center: PropRef; falloff: PropRef; }): ComputeBackedEffect; /** * Tilt shift: a variable-radius Gaussian whose per-pixel radius ramps with perpendicular distance * from a focus line (halfKernel 14 — the ~36px max radius keeps tap spacing under the banding * threshold with ~40% fewer taps). The fragment re-derives the same blur amount to mix the * canvas-res sharp source against the compute-res blurred buffer, so in-focus pixels stay crisp. */ export declare function tiltShift(opts: { intensity: PropRef; width: PropRef; falloff: PropRef; angle: PropRef; center: PropRef; }): ComputeBackedEffect; /** * Bloom (Glow): bright-extract the child above `threshold` at aspect-aware compute resolution, * blur the extract by `size` (per-pixel from the map source when size carries a map driver), and * composite `original + bloom × intensity` with the halo allowed to extend past the child's alpha. * A scalar size of 0 skips compute entirely (pair it with `recompile: crosses(0)` on the size prop). */ export declare function bloom(opts: { intensity: PropRef; threshold: PropRef; size: PropRef; }): ComputeBackedEffect; /** The plain centre tap of the child RTT (premultiplied). */ export declare function childTap(): SampleStage; /** The compass-angle shadow displacement: where to read the child's silhouette from. */ export declare function shadowOffset(opts: { angle: ArgSpec; distance: ArgSpec; }): (params: RttFilterParams) => Expr; /** Two-pass separable Gaussian over the child's alpha silhouette, read at the `at` coordinate. */ export declare function silhouetteCoverage(opts: { at: (params: RttFilterParams) => Expr; blur: ArgSpec; }): (params: RttFilterParams) => Expr; /** * Tint the coverage `color` × `intensity` and composite the shadow behind the child — or, with * `cutout` (a structural boolean prop), show only the shadow with the child's silhouette * punched out. */ export declare function shadowComposite(opts: { coverage: (params: RttFilterParams) => Expr; color: PropRef; intensity: ArgSpec; cutout: PropRef; }): OverlayStage; /** * Fluted-glass geometry: refracted UV + chromatic offset + flute slope. `shape` binds a * compile-time prop baking the slope-exponent endpoints + waves flag. The flute pattern drifts * by the definition's animated clock (declare `animatedTime: {speed: 'speed'}`), negated so * positive speed drifts visually right at angle 0. */ export declare function fluteFrame(opts: { shape: PropRef; angle: ArgSpec; frequency: ArgSpec; softness: ArgSpec; waveAmplitude: ArgSpec; waveFrequency: ArgSpec; refraction: ArgSpec; aberration: ArgSpec; }): GatherFrame; /** * The refracted tap(s) at the frame's UV, edge-clipped and unpremultiplied. `edges` binds the * compile-time sampling branch; `aberration` is a uniform whose on/off crossing is structural — * one tap vs a 3-tap chromatic split along the frame's offset (pair it with a crosses-0 * recompile rule). */ export declare function refractedTaps(frame: GatherFrame, opts: { aberration: PropRef; edges: PropRef; }): SampleStage; /** * Blinn specular over the frame's flute slope, tinted and added on top — weighted by alpha so * transparent regions pick up no phantom highlight. */ export declare function fluteHighlight(frame: GatherFrame, opts: { lightAngle: ArgSpec; highlight: ArgSpec; softness: ArgSpec; color: PropRef; }): OverlayStage; /** A scalar shading term of a peel recipe, read against the peel frame. */ export type PeelShade = (params: RttFilterParams) => Expr; /** * Page-peel geometry: curl UV, fold angle, crease distances + shadow reaches. `corner` binds the * compile-time cpu-only STRING prop (no transform — an inline transform would make the bridge * write the string into an f32 field); its geometry lands as literal args. */ export declare function peelFrame(opts: { corner: PropRef; amount: ArgSpec; radius: ArgSpec; }): GatherFrame; /** Crook darkening down the underside of the curl. */ export declare function curlShading(frame: GatherFrame, opts: { shading: ArgSpec; }): PeelShade; /** The specular band running up the curl. */ export declare function curlSheen(frame: GatherFrame, opts: { highlight: ArgSpec; softness: ArgSpec; }): PeelShade; /** The contact shadow the curl casts on the flat page past the crease. */ export declare function overhangShadow(frame: GatherFrame, opts: { amount: ArgSpec; shadow: ArgSpec; }): PeelShade; /** The shadow on the revealed backing just inside the crease. */ export declare function revealShadow(frame: GatherFrame, opts: { amount: ArgSpec; shadow: ArgSpec; }): PeelShade; /** * The fold composite — cast shadow, shaded flat page, lit curl, back to front. Samples the child * at the frame's curl UV (the lip) and at the screen UV (the flat page). Premultiplied — the * gather species appends the unpremultiply tail. */ export declare function peelCompose(frame: GatherFrame, parts: { shade: PeelShade; sheen: PeelShade; overhang: PeelShade; reveal: PeelShade; }): SampleStage; /** * Reflected sample coordinate: mirror across the horizontal line at `lineY`. Y is down (top=0), * so a point at uv.y > lineY reflects to `2·lineY - uv.y`. Pure function. */ export declare const mirrorRowUV: import('typegpu').TgpuFn<(uv: d.Vec2f, lineY: d.F32) => d.Vec2f>; /** * Planar-reflection composite (pre-unpremultiply). Above the line returns the original content * untouched; below it, the (edge-handled) reflection sample composited "over" the original via * premultiplied alpha, faded by `visibility` (full up to distance−fadeWidth, smoothly to 0 by * `distance`; `falloff` is the fade-zone width as a fraction of distance). Pure function. */ export declare const planarReflectionCompose: import('typegpu').TgpuFn<(original: d.Vec4f, refl: d.Vec4f, uvY: d.F32, lineY: d.F32, distance: d.F32, falloff: d.F32) => d.Vec4f>; /** * GPU-free construction of the depth-ramp blur-map fill graph. Per compute pixel, the desired * blur radius ramps with the row's depth below the line: * `blur × smoothstep(0, blurDistance, height − v) × DEPTH_RAMP_RADIUS_PX` (source pixels). * Row-based (depends only on cy/computeHeight); 2D dispatch, STORAGE textureStore. */ export declare function buildDepthRampFillGraph(computeWidth: number, computeHeight: number): { layout: import('typegpu').TgpuBindGroupLayout<{ blurMap: { storageTexture: d.WgslStorageTexture2d<"rgba32float", string>; }; params: { uniform: d.WgslStruct<{ height: d.F32; blurAmount: d.F32; blurDistance: d.F32; }>; }; }>; kernel: import('typegpu').TgpuFn<(cx: d.U32, cy: d.U32) => d.Void>; Params: d.WgslStruct<{ height: d.F32; blurAmount: d.F32; blurDistance: d.F32; }>; }; /** The reflected sample coordinate stage (identity above the line; the composite gates on it). */ export declare function mirrorAcrossRow(line: PropRef): (params: GpuFragmentParams) => Expr; /** * Depth-ramped variable blur (compute): RTT the child, fill a per-pixel radius map from the * line geometry, run kit/blur's variable Gaussian. Map-driven slots use their static scalar * (compute maps don't drive these per-pixel — the Blur/ProgressiveBlur precedent). */ export declare function depthRampBlur(opts: { line: PropRef; blur: PropRef; blurDistance: PropRef; halfKernel: number; }): { compute: GpuComputeNode; }; /** The over-composite stage: the (edge-handled) reflection tap composited "over" the original * below the line, faded to transparent over `distance`/`falloff`. */ export declare function planarReflection(opts: { line: PropRef; distance: PropRef; falloff: PropRef; edges: PropRef; }, original: Expr, reflection: (uv: Expr) => Expr, reflectedUV: (params: GpuFragmentParams) => Expr): (params: GpuFragmentParams) => Expr; /** * Screen a tinted glow (blurred bright highlights) over a base colour. * `tintStrength = (rgb tint, strength)`. The glow's coverage extends the alpha into transparent * areas (Glow's aura precedent) so the halo isn't clipped to the child's α. */ export declare const tintedScreenGlow: import('typegpu').TgpuFn<(base: d.Vec4f, glow: d.Vec4f, tintStrength: d.Vec4f) => d.Vec4f>; /** * Screened-bloom recipe: the compute half is the kit's highlight-bloom mechanism * (`withBloomCompute`: bright-extract + variable-Gaussian blur at capped compute resolution); * the screen half tints the blurred highlights and screens them back over the graded colour * (no-op when the bloom buffer is absent — GPU-free resolve, or `strength` = 0, which returns * null from `compute`; pair the strength prop with `recompile: crosses(0)`). */ export declare function screenedBloom(slots: { strength: PropRef; radius: PropRef; tint: [number, number, number]; threshold: number; output: string; extractName: string; }): { compute: GpuComputeNode; screen: (base: Expr, at: Expr, params: GpuFragmentParams) => Expr; }; /** * Frame sway — a tiny animated translation + rotation about the frame centre, like an unsteady * projector gate. `amount` scales both amplitude and (via the gated clock) presence; `t` is the * per-frame sway-time accumulator. Returns the UV to sample the content at (a clamp sampler * handles the sliver pushed off-frame). amount=0 → returns `uv` unchanged. */ export declare const swayUV: import('typegpu').TgpuFn<(uv: d.Vec2f, amount: d.F32, t: d.F32) => d.Vec2f>; /** * The frame-sway stage: a gated clock (the `field` extraField — advances only while `amount` > 0, * freezes rather than snapping back at 0) drives a tiny animated translation + rotation of the * content sample UV. Declare the extraField `{schema: f32, initial: 0}` on the definition. */ export declare function frameSway(slots: { amount: PropRef; field: string; }): (params: GpuFragmentParams) => Expr; /** * The bokeh-defocus recipe: the aperture-table gather compute (uniform-radius, or the map-driven * fork when `radius` binds a spatial map — mouse/auto radius stays a per-frame scalar) + the * defocused-buffer sampling fragment. The aperture (shape + blades) is fully RUNTIME: changing * it regenerates the CPU tap table and rewrites one small uniform — no recompile. Compute * unavailable (GPU-free resolve / no device) → sharp unpremultiplied passthrough. */ export declare function bokehDefocus(opts: { radius: PropRef; gain: PropRef; threshold: PropRef; shape: PropRef; blades: PropRef; rotation: PropRef; fringe: PropRef; }): { compute: GpuComputeNode; gpu: { fragment: (params: GpuFragmentParams) => Expr; }; }; //# sourceMappingURL=blurs.d.ts.map