# three-blocks

## 0.14.0

### Minor Changes

- ec85229: Library: Gaussian splats keep their trained colors and full view-dependent shading by default.

  Every 3DGS trainer alpha-blends display-encoded colors, but a color-managed `WebGPURenderer` blends in
  linear light and encodes afterwards, which lifted and desaturated translucent stacks such as fur
  (measured on an SH3 capture: 22.4 dB against the ground-truth render, 27.2 dB after). The new default
  `compositing: 'faithful'` blends the stored colors as trained under any tone mapping or output color
  space by bracketing the splat draw with a scene copy and a display-space resolve. `'display'` stays
  the zero-cost path for `NoToneMapping` + `LinearSRGBColorSpace` output, and `'linear'` restores the
  previous default. Lit mode, MRT passes and the compute-tile renderer keep rendering as `'linear'`.
  `sh: 'auto'` now renders every spherical-harmonics band the file carries instead of stopping at
  degree 2.
  PLY and SOG loading no longer clamp each splat's base color to [0, 1] before the view-dependent bands
  are added: trained base colors overshoot that range (one in five splats of a fur capture), and
  clamping them first put a per-splat color error on fine structures such as individual hairs.

- ec85229: Library: Gaussian splats of a rigged character animate with its skeleton, clips and shape keys.

  `SplatSkin` (from `three-blocks/gaussian-splats`) binds every splat to the closest point of a rigged
  glTF's rest-pose surface on the GPU, then re-poses the splats each frame from the skeleton and the
  meshes' `morphTargetInfluences`, so a plain `AnimationMixer` drives them like a `SkinnedMesh`.
  Each splat also takes the deformation gradient of its bound triangle, so it turns, stretches and
  shears with the skin; `{ deformation: 'rigid' }` keeps bone rotation only.
  `three-blocks tools splat <scene.blend> --skinned` captures the rest pose and writes the matching
  `<subject>.rig.glb` (armature, shape keys and clips) next to the splat.

- ec85229: Library: Walk through Gaussian splat rooms and bounce balls off their surfaces.

### Patch Changes

- ec85229: Library: Dense Gaussian splat close-ups render faster with correct depth ordering.
- ec85229: Library: Gaussian splat close-ups no longer reveal block-shaped holes near the camera.

## 0.13.0

### Minor Changes

- c5cca15: Devtools: The shader watch command, the 186dev Three.js lane and Playwright driver names are gone.

  Removed from `@three-blocks/devtools`: `three-blocks shaders watch`, `watchShaders`, `ShaderWatchQueue` and
  their option types (captures are release artifacts, never edit-loop validation); and
  `createPlaywrightShaderDriver`, `createStaticPlaywrightShaderDriver`,
  `createAttachedPlaywrightShaderDriver` with their `Playwright*` option types — `createShaderDriver()` and
  `ShaderDriverOptions` take the same `serve` / `base` / `url` options, and capture has been Node-native for a release.

  Removed from `three-blocks/shaders`: the pre-release `186dev` lane (`assertThreeWebGPU186Dev`,
  `createThreeWebGPU186DevShaderCompatibility`, `THREE_R186DEV_VERSION`,
  `THREE_WEBGPU_R186DEV_COMPATIBILITY`) and `THREE_BLOCKS_THREE_186DEV_HOOK_TRANSFORM_VERSION` from
  `three-blocks/vite`. Released Three.js 0.186.x is the supported revision and 0.185.x
  stays frozen for one release.

- c5cca15: Devtools: Development names the shaders that compile after the first frame, once per burst.

  `observeThreeBlocksTslBuilds()` (used by `registerDevtools()` and the worker shell in development)
  counts the NodeBuilder builds that run after `freezeFirstLoad()` and, two seconds after the last one,
  prints one `console.info` naming them by material (`splat-velocity ×2, compute`), at most three times
  per session. A material that only renders on first use hitches that interaction whether shaders are
  precompiled or not; late-arriving assets are an expected cause and the line says so.
  `ThreeBlocksTslBuildSnapshot.firstLoadBuilds` makes the late count derivable (`builds - firstLoadBuilds`).

- c5cca15: CLI: One check command verifies types, the production build and every scene, with a PNG per scene.

  `npx three-blocks check [--json]` (devtools `runProjectCheck()`) runs the project's own TypeScript, builds
  the production bundle once in `strict` mode (which captures its shaders), and boots every configured
  scene natively in Node. Each route reports its lifecycle, console and page errors, the reported shader
  mode with `injected` / `missed` / `live` counters, and a PNG of its settled frame under
  `.three-blocks/check/`. `BrowserPreviewOptions.screenshots` and `BrowserPreviewRouteReport.shaders` /
  `.screenshot` expose the same to `three-blocks browser preview`. Generated projects gain a `check`
  script and ignore `.three-blocks/check/`.

- c5cca15: Library: Vite builds capture precompiled shaders from the built bundle; nothing to commit.

  When no fresh committed capture exists and `@three-blocks/devtools` is installed, `vite build` loads the
  bundle it has just written natively in Node and writes
  `<outDir>/three-blocks/shaders/<scene>.<backend>.json`. `shaders: { capture: false }` opts out.
  `ThreeBlocksShaderBuildConfig.built` and `ShaderBuildState.built` carry the public path;
  `installShaderCache()` then loads the manifest from there instead of calling `loadManifest`, so
  `registerDevtools()`, the worker shell and `installShaderCache( { state: threeBlocksShaders } )` need no
  change. `InstallShaderCacheOptions.loadManifest` and `CreateWorkerRuntimeOptions.loadShaderManifest`
  become optional: without a loader the manifest is fetched from `<base>three-blocks/shaders/`
  (`InstallShaderCacheOptions.base`), which also serves a committed capture's public twin, so a build
  host without a GPU can keep a committed cache with no template code. For such a bundle `strict`
  fails the build when the capture fails, instead of stopping a stale receipt at `buildStart`; a host
  without a GPU adapter otherwise ships a correct, live-compiling output. `base` must be an absolute path.

  `captureBuiltShaders()` and `three-blocks shaders capture --serve <dir> --built [--base <path>]` run the
  same engine after any bundler's build. A production bundle no longer needs capture instrumentation:
  the shader runtime hands its renderer to the capture host the Node driver injects
  (`offerRendererToShaderCapture`), the Node renderer can run an init script inside worker threads
  (`addInitScript( { content, workers: true } )`), and the static driver injects its runtime that way.
  Capture classification no longer depends on `constructor.name`, which a minified bundle mangles, and
  the Node DOM applies the user-agent defaults for headings, bold and italic text.

- c5cca15: Starter: Add a scene by adding a folder; the build captures it and the check command boots it.

  A generated project grows by `src/scenes/<name>/scene.ts`, opened with `?scene=<name>`. The worker
  resolves it through one registry (`boot.flags.scene`, a new runtime flag relayed by the app shell),
  the shader tool enumerates the same folders, so `vite build` captures the new scene and
  `three-blocks check` boots it and writes its PNG. An unknown `?scene=` fails with the known scenes.

- c5cca15: Library: Three.js r186 is supported, and development always compiles shaders live until previewed.

  `THREE_BLOCKS_SUPPORTED_THREE_RANGE` widens to `>=0.185.0 <0.187.0` and `isSupportedThreeVersion`
  exposes the same gate to the other bundler adapters. `createThreeWebGPUShaderCompatibility` and
  `createThreeWebGLShaderCompatibility` now route to the installed release, so application code
  survives the upgrade unchanged; `createThreeShaderCompatibility` and `threeShaderCompatibilityId`
  select by backend. On an unverified Three.js revision `threeBlocks()` and the non-Vite adapters warn
  once and compile live instead of throwing; strict builds and captures still stop.

  Development always compiles TSL live, because the next edit strands any receipt: the worker shell,
  `registerDevtools()` and the `threeBlocksShaders` export (`mode: 'live'`) hydrate only on an explicit
  preview, and `ShaderBuildState.mode` lets `installShaderCache()` treat live over a fresh receipt as a
  choice (no warning, never strict). The overlay offers "Preview production shaders" / "Back to live
  TSL"; a preview whose receipt goes stale returns to live by itself, and the policy-changed full
  reload is gone. Its toggle is a plain `?tbShaders=live|precompiled` preference instead of the parity
  harness flag that froze the starter after one frame. `readThreeBlocksRuntimeFlags` parses it on the
  page, `WorkerBootState` relays it as `flags`, and `CreateWorkerRuntimeOptions` accepts it, so a
  worker-owned renderer honours the page's shader mode and its `?webgl=1` backend switch.

  Hydration no longer takes retained-input ordinals (an application that rendered before creating its
  inputs, such as `PMREMGenerator.fromScene()` ahead of `bloom()`, bound the wrong uniform); recipes
  cover r186's `highpModelViewMatrix`, `SunLight` cascades and after-object instancing. Parity
  failures now carry a state-oracle verdict (`ShaderCaptureStats.stateOracle`,
  `TestShadersOptions.stateOracle`, the optional `stateOracle` argument of `ShaderBrowserDriver.observe`).
  Receipt transform 65 strands earlier receipts: recapture.

### Patch Changes

- 53ea952: Library: Precompiled ambient occlusion no longer crashes on its first frame on Three.js r186.

  Three.js r186 `GTAONode` builds its material in the constructor and leaves `setup()` to assign the
  `_ao` callable that `updateBefore()` invokes. Hydration skips `setup()`, and the adapter only
  re-ran it for an addon pass node whose private _material_ was null, so a hydrated GTAO threw
  `this._ao is not a function` on its first frame. The adapter now primes an addon pass node that
  holds any null private state, once per node. `SSRNode` follows the same pattern with `_ssrFn`.

- c5cca15: CLI: JSON output of devtools commands no longer starts with a banner line.

  `three-blocks <devtools command> --json` printed "Running @three-blocks/devtools" on stdout before
  the forwarded document, so a program could not parse it. The banner is skipped under `--json`.

- c5cca15: Library: Ambient occlusion loads precompiled on WebGPU instead of compiling at startup.

  Three.js r186 declares a sampler for a gathered texture (`texture.gather()`) even over a depth
  texture. GTAO reads depth that way, and the captured state addressed the view as the pass texture
  node it was cloned from, so the hydrated bind group lacked that sampler and every GTAO pass fell
  back to a live build. A gathered view now gets its own `textureReference` recipe with a `gather`
  flag, and hydration restores the sampler. Recapture to pick this up.

- c5cca15: Library: Ambient occlusion compiles again with antialiasing on Three.js r186.

  Three.js r186's `GTAONode` reads its centre depth with `gather()`, and WGSL has no `textureGather()`
  overload for multisampled textures, so `ao( scenePass.getTextureNode( 'depth' ), … )` on an
  `antialias: true` renderer failed to compile (it worked on r185). The r186 in-memory patch lane, shared
  by `threeBlocks()` and the webpack, Rollup, esbuild and Next.js adapters, now carries
  [three.js #34609](https://github.com/mrdoob/three.js/pull/34609) verbatim: `generateTextureGather()`
  falls back to four `textureLoad()` calls for multisampled textures. It is removed when a supported
  release contains that pull request. The lane identifier moves to `r186-provider-v2`; receipts are
  unaffected, because no shader that needed this fix could be captured before.

## 0.12.1

### Patch Changes

- 02f3072: Devtools: Run shader captures and project checks in Node with fewer dependencies.

## 0.12.0

### Minor Changes

- aa1d655: Packages: Gaussian splats now use one full-quality default in the library and benchmark.

### Patch Changes

- aa1d655: Library: Screen-space MSDF text now keeps pixel-snapped glyph baselines crisp.
- aa1d655: Packages: Gaussian splats shade and sort visible splats for smoother camera movement.
- aa1d655: Packages: Gaussian splats send leaner per-splat vertex data, trimming the slowest frames.
- aa1d655: Packages: Baked Motion avoids duplicate downloads and ships smaller examples and exports.
- aa1d655: Packages: Splats use less memory, with full frame benchmarks for r186 and SuperSplat 3.

## 0.11.0

### Minor Changes

- 88a9a83: Library: Baked Motion automatically prefers HEVC and falls back to AVC on every device.

  Every rendition width is now encoded once per codec rung, and playback walks that order until
  one decodes: a device with hardware HEVC takes the smaller download, and AVC stays the floor
  because it is the only rung with universal software decode. The codec is not a caller option
  anywhere — CLI, wizard, Blender add-on, or `encodeUTSBV`. Rendition ordering is codec-aware in
  the manifest parser, so the efficient rung can no longer be shadowed by an alphabetical
  tiebreak. The HEVC rung carries a CRF offset because CRF is not a shared scale between the two
  codecs; without it the efficient codec produces the larger file.

  The resident proxy, the opt-in `preload` strategy, and the tilt held-composite lane are removed
  together — they shared their decode, texture-array, and crossfade machinery. Presentation is now
  poster → full. `BakedMotionOptions` loses `strategy`, `proxyOnly`, `vramBudget`, and
  `maxTextureArrayLayers`; `BakedMotion` loses `strategy` and `prewarmPipelineVariants()`;
  diagnostics lose `residency.proxy`; and packages no longer carry `resources.proxy`.

  The wire manifest has a single version with a single schema (`baked-motion.schema.json`), and
  every rendition is per-view: one decoded video frame is one camera view. Packed multi-view
  renditions are gone — they answered pointer jumps 4.4x slower while costing 2.2x the bytes per
  delivered pixel. `utsbv refresh` preserves and rebuilds codec ladders, and quantizes depth one
  step finer than an original bake so a re-encode does not compound its loss.

- 88a9a83: Packages: Indirect batching and its dependent examples are no longer included.
- 88a9a83: Library: SDFFieldNodes provides reusable distance, normal, shadow, and occlusion nodes.

### Patch Changes

- 88a9a83: Tools: Blender reports consistent hub and Mesh to Splat versions in every install mode.
- 88a9a83: Library: Baked Motion tilt packages can ship a coarse all-view atlas for undecoded corners.
- 88a9a83: Library: Baked Motion can author narrower depth tracks to reduce package downloads.
- 88a9a83: Library: Baked Motion bounds tilt warp reprojection so a starved blend goes stale, not stretched.

  A pointer moving faster than corners can decode leaves slots bound to stale or predicted
  views. The reprojection those slots were asked for grew with how far behind decode had
  fallen, and a forward warp's rubber-sheet triangles widen with their view's pose delta —
  visible as stretched geometry leaking past silhouette edges. The weight-authority term that
  normally crushes those sheets is relative, so it cannot suppress one when the closer views
  are exactly the ones still decoding.

  A complete bilinear blend never asks for more than one grid step, so reprojection now stops
  there. Presentation falls behind the pointer under starvation rather than tearing, and
  recovery stays continuous because the clamp bounds the value rather than switching lanes.
  Measured across every settled tilt stage-gate pose, the largest reprojection is 0.69 steps,
  so healthy presentation is untouched: both gate assets return identical pose and sweep
  metrics before and after.

- 88a9a83: Library: Large PLY splat files now load through bundled workers.
- 88a9a83: Library: Baked Motion preserves atlas alpha, resolves paused seeks, and fits mobile budgets.
- 88a9a83: Library: Gaussian splats keep equal-depth ordering stable and avoid duplicate tile staging.
- 88a9a83: Library: Baked Motion and Gaussian splat types now match their supported runtime contracts.
- 88a9a83: Tools: Exact-count splats no longer drop small mesh objects with dense triangulation.
- 88a9a83: Library: HMR replaces outgoing shader registrations without reporting false conflicts.
- 88a9a83: Library: Sphere rasterization ignores inconsistent overflow readbacks instead of rebuilding.
- 88a9a83: Library: WaterVolume keeps hydrostatic density stable at high particle counts.
- 88a9a83: Tools: Baked Motion can now publish verified HEVC renditions alongside H.264.
- 88a9a83: Tools: Baked Motion writes one package format; timelines and camera grids no longer differ.

## 0.10.0

### Minor Changes

- 9d18636: Library: `three-blocks/sdf-raymarching` gains `SkinnedMeshSDF` — a live signed-distance and
  surface-velocity field rebuilt from a skinned mesh's actual triangles, entirely on the GPU,
  every frame.

  Six compute stages (skin → clear → triangle splat → seed resolve → distance propagation →
  sign resolve) produce an rgba16float 3D texture holding surface velocity (xyz) and signed
  distance (w). The skeleton is the provider seam: an `AnimationMixer`, MediaPipe or Kinect
  retargeting, WebXR joints, or any other bone driver feeds the field with no extra
  configuration. TSL helpers (`sample`, `distance`, `gradient`, `surfaceVelocity`) plug the
  field into materials and simulation hooks, and `collide()` ships the complete per-particle
  response — tetrahedral contact normal with a deep-penetration escape blend, friction and
  restitution evaluated against the surface's own per-voxel velocity, capped push-out — so a
  simulation integrates the tracked body in a few lines. The texture and uniforms also bind
  directly into custom node graphs, MPM `particleForce` colliders, and smoke
  `SDFGridBoundary` sources.

  Extracted verbatim from the `webgpu_sdf_body_tracking` showcase, which now consumes the
  block: pass names, WGSL, and field semantics are unchanged, and the example's icosphere
  fixture, sign probes, and ball-pit gates continue to verify the same kernels.

### Patch Changes

- 0c96f1c: Tools: gated downloads keep the credential across the site redirect, so installs no longer fail with "Missing credential". A cached pro tool now refreshes itself when the published build changes, instead of waiting for `three-blocks tools --update`.
- 9ba758a: Packages: Material environments capture reliably and transmission types expose surface distortion.
- d91a3ba: Tools: The Mesh to Splat add-on ships its install fix under a version the hub offers as an update.
- c3506b4: Starter: New projects install compatible devtools and run status without missing dependencies.

## 0.9.0

### Minor Changes

- b14d448: Library: Transmission materials gain independent surface distortion controls.

  `distortion` perturbs only the refraction sample normal, so it can modulate transmitted
  light and nothing else. On a face turned away from the camera Fresnel hands the surface
  over to reflection, and that reflection is computed from a smooth normal — so a grazing
  face stays a clean mirror no matter how hard `distortion` is driven. It is why glass with
  plenty of visible grain head-on goes glassy-smooth on its perpendicular sides.

  `surfaceDistortion` drives the same object-anchored, band-limited noise into the shading
  normal instead, which reaches reflection and refraction alike. It shares `distortionScale`
  and `temporalDistortion`, and composes with `normalNode` and normal maps rather than
  replacing them (it overrides `setupNormal`, so a normal map still applies underneath).

  Defaults to `0`, and at `0` the render is bit-identical to before: all twelve existing
  harness cases drift 0.000 on every tile of their committed signature.

### Patch Changes

- 16993c6: Devtools: Development defers shader capture and keeps automated browser checks headless.
- 83e3068: Materials: fix MeshTransmissionNodeMaterial smearing the backdrop at grazing angles.

  0.8.0 added a mip-LOD floor derived from the screen-space derivative of the refracted
  UV. Where a refracting surface turns away from the camera that derivative explodes, so
  the LOD saturated and the fetch landed in the top mips of the viewport snapshot —
  smearing the backdrop into stretched bands around silhouettes and inside curvature.
  It applied unconditionally, so even `roughness: 0` glass with no distortion, which has
  a zero-width blur cone and should be pin sharp, came out soft.

  The floor is removed; mip selection is again the physically scaled roughness cone alone.
  `roughness: 0` glass is bit-for-bit what it was before 0.8.0.

  The 0.8.0 distortion-noise change is unaffected — the ripple is still object-anchored
  gradient noise that band-limits itself below roughly two pixels per cell.

## 0.8.0

### Minor Changes

- be95dab: Library: MeshTransmissionNodeMaterial distortion now stays stable under motion.

  The distortion normal came from a `sin(dot(sin(p), …))` hash running 2–5.6 cycles per
  world unit per channel, anchored in world space. On a typical object that lands a few
  screen pixels per cycle with no way to fade when the surface shrinks or tilts, so it
  aliased, and a moving object slid through the field instead of carrying it.

  - Distortion now uses gradient noise (`mx_noise_vec3`) sampled in object space and
    rotated into world space, so the ripple is welded to the mesh.
  - The ripple fades out below roughly two pixels per noise cell instead of aliasing.
  - Backdrop mip selection takes the larger of the roughness cone and the true screen
    footprint of the refracted UV, so refraction is filtered by its own minification.

  **Behavior change:** `distortionScale` is now gradient-noise cells per object-space unit
  rather than a multiplier on the old hash's world-space frequency, and it is roughly 5.6×
  coarser at the same value. Existing values need retuning — and values that were far into
  the sub-pixel range now fade to nothing, which is the band limiter working as intended.

  The unused `MeshTransmissionNoiseArguments` type is removed along with the hash it typed.

## 0.7.0

### Minor Changes

- 5455df6: Library: WorkerHost, TextFontWeightVariant, and ThreeBlocksAssetBuildConfig expose new APIs.
- 8e830ad: Tools: Cinema 4D now installs Baked Motion and Object Animation Video from its panel.
- 8e830ad: Library: HDR environments now load reliably in optimized production builds.

### Patch Changes

- 8e830ad: Library: Large PLY splat files now load through bundled workers.

## 0.6.0

### Minor Changes

- Devtools: Vite asset config and inspection handle HDR files and report exact GPU memory.

### Patch Changes

- efb3a0a: Devtools: Loading no longer spins the status chip or terminal progress indicator.
- efb3a0a: Packages: Text projects hydrate precompiled shaders and stay crisp across display resolutions.

## 0.5.0

### Minor Changes

- efb3a0a: CLI: Asset optimization adds Vite config status for project models and textures.

### Patch Changes

- efb3a0a: Library: Baked Motion holds the last complete view while streamed samples load.
- efb3a0a: Packages: MSDF text stays crisp and color-accurate across display resolutions.
- 57aa2a0: CLI: Blender sign-in now tolerates twenty times more redirects before asking you to retry.

## 0.4.0

### Minor Changes

- b6c53aa: Library: Gaussian splats now promote still scenes to the fast tile compositor automatically.
- fd0c70f: Library: Gaussian splats now use faster subgroup sorting when the GPU supports it.

### Patch Changes

- 8036dab: Library: Gaussian splats now stage tile-compositor promotion to avoid frame spikes.
- c9fa239: CLI: New projects return to the shell and prefer Bun for the development command.
- fd0c70f: Devtools: Development stays available when compatible shader receipts predate a version bump.

## 0.3.1

### Patch Changes

- 22be294: Gaussian splats: the record fast path reads projected records directly through the compacted sort order, dropping the draw-order gather kernel and its per-splat record buffer. The copy was measured to save no frame time (the dense-scene draw is bound by per-pixel blend hazards, not vertex fetches) while costing ~60MB of GPU memory at 1.25M splats — GPU memory returns to well under every rival and moving-camera frames shed the gather dispatch.

## 0.3.0

### Minor Changes

- beb026f: Library: Baked Motion now loads each ActiveFrame track once and drops KTX2 pose fields.
- 967a0ee: Library: Baked Motion is now consumable as a texture node on any material, keeps borrowed geometry fixed in place, and adds an explicit billboard option.
- 967a0ee: Library: Baked Motion picks AV1 renditions with an H.264 fallback, skips unused depth tracks, and can stream verified byte-range segments when enabled.
- 96be509: Library: Baked Motion now streams bounded video atlas pages through one automatic GPU path.
- beb026f: Packages: Shader tools now capture both backends by default and show backend tests and sizes.
- 8bd64d6: Gaussian splats: streamed PLY loading and a half-precision SH pipeline. `GaussianSplats.parse` now accepts a fetch `Response` or `ReadableStream` and decodes standard binary PLY records while the bytes arrive, overlapping the network read with parsing. The loader's fused pack pass emits the expanded GPU buffer layouts directly (interleaved vec4 pairs, packed half-float SH in file order), the packed arrays are wrapped as storage attributes with zero copying, and a one-shot GPU scatter applies the Morton order to SH — cutting cold-load time by roughly 3x, page memory by ~55%, and GPU memory for degree-3 SH scenes by ~35% at 1.25M splats. A new `shFormat: 'half' | 'float'` loader option (default `'half'`) selects SH storage precision, and `GaussianSplats.parse` now transfers its input buffer to the parse worker by default (`transferSourceBuffer: false` restores copying). `sortRadixBits` now defaults to `'auto'`: 4-bit digits up to 256k splats (fewer passes win while dispatch-latency-bound) and the previous 2-bit above (measured faster at 1M+).

  Dense static scenes also render substantially faster: above 256k sorted splats, the default `float16` sort keys widen to a 24-bit depth-major/hash-minor layout so equal-depth ties draw in spatially decorrelated order instead of Morton order. Perfectly depth-sorted adjacency was serializing per-pixel blend hazards on tile GPUs — a fully visible 1.25M-splat scene drops from 16.4ms to 11.2ms static and from 20.5ms to 15.0ms orbit p95 on Apple silicon, pixel-identical output (48.8dB cross-renderer agreement unchanged). Temporal sources (spacetime clips, splat video) and sub-256k scenes keep the plain 16-bit layout, so their sort cost and draw order are unchanged.

  The compute-tile renderer now works at large scale and gains an automatic hybrid mode. A hard-coded record stride in the medium/heavy tile raster path made dense scenes render dropped black tiles (and still cameras could never finish capacity validation) — both fixed, with silent chunk-capacity drops now failing validation loudly instead of corrupting output. `rendererMode: 'auto'` promotes to the tile compositor after ~half a second of camera stillness — validating capacity against that exact pose — and demotes to the raster path the same frame anything moves: a fully visible 1.25M-splat scene holds still frames at ~0.3ms (versus 11.2ms raster) while motion keeps raster cost, with tile output matching the raster path's cross-renderer agreement. Tile kernels read the record color path directly, so `shColorMode: 'cached'` is no longer required when the record fast path is active.

- 967a0ee: Library: VAV and OAV clips now stream meshopt-coded UTSBM blocks that inflate off the main thread.
- 967a0ee: Library: The Baked Motion package format is now UTSBV (.utsbv), renaming its public helpers, schemas, and assets.

### Patch Changes

- 967a0ee: Library: Baked Motion no longer submits destroyed video textures during WebGPU playback.
- 96be509: Library: Baked Motion examples now wrap product views in synchronized transmission glass.
- 96be509: Website: The Baked Motion theater temporarily previews a native 2K trailer with shorter credits.
- 967a0ee: Library: Baked Motion timelines now stream decode forward at boosted speeds — no decoder resets, monotonic presentation, and playback diagnostics.
- 96be509: Website: The Baked Motion theater now offers frame-accurate seeking and stepped playback speeds.
- 96be509: Website: The Baked Motion theater now keeps straight side walls closer to its curved screen.
- 96be509: Website: The Baked Motion theater now has sculpted seats and fast, bounded seated views.
- 967a0ee: Library: Baked Motion now renders correctly with the WebGL backend.
- beb026f: CLI: Blender subject pickers now browse collapsed collections with fuzzy graph search.
- 0c23333: CLI: `three-blocks install c4d` now adds a Three Blocks panel to Cinema 4D 2024 and later.
- e8e7e30: CLI: Splat engine setup now appears only when a Mesh to Splat tool needs it.
- a59c7b8: Packages: Documentation now matches the shipped commands, versions, and ports.
- 967a0ee: Library: Precompiled batch culling now preserves the full instance population.
- a59c7b8: Devtools: Shader precompilation now hydrates minified builds without preserving constructor names.
- 967a0ee: Library: Motion tracks now decode each block once instead of once per frame during playback.
- b328fab: Packages: Precompiled shaders now preserve deterministic output across more Three.js examples.
- 0ca530e: Devtools: Shader capture now respects each scene's supported renderer backends.
- beb026f: Devtools: Precompiled indirect batches now skip redundant shader setup.
- 8bd64d6: Website: Gaussian Splatting Visualizer is available in the examples gallery again.
- e8e7e30: Devtools: Shader precompilation now isolates backends and replays shared texture recipes.
- 967a0ee: Tools: Mesh to Splat now audits 4D geometry and trains against the rendered image size.
- 0ca530e: Tools: Mesh to Splat now honors scene-camera scale and completes engine checks after reloads.
- 967a0ee: Tools: Mesh to Splat now offers web-ready presets and native Brush quality.
- 9daa49d: Tools: Mesh to Splat now ignores render-hidden collections when framing captures.
- 9daa49d: Starter: New projects now use the current runtime without stale shader receipts.
- beb026f: Starter: Fresh projects now avoid unstyled flashes and hydrate every captured startup shader.
- 9daa49d: Packages: Three.js 186dev now uses upstream asynchronous compute compilation.
- 74a7597: Library: Vertex Animation Video now fails cleanly when numerical tracks cannot be decoded.
- 0c23333: Devtools: Shader capture tokens now survive live Vite refreshes.
- e8e7e30: Tools: Mesh to Splat no longer crashes when Windows blocks an engine cache.

## 0.2.0

### Minor Changes

- 72bbb71: Add one-shot animated 4D Gaussian capture to the Mesh to Splat Blender add-on and `three-blocks tools splat --animation`. The pipeline locks a camera rig across the scene timeline, preserves barycentric surface correspondence, trains with the managed Brush spacetime binary, auto-detects genuinely static Gaussian attributes, and commits `.b4dgs` output only after a full serialized round-trip validation.
- dc934a2: Add the experimental Baked Motion runtime and verified v2 delivery pipeline. The runtime now supports strict v1/v2 manifests, indexed integrity-checked range streaming, bounded shared decoder admission, observable rendition fallback, typed lifecycle/diagnostics, suspend/resume, first-presentation-safe sampling, adaptive scrub scheduling, raw-luma depth parallax, and deterministic cleanup. The ActiveFrame facade exposes its indexed `ActiveFrameEncodedSource` contract and decoder parking lifecycle. The authoring tool adds atomic multi-rendition output, outer indexes and hashes, decode-back quality/seam verification, and a sanitized build report; poster-first examples document reduced-motion, visibility, range-hosting, and failure policy.
- acb4ece: Ship Blender Hub v0.3.0 with one-click managed Baked Motion installation. The Hub verifies a deterministic private add-on artifact, extracts it safely, registers it without restarting, persists it across Blender launches, and rolls failed updates back. Alpha builds now use the same preproduction site as their CLI, while `npx` installs retain an exact CLI launcher for Blender jobs after the terminal process exits.
- 3693904: Adopt the `three-mesh-bvh` WebGPU `BVHComputeData` API for triangle-BVH boundary constraints and SDF generation. The new boundary-pass overloads accept initialized compute data directly, while deprecated packed-buffer overloads remain source-compatible. Reuse stable BVH proxy nodes across updates, guard unsupported or over-deep trees, release replaced GPU resources, and retain the custom pointer-free traversal for point-cloud BVHs.
- e67d56b: CLI: the interactive session is a real app now — actions return to the menu instead of exiting, Esc walks back one level, errors keep the session alive, and a new Account submenu covers status/sign-in/sign-out/credentials. The palette is anchored on the Logo primaries (gold ▲ · red ● · deep-blue ■ mark, logo-blue accent, gold warnings, logo-red errors), and pro-tool surfaces highlight in gold. `three-blocks install blender` really installs the bundled Three Blocks hub addon (Blender 4.2+ extensions repo, pre-4.2 addons dir otherwise, multi-version picker, `--all-versions`, `--zip`, `--blender-config`) and is version-aware — the menu row shows installed vs bundled and offers the update; `doctor` reports the hub state.

  Both API clients (CLI and hub) now default to the canonical `https://www.threejs-blocks.com` and follow redirects by hand, re-issuing the same method and body — the apex→www 302 previously turned the device-flow POST into a bodyless GET and broke sign-in against production with a 404.

  The hub addon (v0.2.0) signs in from inside Blender via the browser device flow (worker-thread polling, Esc cancels, `online_access` respected), shares the credential with the CLI via `~/.three-blocks/credentials.json`, shows the plan verdict, supports a site override preference for local testing, surfaces a "hub update available" badge from the new public `GET /api/blender/catalog`, and exposes `three_blocks.get_context()` to tool-addons.

- e67d56b: Premium CLI experience (docs/plans/cli-experience.md): a zero-dep terminal kit (`src/cli/ui/` — truecolor-aware brand theme #64a4ff/#d4ff47, ANSI-safe wrap/truncate/columns, boxes, byte-progress downloads, select v2 with Esc-cancel, live doctor checklist, cleanup registry so the terminal is never left broken), every CLI surface reskinned (banner/help, menu, login panels, whoami, doctor, token table, tools upsell + real download progress, CliError hints), seat-aware plan lines from the validate route's new additive `team` fields, and the scaffolder now speaks the same visual language (mirrored mini-kit, arrow-key template picker, next-steps success panel). Piped/CI output stays plain and line-oriented — the e2e grep contract (authorize URL, `pro tools entitled`, `tb_` prefixes, exit codes) is unchanged.
- e67d56b: Add `ComputeSphereRasterizer`: a WebGPU software rasterizer for opaque sphere-impostor particles — frustum-voxel binning (16×16 pixel tiles × 32 log depth slices) with cooperative large-sphere handling, an atomic-free per-pixel nearest-hit raster with front-to-back early termination, self-growing entry capacity, and a fullscreen `DeferredSurfaceNodeMaterial` resolve that keeps native scene lighting (environment IBL, punctual lights, fog) and true fragment depth/normals so GTAO and depth-based post effects continue to work. Renders 1M+ overlapping spheres several times faster than the hardware impostor path once overdraw dominates. Ships with the `webgpu_simulation_water_ocean` example, which advances 1,048,576 MLS-MPM/APIC fluid particles before software rasterization, plus WGSL validation, vitest contracts, and a Playwright browser harness with benchmark.
- 72bbb71: Publish Transmission, Baked Motion, Object Animation Video, Vertex Animation Video, and ActiveFrame Video as documented experimental, runtime-identical facades. These entry points hide decoder, texture, node-graph, GUI, and authoring state from their declaration surfaces. Baked Motion, OAV, VAV, and ActiveFrame expose explicit runtime format versions and validated parsers; packing and encoding remain tooling concerns.
- 623e341: Measure and report the shader-precompilation win across the runtime overlay, Vite receipts, and CLI. Dev sessions now observe first-load TSL build time without changing the shader-provider closure, while `shaders test` records a warmup-discarded median-of-N A/B with spread and optional hardware-labelled committed evidence.

  Make shader claims follow runtime truth: unhydrated caches no longer claim skipped work, adopted apps can run `three-blocks status` without scaffold metadata, page-owned stats panels visibly follow their shared controls, and production bundles continue to erase the observer and overlay.

- 3693904: Move stats panels into the dev overlay, add page-owned renderer adoption through `three-blocks/devtools`, and remove scaffold-owned stats code. Page-owned Vite setups are inferred automatically when scaffold metadata is absent; worker texture previews also keep working when `WebGPURenderer` uses its WebGL fallback backend.

  The browser verifier now activates stats through the public smoke controls, proves texture transfer stops after disable, classifies recovered text-fallback errors across both browser channels, and preloads its synthetic probe dependencies to avoid Vite optimizer reload races.

  `stats: true` now enables stats only for the development server. Production stats require the explicit object form: `stats: { production: true }`.

- 72bbb71: Harden the stable product facades without changing their runtime constructor identities. MSDF text, surface sampling, instance culling, indirect batching, Boids, PBF, SPH, sphere impostors, and the core TSL effects now publish intentional declaration surfaces instead of their engines' mutable pipeline state. Approved configuration, input, output, layout, calibration, statistics, and lifecycle types remain available from each stable block path. Surface sampling accepts the stable `ComputeBVHSamplerSource` protocol without importing the experimental SDF generator contract. Boids also gains an idempotent `dispose()` method for its engine-owned GPU buffers and internally created spatial grid.
- e67d56b: Add `MPMSolver`, `MPMFluidModel`, and `MPMElasticModel`: a reusable WebGPU MLS-MPM/APIC simulation
  block with a four-pass fused default, five-pass reference oracle, stable particle-buffer API,
  fixed-point overflow diagnostics, one-frame-late CFL substeps, optional block binning, f16 grid
  mirror, feature-detected subgroup P2G, builder hooks, and bounded GPU resource disposal. Extract the
  million-particle ocean example onto the public block and add unit, WGSL, real-WebGPU physics, parity,
  elastic, and benchmark gates. The fused path
  prices pressure through a continuity density predictor (`densityPrediction`, default on) — without
  it the one-substep-stale density self-excites gravity-loaded fluid into permanent agitation — and
  the ocean example ships a calm-baseline tuning (equilibrium-profile seed, dispersion-matched
  orbital swell forcing) with a quiet-tank browser regression gate and a headless tuning lab.
- 623e341: Add the first public OAV and VAV schemas with exact indexed-binary numerical tracks and bounded two-frame residency. Writers and readers use schema 1 directly; numerical data is reconstructed into typed arrays for Three.js GPU uploads, while optional VAV UV appearance remains visual media.
- 72bbb71: Narrow the experimental Gaussian Splats and GPU Interaction declarations to documented configuration, input, output, diagnostics, frame operations, and lifecycle APIs while preserving exact runtime constructor identities. Approved visualization and node extensions now share the corresponding `three-blocks/experimental/*` path. Gaussian video packing remains authoring-only through the offline `splat:video` tool.
- 72bbb71: Narrow the experimental Smoke, Water, SDF/Raymarching, and Compute Foundations declarations to documented high-level facades. Runtime constructors and prototypes remain identical, while raw uniforms, storage buffers, TSL graphs, solver passes, caches, render targets, temporary textures, GUI state, and workgroup internals move behind the product boundary. Named configuration, input, output, diagnostics, quality, frame-step, and disposal contracts remain available from each experimental block path.
- e8b569c: Add the hardware-first Object Animation Video runtime, manifest/quantization helpers, Blender authoring addon, direct `.blend` CLI baking with shared object/collection selection, pro encoder, OAT compatibility, and updated gallery example.
- 623e341: Promote Grid Pristine, Transmission, Baked Motion, Gaussian Splats, Smoke,
  SDF/Raymarching, and Water to stable top-level entrypoints. Merge the stable
  Boids, Instance Culling, and Sphere Impostor extensions into their canonical
  entrypoints, and remove the gallery-only example geometry and GUI utility
  subpaths. Add the stable `three-blocks/mpm` solver entrypoint with fluid,
  elastic, force, seeding, diagnostics, and post-pass contracts.
- 623e341: Extend `RayMarchSDFNodeMaterial` with opt-in product-shot stone transport: an analytic studio environment, softened multi-ray scattering, bent entry and exit refraction, field-local clouds and veins, dual-lobe GGX polish, AgX output, integer-pixel dither, and quality folding. The zero-feature defaults preserve the existing opaque and translucent shading paths. The Points → Volume example now compares a scanned cactus with a procedural cabochon and ships Imperial Jade, Lavender Jade, Wax, and Marble presets plus deterministic visual and GPU-budget evidence.
- 72bbb71: Define the initial Three Blocks 0.1.0 public contract: restrict the package root to 17 manifest-approved stable runtime values, keep established stable block paths, and publish every evolving product or low-level extension under `three-blocks/experimental/*`. Stable and experimental are now the only public maturity levels. This structural change does not alter facade signatures or runtime behavior.

  Release gates compare every entry point and declaration—including constructor overloads—against the manifest, compatibility baselines, documentation inventory, and exhaustive ESM/CJS plus TypeScript consumer fixtures.

- 9811acd: Convert every authored runtime, Gaussian splatting, worker, CLI, and barrel module to strict TypeScript while preserving the 417-name ESM/CJS runtime API. Publish declaration-safe public contracts with no `any`, private Three.js references, or source-tree imports; isolate the three byte-stable generated font factories behind strict adapters; and disable JavaScript compilation across the package.
- 5feae2c: Ship the MLS-MPM ocean stack over the solver core: `WaterVolume` (world-unit domain binding, calibrated presets, hydrostatic-equilibrium seeding, dispersion-matched `OceanWaves` wavemaker with absorbing rim, pointer/splash emitters, collider response, single-submission frame), `SurfaceField` (top-down height/foam/velocity columns with batched movable probes and `getHeightAt`), `DiffuseParticles` whitewater (C-matrix spawn potentials, spray/foam/bubble classification, GPU compaction with indirect draw — zero readbacks, deterministic under a seed), `FloatingBody` buoyancy (auto 5-point hull probes, SmoothDamp kinematic follow or Archimedes forces, collider-driven two-way wakes), the screen-space fluid pipeline (`WaterSurfaceRenderer`, `narrowRangeFilter` with pinhole fill, `createWaterComposite`/`WaterNodeMaterial`), and `WaterRayMarchRenderer` for grid-accelerated volume tracing directly over the live MPM mass field. `MPMSolver` gains a `postPasses` hook so composed systems ride the same compute submission. The gallery ocean example now runs on the block APIs with four render modes, shared optical water/whitewater shading, raymarch quality controls and timing harnesses, and a Hokusai-leaning crossing sea.

### Patch Changes

- 803708b: Devtools: Compute shaders now warm asynchronously and ocean shaders hydrate without setup.
- e67d56b: Blender hub v0.2.1: the signed-in card names the user (account name > email, never the `tb_…` token prefix) and the tool rows unlock from the real per-addon entitlement — the catalog fetch now sends the stored credential, and login/sign-out re-fetch so the locks flip live. CLI `login`/`whoami` show the same account name (`/api/tools/validate` now returns `user: {name, email}`).
- 9f20a06: Make Three Blocks devtools a one-line renderer registration across Vite, Next.js, webpack, and bare browser modules. Existing Vite apps now get page ownership and shader inspection from `three-blocks.shaders.json` automatically, the runtime mounts its fallback overlay, and production-aware bundlers select an import-free no-op that preserves both stable devtools exports. The overlay reports real registered shader builds from the renderer hook for page- and worker-owned apps; timing remains attributed to the matching local A/B receipt.

  When a first shader capture lands, the Vite plugin invalidates transforms that were cached while the manifest glob was empty before reloading the page, so the same running dev session hydrates the new precompiled artifact.

  Align CLI and Vite shader inspection on one metadata precedence: explicit plugin options, then scaffold-owned `three-blocks.json`, then custom-app `three-blocks.shaders.json`. Projects containing both files therefore report and capture the same authoritative scene matrix.

  Unify public commands under `npx three-blocks`, remove the legacy capture endpoint and `precompile.config.mjs` reader, and keep built-in text fonts checksum-pinned without shipping their binary payload in the devtools package archive. Custom worker shells can now reuse the `three-blocks/app` stats controllers and structural smoke bridge instead of maintaining parallel page/worker implementations.

- e67d56b: Fix and accelerate `ComputeMeshDynamicSurfaceSampler` and rebuild its `webgpu_compute_sampler_dynamic` example. Dynamic sampling now emits an actual `StorageInstancedBufferAttribute` for GPU-written instance matrices, compacts candidates and samples them in one three-pass GPU batch instead of sorting every source triangle across dozens of submissions, uses conservative cached face bounds and squared-distance tests, keeps live position/normal outputs, wraps secondary candidate indices safely, hides instances when no face is in range, and releases owned GPU resources. The gallery example is now "Migration": a fairy-tale vine — an elastic, pinch-and-stretch torus knot with GPU-recomputed grid normals — carries a fixed population of 100,000 instances across five samplers (grass with wildflower tips, petals, butterflies, fireflies, and birds), and a per-species flight pass detects sampler reassignments on the GPU and animates each one as an arcing migration to its newly sampled anchor: nothing spawns and nothing dies while the ecosystem trails the pointer as a procession. Holding the pointer pinches the vine and gathers the flock, Space freezes the whole population mid-air while the surface keeps breathing, and the deterministic capture freezes every species mid-flight.

  Gallery builds now resolve and verify the workspace-installed Three.js package, synchronize its browser build and addons, pin every example import map to a versioned content hash, retain verified current-version compatibility mirrors, and reject revision, export, addon, or copied-byte drift before deployment.

- acb4ece: Fix starter launches from alpha CLIs and Windows by following the matching npm release channel and invoking npm's JavaScript entrypoint instead of its Windows command shim.
- 35c7bd9: Website: Release pages show the exact version with a short changelog.
- acb4ece: Align package and generated-project notices with the lifetime per-Project commercial license, identify the legal licensor, and ship complete third-party attributions with the core package.
- e8b569c: Improve the Mesh to Splat CLI with interactive mesh and collection discovery, an Everything-first default for imported GLB/mesh files, collection cherry-picking, Eevee/Cycles renderer selection, object-safe Orbit/Interior/Auto rigs, transparent isolated captures, renderer-aware cache invalidation, clean read-only listing without an engine preflight, and concise structured Blender errors with actionable subject lists.
- e67d56b: Ship a minified `dist` (esbuild minify with `keepNames`, sourcemaps still built locally but excluded from the tarball) and an explicit no-AI-training notice: a NOTICE file in the tarball, a second `Required Notice:` line in LICENSE and the dist banner reserving text-and-data-mining rights (EU 2019/790 Art. 4(3)).
- 9f20a06: Precompiled shader capture now preserves distinct storage access views that share one underlying buffer, so a read-only WGSL binding hydrates as read-only instead of collapsing onto its read-write owner. Hydration also verifies storage-buffer and storage-texture access modes against the captured WGSL before a pipeline is created. WebGPU validates the shader/layout pairing asynchronously, so an access drift between capture and replay used to escape the non-strict live fallback and re-submit an invalid pipeline every frame (observed as `GPUValidationError: The buffer type in the shader (ReadOnlyStorage) is not compatible with the type in the layout (Storage)` spam on `compute_csr_raster`). The provider now replicates three r185's `WebGPUBindingUtils` layout rules per binding slot and turns any remaining mismatch into a synchronous hydration failure, which falls back to live TSL compilation for that key exactly as the fail-soft contract promises.
- 4eb273d: Tools: Mesh to Splat, OAV, and VAV are now installable from the Blender hub.
- 37e7f64: Devtools: Fresh scene receipts now precompile automatically while edited scenes stay live.
- 803708b: Devtools: Shader traces now measure replay, skip PMREM setup, and support Three.js r186dev.
- 623e341: Make batch and instance GPU frustum culling conservative for scaled bounding spheres at perspective side planes. Add the experimental GPU Visibility Funnel example, its four-path benchmark harness, and explicit Three Blocks GPU-culling attribution.
- ece8639: Define devtools as a WebGPU-only shader precompilation workflow. Runtime registration now rejects `WebGLRenderer`, the docs lead with stable shader registration, capture, manifest injection, and parity verification, and shader capture uses the consuming project's Vite runtime for Vite 8 compatibility.
- 5e3cc44: Tools: Mesh to Splat now installs beside administrator-owned engine caches on Windows.
- 803708b: CLI: Splat-engine downloads now install reliably on Windows and support both Mac architectures.

This changelog is generated from Changesets.

## 0.1.0-beta.0

- Initial public beta.
