A .ksplat file opens with a 4096-byte header, followed by a 1024-byte header for each
section. Both are mostly unused space. This page follows SplatBuffer.js in
GaussianSplats3D, which writes version 0.1. All numbers are little-endian.
The file header
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 1 | uint8 | versionMajor | 0 |
| 1 | 1 | uint8 | versionMinor | 1 |
| 2 | 2 | Not used | ||
| 4 | 4 | uint32 | maxSectionCount | How many section headers follow |
| 8 | 4 | uint32 | sectionCount | How many sections are in use |
| 12 | 4 | uint32 | maxSplatCount | The splats all sections have room for |
| 16 | 4 | uint32 | splatCount | The splats in the file |
| 20 | 2 | uint16 | compressionLevel | 0, 1 or 2; see Compression levels |
| 22 | 2 | Not used | ||
| 24 | 12 | 3 × float32 | sceneCenter | The centre of the scene, x, y, z |
| 36 | 4 | float32 | minSphericalHarmonicsCoeff | The value of a harmonics byte 0 at level 2; see below |
| 40 | 4 | float32 | maxSphericalHarmonicsCoeff | The value of a harmonics byte 255 at level 2 |
| 44 | 4052 | Not used, to the end of the header at 4096 |
The reader in SplatBuffer.js reads the version but does not check it.
Compression levels
| Level | Centre | Scale | Rotation | Colour | Harmonics | Bytes a splat at degree 0, 1, 2 |
|---|---|---|---|---|---|---|
| 0 | 3 × float32 | 3 × float32 | 4 × float32 | 4 × uint8 | float32 | 44, 80, 140 |
| 1 | 3 × uint16, in a bucket | 3 × half | 4 × half | 4 × uint8 | half | 24, 42, 72 |
| 2 | 3 × uint16, in a bucket | 3 × half | 4 × half | 4 × uint8 | uint8 | 24, 33, 48 |
“Half” is the IEEE 754 16-bit floating point number. The splat record itself is on Sections and splats.
The harmonics range
At level 2 each spherical harmonics coefficient is a byte u, which stands for u / 255 × (max − min) + min, with min and max from offsets 36 and 40. When either is 0, the reader uses −1.5 for the minimum or 1.5 for the maximum: half of the library’s 8-bit range constant, 3. The writer stores a coefficient v as ⌊(v − min) / (max − min) × 255⌋, clamped to 0 to 255.
The section header
maxSectionCount section headers follow the file header, 1024 bytes each,
from offset 4096.
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| +0 | 4 | uint32 | splatCount | The splats in this section |
| +4 | 4 | uint32 | maxSplatCount | The splat records the section has room for |
| +8 | 4 | uint32 | bucketSize | The splats in a full bucket |
| +12 | 4 | uint32 | bucketCount | The buckets, full and partly filled |
| +16 | 4 | float32 | bucketBlockSize | The width of a bucket’s cube |
| +20 | 2 | uint16 | bucketStorageSizeBytes | The bytes a bucket centre takes: 12 at levels 1 and 2, 0 at level 0 |
| +22 | 2 | Not used | ||
| +24 | 4 | uint32 | compressionScaleRange | What a centre offset counts up to; 0 means the level’s default, 32767 (1 at level 0) |
| +28 | 4 | uint32 | storageSizeBytes | The bytes of this section’s data |
| +32 | 4 | uint32 | fullBucketCount | Buckets with bucketSize splats |
| +36 | 4 | uint32 | partiallyFilledBucketCount | Buckets with fewer, whose lengths are stored with the data |
| +40 | 2 | uint16 | sphericalHarmonicsDegree | 0, 1 or 2 |
| +42 | 982 | Not used |
The section data starts after the last section header, at
4096 + 1024 × maxSectionCount, and each section’s data follows the one
before, storageSizeBytes long. Splats are numbered across sections, each
section starting after the previous section’s maxSplatCount.