@loaders.gl/splats 4.5.3 → 5.0.0-alpha.10

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 (80) hide show
  1. package/LICENSE +14 -3
  2. package/dist/dist.dev.js +33699 -27589
  3. package/dist/dist.min.js +49 -52
  4. package/dist/index.cjs +2880 -689
  5. package/dist/index.cjs.map +3 -4
  6. package/dist/index.d.ts +6 -5
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +5 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/ksplat-loader-types.d.ts +24 -1
  11. package/dist/ksplat-loader-types.d.ts.map +1 -1
  12. package/dist/ksplat-loader-types.js +9 -3
  13. package/dist/ksplat-loader-types.js.map +1 -1
  14. package/dist/ksplat-loader.d.ts +1 -0
  15. package/dist/ksplat-loader.d.ts.map +1 -1
  16. package/dist/ksplat-loader.js +2 -1
  17. package/dist/ksplat-loader.js.map +1 -1
  18. package/dist/lib/parse-ksplat.d.ts.map +1 -1
  19. package/dist/lib/parse-ksplat.js +2 -2
  20. package/dist/lib/parse-ksplat.js.map +1 -1
  21. package/dist/lib/parse-rad-chunk.js +5 -5
  22. package/dist/lib/parse-rad-chunk.js.map +1 -1
  23. package/dist/lib/parse-spz.d.ts.map +1 -1
  24. package/dist/lib/parse-spz.js +156 -7
  25. package/dist/lib/parse-spz.js.map +1 -1
  26. package/dist/lib/splats-arrow-table.d.ts.map +1 -1
  27. package/dist/lib/splats-arrow-table.js +0 -1
  28. package/dist/lib/splats-arrow-table.js.map +1 -1
  29. package/dist/rad-loader-types.d.ts +21 -1
  30. package/dist/rad-loader-types.d.ts.map +1 -1
  31. package/dist/rad-loader-types.js +9 -3
  32. package/dist/rad-loader-types.js.map +1 -1
  33. package/dist/rad-loader.d.ts +1 -0
  34. package/dist/rad-loader.d.ts.map +1 -1
  35. package/dist/rad-loader.js +2 -1
  36. package/dist/rad-loader.js.map +1 -1
  37. package/dist/rad-source-loader.d.ts +6 -3
  38. package/dist/rad-source-loader.d.ts.map +1 -1
  39. package/dist/rad-source-loader.js +15 -6
  40. package/dist/rad-source-loader.js.map +1 -1
  41. package/dist/rad-zod-schema.cjs.map +0 -1
  42. package/dist/splat-loader-types.d.ts +24 -1
  43. package/dist/splat-loader-types.d.ts.map +1 -1
  44. package/dist/splat-loader-types.js +9 -3
  45. package/dist/splat-loader-types.js.map +1 -1
  46. package/dist/splat-loader.d.ts +1 -0
  47. package/dist/splat-loader.d.ts.map +1 -1
  48. package/dist/splat-loader.js +2 -1
  49. package/dist/splat-loader.js.map +1 -1
  50. package/dist/splats-format.d.ts +4 -0
  51. package/dist/splats-format.d.ts.map +1 -1
  52. package/dist/splats-format.js +4 -0
  53. package/dist/splats-format.js.map +1 -1
  54. package/dist/spz-loader-types.d.ts +25 -1
  55. package/dist/spz-loader-types.d.ts.map +1 -1
  56. package/dist/spz-loader-types.js +9 -3
  57. package/dist/spz-loader-types.js.map +1 -1
  58. package/dist/spz-loader.d.ts +1 -0
  59. package/dist/spz-loader.d.ts.map +1 -1
  60. package/dist/spz-loader.js +2 -1
  61. package/dist/spz-loader.js.map +1 -1
  62. package/dist/types.d.ts +6 -0
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +6 -6
  65. package/src/index.ts +6 -5
  66. package/src/ksplat-loader-types.ts +9 -2
  67. package/src/ksplat-loader.ts +3 -1
  68. package/src/lib/parse-ksplat.ts +2 -4
  69. package/src/lib/parse-rad-chunk.ts +5 -5
  70. package/src/lib/parse-spz.ts +193 -8
  71. package/src/lib/splats-arrow-table.ts +0 -2
  72. package/src/rad-loader-types.ts +9 -2
  73. package/src/rad-loader.ts +3 -1
  74. package/src/rad-source-loader.ts +21 -8
  75. package/src/splat-loader-types.ts +9 -2
  76. package/src/splat-loader.ts +3 -1
  77. package/src/splats-format.ts +4 -0
  78. package/src/spz-loader-types.ts +9 -2
  79. package/src/spz-loader.ts +3 -1
  80. package/src/types.ts +7 -0
@@ -1,5 +1,26 @@
1
1
  import type { MeshArrowTable } from '@loaders.gl/schema';
2
- /** Loader metadata for Niantic Spatial `.spz` Gaussian splat files. */
2
+ import type { SplatsLoaderOptions } from "./types.js";
3
+ /** Preloads the parser-bearing SPZ loader implementation. */
4
+ declare function preload(): Promise<{
5
+ readonly parse: (arrayBuffer: ArrayBuffer, options?: SplatsLoaderOptions) => Promise<MeshArrowTable>;
6
+ readonly version: any;
7
+ readonly options: {
8
+ readonly splats: {
9
+ readonly shape: "arrow-table";
10
+ };
11
+ };
12
+ readonly name: "SPZ";
13
+ readonly id: "spz";
14
+ readonly module: "splats";
15
+ readonly format: "spz";
16
+ readonly extensions: ["spz"];
17
+ readonly mimeTypes: ["application/octet-stream"];
18
+ readonly binary: true;
19
+ readonly tests: [ArrayBuffer];
20
+ readonly dataType: MeshArrowTable;
21
+ readonly batchType: never;
22
+ }>;
23
+ /** Metadata-only loader for Niantic Spatial `.spz` Gaussian splat files. */
3
24
  export declare const SPZLoader: {
4
25
  readonly version: any;
5
26
  readonly options: {
@@ -7,9 +28,11 @@ export declare const SPZLoader: {
7
28
  readonly shape: "arrow-table";
8
29
  };
9
30
  };
31
+ readonly preload: typeof preload;
10
32
  readonly name: "SPZ";
11
33
  readonly id: "spz";
12
34
  readonly module: "splats";
35
+ readonly format: "spz";
13
36
  readonly extensions: ["spz"];
14
37
  readonly mimeTypes: ["application/octet-stream"];
15
38
  readonly binary: true;
@@ -17,4 +40,5 @@ export declare const SPZLoader: {
17
40
  readonly dataType: MeshArrowTable;
18
41
  readonly batchType: never;
19
42
  };
43
+ export {};
20
44
  //# sourceMappingURL=spz-loader-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spz-loader-types.d.ts","sourceRoot":"","sources":["../src/spz-loader-types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAQvD,uEAAuE;AACvE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;uBACS,cAAc;wBACxB,KAAK;CAQ6C,CAAC"}
1
+ {"version":3,"file":"spz-loader-types.d.ts","sourceRoot":"","sources":["../src/spz-loader-types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,mBAAgB;AAOjD,6DAA6D;AAC7D,iBAAe,OAAO;;;;;;;;;;;;;;;;uBAOS,cAAc;wBACxB,KAAK;GALzB;AAED,4EAA4E;AAC5E,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;uBACS,cAAc;wBACxB,KAAK;CAS6C,CAAC"}
@@ -4,8 +4,13 @@
4
4
  import { SPZFormat } from "./splats-format.js";
5
5
  // __VERSION__ is injected by babel-plugin-version-inline
6
6
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
7
- const VERSION = typeof "4.5.3" !== 'undefined' ? "4.5.3" : 'latest';
8
- /** Loader metadata for Niantic Spatial `.spz` Gaussian splat files. */
7
+ const VERSION = typeof "5.0.0-alpha.10" !== 'undefined' ? "5.0.0-alpha.10" : 'latest';
8
+ /** Preloads the parser-bearing SPZ loader implementation. */
9
+ async function preload() {
10
+ const { SPZLoaderWithParser } = await import("./spz-loader.js");
11
+ return SPZLoaderWithParser;
12
+ }
13
+ /** Metadata-only loader for Niantic Spatial `.spz` Gaussian splat files. */
9
14
  export const SPZLoader = {
10
15
  dataType: null,
11
16
  batchType: null,
@@ -15,6 +20,7 @@ export const SPZLoader = {
15
20
  splats: {
16
21
  shape: 'arrow-table'
17
22
  }
18
- }
23
+ },
24
+ preload
19
25
  };
20
26
  //# sourceMappingURL=spz-loader-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spz-loader-types.js","sourceRoot":"","sources":["../src/spz-loader-types.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,+BAA+B;AAC/B,oCAAoC;AAKpC,OAAO,EAAC,SAAS,EAAC,2BAAwB;AAE1C,yDAAyD;AACzD,qDAAqD;AACrD,MAAM,OAAO,GAAG,cAAkB,KAAK,WAAW,CAAC,CAAC,SAAa,CAAC,CAAC,QAAQ,CAAC;AAE5E,uEAAuE;AACvE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,QAAQ,EAAE,IAAiC;IAC3C,SAAS,EAAE,IAAa;IACxB,GAAG,SAAS;IACZ,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE;QACP,MAAM,EAAE;YACN,KAAK,EAAE,aAAa;SACrB;KACF;CACoE,CAAC"}
1
+ {"version":3,"file":"spz-loader-types.js","sourceRoot":"","sources":["../src/spz-loader-types.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,+BAA+B;AAC/B,oCAAoC;AAKpC,OAAO,EAAC,SAAS,EAAC,2BAAwB;AAE1C,yDAAyD;AACzD,qDAAqD;AACrD,MAAM,OAAO,GAAG,uBAAkB,KAAK,WAAW,CAAC,CAAC,kBAAa,CAAC,CAAC,QAAQ,CAAC;AAE5E,6DAA6D;AAC7D,KAAK,UAAU,OAAO;IACpB,MAAM,EAAC,mBAAmB,EAAC,GAAG,MAAM,MAAM,mBAAgB,CAAC;IAC3D,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,QAAQ,EAAE,IAAiC;IAC3C,SAAS,EAAE,IAAa;IACxB,GAAG,SAAS;IACZ,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE;QACP,MAAM,EAAE;YACN,KAAK,EAAE,aAAa;SACrB;KACF;IACD,OAAO;CAC8D,CAAC"}
@@ -12,6 +12,7 @@ export declare const SPZLoaderWithParser: {
12
12
  readonly name: "SPZ";
13
13
  readonly id: "spz";
14
14
  readonly module: "splats";
15
+ readonly format: "spz";
15
16
  readonly extensions: ["spz"];
16
17
  readonly mimeTypes: ["application/octet-stream"];
17
18
  readonly binary: true;
@@ -1 +1 @@
1
- {"version":3,"file":"spz-loader.d.ts","sourceRoot":"","sources":["../src/spz-loader.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,mBAAgB;AAIjD,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB;kCAEH,WAAW,YAAY,mBAAmB;;;;;;;;;;;;;;;;CAEU,CAAC"}
1
+ {"version":3,"file":"spz-loader.d.ts","sourceRoot":"","sources":["../src/spz-loader.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAC,mBAAmB,EAAC,mBAAgB;AAMjD,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB;kCAEH,WAAW,YAAY,mBAAmB;;;;;;;;;;;;;;;;;CAEU,CAAC"}
@@ -3,9 +3,10 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
  import { parseSPZ } from "./lib/parse-spz.js";
5
5
  import { SPZLoader as SPZLoaderMetadata } from "./spz-loader-types.js";
6
+ const { preload: _SPZLoaderPreload, ...SPZLoaderMetadataWithoutPreload } = SPZLoaderMetadata;
6
7
  /** Parser-bearing loader for Niantic Spatial `.spz` Gaussian splat files. */
7
8
  export const SPZLoaderWithParser = {
8
- ...SPZLoaderMetadata,
9
+ ...SPZLoaderMetadataWithoutPreload,
9
10
  parse: async (arrayBuffer, options) => parseSPZ(arrayBuffer, options)
10
11
  };
11
12
  //# sourceMappingURL=spz-loader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spz-loader.js","sourceRoot":"","sources":["../src/spz-loader.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,+BAA+B;AAC/B,oCAAoC;AAKpC,OAAO,EAAC,QAAQ,EAAC,2BAAwB;AACzC,OAAO,EAAC,SAAS,IAAI,iBAAiB,EAAC,8BAA2B;AAElE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,GAAG,iBAAiB;IACpB,KAAK,EAAE,KAAK,EAAE,WAAwB,EAAE,OAA6B,EAAE,EAAE,CACvE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC+C,CAAC"}
1
+ {"version":3,"file":"spz-loader.js","sourceRoot":"","sources":["../src/spz-loader.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,+BAA+B;AAC/B,oCAAoC;AAKpC,OAAO,EAAC,QAAQ,EAAC,2BAAwB;AACzC,OAAO,EAAC,SAAS,IAAI,iBAAiB,EAAC,8BAA2B;AAElE,MAAM,EAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,+BAA+B,EAAC,GAAG,iBAAiB,CAAC;AAE3F,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,GAAG,+BAA+B;IAClC,KAAK,EAAE,KAAK,EAAE,WAAwB,EAAE,OAA6B,EAAE,EAAE,CACvE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC+C,CAAC"}
package/dist/types.d.ts CHANGED
@@ -4,8 +4,14 @@ export type SplatsLoaderOptions = LoaderOptions & {
4
4
  splats?: {
5
5
  /** Output shape. V1 supports loaders.gl Mesh Arrow tables. */
6
6
  shape?: 'arrow-table';
7
+ /** Coordinate frame stored in the source SPZ payload. */
8
+ sourceCoordinateSystem?: SPZCoordinateSystem;
9
+ /** Coordinate frame expected by the caller. Defaults to the source frame. */
10
+ targetCoordinateSystem?: SPZCoordinateSystem;
7
11
  };
8
12
  };
13
+ /** Coordinate-system labels used by the SPZ container and glTF bridge. */
14
+ export type SPZCoordinateSystem = 'RUB' | 'LUF' | 'RUF' | 'UNSPECIFIED';
9
15
  /** Linear Gaussian splat values before Arrow table construction. */
10
16
  export type GaussianSplats = {
11
17
  /** Source format identifier. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AAE5D,gDAAgD;AAChD,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IAChD,MAAM,CAAC,EAAE;QACP,8DAA8D;QAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;KACvB,CAAC;CACH,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG;IAC3B,gCAAgC;IAChC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3C,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,YAAY,CAAC;IACxB,0DAA0D;IAC1D,MAAM,EAAE,YAAY,CAAC;IACrB,uDAAuD;IACvD,SAAS,EAAE,YAAY,CAAC;IACxB,+CAA+C;IAC/C,MAAM,EAAE,UAAU,CAAC;IACnB,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,YAAY,CAAC;IACpC,kFAAkF;IAClF,SAAS,EAAE,YAAY,CAAC;IACxB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAClC,gDAAgD;IAChD,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AAE5D,gDAAgD;AAChD,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IAChD,MAAM,CAAC,EAAE;QACP,8DAA8D;QAC9D,KAAK,CAAC,EAAE,aAAa,CAAC;QACtB,yDAAyD;QACzD,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;QAC7C,6EAA6E;QAC7E,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;KAC9C,CAAC;CACH,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,aAAa,CAAC;AAExE,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG;IAC3B,gCAAgC;IAChC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3C,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,YAAY,CAAC;IACxB,0DAA0D;IAC1D,MAAM,EAAE,YAAY,CAAC;IACrB,uDAAuD;IACvD,SAAS,EAAE,YAAY,CAAC;IACxB,+CAA+C;IAC/C,MAAM,EAAE,UAAU,CAAC;IACnB,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,YAAY,CAAC;IACpC,kFAAkF;IAClF,SAAS,EAAE,YAAY,CAAC;IACxB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAClC,gDAAgD;IAChD,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/splats",
3
- "version": "4.5.3",
3
+ "version": "5.0.0-alpha.10",
4
4
  "description": "Framework-independent loaders for Gaussian splat formats",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -78,9 +78,9 @@
78
78
  "build-bundle-dev": "ocular-bundle ./bundle.ts --env=dev --output=dist/dist.dev.js"
79
79
  },
80
80
  "dependencies": {
81
- "@loaders.gl/compression": "4.5.3",
82
- "@loaders.gl/loader-utils": "4.5.3",
83
- "@loaders.gl/schema": "4.5.3",
81
+ "@loaders.gl/compression": "5.0.0-alpha.10",
82
+ "@loaders.gl/loader-utils": "5.0.0-alpha.10",
83
+ "@loaders.gl/schema": "5.0.0-alpha.10",
84
84
  "apache-arrow": ">= 17.0.0",
85
85
  "zod": "^4.1.12"
86
86
  },
@@ -88,7 +88,7 @@
88
88
  "zstd-codec": "^0.1.0"
89
89
  },
90
90
  "peerDependencies": {
91
- "@loaders.gl/core": "~4.5.0"
91
+ "@loaders.gl/core": "~5.0.0-alpha.0"
92
92
  },
93
- "gitHead": "3ad4ab002b4a53ac5d88feb856117a8a1e8c5bb0"
93
+ "gitHead": "7cbfaef633e86356c946541dab4977b522745b6c"
94
94
  }
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- export type {GaussianSplats, SplatsLoaderOptions} from './types';
6
5
  export type {
7
6
  RADChunkMetadata,
8
7
  RADChunkMetadataJSON,
@@ -16,10 +15,12 @@ export type {
16
15
  RADSplatEncoding
17
16
  } from './lib/parse-rad';
18
17
  export {SPLATFormat, KSPLATFormat, SPZFormat, RADFormat} from './splats-format';
19
- export {SPLATLoaderWithParser as SPLATLoader} from './splat-loader';
20
- export {KSPLATLoaderWithParser as KSPLATLoader} from './ksplat-loader';
21
- export {SPZLoaderWithParser as SPZLoader} from './spz-loader';
22
- export {RADLoaderWithParser as RADLoader} from './rad-loader';
18
+ export type {GaussianSplats, SPZCoordinateSystem, SplatsLoaderOptions} from './types';
19
+ export {parseSPZ, parseSPZToGaussianSplats} from './lib/parse-spz';
20
+ export {SPLATLoader} from './splat-loader-types';
21
+ export {KSPLATLoader} from './ksplat-loader-types';
22
+ export {SPZLoader} from './spz-loader-types';
23
+ export {RADLoader} from './rad-loader-types';
23
24
  export type {
24
25
  RADChunkRequestOptions,
25
26
  RADChunkTableIteratorOptions,
@@ -11,7 +11,13 @@ import {KSPLATFormat} from './splats-format';
11
11
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
12
12
  const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
13
13
 
14
- /** Loader metadata for `.ksplat` Gaussian splat files. */
14
+ /** Preloads the parser-bearing KSPLAT loader implementation. */
15
+ async function preload() {
16
+ const {KSPLATLoaderWithParser} = await import('./ksplat-loader');
17
+ return KSPLATLoaderWithParser;
18
+ }
19
+
20
+ /** Metadata-only loader for `.ksplat` Gaussian splat files. */
15
21
  export const KSPLATLoader = {
16
22
  dataType: null as unknown as MeshArrowTable,
17
23
  batchType: null as never,
@@ -21,5 +27,6 @@ export const KSPLATLoader = {
21
27
  splats: {
22
28
  shape: 'arrow-table'
23
29
  }
24
- }
30
+ },
31
+ preload
25
32
  } as const satisfies Loader<MeshArrowTable, never, SplatsLoaderOptions>;
@@ -8,9 +8,11 @@ import type {SplatsLoaderOptions} from './types';
8
8
  import {parseKSPLAT} from './lib/parse-ksplat';
9
9
  import {KSPLATLoader as KSPLATLoaderMetadata} from './ksplat-loader-types';
10
10
 
11
+ const {preload: _KSPLATLoaderPreload, ...KSPLATLoaderMetadataWithoutPreload} = KSPLATLoaderMetadata;
12
+
11
13
  /** Parser-bearing loader for `.ksplat` Gaussian splat files. */
12
14
  export const KSPLATLoaderWithParser = {
13
- ...KSPLATLoaderMetadata,
15
+ ...KSPLATLoaderMetadataWithoutPreload,
14
16
  parse: async (arrayBuffer: ArrayBuffer) => parseKSPLAT(arrayBuffer),
15
17
  parseSync: (arrayBuffer: ArrayBuffer) => parseKSPLAT(arrayBuffer)
16
18
  } as const satisfies LoaderWithParser<MeshArrowTable, never, SplatsLoaderOptions>;
@@ -2,8 +2,6 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- /* eslint-disable max-params */
6
-
7
5
  import type {MeshArrowTable} from '@loaders.gl/schema';
8
6
  import type {GaussianSplats} from '../types';
9
7
  import {makeGaussianSplatsArrowTable} from './splats-arrow-table';
@@ -114,7 +112,7 @@ export function parseKSPLATToGaussianSplats(data: ArrayBuffer): GaussianSplats {
114
112
  0,
115
113
  ...sections
116
114
  .slice(0, getActiveSectionCount(header))
117
- .map((section) => getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree))
115
+ .map(section => getSphericalHarmonicsComponentCount(section.sphericalHarmonicsDegree))
118
116
  );
119
117
 
120
118
  const positions = new Float32Array(splatCount * 3);
@@ -165,7 +163,7 @@ export function parseKSPLATToGaussianSplats(data: ArrayBuffer): GaussianSplats {
165
163
  loaderData: {
166
164
  format: 'ksplat',
167
165
  ...header,
168
- sections: sections.slice(0, getActiveSectionCount(header)).map((section) => ({
166
+ sections: sections.slice(0, getActiveSectionCount(header)).map(section => ({
169
167
  splatCount: section.splatCount,
170
168
  maxSplatCount: section.maxSplatCount,
171
169
  sphericalHarmonicsDegree: section.sphericalHarmonicsDegree
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {DeflateCompression} from '@loaders.gl/compression';
5
+ import {DeflateDecompressor} from '@loaders.gl/compression/deflate-decompressor';
6
6
  import type {MeshArrowTable} from '@loaders.gl/schema';
7
7
  import type {GaussianSplats, SplatsLoaderOptions} from '../types';
8
8
  import {
@@ -15,8 +15,8 @@ import {
15
15
  import {makeGaussianSplatsArrowTable} from './splats-arrow-table';
16
16
  import {decodeFloat16, normalizeQuaternion, SH_C0} from './splat-utils';
17
17
 
18
- const RAD_PROPERTY_DEFLATE = new DeflateCompression();
19
- const RAD_PROPERTY_RAW_DEFLATE = new DeflateCompression({raw: true});
18
+ const RAD_PROPERTY_DEFLATE = new DeflateDecompressor({useNative: false});
19
+ const RAD_PROPERTY_RAW_DEFLATE = new DeflateDecompressor({raw: true, useNative: false});
20
20
 
21
21
  /** Options for decoding one Spark RADC chunk payload. */
22
22
  export type RADChunkDecodeOptions = SplatsLoaderOptions & {
@@ -210,7 +210,7 @@ function decodeRADSphericalHarmonics(
210
210
  return null;
211
211
  }
212
212
 
213
- const decodedProperties = shProperties.map((entry) => ({
213
+ const decodedProperties = shProperties.map(entry => ({
214
214
  values: decodeRADFloatProperty(bytes, metadata, entry.property, entry.dimensions),
215
215
  dimensions: entry.dimensions
216
216
  }));
@@ -620,7 +620,7 @@ function findRADProperty(
620
620
  metadata: RADChunkMetadata,
621
621
  propertyName: string
622
622
  ): RADChunkProperty | undefined {
623
- return metadata.properties.find((property) => property.property === propertyName);
623
+ return metadata.properties.find(property => property.property === propertyName);
624
624
  }
625
625
 
626
626
  /** Merges source-level splat encoding with chunk-local encoding. */
@@ -2,9 +2,9 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {ZstdCompression} from '@loaders.gl/compression';
5
+ import {GZipDecompressor, ZstdDecompressor} from '@loaders.gl/compression';
6
6
  import type {MeshArrowTable} from '@loaders.gl/schema';
7
- import type {GaussianSplats, SplatsLoaderOptions} from '../types';
7
+ import type {GaussianSplats, SPZCoordinateSystem, SplatsLoaderOptions} from '../types';
8
8
  import {makeGaussianSplatsArrowTable} from './splats-arrow-table';
9
9
  import {normalizeQuaternion} from './splat-utils';
10
10
 
@@ -46,20 +46,205 @@ export async function parseSPZToGaussianSplats(
46
46
  data: ArrayBuffer,
47
47
  options?: SplatsLoaderOptions
48
48
  ): Promise<GaussianSplats> {
49
+ const version = detectSPZVersion(data);
50
+ if (version === 0) {
51
+ return await parseLegacySPZ(data, options);
52
+ }
53
+ if (version !== SPZ_VERSION) {
54
+ throw new Error(`SPZLoader: version ${version} is not supported.`);
55
+ }
49
56
  const header = parseSPZHeader(data);
50
57
  const streamInfos = parseSPZStreamInfos(data, header, getSPZStreamByteLengths(header));
51
- const compressedStreams = streamInfos.map((streamInfo) =>
58
+ const compressedStreams = streamInfos.map(streamInfo =>
52
59
  data.slice(streamInfo.compressedOffset, streamInfo.compressedOffset + streamInfo.compressedSize)
53
60
  );
54
- const compression = new ZstdCompression({modules: options?.modules});
61
+ const decompressor = new ZstdDecompressor({modules: options?.modules});
55
62
  const streams = await Promise.all(
56
63
  compressedStreams.map((compressedStream, streamIndex) =>
57
- compression.decompress(compressedStream, streamInfos[streamIndex].uncompressedSize)
64
+ decompressor.decompress(compressedStream, streamInfos[streamIndex].uncompressedSize)
58
65
  )
59
66
  );
60
67
 
61
68
  validateSPZStreamLengths(streams, streamInfos);
62
- return decodeSPZStreams(header, streams, data);
69
+ return applySPZCoordinateSystem(
70
+ decodeSPZStreams(header, streams, data),
71
+ options?.splats?.sourceCoordinateSystem ?? 'RUB',
72
+ options?.splats?.targetCoordinateSystem ?? options?.splats?.sourceCoordinateSystem ?? 'RUB'
73
+ );
74
+ }
75
+
76
+ /** Detects the SPZ generation from either the legacy gzip or v4 plaintext header. */
77
+ function detectSPZVersion(data: ArrayBuffer): number {
78
+ if (data.byteLength < 8) {
79
+ throw new Error('SPZLoader: file must contain at least an 8-byte header.');
80
+ }
81
+ const bytes = new Uint8Array(data);
82
+ if (bytes[0] === 0x1f && bytes[1] === 0x8b) {
83
+ // Legacy files carry their 16-byte header inside the gzip stream. The
84
+ // version is therefore read by parseLegacySPZ after decompression.
85
+ return 0;
86
+ }
87
+ if (data.byteLength < SPZ_HEADER_BYTE_LENGTH) {
88
+ throw new Error('SPZLoader: file must contain a 32-byte header.');
89
+ }
90
+ return new DataView(data).getUint32(4, true);
91
+ }
92
+
93
+ /** Decodes the single-stream SPZ v2/v3 container. */
94
+ async function parseLegacySPZ(
95
+ data: ArrayBuffer,
96
+ options?: SplatsLoaderOptions
97
+ ): Promise<GaussianSplats> {
98
+ const decompressed = await new GZipDecompressor({
99
+ modules: options?.modules,
100
+ useNative: true
101
+ }).decompress(data);
102
+ if (decompressed.byteLength < 16) {
103
+ throw new Error('SPZLoader: legacy payload must contain a 16-byte header.');
104
+ }
105
+ const dataView = new DataView(decompressed);
106
+ const header = {
107
+ magic: dataView.getUint32(0, true),
108
+ version: dataView.getUint32(4, true),
109
+ numPoints: dataView.getUint32(8, true),
110
+ shDegree: dataView.getUint8(12),
111
+ fractionalBits: dataView.getUint8(13),
112
+ flags: dataView.getUint8(14)
113
+ };
114
+ if (header.magic !== SPZ_MAGIC) {
115
+ throw new Error('SPZLoader: NGSP magic header not found.');
116
+ }
117
+ if (header.version !== 2 && header.version !== 3) {
118
+ throw new Error(`SPZLoader: version ${header.version} is not supported.`);
119
+ }
120
+ if (dataView.getUint8(15) !== 0) {
121
+ throw new Error('SPZLoader: legacy header reserved byte must be zero.');
122
+ }
123
+ if (header.shDegree > 3) {
124
+ throw new Error(`SPZLoader: spherical harmonics degree ${header.shDegree} is not supported.`);
125
+ }
126
+
127
+ const count = header.numPoints;
128
+ const shComponentCount = getSphericalHarmonicsComponentCount(header.shDegree);
129
+ const positionByteLength = count * 9;
130
+ const alphaByteLength = count;
131
+ const colorByteLength = count * 3;
132
+ const scaleByteLength = count * 3;
133
+ const rotationByteLength = count * (header.version === 2 ? 3 : 4);
134
+ const shByteLength = count * shComponentCount;
135
+ const payloadByteLength =
136
+ positionByteLength +
137
+ alphaByteLength +
138
+ colorByteLength +
139
+ scaleByteLength +
140
+ rotationByteLength +
141
+ shByteLength;
142
+ if (decompressed.byteLength - 16 !== payloadByteLength) {
143
+ throw new Error(
144
+ `SPZLoader: legacy payload has ${decompressed.byteLength - 16} bytes, expected ${payloadByteLength}.`
145
+ );
146
+ }
147
+
148
+ let offset = 16;
149
+ const positions = new Float32Array(count * 3);
150
+ const opacities = new Float32Array(count);
151
+ const colors = new Uint8Array(count * 3);
152
+ const scales = new Float32Array(count * 3);
153
+ const rotations = new Float32Array(count * 4);
154
+ const sphericalHarmonicDcs = new Float32Array(count * 3);
155
+ const sphericalHarmonics = shComponentCount
156
+ ? new Float32Array(count * shComponentCount)
157
+ : undefined;
158
+ decodeSPZPositions(
159
+ new Uint8Array(decompressed, offset, positionByteLength),
160
+ positions,
161
+ header.fractionalBits
162
+ );
163
+ offset += positionByteLength;
164
+ decodeSPZOpacities(new Uint8Array(decompressed, offset, alphaByteLength), opacities);
165
+ offset += alphaByteLength;
166
+ decodeSPZColors(
167
+ new Uint8Array(decompressed, offset, colorByteLength),
168
+ colors,
169
+ sphericalHarmonicDcs
170
+ );
171
+ offset += colorByteLength;
172
+ decodeSPZScales(new Uint8Array(decompressed, offset, scaleByteLength), scales);
173
+ offset += scaleByteLength;
174
+ if (header.version === 2) {
175
+ decodeLegacySPZRotations(new Uint8Array(decompressed, offset, rotationByteLength), rotations);
176
+ } else {
177
+ decodeSPZRotations(new Uint8Array(decompressed, offset, rotationByteLength), rotations);
178
+ }
179
+ offset += rotationByteLength;
180
+ if (sphericalHarmonics) {
181
+ decodeSPZSphericalHarmonics(
182
+ new Uint8Array(decompressed, offset, shByteLength),
183
+ sphericalHarmonics
184
+ );
185
+ }
186
+
187
+ return applySPZCoordinateSystem(
188
+ {
189
+ format: 'spz',
190
+ splatCount: count,
191
+ positions,
192
+ scales,
193
+ rotations,
194
+ colors,
195
+ sphericalHarmonicDcs,
196
+ opacities,
197
+ sphericalHarmonics,
198
+ sphericalHarmonicsComponentCount: shComponentCount || undefined,
199
+ loaderData: {...header, legacy: true}
200
+ },
201
+ options?.splats?.sourceCoordinateSystem ?? 'RUB',
202
+ options?.splats?.targetCoordinateSystem ?? options?.splats?.sourceCoordinateSystem ?? 'RUB'
203
+ );
204
+ }
205
+
206
+ /** Decodes the three signed bytes used by SPZ v2 rotations. */
207
+ function decodeLegacySPZRotations(rotationStream: Uint8Array, rotations: Float32Array): void {
208
+ for (let splatIndex = 0; splatIndex < rotations.length / 4; splatIndex++) {
209
+ const byteOffset = splatIndex * 3;
210
+ const x = signedByte(rotationStream[byteOffset]) / 127;
211
+ const y = signedByte(rotationStream[byteOffset + 1]) / 127;
212
+ const z = signedByte(rotationStream[byteOffset + 2]) / 127;
213
+ const w = Math.sqrt(Math.max(0, 1 - x * x - y * y - z * z));
214
+ const normalized = normalizeQuaternion(w, x, y, z);
215
+ rotations.set(normalized, splatIndex * 4);
216
+ }
217
+ }
218
+
219
+ /** Converts an unsigned byte containing a signed int8 value. */
220
+ function signedByte(value: number): number {
221
+ return value > 127 ? value - 256 : value;
222
+ }
223
+
224
+ /** Applies the explicitly requested SPZ coordinate conversion. */
225
+ function applySPZCoordinateSystem(
226
+ splats: GaussianSplats,
227
+ source: SPZCoordinateSystem,
228
+ target: SPZCoordinateSystem
229
+ ): GaussianSplats {
230
+ if (source === target || source === 'UNSPECIFIED' || target === 'UNSPECIFIED') {
231
+ return splats;
232
+ }
233
+ if (source === 'RUB' && target === 'LUF') {
234
+ for (let index = 0; index < splats.positions.length; index += 3) {
235
+ splats.positions[index] = -splats.positions[index];
236
+ splats.positions[index + 2] = -splats.positions[index + 2];
237
+ }
238
+ for (let index = 0; index < splats.rotations.length; index += 4) {
239
+ splats.rotations[index + 1] = -splats.rotations[index + 1];
240
+ splats.rotations[index + 3] = -splats.rotations[index + 3];
241
+ }
242
+ return splats;
243
+ }
244
+ if (source === 'LUF' && target === 'RUB') {
245
+ return applySPZCoordinateSystem(splats, 'RUB', 'LUF');
246
+ }
247
+ throw new Error(`SPZLoader: coordinate conversion ${source} -> ${target} is not supported.`);
63
248
  }
64
249
 
65
250
  /** Parses and validates the SPZ v4 plaintext header. */
@@ -161,7 +346,7 @@ function getSPZStreamByteLengths(header: SPZHeader): number[] {
161
346
  header.numPoints * 3,
162
347
  header.numPoints * 4,
163
348
  header.numPoints * getSphericalHarmonicsComponentCount(header.shDegree)
164
- ].filter((byteLength) => byteLength > 0);
349
+ ].filter(byteLength => byteLength > 0);
165
350
  }
166
351
 
167
352
  /** Validates that decompressed stream lengths match the TOC. */
@@ -197,7 +382,7 @@ function decodeSPZStreams(
197
382
  scaleStream,
198
383
  rotationStream,
199
384
  sphericalHarmonicsStream
200
- ] = streams.map((stream) => new Uint8Array(stream));
385
+ ] = streams.map(stream => new Uint8Array(stream));
201
386
 
202
387
  decodeSPZPositions(positionStream, positions, header.fractionalBits);
203
388
  decodeSPZScales(scaleStream, scales);
@@ -2,8 +2,6 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- /* eslint-disable max-params */
6
-
7
5
  import * as arrow from 'apache-arrow';
8
6
  import type {Field, MeshArrowTable, Schema} from '@loaders.gl/schema';
9
7
  import type {GaussianSplats} from '../types';
@@ -10,11 +10,18 @@ import type {RADMetadata} from './lib/parse-rad';
10
10
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
11
11
  const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
12
12
 
13
- /** Loader metadata for Spark `.rad` paged LoD Gaussian splat containers. */
13
+ /** Preloads the parser-bearing RAD loader implementation. */
14
+ async function preload() {
15
+ const {RADLoaderWithParser} = await import('./rad-loader');
16
+ return RADLoaderWithParser;
17
+ }
18
+
19
+ /** Metadata-only loader for Spark `.rad` paged LoD Gaussian splat containers. */
14
20
  export const RADLoader = {
15
21
  dataType: null as unknown as RADMetadata,
16
22
  batchType: null as never,
17
23
  ...RADFormat,
18
24
  version: VERSION,
19
- options: {}
25
+ options: {},
26
+ preload
20
27
  } as const satisfies Loader<RADMetadata, never, LoaderOptions>;
package/src/rad-loader.ts CHANGED
@@ -14,9 +14,11 @@ export {
14
14
  type RADChunkDecodeOptions
15
15
  } from './lib/parse-rad-chunk';
16
16
 
17
+ const {preload: _RADLoaderPreload, ...RADLoaderMetadataWithoutPreload} = RADLoaderMetadata;
18
+
17
19
  /** Parser-bearing loader for Spark `.rad` paged LoD Gaussian splat container metadata. */
18
20
  export const RADLoaderWithParser = {
19
- ...RADLoaderMetadata,
21
+ ...RADLoaderMetadataWithoutPreload,
20
22
  parse: async (arrayBuffer: ArrayBuffer) => parseRADHeader(arrayBuffer),
21
23
  parseSync: (arrayBuffer: ArrayBuffer) => parseRADHeader(arrayBuffer)
22
24
  } as const satisfies LoaderWithParser<RADMetadata, never, LoaderOptions>;
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {DataSourceOptions} from '@loaders.gl/loader-utils';
5
+ import type {CoreAPI, DataSourceOptions, SourceLoader} from '@loaders.gl/loader-utils';
6
6
  import {DataSource} from '@loaders.gl/loader-utils';
7
7
  import type {MeshArrowTable} from '@loaders.gl/schema';
8
8
  import {RADFormat} from './splats-format';
@@ -88,9 +88,12 @@ export const RADSourceLoader = {
88
88
  },
89
89
 
90
90
  testURL: (url: string): boolean => /\.rad(?:$|[?#])/i.test(url),
91
- createDataSource: (data: string | Blob, options: RADSourceLoaderOptions): RADSource =>
92
- new RADSource(data, options)
93
- } as const;
91
+ createDataSource: (
92
+ data: string | Blob,
93
+ options: RADSourceLoaderOptions,
94
+ coreApi?: CoreAPI
95
+ ): RADSource => new RADSource(data, options, coreApi)
96
+ } as const satisfies SourceLoader<RADSource>;
94
97
 
95
98
  /** Runtime source for RAD metadata and chunk-byte access. */
96
99
  export class RADSource extends DataSource<string | Blob, RADSourceLoaderOptions> {
@@ -102,8 +105,8 @@ export class RADSource extends DataSource<string | Blob, RADSourceLoaderOptions>
102
105
  /** Lazily initialized per-chunk metadata promises. */
103
106
  private _chunkMetadataPromises: Map<number, Promise<RADChunkMetadata>> = new Map();
104
107
 
105
- constructor(data: string | Blob, options: RADSourceLoaderOptions) {
106
- super(data, options, RADSourceLoader.defaultOptions);
108
+ constructor(data: string | Blob, options: RADSourceLoaderOptions, coreApi?: CoreAPI) {
109
+ super(data, options, RADSourceLoader.defaultOptions, coreApi);
107
110
  this.metadata = this.getMetadata();
108
111
  }
109
112
 
@@ -173,7 +176,7 @@ export class RADSource extends DataSource<string | Blob, RADSourceLoaderOptions>
173
176
  ): Promise<RADChunkMetadata> {
174
177
  let chunkMetadataPromise = this._chunkMetadataPromises.get(chunkIndex);
175
178
  if (!chunkMetadataPromise) {
176
- chunkMetadataPromise = this.getChunk(chunkIndex, options).then((chunk) =>
179
+ chunkMetadataPromise = this.getChunk(chunkIndex, options).then(chunk =>
177
180
  parseRADChunkHeader(chunk)
178
181
  );
179
182
  this._chunkMetadataPromises.set(chunkIndex, chunkMetadataPromise);
@@ -347,7 +350,17 @@ export class RADSource extends DataSource<string | Blob, RADSourceLoaderOptions>
347
350
 
348
351
  /** Fetches through custom source fetch hooks or the injected core fetchFile helper. */
349
352
  private async _fetchResponse(url: string, requestInit: RequestInit): Promise<Response> {
350
- return await this.fetch(url, requestInit);
353
+ if (this._hasCustomFetch()) {
354
+ return await this.fetch(url, requestInit);
355
+ }
356
+ return this.hasCoreApi
357
+ ? await this.coreApi.fetchFile(url, requestInit)
358
+ : await this.fetch(url, requestInit);
359
+ }
360
+
361
+ /** Returns true when source options supplied an explicit fetch override. */
362
+ private _hasCustomFetch(): boolean {
363
+ return Boolean(this.loadOptions?.core?.fetch || this.loadOptions?.fetch);
351
364
  }
352
365
 
353
366
  /** Builds request options for RAD fetches. */