import { PylinkaProject, EmitterSettings } from '@pylinka/graph'; import { C as CompiledAtlasOptions, a as CompiledMaskOptions } from './mask-DvK7Ulmr.js'; /** * The compiled-backend handle: same driving surface as the interpreted * `@pylinka/core/webgl` handle, produced by the true graph→GPU codegen path * (REQUIREMENTS.md §13). Value edits and knobs are zero-recompile (they live in * the vec4 value table); structural edits recompile pipelines and reset the * pool (§7.5). */ interface CompiledStats { aliveCount: number; overflowCount: number; gpuMs: number | null; } interface CompiledParticlesHandle { /** Step the simulation and render one frame. Call once per rAF tick. */ update(dtSeconds: number): void; /** Move where new particles are born (canvas pixels). */ /** * Move where new particles are born (world/canvas pixels). * * `teleport` moves the emitter WITHOUT counting the distance travelled. That * distance is what `rateOverDistance` turns into spawns — the feature that * lays a trail behind a dragged emitter — so jumping the emitter somewhere * for one frame otherwise fires a spawn proportional to how far it jumped, * and another one when it jumps back. Teleport when the move is a cut rather * than a motion: placing a one-off burst, or repositioning between shots. */ setEmitter(x: number, y: number, teleport?: boolean): void; /** Emit an extra burst next frame. */ spawnBurst(count: number): void; /** Set a named knob live — writes a value-table slot, never recompiles. */ setKnob(name: string, x: number, y?: number, z?: number, w?: number): void; /** * Re-read an edited project into the running effect. Value-only edits are * zero-recompile; a changed graph hash rebuilds pipelines and resets the pool * (§7.5); a changed blend mode rebuilds the render pipeline. Returns false if * the change needs a full re-create (only pool capacity does). */ apply(project: PylinkaProject): boolean; /** Reset the pool + scheduler (§11.5 restart). */ restart(): void; /** Whether the canvas is cleared each frame (default true). */ /** * How much world the canvas shows, live. * * `1` maps one world unit to one canvas PIXEL, so on a 2x-density display an * effect authored at 100px covers 50 CSS px — pass `1 / devicePixelRatio` to * make world units device-independent. Above 1 shows more world in the same * canvas (zoom out), below 1 less (zoom in), and because it changes what the * renderer draws rather than stretching a finished image, it stays sharp at * any level. Emitter coordinates stay in canvas pixels. */ zoom: number; /** * Slide the view without moving the effect, in world units. * * Panning by transforming the canvas ELEMENT moves finished pixels: the drawn * area slides out of the viewport and leaves an empty margin, and it does not * combine with a rendered zoom. This shifts the window the renderer draws * through instead. */ viewOffset: [number, number]; autoClear: boolean; /** * What `autoClear` clears to, as straight (non-premultiplied) `[r,g,b,a]` in * 0..1. Defaults to fully transparent. * * A light blend mode can only add to pixels that are IN this framebuffer, so * clearing to the colour the effect will really play on is what makes `add` * and `screen` show what they will actually do. Over a transparent clear * there is nothing to add to. */ clearColor: [number, number, number, number]; /** * Alive particle count. webgl2: synchronous readback on call (debug-tier); * webgpu: the §13.11 async counter readback, refreshed every 30 frames. */ aliveCount(): number; /** Async-refreshed stats (§11.5) — reading never triggers a readback. */ readonly stats: CompiledStats; /** * True while the GPU context or device is gone. `update()` is a no-op * meanwhile. On WebGL2 the effect rebuilds itself once the browser restores * the context, minus the particles that were alive at the time. On WebGPU the * device belongs to whoever created it, so recovery is the host's call. */ readonly contextLost: boolean; readonly backendName: 'webgpu' | 'webgl2'; destroy(): void; } interface CompiledParticlesOptions { /** Which system to run (defaults to the first enabled system). */ systemName?: string; /** dt clamp in seconds (default 0.05). */ maxDt?: number; /** View zoom-out factor (default 1) — see the interpreted backend. */ zoom?: number; /** Particle sprite size multiplier (default 1). */ sizeScale?: number; /** Deterministic base seed (capture mode). Default: Date.now(). */ seed?: number; /** Sprite / uniform-grid atlas; cell picked by `output.initTexIndex` (§13.8). */ atlas?: CompiledAtlasOptions; /** Painted emission area; particles spawn inside it instead of the analytic shape. */ emissionMask?: CompiledMaskOptions; /** * Sub-emitter parent handle: this system becomes a child that spawns one * particle on each of the parent's particle deaths (at the death position), * running its own graph. The parent must be a live compiled handle on the * same backend/canvas. The child mirrors the parent's capacity. */ subParent?: CompiledParticlesHandle; /** Called after any pipeline rebuild with the time it took. */ onRecompile?: (info: { ms: number; reason: 'structural' | 'blend'; }) => void; /** Called when the GPU context or device is lost. */ onContextLost?: () => void; /** Called after a lost context came back and the effect was rebuilt (WebGL2). */ onContextRestored?: () => void; } /** * Per-system CPU frame state shared by the compiled backends: emitter position * (current/previous), spawn scheduling, sim time, frame counter, and the * per-frame baseSeed advance (§13.4, §13.7, §13.11). Alloc-free in tick(). */ declare class SystemClock { ex: number; ey: number; px: number; py: number; time: number; frame: number; baseSeed: number; spawnCount: number; private scheduler; constructor(emitter: EmitterSettings, capacity: number, startX: number, startY: number, seed?: number); /** §13.11 step 2: schedule spawns and advance the seed for this frame. */ tick(dt: number): void; /** §13.11 step 6 — after dispatch, current becomes previous. */ endFrame(dt: number): void; /** emitterVel uniform: travel this frame over dt (§13.7). */ velX(dt: number): number; velY(dt: number): number; spawnBurst(n: number): void; /** Swap emitter settings without losing position (apply()). */ setEmitterSettings(emitter: EmitterSettings, _capacity: number): void; reset(): void; } export { type CompiledParticlesOptions as C, SystemClock as S, type CompiledParticlesHandle as a, type CompiledStats as b };