@voluma/vlam 0.2.4 → 0.3.2

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 (138) hide show
  1. package/README.md +3 -4
  2. package/dist/chunk-loader-DlNwggfG.js +1859 -0
  3. package/dist/chunk-loader-DlNwggfG.js.map +1 -0
  4. package/dist/{compute-sorter.d.ts → core/compute-sorter.d.ts} +1 -1
  5. package/dist/core/index.d.ts +45 -0
  6. package/dist/{splat-scene.d.ts → core/merged-splat-mesh.d.ts} +14 -15
  7. package/dist/{orientation.d.ts → core/orientation.d.ts} +7 -7
  8. package/dist/{relighting.d.ts → core/relighting.d.ts} +1 -1
  9. package/dist/{source-transform.d.ts → core/source-transform.d.ts} +4 -4
  10. package/dist/{splat-budget.d.ts → core/splat-budget.d.ts} +2 -2
  11. package/dist/{splat-data.d.ts → core/splat-data.d.ts} +4 -4
  12. package/dist/{splat-mesh-material.d.ts → core/splat-mesh-material.d.ts} +2 -2
  13. package/dist/{splat-mesh-types.d.ts → core/splat-mesh-types.d.ts} +19 -10
  14. package/dist/{splat-mesh.d.ts → core/splat-mesh.d.ts} +4 -4
  15. package/dist/{splat-modifier.d.ts → core/splat-modifier.d.ts} +5 -5
  16. package/dist/{webgpu-limits.d.ts → core/webgpu-limits.d.ts} +0 -59
  17. package/dist/{effects.d.ts → effects/index.d.ts} +14 -13
  18. package/dist/effects.js.map +1 -1
  19. package/dist/formats/ksplat/index.d.ts +1 -1
  20. package/dist/formats/ksplat/parse-ksplat.d.ts +1 -1
  21. package/dist/formats/ksplat.js.map +1 -1
  22. package/dist/formats/lcc/collision-mesh.d.ts +3 -3
  23. package/dist/formats/lcc/collision-partition.d.ts +1 -1
  24. package/dist/formats/lcc/lcc.d.ts +3 -3
  25. package/dist/formats/lcc/lcc2.d.ts +2 -2
  26. package/dist/formats/lcc/parse-lcc.d.ts +1 -1
  27. package/dist/formats/lcc.js +17 -16
  28. package/dist/formats/lcc.js.map +1 -1
  29. package/dist/formats/ply/index.d.ts +1 -1
  30. package/dist/formats/ply/parse-compressed-ply.d.ts +2 -2
  31. package/dist/formats/ply/parse-splat-ply.d.ts +4 -4
  32. package/dist/formats/ply.js +1 -1
  33. package/dist/formats/ply.js.map +1 -1
  34. package/dist/formats/rad/frontier-worker-protocol.d.ts +8 -1
  35. package/dist/formats/rad/index.d.ts +2 -2
  36. package/dist/formats/rad/parse-rad.d.ts +2 -2
  37. package/dist/formats/rad/rad-foveated-source.d.ts +3 -3
  38. package/dist/formats/rad/rad.d.ts +7 -7
  39. package/dist/formats/rad.js +3 -3
  40. package/dist/formats/rad.js.map +1 -1
  41. package/dist/formats/sog/index.d.ts +1 -1
  42. package/dist/formats/sog/parse-sog.d.ts +6 -6
  43. package/dist/formats/sog.js.map +1 -1
  44. package/dist/formats/splat/index.d.ts +1 -1
  45. package/dist/formats/splat/parse-splat.d.ts +1 -1
  46. package/dist/formats/splat.js.map +1 -1
  47. package/dist/formats/spz/index.d.ts +1 -1
  48. package/dist/formats/spz/parse-spz.d.ts +1 -1
  49. package/dist/formats/spz.js.map +1 -1
  50. package/dist/half-float-Cs4FDq8Q.js.map +1 -1
  51. package/dist/index.js +253 -9047
  52. package/dist/index.js.map +1 -1
  53. package/dist/{chunk-loader.d.ts → loaders/chunk-loader.d.ts} +4 -4
  54. package/dist/loaders/index.d.ts +15 -0
  55. package/dist/{load-scene.d.ts → loaders/load-splat-data.d.ts} +16 -14
  56. package/dist/{load-worker-protocol.d.ts → loaders/load-worker-protocol.d.ts} +2 -2
  57. package/dist/{loading.d.ts → loaders/loading.d.ts} +8 -8
  58. package/dist/loaders.js +26 -0
  59. package/dist/loaders.js.map +1 -0
  60. package/dist/loading-wLo8vRbA.js.map +1 -1
  61. package/dist/{splat-mesh-types-CTN_duw2.js → lod-scheduler-B0a_uBlv.js} +133 -140
  62. package/dist/lod-scheduler-B0a_uBlv.js.map +1 -0
  63. package/dist/logging-BfPdd7NJ.js.map +1 -1
  64. package/dist/{ply-header-BwgExCn-.js → ply-header-B9WllbPg.js} +3 -3
  65. package/dist/ply-header-B9WllbPg.js.map +1 -0
  66. package/dist/radix-sorter-BrbUg_CV.js +178 -0
  67. package/dist/radix-sorter-BrbUg_CV.js.map +1 -0
  68. package/dist/relighting-Tiwep8yd.js +977 -0
  69. package/dist/relighting-Tiwep8yd.js.map +1 -0
  70. package/dist/selection/index.d.ts +13 -0
  71. package/dist/{selection-volume.d.ts → selection/selection-volume.d.ts} +1 -1
  72. package/dist/{splat-partition.d.ts → selection/splat-partition.d.ts} +2 -2
  73. package/dist/selection.js +137 -0
  74. package/dist/selection.js.map +1 -0
  75. package/dist/sh-pack-D5wAe5gg.js.map +1 -1
  76. package/dist/{splat-budget-DXew_86c.js → splat-budget-DuVZspPQ.js} +7 -7
  77. package/dist/splat-budget-DuVZspPQ.js.map +1 -0
  78. package/dist/splat-data-BZM5dhhx.js.map +1 -1
  79. package/dist/splat-mesh-CsLOQb08.js +1942 -0
  80. package/dist/splat-mesh-CsLOQb08.js.map +1 -0
  81. package/dist/splat-mesh-types-BZIko-_9.js +18 -0
  82. package/dist/splat-mesh-types-BZIko-_9.js.map +1 -0
  83. package/dist/static-lod/index.d.ts +12 -0
  84. package/dist/{static-lod-splat-mesh.d.ts → static-lod/static-lod-splat-mesh.d.ts} +3 -3
  85. package/dist/{static-lod-worker-protocol.d.ts → static-lod/static-lod-worker-protocol.d.ts} +1 -1
  86. package/dist/{static-lod.d.ts → static-lod/static-lod.d.ts} +1 -1
  87. package/dist/{static-lod-worker-D2fyqQZO.js → static-lod-worker-DktKnJkR.js} +46 -46
  88. package/dist/{static-lod-worker-D2fyqQZO.js.map → static-lod-worker-DktKnJkR.js.map} +1 -1
  89. package/dist/static-lod.js +148 -0
  90. package/dist/static-lod.js.map +1 -0
  91. package/dist/{budget-governor.d.ts → streaming/budget-governor.d.ts} +4 -4
  92. package/dist/{camera-budget-governor.d.ts → streaming/camera-budget-governor.d.ts} +11 -11
  93. package/dist/{chunk-cache-budget.d.ts → streaming/chunk-cache-budget.d.ts} +5 -5
  94. package/dist/{chunk-fetch-scheduler.d.ts → streaming/chunk-fetch-scheduler.d.ts} +4 -4
  95. package/dist/{dataset-source.d.ts → streaming/dataset-source.d.ts} +1 -1
  96. package/dist/streaming/index.d.ts +23 -0
  97. package/dist/{lod-scheduler.d.ts → streaming/lod-scheduler.d.ts} +1 -1
  98. package/dist/{lod-source.d.ts → streaming/lod-source.d.ts} +9 -9
  99. package/dist/{streamed-splat-mesh-utils.d.ts → streaming/streamed-splat-mesh-utils.d.ts} +2 -2
  100. package/dist/{streamed-splat-mesh.d.ts → streaming/streamed-splat-mesh.d.ts} +66 -32
  101. package/dist/streaming.js +2911 -0
  102. package/dist/streaming.js.map +1 -0
  103. package/dist/unified/index.d.ts +11 -0
  104. package/dist/{unified-splat-renderer.d.ts → unified/unified-splat-mesh.d.ts} +23 -16
  105. package/dist/unified/unified-work-buffer.d.ts +66 -0
  106. package/dist/{work-buffer-gather.d.ts → unified/work-buffer-gather.d.ts} +6 -6
  107. package/dist/{work-buffer-material.d.ts → unified/work-buffer-material.d.ts} +1 -1
  108. package/dist/unified.js +746 -0
  109. package/dist/unified.js.map +1 -0
  110. package/dist/webgpu-limits-Y3CI_6_6.js +43 -0
  111. package/dist/webgpu-limits-Y3CI_6_6.js.map +1 -0
  112. package/package.json +27 -7
  113. package/dist/index.d.ts +0 -54
  114. package/dist/ply-header-BwgExCn-.js.map +0 -1
  115. package/dist/splat-budget-DXew_86c.js.map +0 -1
  116. package/dist/splat-mesh-types-CTN_duw2.js.map +0 -1
  117. /package/dist/{create-splat-renderer.d.ts → core/create-splat-renderer.d.ts} +0 -0
  118. /package/dist/{depth-of-field.d.ts → core/depth-of-field.d.ts} +0 -0
  119. /package/dist/{half-float.d.ts → core/half-float.d.ts} +0 -0
  120. /package/dist/{logging.d.ts → core/logging.d.ts} +0 -0
  121. /package/dist/{radix-sort.d.ts → core/radix-sort.d.ts} +0 -0
  122. /package/dist/{radix-sorter.d.ts → core/radix-sorter.d.ts} +0 -0
  123. /package/dist/{relighting-pass.d.ts → core/relighting-pass.d.ts} +0 -0
  124. /package/dist/{sh-pack.d.ts → core/sh-pack.d.ts} +0 -0
  125. /package/dist/{sort-scheduler.d.ts → core/sort-scheduler.d.ts} +0 -0
  126. /package/dist/{sort-worker-protocol.d.ts → core/sort-worker-protocol.d.ts} +0 -0
  127. /package/dist/{sorter.d.ts → core/sorter.d.ts} +0 -0
  128. /package/dist/{splat-depth-pack.d.ts → core/splat-depth-pack.d.ts} +0 -0
  129. /package/dist/{splat-mesh-picking.d.ts → core/splat-mesh-picking.d.ts} +0 -0
  130. /package/dist/{splat-mesh-pool.d.ts → core/splat-mesh-pool.d.ts} +0 -0
  131. /package/dist/{splat-modifier-stack.d.ts → core/splat-modifier-stack.d.ts} +0 -0
  132. /package/dist/{splat-query.d.ts → core/splat-query.d.ts} +0 -0
  133. /package/dist/{splat-sort-bounds.d.ts → core/splat-sort-bounds.d.ts} +0 -0
  134. /package/dist/{storage-attribute-mirror.d.ts → core/storage-attribute-mirror.d.ts} +0 -0
  135. /package/dist/{worker-sorter.d.ts → core/worker-sorter.d.ts} +0 -0
  136. /package/dist/{xr-view.d.ts → core/xr-view.d.ts} +0 -0
  137. /package/dist/{ply-header.d.ts → loaders/ply-header.d.ts} +0 -0
  138. /package/dist/{lod-manifest.d.ts → streaming/lod-manifest.d.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `@voluma/vlam/unified` - one WebGPU draw over several splat sources.
3
+ *
4
+ * {@link UnifiedSplatMesh} concatenates static and streamed meshes into a
5
+ * shared work buffer so overlapping clouds inter-sort. WebGL2 is unsupported;
6
+ * {@link supportsUnifiedSplatMesh} reports that after renderer init.
7
+ *
8
+ * @module unified
9
+ */
10
+ export { UnifiedSplatMesh, supportsUnifiedSplatMesh, type UnifiedSplatPickResult, type UnifiedSplatMeshOptions, type UnifiedSplatSourceOptions, } from './unified-splat-mesh';
11
+ export { estimateLargestStorageBufferBytes, estimateUnifiedWorkBufferBytes, estimateUnifiedWorkBufferPeakBytes, WORK_BUFFER_CENTERS_BYTES_PER_SPLAT, WORK_BUFFER_BYTES_PER_SLOT, } from './unified-work-buffer';
@@ -1,18 +1,19 @@
1
1
  import * as THREE from 'three/webgpu';
2
- import { type DepthOfFieldSettings } from './depth-of-field';
3
- import { type RelightingSettings, type RelightingUniforms } from './relighting';
4
- import { SplatMesh } from './splat-mesh';
5
- import type { SplatPickOptions, SplatPickResult } from './splat-mesh';
6
- /** Registration settings for one source in a {@link UnifiedSplatRenderer}. */
2
+ import { type DepthOfFieldSettings } from '../core/depth-of-field';
3
+ import { type RelightingSettings, type RelightingUniforms } from '../core/relighting';
4
+ import { SplatMesh } from '../core/splat-mesh';
5
+ import type { SplatPickOptions, SplatPickResult } from '../core/splat-mesh';
6
+ /** Registration settings for one source in a {@link UnifiedSplatMesh}. */
7
7
  export interface UnifiedSplatSourceOptions {
8
- /** Whole-source opacity applied after its modifier stack. Defaults to `1`. */
8
+ /** Whole-source display opacity applied after gather falloff. Defaults to `1`.
9
+ * Does not change RAD LOD classification or splat shape. */
9
10
  opacity?: number;
10
11
  /** Whether this source contributes to the unified draw. Defaults to `true`. */
11
12
  visible?: boolean;
12
13
  /** Higher values survive a fixed work-buffer overflow first. Defaults to `0`. */
13
14
  priority?: number;
14
15
  /**
15
- * Cache a modifier-bearing source until {@link UnifiedSplatRenderer.invalidateSource}
16
+ * Cache a modifier-bearing source until {@link UnifiedSplatMesh.invalidateSource}
16
17
  * is called. Defaults to `false`, which safely re-gathers live modifier
17
18
  * uniforms every frame.
18
19
  *
@@ -23,7 +24,7 @@ export interface UnifiedSplatSourceOptions {
23
24
  cacheModifiers?: boolean;
24
25
  }
25
26
  /**
26
- * Result of a successful {@link UnifiedSplatRenderer.pick}: the frontmost hit
27
+ * Result of a successful {@link UnifiedSplatMesh.pick}: the frontmost hit
27
28
  * across every visible registered source, tagged with the source it landed on.
28
29
  */
29
30
  export interface UnifiedSplatPickResult extends SplatPickResult {
@@ -35,7 +36,7 @@ export interface UnifiedSplatPickResult extends SplatPickResult {
35
36
  *
36
37
  * @experimental May change in a minor release.
37
38
  */
38
- export interface UnifiedSplatRendererOptions {
39
+ export interface UnifiedSplatMeshOptions {
39
40
  /** Composite source colors in display (sRGB) space. Defaults to `false`. */
40
41
  srgbOutput?: boolean;
41
42
  /**
@@ -49,11 +50,11 @@ export interface UnifiedSplatRendererOptions {
49
50
  sortStrategy?: 'counting' | 'exact';
50
51
  }
51
52
  /**
52
- * Returns true when `renderer` can drive {@link UnifiedSplatRenderer}.
53
+ * Returns true when `renderer` can drive {@link UnifiedSplatMesh}.
53
54
  * Heterogeneous gather/sort/draw is WebGPU-only; WebGL2 hosts keep standalone
54
- * `SplatMesh` draws or static {@link SplatScene}.
55
+ * `SplatMesh` draws or static {@link MergedSplatMesh}.
55
56
  */
56
- export declare function supportsUnifiedSplatRenderer(renderer: object): boolean;
57
+ export declare function supportsUnifiedSplatMesh(renderer: object): boolean;
57
58
  /**
58
59
  * One gather → global-sort → draw path for static and streamed splat sources.
59
60
  * Sources retain their own residency and update lifecycle; this mesh gathers
@@ -63,11 +64,11 @@ export declare function supportsUnifiedSplatRenderer(renderer: object): boolean;
63
64
  * registered source mesh instead - sorter bounds and the draw material both
64
65
  * consume world-space centers written by gather.
65
66
  *
66
- * WebGPU only. Prefer {@link supportsUnifiedSplatRenderer} before construction.
67
+ * WebGPU only. Prefer {@link supportsUnifiedSplatMesh} before construction.
67
68
  *
68
69
  * @experimental May change in a minor release.
69
70
  */
70
- export declare class UnifiedSplatRenderer extends THREE.Mesh {
71
+ export declare class UnifiedSplatMesh extends THREE.Mesh {
71
72
  private readonly workBuffer;
72
73
  private readonly workSourceIndex;
73
74
  /** The sorted draw-order buffer; lives outside the geometry, freed on dispose. */
@@ -131,7 +132,7 @@ export declare class UnifiedSplatRenderer extends THREE.Mesh {
131
132
  private overflowedSourceCount;
132
133
  private overflowedSplatCount;
133
134
  private disposed;
134
- constructor(renderer: THREE.WebGPURenderer, capacity: number, options?: UnifiedSplatRendererOptions);
135
+ constructor(renderer: THREE.WebGPURenderer, capacity: number, options?: UnifiedSplatMeshOptions);
135
136
  /** Fixed work-buffer splat capacity chosen at construction. */
136
137
  get capacity(): number;
137
138
  /** Registers a source. The caller keeps ownership and may still query it. */
@@ -149,7 +150,13 @@ export declare class UnifiedSplatRenderer extends THREE.Mesh {
149
150
  get droppedSourceCount(): number;
150
151
  /** Number of active splats omitted in the most recent update due to capacity. */
151
152
  get droppedSplatCount(): number;
152
- /** Updates a source's resolved opacity without rebuilding its gather pipeline. */
153
+ /**
154
+ * Sets whole-source display opacity without rebuilding the gather pipeline.
155
+ *
156
+ * This scales the completed fragment after RAD merged-vs-leaf classification
157
+ * and falloff. It must never alter LOD selection or splat shape; hosts such as
158
+ * marker crossfades rely on that. Values `<= 0` skip drawing the source.
159
+ */
153
160
  setSourceOpacity(source: SplatMesh, opacity: number): void;
154
161
  /** Shows or hides a source without changing its residency. */
155
162
  setSourceVisible(source: SplatMesh, visible: boolean): void;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Byte costs of {@link UnifiedSplatMesh}'s GPU work buffer.
3
+ *
4
+ * Kept off the core entry so hosts that never composite sources do not pay
5
+ * for the accounting, and so the numbers cannot drift from the renderer
6
+ * that allocates those buffers.
7
+ */
8
+ /** Bytes per splat in the largest unified work-buffer attribute (RGBA32F centers). */
9
+ export declare const WORK_BUFFER_CENTERS_BYTES_PER_SPLAT = 16;
10
+ /**
11
+ * Bytes per work-buffer slot across *all* of its attributes: centers, colors,
12
+ * covarianceA and covarianceB at RGBA32F (16 each), plus the isotropic mix and
13
+ * screen-radius scalars (4 each).
14
+ */
15
+ export declare const WORK_BUFFER_BYTES_PER_SLOT: number;
16
+ /**
17
+ * Byte size of the largest single storage-buffer bind VLAM allocates for a
18
+ * given splat capacity (unified work-buffer centers: `capacity × 16`).
19
+ *
20
+ * Use with adapter/device limits to decide whether to raise `requiredLimits`
21
+ * or lower the budget before constructing {@link UnifiedSplatMesh}.
22
+ */
23
+ export declare function estimateLargestStorageBufferBytes(capacity: number): number;
24
+ /**
25
+ * Estimates what a {@link UnifiedSplatMesh}'s work buffer costs, in bytes,
26
+ * once the scene has rendered a frame.
27
+ *
28
+ * This used to be double the figure below, and the doubling was not a detail.
29
+ * Every `THREE.StorageBufferAttribute` is constructed around a JS typed array,
30
+ * and three's WebGPU backend never releases it: the
31
+ * `attribute.onUploadCallback()` call that would is missing from the backend's
32
+ * buffer upload path. So a work buffer of N slots cost
33
+ * N × {@link WORK_BUFFER_BYTES_PER_SLOT} on the GPU *and* the same again on the
34
+ * JS heap, permanently, even though nothing ever reads the CPU copy back - the
35
+ * gather pass writes these buffers entirely on the GPU.
36
+ *
37
+ * `WorkBuffer.releaseCpuMirrors` now drops those mirrors after the first
38
+ * dispatch that uploads them (see `storage-attribute-mirror`), so steady state
39
+ * is the GPU side alone. The *peak* is still double - the array has to exist
40
+ * for the upload copy - which is what
41
+ * {@link estimateUnifiedWorkBufferPeakBytes} reports.
42
+ *
43
+ * Either figure is invisible to `estimateSplatPoolBytes`, which prices the
44
+ * splat *pool* and knows nothing about the unified renderer's scratch space. A
45
+ * host sizing a scene for a memory-constrained device wants both.
46
+ *
47
+ * @param capacity - Work-buffer capacity in splats.
48
+ * @returns Estimated steady-state bytes.
49
+ * @throws {RangeError} if `capacity` is not a non-negative finite number.
50
+ */
51
+ export declare function estimateUnifiedWorkBufferBytes(capacity: number): number;
52
+ /**
53
+ * Peak bytes a {@link UnifiedSplatMesh}'s work buffer occupies: the window
54
+ * between construction and the first dispatch, while the GPU buffer and the JS
55
+ * array three copied it from are both alive.
56
+ *
57
+ * Ask this one when the question is "will allocating this scene succeed" - an
58
+ * out-of-memory failure happens against the peak. Ask
59
+ * {@link estimateUnifiedWorkBufferBytes} when the question is "what will this
60
+ * scene hold once it is up".
61
+ *
62
+ * @param capacity - Work-buffer capacity in splats.
63
+ * @returns Estimated bytes, GPU plus the not-yet-released CPU mirror.
64
+ * @throws {RangeError} if `capacity` is not a non-negative finite number.
65
+ */
66
+ export declare function estimateUnifiedWorkBufferPeakBytes(capacity: number): number;
@@ -1,6 +1,6 @@
1
1
  import * as THREE from 'three/webgpu';
2
- import { type SplatShInputs, type Vec3Uniform } from './splat-mesh-material';
3
- import type { SplatModifier } from './splat-modifier';
2
+ import { type SplatShInputs, type Vec3Uniform } from '../core/splat-mesh-material';
3
+ import type { SplatModifier } from '../core/splat-modifier';
4
4
  /**
5
5
  * GPU gather pass for Phase 0 of the unified renderer. It resolves a source
6
6
  * pool's active local centers into a shared world-space storage buffer. The
@@ -12,7 +12,7 @@ import type { SplatModifier } from './splat-modifier';
12
12
  /** Shared GPU storage for every gathered source in one unified frame. */
13
13
  export declare class WorkBuffer {
14
14
  readonly capacity: number;
15
- /** World-space center xyz; w is the drawable flag (1 draw, 0 modifier-hidden). */
15
+ /** World-space center xyz; w is display opacity (`visibility × source opacity ×` RAD modifier ratio). */
16
16
  readonly centers: THREE.StorageBufferAttribute;
17
17
  /** Resolved color and opacity per work slot. */
18
18
  readonly colors: THREE.StorageBufferAttribute;
@@ -86,8 +86,8 @@ export declare class WorkBufferGather {
86
86
  srgbOutput?: boolean;
87
87
  /**
88
88
  * Source stores Spark LOD alpha (`alpha ÷ 2`, `.rad`). Recover the full
89
- * `alpha ∈ [0,2]` here so the shared draw material sees one convention;
90
- * `alpha > 1` then marks a merged node (see `createWorkBufferMaterial`).
89
+ * `alpha ∈ [0,2]` into `colors.a` from the *original* texture channel so the
90
+ * shared draw material can classify merged vs leaf without seeing fades.
91
91
  */
92
92
  lodAlpha?: boolean;
93
93
  /** Reuse one target across all source gather passes. */
@@ -99,7 +99,7 @@ export declare class WorkBufferGather {
99
99
  * Compiles this gather's compute pipeline without gathering anything.
100
100
  *
101
101
  * WebGPU compiles a compute pipeline lazily, at its first dispatch - not when
102
- * the node graph is built. Measured on a 13-marker scene, a source's *first*
102
+ * the node graph is built. Measured on a 13-mesh scene, a source's *first*
103
103
  * `gather` took up to 2.0s while every later dispatch of the same pipeline
104
104
  * took under 0.4ms, and because `gather` runs inside `update` that compile
105
105
  * landed whole in one render frame. Running it through the async path here
@@ -1,5 +1,5 @@
1
1
  import * as THREE from 'three/webgpu';
2
- import type { FloatUniform, Vec2Uniform } from './splat-mesh-material';
2
+ import type { FloatUniform, Vec2Uniform } from '../core/splat-mesh-material';
3
3
  /**
4
4
  * Creates the unified EWA draw material for gathered world-space splats.
5
5
  *