/** * Transactional scene and component replacement for worker-owned Three.js applications. * * This module does not install Vite handlers by itself. Applications opt into replacement * from their own `import.meta.hot.accept()` callback, which keeps the public entrypoint * side-effect free and makes production tree-shaking predictable. * * @module three-blocks/hmr */ import { Object3D } from 'three'; export type MaybePromise = TValue | PromiseLike; export type HotReplacementPhase = 'capture' | 'create' | 'restore' | 'prepare' | 'compile' | 'commit'; /** A replacement failure that leaves the previously committed object active. */ export declare class HotReplacementError extends Error { readonly phase: HotReplacementPhase; readonly causeValue: unknown; readonly cleanupError: unknown; constructor(phase: HotReplacementPhase, causeValue: unknown, cleanupError?: unknown); } export interface HotScene { /** Shallow, declared state whose compatible fields survive scene replacement. */ readonly hot?: object; captureHotState?(): TState; restoreHotState?(state: TState): MaybePromise; dispose(): MaybePromise; } export type HotSceneFactory = (context: TContext) => MaybePromise; export interface SceneHotReloaderOptions, TContext, TState = unknown> { readonly context: TContext; /** Load newly required resources before the candidate becomes visible. */ readonly prepare?: (scene: TScene, context: TContext) => MaybePromise; /** Compile render and compute pipelines before the atomic reference swap. */ readonly compile?: (scene: TScene, context: TContext) => MaybePromise; /** Atomically expose the candidate to the renderer while updates remain paused. */ readonly commit?: (scene: TScene, previous: TScene, context: TContext) => MaybePromise; /** Optional frame scheduler hooks. `resume` always runs after a matching `pause`. */ readonly pause?: () => void; readonly resume?: () => void; } export interface SceneReplacementResult { readonly previous: TScene; readonly current: TScene; /** Disposal occurs after commit, so a cleanup failure cannot roll back the new scene. */ readonly cleanupError?: unknown; } /** * Transfer compatible own fields while keeping the candidate's declared shape. * Renamed, removed, and re-typed fields therefore keep their new-code defaults. */ export declare function transferDeclaredHotState(previous: HotScene, candidate: HotScene): void; /** * Owns the single scene reference consumed by a render loop and serializes hot updates. * A candidate is prepared completely before `current` changes, so failed replacements * cannot expose a partially initialized scene. */ export declare class SceneHotReloader, TContext, TState = unknown> { #private; constructor(initial: TScene, options: SceneHotReloaderOptions); get current(): TScene; replace(factory: HotSceneFactory): Promise>; } /** State intentionally preserved automatically during component replacement. */ export interface ComponentHotSnapshot { readonly position: readonly [number, number, number]; readonly quaternion: readonly [number, number, number, number]; readonly scale: readonly [number, number, number]; readonly visible: boolean; readonly layers: number; readonly renderOrder: number; readonly name: string; } export declare function captureComponentHotSnapshot(component: Object3D): ComponentHotSnapshot; export declare function restoreComponentHotSnapshot(component: Object3D, snapshot: ComponentHotSnapshot): void; /** * Explicit post-construction lifecycle. Class fields are initialized before `mount` runs; * base constructors never call an overridable lifecycle method. */ export declare abstract class ThreeComponent extends Object3D { abstract mount(context: TContext, options: TOptions): MaybePromise; abstract dispose(): MaybePromise; captureHotState?(): THotState; restoreHotState?(state: THotState): MaybePromise; } export type ThreeComponentClass = ThreeComponent> = new () => TComponent; export interface ComponentMountRequest> { readonly key: string; readonly Component: ThreeComponentClass; readonly parent: Object3D; readonly context: TContext; readonly options: TOptions; readonly index?: number; } export interface ComponentReplacementResult { readonly previous: Object3D; readonly current: TComponent; readonly cleanupError?: unknown; } export interface ComponentHotOperationContext { readonly key: string; readonly context: unknown; readonly options: unknown; } export interface ComponentHotRegistryOptions { readonly pause?: () => void; readonly resume?: () => void; /** Await newly required resources while the previous component remains mounted. */ readonly prepare?: (component: Object3D, operation: ComponentHotOperationContext) => MaybePromise; /** Compile candidate pipelines before the parent/registry transaction commits. */ readonly compile?: (component: Object3D, operation: ComponentHotOperationContext) => MaybePromise; } /** Transactional registry used by component-level `import.meta.hot.accept()` handlers. */ export declare class ComponentHotRegistry { #private; constructor(options?: ComponentHotRegistryOptions); has(key: string): boolean; get(key: string): Object3D | undefined; mount>(request: ComponentMountRequest): Promise; replace>(key: string, Component: ThreeComponentClass): Promise>; dispose(key: string): Promise; disposeAll(): Promise; } export declare function createSceneHotReloader, TContext, TState = unknown>(initial: TScene, options: SceneHotReloaderOptions): SceneHotReloader; export declare function createComponentHotRegistry(options?: ComponentHotRegistryOptions): ComponentHotRegistry;