import { BubbleState } from '../models/internal/bubble-state'; import { RenderLayer } from '../models/public/configuration'; /** * RenderFrameState — metadata passed to each layer hook. */ export interface RenderFrameState { readonly width: number; readonly height: number; readonly dpr: number; readonly theme: "flat" | "glass"; readonly timestamp: DOMHighResTimeStamp; } /** * DrawContext — renderer-agnostic context wrapper for layer hooks. * Hook authors use this instead of a raw canvas/svg union. * ctx.save()/ctx.restore() is called by the renderer around each hook — hook authors * do NOT need to clean up context state. */ export interface DrawContext { readonly type: "canvas" | "svg"; readonly canvas?: CanvasRenderingContext2D; readonly svg?: SVGGElement; } export type LayerHookFn = (ctx: DrawContext, bubbles: ReadonlyArray, state: RenderFrameState) => void; export interface LayerHook { id: string; layer: RenderLayer; priority: number; fn: LayerHookFn; } /** * IRenderer — renders one frame. * Built-in passes are registered internally as hooks with prefix "builtin:". * Developers can remove any built-in and replace it. */ export interface IRenderer { /** Mount the renderer into the container element. */ mount(container: HTMLElement): void; /** Render a complete frame. Called every animation tick by the orchestrator. */ renderFrame(bubbles: ReadonlyArray, state: RenderFrameState): void; /** Render a single layer (used internally and for testing). */ renderLayer(layer: RenderLayer, bubbles: ReadonlyArray, state: RenderFrameState): void; /** Register a developer layer hook. Returns a stable hook ID. */ addLayerHook(hook: Omit): string; /** Remove a hook by ID. Built-in IDs use "builtin:" prefix. */ removeLayerHook(id: string): void; /** Get all hooks, optionally filtered by layer. */ getLayerHooks(layer?: RenderLayer): ReadonlyArray; /** Handle container resize. */ resize(width: number, height: number): void; /** Release DOM resources. */ dispose(): void; }