@jgengine/core 0.11.0 → 0.13.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 (256) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/ai/populationDirector.d.ts +103 -0
  3. package/dist/ai/populationDirector.js +190 -0
  4. package/dist/ai/pursuit.d.ts +56 -0
  5. package/dist/ai/pursuit.js +53 -0
  6. package/dist/authoring.d.ts +1 -1
  7. package/dist/authoring.js +1 -1
  8. package/dist/combat/effects.d.ts +11 -4
  9. package/dist/combat/effects.js +24 -17
  10. package/dist/combat/magazine.d.ts +13 -0
  11. package/dist/combat/magazine.js +27 -0
  12. package/dist/combat/vfxPresets.d.ts +176 -0
  13. package/dist/combat/vfxPresets.js +74 -0
  14. package/dist/combat/weaponFire.d.ts +114 -0
  15. package/dist/combat/weaponFire.js +96 -0
  16. package/dist/combat.d.ts +5 -2
  17. package/dist/combat.js +4 -1
  18. package/dist/devtools/controls.d.ts +38 -0
  19. package/dist/devtools/controls.js +181 -0
  20. package/dist/devtools/devtools.d.ts +5 -197
  21. package/dist/devtools/devtools.js +38 -774
  22. package/dist/devtools/discover.d.ts +32 -0
  23. package/dist/devtools/discover.js +240 -0
  24. package/dist/devtools/fallbackSeams.d.ts +50 -0
  25. package/dist/devtools/fallbackSeams.js +111 -0
  26. package/dist/devtools/frame.d.ts +15 -0
  27. package/dist/devtools/frame.js +247 -0
  28. package/dist/devtools/logs.d.ts +15 -0
  29. package/dist/devtools/logs.js +86 -0
  30. package/dist/devtools/overrides.d.ts +16 -0
  31. package/dist/devtools/overrides.js +66 -0
  32. package/dist/devtools/types.d.ts +212 -0
  33. package/dist/devtools/types.js +1 -0
  34. package/dist/devtools/urlFlags.d.ts +22 -0
  35. package/dist/devtools/urlFlags.js +62 -0
  36. package/dist/economy/auctionBook.d.ts +122 -0
  37. package/dist/economy/auctionBook.js +213 -0
  38. package/dist/economy/priceHistory.d.ts +44 -0
  39. package/dist/economy/priceHistory.js +89 -0
  40. package/dist/economy/unlockPoints.d.ts +92 -0
  41. package/dist/economy/unlockPoints.js +103 -0
  42. package/dist/editor/commandApply.d.ts +5 -0
  43. package/dist/editor/commandApply.js +755 -0
  44. package/dist/editor/commands.d.ts +48 -3
  45. package/dist/editor/commands.js +40 -754
  46. package/dist/editor/directives.d.ts +94 -0
  47. package/dist/editor/directives.js +206 -0
  48. package/dist/editor/document.d.ts +37 -2
  49. package/dist/editor/document.js +422 -6
  50. package/dist/editor/entityCatalog.d.ts +42 -0
  51. package/dist/editor/entityCatalog.js +101 -0
  52. package/dist/editor/environment.d.ts +74 -0
  53. package/dist/editor/environment.js +169 -0
  54. package/dist/editor/index.d.ts +26 -1
  55. package/dist/editor/index.js +8 -1
  56. package/dist/editor/minimap.d.ts +31 -0
  57. package/dist/editor/minimap.js +73 -0
  58. package/dist/editor/streamer.d.ts +66 -0
  59. package/dist/editor/streamer.js +68 -0
  60. package/dist/editor/types.d.ts +143 -0
  61. package/dist/editor/world.d.ts +136 -0
  62. package/dist/editor/world.js +303 -0
  63. package/dist/game/breeding.d.ts +161 -0
  64. package/dist/game/breeding.js +181 -0
  65. package/dist/game/cameraConfig.d.ts +451 -0
  66. package/dist/game/cameraConfig.js +1 -0
  67. package/dist/game/clipRoles.d.ts +51 -0
  68. package/dist/game/clipRoles.js +142 -0
  69. package/dist/game/defineGame.d.ts +16 -9
  70. package/dist/game/defineGame.js +14 -6
  71. package/dist/game/defineSystem.d.ts +2 -0
  72. package/dist/game/defineSystem.js +2 -0
  73. package/dist/game/events.d.ts +28 -0
  74. package/dist/game/partAnimation.d.ts +78 -0
  75. package/dist/game/partAnimation.js +147 -0
  76. package/dist/game/playableGame.d.ts +72 -440
  77. package/dist/game/playableGame.js +1 -1
  78. package/dist/game/progression.d.ts +35 -0
  79. package/dist/game/progression.js +22 -1
  80. package/dist/game/quest.js +1 -3
  81. package/dist/game/tribe.d.ts +184 -0
  82. package/dist/game/tribe.js +432 -0
  83. package/dist/gameplay.d.ts +3 -1
  84. package/dist/gameplay.js +3 -1
  85. package/dist/inventory/encumbrance.d.ts +69 -0
  86. package/dist/inventory/encumbrance.js +68 -0
  87. package/dist/inventory/inventoryModel.d.ts +24 -8
  88. package/dist/inventory/inventoryModel.js +47 -8
  89. package/dist/item/durability.js +1 -3
  90. package/dist/meta/changelog.d.ts +1 -1
  91. package/dist/meta/changelog.js +48 -1
  92. package/dist/movement/movementModel.d.ts +15 -1
  93. package/dist/movement/movementModel.js +33 -15
  94. package/dist/movement/playerMovement.js +102 -2
  95. package/dist/multiplayer/combatSnapshot.js +13 -8
  96. package/dist/multiplayer/presenceModel.d.ts +2 -0
  97. package/dist/multiplayer/presenceModel.js +8 -0
  98. package/dist/physics/drivableVehicle.d.ts +2 -0
  99. package/dist/physics/drivableVehicle.js +1 -1
  100. package/dist/physics/flightDynamics.d.ts +82 -0
  101. package/dist/physics/flightDynamics.js +165 -0
  102. package/dist/physics/gravityField.d.ts +25 -0
  103. package/dist/physics/gravityField.js +41 -0
  104. package/dist/physics/kinematicVehicle.d.ts +87 -0
  105. package/dist/physics/kinematicVehicle.js +193 -11
  106. package/dist/physics/physicsWorld.d.ts +26 -0
  107. package/dist/physics/physicsWorld.js +109 -117
  108. package/dist/physics/vehicleObstacles.d.ts +44 -0
  109. package/dist/physics/vehicleObstacles.js +115 -0
  110. package/dist/random/rng.d.ts +4 -1
  111. package/dist/random/rng.js +4 -1
  112. package/dist/runtime/adapter.d.ts +13 -0
  113. package/dist/runtime/adapter.js +13 -0
  114. package/dist/runtime/context/combat.d.ts +51 -0
  115. package/dist/runtime/context/combat.js +131 -0
  116. package/dist/runtime/context/combatFx.js +15 -5
  117. package/dist/runtime/context/deathLoot.d.ts +30 -0
  118. package/dist/runtime/context/deathLoot.js +39 -0
  119. package/dist/runtime/context/player.d.ts +48 -0
  120. package/dist/runtime/context/player.js +125 -0
  121. package/dist/runtime/context/scene.d.ts +60 -0
  122. package/dist/runtime/context/scene.js +329 -0
  123. package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
  124. package/dist/runtime/context/snapshotCodecs.js +26 -0
  125. package/dist/runtime/descriptors/baseline.js +26 -3
  126. package/dist/runtime/descriptors/features.d.ts +5 -0
  127. package/dist/runtime/descriptors/features.js +20 -2
  128. package/dist/runtime/gameContext.d.ts +2 -428
  129. package/dist/runtime/gameContext.js +133 -500
  130. package/dist/runtime/gameContextTypes.d.ts +500 -0
  131. package/dist/runtime/gameContextTypes.js +1 -0
  132. package/dist/runtime/headlessRunner.d.ts +17 -2
  133. package/dist/runtime/headlessRunner.js +15 -0
  134. package/dist/runtime/hostPolicy.d.ts +51 -0
  135. package/dist/runtime/hostPolicy.js +68 -0
  136. package/dist/runtime/hostedGameRunner.d.ts +3 -1
  137. package/dist/runtime/hostedGameRunner.js +1 -0
  138. package/dist/runtime/hostedWorldSession.d.ts +3 -1
  139. package/dist/runtime/hostedWorldSession.js +1 -0
  140. package/dist/runtime/worldSnapshot.d.ts +13 -1
  141. package/dist/runtime/worldSnapshot.js +15 -3
  142. package/dist/scene/assetCatalog.d.ts +7 -0
  143. package/dist/scene/assetSpace.js +1 -3
  144. package/dist/scene/authoredTriggers.d.ts +50 -0
  145. package/dist/scene/authoredTriggers.js +114 -0
  146. package/dist/scene/builtinSceneKinds.js +8 -3
  147. package/dist/scene/colliders.d.ts +79 -0
  148. package/dist/scene/colliders.js +170 -0
  149. package/dist/scene/collisionMesh.d.ts +94 -0
  150. package/dist/scene/collisionMesh.js +699 -0
  151. package/dist/scene/companion.d.ts +147 -0
  152. package/dist/scene/companion.js +193 -0
  153. package/dist/scene/entityStats.d.ts +7 -9
  154. package/dist/scene/entityStats.js +19 -15
  155. package/dist/scene/sceneKinds.d.ts +16 -0
  156. package/dist/scene/sceneKinds.js +4 -0
  157. package/dist/scene/sceneRaycast.js +15 -0
  158. package/dist/stats/spawnLevelStats.d.ts +110 -0
  159. package/dist/stats/spawnLevelStats.js +140 -0
  160. package/dist/stats/statModifiers.d.ts +16 -0
  161. package/dist/stats/statModifiers.js +30 -1
  162. package/dist/stats/statPool.d.ts +70 -0
  163. package/dist/stats/statPool.js +62 -0
  164. package/dist/store/changeSignal.d.ts +3 -0
  165. package/dist/store/changeSignal.js +2 -0
  166. package/dist/store/observableKeyedStore.d.ts +2 -0
  167. package/dist/store/observableKeyedStore.js +1 -0
  168. package/dist/survival/decayMeter.js +1 -3
  169. package/dist/survival/regionHealth.js +1 -3
  170. package/dist/ui/hudLayout.d.ts +5 -0
  171. package/dist/ui/hudLayout.js +17 -1
  172. package/dist/ui/panelModel.d.ts +120 -0
  173. package/dist/ui/panelModel.js +168 -0
  174. package/dist/ui.d.ts +1 -0
  175. package/dist/ui.js +1 -0
  176. package/dist/world/authoredEntities.d.ts +29 -0
  177. package/dist/world/authoredEntities.js +29 -0
  178. package/dist/world/authoredObjects.d.ts +15 -1
  179. package/dist/world/authoredObjects.js +13 -1
  180. package/dist/world/authoredSpawn.d.ts +39 -0
  181. package/dist/world/authoredSpawn.js +37 -0
  182. package/dist/world/buildSockets.d.ts +152 -0
  183. package/dist/world/buildSockets.js +188 -0
  184. package/dist/world/buildingLots.d.ts +84 -0
  185. package/dist/world/buildingLots.js +119 -0
  186. package/dist/world/buildings.d.ts +6 -0
  187. package/dist/world/cityBlocks.d.ts +152 -0
  188. package/dist/world/cityBlocks.js +670 -0
  189. package/dist/world/cityContent.d.ts +77 -0
  190. package/dist/world/cityContent.js +261 -0
  191. package/dist/world/cityGenerator.d.ts +41 -0
  192. package/dist/world/cityGenerator.js +58 -0
  193. package/dist/world/cityGeometry.d.ts +114 -0
  194. package/dist/world/cityGeometry.js +573 -0
  195. package/dist/world/cityKind.d.ts +314 -0
  196. package/dist/world/cityKind.js +1578 -0
  197. package/dist/world/environmentSummary.js +57 -1
  198. package/dist/world/features.d.ts +53 -5
  199. package/dist/world/features.js +15 -3
  200. package/dist/world/grassKind.js +2 -2
  201. package/dist/world/markers.d.ts +50 -4
  202. package/dist/world/markers.js +49 -0
  203. package/dist/world/massing.js +1 -1
  204. package/dist/world/minimapBake.d.ts +78 -0
  205. package/dist/world/minimapBake.js +208 -0
  206. package/dist/world/minimapTrack.d.ts +17 -0
  207. package/dist/world/minimapTrack.js +22 -0
  208. package/dist/world/place.d.ts +166 -0
  209. package/dist/world/place.js +96 -0
  210. package/dist/world/placeAsset.js +3 -1
  211. package/dist/world/poleLineKind.d.ts +40 -0
  212. package/dist/world/poleLineKind.js +97 -0
  213. package/dist/world/polyline.js +9 -2
  214. package/dist/world/resourceNode.d.ts +109 -0
  215. package/dist/world/resourceNode.js +140 -0
  216. package/dist/world/roads.d.ts +19 -2
  217. package/dist/world/roads.js +60 -3
  218. package/dist/world/scatter.js +2 -20
  219. package/dist/world/streetGenerator.d.ts +159 -0
  220. package/dist/world/streetGenerator.js +684 -0
  221. package/dist/world/streets.d.ts +103 -1
  222. package/dist/world/streets.js +273 -0
  223. package/dist/world/terraform.js +58 -88
  224. package/dist/world/terrain.d.ts +65 -1
  225. package/dist/world/terrain.js +119 -2
  226. package/dist/world.d.ts +14 -5
  227. package/dist/world.js +12 -3
  228. package/package.json +1 -1
  229. package/skills/game-design/SKILL.md +28 -0
  230. package/skills/game-design/agents/openai.yaml +4 -0
  231. package/skills/game-design/references/application-playbook.md +170 -0
  232. package/skills/game-design/references/field-guide.md +288 -0
  233. package/skills/jgengine/SKILL.md +8 -4
  234. package/skills/jgengine/api.md +182 -81
  235. package/skills/jgengine/capabilities.md +104 -2
  236. package/skills/jgengine/recipes/minimal-game.md +88 -0
  237. package/skills/jgengine-combat/SKILL.md +19 -1
  238. package/skills/jgengine-combat/api.md +75 -2
  239. package/skills/jgengine-combat/capabilities.md +61 -1
  240. package/skills/jgengine-combat/recipes/portable-damage-effects.md +197 -0
  241. package/skills/jgengine-combat/recipes/portable-runtime-state.md +154 -0
  242. package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
  243. package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +156 -0
  244. package/skills/jgengine-combat/recipes/visible-attacks.md +81 -0
  245. package/skills/jgengine-combat/reference.md +33 -4
  246. package/skills/jgengine-gameplay/SKILL.md +8 -0
  247. package/skills/jgengine-gameplay/api.md +182 -26
  248. package/skills/jgengine-gameplay/capabilities.md +96 -2
  249. package/skills/jgengine-gameplay/recipes/portable-xp-leveling.md +168 -0
  250. package/skills/jgengine-gameplay/reference-systems.md +10 -5
  251. package/skills/jgengine-world/SKILL.md +13 -0
  252. package/skills/jgengine-world/api.md +453 -21
  253. package/skills/jgengine-world/capabilities.md +112 -2
  254. package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
  255. package/skills/jgengine-world/reference.md +43 -4
  256. package/skills/jgengine/reference-cartridge.md +0 -72
@@ -1,3 +1,4 @@
1
+ import { prepareCollisionMesh } from "./collisionMesh.js";
1
2
  export const DEFAULT_ENTITY_HIT_RADIUS = 0.5;
2
3
  export const DEFAULT_OBJECT_HALF_EXTENTS = [0.5, 0.5, 0.5];
3
4
  /** Matches the shell's fallback actor capsule (~0.7m wide, feet at y=0 to head at ~1.8m). */
@@ -80,6 +81,175 @@ export function scaledObjectColliders(scale) {
80
81
  },
81
82
  };
82
83
  }
84
+ /**
85
+ * The entity-local AABB the rendered model actually occupies, from measured dims + render config — the
86
+ * same scale/normalize/anchor math the shell uses to place the mesh, so box equals visual by
87
+ * construction. `null` when the model is unmeasured (`dims`/`maxY` absent) or degenerate.
88
+ */
89
+ function fittedModelBox(model) {
90
+ const dims = model.dims;
91
+ if (dims === undefined || dims.maxY === undefined)
92
+ return null;
93
+ const { w, d } = dims.footprint;
94
+ const height = dims.maxY - dims.minY;
95
+ if (!(w > 0) || !(d > 0) || !(height > 0))
96
+ return null;
97
+ if (!Number.isFinite(w) || !Number.isFinite(d) || !Number.isFinite(height))
98
+ return null;
99
+ const normalize = model.targetHeight !== undefined && model.targetHeight > 0 ? model.targetHeight / height : 1;
100
+ const scale = (model.scale ?? 1) * normalize;
101
+ if (!(scale > 0) || !Number.isFinite(scale))
102
+ return null;
103
+ const baseY = model.y ?? 0;
104
+ // The renderer centers/grounds whenever it normalizes to targetHeight or anchors "center" (the
105
+ // default); only a raw-origin model without targetHeight keeps its authored pivot.
106
+ const centered = model.targetHeight !== undefined || (model.anchor ?? "center") === "center";
107
+ const halfExtents = [(w / 2) * scale, (height / 2) * scale, (d / 2) * scale];
108
+ const offset = centered
109
+ ? [0, baseY + (height / 2) * scale, 0]
110
+ : [dims.center.x * scale, baseY + (dims.minY + height / 2) * scale, dims.center.z * scale];
111
+ // Maps the model point (center.x, minY, center.z) to the entity-local (0, baseY, 0) the box grounds
112
+ // on when centered; a raw-origin model keeps its authored pivot and only takes the render offset.
113
+ const meshTranslate = centered
114
+ ? [-dims.center.x * scale, baseY - dims.minY * scale, -dims.center.z * scale]
115
+ : [0, baseY, 0];
116
+ return { halfExtents, offset, scale, meshTranslate };
117
+ }
118
+ /** Map a model-space point onto entity-local space with the mesh shape's uniform `scale` and per-axis
119
+ * `translate` (`coord * scale + translate`) — the same composition applied to `meshScale`/`meshTranslate`,
120
+ * so a model-space AABB corner lands exactly where the placed mesh puts it. `scale > 0` keeps min<max. */
121
+ function scaleTranslatePoint(point, scale, translate) {
122
+ return [point[0] * scale + translate[0], point[1] * scale + translate[1], point[2] * scale + translate[2]];
123
+ }
124
+ /** The fitted collider shape for a rendered model: a mesh-accurate triangle shape when the model
125
+ * opts in with a decodable `collisionMesh`, otherwise the conservative fitted box. `null` when the
126
+ * model is unmeasured or degenerate.
127
+ */
128
+ function fittedBodyShape(model) {
129
+ const box = fittedModelBox(model);
130
+ if (box === null)
131
+ return null;
132
+ const mesh = model.collisionMesh !== undefined ? prepareCollisionMesh(model.collisionMesh) : null;
133
+ if (mesh !== null) {
134
+ const sourceBoxes = model.collisionMesh?.boxes;
135
+ const boxes = sourceBoxes !== undefined && sourceBoxes.length > 0
136
+ ? sourceBoxes.map((b) => ({
137
+ min: scaleTranslatePoint(b.min, box.scale, box.meshTranslate),
138
+ max: scaleTranslatePoint(b.max, box.scale, box.meshTranslate),
139
+ }))
140
+ : undefined;
141
+ return {
142
+ kind: "mesh",
143
+ mesh,
144
+ meshScale: box.scale,
145
+ meshTranslate: box.meshTranslate,
146
+ halfExtents: box.halfExtents,
147
+ ...(boxes !== undefined ? { boxes } : {}),
148
+ offset: box.offset,
149
+ };
150
+ }
151
+ return { kind: "aabb", halfExtents: box.halfExtents, offset: box.offset };
152
+ }
153
+ /** Damage hitbox fitted to the rendered model's measured bounds — the model-aware replacement for the
154
+ * fixed humanoid default. `null` when the model is unmeasured, keeping the caller's existing fallback.
155
+ * @internal
156
+ */
157
+ export function fittedEntityColliders(model) {
158
+ const shape = fittedBodyShape(model);
159
+ if (shape === null)
160
+ return null;
161
+ return {
162
+ hitboxes: [
163
+ {
164
+ name: "body",
165
+ purpose: "damage",
166
+ shape,
167
+ damageEligible: true,
168
+ blocks: false,
169
+ },
170
+ ],
171
+ };
172
+ }
173
+ /** Blocking physical body fitted to the rendered model's measured bounds — the model-aware replacement
174
+ * for the unit-cube-times-scale guess. `null` when the model is unmeasured.
175
+ * @internal
176
+ */
177
+ export function fittedObjectColliders(model) {
178
+ const shape = fittedBodyShape(model);
179
+ if (shape === null)
180
+ return null;
181
+ return {
182
+ body: {
183
+ name: "body",
184
+ purpose: "physical",
185
+ shape,
186
+ damageEligible: false,
187
+ blocks: true,
188
+ },
189
+ };
190
+ }
191
+ /** Thin measured axes (decals, blades, flat panels) keep at least this half-extent so the box stays hittable. */
192
+ const MIN_MEASURED_HALF_EXTENT = 0.01;
193
+ /** Tight AABB from measured bounds — `null` when inverted, non-finite, or a degenerate point. */
194
+ function measuredBox(bounds) {
195
+ const { min, max } = bounds;
196
+ let volume = 0;
197
+ for (let axis = 0; axis < 3; axis += 1) {
198
+ const lo = min[axis];
199
+ const hi = max[axis];
200
+ if (!Number.isFinite(lo) || !Number.isFinite(hi) || hi < lo)
201
+ return null;
202
+ volume = Math.max(volume, hi - lo);
203
+ }
204
+ if (!(volume > 0))
205
+ return null;
206
+ return {
207
+ halfExtents: [
208
+ Math.max((max[0] - min[0]) / 2, MIN_MEASURED_HALF_EXTENT),
209
+ Math.max((max[1] - min[1]) / 2, MIN_MEASURED_HALF_EXTENT),
210
+ Math.max((max[2] - min[2]) / 2, MIN_MEASURED_HALF_EXTENT),
211
+ ],
212
+ offset: [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2],
213
+ };
214
+ }
215
+ /** Damage hitbox exactly wrapping runtime-measured render bounds — what `reportBounds` stores for an
216
+ * entity kind. `null` when the bounds are degenerate, keeping the caller's existing fallback.
217
+ * @internal
218
+ */
219
+ export function measuredEntityColliders(bounds) {
220
+ const box = measuredBox(bounds);
221
+ if (box === null)
222
+ return null;
223
+ return {
224
+ hitboxes: [
225
+ {
226
+ name: "body",
227
+ purpose: "damage",
228
+ shape: { kind: "aabb", halfExtents: box.halfExtents, offset: box.offset },
229
+ damageEligible: true,
230
+ blocks: false,
231
+ },
232
+ ],
233
+ };
234
+ }
235
+ /** Blocking physical body exactly wrapping runtime-measured render bounds — what `reportBounds`
236
+ * stores for an object catalog id. `null` when the bounds are degenerate.
237
+ * @internal
238
+ */
239
+ export function measuredObjectColliders(bounds) {
240
+ const box = measuredBox(bounds);
241
+ if (box === null)
242
+ return null;
243
+ return {
244
+ body: {
245
+ name: "body",
246
+ purpose: "physical",
247
+ shape: { kind: "aabb", halfExtents: box.halfExtents, offset: box.offset },
248
+ damageEligible: false,
249
+ blocks: true,
250
+ },
251
+ };
252
+ }
83
253
  /** @internal */
84
254
  export function resolveColliders(set) {
85
255
  if (set === null || set === undefined)
@@ -0,0 +1,94 @@
1
+ import type { EntityPosition } from "./entityStore.js";
2
+ /**
3
+ * Compact, serializable triangle collision mesh measured at asset reindex — the renderer-free source
4
+ * of mesh-accurate hitboxes. Positions are welded onto a 16-bit grid spanning `min`..`max` (model
5
+ * space) and stored base64-encoded, so an opted-in catalog asset ships its collision triangles inside
6
+ * the generated index without the runtime ever touching the rendered scene graph.
7
+ */
8
+ export interface CollisionMeshData {
9
+ /** Model-space bounds of the encoded vertices — the quantization frame. */
10
+ min: readonly [number, number, number];
11
+ max: readonly [number, number, number];
12
+ /** Welded vertex count; `positions` holds exactly `vertexCount * 3` u16 values. */
13
+ vertexCount: number;
14
+ /** Triangle count; `indices` holds exactly `triangleCount * 3` values. */
15
+ triangleCount: number;
16
+ /** Base64 little-endian u16 xyz triples, each axis normalized 0..65535 across `min`..`max`. */
17
+ positions: string;
18
+ /** Base64 little-endian triangle vertex indices — u16, or u32 when `vertexCount` exceeds 65536. */
19
+ indices: string;
20
+ /**
21
+ * Optional compact model-space solid decomposition from {@link voxelizeToBoxes} — a deterministic set
22
+ * of AABBs approximating the model's filled volume so movement obstruction can slide a capsule against
23
+ * the real pillars/lintel of a concave opening (walk THROUGH an arch) instead of one outer box. Absent
24
+ * for models whose voxelization is empty, keeping box-less assets byte-identical.
25
+ */
26
+ boxes?: readonly {
27
+ min: readonly [number, number, number];
28
+ max: readonly [number, number, number];
29
+ }[];
30
+ }
31
+ /** Raw triangle soup for {@link encodeCollisionMesh}: model-space xyz triples plus triangle indices. */
32
+ export interface CollisionMeshSource {
33
+ positions: ArrayLike<number>;
34
+ indices: ArrayLike<number>;
35
+ }
36
+ /**
37
+ * Decoded, BVH-indexed triangles ready for per-ray queries — build once per asset via
38
+ * {@link prepareCollisionMesh}. Treat the fields as opaque; they exist so the raycast hot path can
39
+ * run allocation-free over flat arrays.
40
+ */
41
+ export interface PreparedCollisionMesh {
42
+ /** Dequantized model-space vertex xyz triples. */
43
+ readonly positions: Float32Array;
44
+ /** Triangle vertex indices, 3 per triangle. */
45
+ readonly indices: Uint32Array;
46
+ /** Per-node AABBs, 6 floats (minXYZ, maxXYZ) per node. */
47
+ readonly nodeBounds: Float32Array;
48
+ /** Leaf: first slot in `triOrder`. Internal: right-child node index (left child is `node + 1`). */
49
+ readonly nodeStart: Int32Array;
50
+ /** Leaf: triangle count (> 0). Internal: 0. */
51
+ readonly nodeCount: Int32Array;
52
+ /** Triangle indices grouped by leaf ranges. */
53
+ readonly triOrder: Uint32Array;
54
+ }
55
+ /** Nearest triangle impact from {@link raycastCollisionMesh}: world distance along the ray and the world-space geometric normal facing the ray. */
56
+ export interface CollisionMeshHit {
57
+ distance: number;
58
+ normal: EntityPosition;
59
+ }
60
+ /**
61
+ * Quantize a triangle soup onto the 16-bit grid, weld coincident vertices, and drop triangles that
62
+ * collapse — the reindex-time compressor producing {@link CollisionMeshData}. Returns `null` when no
63
+ * finite, non-degenerate triangle survives.
64
+ */
65
+ export declare function encodeCollisionMesh(source: CollisionMeshSource): CollisionMeshData | null;
66
+ /**
67
+ * Decompose a triangle soup into a compact, deterministic set of model-space AABBs approximating its
68
+ * solid volume — the movement-obstruction counterpart to the raycast BVH. Rasterizes triangles onto a
69
+ * `cellSize` voxel grid, fills each vertical column between its lowest and highest occupied voxel (so a
70
+ * solid becomes solid and a concave opening — an archway — keeps its central gap empty while its pillars
71
+ * and lintel fill in), then greedy-merges occupied voxels into AABBs in a fixed z→y→x order. Pure and
72
+ * allocation-tolerant (runs once per asset at reindex). Caps the output at `maxBoxes`, folding any
73
+ * remainder into one enclosing AABB so obstruction stays conservative. Returns `[]` for degenerate input.
74
+ * @internal
75
+ */
76
+ export declare function voxelizeToBoxes(source: CollisionMeshSource, cellSize?: number, maxBoxes?: number): {
77
+ min: [number, number, number];
78
+ max: [number, number, number];
79
+ }[];
80
+ /**
81
+ * Decode a stored collision mesh and index it with a BVH. Memoized per data object, so the shell and
82
+ * a headless host preparing the same catalog entry share one build. Returns `null` (also memoized)
83
+ * when the payload is malformed.
84
+ */
85
+ export declare function prepareCollisionMesh(data: CollisionMeshData): PreparedCollisionMesh | null;
86
+ /**
87
+ * Nearest triangle hit for a world-space ray against a prepared mesh placed like its rendered model:
88
+ * model space scaled uniformly by `scale`, translated by entity-local `translate`, yaw-rotated by
89
+ * `rotationY`, and moved to `position` — the same composition {@link "scene/colliders".ModelBodySource}
90
+ * fitting applies to the AABB. Allocation-free until the returned hit. `distance` is world distance
91
+ * along `direction` (callers pass `direction` normalized); `normal` is the world-space geometric
92
+ * triangle normal facing the ray.
93
+ */
94
+ export declare function raycastCollisionMesh(mesh: PreparedCollisionMesh, origin: EntityPosition, direction: EntityPosition, maxDistance: number, position: EntityPosition, rotationY: number, scale: number, translate: EntityPosition): CollisionMeshHit | null;