@jgengine/core 0.19.0 → 0.22.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 (266) hide show
  1. package/CHANGELOG.md +364 -0
  2. package/dist/ai/decisionGraph.d.ts +2 -0
  3. package/dist/ai/decisionGraph.js +6 -0
  4. package/dist/ai/flock.d.ts +1 -1
  5. package/dist/ai/flock.js +7 -4
  6. package/dist/anim/animGraph.d.ts +33 -2
  7. package/dist/anim/animGraph.js +200 -12
  8. package/dist/anim/locomotionGraph.d.ts +11 -3
  9. package/dist/anim/locomotionGraph.js +25 -15
  10. package/dist/audio/audioFalloff.d.ts +4 -0
  11. package/dist/audio/voiceAllocator.d.ts +46 -0
  12. package/dist/audio/voiceAllocator.js +76 -0
  13. package/dist/combat/abilityKit.d.ts +19 -0
  14. package/dist/combat/abilityKit.js +40 -4
  15. package/dist/combat/death.d.ts +4 -3
  16. package/dist/combat/death.js +3 -3
  17. package/dist/combat/magazine.d.ts +9 -0
  18. package/dist/combat/magazine.js +24 -2
  19. package/dist/combat/projectiles.d.ts +94 -2
  20. package/dist/combat/projectiles.js +282 -61
  21. package/dist/combat/regenShield.d.ts +14 -0
  22. package/dist/combat/regenShield.js +23 -7
  23. package/dist/crafting/recipeCatalog.d.ts +16 -0
  24. package/dist/crafting/recipeCatalog.js +55 -0
  25. package/dist/economy/auctionBook.d.ts +1 -1
  26. package/dist/economy/auctionBook.js +11 -1
  27. package/dist/economy/listingBook.d.ts +1 -1
  28. package/dist/economy/listingBook.js +11 -1
  29. package/dist/economy/resourceLedger.js +3 -3
  30. package/dist/economy/shopStock.js +7 -6
  31. package/dist/economy/techTree.js +7 -6
  32. package/dist/economy/unlockPoints.js +3 -6
  33. package/dist/editor/commandApply.js +89 -16
  34. package/dist/editor/commands.d.ts +38 -1
  35. package/dist/editor/commands.js +320 -3
  36. package/dist/editor/creatorStorage.d.ts +59 -0
  37. package/dist/editor/creatorStorage.js +164 -0
  38. package/dist/editor/document.d.ts +4 -0
  39. package/dist/editor/document.js +116 -17
  40. package/dist/editor/index.d.ts +3 -0
  41. package/dist/editor/index.js +1 -0
  42. package/dist/editor/liveSync.d.ts +4 -1
  43. package/dist/editor/liveSync.js +26 -10
  44. package/dist/editor/materialAuthoring.d.ts +14 -0
  45. package/dist/editor/materialAuthoring.js +38 -0
  46. package/dist/editor/modelNodeVisibility.d.ts +11 -0
  47. package/dist/editor/modelNodeVisibility.js +29 -0
  48. package/dist/editor/movementCatalog.d.ts +90 -0
  49. package/dist/editor/movementCatalog.js +144 -0
  50. package/dist/editor/simulation.d.ts +60 -0
  51. package/dist/editor/simulation.js +202 -0
  52. package/dist/editor/staticPrefab.d.ts +17 -0
  53. package/dist/editor/staticPrefab.js +51 -0
  54. package/dist/editor/terrainMaterials.d.ts +10 -0
  55. package/dist/editor/terrainMaterials.js +13 -0
  56. package/dist/editor/types.d.ts +11 -0
  57. package/dist/game/cameraConfig.d.ts +3 -1
  58. package/dist/game/clipRoles.d.ts +2 -1
  59. package/dist/game/clipRoles.js +7 -3
  60. package/dist/game/contentValidation.d.ts +69 -0
  61. package/dist/game/contentValidation.js +118 -0
  62. package/dist/game/controlGate.d.ts +8 -0
  63. package/dist/game/controlGate.js +43 -6
  64. package/dist/game/defineGame.d.ts +32 -3
  65. package/dist/game/dialogueGraph.d.ts +20 -0
  66. package/dist/game/dialogueGraph.js +107 -0
  67. package/dist/game/events.d.ts +5 -0
  68. package/dist/game/keyValueStore.d.ts +17 -4
  69. package/dist/game/keyValueStore.js +35 -23
  70. package/dist/game/lootModifiers.d.ts +17 -0
  71. package/dist/game/lootModifiers.js +26 -0
  72. package/dist/game/narrativeAuthoring.d.ts +67 -0
  73. package/dist/game/narrativeAuthoring.js +122 -0
  74. package/dist/game/playableGame.d.ts +52 -20
  75. package/dist/game/quest.d.ts +15 -0
  76. package/dist/game/quest.js +209 -63
  77. package/dist/game/questCatalog.d.ts +50 -0
  78. package/dist/game/questCatalog.js +205 -0
  79. package/dist/game/saveStore.d.ts +6 -5
  80. package/dist/game/saveStore.js +57 -57
  81. package/dist/game/systemRuntime.d.ts +2 -2
  82. package/dist/game/systemRuntime.js +84 -33
  83. package/dist/gameplay.d.ts +3 -0
  84. package/dist/gameplay.js +3 -0
  85. package/dist/interaction/promptRegistry.d.ts +5 -4
  86. package/dist/interaction/promptRegistry.js +8 -2
  87. package/dist/inventory/inventoryModel.js +9 -6
  88. package/dist/inventory/shapedGrid.d.ts +48 -9
  89. package/dist/inventory/shapedGrid.js +69 -10
  90. package/dist/item/durability.js +4 -0
  91. package/dist/item/itemInstanceRegistry.d.ts +32 -1
  92. package/dist/item/itemInstanceRegistry.js +111 -7
  93. package/dist/item/itemgen.d.ts +1 -1
  94. package/dist/item/itemgen.js +1 -1
  95. package/dist/item/modularItem.js +7 -1
  96. package/dist/material/appearanceSignals.d.ts +53 -0
  97. package/dist/material/appearanceSignals.js +47 -0
  98. package/dist/material/hairCards.d.ts +47 -0
  99. package/dist/material/hairCards.js +136 -0
  100. package/dist/material/materialAsset.d.ts +162 -0
  101. package/dist/material/materialAsset.js +382 -0
  102. package/dist/meta/changelog.d.ts +1 -1
  103. package/dist/meta/changelog.js +348 -1
  104. package/dist/movement/characterController.d.ts +5 -2
  105. package/dist/movement/characterController.js +50 -23
  106. package/dist/movement/freeFlight.d.ts +2 -2
  107. package/dist/movement/freeFlight.js +3 -3
  108. package/dist/movement/movementModel.d.ts +24 -1
  109. package/dist/movement/movementModel.js +74 -7
  110. package/dist/movement/playerMovement.d.ts +28 -1
  111. package/dist/movement/playerMovement.js +425 -102
  112. package/dist/movement/poseState.d.ts +2 -0
  113. package/dist/movement/poseState.js +29 -1
  114. package/dist/movement/solidObstacles.d.ts +3 -1
  115. package/dist/movement/solidObstacles.js +8 -5
  116. package/dist/movement/terrainGrade.d.ts +13 -0
  117. package/dist/movement/terrainGrade.js +33 -0
  118. package/dist/movement/voxelController.d.ts +2 -2
  119. package/dist/movement/voxelController.js +3 -3
  120. package/dist/nav/navGrid.d.ts +19 -1
  121. package/dist/nav/navGrid.js +26 -10
  122. package/dist/nav/solidRoute.d.ts +50 -0
  123. package/dist/nav/solidRoute.js +144 -0
  124. package/dist/physics/ballisticSweep.d.ts +10 -3
  125. package/dist/physics/ballisticSweep.js +53 -29
  126. package/dist/physics/forceVolume.d.ts +41 -0
  127. package/dist/physics/forceVolume.js +88 -0
  128. package/dist/physics/kinematicVehicle.d.ts +8 -3
  129. package/dist/physics/kinematicVehicle.js +2 -2
  130. package/dist/physics/physicsWorldBackend.js +19 -3
  131. package/dist/physics/spatialGrid.d.ts +1 -1
  132. package/dist/physics/spatialGrid.js +8 -9
  133. package/dist/physics/vehicleDynamics.d.ts +3 -2
  134. package/dist/physics/vehicleDynamics.js +2 -2
  135. package/dist/physics/vehicleObstacles.d.ts +3 -2
  136. package/dist/physics/vehicleObstacles.js +29 -5
  137. package/dist/runtime/cameraDirector.d.ts +39 -2
  138. package/dist/runtime/cameraDirector.js +162 -0
  139. package/dist/runtime/commandDispatch.d.ts +14 -0
  140. package/dist/runtime/commandDispatch.js +19 -0
  141. package/dist/runtime/context/combat.d.ts +11 -4
  142. package/dist/runtime/context/combat.js +178 -11
  143. package/dist/runtime/context/deathLoot.d.ts +9 -8
  144. package/dist/runtime/context/deathLoot.js +16 -16
  145. package/dist/runtime/context/scene.d.ts +2 -0
  146. package/dist/runtime/context/scene.js +13 -21
  147. package/dist/runtime/descriptors/baseline.js +34 -3
  148. package/dist/runtime/descriptors/features.d.ts +2 -1
  149. package/dist/runtime/descriptors/features.js +18 -0
  150. package/dist/runtime/gameContext.js +79 -13
  151. package/dist/runtime/gameContextTypes.d.ts +14 -0
  152. package/dist/runtime/headlessRunner.d.ts +3 -1
  153. package/dist/runtime/headlessRunner.js +11 -11
  154. package/dist/runtime/hostedGameRunner.d.ts +24 -1
  155. package/dist/runtime/hostedGameRunner.js +156 -10
  156. package/dist/runtime/hostedWorldSession.d.ts +17 -5
  157. package/dist/runtime/hostedWorldSession.js +154 -16
  158. package/dist/runtime/hostedWorldStore.d.ts +2 -2
  159. package/dist/runtime/inputRecorder.d.ts +1 -1
  160. package/dist/runtime/inputRecorder.js +21 -1
  161. package/dist/runtime/inputSnapshot.d.ts +16 -4
  162. package/dist/runtime/inputSnapshot.js +31 -3
  163. package/dist/runtime/runtimeSave.d.ts +10 -6
  164. package/dist/runtime/runtimeSave.js +11 -5
  165. package/dist/runtime/simContext.d.ts +8 -3
  166. package/dist/runtime/simContext.js +7 -3
  167. package/dist/runtime/simSnapshot.js +2 -0
  168. package/dist/runtime/worldReplication.d.ts +2 -0
  169. package/dist/runtime/worldReplication.js +1 -1
  170. package/dist/scene/assetCatalog.d.ts +2 -0
  171. package/dist/scene/behaviorRuntime.d.ts +26 -5
  172. package/dist/scene/behaviorRuntime.js +263 -16
  173. package/dist/scene/behaviors.d.ts +30 -1
  174. package/dist/scene/behaviors.js +29 -0
  175. package/dist/scene/entityStore.d.ts +14 -3
  176. package/dist/scene/entityStore.js +45 -9
  177. package/dist/scene/mount.d.ts +9 -0
  178. package/dist/scene/mount.js +35 -0
  179. package/dist/scene/possession.d.ts +2 -0
  180. package/dist/scene/possession.js +21 -1
  181. package/dist/scene/sceneRaycast.d.ts +7 -0
  182. package/dist/scene/sceneRaycast.js +55 -0
  183. package/dist/scene/spatial.d.ts +20 -1
  184. package/dist/scene/spatial.js +94 -2
  185. package/dist/scene/vehicleSeat.d.ts +36 -2
  186. package/dist/scene/vehicleSeat.js +89 -2
  187. package/dist/stats/accumulatorMeter.d.ts +10 -0
  188. package/dist/stats/accumulatorMeter.js +6 -0
  189. package/dist/stats/eventMeter.d.ts +9 -2
  190. package/dist/stats/eventMeter.js +5 -2
  191. package/dist/store/defineStore.d.ts +3 -1
  192. package/dist/store/defineStore.js +3 -1
  193. package/dist/store/observableKeyedStore.d.ts +1 -1
  194. package/dist/store/observableKeyedStore.js +8 -6
  195. package/dist/time/simClock.d.ts +6 -2
  196. package/dist/time/simClock.js +5 -0
  197. package/dist/vfx/particleDirector.d.ts +58 -6
  198. package/dist/vfx/particleDirector.js +113 -22
  199. package/dist/vfx/particles.d.ts +68 -5
  200. package/dist/vfx/particles.js +284 -32
  201. package/dist/visibility/assetStreaming.d.ts +21 -3
  202. package/dist/visibility/assetStreaming.js +108 -24
  203. package/dist/visibility/settings.d.ts +8 -2
  204. package/dist/visibility/settings.js +3 -0
  205. package/dist/visibility/visibilitySystem.js +1 -0
  206. package/dist/work/expedition.d.ts +110 -0
  207. package/dist/work/expedition.js +195 -0
  208. package/dist/work/staffedStation.d.ts +29 -0
  209. package/dist/work/staffedStation.js +27 -0
  210. package/dist/world/authoredAnimation.d.ts +38 -0
  211. package/dist/world/authoredAnimation.js +99 -0
  212. package/dist/world/authoredObjects.d.ts +24 -4
  213. package/dist/world/authoredObjects.js +43 -16
  214. package/dist/world/authoredSimulation.d.ts +74 -0
  215. package/dist/world/authoredSimulation.js +302 -0
  216. package/dist/world/authoredWeather.d.ts +120 -0
  217. package/dist/world/authoredWeather.js +314 -0
  218. package/dist/world/buildingKit.d.ts +8 -3
  219. package/dist/world/buildingKit.js +21 -8
  220. package/dist/world/environmentForces.d.ts +21 -0
  221. package/dist/world/environmentForces.js +42 -0
  222. package/dist/world/features.d.ts +3 -3
  223. package/dist/world/footprintGrid.d.ts +55 -0
  224. package/dist/world/footprintGrid.js +201 -0
  225. package/dist/world/grassKind.d.ts +10 -0
  226. package/dist/world/grassKind.js +22 -0
  227. package/dist/world/pathTerrain.d.ts +1 -1
  228. package/dist/world/terraform.d.ts +2 -2
  229. package/dist/world/terraform.js +46 -18
  230. package/dist/world/weather.d.ts +17 -0
  231. package/dist/world/weather.js +116 -20
  232. package/dist/world/worldSolids.d.ts +11 -0
  233. package/dist/world/worldSolids.js +112 -1
  234. package/dist/world.d.ts +5 -5
  235. package/dist/world.js +4 -4
  236. package/package.json +1 -1
  237. package/skills/ce-handoff/SKILL.md +1 -1
  238. package/skills/game-design/SKILL.md +2 -0
  239. package/skills/jgengine/SKILL.md +23 -2
  240. package/skills/jgengine/api.md +28 -17
  241. package/skills/jgengine/recipes/minimal-game.md +7 -2
  242. package/skills/jgengine-combat/SKILL.md +8 -2
  243. package/skills/jgengine-combat/api.md +22 -10
  244. package/skills/jgengine-combat/recipes/portable-runtime-state.md +60 -6
  245. package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +37 -3
  246. package/skills/jgengine-combat/reference.md +24 -2
  247. package/skills/jgengine-gameplay/SKILL.md +63 -0
  248. package/skills/jgengine-gameplay/api.md +131 -37
  249. package/skills/jgengine-gameplay/capabilities.md +68 -0
  250. package/skills/jgengine-gameplay/recipes/device-save-status.md +46 -0
  251. package/skills/jgengine-gameplay/recipes/expeditions.md +108 -0
  252. package/skills/jgengine-gameplay/recipes/narrative-authoring.md +76 -0
  253. package/skills/jgengine-gameplay/recipes/paged-item-storage.md +101 -0
  254. package/skills/jgengine-gameplay/recipes/quest-authoring.md +63 -0
  255. package/skills/jgengine-gameplay/recipes/shaped-inventory.md +50 -0
  256. package/skills/jgengine-gameplay/reference-content-validation.md +74 -0
  257. package/skills/jgengine-gameplay/reference-systems.md +119 -0
  258. package/skills/jgengine-world/SKILL.md +12 -3
  259. package/skills/jgengine-world/api.md +201 -58
  260. package/skills/jgengine-world/capabilities.md +116 -3
  261. package/skills/jgengine-world/recipes/character-animation.md +31 -8
  262. package/skills/jgengine-world/recipes/controls.md +4 -0
  263. package/skills/jgengine-world/recipes/npc-senses.md +12 -0
  264. package/skills/jgengine-world/recipes/vehicle-feel.md +3 -1
  265. package/skills/jgengine-world/reference.md +167 -5
  266. package/skills/jgengine-world/visibility.md +28 -1
@@ -0,0 +1,38 @@
1
+ import type { AuthoredAnimation } from "./authoredObjects.js";
2
+ /** Structural marker input; immutable editor scene documents satisfy it. */
3
+ export interface AuthoredAnimationDocumentLike {
4
+ readonly markers: readonly {
5
+ readonly id: string;
6
+ readonly meta?: Readonly<Record<string, unknown>>;
7
+ }[];
8
+ }
9
+ /** Rejected saved animation data with a document location and a repair. */
10
+ export interface AuthoredAnimationDiagnostic {
11
+ readonly path: string;
12
+ readonly message: string;
13
+ readonly repair: string;
14
+ }
15
+ /** Resolved marker animation or the caller's unchanged default, with rejected-value diagnostics. */
16
+ export interface AuthoredAnimationResult {
17
+ readonly animation: AuthoredAnimation | undefined;
18
+ readonly diagnostics: readonly AuthoredAnimationDiagnostic[];
19
+ }
20
+ /**
21
+ * Resolves a caller-selected marker's animation. Authored configuration replaces game defaults;
22
+ * omitted or malformed data retains the exact default. Partial roles remain available for editing.
23
+ * Asset clip and rig compatibility is diagnosed by the animation renderer.
24
+ * @capability authored-animation bind saved character animation without copying game-side validation
25
+ */
26
+ export declare function readAuthoredAnimation(document: AuthoredAnimationDocumentLike, markerId: string, defaults?: AuthoredAnimation): AuthoredAnimationResult;
27
+ /**
28
+ * Validates one saved animation value at the caller's document path without scanning markers.
29
+ * Omitted or malformed values retain the exact default; valid authored configuration replaces it whole.
30
+ * @capability authored-animation validate a located animation override in a single-pass document resolver
31
+ */
32
+ export declare function readAuthoredAnimationValue(value: unknown, path: string, defaults?: AuthoredAnimation): AuthoredAnimationResult;
33
+ /**
34
+ * Reads the latest immutable document each call, validating only when document identity changes.
35
+ * The caller owns the marker-to-character association and its asset-specific animation defaults.
36
+ * @capability authored-animation consume live authored character animation with bounded per-frame work
37
+ */
38
+ export declare function createAuthoredAnimationReader(getDocument: () => AuthoredAnimationDocumentLike, markerId: string, defaults?: AuthoredAnimation): () => AuthoredAnimationResult;
@@ -0,0 +1,99 @@
1
+ import { validateAnimGraph } from "../anim/animGraph.js";
2
+ function record(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ /**
6
+ * Resolves a caller-selected marker's animation. Authored configuration replaces game defaults;
7
+ * omitted or malformed data retains the exact default. Partial roles remain available for editing.
8
+ * Asset clip and rig compatibility is diagnosed by the animation renderer.
9
+ * @capability authored-animation bind saved character animation without copying game-side validation
10
+ */
11
+ export function readAuthoredAnimation(document, markerId, defaults) {
12
+ const index = document.markers.findIndex((marker) => marker.id === markerId);
13
+ return readAuthoredAnimationValue(document.markers[index]?.meta?.animation, `markers[${index}].meta.animation`, defaults);
14
+ }
15
+ /**
16
+ * Validates one saved animation value at the caller's document path without scanning markers.
17
+ * Omitted or malformed values retain the exact default; valid authored configuration replaces it whole.
18
+ * @capability authored-animation validate a located animation override in a single-pass document resolver
19
+ */
20
+ export function readAuthoredAnimationValue(value, path, defaults) {
21
+ const diagnostics = [];
22
+ if (value === undefined)
23
+ return { animation: defaults, diagnostics };
24
+ if (value === "auto" || value === "none")
25
+ return { animation: value, diagnostics };
26
+ const reject = (location, message, requirement) => {
27
+ diagnostics.push({ path: location, message, repair: `Use ${requirement}, or remove the animation override to inherit the game setting.` });
28
+ };
29
+ if (!record(value)) {
30
+ reject(path, "Animation must be an object, auto, or none", "an animation object, auto, or none");
31
+ return { animation: defaults, diagnostics };
32
+ }
33
+ if (value.clock !== undefined && value.clock !== "real" && value.clock !== "game")
34
+ reject(`${path}.clock`, "clock must be real or game", "real or game");
35
+ if (value.auto !== undefined && value.auto !== true)
36
+ reject(`${path}.auto`, "auto must be true when supplied", "true, or omit auto to use explicit configuration");
37
+ for (const key of ["clip"]) {
38
+ if (value[key] !== undefined && typeof value[key] !== "string")
39
+ reject(`${path}.${key}`, `${key} must be a string`, "a clip-name string");
40
+ }
41
+ for (const key of ["loop", "paused"]) {
42
+ if (value[key] !== undefined && typeof value[key] !== "boolean")
43
+ reject(`${path}.${key}`, `${key} must be a boolean`, "true or false");
44
+ }
45
+ for (const key of ["timeScale", "time"]) {
46
+ if (value[key] !== undefined && (typeof value[key] !== "number" || !Number.isFinite(value[key])))
47
+ reject(`${path}.${key}`, `${key} must be a finite number`, "a finite number");
48
+ }
49
+ if (value.states !== undefined) {
50
+ if (!record(value.states))
51
+ reject(`${path}.states`, "states must be an object", "a role-mapping object");
52
+ else {
53
+ for (const key of ["idle", "walk", "run"]) {
54
+ if (value.states[key] !== undefined && typeof value.states[key] !== "string")
55
+ reject(`${path}.states.${key}`, `${key} must be a string`, "a clip-name string");
56
+ }
57
+ for (const key of ["walkSpeed", "runSpeed", "fadeSec"]) {
58
+ const number = value.states[key];
59
+ if (number !== undefined && (typeof number !== "number" || !Number.isFinite(number)))
60
+ reject(`${path}.states.${key}`, `${key} must be a finite number`, "a finite number");
61
+ }
62
+ }
63
+ }
64
+ if (value.oneShots !== undefined) {
65
+ if (!record(value.oneShots))
66
+ reject(`${path}.oneShots`, "oneShots must be an object", "an event-to-clip mapping object");
67
+ else
68
+ for (const [event, clips] of Object.entries(value.oneShots)) {
69
+ if (typeof clips !== "string" && !(Array.isArray(clips) && clips.every((clip) => typeof clip === "string")))
70
+ reject(`${path}.oneShots[${JSON.stringify(event)}]`, "One-shot clips must be a string or an array of strings", "a clip-name string or an array of clip-name strings");
71
+ }
72
+ }
73
+ let animation = value;
74
+ if (value.graph !== undefined) {
75
+ const graph = validateAnimGraph(value.graph);
76
+ for (const diagnostic of graph.diagnostics)
77
+ diagnostics.push({ ...diagnostic, path: `${path}.graph${diagnostic.path === "" ? "" : `.${diagnostic.path}`}` });
78
+ if (graph.graph !== undefined)
79
+ animation = { ...value, graph: graph.graph };
80
+ }
81
+ return { animation: diagnostics.length === 0 ? animation : defaults, diagnostics };
82
+ }
83
+ /**
84
+ * Reads the latest immutable document each call, validating only when document identity changes.
85
+ * The caller owns the marker-to-character association and its asset-specific animation defaults.
86
+ * @capability authored-animation consume live authored character animation with bounded per-frame work
87
+ */
88
+ export function createAuthoredAnimationReader(getDocument, markerId, defaults) {
89
+ let previous;
90
+ let result;
91
+ return () => {
92
+ const document = getDocument();
93
+ if (document !== previous) {
94
+ result = readAuthoredAnimation(document, markerId, defaults);
95
+ previous = document;
96
+ }
97
+ return result;
98
+ };
99
+ }
@@ -1,3 +1,4 @@
1
+ import { type AuthoredAnimationDiagnostic } from "./authoredAnimation.js";
1
2
  import type { ModelAnimationConfig } from "../game/playableGame.js";
2
3
  import type { SceneMarkerLike } from "./sceneShapes.js";
3
4
  /** A placement's authored rig animation override — the stored `marker.meta.animation` contract (#1274). */
@@ -53,10 +54,8 @@ export interface PlaceAuthoredObjectsOptions {
53
54
  */
54
55
  export declare function markerCatalogId(marker: AuthoredObjectMarkerLike): string | null;
55
56
  /**
56
- * The authored per-placement rig animation override stored at `marker.meta.animation` (#1274), or
57
- * `undefined` when absent/malformed. `"auto"` / `"none"` pass through as the string modes; any other
58
- * object is a `ModelAnimationConfig` the shell applies verbatim (validated at author time in the
59
- * editor). Runtime trusts the persisted document here exactly like it trusts position and rotation.
57
+ * Validated per-placement animation from `marker.meta.animation`. Missing or malformed overrides
58
+ * return undefined so the placed object retains its catalog animation; valid data replaces it whole.
60
59
  * @capability authored-objects per-placement animation override from marker.meta.animation
61
60
  */
62
61
  export declare function markerAnimation(marker: AuthoredObjectMarkerLike): AuthoredAnimation | undefined;
@@ -80,6 +79,18 @@ export interface ResolveAuthoredObjectsOptions {
80
79
  * @capability authored-objects place catalog mesh props from an editor document
81
80
  */
82
81
  export declare function resolveAuthoredObjects(document: AuthoredObjectsDocumentLike, options?: ResolveAuthoredObjectsOptions): AuthoredObject[];
82
+ /** Resolved catalog props and located repairs for rejected per-placement animation overrides. */
83
+ export interface AuthoredObjectsResult {
84
+ objects: AuthoredObject[];
85
+ diagnostics: readonly AuthoredAnimationDiagnostic[];
86
+ }
87
+ /**
88
+ * Resolves catalog props and validates their animation in one document pass. Rejected overrides
89
+ * are omitted so each model inherits its original catalog setting. Excluded and unplaced markers
90
+ * remain the responsibility of their own consumers.
91
+ * @capability authored-objects resolve static placements with located animation repairs
92
+ */
93
+ export declare function resolveAuthoredObjectsWithDiagnostics(document: AuthoredObjectsDocumentLike, options?: ResolveAuthoredObjectsOptions): AuthoredObjectsResult;
83
94
  /**
84
95
  * Places resolved authored objects into an object store, grounding each on `sampleHeight(x,z)` plus
85
96
  * per-object and options vertical offsets. Returns the instance ids that were placed (or kept).
@@ -88,3 +99,12 @@ export declare function resolveAuthoredObjects(document: AuthoredObjectsDocument
88
99
  export declare function placeAuthoredObjects(store: AuthoredObjectPlaceTarget, objects: readonly AuthoredObject[], sampleHeight: (x: number, z: number) => number, options?: PlaceAuthoredObjectsOptions): string[];
89
100
  /** Convenience: resolve a document then place every authored catalog prop. */
90
101
  export declare function placeAuthoredObjectsFromDocument(store: AuthoredObjectPlaceTarget, document: AuthoredObjectsDocumentLike, sampleHeight: (x: number, z: number) => number, options?: PlaceAuthoredObjectsOptions): string[];
102
+ /**
103
+ * Update changed authored placements and remove previous authored ids absent from the next document.
104
+ * Initial placement keeps game onInit state; unrelated document edits preserve runtime prop state.
105
+ * Call on document changes, never on simulation ticks; runtime-created objects remain untouched.
106
+ * @capability sync-authored-objects synchronize edited catalog prop poses, elevation and removal through the existing object store
107
+ */
108
+ export declare function syncAuthoredObjects(store: AuthoredObjectPlaceTarget & {
109
+ remove(instanceId: string): boolean;
110
+ }, objects: readonly AuthoredObject[], previousObjects: readonly AuthoredObject[], sampleHeight: (x: number, z: number) => number, options?: Pick<PlaceAuthoredObjectsOptions, "verticalOffset">): AuthoredObject[];
@@ -1,3 +1,4 @@
1
+ import { readAuthoredAnimationValue } from "./authoredAnimation.js";
1
2
  function metaString(meta, key) {
2
3
  const value = meta?.[key];
3
4
  return typeof value === "string" && value.length > 0 ? value : null;
@@ -16,23 +17,13 @@ export function markerCatalogId(marker) {
16
17
  return marker.catalogId;
17
18
  return metaString(marker.meta, "catalogId");
18
19
  }
19
- function isRecord(value) {
20
- return typeof value === "object" && value !== null && !Array.isArray(value);
21
- }
22
20
  /**
23
- * The authored per-placement rig animation override stored at `marker.meta.animation` (#1274), or
24
- * `undefined` when absent/malformed. `"auto"` / `"none"` pass through as the string modes; any other
25
- * object is a `ModelAnimationConfig` the shell applies verbatim (validated at author time in the
26
- * editor). Runtime trusts the persisted document here exactly like it trusts position and rotation.
21
+ * Validated per-placement animation from `marker.meta.animation`. Missing or malformed overrides
22
+ * return undefined so the placed object retains its catalog animation; valid data replaces it whole.
27
23
  * @capability authored-objects per-placement animation override from marker.meta.animation
28
24
  */
29
25
  export function markerAnimation(marker) {
30
- const value = marker.meta?.["animation"];
31
- if (value === "auto" || value === "none")
32
- return value;
33
- if (isRecord(value))
34
- return value;
35
- return undefined;
26
+ return readAuthoredAnimationValue(marker.meta?.["animation"], "meta.animation").animation;
36
27
  }
37
28
  function markerVerticalOffset(marker) {
38
29
  const fromMeta = metaNumber(marker.meta, "verticalOffset") ??
@@ -55,15 +46,29 @@ export const ENTITY_MARKER_KINDS = ["mob", "boss"];
55
46
  * @capability authored-objects place catalog mesh props from an editor document
56
47
  */
57
48
  export function resolveAuthoredObjects(document, options = {}) {
49
+ return resolveAuthoredObjectsWithDiagnostics(document, options).objects;
50
+ }
51
+ /**
52
+ * Resolves catalog props and validates their animation in one document pass. Rejected overrides
53
+ * are omitted so each model inherits its original catalog setting. Excluded and unplaced markers
54
+ * remain the responsibility of their own consumers.
55
+ * @capability authored-objects resolve static placements with located animation repairs
56
+ */
57
+ export function resolveAuthoredObjectsWithDiagnostics(document, options = {}) {
58
58
  const excluded = new Set(options.excludeKinds ?? ENTITY_MARKER_KINDS);
59
59
  const out = [];
60
- for (const marker of document.markers) {
60
+ const diagnostics = [];
61
+ for (let index = 0; index < document.markers.length; index += 1) {
62
+ const marker = document.markers[index];
61
63
  if (excluded.has(marker.kind))
62
64
  continue;
63
65
  const catalogId = markerCatalogId(marker);
64
66
  if (catalogId === null)
65
67
  continue;
66
- const animation = markerAnimation(marker);
68
+ const result = readAuthoredAnimationValue(marker.meta?.["animation"], `markers[${index}].meta.animation`);
69
+ const animation = result.animation;
70
+ for (const diagnostic of result.diagnostics)
71
+ diagnostics.push(diagnostic);
67
72
  out.push({
68
73
  catalogId,
69
74
  x: marker.position.x,
@@ -74,7 +79,7 @@ export function resolveAuthoredObjects(document, options = {}) {
74
79
  ...(animation === undefined ? {} : { animation }),
75
80
  });
76
81
  }
77
- return out;
82
+ return { objects: out, diagnostics };
78
83
  }
79
84
  /**
80
85
  * Places resolved authored objects into an object store, grounding each on `sampleHeight(x,z)` plus
@@ -100,3 +105,25 @@ export function placeAuthoredObjects(store, objects, sampleHeight, options = {})
100
105
  export function placeAuthoredObjectsFromDocument(store, document, sampleHeight, options = {}) {
101
106
  return placeAuthoredObjects(store, resolveAuthoredObjects(document), sampleHeight, options);
102
107
  }
108
+ /**
109
+ * Update changed authored placements and remove previous authored ids absent from the next document.
110
+ * Initial placement keeps game onInit state; unrelated document edits preserve runtime prop state.
111
+ * Call on document changes, never on simulation ticks; runtime-created objects remain untouched.
112
+ * @capability sync-authored-objects synchronize edited catalog prop poses, elevation and removal through the existing object store
113
+ */
114
+ export function syncAuthoredObjects(store, objects, previousObjects, sampleHeight, options = {}) {
115
+ const nextIds = new Set(objects.map((object) => object.instanceId));
116
+ if (nextIds.size !== objects.length)
117
+ throw new Error("Authored object ids must be unique");
118
+ const previous = new Map(previousObjects.map((object) => [object.instanceId, object]));
119
+ for (const object of objects) {
120
+ const before = previous.get(object.instanceId);
121
+ if (before !== undefined && JSON.stringify(before) === JSON.stringify(object))
122
+ continue;
123
+ placeAuthoredObjects(store, [object], sampleHeight, { ...options, onExisting: before === undefined ? "keep" : "replace" });
124
+ }
125
+ for (const object of previousObjects)
126
+ if (!nextIds.has(object.instanceId))
127
+ store.remove(object.instanceId);
128
+ return objects.map((object) => ({ ...object, ...(typeof object.animation === "object" ? { animation: structuredClone(object.animation) } : {}) }));
129
+ }
@@ -0,0 +1,74 @@
1
+ import { type FlockStepAgent } from "../ai/flock.js";
2
+ import type { EditorDocument } from "../editor/types.js";
3
+ import { type AuthoredWeatherSample, type WeatherExposure, type WeatherExposureSnapshot, type WeatherExposureSurface } from "./authoredWeather.js";
4
+ import { type FireCell, type FireGrid } from "./weather.js";
5
+ import type { ParticleDirector } from "../vfx/particleDirector.js";
6
+ import type { Vec3 } from "../vfx/particles.js";
7
+ /** A watched surface is sampled in metres. Its accumulation survives runtime save/restore. */
8
+ export interface AuthoredSurface extends WeatherExposureSurface {
9
+ y?: number;
10
+ }
11
+ /** Appearance adapters consume these units without owning weather state or its clock. */
12
+ export interface EnvironmentAppearanceSignals {
13
+ timeSeconds: number;
14
+ wind: Vec3;
15
+ wetness: number;
16
+ snow: number;
17
+ exposure: number;
18
+ /** Normalized local fire heat, independent of the temperature offset in degrees Celsius. */
19
+ heat: number;
20
+ temperatureOffsetC: number;
21
+ }
22
+ /** Runtime state excludes authored configuration and cosmetic particle pools. */
23
+ export interface AuthoredSimulationSnapshot {
24
+ surfaces: WeatherExposureSnapshot;
25
+ watched: AuthoredSurface[];
26
+ fires: {
27
+ id: string;
28
+ cells: FireCell[];
29
+ }[];
30
+ flocks: {
31
+ id: string;
32
+ agents: FlockStepAgent[];
33
+ routeIndex: number;
34
+ }[];
35
+ }
36
+ /** A habitat's live poses; game species determine appearance and gameplay actor policy. */
37
+ export interface AuthoredFlockState {
38
+ readonly id: string;
39
+ readonly species: string;
40
+ readonly role: "cosmetic" | "gameplay";
41
+ readonly agents: readonly Readonly<FlockStepAgent>[];
42
+ readonly routeIndex: number;
43
+ }
44
+ /** Engine-owned authority uses the caller's simulation clock; render quality cannot change it. */
45
+ export interface AuthoredSimulationRuntime {
46
+ sample(x: number, z: number): AuthoredWeatherSample;
47
+ appearanceAt(surfaceId: string, position: Vec3): EnvironmentAppearanceSignals;
48
+ /** Fraction of open sky from bounded authored shelter volumes. World Y points up. */
49
+ exposureAt(x: number, y: number, z: number): number;
50
+ readonly surfaces: WeatherExposure;
51
+ watch(surface: AuthoredSurface): void;
52
+ forget(id: string): void;
53
+ /** XZ wind adapted to [x,0,z]; response is 1/second, cap is metres/second² (both 0..1e12). */
54
+ windAcceleration(position: Vec3, response: number, maxAcceleration: number): Vec3;
55
+ /** Sum authored fields and wind (response 1/second), capped in metres/second² by game policy. */
56
+ accelerationAt(position: Vec3, timeSeconds: number, windResponse: number, maxAcceleration: number, mask?: number, out?: [number, number, number]): Vec3;
57
+ fire(id: string): FireGrid | undefined;
58
+ /** Cosmetic poses render directly; gameplay habitats are consumed by game actor adapters. */
59
+ flocks(): readonly AuthoredFlockState[];
60
+ step(gameDt: number): void;
61
+ retune(document: EditorDocument): void;
62
+ snapshot(): AuthoredSimulationSnapshot;
63
+ restore(state: AuthoredSimulationSnapshot): void;
64
+ dispose(): void;
65
+ }
66
+ /** Compose authored weather, shelter, accumulation, named effect intents and fire with one clock.
67
+ * @capability authored-environment compose authored weather, shelter, accumulation, fire, flocks and effects using one simulation clock
68
+ */
69
+ export declare function createAuthoredSimulation(options: {
70
+ document?: EditorDocument;
71
+ timeSeconds: () => number;
72
+ particles?: ParticleDirector;
73
+ maxSurfaces?: number;
74
+ }): AuthoredSimulationRuntime;