@jgengine/core 0.8.0 → 0.10.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 (303) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/ai/flock.d.ts +36 -0
  3. package/dist/ai/flock.js +182 -0
  4. package/dist/ai/groupAssist.d.ts +19 -0
  5. package/dist/ai/groupAssist.js +59 -0
  6. package/dist/ai/laneSelect.d.ts +21 -0
  7. package/dist/ai/laneSelect.js +37 -0
  8. package/dist/ai/mobBrain.d.ts +68 -0
  9. package/dist/ai/mobBrain.js +115 -0
  10. package/dist/ai/spawnDirector.d.ts +13 -0
  11. package/dist/ai/spawnDirector.js +41 -17
  12. package/dist/ai/spawnPoint.d.ts +5 -0
  13. package/dist/ai/spawnPoint.js +5 -0
  14. package/dist/ai/threat.d.ts +2 -0
  15. package/dist/ai/threat.js +34 -0
  16. package/dist/audio/audioFalloff.d.ts +5 -2
  17. package/dist/audio/music.d.ts +53 -0
  18. package/dist/audio/music.js +34 -0
  19. package/dist/audio/synth.d.ts +60 -0
  20. package/dist/audio/synth.js +8 -0
  21. package/dist/authoring.d.ts +14 -0
  22. package/dist/authoring.js +14 -0
  23. package/dist/cartridge/runtime.d.ts +15 -0
  24. package/dist/cartridge/runtime.js +556 -0
  25. package/dist/cartridge/spec.d.ts +188 -0
  26. package/dist/cartridge/spec.js +19 -0
  27. package/dist/cartridge/validate.d.ts +2 -0
  28. package/dist/cartridge/validate.js +78 -0
  29. package/dist/combat/abilityKit.d.ts +17 -2
  30. package/dist/combat/abilityKit.js +62 -13
  31. package/dist/combat/castRunner.d.ts +40 -0
  32. package/dist/combat/castRunner.js +56 -0
  33. package/dist/combat/comboPoints.d.ts +14 -0
  34. package/dist/combat/comboPoints.js +52 -0
  35. package/dist/combat/defensiveWindow.d.ts +1 -1
  36. package/dist/combat/defensiveWindow.js +5 -3
  37. package/dist/combat/dotField.d.ts +43 -0
  38. package/dist/combat/dotField.js +48 -0
  39. package/dist/combat/projectiles.d.ts +33 -12
  40. package/dist/combat/projectiles.js +214 -129
  41. package/dist/combat/regenShield.d.ts +35 -0
  42. package/dist/combat/regenShield.js +45 -0
  43. package/dist/combat/resistance.d.ts +16 -4
  44. package/dist/combat/resistance.js +43 -7
  45. package/dist/combat/resourcePool.d.ts +20 -0
  46. package/dist/combat/resourcePool.js +55 -0
  47. package/dist/combat/shotOrigin.d.ts +52 -0
  48. package/dist/combat/shotOrigin.js +86 -0
  49. package/dist/combat/telegraph.d.ts +25 -0
  50. package/dist/combat/telegraph.js +47 -0
  51. package/dist/crafting/recipe.js +4 -1
  52. package/dist/devtools/devtools.d.ts +72 -24
  53. package/dist/devtools/devtools.js +449 -101
  54. package/dist/devtools/transformTunables.js +3 -3
  55. package/dist/devtools/tunableSchema.d.ts +140 -0
  56. package/dist/devtools/tunableSchema.js +476 -0
  57. package/dist/editor/commands.d.ts +65 -0
  58. package/dist/editor/commands.js +193 -0
  59. package/dist/editor/document.d.ts +40 -0
  60. package/dist/editor/document.js +153 -0
  61. package/dist/editor/index.d.ts +30 -0
  62. package/dist/editor/index.js +6 -0
  63. package/dist/editor/types.d.ts +69 -0
  64. package/dist/editor/types.js +29 -0
  65. package/dist/faction/factions.d.ts +33 -0
  66. package/dist/faction/factions.js +76 -0
  67. package/dist/faction/reputation.d.ts +32 -0
  68. package/dist/faction/reputation.js +82 -0
  69. package/dist/game/chat.d.ts +2 -0
  70. package/dist/game/chat.js +9 -1
  71. package/dist/game/chatFilter.d.ts +15 -0
  72. package/dist/game/chatFilter.js +55 -0
  73. package/dist/game/connectedPlayers.d.ts +28 -0
  74. package/dist/game/connectedPlayers.js +21 -0
  75. package/dist/game/controlGate.d.ts +4 -0
  76. package/dist/game/controlGate.js +7 -0
  77. package/dist/game/defineGame.d.ts +44 -1
  78. package/dist/game/defineGame.js +1 -0
  79. package/dist/game/events.d.ts +25 -0
  80. package/dist/game/gamePhase.d.ts +20 -0
  81. package/dist/game/gamePhase.js +21 -0
  82. package/dist/game/keyValueStore.d.ts +25 -0
  83. package/dist/game/keyValueStore.js +61 -0
  84. package/dist/game/levelSequence.d.ts +24 -2
  85. package/dist/game/levelSequence.js +51 -2
  86. package/dist/game/lootTable.d.ts +14 -1
  87. package/dist/game/lootTable.js +28 -7
  88. package/dist/game/modelAnimation.d.ts +8 -0
  89. package/dist/game/modelAnimation.js +18 -0
  90. package/dist/game/playableGame.d.ts +116 -4
  91. package/dist/game/playableGame.js +1 -1
  92. package/dist/game/quest.d.ts +7 -3
  93. package/dist/game/quest.js +17 -8
  94. package/dist/game/race.d.ts +39 -1
  95. package/dist/game/race.js +96 -11
  96. package/dist/game/recordBook.d.ts +27 -0
  97. package/dist/game/recordBook.js +86 -0
  98. package/dist/game/talents.d.ts +47 -0
  99. package/dist/game/talents.js +140 -0
  100. package/dist/index.d.ts +8 -0
  101. package/dist/index.js +8 -0
  102. package/dist/input/actionBindings.d.ts +2 -0
  103. package/dist/input/actionBindings.js +1 -0
  104. package/dist/input/axisInput.d.ts +33 -3
  105. package/dist/input/axisInput.js +60 -4
  106. package/dist/input/bindingOverrides.d.ts +25 -0
  107. package/dist/input/bindingOverrides.js +95 -0
  108. package/dist/input/pointerAxis.d.ts +30 -0
  109. package/dist/input/pointerAxis.js +31 -0
  110. package/dist/input/touchScheme.d.ts +6 -0
  111. package/dist/input/touchScheme.js +45 -7
  112. package/dist/interaction/contextMenu.d.ts +1 -0
  113. package/dist/interaction/contextMenu.js +1 -0
  114. package/dist/interaction/proximityPrompt.d.ts +3 -1
  115. package/dist/interaction/proximityPrompt.js +3 -3
  116. package/dist/meta/changelog.d.ts +1 -1
  117. package/dist/meta/changelog.js +44 -1
  118. package/dist/movement/dash.d.ts +3 -0
  119. package/dist/movement/dash.js +19 -5
  120. package/dist/movement/glideModel.d.ts +44 -0
  121. package/dist/movement/glideModel.js +54 -0
  122. package/dist/movement/grappleSwing.d.ts +34 -0
  123. package/dist/movement/grappleSwing.js +56 -0
  124. package/dist/movement/leaderTrail.d.ts +29 -0
  125. package/dist/movement/leaderTrail.js +67 -0
  126. package/dist/movement/movementModel.d.ts +4 -0
  127. package/dist/movement/movementModel.js +13 -0
  128. package/dist/movement/playerMovement.d.ts +41 -0
  129. package/dist/movement/playerMovement.js +181 -0
  130. package/dist/movement/steering.d.ts +27 -0
  131. package/dist/movement/steering.js +40 -0
  132. package/dist/multiplayer/feedWriteGate.d.ts +10 -0
  133. package/dist/multiplayer/feedWriteGate.js +12 -0
  134. package/dist/multiplayer/presenceModel.d.ts +14 -2
  135. package/dist/multiplayer/presenceModel.js +15 -3
  136. package/dist/nav/corridors.d.ts +30 -0
  137. package/dist/nav/corridors.js +69 -0
  138. package/dist/nav/navGrid.js +30 -4
  139. package/dist/nav/railGraph.d.ts +66 -0
  140. package/dist/nav/railGraph.js +129 -0
  141. package/dist/nav/timetable.d.ts +41 -0
  142. package/dist/nav/timetable.js +94 -0
  143. package/dist/physics/buoyancy.d.ts +6 -0
  144. package/dist/physics/buoyancy.js +14 -0
  145. package/dist/physics/flowTube.d.ts +32 -0
  146. package/dist/physics/flowTube.js +64 -0
  147. package/dist/physics/forceVolume.d.ts +27 -0
  148. package/dist/physics/forceVolume.js +38 -0
  149. package/dist/physics/kinematicVehicle.d.ts +52 -0
  150. package/dist/physics/kinematicVehicle.js +81 -0
  151. package/dist/physics/physicsWorld.d.ts +13 -6
  152. package/dist/physics/physicsWorld.js +169 -40
  153. package/dist/physics/ragdoll.js +1 -1
  154. package/dist/physics/vehicleBody.js +2 -1
  155. package/dist/random/rng.d.ts +2 -0
  156. package/dist/random/rng.js +2 -0
  157. package/dist/random/seedLink.d.ts +5 -0
  158. package/dist/random/seedLink.js +35 -0
  159. package/dist/render/postProcessing.d.ts +56 -0
  160. package/dist/render/postProcessing.js +1 -0
  161. package/dist/runtime/adapter.d.ts +19 -0
  162. package/dist/runtime/adapter.js +11 -5
  163. package/dist/runtime/cameraDirector.d.ts +6 -1
  164. package/dist/runtime/cameraDirector.js +6 -0
  165. package/dist/runtime/commandRunner.d.ts +2 -2
  166. package/dist/runtime/commandRunner.js +2 -2
  167. package/dist/runtime/gameContext.d.ts +72 -8
  168. package/dist/runtime/gameContext.js +374 -61
  169. package/dist/runtime/gameRuntime.d.ts +5 -1
  170. package/dist/runtime/gameRuntime.js +13 -12
  171. package/dist/runtime/hostPersistence.d.ts +9 -1
  172. package/dist/runtime/hostPersistence.js +23 -8
  173. package/dist/runtime/hostedGameRunner.d.ts +49 -0
  174. package/dist/runtime/hostedGameRunner.js +62 -0
  175. package/dist/runtime/hostedWorldSession.d.ts +65 -0
  176. package/dist/runtime/hostedWorldSession.js +57 -0
  177. package/dist/runtime/inputSnapshot.d.ts +18 -0
  178. package/dist/runtime/inputSnapshot.js +7 -0
  179. package/dist/runtime/motionIntents.d.ts +16 -6
  180. package/dist/runtime/motionIntents.js +31 -2
  181. package/dist/runtime/snapshot.d.ts +1 -0
  182. package/dist/runtime/snapshot.js +1 -1
  183. package/dist/runtime/visibility.d.ts +74 -0
  184. package/dist/runtime/visibility.js +127 -0
  185. package/dist/runtime/worldChannel.d.ts +58 -0
  186. package/dist/runtime/worldChannel.js +69 -0
  187. package/dist/runtime/worldMirror.d.ts +24 -0
  188. package/dist/runtime/worldMirror.js +31 -0
  189. package/dist/runtime/worldReplication.d.ts +46 -0
  190. package/dist/runtime/worldReplication.js +185 -0
  191. package/dist/runtime/worldSnapshot.d.ts +17 -0
  192. package/dist/runtime/worldSnapshot.js +15 -0
  193. package/dist/scene/assetCatalog.d.ts +1 -0
  194. package/dist/scene/colliders.d.ts +50 -0
  195. package/dist/scene/colliders.js +101 -0
  196. package/dist/scene/entityStats.d.ts +4 -0
  197. package/dist/scene/entityStats.js +21 -0
  198. package/dist/scene/entityStore.d.ts +51 -5
  199. package/dist/scene/entityStore.js +119 -12
  200. package/dist/scene/objectQuery.d.ts +13 -2
  201. package/dist/scene/objectQuery.js +34 -2
  202. package/dist/scene/objectStore.d.ts +2 -0
  203. package/dist/scene/objectStore.js +31 -12
  204. package/dist/scene/sceneRaycast.d.ts +80 -0
  205. package/dist/scene/sceneRaycast.js +284 -0
  206. package/dist/scene/spatial.d.ts +11 -16
  207. package/dist/scene/spatial.js +99 -38
  208. package/dist/sensor/recordingBuffer.d.ts +6 -0
  209. package/dist/sensor/recordingBuffer.js +7 -0
  210. package/dist/sensor/replayLoop.d.ts +39 -0
  211. package/dist/sensor/replayLoop.js +64 -0
  212. package/dist/sensor/visionCone.d.ts +31 -0
  213. package/dist/sensor/visionCone.js +72 -0
  214. package/dist/session/extraction.d.ts +2 -2
  215. package/dist/session/extraction.js +13 -2
  216. package/dist/settings/settingsModel.d.ts +97 -0
  217. package/dist/settings/settingsModel.js +100 -0
  218. package/dist/stats/statModifiers.d.ts +5 -2
  219. package/dist/stats/statModifiers.js +32 -14
  220. package/dist/store/observableKeyedStore.d.ts +4 -0
  221. package/dist/store/observableKeyedStore.js +17 -2
  222. package/dist/survival/decayMeter.d.ts +1 -1
  223. package/dist/survival/decayMeter.js +0 -1
  224. package/dist/tactics/fallingGrid.d.ts +2 -2
  225. package/dist/tactics/fallingGrid.js +2 -2
  226. package/dist/time/beatClock.d.ts +18 -0
  227. package/dist/time/beatClock.js +24 -0
  228. package/dist/time/idleProgress.d.ts +29 -0
  229. package/dist/time/idleProgress.js +31 -0
  230. package/dist/time/serverTick.d.ts +7 -1
  231. package/dist/time/serverTick.js +27 -4
  232. package/dist/time/stateSchedule.d.ts +57 -0
  233. package/dist/time/stateSchedule.js +121 -0
  234. package/dist/turn/commit.d.ts +2 -2
  235. package/dist/turn/commit.js +2 -2
  236. package/dist/ui/gameLayout.d.ts +125 -0
  237. package/dist/ui/gameLayout.js +129 -0
  238. package/dist/ui/hudLayout.d.ts +58 -0
  239. package/dist/ui/hudLayout.js +207 -0
  240. package/dist/ui/hudScale.d.ts +44 -0
  241. package/dist/ui/hudScale.js +55 -0
  242. package/dist/ui/orientation.d.ts +39 -0
  243. package/dist/ui/orientation.js +49 -0
  244. package/dist/ui/swingTimer.d.ts +42 -0
  245. package/dist/ui/swingTimer.js +38 -0
  246. package/dist/visibility/assetStreaming.d.ts +66 -0
  247. package/dist/visibility/assetStreaming.js +201 -0
  248. package/dist/visibility/bounds.d.ts +66 -0
  249. package/dist/visibility/bounds.js +113 -0
  250. package/dist/visibility/camera.d.ts +21 -0
  251. package/dist/visibility/camera.js +3 -0
  252. package/dist/visibility/config.d.ts +21 -0
  253. package/dist/visibility/config.js +1 -0
  254. package/dist/visibility/diagnostics.d.ts +26 -0
  255. package/dist/visibility/diagnostics.js +36 -0
  256. package/dist/visibility/distance.d.ts +11 -0
  257. package/dist/visibility/distance.js +30 -0
  258. package/dist/visibility/frustum.d.ts +47 -0
  259. package/dist/visibility/frustum.js +186 -0
  260. package/dist/visibility/occlusion.d.ts +36 -0
  261. package/dist/visibility/occlusion.js +45 -0
  262. package/dist/visibility/settings.d.ts +75 -0
  263. package/dist/visibility/settings.js +49 -0
  264. package/dist/visibility/simulationCulling.d.ts +34 -0
  265. package/dist/visibility/simulationCulling.js +36 -0
  266. package/dist/visibility/spatialIndex.d.ts +45 -0
  267. package/dist/visibility/spatialIndex.js +212 -0
  268. package/dist/visibility/visibilitySystem.d.ts +90 -0
  269. package/dist/visibility/visibilitySystem.js +257 -0
  270. package/dist/world/buildings.d.ts +6 -0
  271. package/dist/world/buildings.js +152 -0
  272. package/dist/world/carve.d.ts +7 -2
  273. package/dist/world/carve.js +17 -7
  274. package/dist/world/cellStates.d.ts +45 -0
  275. package/dist/world/cellStates.js +103 -0
  276. package/dist/world/environmentSummary.d.ts +21 -4
  277. package/dist/world/environmentSummary.js +22 -3
  278. package/dist/world/features.d.ts +185 -8
  279. package/dist/world/features.js +64 -6
  280. package/dist/world/gridInstances.d.ts +7 -8
  281. package/dist/world/gridInstances.js +145 -7
  282. package/dist/world/lod.d.ts +17 -0
  283. package/dist/world/lod.js +66 -0
  284. package/dist/world/mapLayers.d.ts +60 -0
  285. package/dist/world/mapLayers.js +44 -0
  286. package/dist/world/massing.d.ts +45 -0
  287. package/dist/world/massing.js +581 -0
  288. package/dist/world/minimap.d.ts +13 -1
  289. package/dist/world/minimap.js +21 -2
  290. package/dist/world/roads.d.ts +47 -0
  291. package/dist/world/roads.js +146 -0
  292. package/dist/world/streets.d.ts +80 -0
  293. package/dist/world/streets.js +144 -0
  294. package/dist/world/terrain.d.ts +69 -3
  295. package/dist/world/terrain.js +309 -16
  296. package/dist/world/water.d.ts +7 -0
  297. package/dist/world/water.js +19 -4
  298. package/dist/world/weather.d.ts +3 -18
  299. package/dist/world/weather.js +4 -17
  300. package/dist/world/windZones.d.ts +47 -0
  301. package/dist/world/windZones.js +59 -0
  302. package/llms.txt +3013 -1726
  303. package/package.json +12 -2
@@ -1,16 +1,48 @@
1
+ import type { BuildingPaletteOverrides, BuildingStyle } from "./buildings.js";
1
2
  export interface WorldBounds {
2
3
  w: number;
3
4
  d: number;
4
5
  }
6
+ export type TerrainMaterial = "grass" | "sand" | "snow" | "rock" | "ash" | "highland" | "slate";
5
7
  export type EnvironmentVec2 = readonly [number, number];
6
8
  export interface EnvironmentArea extends WorldBounds {
7
9
  h?: number;
10
+ /** World-space center of the area; default `[0, 0]` (the world origin). Sites a weather/vegetation band away from the origin, like `building()`/`ocean()` `position`. */
11
+ position?: EnvironmentVec2;
8
12
  }
9
13
  export interface TerrainColors {
10
14
  low?: string;
11
15
  high?: string;
12
16
  waterline?: string;
13
17
  }
18
+ /**
19
+ * Procedural detail-surface layer for terrain: a noise-driven shader that keeps the
20
+ * biome-tinted base ground (from `colors`/`biomeBands`) and blends distinct rock,
21
+ * sand, and snow over it by slope, height, and waterline — turning a flat
22
+ * vertex-colour surface into varied, textured-reading ground with no image assets.
23
+ */
24
+ export interface TerrainDetailConfig {
25
+ /** Steep-slope rock colour. Default "#6f7175". */
26
+ rockColor?: string;
27
+ /** Waterline/beach sand colour. Default "#c2b283". */
28
+ sandColor?: string;
29
+ /** High-altitude snow colour. Default "#eef3f7". */
30
+ snowColor?: string;
31
+ /** Slope (0 flat … 1 vertical) at which rock starts taking over. Default 0.42. */
32
+ rockSlopeStart?: number;
33
+ /** World height above which snow appears. Default 26. */
34
+ snowHeight?: number;
35
+ /** Water level for the sand band; defaults to the terrain's `waterLevel`. */
36
+ waterLevel?: number;
37
+ /** Fine detail noise wavelength in world units. Default 5. */
38
+ detailScale?: number;
39
+ /** Large-scale colour-variation wavelength in world units. Default 45. */
40
+ macroScale?: number;
41
+ /** Surface roughness of the detail material. Default 0.9. */
42
+ roughness?: number;
43
+ /** Overall detail intensity 0..1. Default 1. */
44
+ strength?: number;
45
+ }
14
46
  export interface TerrainFlattenMask {
15
47
  center: EnvironmentVec2;
16
48
  radius: number;
@@ -19,14 +51,77 @@ export interface TerrainFlattenMask {
19
51
  /** Extra blend-ring width outside `radius` where the flat height smoothsteps back to the noise value; default `radius * 0.5`. */
20
52
  falloff?: number;
21
53
  }
54
+ /** Palette and blend fields shared by every `TerrainMaterialRegion` shape. */
55
+ export interface TerrainRegionStyle {
56
+ /** Named palette preset for this region (see `TERRAIN_MATERIAL_PALETTES` in `world/terrain`); overridden field-by-field by `colors`. */
57
+ material?: TerrainMaterial;
58
+ colors?: TerrainColors;
59
+ /** Blend-ring width outside the region core back to the surrounding palette; default: half the region's characteristic size. */
60
+ falloff?: number;
61
+ }
62
+ /** A circular palette zone painted over the base terrain palette — snow caps, ash wastes, spawn circles. */
63
+ export interface TerrainCircleRegion extends TerrainRegionStyle {
64
+ shape?: "circle";
65
+ center: EnvironmentVec2;
66
+ radius: number;
67
+ }
68
+ /** A ribbon palette zone following a centerline — roads and rivers, instead of chaining overlapping circles. */
69
+ export interface TerrainPolylineRegion extends TerrainRegionStyle {
70
+ shape: "polyline";
71
+ /** Centerline vertices in world XZ; needs at least two points. */
72
+ points: readonly EnvironmentVec2[];
73
+ /** Full ribbon width; the painted core extends `width / 2` either side of the centerline. `falloff` defaults to `width * 0.5`. */
74
+ width: number;
75
+ }
76
+ /** A rectangular palette zone, optionally rotated about the world y axis — plazas, fields, districts. */
77
+ export interface TerrainRectRegion extends TerrainRegionStyle {
78
+ shape: "rect";
79
+ center: EnvironmentVec2;
80
+ /** Half-extents along the region's local x and z before rotation. `falloff` defaults to half the smaller extent. */
81
+ halfExtents: EnvironmentVec2;
82
+ /** Rotation about the world y axis in radians; default 0. */
83
+ rotationY?: number;
84
+ }
85
+ /**
86
+ * A palette zone painted over the base terrain palette. Circle (the default when no `shape` is given),
87
+ * `polyline` ribbons for roads/rivers, and rotatable `rect` districts all paint fully inside their core
88
+ * and blend back across `falloff`; later regions in the list win overlaps.
89
+ */
90
+ export type TerrainMaterialRegion = TerrainCircleRegion | TerrainPolylineRegion | TerrainRectRegion;
91
+ /**
92
+ * A z-ordered ground palette zone — the linear-boundary counterpart to the radial `materialRegions`.
93
+ * Adjacent bands cross-fade into each other across a `fade`-wide window centered on the midpoint z
94
+ * between their centers, so a multi-biome world (vale → marsh → peaks along z) blends its ground
95
+ * color instead of hard-switching. Order the list by ascending `z`.
96
+ */
97
+ export interface BiomeBand {
98
+ /** World-space center z of the zone. */
99
+ z: number;
100
+ /** Cross-fade window width straddling the boundary to the next band. Default 64. */
101
+ fade?: number;
102
+ /** Named palette preset for the zone (see `TERRAIN_MATERIAL_PALETTES`); overridden field-by-field by `colors`. */
103
+ material?: TerrainMaterial;
104
+ /** Explicit low/high/waterline hex colors for the zone. */
105
+ colors?: TerrainColors;
106
+ }
22
107
  export interface TerrainEnvironmentConfig {
23
108
  bounds?: WorldBounds;
24
109
  height?: number;
25
110
  heightMap?: string;
111
+ /**
112
+ * Game-supplied height function replacing the built-in noise field — banded biomes, ridge walls,
113
+ * terracing, anything expressible as `(x, z) => y`. `flatten` masks still carve into it, and both
114
+ * the rendered ground and `ctx.world.ground` sample it. A function doesn't serialize; keep it pure.
115
+ */
116
+ heightField?: (x: number, z: number) => number;
26
117
  /** Named palette preset (see `TERRAIN_MATERIAL_PALETTES` in `world/terrain`); default "grass". Overridden field-by-field by `colors`. */
27
- material?: string;
118
+ material?: TerrainMaterial;
28
119
  /** Explicit low/high/waterline hex colors; any field left unset falls back to the resolved `material` preset. */
29
120
  colors?: TerrainColors;
121
+ /** Palette zones blended over the base `material`/`colors` for multi-biome readability. */
122
+ materialRegions?: readonly TerrainMaterialRegion[];
123
+ /** Ordered z-banded ground palettes that cross-fade along the world's z axis (vale → marsh → peaks). Painted under `materialRegions`. */
124
+ biomeBands?: readonly BiomeBand[];
30
125
  segments?: number;
31
126
  seed?: string;
32
127
  frequency?: number;
@@ -36,9 +131,13 @@ export interface TerrainEnvironmentConfig {
36
131
  waterLevel?: number;
37
132
  /** Flat pads carved into the noise field, e.g. for building pads or spawn circles. */
38
133
  flatten?: readonly TerrainFlattenMask[];
134
+ /** Procedural detail surface (noise-driven rock/sand/snow over the biome base). Omit for the flat vertex-colour ground. */
135
+ detail?: TerrainDetailConfig;
39
136
  }
40
137
  export interface RainEnvironmentConfig {
41
138
  area?: EnvironmentArea;
139
+ /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`, letting a biome zone site its own weather away from the origin. */
140
+ position?: EnvironmentVec2;
42
141
  density?: number;
43
142
  speed?: number;
44
143
  dropLength?: number;
@@ -47,6 +146,8 @@ export interface RainEnvironmentConfig {
47
146
  }
48
147
  export interface SnowEnvironmentConfig {
49
148
  area?: EnvironmentArea;
149
+ /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`, letting a biome zone site its own weather away from the origin. */
150
+ position?: EnvironmentVec2;
50
151
  density?: number;
51
152
  speed?: number;
52
153
  flakeSize?: number;
@@ -55,7 +156,9 @@ export interface SnowEnvironmentConfig {
55
156
  color?: string;
56
157
  }
57
158
  export interface GrassEnvironmentConfig {
58
- area?: WorldBounds;
159
+ area?: EnvironmentArea;
160
+ /** World-space center `[x, z]` of the band, matching `building()`/`ocean()` — sugar for `area.position`, letting a biome zone site its own vegetation away from the origin. */
161
+ position?: EnvironmentVec2;
59
162
  density?: number;
60
163
  bladeHeight?: readonly [number, number];
61
164
  bladeWidth?: number;
@@ -67,7 +170,15 @@ export interface OceanEnvironmentConfig {
67
170
  bounds?: WorldBounds;
68
171
  position?: EnvironmentVec2;
69
172
  level?: number;
173
+ /**
174
+ * Scheduled water level as a function of game-time seconds — tides, floods, draining chambers.
175
+ * Wins over `level` (which stays the initial/static value); `waterSurfaceFromDescriptor` bakes it
176
+ * into `WaterSurface.height`, and the shell repositions the rendered ocean from it every frame.
177
+ * A function doesn't serialize; keep it pure and deterministic (compose with `time/stateSchedule`).
178
+ */
179
+ levelAt?: (time: number) => number;
70
180
  waveHeight?: number;
181
+ /** Primary Gerstner wavelength in world units (shared with shell Ocean `waveScale`; default 18). */
71
182
  waveScale?: number;
72
183
  waveSpeed?: number;
73
184
  color?: string;
@@ -94,7 +205,10 @@ export interface BuildingEnvironmentConfig {
94
205
  stories?: readonly [number, number];
95
206
  storyHeight?: number;
96
207
  spacing?: number;
97
- style?: string;
208
+ /** Named palette archetype (see `BUILDING_STYLE_PALETTES` in `world/buildings`); default "generic". Overridden part-by-part by `palette`. */
209
+ style?: BuildingStyle;
210
+ /** Explicit per-part-kind hex colors; any part left unset falls back to the resolved `style` palette. */
211
+ palette?: BuildingPaletteOverrides;
98
212
  seed?: string;
99
213
  }
100
214
  export type PadSize = readonly [number, number] | {
@@ -103,8 +217,10 @@ export type PadSize = readonly [number, number] | {
103
217
  export interface PadEnvironmentConfig {
104
218
  center: EnvironmentVec2;
105
219
  size: PadSize;
106
- /** Surface offset above the terrain height at `center`; default `0.05` — just proud of the ground. */
220
+ /** Surface offset above the terrain height at `center`; default `0.05` — just proud of the ground. Ignored when `elevation` is set. */
107
221
  height?: number;
222
+ /** Absolute world-space Y for the pad surface — a landing pad on a rooftop, a floating platform. Skips the implicit terrain flatten (there's no ground to flatten toward). */
223
+ elevation?: number;
108
224
  color?: string;
109
225
  /** Rotation applied to rectangular pads; ignored for circular pads. */
110
226
  rotationY?: number;
@@ -112,6 +228,15 @@ export interface PadEnvironmentConfig {
112
228
  export type TerrainEnvironmentDescriptor = {
113
229
  kind: "terrain";
114
230
  } & Required<Pick<TerrainEnvironmentConfig, "bounds" | "height">> & Omit<TerrainEnvironmentConfig, "bounds" | "height">;
231
+ /** A bounded terrain patch floating at its own altitude — sky islands, arena platforms, split landmasses with void between. */
232
+ export interface TerrainIslandConfig extends TerrainEnvironmentConfig {
233
+ /** World-space center of the island; its `bounds` rect surrounds this point. */
234
+ origin: EnvironmentVec2;
235
+ }
236
+ export type TerrainIslandDescriptor = Omit<TerrainEnvironmentDescriptor, "kind"> & {
237
+ kind: "island";
238
+ origin: EnvironmentVec2;
239
+ };
115
240
  export type RainEnvironmentDescriptor = {
116
241
  kind: "rain";
117
242
  } & Required<Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color">>;
@@ -123,16 +248,46 @@ export type GrassEnvironmentDescriptor = {
123
248
  } & Required<Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors">> & Pick<GrassEnvironmentConfig, "seed">;
124
249
  export type OceanEnvironmentDescriptor = {
125
250
  kind: "ocean";
126
- } & Required<Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color">> & Pick<OceanEnvironmentConfig, "position">;
251
+ } & Required<Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color">> & Pick<OceanEnvironmentConfig, "position" | "levelAt">;
127
252
  export type BuildingEnvironmentDescriptor = {
128
253
  kind: "building";
129
- } & Required<Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style">> & Pick<BuildingEnvironmentConfig, "seed" | "position">;
254
+ } & Required<Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style">> & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette">;
130
255
  export type PadEnvironmentDescriptor = {
131
256
  kind: "pad";
132
- } & Required<Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color">> & Pick<PadEnvironmentConfig, "rotationY">;
257
+ } & Required<Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color">> & Pick<PadEnvironmentConfig, "rotationY" | "elevation">;
133
258
  export type SkyEnvironmentDescriptor = {
134
259
  kind: "sky";
135
260
  } & Required<Pick<SkyEnvironmentConfig, "preset" | "timeOfDay">> & Omit<SkyEnvironmentConfig, "preset" | "timeOfDay">;
261
+ /** Config for {@link road}: a flat asphalt ribbon draped over the terrain along a centerline. */
262
+ export interface RoadEnvironmentConfig {
263
+ /** Centerline vertices in world XZ; at least two points. */
264
+ path: readonly (readonly [number, number])[];
265
+ /** Ribbon width in world units. Default 8. */
266
+ width?: number;
267
+ /** Asphalt color. Default "#3b3e47". */
268
+ color?: string;
269
+ /** Paint a dashed centerline. Default true. */
270
+ markings?: boolean;
271
+ /** Centerline dash color. Default "#e8c74a". */
272
+ markingColor?: string;
273
+ /** Lift above the terrain to avoid z-fighting; stagger overlapping roads. Default 0.08. */
274
+ elevation?: number;
275
+ /** Sidewalk bands on both edges; `false` for none. Default `{ width: 2.6, color: "#a7adb8" }`. */
276
+ sidewalk?: {
277
+ width?: number;
278
+ color?: string;
279
+ } | false;
280
+ }
281
+ /** Resolved road descriptor produced by {@link road} and rendered by the shell environment scene. */
282
+ export type RoadEnvironmentDescriptor = {
283
+ kind: "road";
284
+ } & Required<Pick<RoadEnvironmentConfig, "path" | "width" | "color" | "markings" | "markingColor" | "elevation">> & {
285
+ /** Resolved sidewalk band, or `false` when the road has none. */
286
+ sidewalk: {
287
+ width: number;
288
+ color: string;
289
+ } | false;
290
+ };
136
291
  export type WeatherEnvironmentDescriptor = RainEnvironmentDescriptor | SnowEnvironmentDescriptor;
137
292
  export type VegetationEnvironmentDescriptor = GrassEnvironmentDescriptor;
138
293
  export type WaterEnvironmentDescriptor = OceanEnvironmentDescriptor;
@@ -140,22 +295,28 @@ export type StructureEnvironmentDescriptor = BuildingEnvironmentDescriptor;
140
295
  export type EnvironmentDescriptorList<T> = T | readonly T[];
141
296
  export interface EnvironmentWorldConfig {
142
297
  terrain?: TerrainEnvironmentDescriptor;
298
+ /** Disconnected landmasses at independent altitudes over the base `terrain` (or over void without one) — see `island()`. */
299
+ islands?: readonly TerrainIslandDescriptor[];
143
300
  sky?: SkyEnvironmentDescriptor;
144
301
  weather?: EnvironmentDescriptorList<WeatherEnvironmentDescriptor>;
145
302
  vegetation?: EnvironmentDescriptorList<VegetationEnvironmentDescriptor>;
146
303
  water?: EnvironmentDescriptorList<WaterEnvironmentDescriptor>;
147
304
  structures?: EnvironmentDescriptorList<StructureEnvironmentDescriptor>;
305
+ /** Road ribbons draped over the terrain — see `road()`. */
306
+ roads?: EnvironmentDescriptorList<RoadEnvironmentDescriptor>;
148
307
  /** Ground pads, e.g. platforms or paved patches; each implicitly flattens the terrain beneath it. */
149
308
  pads?: readonly PadEnvironmentDescriptor[];
150
309
  }
151
310
  export interface EnvironmentWorldFeature {
152
311
  kind: "environment";
153
312
  terrain?: TerrainEnvironmentDescriptor;
313
+ islands?: readonly TerrainIslandDescriptor[];
154
314
  sky?: SkyEnvironmentDescriptor;
155
315
  weather?: readonly WeatherEnvironmentDescriptor[];
156
316
  vegetation?: readonly VegetationEnvironmentDescriptor[];
157
317
  water?: readonly WaterEnvironmentDescriptor[];
158
318
  structures?: readonly StructureEnvironmentDescriptor[];
319
+ roads?: readonly RoadEnvironmentDescriptor[];
159
320
  pads?: readonly PadEnvironmentDescriptor[];
160
321
  }
161
322
  export interface WorldGridCell {
@@ -195,6 +356,7 @@ export interface PlotsWorldConfig extends WorldGridConfig {
195
356
  export interface TilemapWorldConfig extends WorldGridConfig {
196
357
  map: string;
197
358
  }
359
+ /** A declared world shape — biomes, voxel grid, plots, tilemap, environment, or flat — passed to `defineGame`. */
198
360
  export type WorldFeature = ({
199
361
  kind: "biomes";
200
362
  } & BiomesWorldConfig) | ({
@@ -206,19 +368,34 @@ export type WorldFeature = ({
206
368
  } & TilemapWorldConfig) | EnvironmentWorldFeature | {
207
369
  kind: "flat";
208
370
  };
209
- /** Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it. */
371
+ /** Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it. Elevated pads (absolute `elevation`) float free and carve nothing. */
210
372
  export declare function padFlattenMasks(pads: readonly PadEnvironmentDescriptor[]): readonly TerrainFlattenMask[];
373
+ /** Composes an `environment()` world feature from terrain, sky, weather, vegetation, water, structures, roads, and pads. */
211
374
  export declare function environment(config?: EnvironmentWorldConfig): EnvironmentWorldFeature;
375
+ /** Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks. */
212
376
  export declare function terrain(config?: TerrainEnvironmentConfig): TerrainEnvironmentDescriptor;
213
377
  export declare function sky(config?: SkyEnvironmentConfig): SkyEnvironmentDescriptor;
378
+ /** Declares a rainfall weather effect for `environment()` — area, density, speed, and wind. */
214
379
  export declare function rain(config?: RainEnvironmentConfig): RainEnvironmentDescriptor;
380
+ /** Declares a snowfall weather effect for `environment()` — area, density, drift, and wind. */
215
381
  export declare function snow(config?: SnowEnvironmentConfig): SnowEnvironmentDescriptor;
382
+ /** Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors. */
216
383
  export declare function grass(config?: GrassEnvironmentConfig): GrassEnvironmentDescriptor;
384
+ /** Declares an ocean water body for `environment()` — bounds, level, and wave tuning. */
217
385
  export declare function ocean(config?: OceanEnvironmentConfig): OceanEnvironmentDescriptor;
386
+ /** Declare a road ribbon for an `environment()` world; the shell drapes and renders it over the terrain. */
387
+ export declare function road(config: RoadEnvironmentConfig): RoadEnvironmentDescriptor;
388
+ export declare function island(config: TerrainIslandConfig): TerrainIslandDescriptor;
389
+ /** Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. */
218
390
  export declare function building(config?: BuildingEnvironmentConfig): BuildingEnvironmentDescriptor;
219
391
  export declare function pad(config: PadEnvironmentConfig): PadEnvironmentDescriptor;
392
+ /** Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain. */
220
393
  export declare function biomes(config: BiomesWorldConfig): WorldFeature;
394
+ /** Declares a voxel-grid world for block-based games. */
221
395
  export declare function voxel(config: VoxelWorldConfig): WorldFeature;
396
+ /** Declares a subdivided-plots world — farming, base-building, and other parcel-based layouts. */
222
397
  export declare function plots(config?: PlotsWorldConfig): WorldFeature;
398
+ /** Declares a 2D tilemap world from a map string. */
223
399
  export declare function tilemap(config: TilemapWorldConfig): WorldFeature;
400
+ /** Declares an empty flat world — the minimal `WorldFeature` for games with no terrain of their own. */
224
401
  export declare function flat(): WorldFeature;
@@ -7,9 +7,11 @@ function list(value) {
7
7
  function withOptional(base, optional) {
8
8
  return optional === undefined ? base : { ...base, ...optional };
9
9
  }
10
- /** Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it. */
10
+ /** Derives implicit `TerrainFlattenMask`s carving each pad's footprint into the terrain beneath it. Elevated pads (absolute `elevation`) float free and carve nothing. */
11
11
  export function padFlattenMasks(pads) {
12
- return pads.map((padDescriptor) => ({
12
+ return pads
13
+ .filter((padDescriptor) => padDescriptor.elevation === undefined)
14
+ .map((padDescriptor) => ({
13
15
  center: padDescriptor.center,
14
16
  radius: padHalfExtent(padDescriptor.size) * 1.2,
15
17
  }));
@@ -25,32 +27,46 @@ function withPadFlatten(terrainDescriptor, pads) {
25
27
  flatten: [...(terrainDescriptor.flatten ?? []), ...padFlattenMasks(pads)],
26
28
  };
27
29
  }
30
+ /** Composes an `environment()` world feature from terrain, sky, weather, vegetation, water, structures, roads, and pads. */
28
31
  export function environment(config = {}) {
29
32
  const weather = list(config.weather);
30
33
  const vegetation = list(config.vegetation);
31
34
  const water = list(config.water);
32
35
  const structures = list(config.structures);
36
+ const roads = list(config.roads);
33
37
  const terrainDescriptor = withPadFlatten(config.terrain, config.pads);
34
38
  return {
35
39
  kind: "environment",
36
40
  ...(terrainDescriptor === undefined ? {} : { terrain: terrainDescriptor }),
41
+ ...(config.islands === undefined || config.islands.length === 0 ? {} : { islands: config.islands }),
37
42
  ...(config.sky === undefined ? {} : { sky: config.sky }),
38
43
  ...(weather === undefined ? {} : { weather }),
39
44
  ...(vegetation === undefined ? {} : { vegetation }),
40
45
  ...(water === undefined ? {} : { water }),
41
46
  ...(structures === undefined ? {} : { structures }),
47
+ ...(roads === undefined ? {} : { roads }),
42
48
  ...(config.pads === undefined ? {} : { pads: config.pads }),
43
49
  };
44
50
  }
51
+ /** Declares a heightfield terrain patch for `environment()` — bounds, noise, materials, and flatten masks. */
45
52
  export function terrain(config = {}) {
53
+ if (config.baseHeight !== undefined &&
54
+ config.height === undefined &&
55
+ config.heightField === undefined &&
56
+ typeof console !== "undefined") {
57
+ console.warn("[jgengine:terrain] baseHeight is set but height is not — height is the noise amplitude (defaulting to 0 here), so this terrain is a flat plateau at baseHeight. Set height explicitly (height: 0 for an intentional plateau) to silence this.");
58
+ }
46
59
  return withOptional({
47
60
  kind: "terrain",
48
61
  bounds: config.bounds ?? { w: 512, d: 512 },
49
62
  height: config.height ?? 0,
50
63
  }, {
51
64
  ...(config.heightMap === undefined ? {} : { heightMap: config.heightMap }),
65
+ ...(config.heightField === undefined ? {} : { heightField: config.heightField }),
52
66
  ...(config.material === undefined ? {} : { material: config.material }),
53
67
  ...(config.colors === undefined ? {} : { colors: config.colors }),
68
+ ...(config.materialRegions === undefined ? {} : { materialRegions: config.materialRegions }),
69
+ ...(config.biomeBands === undefined ? {} : { biomeBands: config.biomeBands }),
54
70
  ...(config.segments === undefined ? {} : { segments: config.segments }),
55
71
  ...(config.seed === undefined ? {} : { seed: config.seed }),
56
72
  ...(config.frequency === undefined ? {} : { frequency: config.frequency }),
@@ -59,6 +75,7 @@ export function terrain(config = {}) {
59
75
  ...(config.baseHeight === undefined ? {} : { baseHeight: config.baseHeight }),
60
76
  ...(config.waterLevel === undefined ? {} : { waterLevel: config.waterLevel }),
61
77
  ...(config.flatten === undefined ? {} : { flatten: config.flatten }),
78
+ ...(config.detail === undefined ? {} : { detail: config.detail }),
62
79
  });
63
80
  }
64
81
  export function sky(config = {}) {
@@ -74,10 +91,14 @@ export function sky(config = {}) {
74
91
  ...(config.fog === undefined ? {} : { fog: config.fog }),
75
92
  });
76
93
  }
94
+ function withAreaPosition(area, position) {
95
+ return position !== undefined && area.position === undefined ? { ...area, position } : area;
96
+ }
97
+ /** Declares a rainfall weather effect for `environment()` — area, density, speed, and wind. */
77
98
  export function rain(config = {}) {
78
99
  return {
79
100
  kind: "rain",
80
- area: config.area ?? { w: 256, d: 256, h: 80 },
101
+ area: withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position),
81
102
  density: config.density ?? 0.65,
82
103
  speed: config.speed ?? 18,
83
104
  dropLength: config.dropLength ?? 0.8,
@@ -85,10 +106,11 @@ export function rain(config = {}) {
85
106
  color: config.color ?? "#9ec8ff",
86
107
  };
87
108
  }
109
+ /** Declares a snowfall weather effect for `environment()` — area, density, drift, and wind. */
88
110
  export function snow(config = {}) {
89
111
  return {
90
112
  kind: "snow",
91
- area: config.area ?? { w: 256, d: 256, h: 80 },
113
+ area: withAreaPosition(config.area ?? { w: 256, d: 256, h: 80 }, config.position),
92
114
  density: config.density ?? 0.35,
93
115
  speed: config.speed ?? 2.4,
94
116
  flakeSize: config.flakeSize ?? 0.08,
@@ -97,10 +119,11 @@ export function snow(config = {}) {
97
119
  color: config.color ?? "#ffffff",
98
120
  };
99
121
  }
122
+ /** Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors. */
100
123
  export function grass(config = {}) {
101
124
  return withOptional({
102
125
  kind: "grass",
103
- area: config.area ?? { w: 128, d: 128 },
126
+ area: withAreaPosition(config.area ?? { w: 128, d: 128 }, config.position),
104
127
  density: config.density ?? 4,
105
128
  bladeHeight: config.bladeHeight ?? [0.25, 0.9],
106
129
  bladeWidth: config.bladeWidth ?? 0.035,
@@ -108,6 +131,7 @@ export function grass(config = {}) {
108
131
  colors: config.colors ?? ["#3f7d2d", "#66a83f"],
109
132
  }, config.seed === undefined ? undefined : { seed: config.seed });
110
133
  }
134
+ /** Declares an ocean water body for `environment()` — bounds, level, and wave tuning. */
111
135
  export function ocean(config = {}) {
112
136
  return {
113
137
  kind: "ocean",
@@ -118,8 +142,33 @@ export function ocean(config = {}) {
118
142
  waveSpeed: config.waveSpeed ?? 0.55,
119
143
  color: config.color ?? "#1d7fa3",
120
144
  ...(config.position === undefined ? {} : { position: config.position }),
145
+ ...(config.levelAt === undefined ? {} : { levelAt: config.levelAt }),
121
146
  };
122
147
  }
148
+ /** Declare a road ribbon for an `environment()` world; the shell drapes and renders it over the terrain. */
149
+ export function road(config) {
150
+ if (config.path.length < 2) {
151
+ throw new Error("road: path needs at least two points");
152
+ }
153
+ return {
154
+ kind: "road",
155
+ path: config.path,
156
+ width: config.width ?? 8,
157
+ color: config.color ?? "#3b3e47",
158
+ markings: config.markings ?? true,
159
+ markingColor: config.markingColor ?? "#e8c74a",
160
+ elevation: config.elevation ?? 0.08,
161
+ sidewalk: config.sidewalk === false
162
+ ? false
163
+ : { width: config.sidewalk?.width ?? 2.6, color: config.sidewalk?.color ?? "#a7adb8" },
164
+ };
165
+ }
166
+ export function island(config) {
167
+ const { origin, ...terrainConfig } = config;
168
+ const { kind: _kind, ...descriptor } = terrain(terrainConfig);
169
+ return { ...descriptor, kind: "island", origin };
170
+ }
171
+ /** Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. */
123
172
  export function building(config = {}) {
124
173
  return withOptional({
125
174
  kind: "building",
@@ -132,6 +181,7 @@ export function building(config = {}) {
132
181
  }, {
133
182
  ...(config.seed === undefined ? {} : { seed: config.seed }),
134
183
  ...(config.position === undefined ? {} : { position: config.position }),
184
+ ...(config.palette === undefined ? {} : { palette: config.palette }),
135
185
  });
136
186
  }
137
187
  export function pad(config) {
@@ -141,20 +191,28 @@ export function pad(config) {
141
191
  size: config.size,
142
192
  height: config.height ?? 0.05,
143
193
  color: config.color ?? "#8b8680",
144
- }, config.rotationY === undefined ? undefined : { rotationY: config.rotationY });
194
+ }, {
195
+ ...(config.rotationY === undefined ? {} : { rotationY: config.rotationY }),
196
+ ...(config.elevation === undefined ? {} : { elevation: config.elevation }),
197
+ });
145
198
  }
199
+ /** Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain. */
146
200
  export function biomes(config) {
147
201
  return { kind: "biomes", ...config };
148
202
  }
203
+ /** Declares a voxel-grid world for block-based games. */
149
204
  export function voxel(config) {
150
205
  return { kind: "voxel", ...config };
151
206
  }
207
+ /** Declares a subdivided-plots world — farming, base-building, and other parcel-based layouts. */
152
208
  export function plots(config = {}) {
153
209
  return { kind: "plots", ...config };
154
210
  }
211
+ /** Declares a 2D tilemap world from a map string. */
155
212
  export function tilemap(config) {
156
213
  return { kind: "tilemap", ...config };
157
214
  }
215
+ /** Declares an empty flat world — the minimal `WorldFeature` for games with no terrain of their own. */
158
216
  export function flat() {
159
217
  return { kind: "flat" };
160
218
  }
@@ -1,13 +1,12 @@
1
- import type { WorldGridConfig } from "./features.js";
1
+ import type { WorldFeature, WorldGridCell, WorldGridConfig } from "./features.js";
2
2
  export interface GridInstanceTransform {
3
3
  position: readonly [number, number, number];
4
4
  scale: readonly [number, number, number];
5
5
  color: string;
6
6
  }
7
- /**
8
- * Pure cell→instance math for `biomes()`/`voxel()`/`plots()`/`tilemap()` world features: one
9
- * extruded box per declared cell, grounded at y=0 and centered on its cell in x/z. Consumed by
10
- * the shell's grid-world renderer so it can drive a single `THREE.InstancedMesh` without
11
- * duplicating this math per game.
12
- */
13
- export declare function resolveGridInstances(config: WorldGridConfig): readonly GridInstanceTransform[];
7
+ type GridWorldFeature = Extract<WorldFeature, {
8
+ kind: "biomes" | "voxel" | "plots" | "tilemap";
9
+ }>;
10
+ export declare function resolveGridCells(config: WorldGridConfig | GridWorldFeature): readonly WorldGridCell[];
11
+ export declare function resolveGridInstances(config: WorldGridConfig | GridWorldFeature): readonly GridInstanceTransform[];
12
+ export {};