@hello-terrain/three 0.0.0-alpha.11 → 0.0.0-alpha.12

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.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { BufferGeometry, Ray, Vector3 as Vector3$1, Raycaster, Intersection } from 'three';
1
+ import { BufferGeometry, Vector3 as Vector3$1, Ray, Raycaster, Intersection } from 'three';
2
2
  import * as three_webgpu from 'three/webgpu';
3
3
  import { StorageArrayTexture, StorageTexture, Node, WebGPURenderer, StorageBufferAttribute, StorageBufferNode, UniformNode, Vector3, Vector3Like, InstancedMesh, NodeMaterial, ConstNode } from 'three/webgpu';
4
4
  import Node$1 from 'three/src/nodes/core/Node.js';
5
- import * as three_src_nodes_TSL_js from 'three/src/nodes/TSL.js';
6
- import { ShaderCallNodeInternal } from 'three/src/nodes/TSL.js';
7
5
  import * as _hello_terrain_work from '@hello-terrain/work';
8
6
  import { TaskRef, Graph } from '@hello-terrain/work';
7
+ import * as three_src_nodes_TSL_js from 'three/src/nodes/TSL.js';
8
+ import { ShaderCallNodeInternal } from 'three/src/nodes/TSL.js';
9
9
  import * as three_tsl from 'three/tsl';
10
10
 
11
11
  /**
@@ -103,6 +103,100 @@ declare class TerrainGeometry extends BufferGeometry {
103
103
  private generateNormals;
104
104
  }
105
105
 
106
+ type TerrainFieldStorageBackendType = "array-texture" | "atlas" | "texture-3d";
107
+ type TerrainFieldStorageFormat = "rgba16float" | "rgba32float";
108
+ type TerrainFieldStorageOptions = {
109
+ backend?: TerrainFieldStorageBackendType;
110
+ filter?: "nearest" | "linear";
111
+ format?: TerrainFieldStorageFormat;
112
+ };
113
+ interface TerrainFieldStorage {
114
+ readonly backendType: TerrainFieldStorageBackendType;
115
+ readonly edgeVertexCount: number;
116
+ readonly tileCount: number;
117
+ readonly texture: StorageArrayTexture | StorageTexture;
118
+ uv(ix: Node, iy: Node, tileIndex: Node): Node;
119
+ texel(ix: Node, iy: Node, tileIndex: Node): Node;
120
+ /** UV-based filtered sample. `u, v` in [0, 1] tile-local space. */
121
+ sample(u: Node, v: Node, tileIndex: Node): Node;
122
+ resize(width: number, height: number, tileCount: number): void;
123
+ }
124
+ declare function ArrayTextureBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
125
+ declare function AtlasBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
126
+ declare function createTerrainFieldStorage(edgeVertexCount: number, tileCount: number, renderer?: WebGPURenderer, options?: TerrainFieldStorageOptions): TerrainFieldStorage;
127
+ declare function storeTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node, value: Node): Node;
128
+ declare function loadTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
129
+ declare function loadTerrainFieldElevation(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
130
+ declare function loadTerrainFieldNormal(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
131
+ /**
132
+ * UV-based filtered sample. `u, v` are in [0, 1] tile-local space.
133
+ * Respects the filter mode (nearest / linear) set on the storage.
134
+ */
135
+ declare function sampleTerrainField(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
136
+ declare function sampleTerrainFieldElevation(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
137
+ /**
138
+ * Pack a terrain field sample into RGBA: `[height, Nx, Ny, Nz]` where
139
+ * `(Nx, Ny, Nz)` is the unit world-space surface normal. Storing the full
140
+ * world normal (rather than a face-local tangent pair) keeps shading
141
+ * continuous across cube-face seams, since adjacent faces no longer rotate the
142
+ * normal through their own parametric tangent frame.
143
+ */
144
+ declare function packTerrainFieldSample(height: Node, normal: Node): Node;
145
+
146
+ interface TerrainUniformsParams {
147
+ rootSize: number;
148
+ rootOrigin: Vector3Like;
149
+ innerTileSegments: number;
150
+ skirtScale: number;
151
+ elevationScale: number;
152
+ radius: number;
153
+ instanceId: string;
154
+ }
155
+ interface TerrainUniformsContext {
156
+ uRootOrigin: UniformNode<Vector3>;
157
+ uRootSize: UniformNode<number>;
158
+ uInnerTileSegments: UniformNode<number>;
159
+ uSkirtScale: UniformNode<number>;
160
+ uElevationScale: UniformNode<number>;
161
+ uRadius: UniformNode<number>;
162
+ }
163
+ interface LeafStorageState {
164
+ data: Int32Array<ArrayBuffer>;
165
+ attribute: StorageBufferAttribute;
166
+ node: StorageBufferNode;
167
+ }
168
+
169
+ /** Shared (projection-independent) tile-compute helpers. */
170
+ type SharedTileCompute = {
171
+ tileLevel: (nodeIndex: Node) => Node;
172
+ tileFace: (nodeIndex: Node) => Node;
173
+ tileOriginVec2: (nodeIndex: Node) => Node;
174
+ /** Face-local (u, v) in [0, 1] for a grid sample, including skirt border. */
175
+ tileFaceUV: (nodeIndex: Node, ix: Node, iy: Node) => Node;
176
+ };
177
+ /** Projection-specific tile-compute builders. */
178
+ type TileComputeParts = {
179
+ tileSize: (nodeIndex: Node) => Node;
180
+ rootUV: (nodeIndex: Node, ix: Node, iy: Node) => Node;
181
+ tileVertexWorldPosition: (nodeIndex: Node, ix: Node, iy: Node) => Node;
182
+ };
183
+ type TileComputePartsContext = {
184
+ leafStorage: LeafStorageState;
185
+ uniforms: TerrainUniformsContext;
186
+ shared: SharedTileCompute;
187
+ };
188
+ type TileCompute = SharedTileCompute & {
189
+ tileSize: (nodeIndex: Node) => Node;
190
+ rootUVCompute: (nodeIndex: Node, ix: Node, iy: Node) => Node;
191
+ tileVertexWorldPositionCompute: (nodeIndex: Node, ix: Node, iy: Node) => Node;
192
+ };
193
+ /**
194
+ * Build the per-tile compute helpers, composing projection-independent
195
+ * decoders with the projection-specific position/size/uv builders supplied by
196
+ * `projection.gpu.createTileComputeParts`.
197
+ */
198
+ declare function createTileCompute(leafStorage: LeafStorageState, uniforms: TerrainUniformsContext, projection: SurfaceProjection): TileCompute;
199
+
106
200
  declare const Dir: {
107
201
  readonly LEFT: 0;
108
202
  readonly RIGHT: 1;
@@ -128,21 +222,26 @@ type TileBounds = {
128
222
  /** conservative radius */
129
223
  r: number;
130
224
  };
131
- type TopologyProjection = "flat" | "cubeSphere";
225
+ /** Scaled world-space elevation displacement range for a tile. */
226
+ type ElevationRangeOut = {
227
+ min: number;
228
+ max: number;
229
+ };
132
230
  type Topology = {
133
231
  spaceCount: number;
134
232
  /** maximum number of roots returned by `rootTiles` */
135
233
  maxRootCount: number;
136
234
  /**
137
- * GPU position/normal assembly projection. Defaults to `flat` when absent.
138
- * `cubeSphere` selects radial sphere mapping from cube faces.
235
+ * Injected surface projection strategy. Encapsulates the GPU position/normal
236
+ * assembly and the CPU query/raycast/LOD behavior for this topology, so the
237
+ * pipeline never branches on a projection kind.
139
238
  */
140
- projection?: TopologyProjection;
141
- /** Sphere radius in world units (cube-sphere projection only). */
239
+ projection: SurfaceProjection;
240
+ /** Representative surface radius in world units (curved projections only). */
142
241
  radius?: number;
143
242
  /**
144
- * Planet center in world space (cube-sphere projection only). Used to apply
145
- * the camera elevation offset along the radial up-direction during LOD.
243
+ * Surface center in world space (curved projections only). Used to apply the
244
+ * camera elevation offset along the surface up-direction during LOD.
146
245
  */
147
246
  center?: {
148
247
  x: number;
@@ -159,12 +258,13 @@ type Topology = {
159
258
  /**
160
259
  * Conservative camera-relative bounds for LOD decisions.
161
260
  * Avoids absolute world coordinates so Earth-scale worlds remain stable.
261
+ * When `elevationRange` is provided, bounds should account for displaced geometry.
162
262
  */
163
263
  tileBounds(tile: TileId, cameraOrigin: {
164
264
  x: number;
165
265
  y: number;
166
266
  z: number;
167
- }, out: TileBounds): void;
267
+ }, out: TileBounds, elevationRange?: ElevationRangeOut): void;
168
268
  /**
169
269
  * Fill root tiles for the current frame and return the count.
170
270
  * Implementations should write level-0 tiles into `out[0..count)`.
@@ -235,6 +335,11 @@ type UpdateParams = {
235
335
  targetPixels?: number;
236
336
  /** Prevent flicker by separating split/merge thresholds (0..1 typical) */
237
337
  hysteresis?: number;
338
+ /**
339
+ * Previous-frame per-tile elevation range in world-space displacement units
340
+ * (already scaled by `elevationScale`). Returns false when no data is available.
341
+ */
342
+ tileElevationRange?: (space: number, level: number, x: number, y: number, out: ElevationRangeOut) => boolean;
238
343
  };
239
344
  type QuadtreeConfig = {
240
345
  maxNodes: number;
@@ -301,6 +406,7 @@ type QuadtreeState = {
301
406
  scratchTile: TileId;
302
407
  scratchNeighbor: TileId;
303
408
  scratchBounds: TileBounds;
409
+ scratchElevationRange: ElevationRangeOut;
304
410
  scratchRootTiles: TileId[];
305
411
  /** topology space count is fixed for a given state */
306
412
  spaceCount: number;
@@ -334,8 +440,6 @@ type FlatTopologyConfig = {
334
440
  y: number;
335
441
  z: number;
336
442
  };
337
- /** optional conservative vertical extent, included in bounds radius */
338
- maxHeight?: number;
339
443
  };
340
444
  declare function createFlatTopology(cfg: FlatTopologyConfig): Topology;
341
445
 
@@ -346,8 +450,6 @@ type InfiniteFlatTopologyConfig = {
346
450
  y: number;
347
451
  z: number;
348
452
  };
349
- /** optional conservative vertical extent, included in bounds radius */
350
- maxHeight?: number;
351
453
  /** half-width of root grid in root tiles (1 => 3x3 roots) */
352
454
  rootGridRadius?: number;
353
455
  };
@@ -362,8 +464,8 @@ type CubeSphereTopologyConfig = {
362
464
  y: number;
363
465
  z: number;
364
466
  };
365
- /** Optional conservative vertical extent, included in bounds radius. */
366
- maxHeight?: number;
467
+ /** When true, elevation displaces inward and skirts point outward. */
468
+ invert?: boolean;
367
469
  };
368
470
  /**
369
471
  * Cube-sphere topology: six quadtree faces wrapped onto a sphere.
@@ -401,13 +503,13 @@ type CubeFace = {
401
503
  declare const CUBE_FACE_COUNT = 6;
402
504
  declare const CUBE_FACES: readonly CubeFace[];
403
505
 
404
- type Vec3Mutable = [number, number, number];
506
+ type Vec3Mutable$1 = [number, number, number];
405
507
  /**
406
508
  * Cube-space point for a face-local coordinate (u, v) in [0, 1]:
407
509
  * cube = forward + (2u-1) * right + (2v-1) * up
408
510
  * The result is unnormalized; normalize it to obtain the sphere direction.
409
511
  */
410
- declare function faceUVToCube(face: number, u: number, v: number, out: Vec3Mutable): void;
512
+ declare function faceUVToCube(face: number, u: number, v: number, out: Vec3Mutable$1): void;
411
513
  /** Pick the cube face whose normal axis dominates the direction. */
412
514
  declare function directionToFace(d: Vec3): number;
413
515
  /** Face-local (u, v) in [0, 1] for a direction known to fall on `face`. */
@@ -420,45 +522,255 @@ declare function directionToFaceUV(face: number, d: Vec3, out: [number, number])
420
522
  * - longitude is the angle around the +Y axis, in `[-180, 180]`,
421
523
  * measured from +Z toward +X (lon = 0 points along +Z).
422
524
  */
423
- declare function latLongToDirection(latDeg: number, lonDeg: number, out: Vec3Mutable): void;
525
+ declare function latLongToDirection(latDeg: number, lonDeg: number, out: Vec3Mutable$1): void;
424
526
  /** Inverse of {@link latLongToDirection}; returns degrees. */
425
527
  declare function directionToLatLong(d: Vec3): {
426
528
  latitude: number;
427
529
  longitude: number;
428
530
  };
429
531
 
430
- type TerrainFieldStorageBackendType = "array-texture" | "atlas" | "texture-3d";
431
- type TerrainFieldStorageFormat = "rgba16float" | "rgba32float";
432
- type TerrainFieldStorageOptions = {
433
- backend?: TerrainFieldStorageBackendType;
434
- filter?: "nearest" | "linear";
435
- format?: TerrainFieldStorageFormat;
532
+ type TorusTopologyConfig = {
533
+ /** Distance from the torus center to the tube center (the donut radius). */
534
+ majorRadius: number;
535
+ /** Radius of the tube cross-section. */
536
+ minorRadius: number;
537
+ /** Torus center in world space (defaults to origin). */
538
+ center?: {
539
+ x: number;
540
+ y: number;
541
+ z: number;
542
+ };
543
+ /** When true, elevation displaces inward and skirts point outward. */
544
+ invert?: boolean;
436
545
  };
437
- interface TerrainFieldStorage {
438
- readonly backendType: TerrainFieldStorageBackendType;
439
- readonly edgeVertexCount: number;
440
- readonly tileCount: number;
441
- readonly texture: StorageArrayTexture | StorageTexture;
442
- uv(ix: Node, iy: Node, tileIndex: Node): Node;
443
- texel(ix: Node, iy: Node, tileIndex: Node): Node;
444
- /** UV-based filtered sample. `u, v` in [0, 1] tile-local space. */
445
- sample(u: Node, v: Node, tileIndex: Node): Node;
446
- resize(width: number, height: number, tileCount: number): void;
546
+ /**
547
+ * Torus (donut) topology: a single quadtree space whose `(u, v)` axes wrap
548
+ * around the major circle and the tube cross-section. Both axes are periodic,
549
+ * so every same-level neighbor exists (wrapping modulo the level resolution).
550
+ *
551
+ * Level-0 resolution is anisotropic: `baseU = round(major/minor)` tiles along
552
+ * `u` and `baseV = 1` along `v`, so root tiles are approximately square in
553
+ * world space before isotropic LOD subdivision.
554
+ */
555
+ declare function createTorusTopology(cfg: TorusTopologyConfig): Topology;
556
+
557
+ type Vec3Mutable = [number, number, number];
558
+ /** Wrap a value into [0, 1). */
559
+ declare function wrap01(t: number): number;
560
+ /**
561
+ * Torus surface point for parameters (u, v) in [0, 1].
562
+ *
563
+ * Convention (matches `latLongToDirection`'s longitude axis):
564
+ * - `theta = 2*pi*u` sweeps around the +Y axis, measured from +Z toward +X.
565
+ * - `phi = 2*pi*v` sweeps around the tube cross-section, `phi = 0` pointing
566
+ * radially outward in the XZ plane and `phi = pi/2` pointing toward +Y.
567
+ *
568
+ * `displacement` is the elevation added to the tube (minor) radius.
569
+ */
570
+ declare function torusUVToPoint(u: number, v: number, majorRadius: number, minorRadius: number, displacement: number, center: {
571
+ x: number;
572
+ y: number;
573
+ z: number;
574
+ }, out: Vec3Mutable, invert?: boolean): void;
575
+ /** Outward unit surface normal of the base (undisplaced) torus at (u, v). */
576
+ declare function torusOutwardNormal(u: number, v: number, out: Vec3Mutable, invert?: boolean): void;
577
+ type TorusSurfaceParams = {
578
+ /** Wrapped major-circle parameter in [0, 1). */
579
+ u: number;
580
+ /** Wrapped tube parameter in [0, 1). */
581
+ v: number;
582
+ /** Distance from the point to the tube center circle. */
583
+ tubeDistance: number;
584
+ };
585
+ /**
586
+ * Map a world point to torus surface parameters. `tubeDistance - minorRadius`
587
+ * is the signed radial displacement of the point relative to the base torus.
588
+ */
589
+ declare function positionToTorusParams(px: number, py: number, pz: number, majorRadius: number, center: {
590
+ x: number;
591
+ y: number;
592
+ z: number;
593
+ }, out: TorusSurfaceParams): void;
594
+
595
+ type TerrainQueryConfig = {
596
+ rootSize: number;
597
+ originX: number;
598
+ originY: number;
599
+ originZ: number;
600
+ innerTileSegments: number;
601
+ elevationScale: number;
602
+ maxLevel: number;
603
+ /** Representative surface radius (curved projections only). */
604
+ radius: number;
605
+ /** Level-0 tile count along u before LOD subdivision (defaults to 1). */
606
+ baseU?: number;
607
+ /** Level-0 tile count along v before LOD subdivision (defaults to 1). */
608
+ baseV?: number;
609
+ };
610
+ interface CpuTerrainCache {
611
+ readonly generation: number;
612
+ readonly ready: boolean;
613
+ updateConfig(config: TerrainQueryConfig): void;
614
+ triggerReadback(renderer: WebGPURenderer, attribute: StorageBufferAttribute, spatialIndex: SpatialIndex, boundsAttribute?: StorageBufferAttribute, activeLeafCount?: number): void;
615
+ /** Release GPU readback staging buffers owned by this cache. */
616
+ dispose(): void;
617
+ getElevation(worldX: number, worldZ: number): number | null;
618
+ getNormal(worldX: number, worldZ: number): Vector3$1 | null;
619
+ getTile(worldX: number, worldZ: number): TerrainTile | null;
620
+ getTileBounds(worldX: number, worldZ: number): TerrainTileBounds | null;
621
+ getGlobalElevationRange(): ElevationRange | null;
622
+ sampleTerrainBatch(positions: Float32Array): TerrainSampleBatch;
623
+ sampleTerrain(worldX: number, worldZ: number): TerrainSample;
624
+ /** True when the active projection supplies surface ops. */
625
+ readonly hasSurface: boolean;
626
+ sampleSurfaceByPosition(px: number, py: number, pz: number): TerrainSurfaceSample;
627
+ getElevationBySurfacePosition(px: number, py: number, pz: number): number | null;
628
+ getNormalBySurfacePosition(px: number, py: number, pz: number): Vector3$1 | null;
629
+ getTileBySurfacePosition(px: number, py: number, pz: number): TerrainTile | null;
630
+ getTileBoundsBySurfacePosition(px: number, py: number, pz: number): TerrainTileBounds | null;
631
+ sampleSurfaceBatchByPosition(positions: Float32Array): TerrainSurfaceSampleBatch;
632
+ /**
633
+ * Previous-frame raw elevation min/max for a tile (unscaled field values).
634
+ * Returns false when no snapshot data is available for the tile.
635
+ */
636
+ getTileElevationRange(space: number, level: number, x: number, y: number, out: {
637
+ min: number;
638
+ max: number;
639
+ }): boolean;
447
640
  }
448
- declare function ArrayTextureBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
449
- declare function AtlasBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
450
- declare function createTerrainFieldStorage(edgeVertexCount: number, tileCount: number, renderer?: WebGPURenderer, options?: TerrainFieldStorageOptions): TerrainFieldStorage;
451
- declare function storeTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node, value: Node): Node;
452
- declare function loadTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
453
- declare function loadTerrainFieldElevation(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
454
- declare function loadTerrainFieldNormal(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
641
+
455
642
  /**
456
- * UV-based filtered sample. `u, v` are in [0, 1] tile-local space.
457
- * Respects the filter mode (nearest / linear) set on the storage.
643
+ * CPU sampling over a snapshot elevation-field buffer laid out as
644
+ * `maxNodes × (edgeVertexCount × edgeVertexCount)` raw heights.
645
+ *
646
+ * Plain-number math only (no three.js, no TSL); callers build vectors at the
647
+ * consumer-facing boundary.
458
648
  */
459
- declare function sampleTerrainField(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
460
- declare function sampleTerrainFieldElevation(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
461
- declare function packTerrainFieldSample(height: Node, normalXZ: Node, extra?: Node): Node;
649
+ interface ElevationGridShape {
650
+ edgeVertexCount: number;
651
+ verticesPerNode: number;
652
+ }
653
+
654
+ /** Stable projection identifier — for debugging/telemetry only, never switched on. */
655
+ type ProjectionKind = "flat" | "cubeSphere" | "torus" | (string & {});
656
+ interface Vec3Like {
657
+ x: number;
658
+ y: number;
659
+ z: number;
660
+ }
661
+ interface RenderVertexPositionContext {
662
+ leafStorage: LeafStorageState;
663
+ uniforms: TerrainUniformsContext;
664
+ terrainFieldStorage?: TerrainFieldStorage;
665
+ }
666
+ interface FieldNormalContext {
667
+ elevationFieldNode: Node;
668
+ edgeVertexCount: number;
669
+ tile: TileCompute;
670
+ uniforms: TerrainUniformsContext;
671
+ }
672
+ /** Per-vertex field-stage normal: `(nodeIndex, ix, iy) => unit world normal`. */
673
+ type FieldNormalFn = (nodeIndex: Node, ix: Node, iy: Node) => Node;
674
+ interface SurfaceProjectionGpu {
675
+ /** Render-path world position; also assigns the vertex normal varying. */
676
+ renderVertexPosition(ctx: RenderVertexPositionContext): Node;
677
+ /** Projection-specific compute-stage tile builders (size / uv / position). */
678
+ createTileComputeParts(ctx: TileComputePartsContext): TileComputeParts;
679
+ /** Field-stage surface normal builder. */
680
+ createFieldNormal(ctx: FieldNormalContext): FieldNormalFn;
681
+ /** Optional extra GPU samplers (e.g. sphere ByDirection); no-op for flat. */
682
+ augmentSampler?(sampler: TerrainSampler, params: CreateTerrainSamplerParams): void;
683
+ }
684
+ /** A world point projected onto a closed surface: tile space + face-local uv. */
685
+ interface SurfaceKey {
686
+ /** Tile space/face index (0 for torus, 0..5 for cube-sphere faces). */
687
+ space: number;
688
+ /** Face-local u in [0, 1). */
689
+ u: number;
690
+ /** Face-local v in [0, 1). */
691
+ v: number;
692
+ /** Outward unit direction at the key (for the surface sample `direction`). */
693
+ dirX: number;
694
+ dirY: number;
695
+ dirZ: number;
696
+ }
697
+ /** Grid neighborhood passed to {@link CpuSurfaceOps.surfaceNormal}. */
698
+ interface SurfaceNormalContext {
699
+ elevation: Float32Array;
700
+ shape: ElevationGridShape;
701
+ leafIndex: number;
702
+ /** Fractional grid coords of the sample within the leaf. */
703
+ gx: number;
704
+ gy: number;
705
+ innerTileSegments: number;
706
+ elevationScale: number;
707
+ level: number;
708
+ }
709
+ /**
710
+ * Projection-specific CPU surface math, injected into the terrain cache so the
711
+ * cache stays projection-agnostic. Implementations own their scratch (no
712
+ * module-scope state).
713
+ */
714
+ interface CpuSurfaceOps {
715
+ /** Map a world position to a surface key; `false` if it has no projection. */
716
+ positionToKey(px: number, py: number, pz: number, out: SurfaceKey): boolean;
717
+ /** Displaced world position from a key + scaled elevation (writes `out`). */
718
+ surfacePosition(key: SurfaceKey, elevation: number, out: Vector3$1): void;
719
+ /** Unit world-space surface normal from a key + grid neighborhood. */
720
+ surfaceNormal(key: SurfaceKey, ctx: SurfaceNormalContext): Vector3$1;
721
+ }
722
+ interface ProjectionRaycastContext {
723
+ ray: Ray;
724
+ options?: RaycastOptions;
725
+ terrainQuery: TerrainQuery | null;
726
+ surfaceQuery: TerrainSurfaceQuery | null;
727
+ sphereQuery: TerrainSphereQuery | null;
728
+ config: TerrainRaycastConfig;
729
+ }
730
+ interface RuntimeQueries {
731
+ query: TerrainQuery;
732
+ /** Generic surface query (position/uv keyed); `null` on flat surfaces. */
733
+ surfaceQuery: TerrainSurfaceQuery | null;
734
+ /** Cube-sphere query (adds direction/lat-long); `null` unless cube-sphere. */
735
+ sphereQuery: TerrainSphereQuery | null;
736
+ }
737
+ interface SurfaceProjectionCpu {
738
+ /**
739
+ * Offset the camera toward the terrain surface so LOD distance is measured
740
+ * from the surface, not the datum. Mutates `cam` in place by `elevation`
741
+ * along the projection's up-direction.
742
+ */
743
+ cameraSurfaceOffset(cam: Vec3Like, elevation: number): void;
744
+ /**
745
+ * Surface sampling ops injected into the terrain cache; `null` for flat
746
+ * surfaces (which have no closed-surface query).
747
+ */
748
+ createSurfaceOps(): CpuSurfaceOps | null;
749
+ /** Build the runtime query objects the projection exposes. */
750
+ createRuntimeQueries(cache: CpuTerrainCache): RuntimeQueries;
751
+ /** Projection-specific CPU raycast (precise, falling back to bounds). */
752
+ raycast(ctx: ProjectionRaycastContext): TerrainRaycastResult | null;
753
+ }
754
+ interface SurfaceProjection {
755
+ /** Identifier; never switched on internally. */
756
+ readonly kind: ProjectionKind;
757
+ /** Representative radius (bounds/uniform helper); undefined for flat. */
758
+ readonly radius?: number;
759
+ /** Surface center in world space; undefined for flat. */
760
+ readonly center?: Vec3Like;
761
+ /** Closed surfaces face outward → flip triangle winding. */
762
+ readonly faceOutward: boolean;
763
+ /**
764
+ * Per-axis level-0 tile count before LOD subdivision. Defaults to `{ u: 1, v: 1 }`.
765
+ * At level `L`, resolution is `baseU * 2^L` by `baseV * 2^L` tiles.
766
+ */
767
+ readonly baseResolution?: {
768
+ u: number;
769
+ v: number;
770
+ };
771
+ gpu: SurfaceProjectionGpu;
772
+ cpu: SurfaceProjectionCpu;
773
+ }
462
774
 
463
775
  interface ElevationParams {
464
776
  worldPosition: Node$1;
@@ -472,29 +784,6 @@ interface ElevationParams {
472
784
  }
473
785
  type ElevationCallback = (params: ElevationParams) => Node$1;
474
786
 
475
- interface TerrainUniformsParams {
476
- rootSize: number;
477
- rootOrigin: Vector3Like;
478
- innerTileSegments: number;
479
- skirtScale: number;
480
- elevationScale: number;
481
- radius: number;
482
- instanceId: string;
483
- }
484
- interface TerrainUniformsContext {
485
- uRootOrigin: UniformNode<Vector3>;
486
- uRootSize: UniformNode<number>;
487
- uInnerTileSegments: UniformNode<number>;
488
- uSkirtScale: UniformNode<number>;
489
- uElevationScale: UniformNode<number>;
490
- uRadius: UniformNode<number>;
491
- }
492
- interface LeafStorageState {
493
- data: Int32Array<ArrayBuffer>;
494
- attribute: StorageBufferAttribute;
495
- node: StorageBufferNode;
496
- }
497
-
498
787
  interface GpuSpatialIndexContext {
499
788
  data: Uint32Array<ArrayBuffer>;
500
789
  size: number;
@@ -524,7 +813,8 @@ interface CreateTerrainSamplerParams {
524
813
  elevationCallback: ElevationCallback;
525
814
  /** Maximum quadtree level to probe during tile lookup. */
526
815
  maxLevel: number;
527
- projection?: TopologyProjection;
816
+ /** Active surface projection (drives optional GPU sampler augmentation). */
817
+ projection: SurfaceProjection;
528
818
  }
529
819
  interface TerrainSample {
530
820
  elevation: number;
@@ -589,31 +879,42 @@ interface TerrainQuery {
589
879
  readonly generation: number;
590
880
  }
591
881
  /**
592
- * Cube-sphere terrain query. A surface location is identified by a direction
593
- * from the planet center (the canonical form); `ByPosition` projects any world
594
- * point onto its direction, and `ByLatLong` takes degrees (latitude
595
- * `[-90, 90]`, longitude `[-180, 180]`). Elevation is the radial displacement
596
- * above the base radius.
882
+ * Generic closed-surface terrain query, keyed on a world position projected
883
+ * onto the surface. Exposed for every non-flat projection (cube-sphere, torus,
884
+ * ...); `null` on flat surfaces. Elevation is the displacement above the base
885
+ * surface (already scaled by `elevationScale`); `position` is the full
886
+ * world-space surface point.
887
+ */
888
+ interface TerrainSurfaceQuery {
889
+ readonly generation: number;
890
+ getElevationByPosition(position: Vector3$1): number | null;
891
+ getNormalByPosition(position: Vector3$1): Vector3$1 | null;
892
+ sampleTerrainByPosition(position: Vector3$1): TerrainSurfaceSample;
893
+ getTileByPosition(position: Vector3$1): TerrainTile | null;
894
+ getTileBoundsByPosition(position: Vector3$1): TerrainTileBounds | null;
895
+ /** Batch sample; `positions` is a Float32Array of xyz triples. */
896
+ sampleTerrainBatchByPosition(positions: Float32Array): TerrainSurfaceSampleBatch;
897
+ }
898
+ /**
899
+ * Cube-sphere terrain query. Extends the generic surface query with the
900
+ * sphere-only direction/lat-long keys. A surface location is identified by a
901
+ * direction from the planet center (the canonical form); `ByPosition` projects
902
+ * any world point onto its direction, and `ByLatLong` takes degrees (latitude
903
+ * `[-90, 90]`, longitude `[-180, 180]`).
597
904
  *
598
905
  * Exposed only when the active surface uses the `cubeSphere` projection
599
906
  * (otherwise `null` on the query context / runtime).
600
907
  */
601
- interface TerrainSphereQuery {
602
- readonly generation: number;
908
+ interface TerrainSphereQuery extends TerrainSurfaceQuery {
603
909
  getElevationByDirection(direction: Vector3$1): number | null;
604
- getElevationByPosition(position: Vector3$1): number | null;
605
910
  getElevationByLatLong(latitudeDeg: number, longitudeDeg: number): number | null;
606
911
  getNormalByDirection(direction: Vector3$1): Vector3$1 | null;
607
- getNormalByPosition(position: Vector3$1): Vector3$1 | null;
608
912
  getNormalByLatLong(latitudeDeg: number, longitudeDeg: number): Vector3$1 | null;
609
913
  sampleTerrainByDirection(direction: Vector3$1): TerrainSurfaceSample;
610
- sampleTerrainByPosition(position: Vector3$1): TerrainSurfaceSample;
611
914
  sampleTerrainByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainSurfaceSample;
612
915
  getTileByDirection(direction: Vector3$1): TerrainTile | null;
613
- getTileByPosition(position: Vector3$1): TerrainTile | null;
614
916
  getTileByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTile | null;
615
917
  getTileBoundsByDirection(direction: Vector3$1): TerrainTileBounds | null;
616
- getTileBoundsByPosition(position: Vector3$1): TerrainTileBounds | null;
617
918
  getTileBoundsByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTileBounds | null;
618
919
  /** Batch sample; `directions` is a Float32Array of xyz triples. */
619
920
  sampleTerrainBatchByDirection(directions: Float32Array): TerrainSurfaceSampleBatch;
@@ -623,6 +924,22 @@ interface RaycastOptions {
623
924
  refinementSteps?: number;
624
925
  maxDistance?: number;
625
926
  }
927
+ /**
928
+ * Shared raycast bounds for the CPU marcher. Flat raycasts use the XZ extent +
929
+ * `[minY, maxY]`; curved projections derive their own radial shell from their
930
+ * geometry plus the query's global elevation range, and only read `center*`.
931
+ */
932
+ interface TerrainRaycastConfig {
933
+ rootSize: number;
934
+ originX: number;
935
+ originY: number;
936
+ originZ: number;
937
+ minY: number;
938
+ maxY: number;
939
+ centerX: number;
940
+ centerY: number;
941
+ centerZ: number;
942
+ }
626
943
  interface TerrainRaycastResult {
627
944
  position: Vector3$1;
628
945
  normal: Vector3$1;
@@ -707,59 +1024,6 @@ declare function createComputePipelineTasks(leafStageTask: TaskRef<ComputePipeli
707
1024
  }>;
708
1025
  };
709
1026
 
710
- declare function createTileCompute(leafStorage: LeafStorageState, uniforms: TerrainUniformsContext, projection?: TopologyProjection): {
711
- tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
712
- tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
713
- tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
714
- tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
715
- tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
716
- rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
717
- tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
718
- };
719
-
720
- type TerrainQueryConfig = {
721
- rootSize: number;
722
- originX: number;
723
- originY: number;
724
- originZ: number;
725
- innerTileSegments: number;
726
- elevationScale: number;
727
- maxLevel: number;
728
- /** Topology projection; `cubeSphere` enables the direction/lat-long queries. */
729
- projection: TopologyProjection;
730
- /** Sphere radius in world units (cube-sphere projection only). */
731
- radius: number;
732
- };
733
- interface CpuTerrainCache {
734
- readonly generation: number;
735
- readonly ready: boolean;
736
- updateConfig(config: TerrainQueryConfig): void;
737
- triggerReadback(renderer: WebGPURenderer, attribute: StorageBufferAttribute, spatialIndex: SpatialIndex, boundsAttribute?: StorageBufferAttribute, activeLeafCount?: number): void;
738
- getElevation(worldX: number, worldZ: number): number | null;
739
- getNormal(worldX: number, worldZ: number): Vector3$1 | null;
740
- getTile(worldX: number, worldZ: number): TerrainTile | null;
741
- getTileBounds(worldX: number, worldZ: number): TerrainTileBounds | null;
742
- getGlobalElevationRange(): ElevationRange | null;
743
- sampleTerrainBatch(positions: Float32Array): TerrainSampleBatch;
744
- sampleTerrain(worldX: number, worldZ: number): TerrainSample;
745
- getElevationByDirection(direction: Vector3$1): number | null;
746
- getElevationByPosition(position: Vector3$1): number | null;
747
- getElevationByLatLong(latitudeDeg: number, longitudeDeg: number): number | null;
748
- getNormalByDirection(direction: Vector3$1): Vector3$1 | null;
749
- getNormalByPosition(position: Vector3$1): Vector3$1 | null;
750
- getNormalByLatLong(latitudeDeg: number, longitudeDeg: number): Vector3$1 | null;
751
- sampleTerrainByDirection(direction: Vector3$1): TerrainSurfaceSample;
752
- sampleTerrainByPosition(position: Vector3$1): TerrainSurfaceSample;
753
- sampleTerrainByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainSurfaceSample;
754
- getTileByDirection(direction: Vector3$1): TerrainTile | null;
755
- getTileByPosition(position: Vector3$1): TerrainTile | null;
756
- getTileByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTile | null;
757
- getTileBoundsByDirection(direction: Vector3$1): TerrainTileBounds | null;
758
- getTileBoundsByPosition(position: Vector3$1): TerrainTileBounds | null;
759
- getTileBoundsByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTileBounds | null;
760
- sampleTerrainBatchByDirection(directions: Float32Array): TerrainSurfaceSampleBatch;
761
- }
762
-
763
1027
  interface QuadtreeConfigState {
764
1028
  state: QuadtreeState;
765
1029
  topology: Topology;
@@ -775,6 +1039,8 @@ interface ElevationFieldContext {
775
1039
  interface TerrainQueryContext {
776
1040
  cache: CpuTerrainCache;
777
1041
  query: TerrainQuery;
1042
+ /** Generic closed-surface query; `null` on flat surfaces. */
1043
+ surfaceQuery: TerrainSurfaceQuery | null;
778
1044
  /** Cube-sphere query; `null` unless the topology uses the cubeSphere projection. */
779
1045
  sphereQuery: TerrainSphereQuery | null;
780
1046
  shapeKey: string;
@@ -819,15 +1085,7 @@ declare const createElevationFieldContextTask: _hello_terrain_work.Task<{
819
1085
  attribute: StorageBufferAttribute;
820
1086
  node: three_webgpu.StorageBufferNode;
821
1087
  }, string, unknown>;
822
- declare const tileNodesTask: _hello_terrain_work.Task<{
823
- tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
824
- tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
825
- tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
826
- tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
827
- tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
828
- rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
829
- tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
830
- }, string, unknown>;
1088
+ declare const tileNodesTask: _hello_terrain_work.Task<TileCompute, string, unknown>;
831
1089
  /**
832
1090
  * Root compute stage — generates elevation data and writes to the
833
1091
  * elevation field storage buffer. Returns a single-element `ComputePipeline`.
@@ -908,7 +1166,7 @@ declare const elevationFn: _hello_terrain_work.ParamRef<ElevationCallback>;
908
1166
  * (e.g. buffer resize), so this task stays cached during normal quadtree
909
1167
  * updates — no unnecessary shader rebuilds.
910
1168
  */
911
- declare const positionNodeTask: _hello_terrain_work.Task<three_src_nodes_TSL_js.ShaderCallNodeInternal, string, unknown>;
1169
+ declare const positionNodeTask: _hello_terrain_work.Task<three_webgpu.Node, string, unknown>;
912
1170
 
913
1171
  /**
914
1172
  * Derives the terrain topology from `rootSize` and `origin`.
@@ -964,21 +1222,13 @@ declare const terrainTasks: {
964
1222
  readonly gpuSpatialIndexUpload: _hello_terrain_work.Task<GpuSpatialIndexContext, string, unknown>;
965
1223
  readonly createUniforms: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
966
1224
  readonly updateUniforms: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
967
- readonly positionNode: _hello_terrain_work.Task<three_src_nodes_TSL_js.ShaderCallNodeInternal, string, unknown>;
1225
+ readonly positionNode: _hello_terrain_work.Task<three_webgpu.Node, string, unknown>;
968
1226
  readonly createElevationFieldContext: _hello_terrain_work.Task<{
969
1227
  data: Float32Array<ArrayBuffer>;
970
1228
  attribute: three_webgpu.StorageBufferAttribute;
971
1229
  node: three_webgpu.StorageBufferNode;
972
1230
  }, string, unknown>;
973
- readonly createTileNodes: _hello_terrain_work.Task<{
974
- tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
975
- tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
976
- tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
977
- tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
978
- tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
979
- rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
980
- tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
981
- }, string, unknown>;
1231
+ readonly createTileNodes: _hello_terrain_work.Task<TileCompute, string, unknown>;
982
1232
  readonly createTerrainFieldTexture: _hello_terrain_work.Task<any, string, {
983
1233
  renderer: WebGPURenderer;
984
1234
  }>;
@@ -1012,35 +1262,29 @@ type ComputeDeviceLimits = {
1012
1262
  };
1013
1263
  declare function getDeviceComputeLimits(renderer: WebGPURenderer): ComputeDeviceLimits;
1014
1264
 
1265
+ /**
1266
+ * Add the cube-sphere direction samplers to a base sampler. Called from the
1267
+ * cube-sphere projection's `gpu.augmentSampler` hook.
1268
+ */
1269
+ declare function augmentCubeSphereSampler(sampler: TerrainSampler, params: CreateTerrainSamplerParams): void;
1015
1270
  declare function createTerrainSampler(params: CreateTerrainSamplerParams): TerrainSampler;
1016
1271
 
1017
1272
  /** Flat (heightfield) query, keyed on world XZ. */
1018
1273
  declare function createTerrainQuery(cache: CpuTerrainCache): TerrainQuery;
1019
- /** Cube-sphere query, keyed on a direction / position / lat-long. */
1020
- declare function createTerrainSphereQuery(cache: CpuTerrainCache): TerrainSphereQuery;
1021
-
1022
- type CpuRaycastConfig = {
1023
- rootSize: number;
1024
- originX: number;
1025
- originZ: number;
1026
- minY: number;
1027
- maxY: number;
1028
- /** Topology projection; `cubeSphere` selects the radial sphere raycast. */
1029
- projection?: TopologyProjection;
1030
- /** Planet center (cube-sphere only). */
1031
- centerX?: number;
1032
- centerY?: number;
1033
- centerZ?: number;
1034
- /** Base sphere radius (cube-sphere only). */
1035
- radius?: number;
1036
- /** Inner/outer radial bounds of the terrain shell (cube-sphere only). */
1037
- minRadius?: number;
1038
- maxRadius?: number;
1039
- };
1274
+ /**
1275
+ * Generic closed-surface query, keyed on a world position projected onto the
1276
+ * surface. Cube-sphere extends this with direction/lat-long keys.
1277
+ */
1278
+ declare function createTerrainSurfaceQuery(cache: CpuTerrainCache): TerrainSurfaceQuery;
1040
1279
 
1041
- type TerrainRaycastConfig = CpuRaycastConfig;
1280
+ /**
1281
+ * Build a terrain raycaster that delegates the projection-specific marching to
1282
+ * the active surface projection — no branching on a projection kind here.
1283
+ */
1042
1284
  declare function createTerrainRaycast(params: {
1285
+ getProjection: () => SurfaceProjection;
1043
1286
  getTerrainQuery: () => TerrainQuery | null;
1287
+ getSurfaceQuery: () => TerrainSurfaceQuery | null;
1044
1288
  getSphereQuery: () => TerrainSphereQuery | null;
1045
1289
  getConfig: () => TerrainRaycastConfig;
1046
1290
  }): TerrainRaycast;
@@ -1159,5 +1403,31 @@ declare const voronoiCells: three_src_nodes_TSL_js.ShaderNodeFn<[three_tsl.Proxi
1159
1403
  uv: Node;
1160
1404
  }>]>;
1161
1405
 
1162
- export { ArrayTextureBackend, AtlasBackend, CUBE_FACES, CUBE_FACE_COUNT, Dir, TerrainGeometry, TerrainMesh, U32_EMPTY, allocLeafSet, allocSeamTable, beginUpdate, blendAngleCorrectedNormals, buildLeafIndex, buildSeams2to1, compileComputeTask, createComputePipelineTasks, createCubeSphereTopology, createElevationFieldContextTask, createFlatTopology, createInfiniteFlatTopology, createSpatialIndex, createState, createTerrainFieldStorage, createTerrainFieldTextureTask, createTerrainQuery, createTerrainRaycast, createTerrainSampler, createTerrainSamplerTask, createTerrainSphereQuery, createTerrainUniforms, createUniformsTask, cubeFaceBasis, cubeFaceDirection, cubeFaceFromDirection, cubeFacePoint, cubeFaceUVFromDirection, deriveNormalZ, directionToFace, directionToFaceUV, directionToLatLong, elevationFieldStageTask, elevationFn, elevationScale, executeComputeTask, faceUVToCube, getDeviceComputeLimits, gpuSpatialIndexStorageTask, gpuSpatialIndexUploadTask, innerTileSegments, instanceIdTask, isSkirtUV, isSkirtVertex, latLongToDirection, leafGpuBufferTask, leafStorageTask, loadTerrainField, loadTerrainFieldElevation, loadTerrainFieldNormal, maxLevel, maxNodes, origin, packTerrainFieldSample, positionNodeTask, quadtreeConfigTask, quadtreeUpdate, quadtreeUpdateTask, radius, resetLeafSet, resetSeamTable, rootSize, sampleTerrainField, sampleTerrainFieldElevation, skirtScale, sphereTangentFrameNormal, storeTerrainField, tangentFromAxis, terrainFieldFilter, terrainFieldStageTask, terrainGraph, terrainQueryTask, terrainRaycastTask, terrainReadbackTask, terrainTasks, textureSpaceToVectorSpace, tileNodesTask, topology, topologyTask, unpackTangentNormal, update, updateUniformsTask, vElevation, vGlobalVertexIndex, vectorSpaceToTextureSpace, voronoiCells };
1163
- export type { ComputePipeline, ComputeStageCallback, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodMode, QuadtreeConfig, QuadtreeConfigState, QuadtreeState, RaycastOptions, SeamTable, SpatialIndex, TerrainFieldStorage, TerrainFieldStorageBackendType, TerrainFieldStorageFormat, TerrainFieldStorageOptions, TerrainGraph, TerrainQuery, TerrainQueryContext, TerrainRaycast, TerrainRaycastConfig, TerrainRaycastResult, TerrainSample, TerrainSampleBatch, TerrainSampler, TerrainSphereQuery, TerrainSurfaceSample, TerrainSurfaceSampleBatch, TerrainTasks, TerrainTile, TerrainTileBounds, TerrainUniformsContext, TerrainUniformsParams, TileBounds, TileId, Topology, TopologyProjection, UpdateParams, Vec3, Vec3Mutable };
1406
+ /** Flat heightfield projection: tiles in the XZ plane, elevation along +Y. */
1407
+ declare function createFlatProjection(): SurfaceProjection;
1408
+
1409
+ interface CubeSphereProjectionConfig {
1410
+ radius: number;
1411
+ center?: Vec3Like;
1412
+ /** When true, elevation displaces inward and skirts point outward. */
1413
+ invert?: boolean;
1414
+ }
1415
+ /** Cube-sphere projection: six faces wrapped radially onto a sphere. */
1416
+ declare function createCubeSphereProjection(config: CubeSphereProjectionConfig): SurfaceProjection;
1417
+
1418
+ interface TorusProjectionConfig {
1419
+ majorRadius: number;
1420
+ minorRadius: number;
1421
+ center?: Vec3Like;
1422
+ /** When true, elevation displaces inward and skirts point outward. */
1423
+ invert?: boolean;
1424
+ /** Level-0 tile count along u before LOD subdivision (defaults to 1). */
1425
+ baseU?: number;
1426
+ /** Level-0 tile count along v before LOD subdivision (defaults to 1). */
1427
+ baseV?: number;
1428
+ }
1429
+ /** Torus (donut) projection: a single closed surface periodic in both axes. */
1430
+ declare function createTorusProjection(config: TorusProjectionConfig): SurfaceProjection;
1431
+
1432
+ export { ArrayTextureBackend, AtlasBackend, CUBE_FACES, CUBE_FACE_COUNT, Dir, TerrainGeometry, TerrainMesh, U32_EMPTY, allocLeafSet, allocSeamTable, augmentCubeSphereSampler, beginUpdate, blendAngleCorrectedNormals, buildLeafIndex, buildSeams2to1, compileComputeTask, createComputePipelineTasks, createCubeSphereProjection, createCubeSphereTopology, createElevationFieldContextTask, createFlatProjection, createFlatTopology, createInfiniteFlatTopology, createSpatialIndex, createState, createTerrainFieldStorage, createTerrainFieldTextureTask, createTerrainQuery, createTerrainRaycast, createTerrainSampler, createTerrainSamplerTask, createTerrainSurfaceQuery, createTerrainUniforms, createTorusProjection, createTorusTopology, createUniformsTask, cubeFaceBasis, cubeFaceDirection, cubeFaceFromDirection, cubeFacePoint, cubeFaceUVFromDirection, deriveNormalZ, directionToFace, directionToFaceUV, directionToLatLong, elevationFieldStageTask, elevationFn, elevationScale, executeComputeTask, faceUVToCube, getDeviceComputeLimits, gpuSpatialIndexStorageTask, gpuSpatialIndexUploadTask, innerTileSegments, instanceIdTask, isSkirtUV, isSkirtVertex, latLongToDirection, leafGpuBufferTask, leafStorageTask, loadTerrainField, loadTerrainFieldElevation, loadTerrainFieldNormal, maxLevel, maxNodes, origin, packTerrainFieldSample, positionNodeTask, positionToTorusParams, quadtreeConfigTask, quadtreeUpdate, quadtreeUpdateTask, radius, resetLeafSet, resetSeamTable, rootSize, sampleTerrainField, sampleTerrainFieldElevation, skirtScale, sphereTangentFrameNormal, storeTerrainField, tangentFromAxis, terrainFieldFilter, terrainFieldStageTask, terrainGraph, terrainQueryTask, terrainRaycastTask, terrainReadbackTask, terrainTasks, textureSpaceToVectorSpace, tileNodesTask, topology, topologyTask, torusOutwardNormal, torusUVToPoint, unpackTangentNormal, update, updateUniformsTask, vElevation, vGlobalVertexIndex, vectorSpaceToTextureSpace, voronoiCells, wrap01 };
1433
+ export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodMode, ProjectionKind, ProjectionRaycastContext, QuadtreeConfig, QuadtreeConfigState, QuadtreeState, RaycastOptions, RenderVertexPositionContext, RuntimeQueries, SeamTable, SpatialIndex, SurfaceKey, SurfaceNormalContext, SurfaceProjection, SurfaceProjectionCpu, SurfaceProjectionGpu, TerrainFieldStorage, TerrainFieldStorageBackendType, TerrainFieldStorageFormat, TerrainFieldStorageOptions, TerrainGraph, TerrainQuery, TerrainQueryContext, TerrainRaycast, TerrainRaycastConfig, TerrainRaycastResult, TerrainSample, TerrainSampleBatch, TerrainSampler, TerrainSphereQuery, TerrainSurfaceQuery, TerrainSurfaceSample, TerrainSurfaceSampleBatch, TerrainTasks, TerrainTile, TerrainTileBounds, TerrainUniformsContext, TerrainUniformsParams, TileBounds, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };