import type { ConstructorOf } from "../core.js"; import { Random } from "../data/random.js"; import type { Canvas } from "./canvas.js"; import type { CanvasSandboxApplication, CanvasSandboxExpectedOptions } from "./canvas-sandbox.js"; import { Canvas2DHeadless } from "./canvas2d-headless.js"; import { RenderLoop } from "./render-loop.js"; /** * Sent from the host when a worker should reconfigure itself. */ export interface CanvasWorkerMessageReconfigure { /** * Type identifier of this message. */ type: "reconfigure"; /** * New ID for the worker. */ id: string; /** * New canvas for the worker to use. */ canvas: OffscreenCanvas; /** * New application options to use. */ options: TApplicationOptions; } /** * Sent from the host when a worker should start its rendering kernel. */ export interface CanvasWorkerMessageStart { /** * Type identifier of this message. */ type: "start"; /** * New application options to use before starting. */ options: TApplicationOptions; } /** * Sent from the host when a worker should un/pause rendering. */ export interface CanvasWorkerMessagePause { /** * Type identifier of this message. */ type: "pause"; /** * Should the worker pause (`true`) or unpause (`false`)? */ pause: boolean; } /** * Sent from a worker when it finished rendering the current scene. */ export interface CanvasWorkerSceneFinishMessage { /** * Type identifier of this message. */ type: "sceneFinish"; /** * Point in time when the scene finished rendering. */ timestamp: number; } /** * The messages that are passed between the canvas sandbox host and its workers. */ export type CanvasWorkerMessage = CanvasWorkerMessageReconfigure | CanvasWorkerMessageStart | CanvasWorkerSceneFinishMessage | CanvasWorkerMessagePause | { type: string; }; /** * The canvas worker handles a web worker instance in the canvas sandbox host. * * It provides a thin abstraction over the web worker IPC messaging. */ export declare class CanvasWorker extends EventTarget { /** * The ID of this worker. */ id: string; /** * The canvas element that this worker should handle. * This is purely for informational purposes on the host side. */ canvas: HTMLCanvasElement | undefined; /** * The offscreen canvas that we created for this worker. */ canvasOffscreen: OffscreenCanvas | undefined; /** * The application options for the worker. * * These are usually very similar, if not identical, to the host application options. * Workers just usually get a different viewport assigned to them, correlating with the * canvas element in the DOM that they draw to. */ readonly options: TApplicationOptions; /** * The web worker instance itself. */ readonly workerInstance: Worker; /** * Constructs a new canvas worker. * @param id - The ID of the worker. * @param source - The code that the worker should run. It's common to use a hybrid code module * for as the sandbox application. This means the code of the host and the workers is identical, * they just construct different code path on load/init. In such case, the source can simply be * `new URL(import.meta.url)`. * @param canvas - The canvas element to draw to. * @param options - The application options. */ constructor(id: string, source: URL, canvas: HTMLCanvasElement, options: TApplicationOptions); /** * Posts a message to the worker. * * As messages to workers are _posted_ instead of _sent_, there is no delivery feedback. * @param message - The message to post. * @param transfer - The transferables to transfer to the worker with this message. */ postMessage(message: CanvasWorkerMessage, transfer?: Array): void; } /** * The canvas worker instance handles a web worker instance in worker instance itself, and * handles a feedback channel to the host application. * * It provides a thin abstraction over the web worker IPC messaging. * * ```ts * // Construct inside of worker from global scope and rendering kernel class. * const worker = new CanvasWorkerInstance(self, RenderKernel); * // Listen to custom events (messages) you send from the host. * worker.addEventListener("fade", () => worker.renderKernel?.fadeOut()); * ``` */ export declare class CanvasWorkerInstance> extends EventTarget { #private; /** * The global scope of the worker. */ readonly self: typeof globalThis; /** * The ID of the worker. */ id: string; /** * The rendering kernel, which produces frames, and renders them to our * offscreen canvas. */ renderKernel: TKernel | undefined; /** * The canvas element we're presenting to. */ canvas: TCanvas | undefined; /** * The offscreen canvas we're rendering to. */ offscreenCanvas: OffscreenCanvas | undefined; /** * Our rendering context to draw to. */ offscreenContext: OffscreenCanvasRenderingContext2D | undefined; /** * Manages frame rendering timing. */ renderLoop: RenderLoop | undefined; /** * Constructs a new canvas worker instance. * * Note that many properties are only initialized after the host sent an * initialization message. * @param self - Our global worker scope. * @param Kernel - The rendering kernel class to construct. */ constructor(self: typeof globalThis, Kernel: ConstructorOf); /** * Render a frame. * @param delta - How many milliseconds have passed since the last invocation? */ render: (delta: number) => void; /** * Reconfigure the worker. * @param id - New ID for this worker. * @param offscreenCanvas - New canvas to render to. * @param options - New application options. */ reconfigure(id: string, offscreenCanvas: OffscreenCanvas, options: TApplicationOptions): void; /** * Start rendering. * @param options - New application options. */ start(options: TApplicationOptions): void; /** * Posts a message to the host. * @param message - The message to post. */ postMessage(message: CanvasWorkerMessage): void; } /** * Base class for multi-process canvas sandbox applications. * * Helps in orchestrating the workers. */ export declare abstract class CanvasSandboxHostApplication implements CanvasSandboxApplication { /** * Usually a hidden canvas that serves as a proxy for canvas sandbox events. */ canvas: TCanvas; /** * Application options. */ options: TApplicationOptions; /** * PRNG instance for the application. */ random: Random; /** * Is the application running right now? */ paused: boolean; /** * Web worker instances. */ readonly workers: CanvasWorker[]; /** * Construct a new host application. * @param canvas - Usually a hidden canvas in the DOM to serve as an event proxy. * @param options - Application options. */ constructor(canvas: TCanvas, options: TApplicationOptions); /** * Reconfigure the application with the given options and restart it. * @param canvas - The canvas to use. * @param options - The new options to use. */ abstract reconfigure(canvas: TCanvas, options?: Partial): void; /** * Request the application to draw a new frame. * This call has no effect in a host application, as all rendering happens in the workers. * @param _delta - How many milliseconds passed since the last frame draw. * @param _timestamp - The current timestamp. */ onDraw(_delta: number, _timestamp: number): void; /** * Pauses all workers. */ pause(): void; /** * Start the application. */ start(): void; /** * Posts a message to all workers. * @param message - Message to post to all workers. */ postMessageAll(message: CanvasWorkerMessage): void; }