Something went wrong. Try again.
A WebGPU retro game engine for TypeScript, inspired by RetroBlit. Build pixel-perfect 2D games with a clean, fantasy-console-style API.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293import type { Vector2i } from '../../utils/Vector2i';
/** * Tier identifier for a post-processing effect. * * - `'pixel'` - runs at logical render resolution (e.g. 320x240) on the `r8uint` * framebuffer that stores **palette indices**, before palette resolve/upscale. * Use for effects that stay in index space: glitch shifts, mosaic blocks, * index inversion. Effects in this tier should avoid introducing values that are * not meaningful palette slots (e.g. blurs, gradients). * - `'display'` - runs at the canvas output resolution (e.g. 1280x960) after * palette resolve/upscale. Use for effects that simulate the physical display the * game appears on: CRT scanlines, barrel distortion, RGB shadow mask, * vignette, chromatic aberration, monochrome amber/green, bloom, etc. The * higher resolution lets curved sampling (barrel) express smoothly without * floor-quantizing onto the logical pixel grid. */export type EffectTier = 'pixel' | 'display';
/** * Fullscreen post-processing effect contract. * * An effect samples a single source color texture and writes a processed result * into a destination color texture (the next chain link or the swap chain). The * {@link PostProcessChain} owns the source/destination wiring; effects are * responsible only for their own pipeline, uniform buffer, and per-pass encoding. * * Lifetime: * 1. {@link init} - called once when the effect is added to the chain. * 2. {@link updateUniforms} + {@link encodePass} - called once per frame. * 3. {@link dispose} - optional cleanup when the effect is removed or the chain * is cleared. * * Implementations must reuse uniform buffers and avoid per-frame allocations on * the hot path. */export interface Effect { /** * Tier this effect runs in. Determines whether the engine routes it to the * pixel chain (logical resolution) or the display chain (output resolution). * * See {@link EffectTier} for guidance on which tier suits a given effect. */ readonly tier: EffectTier;
/** * Creates GPU resources (pipeline, layout, uniform buffer, sampler binding). * * Idempotent: calling twice on the same instance is undefined behavior; the * chain guarantees it is only invoked once per effect instance. * * @param device - WebGPU device used for resource creation. * @param format - Color attachment format for this chain (`r8uint` for the pixel * tier, swap-chain format for the display tier) so ping-pong textures match the * effect pipelines. * @param displaySize - Source render target resolution in pixels. Effects use * this for resolution-aware uniforms (e.g. CRT mask scale, bloom texel size). */ init(device: GPUDevice, format: GPUTextureFormat, displaySize: Vector2i): void;
/** * Writes per-frame uniform data to the GPU. * * Called by {@link PostProcessChain} immediately before {@link encodePass}. * * @param deltaMs - Wall-clock milliseconds since the previous frame. * @param sourceSize - Pixel dimensions of the source texture for this pass. */ updateUniforms(deltaMs: number, sourceSize: Vector2i): void;
/** * Encodes a single full-screen render pass. * * The pass must begin with `colorAttachments[0].view = destView` and load * with `clear` (any clearColor; the shader overwrites the entire surface). * The pass binds {@link sourceView} as its sampled input texture. * * @param encoder - Active command encoder owned by the renderer. * @param sourceView - View of the texture to sample from. * @param destView - View of the texture to render into. */ encodePass(encoder: GPUCommandEncoder, sourceView: GPUTextureView, destView: GPUTextureView): void;
/** * Releases GPU resources owned by this effect. * * Optional. Implementations that allocate `GPUBuffer` or `GPUTexture` * instances should destroy them here. The chain calls this when the effect * is removed or when the chain itself is disposed. */ dispose?(): void;}