gaussian-splat-lite 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/CONTRIBUTING.md +79 -0
  3. package/Gaussian-Splat-Lite.svg +104 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +10 -0
  6. package/README.md +272 -0
  7. package/THIRD_PARTY_LICENSES.md +53 -0
  8. package/dist/assets/worker-7HrXsEvI.js.map +1 -0
  9. package/dist/assets/worker-XHJGFfdJ.js.map +1 -0
  10. package/dist/gaussian-splat-lite.cjs +3039 -0
  11. package/dist/gaussian-splat-lite.cjs.map +1 -0
  12. package/dist/gaussian-splat-lite.min.cjs +886 -0
  13. package/dist/gaussian-splat-lite.min.cjs.map +1 -0
  14. package/dist/gaussian-splat-lite.module.js +3023 -0
  15. package/dist/gaussian-splat-lite.module.js.map +1 -0
  16. package/dist/gaussian-splat-lite.module.min.js +2840 -0
  17. package/dist/gaussian-splat-lite.module.min.js.map +1 -0
  18. package/dist/types/GaussianSplatRenderer.d.cts +385 -0
  19. package/dist/types/GaussianSplatRenderer.d.ts +385 -0
  20. package/dist/types/SplatAccumulator.d.cts +72 -0
  21. package/dist/types/SplatAccumulator.d.ts +72 -0
  22. package/dist/types/SplatEdit.d.cts +86 -0
  23. package/dist/types/SplatEdit.d.ts +86 -0
  24. package/dist/types/SplatGeometry.d.cts +4 -0
  25. package/dist/types/SplatGeometry.d.ts +4 -0
  26. package/dist/types/SplatLoader.d.cts +31 -0
  27. package/dist/types/SplatLoader.d.ts +31 -0
  28. package/dist/types/SplatMesh.d.cts +74 -0
  29. package/dist/types/SplatMesh.d.ts +74 -0
  30. package/dist/types/SplatSource.d.cts +23 -0
  31. package/dist/types/SplatSource.d.ts +23 -0
  32. package/dist/types/SplatWorker.d.cts +30 -0
  33. package/dist/types/SplatWorker.d.ts +30 -0
  34. package/dist/types/Splats.d.cts +54 -0
  35. package/dist/types/Splats.d.ts +54 -0
  36. package/dist/types/cameraRelative.d.cts +22 -0
  37. package/dist/types/cameraRelative.d.ts +22 -0
  38. package/dist/types/defines.d.cts +22 -0
  39. package/dist/types/defines.d.ts +22 -0
  40. package/dist/types/index.d.cts +12 -0
  41. package/dist/types/index.d.mts +1 -0
  42. package/dist/types/index.d.ts +12 -0
  43. package/dist/types/shaders.d.cts +1 -0
  44. package/dist/types/shaders.d.ts +1 -0
  45. package/dist/types/splatTransform.d.cts +10 -0
  46. package/dist/types/splatTransform.d.ts +10 -0
  47. package/dist/types/utils.d.cts +33 -0
  48. package/dist/types/utils.d.ts +33 -0
  49. package/dist/types/wasm.d.cts +2 -0
  50. package/dist/types/wasm.d.ts +2 -0
  51. package/dist/types/worker.d.cts +42 -0
  52. package/dist/types/worker.d.ts +42 -0
  53. package/docs/GaussianSplatRenderer.md +107 -0
  54. package/docs/SplatAccumulator.md +44 -0
  55. package/docs/SplatEdit.md +84 -0
  56. package/docs/SplatFileType.md +30 -0
  57. package/docs/SplatLoader.md +28 -0
  58. package/docs/SplatMesh.md +80 -0
  59. package/docs/SplatSource.md +26 -0
  60. package/docs/Splats.md +58 -0
  61. package/package.json +109 -0
@@ -0,0 +1,2 @@
1
+ export declare const WASM_MODULE: Promise<WebAssembly.Module>;
2
+ export declare function isInitialized(): boolean;
@@ -0,0 +1,2 @@
1
+ export declare const WASM_MODULE: Promise<WebAssembly.Module>;
2
+ export declare function isInitialized(): boolean;
@@ -0,0 +1,42 @@
1
+ import { SplatResult } from './defines.cjs';
2
+ declare const rpcHandlers: {
3
+ setSortCenters: typeof setSortCenters;
4
+ sortCenters32: typeof sortCenters32;
5
+ loadSplats: typeof loadSplats;
6
+ nextChunk: typeof nextChunk;
7
+ };
8
+ export type RpcHandlers = typeof rpcHandlers;
9
+ declare function setSortCenters({ centers, rangeBases, rangeCounts, rangeOrigins, }: {
10
+ centers: Float32Array;
11
+ rangeBases: Uint32Array;
12
+ rangeCounts: Uint32Array;
13
+ rangeOrigins: Float64Array;
14
+ }): {
15
+ numSplats: number;
16
+ };
17
+ declare function sortCenters32({ numSplats, cameraPosition, direction, radial, ordering, }: {
18
+ numSplats: number;
19
+ cameraPosition: [number, number, number];
20
+ direction: [number, number, number];
21
+ radial: boolean;
22
+ ordering: Uint32Array;
23
+ }): {
24
+ activeSplats: number;
25
+ ordering: Uint32Array<ArrayBufferLike>;
26
+ };
27
+ declare function loadSplats({ url, requestHeader, withCredentials, fileBytes, fileType, pathName, chunked, chunkedLength, }: {
28
+ url?: string;
29
+ requestHeader?: Record<string, string>;
30
+ withCredentials?: boolean;
31
+ fileBytes?: Uint8Array;
32
+ fileType?: string;
33
+ pathName?: string;
34
+ chunked?: boolean;
35
+ chunkedLength?: number;
36
+ }, { sendStatus }: {
37
+ sendStatus: (data: unknown) => void;
38
+ }): Promise<SplatResult>;
39
+ declare function nextChunk({ chunk }: {
40
+ chunk: Uint8Array;
41
+ }): Promise<void>;
42
+ export {};
@@ -0,0 +1,42 @@
1
+ import { SplatResult } from './defines';
2
+ declare const rpcHandlers: {
3
+ setSortCenters: typeof setSortCenters;
4
+ sortCenters32: typeof sortCenters32;
5
+ loadSplats: typeof loadSplats;
6
+ nextChunk: typeof nextChunk;
7
+ };
8
+ export type RpcHandlers = typeof rpcHandlers;
9
+ declare function setSortCenters({ centers, rangeBases, rangeCounts, rangeOrigins, }: {
10
+ centers: Float32Array;
11
+ rangeBases: Uint32Array;
12
+ rangeCounts: Uint32Array;
13
+ rangeOrigins: Float64Array;
14
+ }): {
15
+ numSplats: number;
16
+ };
17
+ declare function sortCenters32({ numSplats, cameraPosition, direction, radial, ordering, }: {
18
+ numSplats: number;
19
+ cameraPosition: [number, number, number];
20
+ direction: [number, number, number];
21
+ radial: boolean;
22
+ ordering: Uint32Array;
23
+ }): {
24
+ activeSplats: number;
25
+ ordering: Uint32Array<ArrayBufferLike>;
26
+ };
27
+ declare function loadSplats({ url, requestHeader, withCredentials, fileBytes, fileType, pathName, chunked, chunkedLength, }: {
28
+ url?: string;
29
+ requestHeader?: Record<string, string>;
30
+ withCredentials?: boolean;
31
+ fileBytes?: Uint8Array;
32
+ fileType?: string;
33
+ pathName?: string;
34
+ chunked?: boolean;
35
+ chunkedLength?: number;
36
+ }, { sendStatus }: {
37
+ sendStatus: (data: unknown) => void;
38
+ }): Promise<SplatResult>;
39
+ declare function nextChunk({ chunk }: {
40
+ chunk: Uint8Array;
41
+ }): Promise<void>;
42
+ export {};
@@ -0,0 +1,107 @@
1
+ # GaussianSplatRenderer
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ ```ts
6
+ new GaussianSplatRenderer(options: GaussianSplatRendererOptions)
7
+ ```
8
+
9
+ ## Basic options
10
+
11
+ | Option | Type | Default | Description |
12
+ | --- | --- | --- | --- |
13
+ | `renderer` | `THREE.WebGLRenderer` | Required | The Three.js WebGL renderer |
14
+ | `onDirty` | `() => void` | `undefined` | Called when loading, generation, or sorting requires another render |
15
+ | `premultipliedAlpha` | `boolean` | `true` | Uses premultiplied alpha while accumulating Splat RGB |
16
+ | `timer` | `THREE.Timer` | New internal timer | Shares time with another animation system; caller owns and updates a supplied timer |
17
+ | `autoUpdate` | `boolean` | `true` | Automatically checks the Splat collection each frame |
18
+ | `preUpdate` | `boolean` | `true` | Updates before drawing; WebXR presentation automatically uses an asynchronous post-render update |
19
+ | `accumPackedSplats` | `boolean` | `false` | Uses compressed Packed Splats for intermediate data, reducing memory at the cost of precision; changing it regenerates the accumulator on the next update |
20
+
21
+ ## Quality and appearance options
22
+
23
+ | Option | Type | Default | Description |
24
+ | --- | --- | --- | --- |
25
+ | `maxStdDev` | `number` | `Math.sqrt(8)` | Maximum standard deviations drawn from each Gaussian center; lower values improve speed but crop edges |
26
+ | `minPixelRadius` | `number` | `1` | Minimum screen-space Splat radius |
27
+ | `maxPixelRadius` | `number` | `512` | Maximum screen-space Splat radius |
28
+ | `minAlpha` | `number` | `0.5 / 255` | Fragments below this alpha are discarded |
29
+ | `enable2DGS` | `boolean` | `false` | Treats a Splat with exactly one zero scale axis as a 2D Gaussian |
30
+ | `preBlurAmount` | `number` | `0` | Adds to the covariance diagonal before opacity correction |
31
+ | `blurAmount` | `number` | `0.3` | Anti-aliasing blur amount with opacity correction |
32
+ | `focalDistance` | `number` | `0` | Distance to the depth-of-field focal plane |
33
+ | `apertureAngle` | `number` | `0` | Full aperture angle in radians; `0` disables depth of field |
34
+ | `clipXY` | `number` | `1.25` | Center-clipping factor relative to the X/Y frustum boundary; `1` clips immediately outside it |
35
+ | `focalAdjustment` | `number` | `2` | Projected Splat-size adjustment; larger values generally look sharper |
36
+
37
+ ## Sorting, material, and offscreen options
38
+
39
+ | Option | Type | Default | Description |
40
+ | --- | --- | --- | --- |
41
+ | `sortRadial` | `boolean` | `false` | Sorts by geometric distance when `true`, or by Z depth when `false` |
42
+ | `minSortIntervalMs` | `number` | `0` | Minimum interval between sort calls, in milliseconds |
43
+ | `transparent` | `boolean` | `true` | Places the Splat material in the Three.js transparent render pass |
44
+ | `depthTest` | `boolean` | `true` | Reads the depth buffer for occlusion with regular meshes |
45
+ | `depthWrite` | `boolean` | `false` | Writes depth; normally undesirable for transparent Splats |
46
+ | `extraUniforms` | `Record<string, unknown>` | `undefined` | Additional values merged into the default shader uniforms |
47
+ | `vertexShader` | `string` | Built in | Replaces the default Splat vertex shader |
48
+ | `fragmentShader` | `string` | Built in | Replaces the default Splat fragment shader |
49
+ | `target` | `TargetOptions` | `undefined` | Creates a dedicated offscreen render target |
50
+
51
+ The `target` structure is:
52
+
53
+ ```ts
54
+ type TargetOptions = {
55
+ width: number;
56
+ height: number;
57
+ doubleBuffer?: boolean; // false
58
+ superXY?: number; // 1-4, default 1
59
+ } & THREE.RenderTargetOptions;
60
+ ```
61
+
62
+ `superXY` renders at a higher resolution and performs simple CPU averaging when `readTarget()` is called. Both `width * superXY` and `height * superXY` must be no greater than 8192.
63
+
64
+ ## Common properties and methods
65
+
66
+ | API | Description |
67
+ | --- | --- |
68
+ | `update({ scene, camera })` | Manually generates and sorts Splats; returns `Promise<void>` |
69
+ | `clearSplats()` | Clears the current display buffer without removing scene objects |
70
+ | `render(scene, camera)` | Performs one Three.js render using this instance as the active Splat renderer |
71
+ | `renderTarget({ scene, camera })` | Renders to the target configured in the constructor |
72
+ | `readTarget()` | Reads the latest offscreen result as an RGBA `Uint8Array` |
73
+ | `renderReadTarget({ scene, camera })` | Renders and reads an offscreen result |
74
+ | `renderCubeMap(...)` | Renders a cube map from a world-space position |
75
+ | `readCubeTargets()` | Reads RGBA bytes from all six cube faces |
76
+ | `renderEnvMap(...)` | Renders and PMREM-prefilters an environment map |
77
+ | `recurseSetEnvMap(root, envMap)` | Assigns an environment map to descendant `MeshStandardMaterial` instances |
78
+ | `dispose()` | Releases materials, geometry, textures, targets, and the sorting worker |
79
+ | `premultipliedAlpha` | A read/write property that recompiles the material when changed |
80
+ | `accumPackedSplats` | A read/write property that switches accumulator encoding on the next update |
81
+
82
+ For an on-demand render loop, connect `onDirty` to the application's render scheduler:
83
+
84
+ ```js
85
+ let needsRender = true;
86
+
87
+ function requestRender() {
88
+ needsRender = true;
89
+ }
90
+
91
+ controls.addEventListener("update", requestRender);
92
+
93
+ const splatRenderer = new GaussianSplatRenderer({
94
+ renderer,
95
+ onDirty: requestRender,
96
+ });
97
+ scene.add(splatRenderer);
98
+
99
+ renderer.setAnimationLoop((time) => {
100
+ controls.update(time);
101
+ if (!needsRender) return;
102
+
103
+ // Clear the flag before rendering so a new onDirty call is preserved.
104
+ needsRender = false;
105
+ renderer.render(scene, camera);
106
+ });
107
+ ```
@@ -0,0 +1,44 @@
1
+ # SplatAccumulator
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ `SplatAccumulator` is the low-level GPU generation buffer used by `GaussianSplatRenderer` to combine visible `SplatMesh` objects into renderable texture arrays. Applications normally should not construct or update it directly.
6
+
7
+ ## Constructor
8
+
9
+ ```ts
10
+ new SplatAccumulator(options?: { packedSplats?: boolean })
11
+ ```
12
+
13
+ | Option | Type | Default | Description |
14
+ | --- | --- | --- | --- |
15
+ | `packedSplats` | `boolean` | `false` | Uses compressed Packed Splats when enabled; otherwise uses normal Splats |
16
+
17
+ The similarly named `GaussianSplatRenderer.accumPackedSplats` option defaults to `false`. Changing it at runtime regenerates that renderer's accumulator on the next update.
18
+
19
+ ## Common state
20
+
21
+ | Property | Description |
22
+ | --- | --- |
23
+ | `numSplats` | Number of valid Splats in the current combined buffer |
24
+ | `maxSplats` | Allocated Splat capacity |
25
+ | `mapping` | `SplatMapping[]` entries associating each visible mesh with its buffer range and versions |
26
+ | `version` | Combined generated-data version |
27
+ | `mappingVersion` | Combined mesh-to-buffer mapping version |
28
+ | `viewOrigin` / `viewDirection` | Camera position and direction used by the current generation pass |
29
+ | `time` / `deltaTime` | Timer values used for per-frame mesh updates |
30
+
31
+ ## Common methods
32
+
33
+ | API | Description |
34
+ | --- | --- |
35
+ | `getTextures()` | Returns the generated Splat data textures, or empty fallback textures before allocation |
36
+ | `getSplatShapeTexture()` | Returns the generated Splat-shape texture |
37
+ | `generateMapping(splatCounts)` | Assigns texture-row-aligned ranges and returns their required capacity |
38
+ | `ensureGenerate({ maxSplats })` | Allocates or grows the generation target; returns whether a new target was created |
39
+ | `generate({ mesh, base, count, renderer })` | Generates one mesh into its assigned accumulator range |
40
+ | `prepareGenerate({ renderer, scene, timer, camera, previous })` | Collects visible meshes, runs frame updates, compares versions, and returns a deferred generation plan |
41
+ | `checkVersions(mapping)` | Reports generated-data, mapping, and sorting changes relative to another mapping |
42
+ | `dispose()` | Releases the accumulator render target |
43
+
44
+ `prepareGenerate()`, `generate()`, and version management are renderer plumbing. Use `GaussianSplatRenderer.update()` for normal manual updates.
@@ -0,0 +1,84 @@
1
+ # SDF color and opacity editing
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ SDF edits affect RGBA only. They do not move Splat centers or invalidate an existing depth order. Available shapes are:
6
+
7
+ ```ts
8
+ SplatEditSdfType.ALL
9
+ SplatEditSdfType.PLANE
10
+ SplatEditSdfType.SPHERE
11
+ SplatEditSdfType.BOX
12
+ SplatEditSdfType.ELLIPSOID
13
+ SplatEditSdfType.CYLINDER
14
+ SplatEditSdfType.CAPSULE
15
+ SplatEditSdfType.INFINITE_CONE
16
+ ```
17
+
18
+ The following edit affects only `splat`:
19
+
20
+ ```js
21
+ import * as THREE from "three";
22
+ import {
23
+ SplatEdit,
24
+ SplatEditRgbaBlendMode,
25
+ SplatEditSdf,
26
+ SplatEditSdfType,
27
+ } from "gaussian-splat-lite";
28
+
29
+ const edit = new SplatEdit({
30
+ name: "Warm sphere",
31
+ rgbaBlendMode: SplatEditRgbaBlendMode.MULTIPLY,
32
+ softEdge: 0.1,
33
+ sdfSmooth: 0,
34
+ });
35
+
36
+ const sphere = new SplatEditSdf({
37
+ type: SplatEditSdfType.SPHERE,
38
+ color: new THREE.Color(1, 0.5, 0.5),
39
+ opacity: 0.4,
40
+ radius: 1,
41
+ });
42
+
43
+ sphere.position.set(0, 0, 0);
44
+ edit.add(sphere);
45
+ splat.add(edit);
46
+ ```
47
+
48
+ Adding a `SplatEdit` directly to the scene, rather than below a particular `SplatMesh`, makes it a global edit for every editable Splat mesh:
49
+
50
+ ```js
51
+ scene.add(edit);
52
+ ```
53
+
54
+ ## SplatEdit options
55
+
56
+ | Option | Type | Default | Description |
57
+ | --- | --- | --- | --- |
58
+ | `name` | `string` | Generated | Object name |
59
+ | `rgbaBlendMode` | `SplatEditRgbaBlendMode` | `MULTIPLY` | Component-wise multiplication or `ADD_RGBA` addition |
60
+ | `sdfSmooth` | `number` | `0` | Smoothing amount when combining SDF shapes |
61
+ | `softEdge` | `number` | `0` | Region-edge feathering distance |
62
+ | `invert` | `boolean` | `false` | Inverts the entire edit region |
63
+ | `sdfs` | `SplatEditSdf[]` | `null` | Explicit shape list; SDFs can instead be child objects |
64
+
65
+ ## SplatEdit methods
66
+
67
+ | API | Description |
68
+ | --- | --- |
69
+ | `addSdf(sdf)` | Adds an SDF to the explicit `sdfs` list without adding the same object twice |
70
+ | `removeSdf(sdf)` | Removes an SDF from the explicit `sdfs` list |
71
+
72
+ `addSdf()` and `removeSdf()` manage the explicit list. When `sdfs` is not `null`, the renderer uses that list instead of traversing the `SplatEdit` child hierarchy. Use `edit.add(sdf)` and `edit.remove(sdf)` when the SDFs should instead be regular `THREE.Object3D` children.
73
+
74
+ ## SplatEditSdf options
75
+
76
+ | Option | Type | Default | Description |
77
+ | --- | --- | --- | --- |
78
+ | `type` | `SplatEditSdfType` | `SPHERE` | SDF shape |
79
+ | `invert` | `boolean` | `false` | Inverts the inside and outside of the shape |
80
+ | `opacity` | `number` | `1` | Alpha value used by the edit |
81
+ | `color` | `THREE.Color` | White | RGB value used by the edit |
82
+ | `radius` | `number` | `0` | Radius used by sphere, cylinder, capsule, and related shapes |
83
+
84
+ An SDF extends `THREE.Object3D`; its position, rotation, and scale define the edit region. Edits execute in creation order by default, and the order can be changed through `edit.ordering`.
@@ -0,0 +1,30 @@
1
+ # SplatFileType
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ `SplatFileType` identifies the two file formats decoded by Gaussian-Splat-Lite:
6
+
7
+ ```ts
8
+ enum SplatFileType {
9
+ PLY = "ply",
10
+ SPZ = "spz",
11
+ }
12
+ ```
13
+
14
+ The loader normally infers the type from a URL or `fileName` ending in `.ply` or `.spz`. Specify `fileType` when the input name has no recognizable extension or when loading unnamed in-memory data.
15
+
16
+ ```js
17
+ import { SplatFileType, SplatMesh } from "gaussian-splat-lite";
18
+
19
+ const fromUrl = new SplatMesh({
20
+ url: "/download/model",
21
+ fileType: SplatFileType.SPZ,
22
+ });
23
+
24
+ const fromMemory = new SplatMesh({
25
+ fileBytes: bytes,
26
+ fileType: SplatFileType.PLY,
27
+ });
28
+ ```
29
+
30
+ The same `fileType` option is accepted by `SplatMesh`, `Splats`, and the low-level `SplatLoader.loadInternal()` APIs.
@@ -0,0 +1,28 @@
1
+ # SplatLoader
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ `SplatLoader` follows the Three.js `Loader` API style. It first returns decoded `Splats`; `parse()` then wraps that source in a `SplatMesh`.
6
+
7
+ ```js
8
+ import { SplatLoader } from "gaussian-splat-lite";
9
+
10
+ const loader = new SplatLoader();
11
+ const decoded = await loader.loadAsync("/assets/model.spz", (event) => {
12
+ console.log(event.loaded, event.total);
13
+ });
14
+
15
+ const splat = loader.parse(decoded);
16
+ scene.add(splat);
17
+ ```
18
+
19
+ The callback form matches the normal Three.js Loader pattern:
20
+
21
+ ```js
22
+ loader.load(
23
+ "/assets/model.ply",
24
+ (decoded) => scene.add(loader.parse(decoded)),
25
+ (event) => console.log(event.loaded, event.total),
26
+ (error) => console.error(error),
27
+ );
28
+ ```
@@ -0,0 +1,80 @@
1
+ # SplatMesh
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ `SplatMesh` extends `THREE.Object3D`, so it supports the standard `position`, `quaternion`, `scale`, `visible`, `layers`, and parent/child hierarchy APIs.
6
+
7
+ ```ts
8
+ new SplatMesh(options?: SplatMeshOptions)
9
+ ```
10
+
11
+ ## Options
12
+
13
+ | Option | Type | Default | Description |
14
+ | --- | --- | --- | --- |
15
+ | `url` | `string` | `undefined` | PLY/SPZ file URL |
16
+ | `fileBytes` | `Uint8Array \| ArrayBuffer` | `undefined` | Complete file data in memory |
17
+ | `fileType` | `SplatFileType` | Inferred from name | Explicitly selects `PLY` or `SPZ` |
18
+ | `fileName` | `string` | `undefined` | Supplies a name for inferring the format of byte or stream input |
19
+ | `stream` | `ReadableStream` | `undefined` | Chunked input stream |
20
+ | `streamLength` | `number` | `undefined` | Total stream length for progress reporting |
21
+ | `splats` | `SplatSource` | New `Splats` | Uses an existing built-in or custom source |
22
+ | `maxSplats` | `number` | `0` | Initial capacity for programmatic construction; grows when necessary |
23
+ | `constructSplats` | `(splats) => void \| Promise<void>` | `undefined` | Populates `Splats` during initialization |
24
+ | `onProgress` | `(event: ProgressEvent) => void` | `undefined` | Download or stream decoding progress callback |
25
+ | `onLoad` | `(mesh) => void \| Promise<void>` | `undefined` | Called after initialization completes |
26
+ | `editable` | `boolean` | `true` | Applies global and local SDF edits |
27
+ | `raycastable` | `boolean` | `true` | Participates in Three.js raycasting |
28
+ | `minRaycastOpacity` | `number` | `0.05` | Per-Splat kernel-alpha threshold; clips the raycast hit area at this opacity, including special-shape Splats |
29
+ | `onFrame` | `({ mesh, time, deltaTime }) => void` | `undefined` | Called before Splat generation for a frame |
30
+
31
+ Normally, choose exactly one of `url`, `fileBytes`, or `stream`. The `splats` option is intended for advanced custom sources and should not be mixed with file input.
32
+
33
+ ## Common properties
34
+
35
+ | Property | Type / default | Description |
36
+ | --- | --- | --- |
37
+ | `initialized` | `Promise<SplatMesh>` | Resolves after asynchronous loading and construction |
38
+ | `isInitialized` | `boolean` | Whether initialization has completed |
39
+ | `numSplats` | `number` | Current Splat count |
40
+ | `recolor` | `THREE.Color(1, 1, 1)` | RGB multiplier applied to the entire object |
41
+ | `opacity` | `1` | Opacity multiplier applied to the entire object |
42
+ | `maxSh` | `3` | Maximum spherical-harmonic degree; use `0` for base color only |
43
+ | `edits` | `SplatEdit[] \| null` | Explicit edits applied only to this mesh |
44
+ | `splats` | `SplatSource \| undefined` | Current underlying source |
45
+ | `needsUpdate` | `boolean` setter | Set to `true` to force Splat regeneration and depth re-sorting; `false` does nothing |
46
+
47
+ ## Common methods
48
+
49
+ ```ts
50
+ await mesh.initialized;
51
+
52
+ mesh.getBoundingBox(); // Centers only; faster.
53
+ mesh.getBoundingBox(false); // Includes rotated and scaled Splat bounds.
54
+
55
+ mesh.pushSplat(center, scales, quaternion, opacity, color);
56
+ mesh.forEachSplat((index, center, scales, quaternion, opacity, color) => {});
57
+
58
+ mesh.updateVersion(); // Regenerate and re-sort.
59
+ mesh.updateVersion({ sort: false }); // Appearance only; reuse sorting.
60
+ mesh.updateMappingVersion(); // Count or mapping changed.
61
+ mesh.dispose();
62
+ ```
63
+
64
+ `getBoundingBox()` can only be called after initialization. `pushSplat()` only affects a mesh backed by the built-in `Splats` source.
65
+
66
+ ## Raycasting
67
+
68
+ `SplatMesh` implements the Three.js `raycast()` protocol:
69
+
70
+ ```js
71
+ const raycaster = new THREE.Raycaster();
72
+ raycaster.setFromCamera(pointer, camera);
73
+
74
+ const intersections = raycaster.intersectObject(splat);
75
+ if (intersections.length > 0) {
76
+ console.log(intersections[0].point, intersections[0].distance);
77
+ }
78
+ ```
79
+
80
+ Raycasting currently requires the built-in `Splats` source and `raycastable: true`. During the earliest stage of module startup, raycasting temporarily returns no intersections until the main-thread WebAssembly instance is ready.
@@ -0,0 +1,26 @@
1
+ # Custom SplatSource
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ Advanced integrations can implement and supply a custom `SplatSource`. A source must provide both CPU center iteration and GPU texture access:
6
+
7
+ ```ts
8
+ interface SplatSource {
9
+ needsUpdate: boolean;
10
+
11
+ dispose(): void;
12
+ getNumSplats(): number;
13
+ getNumSh(): number;
14
+ getSplatTextures(): readonly [
15
+ THREE.DataArrayTexture,
16
+ THREE.DataArrayTexture,
17
+ ];
18
+ getShTextures(): SplatShTextures;
19
+ forEachCenter(callback: (index, x, y, z) => void): void;
20
+ forEachSplat(callback: (index, center, scales, quaternion, opacity, color) => void): void;
21
+ }
22
+
23
+ const mesh = new SplatMesh({ splats: customSource });
24
+ ```
25
+
26
+ This is an extension point for the low-level encoding. Shader construction, arbitrary per-Splat modifiers, and dynamic shader nodes are deliberately outside this interface.
package/docs/Splats.md ADDED
@@ -0,0 +1,58 @@
1
+ # Splats
2
+
3
+ [Back to the API overview](../README.md#core-concepts-and-public-api)
4
+
5
+ `Splats` is the built-in mutable source. In addition to file input, it provides direct per-Splat access:
6
+
7
+ ```js
8
+ const data = splat.splats;
9
+ const item = data.getSplat(0);
10
+
11
+ data.setSplat(
12
+ 0,
13
+ item.center,
14
+ item.scales.multiplyScalar(1.1),
15
+ item.quaternion,
16
+ item.opacity,
17
+ item.color,
18
+ );
19
+
20
+ data.pushSplat(center, scales, quaternion, opacity, color);
21
+ data.forEachSplat((index, center, scales, quaternion, opacity, color) => {});
22
+ ```
23
+
24
+ The constructor and `reinitialize()` accept the same `SplatsOptions`:
25
+
26
+ | Option | Type | Default | Description |
27
+ | --- | --- | --- | --- |
28
+ | `url` | `string` | `undefined` | PLY/SPZ file URL |
29
+ | `fileBytes` | `Uint8Array \| ArrayBuffer` | `undefined` | In-memory file data |
30
+ | `fileType` | `SplatFileType` | Inferred from name | Explicit file format |
31
+ | `fileName` | `string` | `undefined` | Name used to infer byte or stream input format |
32
+ | `stream` | `ReadableStream` | `undefined` | Chunked input stream |
33
+ | `streamLength` | `number` | `undefined` | Total input-stream length |
34
+ | `maxSplats` | `number` | `0` | Initial capacity |
35
+ | `splatArrays` | `[Uint32Array, Uint32Array]` | Empty arrays | Two pre-encoded Splat data arrays |
36
+ | `numSplats` | `number` | Capacity | Number of valid Splats in `splatArrays` |
37
+ | `construct` | `(splats) => void \| Promise<void>` | `undefined` | Populates the source during initialization |
38
+ | `onProgress` | `(event: ProgressEvent) => void` | `undefined` | Loading progress callback |
39
+ | `extra` | `Record<string, unknown>` | `{}` | Additional data such as SH arrays |
40
+
41
+ File input, `splatArrays`, and `construct` serve different initialization paths and normally should not be mixed. Supplying `splatArrays` directly is a low-level encoded-data API.
42
+
43
+ The main methods are:
44
+
45
+ | API | Description |
46
+ | --- | --- |
47
+ | `initialized` / `isInitialized` | Asynchronous initialization state |
48
+ | `getNumSplats()` / `getNumSh()` | Returns Splat count and available SH degree |
49
+ | `getSplat(index)` | Decodes and returns one Splat |
50
+ | `setSplat(index, ...)` | Adds or overwrites one Splat |
51
+ | `pushSplat(...)` | Appends one Splat |
52
+ | `forEachCenter(callback)` | Iterates centers only, suitable for spatial-index construction |
53
+ | `forEachSplat(callback)` | Iterates and fully decodes every Splat |
54
+ | `ensureSplats(count)` | Ensures underlying array capacity |
55
+ | `reinitialize(options)` | Reinitializes from a file, stream, array, or construction callback |
56
+ | `dispose()` | Releases textures and data references |
57
+
58
+ After modifying low-level arrays such as `splatArrays` directly, set `data.needsUpdate = true`. Prefer `setSplat()` and `pushSplat()`, which manage capacity and update state automatically.
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "gaussian-splat-lite",
3
+ "version": "0.1.0",
4
+ "description": "A lightweight Three.js Gaussian Splatting renderer with PLY/SPZ loading, WebAssembly-accelerated sorting and raycasting, multi-Splat rendering, and high-precision GIS/ECEF coordinate support",
5
+ "author": "William Liu <lyz15972107087@gmail.com>",
6
+ "type": "module",
7
+ "license": "Apache-2.0",
8
+ "main": "./dist/gaussian-splat-lite.cjs",
9
+ "module": "./dist/gaussian-splat-lite.module.js",
10
+ "types": "./dist/types/index.d.mts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/types/index.d.mts",
15
+ "default": "./dist/gaussian-splat-lite.module.js"
16
+ },
17
+ "require": {
18
+ "types": "./dist/types/index.d.cts",
19
+ "default": "./dist/gaussian-splat-lite.cjs"
20
+ }
21
+ }
22
+ },
23
+ "scripts": {
24
+ "build": "npm run build:production && npm run build:dev && npm run build:types:cjs",
25
+ "build:dev": "vite build --mode dev",
26
+ "build:production": "vite build --mode production",
27
+ "build:site": "vite build --config vite.site.config.ts",
28
+ "build:types:cjs": "node scripts/build-cjs-types.js",
29
+ "build:wasm": "node rust/build_wasm.js",
30
+ "build:watch": "onchange 'src/**/*.{ts,glsl}' -- npm run build:dev",
31
+ "check": "tsc --noEmit",
32
+ "check:rust": "cargo fmt --manifest-path rust/Cargo.toml --all -- --check",
33
+ "clean": "rm -rf dist/ node_modules/ rust/target/ rust/gaussian-splat-rs/pkg/",
34
+ "dev": "npm run build:dev && node scripts/dev.js",
35
+ "format": "biome format .",
36
+ "format:fix": "biome format . --fix",
37
+ "lint": "biome check .",
38
+ "lint:fix": "biome check . --fix",
39
+ "pack:check": "npm pack --dry-run && publint",
40
+ "prepack": "npm run check && npm run check:rust && npm run lint && npm test && npm run build",
41
+ "release:check": "npm run build:wasm && npm run build:site && npm run pack:check",
42
+ "start": "npm run dev",
43
+ "test": "npm run test:js && npm run test:rust",
44
+ "test:js": "node --no-warnings --loader ts-node/esm --test test/utils.test.ts",
45
+ "test:rust": "cargo test --manifest-path rust/Cargo.toml --workspace --locked"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "docs",
50
+ "CHANGELOG.md",
51
+ "CONTRIBUTING.md",
52
+ "Gaussian-Splat-Lite.svg",
53
+ "LICENSE",
54
+ "NOTICE",
55
+ "README.md",
56
+ "THIRD_PARTY_LICENSES.md"
57
+ ],
58
+ "engines": {
59
+ "node": ">=20.9"
60
+ },
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "git+https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite.git"
64
+ },
65
+ "homepage": "https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite#readme",
66
+ "bugs": {
67
+ "url": "https://github.com/WilliamLiu-1997/Gaussian-Splat-Lite/issues"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public",
71
+ "registry": "https://registry.npmjs.org/"
72
+ },
73
+ "devDependencies": {
74
+ "@biomejs/biome": "1.9.4",
75
+ "@types/three": "0.185.1",
76
+ "gaussian-splat-rs": "file:rust/gaussian-splat-rs/pkg",
77
+ "onchange": "7.1.0",
78
+ "publint": "0.3.24",
79
+ "three": "^0.185.1",
80
+ "ts-node": "10.9.2",
81
+ "typescript": "^5.7.3",
82
+ "vite": "^6.0.11",
83
+ "vite-plugin-arraybuffer": "^0.1.4",
84
+ "vite-plugin-dts": "^4.5.4",
85
+ "vite-plugin-glsl": "^1.3.1"
86
+ },
87
+ "peerDependencies": {
88
+ "three": ">=0.185.1"
89
+ },
90
+ "keywords": [
91
+ "3d",
92
+ "3dgs",
93
+ "ecef",
94
+ "gaussian-splatting",
95
+ "gis",
96
+ "gsplats",
97
+ "ply",
98
+ "spz",
99
+ "three.js",
100
+ "threejs",
101
+ "webassembly",
102
+ "webgl"
103
+ ],
104
+ "allowScripts": {
105
+ "@biomejs/biome@1.9.4": true,
106
+ "esbuild@0.25.2": true,
107
+ "fsevents@2.3.3": true
108
+ }
109
+ }