@jgengine/shell 0.10.0 → 0.12.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 (286) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/CombatPresentation.d.ts +5 -0
  5. package/dist/CombatPresentation.js +8 -0
  6. package/dist/GameHost.d.ts +25 -1
  7. package/dist/GameHost.js +60 -4
  8. package/dist/GamePhaseStamp.d.ts +1 -0
  9. package/dist/GamePhaseStamp.js +9 -0
  10. package/dist/GamePlayer.d.ts +5 -0
  11. package/dist/GamePlayer.js +5 -0
  12. package/dist/GamePlayerShell.d.ts +5 -12
  13. package/dist/GamePlayerShell.js +67 -1332
  14. package/dist/GameUiPreview.js +3 -2
  15. package/dist/Shell3dPresentation.d.ts +63 -0
  16. package/dist/Shell3dPresentation.js +302 -0
  17. package/dist/ShellChrome.d.ts +51 -0
  18. package/dist/ShellChrome.js +51 -0
  19. package/dist/ShellHudPresentation.d.ts +41 -0
  20. package/dist/ShellHudPresentation.js +22 -0
  21. package/dist/audio/audioEngine.d.ts +4 -0
  22. package/dist/audio/audioEngine.js +128 -21
  23. package/dist/audio/audioWire.d.ts +40 -0
  24. package/dist/audio/audioWire.js +62 -0
  25. package/dist/audio/loopParams.d.ts +20 -0
  26. package/dist/audio/loopParams.js +28 -0
  27. package/dist/behaviour.d.ts +2 -1
  28. package/dist/behaviour.js +2 -1
  29. package/dist/behaviourAttach.d.ts +1 -0
  30. package/dist/behaviourAttach.js +1 -0
  31. package/dist/behaviourDriver.d.ts +1 -0
  32. package/dist/behaviourDriver.js +1 -0
  33. package/dist/boundActionDispatch.d.ts +13 -0
  34. package/dist/boundActionDispatch.js +37 -0
  35. package/dist/camera/GameCameraRig.d.ts +5 -2
  36. package/dist/camera/GameCameraRig.js +8 -3
  37. package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
  38. package/dist/camera/GameFirstPersonCamera.js +8 -3
  39. package/dist/camera/GameInspectionCamera.d.ts +1 -1
  40. package/dist/camera/GameInspectionCamera.js +2 -2
  41. package/dist/camera/GameOrbitCamera.js +24 -9
  42. package/dist/camera/cameraBlendMath.d.ts +3 -0
  43. package/dist/camera/cameraBlendMath.js +3 -0
  44. package/dist/camera/cameraRigs.d.ts +3 -1
  45. package/dist/camera/cameraRigs.js +21 -3
  46. package/dist/camera/fovPreference.d.ts +6 -1
  47. package/dist/camera/fovPreference.js +6 -1
  48. package/dist/camera/index.d.ts +4 -7
  49. package/dist/camera/index.js +4 -7
  50. package/dist/camera/inspectionCameraMath.d.ts +7 -2
  51. package/dist/camera/inspectionCameraMath.js +7 -2
  52. package/dist/camera/orbitCameraMath.d.ts +36 -6
  53. package/dist/camera/orbitCameraMath.js +56 -6
  54. package/dist/camera/rigMath.d.ts +114 -24
  55. package/dist/camera/rigMath.js +129 -24
  56. package/dist/camera/rigResolve.d.ts +4 -2
  57. package/dist/camera/rigResolve.js +4 -2
  58. package/dist/camera/shakeChannel.d.ts +6 -2
  59. package/dist/camera/shakeChannel.js +6 -2
  60. package/dist/camera/shakeChannelMath.d.ts +1 -0
  61. package/dist/camera/shakeChannelMath.js +1 -0
  62. package/dist/commandSink.d.ts +8 -3
  63. package/dist/commandSink.js +8 -3
  64. package/dist/defineGame.d.ts +15 -1
  65. package/dist/defineGame.js +50 -9
  66. package/dist/devtools/ColPanel.d.ts +1 -0
  67. package/dist/devtools/ColPanel.js +14 -0
  68. package/dist/devtools/DevtoolsOverlay.d.ts +11 -7
  69. package/dist/devtools/DevtoolsOverlay.js +47 -462
  70. package/dist/devtools/KeysPanel.d.ts +4 -0
  71. package/dist/devtools/KeysPanel.js +31 -0
  72. package/dist/devtools/LogsPanel.d.ts +1 -0
  73. package/dist/devtools/LogsPanel.js +12 -0
  74. package/dist/devtools/NetPanel.d.ts +4 -0
  75. package/dist/devtools/NetPanel.js +10 -0
  76. package/dist/devtools/PerfPanel.d.ts +4 -0
  77. package/dist/devtools/PerfPanel.js +53 -0
  78. package/dist/devtools/TunePanel.d.ts +3 -0
  79. package/dist/devtools/TunePanel.js +309 -0
  80. package/dist/devtools/agentBridge.d.ts +41 -0
  81. package/dist/devtools/agentBridge.js +266 -0
  82. package/dist/devtools/collisionDebug.d.ts +6 -0
  83. package/dist/devtools/collisionDebug.js +6 -0
  84. package/dist/devtools/collisionDebugMath.d.ts +8 -2
  85. package/dist/devtools/collisionDebugMath.js +24 -5
  86. package/dist/devtools/devtoolsOverrides.d.ts +6 -0
  87. package/dist/devtools/devtoolsOverrides.js +48 -0
  88. package/dist/devtools/panelAtoms.d.ts +9 -0
  89. package/dist/devtools/panelAtoms.js +10 -0
  90. package/dist/devtools/perfDiagnose.d.ts +2 -0
  91. package/dist/devtools/perfDiagnose.js +43 -0
  92. package/dist/diagnostics/RuntimeDiagnostics.d.ts +36 -0
  93. package/dist/diagnostics/RuntimeDiagnostics.js +80 -0
  94. package/dist/drivers/FrameDriver.d.ts +37 -0
  95. package/dist/drivers/FrameDriver.js +232 -0
  96. package/dist/drivers/HudOnlyDriver.d.ts +16 -0
  97. package/dist/drivers/HudOnlyDriver.js +60 -0
  98. package/dist/environment/Daylight.d.ts +23 -7
  99. package/dist/environment/Daylight.js +106 -13
  100. package/dist/environment/EnvironmentScene.js +44 -9
  101. package/dist/environment/VolumetricClouds.d.ts +17 -0
  102. package/dist/environment/VolumetricClouds.js +202 -0
  103. package/dist/environment/daylightCycle.d.ts +3 -1
  104. package/dist/environment/daylightCycle.js +3 -1
  105. package/dist/environment/groundPadMath.d.ts +3 -0
  106. package/dist/environment/groundPadMath.js +3 -0
  107. package/dist/environment/index.d.ts +1 -0
  108. package/dist/environment/index.js +1 -0
  109. package/dist/environment/skyLightingPolicy.d.ts +2 -0
  110. package/dist/environment/skyLightingPolicy.js +2 -0
  111. package/dist/environment/terrainGroundColor.d.ts +9 -0
  112. package/dist/environment/terrainGroundColor.js +22 -0
  113. package/dist/gameKit.d.ts +27 -0
  114. package/dist/gameKit.js +29 -0
  115. package/dist/hotbarActions.d.ts +26 -0
  116. package/dist/hotbarActions.js +27 -0
  117. package/dist/inputSink.d.ts +16 -4
  118. package/dist/inputSink.js +57 -7
  119. package/dist/map/MapMarkerBeacons.d.ts +3 -2
  120. package/dist/materialOverride.d.ts +10 -0
  121. package/dist/materialOverride.js +15 -3
  122. package/dist/multiplayer.js +8 -2
  123. package/dist/postfx/PostProcessing.d.ts +9 -1
  124. package/dist/postfx/PostProcessing.js +56 -11
  125. package/dist/postfx/gradeShader.js +9 -1
  126. package/dist/presentationResolve.d.ts +35 -0
  127. package/dist/presentationResolve.js +51 -0
  128. package/dist/registry.d.ts +4 -2
  129. package/dist/render/EnvironmentLighting.d.ts +10 -0
  130. package/dist/render/EnvironmentLighting.js +34 -0
  131. package/dist/render/SceneLighting.d.ts +7 -0
  132. package/dist/render/SceneLighting.js +18 -0
  133. package/dist/render/SceneModels.d.ts +14 -0
  134. package/dist/render/SceneModels.js +337 -0
  135. package/dist/render/assetBase.d.ts +17 -0
  136. package/dist/render/assetBase.js +35 -0
  137. package/dist/render/defaultSurface.d.ts +29 -0
  138. package/dist/render/defaultSurface.js +101 -0
  139. package/dist/render/modelLoad.d.ts +24 -0
  140. package/dist/render/modelLoad.js +76 -0
  141. package/dist/render/modelRender.d.ts +11 -0
  142. package/dist/render/modelRender.js +15 -0
  143. package/dist/render/resolveModel.d.ts +54 -3
  144. package/dist/render/resolveModel.js +116 -4
  145. package/dist/render/useEntityRenderCues.d.ts +13 -0
  146. package/dist/render/useEntityRenderCues.js +62 -0
  147. package/dist/scatter/InstancedScatter.d.ts +24 -0
  148. package/dist/scatter/InstancedScatter.js +135 -0
  149. package/dist/scatter/scatterModels.d.ts +25 -0
  150. package/dist/scatter/scatterModels.js +61 -0
  151. package/dist/scatter/scatterProxies.d.ts +6 -0
  152. package/dist/scatter/scatterProxies.js +118 -0
  153. package/dist/scatter.d.ts +1 -0
  154. package/dist/scatter.js +1 -0
  155. package/dist/scene/AuthoredScene.d.ts +84 -0
  156. package/dist/scene/AuthoredScene.js +178 -0
  157. package/dist/scene/CityRenderer.d.ts +2 -0
  158. package/dist/scene/CityRenderer.js +1031 -0
  159. package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
  160. package/dist/scene/GeneratedAssetRenderer.js +59 -0
  161. package/dist/scene/GrassFieldRenderer.d.ts +2 -0
  162. package/dist/scene/GrassFieldRenderer.js +73 -0
  163. package/dist/scene/PoleLineRenderer.d.ts +2 -0
  164. package/dist/scene/PoleLineRenderer.js +287 -0
  165. package/dist/scene/SoilPatchRenderer.d.ts +2 -0
  166. package/dist/scene/SoilPatchRenderer.js +84 -0
  167. package/dist/scene/StudioStage.d.ts +37 -0
  168. package/dist/scene/StudioStage.js +42 -0
  169. package/dist/scene/WaterRenderer.d.ts +2 -0
  170. package/dist/scene/WaterRenderer.js +61 -0
  171. package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
  172. package/dist/scene/builtinSceneKindRenderers.js +26 -0
  173. package/dist/scene/cityWindowMaterial.d.ts +16 -0
  174. package/dist/scene/cityWindowMaterial.js +81 -0
  175. package/dist/scene/sceneKindRenderers.d.ts +30 -0
  176. package/dist/scene/sceneKindRenderers.js +17 -0
  177. package/dist/scene.d.ts +1 -0
  178. package/dist/scene.js +1 -0
  179. package/dist/settings/appliedSettings.d.ts +7 -1
  180. package/dist/settings/appliedSettings.js +13 -2
  181. package/dist/settings/settingsController.d.ts +2 -0
  182. package/dist/settings/settingsController.js +22 -1
  183. package/dist/shellConstants.d.ts +4 -0
  184. package/dist/shellConstants.js +4 -0
  185. package/dist/shellMovement.d.ts +8 -0
  186. package/dist/shellMovement.js +11 -0
  187. package/dist/shellPointer.d.ts +20 -0
  188. package/dist/shellPointer.js +28 -0
  189. package/dist/structures/PlacementGhost.d.ts +4 -0
  190. package/dist/structures/PlacementGhost.js +4 -0
  191. package/dist/structures/TransformGizmo.d.ts +53 -0
  192. package/dist/structures/TransformGizmo.js +59 -0
  193. package/dist/structures/index.d.ts +1 -0
  194. package/dist/structures/index.js +1 -0
  195. package/dist/terrain/GrassField.d.ts +11 -3
  196. package/dist/terrain/GrassField.js +16 -6
  197. package/dist/terrain/TerraformBrushCursor.js +3 -0
  198. package/dist/terrain/grassBudget.d.ts +11 -2
  199. package/dist/terrain/grassBudget.js +20 -4
  200. package/dist/terrain/grassGeometry.d.ts +35 -0
  201. package/dist/terrain/grassGeometry.js +85 -20
  202. package/dist/terrain/grassMaterial.d.ts +20 -0
  203. package/dist/terrain/grassMaterial.js +68 -13
  204. package/dist/terrain/heightfieldGeometry.d.ts +34 -0
  205. package/dist/terrain/heightfieldGeometry.js +109 -0
  206. package/dist/terrain/index.d.ts +1 -0
  207. package/dist/terrain/index.js +1 -0
  208. package/dist/terrain/random.d.ts +3 -0
  209. package/dist/terrain/random.js +3 -0
  210. package/dist/terrain/soilPatchMaterial.d.ts +23 -0
  211. package/dist/terrain/soilPatchMaterial.js +147 -0
  212. package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
  213. package/dist/terrain/terrainDetailMaterial.js +87 -7
  214. package/dist/terrain/terrainMath.d.ts +8 -1
  215. package/dist/terrain/terrainMath.js +8 -1
  216. package/dist/touch/TouchControlsOverlay.d.ts +9 -5
  217. package/dist/touch/TouchControlsOverlay.js +201 -22
  218. package/dist/useShellMultiplayerSync.d.ts +9 -0
  219. package/dist/useShellMultiplayerSync.js +98 -0
  220. package/dist/visibility/CullingProvider.js +1 -1
  221. package/dist/water/Ocean.d.ts +7 -1
  222. package/dist/water/Ocean.js +16 -3
  223. package/dist/water/OceanConfig.d.ts +11 -0
  224. package/dist/water/OceanConfig.js +8 -0
  225. package/dist/water/OceanMaterial.d.ts +12 -0
  226. package/dist/water/OceanMaterial.js +9 -0
  227. package/dist/water/OceanShader.d.ts +2 -2
  228. package/dist/water/OceanShader.js +78 -10
  229. package/dist/weather/fireSpreadPose.d.ts +1 -0
  230. package/dist/weather/fireSpreadPose.js +1 -0
  231. package/dist/weather/weatherGeometry.d.ts +1 -0
  232. package/dist/weather/weatherGeometry.js +1 -0
  233. package/dist/weather/weatherMath.d.ts +3 -0
  234. package/dist/weather/weatherMath.js +3 -0
  235. package/dist/weather/weatherUniforms.d.ts +3 -0
  236. package/dist/weather/weatherUniforms.js +3 -0
  237. package/dist/world/PlaceScene.d.ts +11 -0
  238. package/dist/world/PlaceScene.js +27 -0
  239. package/dist/world/RetainedVfx.d.ts +10 -0
  240. package/dist/world/RetainedVfx.js +136 -0
  241. package/dist/world/WorldHud.d.ts +49 -2
  242. package/dist/world/WorldHud.js +87 -2
  243. package/dist/world/WorldScene.d.ts +21 -0
  244. package/dist/world/WorldScene.js +186 -0
  245. package/dist/world/WorldVfx.d.ts +9 -0
  246. package/dist/world/WorldVfx.js +184 -0
  247. package/dist/world/entityPose.d.ts +2 -0
  248. package/dist/world/entityPose.js +2 -0
  249. package/dist/world/floatTextStyle.d.ts +1 -0
  250. package/dist/world/floatTextStyle.js +1 -0
  251. package/dist/world/telegraphPulse.d.ts +1 -0
  252. package/dist/world/telegraphPulse.js +1 -0
  253. package/dist/world/worldBarSamples.d.ts +25 -0
  254. package/dist/world/worldBarSamples.js +38 -0
  255. package/dist/worldSky.d.ts +11 -0
  256. package/dist/worldSky.js +21 -0
  257. package/dist/worldSync.d.ts +2 -1
  258. package/dist/worldSync.js +2 -1
  259. package/package.json +6 -6
  260. package/skills/game-design/SKILL.md +28 -0
  261. package/skills/game-design/agents/openai.yaml +4 -0
  262. package/skills/game-design/references/application-playbook.md +170 -0
  263. package/skills/game-design/references/field-guide.md +288 -0
  264. package/skills/jgengine/SKILL.md +54 -0
  265. package/skills/jgengine/api.md +527 -0
  266. package/skills/jgengine/capabilities.md +131 -0
  267. package/skills/jgengine/recipes/minimal-game.md +88 -0
  268. package/skills/jgengine-ui/SKILL.md +41 -0
  269. package/skills/jgengine-ui/api.md +2007 -0
  270. package/skills/jgengine-ui/capabilities.md +211 -0
  271. package/skills/jgengine-ui/recipes/portable-minimap.md +150 -0
  272. package/skills/jgengine-ui/reference.md +513 -0
  273. package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
  274. package/skills/jgengine-world/SKILL.md +51 -0
  275. package/skills/jgengine-world/api.md +3056 -0
  276. package/skills/jgengine-world/capabilities.md +476 -0
  277. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  278. package/skills/jgengine-world/reference.md +261 -0
  279. package/skills/level-design/SKILL.md +54 -0
  280. package/skills/level-design/agents/openai.yaml +4 -0
  281. package/skills/level-design/references/application-playbook.md +192 -0
  282. package/skills/level-design/references/field-guide.md +337 -0
  283. package/skills/level-design/references/live-editor-loop.md +179 -0
  284. package/dist/cartridge.d.ts +0 -145
  285. package/dist/cartridge.js +0 -246
  286. package/llms.txt +0 -2761
@@ -0,0 +1,118 @@
1
+ import * as THREE from "three";
2
+ const BARK = "#5b4127";
3
+ const LEAF = "#3f6b30";
4
+ const PINE = "#2f5330";
5
+ const OAK = "#4a7a37";
6
+ const BUSH = "#4d7d3a";
7
+ const ROCK = "#82858c";
8
+ const GRASS = "#5f9a3c";
9
+ const PALM_BARK = "#8a7355";
10
+ const PALM_FROND = "#4c8b3d";
11
+ const CYPRESS = "#31502f";
12
+ /** Concatenates part geometries into one vertex-colored buffer (position + normal + color). */
13
+ function mergeParts(parts) {
14
+ const geos = parts.map((part) => (part.geometry.index === null ? part.geometry : part.geometry.toNonIndexed()));
15
+ let total = 0;
16
+ for (const geo of geos)
17
+ total += geo.attributes.position.count;
18
+ const position = new Float32Array(total * 3);
19
+ const normal = new Float32Array(total * 3);
20
+ const color = new Float32Array(total * 3);
21
+ const tint = new THREE.Color();
22
+ let offset = 0;
23
+ for (let i = 0; i < geos.length; i += 1) {
24
+ const geo = geos[i];
25
+ const pos = geo.attributes.position;
26
+ const nor = geo.attributes.normal;
27
+ position.set(pos.array, offset * 3);
28
+ normal.set(nor.array, offset * 3);
29
+ tint.set(parts[i].color);
30
+ for (let v = 0; v < pos.count; v += 1) {
31
+ color[(offset + v) * 3] = tint.r;
32
+ color[(offset + v) * 3 + 1] = tint.g;
33
+ color[(offset + v) * 3 + 2] = tint.b;
34
+ }
35
+ offset += pos.count;
36
+ }
37
+ for (const geo of geos)
38
+ geo.dispose();
39
+ const merged = new THREE.BufferGeometry();
40
+ merged.setAttribute("position", new THREE.BufferAttribute(position, 3));
41
+ merged.setAttribute("normal", new THREE.BufferAttribute(normal, 3));
42
+ merged.setAttribute("color", new THREE.BufferAttribute(color, 3));
43
+ merged.computeBoundingSphere();
44
+ return merged;
45
+ }
46
+ function trunk(height, radius) {
47
+ const geo = new THREE.CylinderGeometry(radius * 0.8, radius, height, 5);
48
+ geo.translate(0, height / 2, 0);
49
+ return geo;
50
+ }
51
+ function cone(radius, height, y, segments = 7) {
52
+ const geo = new THREE.ConeGeometry(radius, height, segments);
53
+ geo.translate(0, y + height / 2, 0);
54
+ return geo;
55
+ }
56
+ function sphere(radius, y, squash = 1) {
57
+ const geo = new THREE.IcosahedronGeometry(radius, 1);
58
+ geo.scale(1, squash, 1);
59
+ geo.translate(0, y, 0);
60
+ return geo;
61
+ }
62
+ const BUILDERS = {
63
+ tree: () => mergeParts([
64
+ { geometry: trunk(1.1, 0.12), color: BARK },
65
+ { geometry: cone(0.8, 1.7, 0.9), color: LEAF },
66
+ ]),
67
+ pine: () => mergeParts([
68
+ { geometry: trunk(0.9, 0.1), color: BARK },
69
+ { geometry: cone(0.7, 1.0, 0.7), color: PINE },
70
+ { geometry: cone(0.55, 0.9, 1.35), color: PINE },
71
+ { geometry: cone(0.38, 0.8, 1.95), color: PINE },
72
+ ]),
73
+ oak: () => mergeParts([
74
+ { geometry: trunk(1.0, 0.14), color: BARK },
75
+ { geometry: sphere(0.85, 1.55, 0.85), color: OAK },
76
+ ]),
77
+ bush: () => mergeParts([{ geometry: sphere(0.55, 0.45, 0.8), color: BUSH }]),
78
+ shrub: () => mergeParts([{ geometry: sphere(0.5, 0.4, 0.75), color: BUSH }]),
79
+ rock: () => mergeParts([{ geometry: sphere(0.5, 0.28, 0.7), color: ROCK }]),
80
+ stone: () => mergeParts([{ geometry: sphere(0.4, 0.22, 0.65), color: ROCK }]),
81
+ grass: () => mergeParts([
82
+ { geometry: cone(0.09, 0.7, 0), color: GRASS },
83
+ { geometry: cone(0.08, 0.55, 0).translate(0.12, 0, 0.05), color: GRASS },
84
+ { geometry: cone(0.08, 0.6, 0).translate(-0.1, 0, -0.06), color: GRASS },
85
+ ]),
86
+ palm: () => {
87
+ // Tall bare trunk with a radial crown of drooping fronds — each frond a flattened cone laid
88
+ // near-horizontal, tips sagging below the crown.
89
+ const parts = [{ geometry: trunk(2.6, 0.09), color: PALM_BARK }];
90
+ for (let i = 0; i < 6; i += 1) {
91
+ const yaw = (i / 6) * Math.PI * 2;
92
+ const frond = new THREE.ConeGeometry(0.16, 1.35, 4);
93
+ frond.scale(1, 1, 0.35);
94
+ frond.rotateX(-Math.PI / 2 - 0.5);
95
+ frond.rotateY(yaw);
96
+ frond.translate(Math.sin(yaw) * 0.32, 2.62, Math.cos(yaw) * 0.32);
97
+ parts.push({ geometry: frond, color: PALM_FROND });
98
+ }
99
+ parts.push({ geometry: sphere(0.14, 2.56), color: PALM_BARK });
100
+ return mergeParts(parts);
101
+ },
102
+ cypress: () => mergeParts([
103
+ { geometry: trunk(0.5, 0.07), color: BARK },
104
+ { geometry: cone(0.34, 2.5, 0.35, 6), color: CYPRESS },
105
+ { geometry: cone(0.2, 0.7, 2.75, 5), color: CYPRESS },
106
+ ]),
107
+ };
108
+ function defaultProxy() {
109
+ return mergeParts([{ geometry: cone(0.35, 1.2, 0), color: GRASS }]);
110
+ }
111
+ /**
112
+ * Builds the merged proxy geometry for a scatter item id, memoized per builder call by the caller.
113
+ * @internal — the geometry catalog behind the `InstancedScatter` renderer.
114
+ */
115
+ export function buildScatterProxy(item) {
116
+ const builder = BUILDERS[item];
117
+ return builder === undefined ? defaultProxy() : builder();
118
+ }
@@ -0,0 +1 @@
1
+ export * from "./scatter/InstancedScatter.js";
@@ -0,0 +1 @@
1
+ export * from "./scatter/InstancedScatter.js";
@@ -0,0 +1,84 @@
1
+ import type { EditorDocument } from "@jgengine/core/editor/index";
2
+ import type { ModelConfig } from "@jgengine/core/game/playableGame";
3
+ import type { AssetCatalog } from "@jgengine/core/scene/assetCatalog";
4
+ import type { TerrainField } from "@jgengine/core/world/terrain";
5
+ /**
6
+ * Resolves the document AuthoredScene renders: when a {@link getDocumentLiveSync} bus is
7
+ * installed (editor host live), subscribe to document patches; otherwise use the prop.
8
+ * Document is authoritative — runtime overrides never land here unless written back.
9
+ * @internal
10
+ */
11
+ export declare function useLiveEditorDocument(document: EditorDocument, live?: boolean): EditorDocument;
12
+ /** Props for {@link AuthoredPaths}: the document, the ground field to drape over, and a kind filter. */
13
+ export interface AuthoredPathsProps {
14
+ document: EditorDocument;
15
+ field: TerrainField;
16
+ /** Only render these path kinds; default renders every non-scatter path. */
17
+ kinds?: readonly string[];
18
+ }
19
+ /**
20
+ * Renders a document's non-scatter paths (roads, routes, corridors) as ground-draped ribbons — the
21
+ * editor authors the polyline, the engine drapes it over the live terrain at runtime. Width comes
22
+ * from `path.width`, color from `path.meta.color`/`path.color`. A game never hand-rolls path meshes.
23
+ */
24
+ export declare function AuthoredPaths({ document, field, kinds }: AuthoredPathsProps): import("react").JSX.Element;
25
+ /** Props for {@link AuthoredObjects}: document, ground field, and optional lift / onExisting. */
26
+ export interface AuthoredObjectsProps {
27
+ document: EditorDocument;
28
+ field: TerrainField;
29
+ /** Extra lift in meters on top of each marker's own verticalOffset (default 0). */
30
+ verticalOffset?: number;
31
+ /**
32
+ * How to treat instance ids already in the object store. Default `"keep"` so an onInit
33
+ * `placeAuthoredObjects` call wins and remounts stay remount-safe.
34
+ */
35
+ onExisting?: "throw" | "replace" | "keep";
36
+ }
37
+ /**
38
+ * Places every editor marker with a catalog id into `ctx.scene.object`, grounded on `field`.
39
+ * WorldScene renders them through the game's `objectModels` seam — no bespoke place loop. Pure
40
+ * headless twin: `resolveAuthoredObjects` / `placeAuthoredObjects`.
41
+ */
42
+ export declare function AuthoredObjects({ document, field, verticalOffset, onExisting, }: AuthoredObjectsProps): null;
43
+ /** Props for {@link AuthoredScene}: the document to render and the ground field to drape/ground on. */
44
+ export interface AuthoredSceneProps {
45
+ document: EditorDocument;
46
+ field: TerrainField;
47
+ /** Restrict rendered path kinds; default renders every non-scatter path. */
48
+ pathKinds?: readonly string[];
49
+ /**
50
+ * Scatter palette item id → model asset id or `ModelConfig`; a mapped item GPU-instances the real
51
+ * catalog GLB instead of the stylized proxy. Keyed by scatter `item` (not entity name — pass a
52
+ * dedicated map even if it shares entries with `entityModels`). Requires `assets`.
53
+ */
54
+ scatterModels?: Record<string, string | ModelConfig>;
55
+ /** Catalog `scatterModels` string ids resolve through; required together with `scatterModels`. */
56
+ assets?: AssetCatalog;
57
+ /**
58
+ * When true (default), subscribe to the global document live-sync bus if the editor host is
59
+ * mounted so headless/RPC document patches hot-apply without a full reload. Pass false to pin
60
+ * the `document` prop (tests, one-shot previews).
61
+ */
62
+ live?: boolean;
63
+ /**
64
+ * Place the document's catalog-id markers into the object
65
+ * store — WorldScene renders them via the game's `objectModels` seam. Omit when the game places
66
+ * props itself in onInit with `placeAuthoredObjects`.
67
+ */
68
+ placeObjects?: boolean | {
69
+ verticalOffset?: number;
70
+ };
71
+ /** Terrain surface color sampler forwarded to studio renderers (see `SceneKindRenderContext.groundColorAt`). */
72
+ groundColorAt?: (x: number, z: number) => string;
73
+ }
74
+ /**
75
+ * Renders an editor document's scene content — draped paths plus GPU-instanced foliage — from one
76
+ * mount, grounded on the live `field`. The runtime counterpart to authoring a scene in the editor:
77
+ * drag paths and foliage regions, save `editor.scene.json`, and the game plays them with no bespoke
78
+ * render code. When a live-sync bus is installed (editor host), document patches stream in and
79
+ * re-render automatically — document is authoritative; runtime overrides stay ephemeral unless
80
+ * written back. Terrain/collision come from the world's ground field (`environment({ sculpt })`);
81
+ * place markers with your own entity spawns. Pass `scatterModels`+`assets` to resolve palette items to
82
+ * real catalog GLBs; unmapped items keep the stylized proxy.
83
+ */
84
+ export declare function AuthoredScene({ document, field, pathKinds, scatterModels, assets, live, placeObjects, groundColorAt, }: AuthoredSceneProps): import("react").JSX.Element;
@@ -0,0 +1,178 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment, useEffect, useMemo, useState } from "react";
3
+ import * as THREE from "three";
4
+ import { getDocumentLiveSync, subscribeDocumentLiveSyncInstall, } from "@jgengine/core/editor/index";
5
+ import { placeAuthoredObjects, resolveAuthoredObjects, } from "@jgengine/core/world/authoredObjects";
6
+ import { buildRoadRibbon, roundPathCorners } from "@jgengine/core/world/roads";
7
+ import { isScatterPath, resolveScatter } from "@jgengine/core/world/scatterRegion";
8
+ import { getAssetGenerator } from "@jgengine/core/scene/assetGenerator";
9
+ import { useGameContext } from "@jgengine/react/provider";
10
+ import { createModelMapResolver } from "../render/resolveModel.js";
11
+ import { InstancedScatter } from "../scatter/InstancedScatter.js";
12
+ import { GeneratedAssetInstance } from "./GeneratedAssetRenderer.js";
13
+ import { registerBuiltinSceneKindRenderers } from "./builtinSceneKindRenderers.js";
14
+ import { getSceneKindRenderer } from "./sceneKindRenderers.js";
15
+ /**
16
+ * Resolves the document AuthoredScene renders: when a {@link getDocumentLiveSync} bus is
17
+ * installed (editor host live), subscribe to document patches; otherwise use the prop.
18
+ * Document is authoritative — runtime overrides never land here unless written back.
19
+ * @internal
20
+ */
21
+ export function useLiveEditorDocument(document, live = true) {
22
+ const [resolved, setResolved] = useState(document);
23
+ useEffect(() => {
24
+ if (!live) {
25
+ setResolved(document);
26
+ return;
27
+ }
28
+ let unsubDoc;
29
+ const attach = () => {
30
+ unsubDoc?.();
31
+ unsubDoc = undefined;
32
+ const sync = getDocumentLiveSync();
33
+ if (sync === null) {
34
+ setResolved(document);
35
+ return;
36
+ }
37
+ setResolved(sync.getDocument());
38
+ unsubDoc = sync.subscribeDocument((event) => setResolved(event.document));
39
+ };
40
+ attach();
41
+ const unsubInstall = subscribeDocumentLiveSyncInstall(attach);
42
+ return () => {
43
+ unsubInstall();
44
+ unsubDoc?.();
45
+ };
46
+ }, [document, live]);
47
+ return live ? resolved : document;
48
+ }
49
+ registerBuiltinSceneKindRenderers();
50
+ function markerToKindObject(marker) {
51
+ return { id: marker.id, kind: marker.kind, position: marker.position, ...(marker.rotationY === undefined ? {} : { rotationY: marker.rotationY }), ...(marker.meta === undefined ? {} : { meta: marker.meta }) };
52
+ }
53
+ function volumeToKindObject(volume) {
54
+ return {
55
+ id: volume.id,
56
+ kind: volume.kind,
57
+ center: volume.center,
58
+ ...(volume.halfExtents === undefined ? {} : { halfExtents: volume.halfExtents }),
59
+ ...(volume.radius === undefined ? {} : { radius: volume.radius }),
60
+ ...(volume.meta === undefined ? {} : { meta: volume.meta }),
61
+ };
62
+ }
63
+ function pathToKindObject(path) {
64
+ return { id: path.id, kind: path.kind, points: path.points.map((point) => ({ x: point.x, y: point.y, z: point.z })), ...(path.meta === undefined ? {} : { meta: path.meta }) };
65
+ }
66
+ /** Renders every marker placed as a parametric generator asset, re-resolved from its `meta` + seed. */
67
+ function AuthoredGenerators({ document, field }) {
68
+ const markers = useMemo(() => document.markers.filter((marker) => typeof marker.meta?.["assetId"] === "string" && getAssetGenerator(marker.meta["assetId"]) !== undefined), [document.markers]);
69
+ return (_jsx(_Fragment, { children: markers.map((marker) => (_jsx(GeneratedAssetInstance, { meta: marker.meta, position: [marker.position.x, field.sampleHeight(marker.position.x, marker.position.z), marker.position.z], rotationY: marker.rotationY ?? 0 }, marker.id))) }));
70
+ }
71
+ /**
72
+ * Mounts every registered studio renderer for the kinds present in a document — water and any
73
+ * game/example-registered kind — grouping objects by kind and handing each renderer its slice.
74
+ * Scatter stays on the batched {@link InstancedScatter} path (its cross-region avoid masks need the
75
+ * whole document), so it is skipped here.
76
+ */
77
+ function AuthoredStudios({ document, context }) {
78
+ const byKind = useMemo(() => {
79
+ const groups = new Map();
80
+ const add = (kind, object) => {
81
+ if (isScatterPath({ kind }) || getSceneKindRenderer(kind) === undefined)
82
+ return;
83
+ const bucket = groups.get(kind);
84
+ if (bucket === undefined)
85
+ groups.set(kind, [object]);
86
+ else
87
+ bucket.push(object);
88
+ };
89
+ for (const marker of document.markers)
90
+ add(marker.kind, markerToKindObject(marker));
91
+ for (const volume of document.volumes)
92
+ add(volume.kind, volumeToKindObject(volume));
93
+ for (const path of document.paths)
94
+ add(path.kind, pathToKindObject(path));
95
+ return groups;
96
+ }, [document]);
97
+ return (_jsx(_Fragment, { children: [...byKind.entries()].map(([kind, objects]) => {
98
+ const renderer = getSceneKindRenderer(kind);
99
+ return renderer === undefined ? null : _jsx(Fragment, { children: renderer({ objects, context }) }, kind);
100
+ }) }));
101
+ }
102
+ const DEFAULT_PATH_COLOR = "#7a6444";
103
+ /** One editor path drawn as a ground-draped ribbon — subdivided and sampled against the live field. */
104
+ function DrapedPath({ points, width, color, field, }) {
105
+ const geometry = useMemo(() => {
106
+ // Fillet sharp turns first so bends read as smooth arcs, not overlapping rectangles.
107
+ const rounded = roundPathCorners(points, Math.max(1.5, width * 0.9), 6);
108
+ const ribbon = buildRoadRibbon(rounded, width, (x, z) => field.sampleHeight(x, z), {
109
+ elevation: 0.18,
110
+ maxSegmentLength: 1,
111
+ });
112
+ const geo = new THREE.BufferGeometry();
113
+ geo.setAttribute("position", new THREE.BufferAttribute(ribbon.positions, 3));
114
+ geo.setIndex(new THREE.BufferAttribute(ribbon.indices, 1));
115
+ geo.computeVertexNormals();
116
+ return geo;
117
+ // eslint-disable-next-line react-hooks/exhaustive-deps
118
+ }, [points, width, field]);
119
+ useEffect(() => () => geometry.dispose(), [geometry]);
120
+ if (points.length < 2)
121
+ return null;
122
+ return (_jsx("mesh", { geometry: geometry, receiveShadow: true, children: _jsx("meshStandardMaterial", { color: color, roughness: 1, metalness: 0, side: THREE.DoubleSide }) }));
123
+ }
124
+ function pathColor(meta, color) {
125
+ if (typeof meta?.["color"] === "string")
126
+ return meta["color"];
127
+ return color ?? DEFAULT_PATH_COLOR;
128
+ }
129
+ /**
130
+ * Renders a document's non-scatter paths (roads, routes, corridors) as ground-draped ribbons — the
131
+ * editor authors the polyline, the engine drapes it over the live terrain at runtime. Width comes
132
+ * from `path.width`, color from `path.meta.color`/`path.color`. A game never hand-rolls path meshes.
133
+ */
134
+ export function AuthoredPaths({ document, field, kinds }) {
135
+ const paths = document.paths.filter((path) => !isScatterPath(path) && getSceneKindRenderer(path.kind) === undefined && (kinds === undefined || kinds.includes(path.kind)));
136
+ return (_jsx(_Fragment, { children: paths.map((path) => (_jsx(DrapedPath, { points: path.points.map((point) => [point.x, point.z]), width: path.width ?? 4, color: pathColor(path.meta, path.color), field: field }, path.id))) }));
137
+ }
138
+ /**
139
+ * Places every editor marker with a catalog id into `ctx.scene.object`, grounded on `field`.
140
+ * WorldScene renders them through the game's `objectModels` seam — no bespoke place loop. Pure
141
+ * headless twin: `resolveAuthoredObjects` / `placeAuthoredObjects`.
142
+ */
143
+ export function AuthoredObjects({ document, field, verticalOffset = 0, onExisting = "keep", }) {
144
+ const ctx = useGameContext();
145
+ const objects = useMemo(() => resolveAuthoredObjects(document), [document]);
146
+ useEffect(() => {
147
+ if (objects.length === 0)
148
+ return;
149
+ placeAuthoredObjects(ctx.scene.object, objects, (x, z) => field.sampleHeight(x, z), {
150
+ verticalOffset,
151
+ onExisting,
152
+ });
153
+ }, [ctx.scene.object, field, objects, onExisting, verticalOffset]);
154
+ return null;
155
+ }
156
+ /**
157
+ * Renders an editor document's scene content — draped paths plus GPU-instanced foliage — from one
158
+ * mount, grounded on the live `field`. The runtime counterpart to authoring a scene in the editor:
159
+ * drag paths and foliage regions, save `editor.scene.json`, and the game plays them with no bespoke
160
+ * render code. When a live-sync bus is installed (editor host), document patches stream in and
161
+ * re-render automatically — document is authoritative; runtime overrides stay ephemeral unless
162
+ * written back. Terrain/collision come from the world's ground field (`environment({ sculpt })`);
163
+ * place markers with your own entity spawns. Pass `scatterModels`+`assets` to resolve palette items to
164
+ * real catalog GLBs; unmapped items keep the stylized proxy.
165
+ */
166
+ export function AuthoredScene({ document, field, pathKinds, scatterModels, assets, live = true, placeObjects, groundColorAt, }) {
167
+ const liveDocument = useLiveEditorDocument(document, live);
168
+ const instances = useMemo(() => resolveScatter(liveDocument, field), [liveDocument, field]);
169
+ const resolveItem = useMemo(() => createModelMapResolver(scatterModels, assets, "scatterModels"), [scatterModels, assets]);
170
+ const shouldPlaceObjects = placeObjects === true || (typeof placeObjects === "object" && placeObjects !== null);
171
+ const objectVerticalOffset = typeof placeObjects === "object" && placeObjects !== null ? (placeObjects.verticalOffset ?? 0) : 0;
172
+ return (_jsxs(_Fragment, { children: [_jsx(AuthoredPaths, { document: liveDocument, field: field, ...(pathKinds === undefined ? {} : { kinds: pathKinds }) }), _jsx(InstancedScatter, { instances: instances, ...(resolveItem === undefined ? {} : { resolveItem }) }), _jsx(AuthoredStudios, { document: liveDocument, context: {
173
+ document: liveDocument,
174
+ field,
175
+ ...(assets === undefined ? {} : { assets }),
176
+ ...(groundColorAt === undefined ? {} : { groundColorAt }),
177
+ } }), _jsx(AuthoredGenerators, { document: liveDocument, field: field }), shouldPlaceObjects ? (_jsx(AuthoredObjects, { document: liveDocument, field: field, verticalOffset: objectVerticalOffset })) : null] }));
178
+ }
@@ -0,0 +1,2 @@
1
+ /** Registers the `city` volume runtime renderer. Called by `registerBuiltinSceneKindRenderers`. @internal */
2
+ export declare function registerCityRenderer(): void;