SliceCache ("S-cache") — a per-(node, view) LRU of decoded per-slice geometry.
Sits ABOVE the L0/L1/L2 chunk caches. Where those are keyed by chunk and skip
only decompression, the SliceCache is keyed by the view (a node path + the
query's slice/tolerance/displayDims signature) and caches the fully decoded
per-slice geometry a progressive loader assembled. That lets revisiting a
slice — e.g. scrubbing back to a timepoint in a 4D dataset — skip the whole
query + fetch + dequant + gather pipeline (~100 ms on a large timelapse) and
only re-run the cheap nD→3D projection downstream.
The payload is OPAQUE to this cache: the owning loader stores a cloned snapshot
of its decoded per-LOD data and casts it back on retrieval. The clone is the
loader's responsibility because its decoded arrays are views into a reused
accumulator buffer (see the spatial-index loaders) — a cross-view cache must
not alias buffers the next load overwrites. The cache only tracks bytes for
its byte-budget LRU eviction, so the loader passes the retained byte count.
Invalidation: content-hash change / dataset switch clears the whole cache
(wired next to L0 in cache-setup.ts). The view signature in the key covers
slice/tolerance/displayDims; nothing projection-affecting (truncate, colormap,
opacity) enters the key because projection re-runs on every hit.
PRE- vs POST-projection payloads (a deliberate, inherent asymmetry):
Lines/GSplats cache PRE-projection decoded data — their projection is a
downstream worker step owned by the scene-loader's data processors. Note the
projection DOES re-run on a slice REVISIT (a scrub-back bumps the progressive
loader's reset generation, so the memoized concat yields a NEW object
reference and the handlers' isAlreadyCommitted identity fast path does NOT
fire — that fast path only skips a redundant re-commit of the CURRENT view).
The reason projection is not cached post-hoc here is that gsplat projection
depends on the live uTruncate material uniform (it feeds
project_gsplats_nd_to_3d and changes the visible count), which is outside
this cache's view key — so a post-projection payload would need to key on
(and invalidate with) rendering controls, coupling this cache to the
processors. Points caches POST-projection data because its projection is
folded into the loader itself and consumes only key fields + node-static
context (no live uniform) — so a hit safely skips the WASM projection too.
SliceCache ("S-cache") — a per-(node, view) LRU of decoded per-slice geometry.
Sits ABOVE the L0/L1/L2 chunk caches. Where those are keyed by chunk and skip only decompression, the SliceCache is keyed by the view (a node path + the query's slice/tolerance/displayDims signature) and caches the fully decoded per-slice geometry a progressive loader assembled. That lets revisiting a slice — e.g. scrubbing back to a timepoint in a 4D dataset — skip the whole query + fetch + dequant + gather pipeline (~100 ms on a large timelapse) and only re-run the cheap nD→3D projection downstream.
The payload is OPAQUE to this cache: the owning loader stores a cloned snapshot of its decoded per-LOD data and casts it back on retrieval. The clone is the loader's responsibility because its decoded arrays are views into a reused accumulator buffer (see the spatial-index loaders) — a cross-view cache must not alias buffers the next load overwrites. The cache only tracks bytes for its byte-budget LRU eviction, so the loader passes the retained byte count.
Invalidation: content-hash change / dataset switch clears the whole cache (wired next to L0 in cache-setup.ts). The view signature in the key covers slice/tolerance/displayDims; nothing projection-affecting (truncate, colormap, opacity) enters the key because projection re-runs on every hit.
PRE- vs POST-projection payloads (a deliberate, inherent asymmetry): Lines/GSplats cache PRE-projection decoded data — their projection is a downstream worker step owned by the scene-loader's data processors. Note the projection DOES re-run on a slice REVISIT (a scrub-back bumps the progressive loader's reset generation, so the memoized concat yields a NEW object reference and the handlers'
isAlreadyCommittedidentity fast path does NOT fire — that fast path only skips a redundant re-commit of the CURRENT view). The reason projection is not cached post-hoc here is that gsplat projection depends on the liveuTruncatematerial uniform (it feedsproject_gsplats_nd_to_3dand changes the visible count), which is outside this cache's view key — so a post-projection payload would need to key on (and invalidate with) rendering controls, coupling this cache to the processors. Points caches POST-projection data because its projection is folded into the loader itself and consumes only key fields + node-static context (no live uniform) — so a hit safely skips the WASM projection too.