@tingtingtingtin/splatkit
v0.1.8
Published
Experimental Three.js Gaussian Splat viewer with embeddable headless and UI wrappers.
Maintainers
Readme
SplatKit: Three.js Splat Viewer
Work-in-progress Gaussian Splat renderer built with Three.js, TypeScript, GLSL, and Web Workers.
This package is experimental and APIs may change between releases.
This repository now has two usage modes:
- Standalone page app (entry at
src/main.ts) - Embeddable viewer classes:
SplatViewer(headless core, no UI)SplatViewerUI(optional overlay UI wrapper)
Inspired by:
Features
- Custom splat pipeline with packed
DataTexturestorage - GLSL splat shading and ellipse projection
- Worker-based depth sorting for transparent blending
- Dynamic instance-count control by percentage
- Camera controls:
- Orbit controls
- WASD translation
- right-drag panning (inverted screen direction)
- Runtime reset and consistency recovery hooks
- Embeddable class API for host applications
Quick Start
Requirements
- Node.js 20+
Install
npm installRun development server
npm run devProduction build
npm run buildPreview production build
npm run previewStandalone Mode
src/main.ts is a deployable standalone entry.
It mounts SplatViewerUI into #app in index.html.
Embedding API
Important packaging/runtime notes:
- Experimental package: expect API and build changes while the renderer evolves.
- Worker limitation:
SplatWorkeris instantiated vianew URL("./SplatWorker.ts", import.meta.url), so bundler behavior is tied to Vite-compatible worker URL handling. - Styles:
SplatVieweris headless and has no UI styles.SplatViewerUIexpects styles to be provided by the consumer. You can either include your own stylesheet or import the package sheet fromthreejs-gs-framework/style.css.
1. Headless viewer (no UI)
Use this when your app already has its own controls/DOM.
import { SplatViewer } from "./SplatViewer";
const container = document.getElementById("viewer")!;
const viewer = new SplatViewer(container, {
url: "https://media.reshot.ai/models/nike_next/model.splat",
background: 0x111111,
moveSpeed: 3,
enableWASD: true,
enableRightDragPan: true,
});
await viewer.waitUntilReady();
viewer.setInstancePercent(100);
// Later
viewer.dispose();SplatViewer methods:
waitUntilReady(): Promise<void>setInstancePercent(percent: number): numberreset(reason?: string): voidgetStats(): { totalSplats, instanceCount, cameraPosition }dispose(): void
2. Viewer with built-in overlay UI
Use this when you want a quick ready-made panel and loading/fps overlays.
import { SplatViewerUI } from "./SplatViewerUI";
const container = document.getElementById("viewer")!;
const viewerUI = new SplatViewerUI(container, {
url: "https://media.reshot.ai/models/nike_next/model.splat",
initialPercent: 100,
});
// Later
viewerUI.dispose();Controls
- Orbit: mouse drag
- Translate:
W,A,S,D - Pan: right-click drag
- Reset view: UI reset button
Project Structure
Core rendering
src/classes/SplatLoader.ts: parse/load.splatsrc/classes/SplatPacker.ts: pack splat attributes for GPU texture usagesrc/classes/SplatGeometry.ts: create instanced quad geometry + packed texturesrc/classes/SplatMaterial.ts: shader material and uniformssrc/classes/SplatRenderer.ts: orchestration, async readiness, sort/update/reset APIssrc/classes/SplatWorker.ts: worker-side depth sort
Wrappers and app entry
src/SplatViewer.ts: headless embeddable viewer classsrc/SplatViewerUI.ts: opt-in overlay UI wrapper aroundSplatViewersrc/main.ts: standalone page bootstrap
Shaders
src/shaders/splat.vertsrc/shaders/splat.frag
Rendering Pipeline (High Level)
- Load binary splat buffer.
- Pack splat data into integer texture storage.
- Render instanced quads, one per splat.
- Project covariance to screen-space ellipse in vertex shader.
- Apply Gaussian falloff in fragment shader.
- Keep transparent blending stable using worker depth sorting.
Notes
- This is still a learning project and API surface may change.
- Remote model URLs are subject to CORS/network constraints.
- Performance depends heavily on GPU/browser and splat count.
