Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...
    Index
    workers: WorkerInstance[] = []
    initPromise: Promise<void> | null = null
    readyPromise: Promise<void> | null = null

    "At least ONE worker is usable" gate, settled as soon as the first worker is published — rejected only when the attempt ends with none.

    Distinct from initPromise, which keeps its all-settled meaning. The hot path awaits THIS one: a 1024-splat first LOD rung has no use for workers 2..N, and waiting for them cost 2.23 s of a measured 8.0 s first paint (workers become ready ~160 ms apart as each compiles its own copy of the WASM module).

    Mirrors initPromise's deliberate "stays rejected" contract — it is NOT nulled on failure, so a poisoned pool keeps failing fast instead of re-running the init guard per call. dispose(), reinitialize() and the 'pool-empty' branch of handleWorkerFailure are the only resets.

    settleReady: ((error?: unknown) => void) | null = null

    Settles readyPromise: no argument resolves, an error rejects.

    nextWorkerIndex: number = 0
    poolAbortSignal: AbortSignal | undefined

    Pool-wide abort signal. When set (by setAbortSignal), every runWithTimeout call additionally races against this signal so a dataset-switch in SceneLoader can immediately settle all in-flight worker promises. The signal does not cancel WASM execution — see WorkerAbortError for the trade-off.

    Setting a new signal replaces (not chains) any previously-set signal. The new signal applies to subsequent runWithTimeout calls; already-racing promises continue with their original signal until they settle.

    initGeneration: number = 0
    pendingWorkers: Set<Worker> = ...
    • Get the configured worker count, capped by hardware concurrency

      • workerCount = 0: Auto mode, uses (hardwareConcurrency - 1)
      • workerCount > 0: Uses that number, capped at (hardwareConcurrency - 1)

      Returns number

    • Resolve as soon as the pool has ONE usable worker, instead of all of them.

      The hot path's contract. initialize() keeps the all-settled one, so anything that genuinely wants a full pool (or wants to observe the final worker count) should keep awaiting that.

      Returns Promise<void>

    • Race api.initialize() against (1) a hard init timeout and (2) the worker's own onerror/onmessageerror events.

      The pool's permanent attachWorkerErrorHandlers evicts a failed worker via handleWorkerFailure, but during pool init the worker isn't in this.workers yet — so handleWorkerFailure finds nothing to evict and the dangling Comlink initialize() promise never settles. (Repro: route-block the worker script in a Playwright test; the page hangs at boot.)

      We attach a short-lived listener that rejects the init promise when the worker fails before it joins the pool. The init timeout is the belt-and-suspenders fallback — even if no error event fires (e.g. a network stall that never resolves), we eventually reject and let the caller fall back to the main thread.

      Parameters

      • worker: Worker
      • api: Remote<
            {
                initialize: (
                    wasmPath?: string,
                    wasmModule?: Module,
                ) => Promise<WorkerInitResult>;
                decodeQuantized: (
                    p: {
                        data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                        bounds: [number, number];
                        dtype: "uint8" | "uint16";
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                decodeLogScalar: (
                    p: {
                        data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                        maxLog: number;
                        dtype: "uint8" | "uint16";
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                decodeGeologScalar: (
                    p: {
                        data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                        minLog: number;
                        maxLog: number;
                        dtype: "uint8" | "uint16";
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                decodePerChannel: (
                    p: {
                        data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                        kind: PerChannelKind;
                        colLo: Float64Array;
                        colHi: Float64Array;
                        zeroLevel: boolean;
                        colOffset: number;
                        bits: 8 | 16;
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                decodeLUT: (
                    p: {
                        indices: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                        lut: number[];
                        k: number;
                        lutMode: "row" | "scalar";
                        dtype?: "uint8" | "uint16";
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                decodeBroadcasted: (
                    p: {
                        value: Float32Array;
                        numPoints: number;
                        elementsPerPoint: number;
                    },
                ) => Promise<Float32Array<ArrayBufferLike>>;
                projectLinesTo3D: (
                    p: {
                        positions: Float32Array;
                        segments: Uint32Array;
                        widths: Float32Array;
                        colors:
                            | Uint8Array<ArrayBufferLike>
                            | Float32Array<ArrayBufferLike>
                            | Uint16Array<ArrayBufferLike>
                            | null;
                        sharpness: Float32Array<ArrayBufferLike> | null;
                        scalars:
                            | Uint8Array<ArrayBufferLike>
                            | Float32Array<ArrayBufferLike>
                            | Float16Array<ArrayBufferLike>
                            | null;
                        viewState: ProjectionViewState;
                        ndim: number;
                        segmentCount: number;
                        colorComponents?: 3 | 4;
                        emitSourceIndices?: boolean;
                    },
                ) => Promise<
                    {
                        startPositions: Float32Array;
                        endPositions: Float32Array;
                        startColors: Float32Array;
                        endColors: Float32Array;
                        startWidths: Float32Array;
                        endWidths: Float32Array;
                        startSharpness: Float32Array;
                        endSharpness: Float32Array;
                        startScalars: Float32Array;
                        endScalars: Float32Array;
                        startAlphas: Float32Array;
                        endAlphas: Float32Array;
                        segmentLengths: Float32Array;
                        startJointCode: Float32Array;
                        endJointCode: Float32Array;
                        visibleSegmentCount: number;
                        bounds?: LinesProjectionBounds;
                        sourceSegmentIndices?: Uint32Array<ArrayBufferLike>;
                    },
                >;
                projectGSplatsTo3D: (
                    p: {
                        positions: Float32Array;
                        choleskyFactors: Float32Array;
                        amplitudes: Float32Array;
                        colors:
                            | Uint8Array<ArrayBufferLike>
                            | Float32Array<ArrayBufferLike>
                            | Uint16Array<ArrayBufferLike>
                            | null;
                        sharpness: Float32Array<ArrayBufferLike> | null;
                        viewState: ProjectionViewState;
                        ndim: number;
                        splatCount: number;
                        discreteDims?: readonly number[];
                        discreteSteps?: Record<number, number>;
                        extendToAllDims?: readonly number[];
                        truncate?: number;
                        colorComponents?: 3 | 4;
                        emitSourceIndices?: boolean;
                    },
                ) => Promise<
                    {
                        centers3D: Float32Array;
                        choleskyFactors3D: Float32Array;
                        amplitudes: Float32Array;
                        colors: Float32Array;
                        visibleCount: number;
                        bounds?: GSplatsProjectionBounds;
                        sourceIndices?: Uint32Array<ArrayBufferLike>;
                    },
                >;
            },
        >
      • workerNumber: number
      • OptionalwasmPath: string

      Returns Promise<WorkerInitResult>

    • Install onerror and onmessageerror handlers on a freshly-created worker so a crash inside the worker (uncaught throw, OOM during WASM init, unserializable Comlink message) surfaces as a logged failure and is removed from the active pool, rather than escaping to the browser's window.onerror and freezing requests that are awaiting Comlink replies from this worker.

      Note: this is a best-effort safety net. Comlink-wrapped calls that are mid-flight when the worker dies will still hang their callers — route hot paths through runWithTimeout for the per-call timeout that complements this handler.

      Parameters

      • worker: Worker
      • workerNumber: number

      Returns void

    • Remove a failed worker from the pool and terminate it. If this drops the pool to zero workers, log a clear error so the surrounding application can decide whether to fall back to the main-thread implementation or surface a failure dialog.

      Parameters

      • worker: Worker
      • reason: string

      Returns void

    • Explicitly reset the pool's cached init promise so the next getWorker / runWithTimeout call re-runs init. Used to recover from a transient init failure (e.g. the worker chunk was briefly unreachable) without restarting the entire app.

      Routine "init failed once, fall back" cases should NOT call this — letting the rejected promise stick keeps subsequent calls fast (instant reject) instead of stacking 10s init guards.

      Returns void

    • Race a worker-routed Promise against a timeout. On timeout, log the failure, evict the responsible worker (if known) via handleWorkerFailure, and reject with WorkerTimeoutError. A timeoutMs of 0 disables the timeout — callers that don't need it can still use this helper as a thin pass-through to keep the call-site uniform.

      worker may be omitted when the caller cannot identify which worker handled the call (e.g. round-robin selection); the timeout still fires, but the pool isn't pruned.

      Type Parameters

      • T

      Parameters

      • operation: string
      • call: Promise<T>
      • timeoutMs: number
      • Optionalworker: Worker

      Returns Promise<T>

    • Get a worker API using round-robin selection.

      Untracked callers receive workers in rotating order. For load-aware selection (picking the worker with the fewest active queries), use getWorkerWithTracking instead.

      Important — no timeout guard. Direct await on the returned Remote<DataWorkerAPI> lets a dead/stuck worker hang the caller indefinitely (Comlink's onerror handler can't settle an in-flight promise). Production code MUST go through runWithTimeout instead — it routes the call through withTimeout on a round-robin-selected worker. This direct getWorker() accessor is intentionally retained for tests and low-level worker-pool unit tests that need raw access; lint-grep for new production uses periodically.

      Returns Promise<
          Remote<
              {
                  initialize: (
                      wasmPath?: string,
                      wasmModule?: Module,
                  ) => Promise<WorkerInitResult>;
                  decodeQuantized: (
                      p: {
                          data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                          bounds: [number, number];
                          dtype: "uint8" | "uint16";
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  decodeLogScalar: (
                      p: {
                          data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                          maxLog: number;
                          dtype: "uint8" | "uint16";
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  decodeGeologScalar: (
                      p: {
                          data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                          minLog: number;
                          maxLog: number;
                          dtype: "uint8" | "uint16";
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  decodePerChannel: (
                      p: {
                          data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                          kind: PerChannelKind;
                          colLo: Float64Array;
                          colHi: Float64Array;
                          zeroLevel: boolean;
                          colOffset: number;
                          bits: 8 | 16;
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  decodeLUT: (
                      p: {
                          indices: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                          lut: number[];
                          k: number;
                          lutMode: "row" | "scalar";
                          dtype?: "uint8" | "uint16";
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  decodeBroadcasted: (
                      p: {
                          value: Float32Array;
                          numPoints: number;
                          elementsPerPoint: number;
                      },
                  ) => Promise<Float32Array<ArrayBufferLike>>;
                  projectLinesTo3D: (
                      p: {
                          positions: Float32Array;
                          segments: Uint32Array;
                          widths: Float32Array;
                          colors:
                              | Uint8Array<ArrayBufferLike>
                              | Float32Array<ArrayBufferLike>
                              | Uint16Array<ArrayBufferLike>
                              | null;
                          sharpness: Float32Array<ArrayBufferLike> | null;
                          scalars:
                              | Uint8Array<ArrayBufferLike>
                              | Float32Array<ArrayBufferLike>
                              | Float16Array<ArrayBufferLike>
                              | null;
                          viewState: ProjectionViewState;
                          ndim: number;
                          segmentCount: number;
                          colorComponents?: 3 | 4;
                          emitSourceIndices?: boolean;
                      },
                  ) => Promise<
                      {
                          startPositions: Float32Array;
                          endPositions: Float32Array;
                          startColors: Float32Array;
                          endColors: Float32Array;
                          startWidths: Float32Array;
                          endWidths: Float32Array;
                          startSharpness: Float32Array;
                          endSharpness: Float32Array;
                          startScalars: Float32Array;
                          endScalars: Float32Array;
                          startAlphas: Float32Array;
                          endAlphas: Float32Array;
                          segmentLengths: Float32Array;
                          startJointCode: Float32Array;
                          endJointCode: Float32Array;
                          visibleSegmentCount: number;
                          bounds?: LinesProjectionBounds;
                          sourceSegmentIndices?: Uint32Array<ArrayBufferLike>;
                      },
                  >;
                  projectGSplatsTo3D: (
                      p: {
                          positions: Float32Array;
                          choleskyFactors: Float32Array;
                          amplitudes: Float32Array;
                          colors:
                              | Uint8Array<ArrayBufferLike>
                              | Float32Array<ArrayBufferLike>
                              | Uint16Array<ArrayBufferLike>
                              | null;
                          sharpness: Float32Array<ArrayBufferLike> | null;
                          viewState: ProjectionViewState;
                          ndim: number;
                          splatCount: number;
                          discreteDims?: readonly number[];
                          discreteSteps?: Record<number, number>;
                          extendToAllDims?: readonly number[];
                          truncate?: number;
                          colorComponents?: 3 | 4;
                          emitSourceIndices?: boolean;
                      },
                  ) => Promise<
                      {
                          centers3D: Float32Array;
                          choleskyFactors3D: Float32Array;
                          amplitudes: Float32Array;
                          colors: Float32Array;
                          visibleCount: number;
                          bounds?: GSplatsProjectionBounds;
                          sourceIndices?: Uint32Array<ArrayBufferLike>;
                      },
                  >;
              },
          >,
      >

    • Pick the kind-appropriate timeout from config. Projection AND decode share workerProjectionTimeoutMs (both are long-running CPU-bound calls — a dedicated decode knob can be added later if telemetry shows a need).

      Parameters

      Returns number

    • Run a worker call through withTimeout on a round-robin-selected worker. The single production entry point for any Comlink-routed call that needs a hang-detection guard — direct await against a worker Remote lets a dead worker hang the caller forever (the onerror handler can't settle a Comlink promise that's already in flight).

      On timeout the responsible worker is evicted via handleWorkerFailure and the caller receives a WorkerTimeoutError. The geometry loaders deliberately do NOT run the projection in-process on a timeout (see isWorkerInfrastructureError) — the failure is recorded and the node retried against a fresh worker instead of blocking the UI thread.

      Type Parameters

      • T

      Parameters

      • op: string
      • kind: TimeoutKind
      • fn: (
            api: Remote<
                {
                    initialize: (
                        wasmPath?: string,
                        wasmModule?: Module,
                    ) => Promise<WorkerInitResult>;
                    decodeQuantized: (
                        p: {
                            data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                            bounds: [number, number];
                            dtype: "uint8" | "uint16";
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    decodeLogScalar: (
                        p: {
                            data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                            maxLog: number;
                            dtype: "uint8" | "uint16";
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    decodeGeologScalar: (
                        p: {
                            data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                            minLog: number;
                            maxLog: number;
                            dtype: "uint8" | "uint16";
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    decodePerChannel: (
                        p: {
                            data: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                            kind: PerChannelKind;
                            colLo: Float64Array;
                            colHi: Float64Array;
                            zeroLevel: boolean;
                            colOffset: number;
                            bits: 8 | 16;
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    decodeLUT: (
                        p: {
                            indices: Uint8Array<ArrayBufferLike> | Uint16Array<ArrayBufferLike>;
                            lut: number[];
                            k: number;
                            lutMode: "row" | "scalar";
                            dtype?: "uint8" | "uint16";
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    decodeBroadcasted: (
                        p: {
                            value: Float32Array;
                            numPoints: number;
                            elementsPerPoint: number;
                        },
                    ) => Promise<Float32Array<ArrayBufferLike>>;
                    projectLinesTo3D: (
                        p: {
                            positions: Float32Array;
                            segments: Uint32Array;
                            widths: Float32Array;
                            colors:
                                | Uint8Array<ArrayBufferLike>
                                | Float32Array<ArrayBufferLike>
                                | Uint16Array<ArrayBufferLike>
                                | null;
                            sharpness: Float32Array<ArrayBufferLike> | null;
                            scalars:
                                | Uint8Array<ArrayBufferLike>
                                | Float32Array<ArrayBufferLike>
                                | Float16Array<ArrayBufferLike>
                                | null;
                            viewState: ProjectionViewState;
                            ndim: number;
                            segmentCount: number;
                            colorComponents?: 3 | 4;
                            emitSourceIndices?: boolean;
                        },
                    ) => Promise<
                        {
                            startPositions: Float32Array;
                            endPositions: Float32Array;
                            startColors: Float32Array;
                            endColors: Float32Array;
                            startWidths: Float32Array;
                            endWidths: Float32Array;
                            startSharpness: Float32Array;
                            endSharpness: Float32Array;
                            startScalars: Float32Array;
                            endScalars: Float32Array;
                            startAlphas: Float32Array;
                            endAlphas: Float32Array;
                            segmentLengths: Float32Array;
                            startJointCode: Float32Array;
                            endJointCode: Float32Array;
                            visibleSegmentCount: number;
                            bounds?: LinesProjectionBounds;
                            sourceSegmentIndices?: Uint32Array<ArrayBufferLike>;
                        },
                    >;
                    projectGSplatsTo3D: (
                        p: {
                            positions: Float32Array;
                            choleskyFactors: Float32Array;
                            amplitudes: Float32Array;
                            colors:
                                | Uint8Array<ArrayBufferLike>
                                | Float32Array<ArrayBufferLike>
                                | Uint16Array<ArrayBufferLike>
                                | null;
                            sharpness: Float32Array<ArrayBufferLike> | null;
                            viewState: ProjectionViewState;
                            ndim: number;
                            splatCount: number;
                            discreteDims?: readonly number[];
                            discreteSteps?: Record<number, number>;
                            extendToAllDims?: readonly number[];
                            truncate?: number;
                            colorComponents?: 3 | 4;
                            emitSourceIndices?: boolean;
                        },
                    ) => Promise<
                        {
                            centers3D: Float32Array;
                            choleskyFactors3D: Float32Array;
                            amplitudes: Float32Array;
                            colors: Float32Array;
                            visibleCount: number;
                            bounds?: GSplatsProjectionBounds;
                            sourceIndices?: Uint32Array<ArrayBufferLike>;
                        },
                    >;
                },
            >,
        ) => Promise<T>
      • Optionalsignal: AbortSignal

      Returns Promise<T>

    • Set or clear the pool-wide abort signal. Every subsequent runWithTimeout call additionally races against this signal. Used by SceneLoader.loadScene to immediately settle worker tasks queued by the previous dataset when the user switches datasets.

      Pass undefined to clear (no pool-wide signal — only caller- supplied signals apply).

      Setting a new signal replaces (not chains) any previously-set signal. Already-racing promises continue with their original effective signal until they settle.

      Parameters

      • signal: AbortSignal | undefined

      Returns void

    • Combine the pool-wide signal with a caller-supplied signal into a single scoped abort source. Returns undefined when both are absent. Uses native AbortSignal.any when available (modern browsers / Node 20+) and falls back to the simpler "trip either one" wiring for older runtimes; the returned scope's dispose() releases the fallback's source listeners once the call settles.

      Parameters

      • a: AbortSignal | undefined
      • b: AbortSignal | undefined

      Returns CombinedSignalScope | undefined

    • Get a worker with query tracking for load balancing.

      Returns the worker api, the underlying worker (for eviction-on-timeout), and callbacks to mark query start/end so the active-queries counter reflects in-flight load.

      Used by runWithTimeout to route hot-path calls to the least-loaded worker. A stalled worker stops being selected once its activeQueries grows past the others — without this, the round-robin fallback would queue new calls on the stalled worker until it timed out individually.

      Returns Promise<TrackedWorkerHandle>

    • Convenience accessor for the aggregate "in-flight task" count. Exposed in __luxarDebug.workers.queueDepth for live diagnostics of prefetch backpressure / dataset-switch task accumulation.

      Returns number

      The number of worker tasks currently in flight across the pool (sum of activeQueries per worker). Zero when the pool is idle.

    • Clean up all worker resources.

      Also terminates workers still pending init (via pendingWorkers) and bumps initGeneration so any factories still in flight detect the dispose and self-terminate when they resolve.

      Returns void