Log inGet started

gaussianSplat

Updated 22 August 2026
room_01.gaussianSplat/
  room-01.spz    the capture — the primary the runtime decodes
  .metadata      count, bounds, SH degree, axis convention
  README.md

The capture keeps the name it arrived under, so the file you dropped in is the file you find inside. Reach its bytes through the asset — captureRef:getBytes() — rather than by spelling the filename.

Putting a capture in the scene

A capture instantiates under the same name a bundle and an avatar do — the entity drawing the cloud is spawned for you, in the axis convention the container recorded:

local root = asset.resolve("room", "gaussianSplat"):instantiate()
local child = captureRef:instantiate(entity.spawn("mount"))  -- as an owner's child

It is scene-compatible (ref:canInstantiate() is true), so every consumer of the scene contract takes one: zero entityOps fromAsset <capture> is the same spawn as one packaged call, and an Asset component pointed at a capture spawns and tears down the cloud with its owner.

To place the cloud by hand instead, point a GaussianSplat component at it:

local id = entity.spawn("scan").id
entity(id).component.add("GaussianSplat", { source = "captures/room.gaussianSplat" })

Reading a cloud without decoding it

.metadata carries what a tool needs to reason about a capture — how many splats it holds, the world-space box it occupies, whether it stores view-dependent colour — so framing a camera on a cloud or reporting its cost does not pay for a decode of the whole thing.

{
  "count": 1920000,
  "boundsMin": [-24.48, -0.92, -22.19],
  "boundsMax": [27.52, 33.40, 16.81],
  "shDegree": 0,
  "convention": "rightDownFront",
  "recordBytes": 24
}

boundsMin / boundsMax are the full extent, outliers included. A capture of a whole scene usually carries a sparse halo of stray Gaussians far outside the part anyone looks at, so framing a camera on these bounds puts it outside the scene looking at the halo. For a scene capture, place the camera inside it.

Why the capture stays the primary

The engine's packed record pool is 24 bytes per splat — larger than the .spz the capture arrived in, whose quantized encoding is what makes the format worth using. Baking the pool into the container would spend storage to save a decode that costs a few hundred milliseconds once per load.

Guide

guides { path = "topics/gaussian-splats" } covers capturing, placing, and tuning a cloud.

  • asset-type
  • reference