@threenative/terrain 0.0.0-stage → 0.1.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 (125) hide show
  1. package/AGENT_GUIDE.md +194 -0
  2. package/LICENSE +21 -0
  3. package/README.md +71 -2
  4. package/THIRD_PARTY_NOTICES.md +38 -0
  5. package/dist/editor/index.d.ts +231 -0
  6. package/dist/editor/index.js +5624 -0
  7. package/dist/editor/server.d.ts +3 -0
  8. package/dist/editor/server.js +3688 -0
  9. package/dist/editor/worker.d.ts +2 -0
  10. package/dist/editor/worker.js +2212 -0
  11. package/dist/export.d.ts +54 -0
  12. package/dist/export.js +297 -0
  13. package/dist/index.d.ts +335 -0
  14. package/dist/index.js +2927 -0
  15. package/dist/server-ByM2hmYJ.d.ts +630 -0
  16. package/dist/terrain-gPnkCU6S.d.ts +141 -0
  17. package/dist/three.d.ts +14 -0
  18. package/dist/three.js +40 -0
  19. package/dist/types-Ant8-Axc.d.ts +486 -0
  20. package/package.json +86 -3
  21. package/starter/alpine/README.md +29 -0
  22. package/starter/alpine/assets.json +12 -0
  23. package/starter/alpine/bake.mjs +118 -0
  24. package/starter/alpine/recipe.json +66167 -0
  25. package/starter/alpine/sky.ts +23 -0
  26. package/starter/alpine/surface.json +53 -0
  27. package/starter/alpine/world.ts +335 -0
  28. package/starter/coastal/README.md +37 -0
  29. package/starter/coastal/assets.json +10 -0
  30. package/starter/coastal/bake.mjs +118 -0
  31. package/starter/coastal/recipe.json +66161 -0
  32. package/starter/coastal/sea.ts +327 -0
  33. package/starter/coastal/sky.ts +24 -0
  34. package/starter/coastal/surface.json +41 -0
  35. package/starter/coastal/world.ts +386 -0
  36. package/starter/desert/README.md +35 -0
  37. package/starter/desert/assets.json +12 -0
  38. package/starter/desert/bake.mjs +118 -0
  39. package/starter/desert/recipe.json +66156 -0
  40. package/starter/desert/sky.ts +23 -0
  41. package/starter/desert/surface.json +54 -0
  42. package/starter/desert/world.ts +335 -0
  43. package/starter/forest/README.md +46 -0
  44. package/starter/forest/assets.json +32 -0
  45. package/starter/forest/bake.mjs +118 -0
  46. package/starter/forest/recipe.json +4586 -0
  47. package/starter/forest/sky.ts +27 -0
  48. package/starter/forest/surface.json +79 -0
  49. package/starter/forest/water.ts +266 -0
  50. package/starter/forest/world.ts +413 -0
  51. package/starter/tundra/README.md +29 -0
  52. package/starter/tundra/assets.json +12 -0
  53. package/starter/tundra/bake.mjs +118 -0
  54. package/starter/tundra/recipe.json +66325 -0
  55. package/starter/tundra/sky.ts +27 -0
  56. package/starter/tundra/surface.json +54 -0
  57. package/starter/tundra/water.ts +313 -0
  58. package/starter/tundra/world.ts +366 -0
  59. package/starter-assets/bark_brown_02/bark_brown_02_diff_1k.jpg +0 -0
  60. package/starter-assets/bark_brown_02/bark_brown_02_nor_gl_1k.jpg +0 -0
  61. package/starter-assets/bark_brown_02/bark_brown_02_rough_1k.jpg +0 -0
  62. package/starter-assets/boulder_01/boulder-mid.glb +0 -0
  63. package/starter-assets/boulder_01/boulder-near.glb +0 -0
  64. package/starter-assets/cliff_side/cliff_side_ao_1k.jpg +0 -0
  65. package/starter-assets/cliff_side/cliff_side_diff_1k.jpg +0 -0
  66. package/starter-assets/cliff_side/cliff_side_nor_gl_1k.jpg +0 -0
  67. package/starter-assets/cliff_side/cliff_side_rough_1k.jpg +0 -0
  68. package/starter-assets/credits.json +1022 -0
  69. package/starter-assets/fern_02/fern_02_alpha_512.png +0 -0
  70. package/starter-assets/fern_02/fern_02_diff_512.jpg +0 -0
  71. package/starter-assets/fern_02/fern_02_nor_gl_512.jpg +0 -0
  72. package/starter-assets/fir_tree_01/fir-b-lod1.glb +0 -0
  73. package/starter-assets/fir_tree_01/fir-b-lod2.glb +0 -0
  74. package/starter-assets/fir_tree_01/fir-c-lod1.glb +0 -0
  75. package/starter-assets/fir_tree_01/fir-c-lod2.glb +0 -0
  76. package/starter-assets/fir_tree_01/fir_tree_01_twig_arm_1k.jpg +0 -0
  77. package/starter-assets/fir_tree_01/fir_tree_01_twig_diff_1k.jpg +0 -0
  78. package/starter-assets/fir_tree_01/fir_tree_01_twig_nor_gl_1k.jpg +0 -0
  79. package/starter-assets/forest_ground_04/forest_ground_04_ao_1k.jpg +0 -0
  80. package/starter-assets/forest_ground_04/forest_ground_04_diff_1k.jpg +0 -0
  81. package/starter-assets/forest_ground_04/forest_ground_04_nor_gl_1k.jpg +0 -0
  82. package/starter-assets/forest_ground_04/forest_ground_04_rough_1k.jpg +0 -0
  83. package/starter-assets/forest_leaves_02/forest_leaves_02_arm_512.jpg +0 -0
  84. package/starter-assets/forest_leaves_02/forest_leaves_02_diff_512.jpg +0 -0
  85. package/starter-assets/forest_leaves_02/forest_leaves_02_nor_gl_512.jpg +0 -0
  86. package/starter-assets/grass_medium_02/grass_medium_02_alpha_512.png +0 -0
  87. package/starter-assets/grass_medium_02/grass_medium_02_diff_512.jpg +0 -0
  88. package/starter-assets/grass_medium_02/grass_medium_02_nor_gl_512.jpg +0 -0
  89. package/starter-assets/hdri/kloofendal_48d_partly_cloudy_1k.hdr +0 -0
  90. package/starter-assets/leafy_grass/leafy_grass_ao_1k.jpg +0 -0
  91. package/starter-assets/leafy_grass/leafy_grass_diff_1k.jpg +0 -0
  92. package/starter-assets/leafy_grass/leafy_grass_nor_gl_1k.jpg +0 -0
  93. package/starter-assets/leafy_grass/leafy_grass_rough_1k.jpg +0 -0
  94. package/starter-assets/lichen_rock/lichen_rock_arm_512.jpg +0 -0
  95. package/starter-assets/lichen_rock/lichen_rock_diff_512.jpg +0 -0
  96. package/starter-assets/lichen_rock/lichen_rock_nor_gl_512.jpg +0 -0
  97. package/starter-assets/mossy_rock/mossy_rock_ao_1k.jpg +0 -0
  98. package/starter-assets/mossy_rock/mossy_rock_diff_1k.jpg +0 -0
  99. package/starter-assets/mossy_rock/mossy_rock_nor_gl_1k.jpg +0 -0
  100. package/starter-assets/mossy_rock/mossy_rock_rough_1k.jpg +0 -0
  101. package/starter-assets/needle-atlas.png +0 -0
  102. package/starter-assets/needle-surface.png +0 -0
  103. package/starter-assets/river_small_rocks/river_small_rocks_arm_512.jpg +0 -0
  104. package/starter-assets/river_small_rocks/river_small_rocks_diff_512.jpg +0 -0
  105. package/starter-assets/river_small_rocks/river_small_rocks_nor_gl_512.jpg +0 -0
  106. package/starter-assets/rock_boulder_dry/rock_boulder_dry_arm_512.jpg +0 -0
  107. package/starter-assets/rock_boulder_dry/rock_boulder_dry_diff_512.jpg +0 -0
  108. package/starter-assets/rock_boulder_dry/rock_boulder_dry_nor_gl_512.jpg +0 -0
  109. package/starter-assets/rocks/boulder-mid.glb +0 -0
  110. package/starter-assets/rocks/boulder-near.glb +0 -0
  111. package/starter-assets/rocks/boulder-prep.json +37 -0
  112. package/starter-assets/rocks/rock01-mid.glb +0 -0
  113. package/starter-assets/rocks/rock01-near.glb +0 -0
  114. package/starter-assets/rocks/rock01-prep.json +37 -0
  115. package/starter-assets/rocks/rock04-mid.glb +0 -0
  116. package/starter-assets/rocks/rock04-near.glb +0 -0
  117. package/starter-assets/rocks/rock04-prep.json +37 -0
  118. package/starter-assets/sand_01/sand_01_ao_1k.jpg +0 -0
  119. package/starter-assets/sand_01/sand_01_diff_1k.jpg +0 -0
  120. package/starter-assets/sand_01/sand_01_nor_gl_1k.jpg +0 -0
  121. package/starter-assets/sand_01/sand_01_rough_1k.jpg +0 -0
  122. package/starter-assets/snow_02/snow_02_ao_1k.jpg +0 -0
  123. package/starter-assets/snow_02/snow_02_diff_1k.jpg +0 -0
  124. package/starter-assets/snow_02/snow_02_nor_gl_1k.jpg +0 -0
  125. package/starter-assets/snow_02/snow_02_rough_1k.jpg +0 -0
@@ -0,0 +1,335 @@
1
+ export { L as LayerPatch, O as OperationOptions, P as PatchCommand, T as Terrain, a as TerrainEvaluator } from './terrain-gPnkCU6S.js';
2
+ import { M as MaterialId, a as IMask, i as ISampledGrid, O as OperationType, d as ITerrainDocument, I as ITerrainState, j as IBakeMeshOptions, g as IBakedMesh, k as IBakeTerrainOptions, l as IBakedTerrain, h as IPlacementOverride, m as IDecodeHeightPngOptions, n as IDecodeRaw16Options, o as IHeightRange, p as IRaw16Options, q as IExportFile, E as ExportKind, r as IExportArchive } from './types-Ant8-Axc.js';
3
+ export { s as IBiomeParams, t as IBrushParams, u as IClearParams, f as ICopyRegionOptions, v as IDecodedHeightPng, w as IErodeParams, x as IErosionMaps, e as IEvaluateOptions, y as IFlattenParams, z as IGradeParams, A as IGrid, B as IHeightData, C as IHeightPngMetadata, D as IHeightmapParams, F as ILayer, G as IMaterialRule, H as IMaterialsParams, J as INoiseParams, K as IPaintParams, N as IPasteParams, P as IPlacement, Q as IRampParams, R as IRiver, S as IRiverParams, T as IRoadParams, U as IScatterClear, V as IScatterParams, W as IScatterRule, X as ISculptParams, Y as ISmoothParams, Z as ISplatPng, _ as IStampParams, $ as ITerraceParams, c as ITerrainConfig, a0 as ITerrainInspection, a1 as IWaterBody, a2 as IWaterParams, a3 as IWaterRule, L as Layer, b as LayerParams, a4 as MaskSampler, a5 as MaskType, a6 as SplinePoint } from './types-Ant8-Axc.js';
4
+
5
+ /** The eight splat channels, in channel order. Index 0 is the default base channel. */
6
+ declare const MATERIAL_IDS: readonly MaterialId[];
7
+ /**
8
+ * Serializable mask builders. A mask is data, never a callback, so a recipe round-trips through
9
+ * JSON and an editor can rewrite one field without executing anything.
10
+ */
11
+ declare const Mask: Readonly<{
12
+ all: () => IMask;
13
+ none: () => IMask;
14
+ circle: (at: readonly [number, number], radius: number, softness?: number) => IMask;
15
+ rectangle: (at: readonly [number, number], size: number | readonly [number, number], rotation?: number, softness?: number) => IMask;
16
+ height: (min?: number, max?: number, fade?: number) => IMask;
17
+ slope: (min?: number, max?: number, fade?: number) => IMask;
18
+ noise: (scale?: number, threshold?: number, seed?: number, fade?: number) => IMask;
19
+ biome: (name: string) => IMask;
20
+ material: (name: MaterialId) => IMask;
21
+ and: (...masks: IMask[]) => IMask;
22
+ or: (...masks: IMask[]) => IMask;
23
+ not: (mask: IMask) => IMask;
24
+ }>;
25
+
26
+ /** Bilinear world-space height query. It is not the rendered or collidable triangle surface. */
27
+ /**
28
+ * Bilinear query of canonical height samples; triangle sampling is a separate contract.
29
+ * @requires npm i @threenative/terrain
30
+ * @situation query an authored heightfield at world coordinates
31
+ * @constraint authoring data only; the game owns appearance, physics and rendering
32
+ * @example const height = sampleHeight(new Terrain({ resolution: 17 }).evaluate(), 0, 0);
33
+ */
34
+ declare const sampleHeight: (grid: ISampledGrid, x: number, z: number) => number;
35
+ /** `[dh/dx, dh/dz]` at a world position. */
36
+ /**
37
+ * World-space height gradient from the canonical samples.
38
+ * @requires npm i @threenative/terrain
39
+ * @situation measure an authored terrain gradient in metres
40
+ * @constraint authoring data only; the game owns appearance, physics and rendering
41
+ * @example const gradient = gradientAt(new Terrain({ resolution: 17 }).evaluate(), 0, 0);
42
+ */
43
+ declare function gradientAt(grid: ISampledGrid, x: number, z: number): [number, number];
44
+ /** Slope in degrees at one sample index. */
45
+ /**
46
+ * Slope in degrees at a heightfield sample.
47
+ * @requires npm i @threenative/terrain
48
+ * @situation measure terrain slope for authoring diagnostics
49
+ * @constraint authoring data only; the game owns appearance, physics and rendering
50
+ * @example const slope = slopeAtIndex(new Terrain({ resolution: 17 }).evaluate(), 0);
51
+ */
52
+ declare function slopeAtIndex(grid: ISampledGrid, i: number): number;
53
+ /**
54
+ * A slope, in degrees, that the given share of this terrain's interior vertices lie at or below.
55
+ *
56
+ * Placement rules keyed to fixed degrees break when a world is rebaked smoother or rougher: an
57
+ * outcrop rule of "over 30 degrees" placed nothing on a forest whose 98th percentile is 22. Asking
58
+ * the terrain for its own steepest share keeps the rule meaning the same thing on every world.
59
+ *
60
+ * @requires npm i @threenative/terrain
61
+ * @situation place rocks or cliffs on a terrain's own steepest ground instead of a fixed slope in degrees
62
+ * @constraint interior vertices only (edges have one-sided differences); quantile must be in [0, 1]
63
+ * @example const steep = slopeQuantile(grid, 0.98); if (slopeAt(x, z) > Math.min(30, steep)) placeRock(x, z);
64
+ */
65
+ declare function slopeQuantile(grid: ISampledGrid, quantile: number): number;
66
+ /**
67
+ * Samples a spline: Catmull-Rom horizontally to avoid corners, linear vertically to avoid
68
+ * overshoot. `smooth: false` walks the polyline.
69
+ */
70
+ /**
71
+ * Recovered horizontal Catmull–Rom and vertically linear profile sampler.
72
+ * @requires npm i @threenative/terrain
73
+ * @situation sample a road or river profile without vertical overshoot
74
+ * @constraint authoring data only; the game owns appearance, physics and rendering
75
+ * @example const points = splinePoints([[0, 4, 0], [10, 2, 10]], 3, false);
76
+ */
77
+ declare function splinePoints(points: readonly (readonly [number, number, number])[], step?: number, smooth?: boolean): [number, number, number][];
78
+
79
+ /** Valid grid resolutions: vertices per side, not cells. */
80
+ declare const RESOLUTIONS: readonly number[];
81
+ /** The parameters each operation accepts. Anything else is rejected before the state changes. */
82
+ declare const PARAMS: Readonly<Record<OperationType, readonly string[]>>;
83
+ /** Validates a whole recipe: version, config, layer count and unique layer IDs. */
84
+ /**
85
+ * Validates the recovered recipe schema, operation allow-lists and numeric bounds.
86
+ * @requires npm i @threenative/terrain
87
+ * @situation validate a terrain document before accepting an authoring write
88
+ * @constraint authoring data only; the game owns appearance, physics and rendering
89
+ * @example validateDocument(new Terrain({ resolution: 17 }).toJSON());
90
+ */
91
+ declare function validateDocument(doc: ITerrainDocument): void;
92
+
93
+ /**
94
+ * Bakes the recovered indexed top surface and optional vertical skirts into caller-owned arrays.
95
+ * @requires npm i @threenative/terrain
96
+ * @situation bake an authored terrain into portable indexed mesh arrays
97
+ * @constraint no material is chosen; vertex colours exist only with a caller-supplied palette
98
+ * @example const mesh = bakeMesh(new Terrain({ resolution: 17 }).evaluate());
99
+ * @override step, chunk bounds, skirtDepth and palette belong to the caller
100
+ */
101
+ declare function bakeMesh(state: ITerrainState, { step, x, z, cells, skirtDepth, palette, }?: IBakeMeshOptions): IBakedMesh;
102
+ /**
103
+ * Bakes finite LOD chunks, the same collision samples and resolved placements.
104
+ * @requires npm i @threenative/terrain
105
+ * @situation prepare terrain arrays and collision before a game starts
106
+ * @constraint collision origin is the southwest corner; engine Heightfield origin is its centre
107
+ * @example const baked = bakeTerrain(new Terrain({ resolution: 129 }).evaluate(), { chunkCells: 64 });
108
+ * @override chunkCells, lodSteps, skirtDepth and palette are explicit authoring choices
109
+ */
110
+ declare function bakeTerrain(state: ITerrainState, { chunkCells, lodSteps, skirtDepth, palette, }?: IBakeTerrainOptions): IBakedTerrain;
111
+
112
+ /**
113
+ * Validate and clone stable-key placement transforms before saving or previewing them.
114
+ * @requires npm i -D @threenative/terrain
115
+ * @situation validate finite positive manual prop transforms before a terrain authoring transaction
116
+ * @constraint grounding defaults on only when omitted; position and scale have three components and quaternion is unit length
117
+ * @example const transforms = validatePlacementOverrides(document.placementOverrides);
118
+ * @override grounding=false preserves authored Y and keeps clearance observable
119
+ */
120
+ declare function validatePlacementOverrides(value?: unknown): Record<string, IPlacementOverride>;
121
+ /**
122
+ * Attach manual transforms to raw evaluated candidates and report orphan keys.
123
+ * @requires npm i -D @threenative/terrain
124
+ * @situation retain manual prop transforms across terrain scatter re-evaluation
125
+ * @constraint headless authoring; game applies transforms against its model bounds and actual terrain surface
126
+ * @example const state = applyPlacementOverrides(terrain.evaluate(), document.placementOverrides ?? {});
127
+ * @override transform.grounding=false preserves requested Y while the game still measures clearance
128
+ */
129
+ declare function applyPlacementOverrides(state: ITerrainState, value: unknown): ITerrainState;
130
+
131
+ /**
132
+ * Encodes finite metre elevations as an explicit-range RAW16 buffer.
133
+ * @requires npm i @threenative/terrain
134
+ * @situation export terrain heights with a numerical range sidecar
135
+ * @constraint authoring data only; the game owns appearance, physics and rendering
136
+ * @example const raw = encodeRAW16(new Float32Array([0, 1]), { min: 0, max: 1 });
137
+ */
138
+ declare function encodeRAW16(values: ArrayLike<number> & Iterable<number>, options?: IRaw16Options): Uint8Array<ArrayBuffer>;
139
+ /**
140
+ * Validates dimensions and range before decoding numerical height samples.
141
+ * @requires npm i @threenative/terrain
142
+ * @situation import a RAW16 terrain height buffer with explicit dimensions
143
+ * @constraint authoring data only; the game owns appearance, physics and rendering
144
+ * @example const decoded = decodeRAW16(new Uint8Array(8), { width: 2, height: 2, min: 0, max: 1 });
145
+ */
146
+ declare function decodeRAW16(input: Uint8Array | ArrayBuffer, { width, height, min, max, littleEndian }: IDecodeRaw16Options): {
147
+ width: number;
148
+ height: number;
149
+ values: Float32Array<ArrayBuffer>;
150
+ min: number;
151
+ max: number;
152
+ };
153
+ /**
154
+ * Encodes numerical grayscale PNG16 with embedded elevation range.
155
+ * @requires npm i @threenative/terrain
156
+ * @situation export a terrain heightmap without an eight-bit colour conversion
157
+ * @constraint authoring data only; the game owns appearance, physics and rendering
158
+ * @example const png = await encodeHeightPNG(new Terrain({ resolution: 17 }).evaluate());
159
+ */
160
+ declare function encodeHeightPNG(state: ITerrainState, options?: Partial<IHeightRange>): Promise<Uint8Array<ArrayBuffer>>;
161
+ /**
162
+ * Encodes the eight linear material-weight channels as two RGBA images.
163
+ * @requires npm i @threenative/terrain
164
+ * @situation export terrain splat weights as linear data
165
+ * @constraint authoring data only; the game owns appearance, physics and rendering
166
+ * @example const maps = await encodeSplatPNGs(new Terrain({ resolution: 17 }).evaluate());
167
+ */
168
+ declare function encodeSplatPNGs(state: ITerrainState): Promise<{
169
+ channels: MaterialId[];
170
+ bytes: Uint8Array<ArrayBuffer>;
171
+ }[]>;
172
+ /**
173
+ * CRC-checked bounded non-interlaced grayscale PNG height decoder.
174
+ * @requires npm i @threenative/terrain
175
+ * @situation import numerical PNG8 or PNG16 terrain elevations
176
+ * @constraint authoring data only; the game owns appearance, physics and rendering
177
+ * @example const png = await encodeHeightPNG(new Terrain({ resolution: 17 }).evaluate()); const heights = await decodeHeightPNG(png);
178
+ */
179
+ declare function decodeHeightPNG(input: Uint8Array | ArrayBuffer, options?: IDecodeHeightPngOptions): Promise<{
180
+ width: number;
181
+ height: number;
182
+ values: Float32Array<ArrayBuffer>;
183
+ min: number;
184
+ max: number;
185
+ bitDepth: number;
186
+ hasEmbeddedRange: boolean;
187
+ }>;
188
+ /** Engine-independent GLB 2.0: static colored terrain geometry, no hidden external resources. */
189
+ /**
190
+ * Legacy terrain-only GLB encoding with embedded mesh arrays and no chosen material.
191
+ * @requires npm i @threenative/terrain
192
+ * @situation export baked terrain geometry without engine extensions
193
+ * @constraint authoring data only; the game owns appearance, physics and rendering
194
+ * @example const glb = encodeGLB(bakeMesh(new Terrain({ resolution: 17 }).evaluate()));
195
+ */
196
+ declare function encodeGLB(input: IBakedMesh | readonly IBakedMesh[]): Uint8Array<ArrayBuffer>;
197
+
198
+ /** Deterministic ZIP (store method). No compression library or server required. */
199
+ /**
200
+ * Deterministic store-method ZIP with safe unique relative filenames.
201
+ * @requires npm i @threenative/terrain
202
+ * @situation archive derived terrain files without another dependency
203
+ * @constraint authoring data only; the game owns appearance, physics and rendering
204
+ * @example const archive = encodeZIP([{ name: "height.raw", bytes: new Uint8Array(8) }]);
205
+ */
206
+ declare function encodeZIP(files: readonly IExportFile[]): Uint8Array<ArrayBuffer>;
207
+ /**
208
+ * Recovered numerical/project exports; GLB/runtime outputs contain terrain only.
209
+ * @requires npm i @threenative/terrain
210
+ * @situation export a terrain recipe and its numerical runtime data
211
+ * @constraint authoring data only; the game owns appearance, physics and rendering
212
+ * @example const terrain = new Terrain({ resolution: 17 }); const file = await makeExport(terrain.evaluate(), terrain.toJSON(), "project");
213
+ */
214
+ declare function makeExport(state: ITerrainState, recipe: ITerrainDocument, kind: ExportKind): Promise<IExportArchive>;
215
+
216
+ /** One streamed asset: its LOD0 model, its authored bounds and the levels it swaps to. */
217
+ interface IWorldPackageAsset {
218
+ readonly glb: string;
219
+ readonly bounds: {
220
+ readonly min: readonly [number, number, number];
221
+ readonly max: readonly [number, number, number];
222
+ };
223
+ readonly lods?: readonly {
224
+ readonly glb: string;
225
+ readonly distance: number;
226
+ }[];
227
+ readonly maxDistance?: number;
228
+ }
229
+ /** One cell's contiguous run of placement records, eight float32 values each. */
230
+ interface IWorldPackageRun {
231
+ readonly asset: string;
232
+ /** Record offset into the placement buffer, not a byte offset. */
233
+ readonly offset: number;
234
+ readonly count: number;
235
+ }
236
+ /** The `world.json` contract, declared here so this addon needs no `@threenative/core` import. */
237
+ interface IWorldPackageManifest {
238
+ readonly version: 1;
239
+ readonly extent: {
240
+ readonly minX: number;
241
+ readonly minZ: number;
242
+ readonly sizeX: number;
243
+ readonly sizeZ: number;
244
+ };
245
+ readonly cellSize: number;
246
+ readonly terrain: {
247
+ readonly heightmap: string;
248
+ readonly columns: number;
249
+ readonly rows: number;
250
+ readonly spacing: number;
251
+ readonly heightMin: number;
252
+ readonly heightMax: number;
253
+ readonly layers?: Readonly<Record<string, string>>;
254
+ };
255
+ readonly assets: Readonly<Record<string, IWorldPackageAsset>>;
256
+ readonly placements: string;
257
+ readonly cells: readonly {
258
+ readonly x: number;
259
+ readonly z: number;
260
+ readonly runs: readonly IWorldPackageRun[];
261
+ }[];
262
+ }
263
+ /** The splat layout to copy into a terrain table: eight material masks in two RGBA8 planes. */
264
+ interface IWorldPackageSplat {
265
+ readonly size: number;
266
+ readonly planes: number;
267
+ readonly masks: Readonly<Record<string, readonly [number, "r" | "g" | "b" | "a"]>>;
268
+ }
269
+ interface IBakeWorldPackageOptions {
270
+ /** Every asset any instance may reference. An instance outside this set fails the bake. */
271
+ readonly assets: Readonly<Record<string, IWorldPackageAsset>>;
272
+ /** Metres per streamed cell. Defaults to 64. */
273
+ readonly cellSize?: number;
274
+ /** Extra `terrain.layers` entries, e.g. `{ table: "terrain-table.json" }`. */
275
+ readonly layers?: Readonly<Record<string, string>>;
276
+ readonly names?: {
277
+ readonly heightmap?: string;
278
+ readonly placements?: string;
279
+ readonly splat?: string;
280
+ };
281
+ }
282
+ interface IBakedWorldPackage {
283
+ readonly manifest: IWorldPackageManifest;
284
+ readonly splat: IWorldPackageSplat;
285
+ /** The three binary files, keyed by the manifest names that point at them. */
286
+ readonly files: Readonly<Record<string, Uint8Array>>;
287
+ }
288
+ /**
289
+ * Bake an evaluated terrain into the engine's world package: a `world.json` manifest, a uint16
290
+ * heightmap, a splat mask array, a placement buffer of eight float32 per instance, and the square
291
+ * cells that stream them. The encodings and row orders are the ones the Blender recipe
292
+ * `export_world.py` writes, so one runtime streams both without a second reader.
293
+ *
294
+ * @requires npm i -D @threenative/terrain
295
+ * @situation hand an evaluated Strata terrain to a game without a Blender round trip
296
+ * @constraint headless authoring; no three, no DOM, and nothing here decides how the world looks
297
+ * @example const { manifest, files } = bakeWorldPackage(state, { assets });
298
+ * @override every asset path, bound, LOD distance and cell size comes from the caller's options
299
+ */
300
+ declare function bakeWorldPackage(state: ITerrainState, options: IBakeWorldPackageOptions): IBakedWorldPackage;
301
+
302
+ /**
303
+ * A spatial index for water proximity: river segments, river stations and lake shores.
304
+ *
305
+ * Every caller that asks "is this point near water?" over a whole heightfield or a scatter pass
306
+ * otherwise scans every segment per point. In the Strata preview that cost 3.4 s (scatter) and
307
+ * 2.3 s (ground curvature) of a synchronous scene entry on a 612-station river (PRD-466, PRD-541).
308
+ * Each segment is registered in every grid cell its bounding box covers once grown by its own reach,
309
+ * so `nearby` returns a superset of the segments within reach of the point. The caller keeps its own
310
+ * exact distance and level test on that short list.
311
+ */
312
+ interface IWaterSegment<T> {
313
+ /** One end, `[x, z]` in world metres. A station or a lake centre passes the same point twice. */
314
+ readonly a: readonly [number, number];
315
+ readonly b: readonly [number, number];
316
+ /** How far from the segment the caller's test can still answer true, in metres. */
317
+ readonly reach: number;
318
+ readonly data: T;
319
+ }
320
+ interface ISegmentIndex<T> {
321
+ /** Every segment whose reach may cover `(x, z)`. Never misses one; may include farther ones. */
322
+ nearby(x: number, z: number): readonly T[];
323
+ }
324
+ /**
325
+ * Build the index once per world; ask `nearby` per scatter candidate or heightfield vertex.
326
+ *
327
+ * @requires npm i @threenative/terrain
328
+ * @situation test scatter candidates or terrain vertices against rivers and lakes without scanning every segment
329
+ * @situation find which river stations can reach a heightfield vertex when baking a wet margin
330
+ * @constraint returns candidates only; the caller applies its own exact distance and level test
331
+ * @example const rivers = createSegmentIndex(segments, 32); const wet = rivers.nearby(x, z).some(isWet);
332
+ */
333
+ declare function createSegmentIndex<T>(segments: readonly IWaterSegment<T>[], cellSize: number): ISegmentIndex<T>;
334
+
335
+ export { ExportKind, IBakeMeshOptions, IBakeTerrainOptions, IBakedMesh, IBakedTerrain, IDecodeHeightPngOptions, IDecodeRaw16Options, IExportArchive, IExportFile, IHeightRange, IMask, IPlacementOverride, IRaw16Options, ISampledGrid, type ISegmentIndex, ITerrainDocument, ITerrainState, type IWaterSegment, MATERIAL_IDS, Mask, MaterialId, OperationType, PARAMS, RESOLUTIONS, applyPlacementOverrides, bakeMesh, bakeTerrain, bakeWorldPackage, createSegmentIndex, decodeHeightPNG, decodeRAW16, encodeGLB, encodeHeightPNG, encodeRAW16, encodeSplatPNGs, encodeZIP, gradientAt, makeExport, sampleHeight, slopeAtIndex, slopeQuantile, splinePoints, validateDocument, validatePlacementOverrides };