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

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.cts CHANGED
@@ -237,17 +237,6 @@ type Topology = {
237
237
  * pipeline never branches on a projection kind.
238
238
  */
239
239
  projection: SurfaceProjection;
240
- /** Representative surface radius in world units (curved projections only). */
241
- radius?: number;
242
- /**
243
- * Surface center in world space (curved projections only). Used to apply the
244
- * camera elevation offset along the surface up-direction during LOD.
245
- */
246
- center?: {
247
- x: number;
248
- y: number;
249
- z: number;
250
- };
251
240
  /**
252
241
  * Compute the same-level neighbor TileId in the requested direction.
253
242
  * Returns false if the neighbor is outside the valid topology.
@@ -305,42 +294,36 @@ type SeamTable = {
305
294
  declare function allocSeamTable(capacity: number): SeamTable;
306
295
  declare function resetSeamTable(seams: SeamTable): void;
307
296
  type LodMode = "distance" | "screen";
297
+ /**
298
+ * How subdivision decisions are made. A discriminated union so each mode only
299
+ * carries (and requires) its own thresholds.
300
+ * - `distance` (default): split when the camera is within `distanceFactor × r`.
301
+ * - `screen`: split when the projected pixel radius exceeds `targetPixels`.
302
+ */
303
+ type LodCriteria = {
304
+ mode?: "distance";
305
+ distanceFactor?: number;
306
+ } | {
307
+ mode: "screen";
308
+ /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)). */
309
+ projectionFactor: number;
310
+ /** Target pixel radius/size threshold for screen-space refinement. */
311
+ targetPixels: number;
312
+ };
313
+ /**
314
+ * Per-tile elevation range provider: previous-frame world-space displacement
315
+ * min/max (already scaled by `elevationScale`). Returns false when no data is
316
+ * available yet. Allocation-free via the `out` scratch.
317
+ */
318
+ type TileElevationRangeFn = (tile: TileId, out: ElevationRangeOut) => boolean;
308
319
  type UpdateParams = {
309
320
  cameraOrigin: {
310
321
  x: number;
311
322
  y: number;
312
323
  z: number;
313
324
  };
314
- /**
315
- * Terrain elevation beneath the camera (from the previous frame). During
316
- * refinement it offsets the camera toward the terrain surface so LOD distance
317
- * is measured relative to the surface rather than the datum:
318
- * - flat: subtracted from `cameraOrigin.y`.
319
- * - cube-sphere: subtracted along the radial up-direction from the planet center.
320
- */
321
- elevationAtCameraXZ?: number;
322
- /**
323
- * Controls how subdivision decisions are made.
324
- * `distance` is the initial focus; `screen` is supported for future parity.
325
- */
326
- mode?: LodMode;
327
- /**
328
- * Distance-based refinement threshold.
329
- * Interpretation is criteria-dependent; keep it stable across surfaces by using bounds.
330
- */
331
- distanceFactor?: number;
332
- /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)) */
333
- projectionFactor?: number;
334
- /** Target pixel radius/size threshold for screen-space refinement */
335
- targetPixels?: number;
336
- /** Prevent flicker by separating split/merge thresholds (0..1 typical) */
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;
343
- };
325
+ tileElevationRange?: TileElevationRangeFn;
326
+ } & LodCriteria;
344
327
  type QuadtreeConfig = {
345
328
  maxNodes: number;
346
329
  maxLevel: number;
@@ -623,6 +606,12 @@ interface CpuTerrainCache {
623
606
  sampleTerrain(worldX: number, worldZ: number): TerrainSample;
624
607
  /** True when the active projection supplies surface ops. */
625
608
  readonly hasSurface: boolean;
609
+ /**
610
+ * Swap the projection surface ops (CPU position/normal math). Used when the
611
+ * surface geometry changes (e.g. cube-sphere radius/center) without changing
612
+ * the buffer shape, so picks/queries stay in sync without reallocating.
613
+ */
614
+ setSurfaceOps(surfaceOps: CpuSurfaceOps | null): void;
626
615
  sampleSurfaceByPosition(px: number, py: number, pz: number): TerrainSurfaceSample;
627
616
  getElevationBySurfacePosition(px: number, py: number, pz: number): number | null;
628
617
  getNormalBySurfacePosition(px: number, py: number, pz: number): Vector3$1 | null;
@@ -735,12 +724,6 @@ interface RuntimeQueries {
735
724
  sphereQuery: TerrainSphereQuery | null;
736
725
  }
737
726
  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
727
  /**
745
728
  * Surface sampling ops injected into the terrain cache; `null` for flat
746
729
  * surfaces (which have no closed-surface query).
@@ -748,7 +731,10 @@ interface SurfaceProjectionCpu {
748
731
  createSurfaceOps(): CpuSurfaceOps | null;
749
732
  /** Build the runtime query objects the projection exposes. */
750
733
  createRuntimeQueries(cache: CpuTerrainCache): RuntimeQueries;
751
- /** Projection-specific CPU raycast (precise, falling back to bounds). */
734
+ /**
735
+ * Projection-specific CPU raycast against the displaced surface. Returns
736
+ * `null` when the ray misses the surface or the query snapshot isn't ready.
737
+ */
752
738
  raycast(ctx: ProjectionRaycastContext): TerrainRaycastResult | null;
753
739
  }
754
740
  interface SurfaceProjection {
@@ -1043,7 +1029,14 @@ interface TerrainQueryContext {
1043
1029
  surfaceQuery: TerrainSurfaceQuery | null;
1044
1030
  /** Cube-sphere query; `null` unless the topology uses the cubeSphere projection. */
1045
1031
  sphereQuery: TerrainSphereQuery | null;
1032
+ /** Buffer-shape identity (maxNodes/segments/projection kind); change recreates the cache. */
1046
1033
  shapeKey: string;
1034
+ /**
1035
+ * The projection these queries close over. Recreated on any geometry change
1036
+ * (e.g. cube-sphere radius, torus major/minor); an identity change rebuilds
1037
+ * the surface ops + queries so picks/markers stay in sync.
1038
+ */
1039
+ projection: SurfaceProjection;
1047
1040
  }
1048
1041
  /** Task refs for the standard terrain pipeline. */
1049
1042
  interface TerrainTasks {
@@ -1242,7 +1235,7 @@ declare const terrainTasks: {
1242
1235
  renderer: WebGPURenderer;
1243
1236
  }>;
1244
1237
  readonly tileBoundsContext: _hello_terrain_work.Task<TileBoundsContext & {
1245
- kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number) => three_webgpu.ComputeNode>;
1238
+ kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number, edgeVertexCount: number) => three_webgpu.ComputeNode>;
1246
1239
  }, string, unknown>;
1247
1240
  readonly tileBoundsReduction: _hello_terrain_work.Task<any, string, {
1248
1241
  renderer: WebGPURenderer;
@@ -1430,4 +1423,4 @@ interface TorusProjectionConfig {
1430
1423
  declare function createTorusProjection(config: TorusProjectionConfig): SurfaceProjection;
1431
1424
 
1432
1425
  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 };
1426
+ export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodCriteria, 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, TileElevationRangeFn, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };
package/dist/index.d.mts CHANGED
@@ -237,17 +237,6 @@ type Topology = {
237
237
  * pipeline never branches on a projection kind.
238
238
  */
239
239
  projection: SurfaceProjection;
240
- /** Representative surface radius in world units (curved projections only). */
241
- radius?: number;
242
- /**
243
- * Surface center in world space (curved projections only). Used to apply the
244
- * camera elevation offset along the surface up-direction during LOD.
245
- */
246
- center?: {
247
- x: number;
248
- y: number;
249
- z: number;
250
- };
251
240
  /**
252
241
  * Compute the same-level neighbor TileId in the requested direction.
253
242
  * Returns false if the neighbor is outside the valid topology.
@@ -305,42 +294,36 @@ type SeamTable = {
305
294
  declare function allocSeamTable(capacity: number): SeamTable;
306
295
  declare function resetSeamTable(seams: SeamTable): void;
307
296
  type LodMode = "distance" | "screen";
297
+ /**
298
+ * How subdivision decisions are made. A discriminated union so each mode only
299
+ * carries (and requires) its own thresholds.
300
+ * - `distance` (default): split when the camera is within `distanceFactor × r`.
301
+ * - `screen`: split when the projected pixel radius exceeds `targetPixels`.
302
+ */
303
+ type LodCriteria = {
304
+ mode?: "distance";
305
+ distanceFactor?: number;
306
+ } | {
307
+ mode: "screen";
308
+ /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)). */
309
+ projectionFactor: number;
310
+ /** Target pixel radius/size threshold for screen-space refinement. */
311
+ targetPixels: number;
312
+ };
313
+ /**
314
+ * Per-tile elevation range provider: previous-frame world-space displacement
315
+ * min/max (already scaled by `elevationScale`). Returns false when no data is
316
+ * available yet. Allocation-free via the `out` scratch.
317
+ */
318
+ type TileElevationRangeFn = (tile: TileId, out: ElevationRangeOut) => boolean;
308
319
  type UpdateParams = {
309
320
  cameraOrigin: {
310
321
  x: number;
311
322
  y: number;
312
323
  z: number;
313
324
  };
314
- /**
315
- * Terrain elevation beneath the camera (from the previous frame). During
316
- * refinement it offsets the camera toward the terrain surface so LOD distance
317
- * is measured relative to the surface rather than the datum:
318
- * - flat: subtracted from `cameraOrigin.y`.
319
- * - cube-sphere: subtracted along the radial up-direction from the planet center.
320
- */
321
- elevationAtCameraXZ?: number;
322
- /**
323
- * Controls how subdivision decisions are made.
324
- * `distance` is the initial focus; `screen` is supported for future parity.
325
- */
326
- mode?: LodMode;
327
- /**
328
- * Distance-based refinement threshold.
329
- * Interpretation is criteria-dependent; keep it stable across surfaces by using bounds.
330
- */
331
- distanceFactor?: number;
332
- /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)) */
333
- projectionFactor?: number;
334
- /** Target pixel radius/size threshold for screen-space refinement */
335
- targetPixels?: number;
336
- /** Prevent flicker by separating split/merge thresholds (0..1 typical) */
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;
343
- };
325
+ tileElevationRange?: TileElevationRangeFn;
326
+ } & LodCriteria;
344
327
  type QuadtreeConfig = {
345
328
  maxNodes: number;
346
329
  maxLevel: number;
@@ -623,6 +606,12 @@ interface CpuTerrainCache {
623
606
  sampleTerrain(worldX: number, worldZ: number): TerrainSample;
624
607
  /** True when the active projection supplies surface ops. */
625
608
  readonly hasSurface: boolean;
609
+ /**
610
+ * Swap the projection surface ops (CPU position/normal math). Used when the
611
+ * surface geometry changes (e.g. cube-sphere radius/center) without changing
612
+ * the buffer shape, so picks/queries stay in sync without reallocating.
613
+ */
614
+ setSurfaceOps(surfaceOps: CpuSurfaceOps | null): void;
626
615
  sampleSurfaceByPosition(px: number, py: number, pz: number): TerrainSurfaceSample;
627
616
  getElevationBySurfacePosition(px: number, py: number, pz: number): number | null;
628
617
  getNormalBySurfacePosition(px: number, py: number, pz: number): Vector3$1 | null;
@@ -735,12 +724,6 @@ interface RuntimeQueries {
735
724
  sphereQuery: TerrainSphereQuery | null;
736
725
  }
737
726
  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
727
  /**
745
728
  * Surface sampling ops injected into the terrain cache; `null` for flat
746
729
  * surfaces (which have no closed-surface query).
@@ -748,7 +731,10 @@ interface SurfaceProjectionCpu {
748
731
  createSurfaceOps(): CpuSurfaceOps | null;
749
732
  /** Build the runtime query objects the projection exposes. */
750
733
  createRuntimeQueries(cache: CpuTerrainCache): RuntimeQueries;
751
- /** Projection-specific CPU raycast (precise, falling back to bounds). */
734
+ /**
735
+ * Projection-specific CPU raycast against the displaced surface. Returns
736
+ * `null` when the ray misses the surface or the query snapshot isn't ready.
737
+ */
752
738
  raycast(ctx: ProjectionRaycastContext): TerrainRaycastResult | null;
753
739
  }
754
740
  interface SurfaceProjection {
@@ -1043,7 +1029,14 @@ interface TerrainQueryContext {
1043
1029
  surfaceQuery: TerrainSurfaceQuery | null;
1044
1030
  /** Cube-sphere query; `null` unless the topology uses the cubeSphere projection. */
1045
1031
  sphereQuery: TerrainSphereQuery | null;
1032
+ /** Buffer-shape identity (maxNodes/segments/projection kind); change recreates the cache. */
1046
1033
  shapeKey: string;
1034
+ /**
1035
+ * The projection these queries close over. Recreated on any geometry change
1036
+ * (e.g. cube-sphere radius, torus major/minor); an identity change rebuilds
1037
+ * the surface ops + queries so picks/markers stay in sync.
1038
+ */
1039
+ projection: SurfaceProjection;
1047
1040
  }
1048
1041
  /** Task refs for the standard terrain pipeline. */
1049
1042
  interface TerrainTasks {
@@ -1242,7 +1235,7 @@ declare const terrainTasks: {
1242
1235
  renderer: WebGPURenderer;
1243
1236
  }>;
1244
1237
  readonly tileBoundsContext: _hello_terrain_work.Task<TileBoundsContext & {
1245
- kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number) => three_webgpu.ComputeNode>;
1238
+ kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number, edgeVertexCount: number) => three_webgpu.ComputeNode>;
1246
1239
  }, string, unknown>;
1247
1240
  readonly tileBoundsReduction: _hello_terrain_work.Task<any, string, {
1248
1241
  renderer: WebGPURenderer;
@@ -1430,4 +1423,4 @@ interface TorusProjectionConfig {
1430
1423
  declare function createTorusProjection(config: TorusProjectionConfig): SurfaceProjection;
1431
1424
 
1432
1425
  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 };
1426
+ export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodCriteria, 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, TileElevationRangeFn, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };
package/dist/index.d.ts CHANGED
@@ -237,17 +237,6 @@ type Topology = {
237
237
  * pipeline never branches on a projection kind.
238
238
  */
239
239
  projection: SurfaceProjection;
240
- /** Representative surface radius in world units (curved projections only). */
241
- radius?: number;
242
- /**
243
- * Surface center in world space (curved projections only). Used to apply the
244
- * camera elevation offset along the surface up-direction during LOD.
245
- */
246
- center?: {
247
- x: number;
248
- y: number;
249
- z: number;
250
- };
251
240
  /**
252
241
  * Compute the same-level neighbor TileId in the requested direction.
253
242
  * Returns false if the neighbor is outside the valid topology.
@@ -305,42 +294,36 @@ type SeamTable = {
305
294
  declare function allocSeamTable(capacity: number): SeamTable;
306
295
  declare function resetSeamTable(seams: SeamTable): void;
307
296
  type LodMode = "distance" | "screen";
297
+ /**
298
+ * How subdivision decisions are made. A discriminated union so each mode only
299
+ * carries (and requires) its own thresholds.
300
+ * - `distance` (default): split when the camera is within `distanceFactor × r`.
301
+ * - `screen`: split when the projected pixel radius exceeds `targetPixels`.
302
+ */
303
+ type LodCriteria = {
304
+ mode?: "distance";
305
+ distanceFactor?: number;
306
+ } | {
307
+ mode: "screen";
308
+ /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)). */
309
+ projectionFactor: number;
310
+ /** Target pixel radius/size threshold for screen-space refinement. */
311
+ targetPixels: number;
312
+ };
313
+ /**
314
+ * Per-tile elevation range provider: previous-frame world-space displacement
315
+ * min/max (already scaled by `elevationScale`). Returns false when no data is
316
+ * available yet. Allocation-free via the `out` scratch.
317
+ */
318
+ type TileElevationRangeFn = (tile: TileId, out: ElevationRangeOut) => boolean;
308
319
  type UpdateParams = {
309
320
  cameraOrigin: {
310
321
  x: number;
311
322
  y: number;
312
323
  z: number;
313
324
  };
314
- /**
315
- * Terrain elevation beneath the camera (from the previous frame). During
316
- * refinement it offsets the camera toward the terrain surface so LOD distance
317
- * is measured relative to the surface rather than the datum:
318
- * - flat: subtracted from `cameraOrigin.y`.
319
- * - cube-sphere: subtracted along the radial up-direction from the planet center.
320
- */
321
- elevationAtCameraXZ?: number;
322
- /**
323
- * Controls how subdivision decisions are made.
324
- * `distance` is the initial focus; `screen` is supported for future parity.
325
- */
326
- mode?: LodMode;
327
- /**
328
- * Distance-based refinement threshold.
329
- * Interpretation is criteria-dependent; keep it stable across surfaces by using bounds.
330
- */
331
- distanceFactor?: number;
332
- /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)) */
333
- projectionFactor?: number;
334
- /** Target pixel radius/size threshold for screen-space refinement */
335
- targetPixels?: number;
336
- /** Prevent flicker by separating split/merge thresholds (0..1 typical) */
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;
343
- };
325
+ tileElevationRange?: TileElevationRangeFn;
326
+ } & LodCriteria;
344
327
  type QuadtreeConfig = {
345
328
  maxNodes: number;
346
329
  maxLevel: number;
@@ -623,6 +606,12 @@ interface CpuTerrainCache {
623
606
  sampleTerrain(worldX: number, worldZ: number): TerrainSample;
624
607
  /** True when the active projection supplies surface ops. */
625
608
  readonly hasSurface: boolean;
609
+ /**
610
+ * Swap the projection surface ops (CPU position/normal math). Used when the
611
+ * surface geometry changes (e.g. cube-sphere radius/center) without changing
612
+ * the buffer shape, so picks/queries stay in sync without reallocating.
613
+ */
614
+ setSurfaceOps(surfaceOps: CpuSurfaceOps | null): void;
626
615
  sampleSurfaceByPosition(px: number, py: number, pz: number): TerrainSurfaceSample;
627
616
  getElevationBySurfacePosition(px: number, py: number, pz: number): number | null;
628
617
  getNormalBySurfacePosition(px: number, py: number, pz: number): Vector3$1 | null;
@@ -735,12 +724,6 @@ interface RuntimeQueries {
735
724
  sphereQuery: TerrainSphereQuery | null;
736
725
  }
737
726
  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
727
  /**
745
728
  * Surface sampling ops injected into the terrain cache; `null` for flat
746
729
  * surfaces (which have no closed-surface query).
@@ -748,7 +731,10 @@ interface SurfaceProjectionCpu {
748
731
  createSurfaceOps(): CpuSurfaceOps | null;
749
732
  /** Build the runtime query objects the projection exposes. */
750
733
  createRuntimeQueries(cache: CpuTerrainCache): RuntimeQueries;
751
- /** Projection-specific CPU raycast (precise, falling back to bounds). */
734
+ /**
735
+ * Projection-specific CPU raycast against the displaced surface. Returns
736
+ * `null` when the ray misses the surface or the query snapshot isn't ready.
737
+ */
752
738
  raycast(ctx: ProjectionRaycastContext): TerrainRaycastResult | null;
753
739
  }
754
740
  interface SurfaceProjection {
@@ -1043,7 +1029,14 @@ interface TerrainQueryContext {
1043
1029
  surfaceQuery: TerrainSurfaceQuery | null;
1044
1030
  /** Cube-sphere query; `null` unless the topology uses the cubeSphere projection. */
1045
1031
  sphereQuery: TerrainSphereQuery | null;
1032
+ /** Buffer-shape identity (maxNodes/segments/projection kind); change recreates the cache. */
1046
1033
  shapeKey: string;
1034
+ /**
1035
+ * The projection these queries close over. Recreated on any geometry change
1036
+ * (e.g. cube-sphere radius, torus major/minor); an identity change rebuilds
1037
+ * the surface ops + queries so picks/markers stay in sync.
1038
+ */
1039
+ projection: SurfaceProjection;
1047
1040
  }
1048
1041
  /** Task refs for the standard terrain pipeline. */
1049
1042
  interface TerrainTasks {
@@ -1242,7 +1235,7 @@ declare const terrainTasks: {
1242
1235
  renderer: WebGPURenderer;
1243
1236
  }>;
1244
1237
  readonly tileBoundsContext: _hello_terrain_work.Task<TileBoundsContext & {
1245
- kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number) => three_webgpu.ComputeNode>;
1238
+ kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number, edgeVertexCount: number) => three_webgpu.ComputeNode>;
1246
1239
  }, string, unknown>;
1247
1240
  readonly tileBoundsReduction: _hello_terrain_work.Task<any, string, {
1248
1241
  renderer: WebGPURenderer;
@@ -1430,4 +1423,4 @@ interface TorusProjectionConfig {
1430
1423
  declare function createTorusProjection(config: TorusProjectionConfig): SurfaceProjection;
1431
1424
 
1432
1425
  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 };
1426
+ export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodCriteria, 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, TileElevationRangeFn, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };