import { Difference } from 'microdiff'; /** * Message protocol between the main thread and an optional {@link GameWorker}-registered * Worker. Kept intentionally small: each request names one unit of work Pixi'VN (or a * third-party library building on it, via `"custom"` - see `registerGameWorkerHandler`) knows * how to hand off, and the worker replies with the same `id` so the caller can match the * response. * * This protocol (and everything it carries) only ever deals with plain, structured-clone-safe * data - never PixiJS/canvas/audio objects, which can't leave the main thread. */ type GameWorkerRequest = { id: number; type: "restore-diff"; /** The base state to apply `diff` to (not mutated). */ state: object; diff: Difference[]; } | { id: number; type: "diff"; /** The two states to compare (neither is mutated). */ before: object; after: object; } | { id: number; type: "clone"; /** The value to deep-clone. */ value: object; } | { id: number; type: "custom"; /** Identifies which registered handler (see `registerGameWorkerHandler`) should run. */ kind: string; payload: unknown; }; type GameWorkerResponse = { id: number; type: "restore-diff-result"; result: object; } | { id: number; type: "diff-result"; result: Difference[]; } | { id: number; type: "clone-result"; result: object; } | { id: number; type: "custom-result"; result: unknown; } | { id: number; type: "error"; error: string; }; /** * The worker-side half of the {@link GameWorkerManager} protocol. The game project creates its * own Worker (so it controls the bundler-specific setup) and points its `message` handling here: * * ```ts * // game-worker.ts, built as its own entry by the project's bundler * import { handleGameWorkerMessage } from "@drincs/pixi-vn/worker"; * * self.onmessage = async (event) => { * const response = await handleGameWorkerMessage(event.data); * if (response) self.postMessage(response); * }; * ``` * * A third-party library sharing this same worker (see `registerGameWorkerHandler`) just needs * its own worker-side registration module imported alongside this one, in that same file. * * Everything this processes is plain, structured-clone-safe data by construction - it never * touches PixiJS/canvas/audio, which only exist on the main thread. */ declare function handleGameWorkerMessage(request: GameWorkerRequest): Promise; /** * Optional integration point for offloading Pixi'VN's own heavy, pure (no DOM/PixiJS/audio) * computations to a Worker the game project registers. Pixi'VN never creates a Worker itself * and works exactly as before if none is registered - this is opt-in, not a requirement, so * projects that can't or don't want to use Workers (SSR, certain embeds, ...) are unaffected. * * The game project owns the `Worker` instance (so it controls the bundler-specific `new * Worker(new URL(...), { type: "module" })` call, any CSP/nonce concerns, and whether it exists * at all) and just needs its `onmessage` wired to {@link handleGameWorkerMessage} - see that * function's doc comment for the worker-side half of this. */ declare class GameWorkerManager { private static _worker; private static _pending; private static _nextId; static get isAvailable(): boolean; /** * Registers the Worker Pixi'VN may use for eligible heavy computations. Replaces any * previously registered worker (its still-pending requests are rejected, never left * hanging). */ static register(worker: Worker): void; /** Stops using the registered worker (does not terminate it - the caller owns its lifecycle). */ static unregister(): void; private static _handleMessage; /** * Sends one {@link GameWorkerRequest} and resolves with its matching response's `result`. * Rejects if no worker is registered - callers are expected to fall back to computing the * same result synchronously in that case (see {@link restoreDiff}/{@link diff}/{@link clone}'s * own call sites), not to treat the worker as required. */ private static _request; /** Applies `diff` to `state` on the registered worker (see `restoreDiffChanges`). */ static restoreDiff(state: T, diff: Difference[]): Promise; /** Computes the `microdiff` difference between `before` and `after` on the registered worker. */ static diff(before: object, after: object): Promise; /** Deep-clones `value` (JSON round-trip, matching `createExportableElement`) on the registered worker. */ static clone(value: T): Promise; /** * Runs the handler a third-party library registered for `kind` (see * `registerGameWorkerHandler`) on the registered worker, passing it `payload`. Lets a * library built on top of Pixi'VN share this same worker instead of needing one of its own - * see that function's doc comment for the worker-side half of this. */ static custom(kind: string, payload: unknown): Promise; } type GameWorkerHandler = (payload: unknown) => unknown | Promise; /** Registers (or replaces) the worker-side handler for `kind`. See this file's doc comment. */ declare function registerGameWorkerHandler(kind: string, handler: GameWorkerHandler): void; /** Removes the worker-side handler previously registered for `kind`, if any. */ declare function unregisterGameWorkerHandler(kind: string): void; /** * Applies `stateDiff` to `state`, via the registered game worker if one is available (see * `Game.worker`), falling back to computing it synchronously on the main thread otherwise - * whether that's because no worker was registered, or because the worker call itself failed (the * caller should never hard-fail just because the optional worker hiccuped). */ declare function restoreDiffMaybeOffloaded(state: T, stateDiff: Difference[]): Promise; /** * Computes the difference between `before` and `after`, via the registered game worker if * available, falling back to the main thread otherwise. Mirrors * {@link restoreDiffMaybeOffloaded} - same worker, opposite direction. */ declare function diffMaybeOffloaded(before: object, after: object): Promise; /** * Deep-clones `value` (matching `createExportableElement`'s JSON-round-trip semantics), via the * registered game worker if available, falling back to the main thread otherwise. */ declare function cloneMaybeOffloaded(value: T): Promise; export { GameWorkerManager, cloneMaybeOffloaded, diffMaybeOffloaded, handleGameWorkerMessage, registerGameWorkerHandler, restoreDiffMaybeOffloaded, unregisterGameWorkerHandler }; export type { GameWorkerHandler, GameWorkerRequest, GameWorkerResponse };