procedural-terrains 0.1.0-alpha.0 → 2.0.0

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 (106) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +243 -237
  3. package/dist/{CompileMaterial-xRSfAPw7.js → CompileMaterial-DZiWxNZC.js} +2 -2
  4. package/dist/CompileMaterial-DZiWxNZC.js.map +1 -0
  5. package/dist/DetailPageCache-C0qhr02H.js +171 -0
  6. package/dist/DetailPageCache-C0qhr02H.js.map +1 -0
  7. package/dist/ExportEncoding-DOxfYfK8.js.map +1 -1
  8. package/dist/FiniteTerrain-B34WMz5S.js +1925 -0
  9. package/dist/FiniteTerrain-B34WMz5S.js.map +1 -0
  10. package/dist/{InfiniteTerrain-oi0A4Vxw.js → InfiniteTerrain-SgoJz3qJ.js} +5 -4
  11. package/dist/InfiniteTerrain-SgoJz3qJ.js.map +1 -0
  12. package/dist/{MiniTerrain-BrVyDXJH.js → MiniTerrain-Blt0H1S0.js} +97 -20
  13. package/dist/MiniTerrain-Blt0H1S0.js.map +1 -0
  14. package/dist/{MiniWaterMaterial-BHUu65mQ.js → MiniWaterMaterial-DLml0hi6.js} +35 -10
  15. package/dist/MiniWaterMaterial-DLml0hi6.js.map +1 -0
  16. package/dist/PlanetHeightSampler-CVP8-zSR.js.map +1 -1
  17. package/dist/{PlanetMaterial-C5npG09e.js → PlanetMaterial-B1_ZPlx5.js} +3 -4
  18. package/dist/PlanetMaterial-B1_ZPlx5.js.map +1 -0
  19. package/dist/{PlanetTerrain-WWz9mLmY.js → PlanetTerrain-DCvxS1Q8.js} +4 -4
  20. package/dist/PlanetTerrain-DCvxS1Q8.js.map +1 -0
  21. package/dist/ProgramHealthGate-DS47bUo1.js +935 -0
  22. package/dist/ProgramHealthGate-DS47bUo1.js.map +1 -0
  23. package/dist/RendererState-BwgUc9ze.js.map +1 -1
  24. package/dist/RevisionScope-J__6V9I_.js +210 -0
  25. package/dist/RevisionScope-J__6V9I_.js.map +1 -0
  26. package/dist/SurfaceGraph-DsI-Nb1C.js.map +1 -1
  27. package/dist/{SurfaceTextureRoles-CchcgOH1.js → SurfaceTextureRoles-tRGhAZXG.js} +4 -4
  28. package/dist/SurfaceTextureRoles-tRGhAZXG.js.map +1 -0
  29. package/dist/{TerrainClouds-I0DrVLLm.js → TerrainClouds-BuKvwnWw.js} +28 -23
  30. package/dist/TerrainClouds-BuKvwnWw.js.map +1 -0
  31. package/dist/{TerrainHeightCache-wAUIBZtx.js → TerrainHeightCache-Dsde6EDL.js} +2 -2
  32. package/dist/TerrainHeightCache-Dsde6EDL.js.map +1 -0
  33. package/dist/TerrainParameters-A3fcNJTR.js +3373 -0
  34. package/dist/TerrainParameters-A3fcNJTR.js.map +1 -0
  35. package/dist/{TerrainSources-DZZliDBJ.js → TerrainSources-Bye63rDk.js} +947 -3
  36. package/dist/TerrainSources-Bye63rDk.js.map +1 -0
  37. package/dist/{TerrainWater-D78XunS8.js → TerrainWater-Cil7waG3.js} +137 -32
  38. package/dist/TerrainWater-Cil7waG3.js.map +1 -0
  39. package/dist/{WaterMaterial-Cy4DiYui.js → WaterMaterial-BUsAp0SS.js} +2 -2
  40. package/dist/WaterMaterial-BUsAp0SS.js.map +1 -0
  41. package/dist/assets/DetailPageWorker-CqGjR0ER.js.map +1 -1
  42. package/dist/assets/SurfacePreparation.worker-Jts9_tyU.js.map +1 -1
  43. package/dist/assets/erosion.worker-BjbbybpK.js.map +1 -1
  44. package/dist/assets.js +1 -1
  45. package/dist/assets.js.map +1 -1
  46. package/dist/biomeGLSL-CIkhxIlH.js.map +1 -1
  47. package/dist/clouds.js +2 -2
  48. package/dist/documents.js +17 -7
  49. package/dist/documents.js.map +1 -1
  50. package/dist/export.js +1 -2
  51. package/dist/export.js.map +1 -1
  52. package/dist/generation-BVR5tVBH.js.map +1 -1
  53. package/dist/index.js +1 -1
  54. package/dist/infinite.js +1 -1
  55. package/dist/mini.js +1 -1
  56. package/dist/noiseStackCodegen-C4R9Y3L8.js.map +1 -1
  57. package/dist/planet.js +1 -1
  58. package/dist/planetGLSL-2xas0f3o.js.map +1 -1
  59. package/dist/real-world.js +1 -1
  60. package/dist/real-world.js.map +1 -1
  61. package/dist/render.js +29 -175
  62. package/dist/render.js.map +1 -1
  63. package/dist/viewer.js +1 -1
  64. package/dist/viewer.js.map +1 -1
  65. package/dist/water.js +2 -2
  66. package/dist/waterLightingGLSL-DJ1lX0Cy.js.map +1 -1
  67. package/package.json +94 -94
  68. package/types/assets.d.ts +84 -84
  69. package/types/clouds.d.ts +78 -64
  70. package/types/documents.d.ts +5 -5
  71. package/types/export.d.ts +35 -35
  72. package/types/generation.d.ts +26 -26
  73. package/types/index.d.ts +300 -236
  74. package/types/infinite.d.ts +2 -2
  75. package/types/mini.d.ts +63 -63
  76. package/types/planet.d.ts +2 -2
  77. package/types/real-world.d.ts +38 -38
  78. package/types/render.d.ts +46 -45
  79. package/types/viewer.d.ts +14 -14
  80. package/types/water.d.ts +108 -101
  81. package/dist/CloudSettings-o31yZs9N.js +0 -138
  82. package/dist/CloudSettings-o31yZs9N.js.map +0 -1
  83. package/dist/CloudShadowPass-BtxrgoAJ.js +0 -1267
  84. package/dist/CloudShadowPass-BtxrgoAJ.js.map +0 -1
  85. package/dist/CompileMaterial-xRSfAPw7.js.map +0 -1
  86. package/dist/FiniteTerrain-CtkWkoxn.js +0 -4121
  87. package/dist/FiniteTerrain-CtkWkoxn.js.map +0 -1
  88. package/dist/InfiniteTerrain-oi0A4Vxw.js.map +0 -1
  89. package/dist/MiniTerrain-BrVyDXJH.js.map +0 -1
  90. package/dist/MiniWaterMaterial-BHUu65mQ.js.map +0 -1
  91. package/dist/PlanetMaterial-C5npG09e.js.map +0 -1
  92. package/dist/PlanetTerrain-WWz9mLmY.js.map +0 -1
  93. package/dist/ProgramHealthGate-CDL2dmsa.js +0 -172
  94. package/dist/ProgramHealthGate-CDL2dmsa.js.map +0 -1
  95. package/dist/RevisionScope-B6OuKn76.js +0 -68
  96. package/dist/RevisionScope-B6OuKn76.js.map +0 -1
  97. package/dist/SurfaceTextureRoles-CchcgOH1.js.map +0 -1
  98. package/dist/TerrainClouds-I0DrVLLm.js.map +0 -1
  99. package/dist/TerrainHeightCache-wAUIBZtx.js.map +0 -1
  100. package/dist/TerrainSources-DZZliDBJ.js.map +0 -1
  101. package/dist/TerrainWater-D78XunS8.js.map +0 -1
  102. package/dist/WaterMaterial-Cy4DiYui.js.map +0 -1
  103. package/dist/WaterSettings-CDMgI_U1.js +0 -410
  104. package/dist/WaterSettings-CDMgI_U1.js.map +0 -1
  105. package/dist/terrainSurfaceTextureGLSL-D9BQYXKy.js +0 -947
  106. package/dist/terrainSurfaceTextureGLSL-D9BQYXKy.js.map +0 -1
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 ZyFou
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense,
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZyFou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense,
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,237 +1,243 @@
1
- # Procedural Terrains — Three.js runtime
2
-
3
- An ESM library extracted from Terrain Studio 2.0.0. Finite, infinite, planetary
4
- and Mini worlds reuse the studio's terrain geometry, noise, shaders and caches.
5
- The package has no React, Electron, account, stylesheet or backend dependency.
6
- Three.js `~0.185.1` is a peer dependency; `fflate` handles packed materials,
7
- paint documents and ZIP exports. The current version is an alpha.
8
-
9
- ## Install
10
-
11
- ```sh
12
- npm install procedural-terrains
13
- ```
14
-
15
- Use `three@~0.185.1` in your application (npm also installs this peer automatically). The package
16
- contains ESM entry points, declarations, bundled Workers and the MIT license.
17
- No studio files or material packs are copied into the package.
18
-
19
- To build from source: `npm ci && npm run build` in the repository. An installable
20
- archive is also produced in `dist/npm/`. See [release publishing](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/package-publishing.md).
21
-
22
- ## Use your own renderer and loop
23
-
24
- ```js
25
- import { createTerrain } from 'procedural-terrains';
26
-
27
- const terrain = await createTerrain({ renderer, configuration: {
28
- layout: { chunkCount: 8, chunkSize: 128 },
29
- source: { kind: 'noise', seed: 1337, octaves: 7 },
30
- heightScale: 560,
31
- } });
32
- scene.add(terrain.object);
33
- await terrain.prepare(camera);
34
-
35
- function frame(deltaSeconds) {
36
- terrain.update(deltaSeconds, { camera });
37
- renderer.render(scene, camera);
38
- }
39
- await terrain.configure({ source: { seed: 42 } });
40
- const height = terrain.sampleHeight(0, 0);
41
- const document = terrain.serialize();
42
- terrain.dispose();
43
- ```
44
-
45
- The host owns the renderer, camera, scene, resize policy and animation loop.
46
- Use an identity world transform for each terrain and its ancestors. Rendering
47
- requires browser WebGL2; importing the modules and using data models does not
48
- require DOM globals. CPU height samples approximate the GPU field and are not
49
- exact triangle collision queries. Heights and dimensions are in world units.
50
- The built-in shaders use their own sun/ambient lighting and display-encoded
51
- colour; arbitrary scene lights and renderer tone mapping are not adopted.
52
-
53
- ## Entry points
54
-
55
- | Import | Public components |
56
- | --- | --- |
57
- | `procedural-terrains` | `createTerrain`, `FiniteTerrain` |
58
- | `/infinite` | `createInfiniteTerrain` with camera-centred streaming and clipmaps |
59
- | `/planet` | `createPlanetTerrain` with cube-sphere patches and height/climate bakes |
60
- | `/mini` | `createMiniTerrain`, Mini state/layout/framing helpers |
61
- | `/generation` | Noise Stack builders, graph compiler/document builders, manual document normalization |
62
- | `/water` | `createWater`, `TerrainWater`, defaults/modes |
63
- | `/clouds` | `createClouds`, `TerrainClouds`, defaults |
64
- | `/render` | `TerrainRenderPipeline`, `TerrainPass`, optional height/detail caches |
65
- | `/assets` | Explicit resource scopes, material providers, erosion/surface Workers |
66
- | `/real-world` | `TerrariumProvider`, `createRealWorldTerrain` |
67
- | `/export` | `exportTerrain`, `zipTerrainExport` |
68
- | `/documents` | `loadTerrainDocument` |
69
- | `/viewer` | Explicit DOM viewer with its own renderer, controls and loop |
70
-
71
- All runtime instances implement `prepare`, `configure`, `update`, `serialize`,
72
- `getDiagnostics` and idempotent `dispose`. Destruction releases owned resources
73
- and detaches the group. It never destroys a borrowed renderer, imagery texture,
74
- surface resource or `TerrainResources` scope. Shared resources remain alive
75
- until their last lease is released. Dispose effects individually or with their
76
- terrain; dispose pipelines separately.
77
-
78
- ## World modes and sources
79
-
80
- ```js
81
- import { createInfiniteTerrain } from 'procedural-terrains/infinite';
82
- import { createPlanetTerrain } from 'procedural-terrains/planet';
83
- import { createMiniTerrain } from 'procedural-terrains/mini';
84
-
85
- const infinite = await createInfiniteTerrain({ renderer, configuration: {
86
- layout: { chunkSize: 128, viewRadius: 8, cacheResolution: 256 },
87
- } });
88
- const planet = await createPlanetTerrain({ renderer, configuration: {
89
- layout: { radius: 16000, faceGrid: 8, bakeResolution: 256 },
90
- } });
91
- const mini = await createMiniTerrain({ renderer,
92
- mini: { recipe: 'cove', seed: 1337, width: 1024, quality: 'balanced' },
93
- backdrop: false,
94
- });
95
- await mini.mini.configure({ waterLevel: 0.6 });
96
- const framing = mini.mini.framing(); // suggestion; does not move your camera
97
- ```
98
-
99
- Choose a world at construction. Create another instance when switching world
100
- modes. Mini is a finite presentation: configure its managed relief, composition,
101
- resolution and footprint through `terrain.mini.configure`. Water/cloud layers
102
- are explicit opt-ins. Mini does not install editor controls, vegetation or a
103
- studio background; `backdrop: true` enables its background.
104
-
105
- Finite sources support `noise` (optional Noise Stack), `graph` (validated graph
106
- document), `manual` (shapes/sculpt with flat, procedural or graph base) and
107
- `heightmap` (`data`, `width`, `height`). Heightmaps cover the board, row zero at
108
- negative Z, contain world-unit heights, and are uploaded as filtered half floats.
109
- Infinite worlds support unbounded noise/2D graphs; planets require a Noise Stack
110
- with 3D evaluation. Unsupported combinations fail explicitly. Source documents
111
- are detached and frozen with the normalized configuration.
112
-
113
- ```js
114
- await terrain.configure({ source: {
115
- kind: 'heightmap', width: 2, height: 2,
116
- data: new Float32Array([0, 50, 120, 30]),
117
- } });
118
- ```
119
-
120
- `sampleHeight` returns null outside finite boards; use `sampleHeight3D` with a
121
- nonzero direction for planets. Planet samples return relief above the radius.
122
- LOD resolutions must be four even values halving at each step. Mini uses the
123
- studio's fixed 128/256/512 segment profiles instead. World-specific layout
124
- options control streaming/triangle budgets and bake resolutions.
125
-
126
- ## Water, clouds and scene composition
127
-
128
- ```js
129
- import { createWater } from 'procedural-terrains/water';
130
- import { createClouds } from 'procedural-terrains/clouds';
131
- import { TerrainRenderPipeline } from 'procedural-terrains/render';
132
-
133
- const water = await createWater({ terrain, mode: 'volumetric' });
134
- const clouds = await createClouds({ terrain, mode: 'realistic' });
135
- const pipeline = new TerrainRenderPipeline({ renderer, terrains: [terrain] });
136
- await terrain.prepare(camera);
137
- function frame(dt) {
138
- terrain.update(dt, { camera });
139
- pipeline.render(scene, camera);
140
- }
141
- ```
142
-
143
- The pipeline renders the **whole host scene** into its own colour/depth target,
144
- captures water reflection/refraction when needed, composites clouds against
145
- opaque depth in a distinct target, then applies underwater effects. This avoids
146
- sampling an attached depth texture. It restores target, viewport, scissor,
147
- clear state and XR/shadow flags. `TerrainPass` replaces `RenderPass` in an
148
- EffectComposer; it is not an extra full-scene overlay after another RenderPass.
149
-
150
- Water modes: `off`, `legacy`, `realistic`, `volumetric`, `cinematic`, `stylized`.
151
- The existing world/quality fallback rules apply: inspect requested/effective
152
- modes with `water.getDiagnostics()`. Clouds support `legacy` and `realistic` in
153
- all world modes. Each terrain should have one water and one cloud layer.
154
-
155
- Finite terrain rendering can run directly with `renderer.render`. Add
156
- `createHeightCache({ terrain, resolution: 512 })` or
157
- `createDetailCache({ terrain, quality: 2 })` when needed. Height caches retain
158
- the studio's double buffering; detail caches own their worker and GPU pages.
159
- Mini, planet and infinite adapters retain their existing specialized caches.
160
-
161
- ## Materials and external data
162
-
163
- ```js
164
- import { TerrainSurfaceProvider, createSurfaceResources } from 'procedural-terrains/assets';
165
- const provider = new TerrainSurfaceProvider({ baseUrl: 'https://your-host/material-pack/' });
166
- const surface = await createSurfaceResources({ provider, document: surfaceDocument });
167
- await terrain.setSurface(surface);
168
- // After detaching from every terrain:
169
- await terrain.setSurface(null);
170
- surface.dispose();
171
- provider.dispose();
172
- ```
173
-
174
- Host `catalog.json` and its `.pbr` files yourself. Catalog hashes and material
175
- budgets are checked. Local assets use an injected `loadUserAsset`; historical
176
- maps require an explicit `legacyBaseUrl`. `TerrainSurfaceWorker.prepare` accepts
177
- serializable pack URLs/documents; `TerrainCompute.erode` uses a dedicated worker
178
- per job, preserves caller buffers and returns additive `delta` plus erosion
179
- maps. Inject worker factories for CSP/custom hosting. There is no implicit
180
- request to the studio's `/textures`, storage, account or API.
181
-
182
- `createRealWorldTerrain` accepts your provider's `loadHeightmap` and optional
183
- `loadImagery`. The `TerrariumProvider` adapter requires explicit tile URL
184
- functions, optionally injected fetch, and attribution. Its ordered bbox uses
185
- `west/east/south/north`, Web Mercator latitude limits and at most 6×6 tiles.
186
- Antimeridian bboxes must be split by the caller. No Leaflet or Overpass service
187
- is loaded. City/building queries remain application/provider responsibilities.
188
-
189
- ## Documents and exports
190
-
191
- ```js
192
- import { loadTerrainDocument } from 'procedural-terrains/documents';
193
- import { exportTerrain, zipTerrainExport } from 'procedural-terrains/export';
194
- const restored = await loadTerrainDocument(terrain.serialize(), { renderer });
195
- const result = await exportTerrain(terrain, {
196
- format: 'glb', meshRes: 128, texRes: 512,
197
- bakeColor: true, exportHeightmap: true,
198
- });
199
- const zipBytes = zipTerrainExport(result); // caller chooses how/where to save
200
- ```
201
-
202
- Exports return named byte arrays, filename and diagnostics without a download
203
- or filesystem side effect. GLB/OBJ and map baking share the studio's builders.
204
- Infinite exports require a bounded square `region: { cx, cz, size }` in world
205
- units. Planet exports cover all six faces. A detached terrain document is
206
- included; Mini presentation, water and clouds serialize as extensions. Borrowed
207
- GPU material/imagery assets must be reattached by the application after loading.
208
- Await GPU operations before starting another export or disposing borrowed assets.
209
-
210
- Configuration revisions supersede pending work. Cancellation rejects with
211
- `TERRAIN_CANCELLED`, replacement with `TERRAIN_SUPERSEDED`, destruction with
212
- `TERRAIN_DISPOSED`. GPU driver compilation itself cannot be interrupted; its
213
- retired candidates are disposed when it settles. Shader candidates publish only
214
- after validation. Cache/effect warm-up follows the synchronous configuration
215
- commit; if it fails, the committed configuration remains available and
216
- `prepare(camera)` can be retried. Do not assume a rejected warm-up rolls back
217
- a configuration already committed. `configuration` is immutable.
218
-
219
- ## Validation
220
-
221
- ```sh
222
- npm run check:lib
223
- npm test
224
- node --test tests/*.node.mjs
225
- npm run build
226
- npm ci --prefix examples/three-finite-terrain
227
- npm run build --prefix examples/three-finite-terrain
228
- npx playwright install chromium
229
- npm run test:lib:browser
230
- npm run test:lib:worlds
231
- ```
232
-
233
- The checks install the actual npm tarball in a clean consumer, import every ESM
234
- entry without DOM, compile strict TypeScript consumers, and exercise actual
235
- WebGL shaders, worlds, sources, effects, workers, PBR resources and exports.
236
- Browser checks can use `TERRAIN_BROWSER_PATH` for an installed Chromium binary.
237
- See `docs/npm-runtime-migration.md` in the repository for boundaries and migration.
1
+ # Procedural Terrains — Three.js runtime
2
+
3
+ An ESM library extracted from Terrain Studio 2.0.0. Finite, infinite, planetary
4
+ and Mini worlds reuse the studio's terrain geometry, noise, shaders and caches.
5
+ The package has no React, Electron, account, stylesheet or backend dependency.
6
+ Three.js `~0.185.1` is a peer dependency; `fflate` handles packed materials,
7
+ paint documents and ZIP exports. The runtime version follows the studio release; this source builds version 2.0.0.
8
+
9
+ ## Feature coverage and independent effects
10
+
11
+ The runtime does not contain every editor tool. See the [feature matrix](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/features.md), [water API](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/water.md), [cloud API](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/clouds.md), and [larger-world guide](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/large-worlds.md).
12
+
13
+ Water and clouds can be used around custom Three.js meshes without generating a terrain. Call createWater/createClouds with renderer and world, add each effect.object, pass effects to TerrainRenderPipeline and update them once per frame. Pass terrain instead to attach a layer managed by that terrain. Separate water/cloud/large-world playground templates are available in the studio documentation.
14
+
15
+ ## Install
16
+
17
+ ```sh
18
+ npm install procedural-terrains
19
+ ```
20
+
21
+ Use `three@~0.185.1` in your application (npm also installs this peer automatically). The package
22
+ contains ESM entry points, declarations, bundled Workers and the MIT license.
23
+ No studio files or material packs are copied into the package.
24
+
25
+ To build from source: `npm ci && npm run build` in the repository. An installable
26
+ archive is also produced in `dist/npm/`. See [release publishing](https://github.com/ZyFou/ProceduralTerrains/blob/develop/docs/package-publishing.md).
27
+
28
+ ## Use your own renderer and loop
29
+
30
+ ```js
31
+ import { createTerrain } from 'procedural-terrains';
32
+
33
+ const terrain = await createTerrain({ renderer, configuration: {
34
+ layout: { chunkCount: 8, chunkSize: 128 },
35
+ source: { kind: 'noise', seed: 1337, octaves: 7 },
36
+ heightScale: 560,
37
+ } });
38
+ scene.add(terrain.object);
39
+ await terrain.prepare(camera);
40
+
41
+ function frame(deltaSeconds) {
42
+ terrain.update(deltaSeconds, { camera });
43
+ renderer.render(scene, camera);
44
+ }
45
+ await terrain.configure({ source: { seed: 42 } });
46
+ const height = terrain.sampleHeight(0, 0);
47
+ const document = terrain.serialize();
48
+ terrain.dispose();
49
+ ```
50
+
51
+ The host owns the renderer, camera, scene, resize policy and animation loop.
52
+ Use an identity world transform for each terrain and its ancestors. Rendering
53
+ requires browser WebGL2; importing the modules and using data models does not
54
+ require DOM globals. CPU height samples approximate the GPU field and are not
55
+ exact triangle collision queries. Heights and dimensions are in world units.
56
+ The built-in shaders use their own sun/ambient lighting and display-encoded
57
+ colour; arbitrary scene lights and renderer tone mapping are not adopted.
58
+
59
+ ## Entry points
60
+
61
+ | Import | Public components |
62
+ | --- | --- |
63
+ | `procedural-terrains` | `createTerrain`, `FiniteTerrain` |
64
+ | `/infinite` | `createInfiniteTerrain` with camera-centred streaming and clipmaps |
65
+ | `/planet` | `createPlanetTerrain` with cube-sphere patches and height/climate bakes |
66
+ | `/mini` | `createMiniTerrain`, Mini state/layout/framing helpers |
67
+ | `/generation` | Noise Stack builders, graph compiler/document builders, manual document normalization |
68
+ | `/water` | `createWater`, `TerrainWater`, defaults/modes |
69
+ | `/clouds` | `createClouds`, `TerrainClouds`, defaults |
70
+ | `/render` | `TerrainRenderPipeline`, `TerrainPass`, optional height/detail caches |
71
+ | `/assets` | Explicit resource scopes, material providers, erosion/surface Workers |
72
+ | `/real-world` | `TerrariumProvider`, `createRealWorldTerrain` |
73
+ | `/export` | `exportTerrain`, `zipTerrainExport` |
74
+ | `/documents` | `loadTerrainDocument` |
75
+ | `/viewer` | Explicit DOM viewer with its own renderer, controls and loop |
76
+
77
+ All runtime instances implement `prepare`, `configure`, `update`, `serialize`,
78
+ `getDiagnostics` and idempotent `dispose`. Destruction releases owned resources
79
+ and detaches the group. It never destroys a borrowed renderer, imagery texture,
80
+ surface resource or `TerrainResources` scope. Shared resources remain alive
81
+ until their last lease is released. Dispose effects individually or with their
82
+ terrain; dispose pipelines separately.
83
+
84
+ ## World modes and sources
85
+
86
+ ```js
87
+ import { createInfiniteTerrain } from 'procedural-terrains/infinite';
88
+ import { createPlanetTerrain } from 'procedural-terrains/planet';
89
+ import { createMiniTerrain } from 'procedural-terrains/mini';
90
+
91
+ const infinite = await createInfiniteTerrain({ renderer, configuration: {
92
+ layout: { chunkSize: 128, viewRadius: 8, cacheResolution: 256 },
93
+ } });
94
+ const planet = await createPlanetTerrain({ renderer, configuration: {
95
+ layout: { radius: 16000, faceGrid: 8, bakeResolution: 256 },
96
+ } });
97
+ const mini = await createMiniTerrain({ renderer,
98
+ mini: { recipe: 'cove', seed: 1337, width: 1024, quality: 'balanced' },
99
+ backdrop: false,
100
+ });
101
+ await mini.mini.configure({ waterLevel: 0.6 });
102
+ const framing = mini.mini.framing(); // suggestion; does not move your camera
103
+ ```
104
+
105
+ Choose a world at construction. Create another instance when switching world
106
+ modes. Mini is a finite presentation: configure its managed relief, composition,
107
+ resolution and footprint through `terrain.mini.configure`. Water/cloud layers
108
+ are explicit opt-ins. Mini does not install editor controls, vegetation or a
109
+ studio background; `backdrop: true` enables its background.
110
+
111
+ Finite sources support `noise` (optional Noise Stack), `graph` (validated graph
112
+ document), `manual` (shapes/sculpt with flat, procedural or graph base) and
113
+ `heightmap` (`data`, `width`, `height`). Heightmaps cover the board, row zero at
114
+ negative Z, contain world-unit heights, and are uploaded as filtered half floats.
115
+ Infinite worlds support unbounded noise/2D graphs; planets require a Noise Stack
116
+ with 3D evaluation. Unsupported combinations fail explicitly. Source documents
117
+ are detached and frozen with the normalized configuration.
118
+
119
+ ```js
120
+ await terrain.configure({ source: {
121
+ kind: 'heightmap', width: 2, height: 2,
122
+ data: new Float32Array([0, 50, 120, 30]),
123
+ } });
124
+ ```
125
+
126
+ `sampleHeight` returns null outside finite boards; use `sampleHeight3D` with a
127
+ nonzero direction for planets. Planet samples return relief above the radius.
128
+ LOD resolutions must be four even values halving at each step. Mini uses the
129
+ studio's fixed 128/256/512 segment profiles instead. World-specific layout
130
+ options control streaming/triangle budgets and bake resolutions.
131
+
132
+ ## Water, clouds and scene composition
133
+
134
+ ```js
135
+ import { createWater } from 'procedural-terrains/water';
136
+ import { createClouds } from 'procedural-terrains/clouds';
137
+ import { TerrainRenderPipeline } from 'procedural-terrains/render';
138
+
139
+ const water = await createWater({ terrain, mode: 'volumetric' });
140
+ const clouds = await createClouds({ terrain, mode: 'realistic' });
141
+ const pipeline = new TerrainRenderPipeline({ renderer, terrains: [terrain] });
142
+ await terrain.prepare(camera);
143
+ function frame(dt) {
144
+ terrain.update(dt, { camera });
145
+ pipeline.render(scene, camera);
146
+ }
147
+ ```
148
+
149
+ The pipeline renders the **whole host scene** into its own colour/depth target,
150
+ captures water reflection/refraction when needed, composites clouds against
151
+ opaque depth in a distinct target, then applies underwater effects. This avoids
152
+ sampling an attached depth texture. It restores target, viewport, scissor,
153
+ clear state and XR/shadow flags. `TerrainPass` replaces `RenderPass` in an
154
+ EffectComposer; it is not an extra full-scene overlay after another RenderPass.
155
+
156
+ Water modes: `off`, `legacy`, `realistic`, `volumetric`, `cinematic`, `stylized`.
157
+ The existing world/quality fallback rules apply: inspect requested/effective
158
+ modes with `water.getDiagnostics()`. Clouds support `legacy` and `realistic` in
159
+ all world modes. Each terrain should have one water and one cloud layer.
160
+
161
+ Finite terrain rendering can run directly with `renderer.render`. Add
162
+ `createHeightCache({ terrain, resolution: 512 })` or
163
+ `createDetailCache({ terrain, quality: 2 })` when needed. Height caches retain
164
+ the studio's double buffering; detail caches own their worker and GPU pages.
165
+ Mini, planet and infinite adapters retain their existing specialized caches.
166
+
167
+ ## Materials and external data
168
+
169
+ ```js
170
+ import { TerrainSurfaceProvider, createSurfaceResources } from 'procedural-terrains/assets';
171
+ const provider = new TerrainSurfaceProvider({ baseUrl: 'https://your-host/material-pack/' });
172
+ const surface = await createSurfaceResources({ provider, document: surfaceDocument });
173
+ await terrain.setSurface(surface);
174
+ // After detaching from every terrain:
175
+ await terrain.setSurface(null);
176
+ surface.dispose();
177
+ provider.dispose();
178
+ ```
179
+
180
+ Host `catalog.json` and its `.pbr` files yourself. Catalog hashes and material
181
+ budgets are checked. Local assets use an injected `loadUserAsset`; historical
182
+ maps require an explicit `legacyBaseUrl`. `TerrainSurfaceWorker.prepare` accepts
183
+ serializable pack URLs/documents; `TerrainCompute.erode` uses a dedicated worker
184
+ per job, preserves caller buffers and returns additive `delta` plus erosion
185
+ maps. Inject worker factories for CSP/custom hosting. There is no implicit
186
+ request to the studio's `/textures`, storage, account or API.
187
+
188
+ `createRealWorldTerrain` accepts your provider's `loadHeightmap` and optional
189
+ `loadImagery`. The `TerrariumProvider` adapter requires explicit tile URL
190
+ functions, optionally injected fetch, and attribution. Its ordered bbox uses
191
+ `west/east/south/north`, Web Mercator latitude limits and at most 6×6 tiles.
192
+ Antimeridian bboxes must be split by the caller. No Leaflet or Overpass service
193
+ is loaded. City/building queries remain application/provider responsibilities.
194
+
195
+ ## Documents and exports
196
+
197
+ ```js
198
+ import { loadTerrainDocument } from 'procedural-terrains/documents';
199
+ import { exportTerrain, zipTerrainExport } from 'procedural-terrains/export';
200
+ const restored = await loadTerrainDocument(terrain.serialize(), { renderer });
201
+ const result = await exportTerrain(terrain, {
202
+ format: 'glb', meshRes: 128, texRes: 512,
203
+ bakeColor: true, exportHeightmap: true,
204
+ });
205
+ const zipBytes = zipTerrainExport(result); // caller chooses how/where to save
206
+ ```
207
+
208
+ Exports return named byte arrays, filename and diagnostics without a download
209
+ or filesystem side effect. GLB/OBJ and map baking share the studio's builders.
210
+ Infinite exports require a bounded square `region: { cx, cz, size }` in world
211
+ units. Planet exports cover all six faces. A detached terrain document is
212
+ included; Mini presentation, water and clouds serialize as extensions. Borrowed
213
+ GPU material/imagery assets must be reattached by the application after loading.
214
+ Await GPU operations before starting another export or disposing borrowed assets.
215
+
216
+ Configuration revisions supersede pending work. Cancellation rejects with
217
+ `TERRAIN_CANCELLED`, replacement with `TERRAIN_SUPERSEDED`, destruction with
218
+ `TERRAIN_DISPOSED`. GPU driver compilation itself cannot be interrupted; its
219
+ retired candidates are disposed when it settles. Shader candidates publish only
220
+ after validation. Cache/effect warm-up follows the synchronous configuration
221
+ commit; if it fails, the committed configuration remains available and
222
+ `prepare(camera)` can be retried. Do not assume a rejected warm-up rolls back
223
+ a configuration already committed. `configuration` is immutable.
224
+
225
+ ## Validation
226
+
227
+ ```sh
228
+ npm run check:lib
229
+ npm test
230
+ node --test tests/*.node.mjs
231
+ npm run build
232
+ npm ci --prefix examples/three-finite-terrain
233
+ npm run build --prefix examples/three-finite-terrain
234
+ npx playwright install chromium
235
+ npm run test:lib:browser
236
+ npm run test:lib:worlds
237
+ ```
238
+
239
+ The checks install the actual npm tarball in a clean consumer, import every ESM
240
+ entry without DOM, compile strict TypeScript consumers, and exercise actual
241
+ WebGL shaders, worlds, sources, effects, workers, PBR resources and exports.
242
+ Browser checks can use `TERRAIN_BROWSER_PATH` for an installed Chromium binary.
243
+ See `docs/npm-runtime-migration.md` in the repository for boundaries and migration.
@@ -1,5 +1,5 @@
1
1
  import * as THREE from "three";
2
- import { v as validatePrograms, p as programHealthError } from "./ProgramHealthGate-CDL2dmsa.js";
2
+ import { v as validatePrograms, p as programHealthError } from "./ProgramHealthGate-DS47bUo1.js";
3
3
  async function compileMaterial(renderer, material, camera, probe = null) {
4
4
  const geometry = probe?.geometry ?? new THREE.PlaneGeometry(2, 2);
5
5
  const mesh = probe?.mesh ?? new THREE.Mesh(geometry, material);
@@ -16,4 +16,4 @@ async function compileMaterial(renderer, material, camera, probe = null) {
16
16
  export {
17
17
  compileMaterial as c
18
18
  };
19
- //# sourceMappingURL=CompileMaterial-xRSfAPw7.js.map
19
+ //# sourceMappingURL=CompileMaterial-DZiWxNZC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompileMaterial-DZiWxNZC.js","sources":["../../../src/runtime/resources/CompileMaterial.js"],"sourcesContent":["import * as THREE from 'three';\nimport { validatePrograms, programHealthError } from '../../engine/render/ProgramHealthGate.js';\n\nexport async function compileMaterial(renderer, material, camera, probe = null) {\n const geometry = probe?.geometry ?? new THREE.PlaneGeometry(2, 2);\n const mesh = probe?.mesh ?? new THREE.Mesh(geometry, material);\n const scene = new THREE.Scene();\n scene.add(mesh);\n try {\n await renderer.compileAsync(scene, camera);\n const health = await validatePrograms({ renderer, materials: [material] });\n if (!health.ok) throw programHealthError(health);\n } finally {\n geometry.dispose();\n }\n}\n"],"names":[],"mappings":";;AAGO,eAAe,gBAAgB,UAAU,UAAU,QAAQ,QAAQ,MAAM;AAC9E,QAAM,WAAW,OAAO,YAAY,IAAI,MAAM,cAAc,GAAG,CAAC;AAChE,QAAM,OAAO,OAAO,QAAQ,IAAI,MAAM,KAAK,UAAU,QAAQ;AAC7D,QAAM,QAAQ,IAAI,MAAM,MAAK;AAC7B,QAAM,IAAI,IAAI;AACd,MAAI;AACF,UAAM,SAAS,aAAa,OAAO,MAAM;AACzC,UAAM,SAAS,MAAM,iBAAiB,EAAE,UAAU,WAAW,CAAC,QAAQ,GAAG;AACzE,QAAI,CAAC,OAAO,GAAI,OAAM,mBAAmB,MAAM;AAAA,EACjD,UAAC;AACC,aAAS,QAAO;AAAA,EAClB;AACF;"}