Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module data/scene-loader/prefetch/slice-prefetcher

    SlicePrefetcher — projected t+1 prefetch during dimension playback.

    While a dimension is PLAYING, refinement is suppressed (the progressive loaders report hasMoreLODs === false under a frame budget), leaving an idle window between a tick's commit and the next tick. This prefetcher uses that window to build the NEXT timepoint's decoded ladder and store it in the shared SliceCache under the t+1 view signature, so the next real tick's restoreLadder hits instantly and its whole frame budget goes to DEEPENING the prefix instead of rebuilding it. Being driven by DimensionAnimationManager.peekNextValue, it is loop/bounce/backward aware — in particular it warms the loop WRAP (t=max → t=min), which the linear-extrapolation chunk prefetch cannot predict.

    The foreground loaders CANNOT be reused for a concurrent prefetch: they hold mutable per-instance state (_activeSignal read by the RangeLoader signal-source and the L0 proxy, a REUSED accumulator whose returned arrays the next load overwrites, loadedLODs/lastViewState in the progressive wrappers). And SceneLoader.updateView is single-flight — routing a prefetch through it would abort/supersede the foreground pass and merge t+1 into the persistent view state (stuck-display hazard).

    So each registered node gets a lazily-built SHADOW loader from the same factory helpers: own accumulator, own signal, zero shared mutable state with the foreground. The S-cache IS the handoff — the shadow's own updateView does restore→deepen→store (it carries a frameBudgetMs, which bounds how far one pass deepens ≈ one cold level and makes the progressive loaders store the deepened prefix), and the foreground restores on the real tick. Shadows are deliberately NOT monitor-connected (the factory is side-effect-free by design), so shadow loads never double-count metrics.

    A cold LOD level takes longer than one playback frame to decode, so the shadow deepen must NOT be aborted every tick — the foreground therefore does NOT preempt it. Instead prefetch is a no-op while a batch is still in flight (see inFlight): the running deepen completes and caches its level, and the next FREE tick re-targets at the then-current predicted view. Across playback loops this fills the SliceCache toward full ladders, so cached quality climbs while the foreground stays responsive.

    This is safe because the shadow runs on its own loader instances (own accumulator + signal), decodes on the worker pool, and only writes the shared SliceCache under content-keyed entries — it cannot stall or corrupt a foreground tick. prefetch() is fire-and-forget (never awaited; every rejection, including expected AbortErrors, is swallowed); its fetches share the global 24-slot data fetch lane and are bounded by the budget + abort. abortInFlight() / releaseShadows() (playback end) / dispose() tear it down.

    SlicePrefetcher
    SlicePrefetcherCtx