Radix draws 3D Gaussian splats in three.js, on WebGPU or on WebGL2 from the same shaders. Each frame it projects the splats of all objects in a scene, sorts them together, and draws them in one draw call.
Several objects in one sort · four projection methods · splats generated in shaders · stereo XR · one table format from files to the GPU
A file is decoded once on a worker and uploaded once. Then each render projects the splats for the camera, sorts them back to front, and draws them. On WebGPU these steps all run on the GPU in the same frame. On WebGL2 the sort runs on a worker, and its result arrives a few frames later.
// WebGPU, or WebGL2 where WebGPU is missing
const renderer = await createRenderer();
// Decode on a worker, then upload to textures
const data = await loadSplats("scene.spz");
const splats = GpuArrays.fromData(renderer, data);
const collection = new SplatCollection([SplatCollection.arrays(splats)]);
const splatRenderer = new SplatRenderer({ renderer, collection });
scene.add(splatRenderer);
renderer.setAnimationLoop(() => renderer.render(scene, camera));
See also: Quickstart What a render does The pipeline
See also: The comparison Benchmarks Performance
All code is in src/, which imports nothing else from the project. Click a layer to see its classes and the pages about it. Beside them, controls/ (CameraControls) imports only three.js, and nothing imports it.
core/ is the data and the math, gpu/ puts that data in textures and reads and writes it in shaders, wgpu/ adds compute and the GPU sort, worker/ runs core/ off the main thread, and render/ projects and draws splats with all of them. Anything named Wgpu* needs WebGPU; everything else runs on WebGL2 too.
See also: The reference Checks