v2.21.0

leptos-rs/leptosv2.21.0Jul 21, 2026by mvaligursky

AI Summary

A major engine update introducing Gaussian Splatting support, physics backend decoupling, extensive XR improvements, and performance optimizations for rendering and asset handling.

Key Highlights

  • Add support for KHR_gaussian_splatting glTF extension and SPZ format
  • Decouple physics into a backend abstraction (Ammo and Null implementations)
  • Add volumetric fog rendering to CameraFrame
  • Add XrManipulation script for two-hand drag, rotate, and scale in XR scenes

Breaking Changes

  • Remove MeshInstance parameter pass flags
  • Rename gsplat script classes to match core GSplat casing

New Features

  • GSplat glass refraction and tree wind examples
  • Volumetric fog rendering
  • Instanced wide line renderer
  • KTX2 cubemap support
  • Physics backend abstraction (Ammo/Null)
  • XrManipulation script
  • Texture.copy API
  • CircleGeometry procedural geometry
  • Pen input support in touch sources
  • Filtered subscription APIs for checkpoints, transactions, and events

Full Release Notes

## Breaking Changes
* [BREAKING] Remove `MeshInstance` parameter pass flags by @mvaligursky in #9071
* [BREAKING] Rename gsplat script classes to match core `GSplat` casing by @willeastcott in #9040

## Changes

* Add instanced wide line renderer by @mvaligursky in #9090
* Add volumetric fog rendering to `CameraFrame` by @mvaligursky in #9069
* Support KTX2 cubemaps by @MotivaCG in #9065
* Add support for `KHR_gaussian_splatting` glTF extension by @mvaligursky in #9015
* Add SPZ gaussian splat format support via external parser by @mvaligursky in #9018
* Re-add `Camera.beforePasses` extension point by @mvaligursky in #9073
* Decouple physics into a backend abstraction with Ammo and Null implementations by @willeastcott in #9043
* Move simulation registration onto the rigid body system by @willeastcott in #9044
* Flatten collision type implementations into a dispatch table by @willeastcott in #9045
* Add `XrManipulation` script: two-hand drag, rotate and scale for XR scenes by @willeastcott in #9030
* Upgrade `XrNavigation` teleport visuals to ballistic arc with ring indicator by @willeastcott in #9024
* Refactor XR scripts: dedupe within-file logic and align naming by @willeastcott in #9032
* Move XR scripts into `scripts/esm/xr` folder by @willeastcott in #9038
* Add Engine Scripts API reference for `scripts/esm` by @willeastcott in #9042
* Add pluggable parser registry to `ResourceHandler` and convert built-in handlers by @mvaligursky in #9001
* Convert `MaterialHandler`, audio, anim and template handlers to the parser registry by @mvaligursky in #9004 #9005 #9006
* Extract glTF extensions from the glb parser into separate modules by @mvaligursky in #9007 #9008
* Convert the obj model parser to an ES module in `scripts/esm/parsers` by @mvaligursky in #9019
* Add `withCredentials` option for asset loading by @mvaligursky in #8983
* Add `Texture.copy` for texture-to-texture copies by @mvaligursky in #8970
* Add `CircleGeometry` procedural geometry class by @mvaligursky in #9027
* Add clear/remove API to `Curve` and `CurveSet` by @mvaligursky in #8980
* Add unclamped scalar interpolation by @mvaligursky in #9087
* Add request/execute mesh-instance culling by @mvaligursky in #8978
* Allow `Texture#mipmaps` to be changed at runtime on WebGPU by @mvaligursky in #9003
* Use uniform buffers for view-level uniforms on WebGL2 by @mvaligursky in #8987
* Route view uniforms through dynamic buffers; remove view bind groups by @mvaligursky in #8967
* Make `StorageBuffer.read` public by @mvaligursky in #8986
* Add public `app` getter to `ResourceHandler`, mark `_app` protected by @mvaligursky in #8991
* Support pen input in touch sources by @d0rianb in #9013
* Skip WebXR startup probe when `xr-spatial-tracking` is disallowed by @mvaligursky in #8964
* Warn about unknown options passed to `addComponent` by @mvaligursky in #8995
* Load MSDF font atlases without mipmaps by @mvaligursky in #9002
* Refactor `OutlineRenderer` to use dedicated shader output by @mvaligursky in #9070
* Refactor light and directional-shadow culling into separate phases by @mvaligursky in #8961
* Rework shadow update-mode lifecycle; keep THISFRAME pending until rendered by @mvaligursky in #8962
* Build the frame graph before mesh and shadow-caster culling by @mvaligursky in #8965
* Allocate local light shadow maps before the frame graph is built by @mvaligursky in #8966
* Decouple `RenderPassForward` from `RenderAction` via `LayerRenderStep` by @mvaligursky in #8975
* Extract visibility culling into a `Culler` class by @mvaligursky in #8979
* Use `Debug.removed` for nonfunctional compatibility shims by @mvaligursky in #9082
* Recommend `EventHandle.off()` for event removal by @mvaligursky in #8974
* Exclude `@ignore` typedefs from generated API docs by @mvaligursky in #8989
* Add compute shader definition types to docs by @mvaligursky in #9067

## Fixes

* Fix crash when a gsplat octree asset is unloaded while still registered in the streaming world by @slimbuck in #9011
* Fix crash when a gsplat component detaches its asset while still registered in the streaming world by @slimbuck in #9016
* Fix crash when unloading SOG assets still referenced by the unified world by @slimbuck in #9035
* Fix gsplat loading progress getting permanently stuck after a cancelled mid-flight load by @slimbuck in #8998
* Rebuild bind groups when a bound texture's GPU resource is recreated by @slimbuck in #8982
* Fix SOG bundle parser continuing after asset unloads mid-load by @mvaligursky in #9037
* Fix SOG streaming re-load returning destroyed textures from loader cache by @mvaligursky in #9039
* Fix GPU device hang when picking gsplats on Windows/NVIDIA by @mvaligursky in #9036
* Re-copy work buffer for streamed gsplat placements and all consumers by @mvaligursky in #9021
* Fix `lodRangeMin`/`lodRangeMax` not applied from `GSplatComponent` init data by @willeastcott in #8968
* Fix gsplat work buffer not re-rendered for non-streaming splats on device restore by @mvaligursky in #8973
* Free SOG bundle archive memory after texture upload by @mvaligursky in #8972
* Fix markup text color shift by storing vertex palettes in linear space by @mvaligursky in #9034
* Fix skybox staying black after cubemap asset unload and reload by @mvaligursky in #9017
* Fix specular-glossiness diffuse texture not marked as sRGB in glb parser by @mvaligursky in #9009
* Fix glTF occlusion strength support by @mvaligursky in #9066
* Fix MSDF text anti-aliasing stability at small sizes by @willeastcott in #8990
* Free font textures when a font asset is unloaded by @mvaligursky in #8969
* Fix inverted buffer usage flags in `Mesh.clear()` by @willeastcott in #9023
* Fix `AnimationComponent` crash on tracks with events by @mvaligursky in #8985
* Fix `XrMenu` finger-poke clicks and textured button tint restore by @willeastcott in #9025
* Fix `XrNavigation` castRay plane coupling and stale teleport cache by @willeastcott in #9026
* Fix compound wiring for collision children that have their own rigidbody by @willeastcott in #9048
* Fix device constructor crash when canvas lacks `getBoundingClientRect` by @mvaligursky in #9000
* Fix deprecated API migration messages by @mvaligursky in #9079
* Fix deprecated gloss aliases by @mvaligursky in #9080
* Mark live API getters readonly by @kpal81xd in #8959

## Examples

* Add gaussian splat glass refraction example by @mvaligursky in #9020
* Add gaussian splat tree wind example with reusable GsplatTrees script by @mvaligursky in #9022
* Add reusable Water script with planar reflection and refraction, and a water example by @mvaligursky in #9029
* Add KTX2 cubemap example by @mvaligursky in #9068
* Modernize the graphics/layers example by @mvaligursky in #9088
* Fix `ProceduralSky` light drifting off the visible sun near sunset by @mvaligursky in #9028
* Fix HUD-only flags in shadow-soft and shadow-cascades examples by @mvaligursky in #9092 #9093
* Fix range/radius in shader toon and wobble examples by @mvaligursky in #9094

## Engine Dependencies

* Update all npm dependencies by @renovate[bot] in #9053

### Contributors

* @d0rianb
* @hellohejinyu
* @kpal81xd
* @MotivaCG
* @mvaligursky
* @slimbuck
* @willeastcott

## New Contributors

* @d0rianb made their first contribution in #9013
* @hellohejinyu made their first contribution in #9050
* @MotivaCG made their first contribution in #9065

**Full Changelog**: https://github.com/playcanvas/engine/compare/v2.20.6...v2.21.0