PlayCanvas Engine v2.21.0 Adds glTF and SPZ Gaussian Splat Loading

Michael Rubloff

PlayCanvas has released Engine v2.21.0, which loads gaussian splats from glb files carrying the KHRgaussian_splatting extension. The glb parser decodes splat primitives, POINTS meshes flagged with the extension, into GSplatData and GSplatResource. Namespaced attributes are de-interleaved into the PLY style layout, quaternions reordered from xyzw to wxyz, per coefficient spherical harmonic RGB regrouped into channel major f_rest fields, and the data morton reordered as the PLY path is.
The engine's gsplat loaders have covered PLY, its compressed variant and SOG, and Engine 2.13 extended the unified gsplat renderer with a ColorRamp mode and spherical harmonic re-evaluation on camera movement. The Khronos Group published KHR_gaussian_splatting as a glTF baseline for Gaussian Splatting, still at release candidate, and the splat-transform CLI already writes files that use it.
The extension stores linear scale and post sigmoid opacity, so GSplatData gains an activated flag and the iterator, AABB, focal point and color texture paths read those values directly. PLY behavior is unchanged. Container resources expose splats through a new ContainerResource#gsplats array, and instantiateRenderEntity attaches a gsplat component to splat carrying nodes.
Unsupported values warn in debug builds, covering non-ellipse kernels, the lin_rec709_display colorSpace and non-POINTS modes, while sortingMethod and projection are ignored because sorting runs from the engine's global gsplat settings. The companion SPZ compression extension is not supported and remains an unmerged draft.
Niantic open sourced SPZ in late 2024, and Engine v2.21.0 reads it through spz-parser.mjs, an external parser script registered with app.loader.getHandler('gsplat').addParser(new SpzParser(app)). SpzParser reads the SPZ v4 NGSP container directly and keeps the data quantized in GPU textures at roughly 20 bytes per splat plus optional spherical harmonics, dequantized in the shader as the compressed PLY and SOG paths are. The parser supports 0 to 3 SH bands, clamps degree 4 files to 3, and runs under GLSL and WGSL.
ZSTD compressed attribute streams are decompressed by a wasm module the application registers draco style through pc.WasmModule.setConfig, and the 54kB zstddeclib build is vendored into the examples. No engine code changed for SPZ, since the parser builds on the public GSplatResourceBase and GSplatFormat API. A new simple-spz example loads the biker asset at 2.1MB in spz v4 against 2.5MB as compressed ply.
The breaking change renames the scripts/esm/gsplat script classes from Gsplat to GSplat, matching the core GSplatComponent and GSplatContainer casing, so a named npm import of GsplatFlipbook becomes GSplatFlipbook. The scriptName strings, including streamedGsplat and gsplatFlipbook, are unchanged, so Editor projects that reference scripts by name are unaffected.
Engine v2.21.0 also adds volumetric fog in CameraFrame, KTX2 cubemap support, an XrManipulation script for two hand drag, rotate and scale, and a physics backend abstraction with Ammo and Null implementations. The engine is available now on npm.
New to Gaussian Splatting? Start here






