import { ComputeStep, PingPongPair } from '../compute'; import { GpuFragmentParams, KitTexture } from '../contract'; export { createPingPongPair, type PingPongPair } from '../compute'; /** Texture size as `[width, height]`, or one number for a square. */ export type SimSize = number | readonly [number, number]; /** One side of the ping-pong: the state texture plus any extra lockstep-swapping slots. */ export interface SimSlot { /** The state texture for this side. */ state: unknown; /** Extra per-side textures declared via `extraSlots`, keyed by their declared name. */ extra: Record; } /** What `bindGroups` / `staticGroups` get to build bind groups from. */ export interface SimBindContext { /** The child RTT, already typed for `root.createBindGroup`. */ childTexture: never; /** The display copy the fragment samples (a write-only storage target for the kernel). */ display: unknown; /** Orientation-independent textures declared via `textures`, keyed by name. */ textures: Record; } /** What the per-frame callback gets. */ export interface SimTick { /** Bind groups for the CURRENT orientation. */ groups: TGroups; /** Orientation-independent bind groups (from `staticGroups`), or `undefined` if none declared. */ shared: TStatic; /** Frame delta, clamped to `maxDeltaTime` and multiplied by the `speedProp` value. */ dt: number; /** Sum of every `dt` so far — the sim's own clock, unaffected by the global time uniform. */ localTime: number; /** The raw frame delta before clamping and speed scaling. */ rawDeltaTime: number; } export interface FeedbackTrailSimOptions { /** State + display resolution. */ size: SimSize; /** Storage format for state, display and extra textures. Must be a core storage format. */ format: 'rgba16float' | 'rgba32float'; /** * Extra texture pairs that swap in LOCKSTEP with the state (TimeTrail's previous-live-frame * copy). Value is that slot's size — pass `[1, 1]` for a stub a compile-time-disabled kernel * variant never touches but the bind group still has to fill. */ extraSlots?: Record; /** Orientation-independent extra textures (KeyFrames' feature grid). */ textures?: Record; /** Prop whose value scales `dt`. Omit for an unscaled (real-time) sim. */ speedProp?: string; /** Upper bound on the frame delta before speed scaling. Defaults to 0.05 s. */ maxDeltaTime?: number; /** Build the bind groups for one orientation. Called twice (once per orientation), late. */ bindGroups: (ctx: SimBindContext, read: SimSlot, write: SimSlot) => TGroups; /** Build orientation-independent bind groups. Called once, late. */ staticGroups?: (ctx: SimBindContext) => TStatic; } export interface FeedbackTrailSim { /** The child's RTT handle — put it in `outputs` so the fragment samples it rather than re-RTTing. */ readonly childTexture: KitTexture; /** The registered display copy — put it in `outputs`; the fragment samples this. */ readonly display: KitTexture; /** The raw state pair, for a shader that needs the textures directly. */ readonly pair: PingPongPair; /** Hand straight to the compute node's `bindInputs`. */ bindInputs: (resolve: (key: string) => { texture: unknown; } | undefined) => void; /** * The body of `getComputeNodes`. Returns `null` before the child RTT is bound. Otherwise * advances the clock, invokes `frame`, and swaps the ping-pong — but only if `frame` returned * steps, so an idle-skip frame leaves the orientation untouched. */ tick: (frameParams: unknown, frame: (t: SimTick) => ComputeStep[] | null) => ComputeStep[] | null; } /** * Allocate and wire a state-texture feedback simulation. Returns `null` when there is no child or * no GPU device, which is the "fragment falls back to a passthrough" branch every consumer has. * * @example * const sim = createFeedbackTrailSim(params, { * size: STATE_RES, * format: 'rgba16float', * speedProp: 'speed', * bindGroups: ({childTexture, display}, read, write) => * root.createBindGroup(moshLayout, { * src: childTexture, prev: read.state, next: write.state, display, * params: paramsBuf.buffer, * } as never), * }) * if (!sim) return null * return { * outputs: {childTexture: sim.childTexture, display: sim.display}, * bindInputs: sim.bindInputs, * getComputeNodes: (fp) => sim.tick(fp, ({groups, dt, localTime}) => { * paramsBuf.write({time: localTime, dt, ...}) * return [pipeline.with(groups)] * }), * } */ export declare function createFeedbackTrailSim(params: GpuFragmentParams, opts: FeedbackTrailSimOptions): FeedbackTrailSim | null; //# sourceMappingURL=feedbackSim.d.ts.map