@its-not-rocket-science/ananke 0.1.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.
- package/CHANGELOG.md +135 -0
- package/LICENSE +21 -0
- package/README.md +2199 -0
- package/STABLE_API.md +266 -0
- package/dist/src/anatomy/anatomy-compiler.d.ts +14 -0
- package/dist/src/anatomy/anatomy-compiler.js +277 -0
- package/dist/src/anatomy/anatomy-contracts.d.ts +94 -0
- package/dist/src/anatomy/anatomy-contracts.js +1 -0
- package/dist/src/anatomy/anatomy-helpers.d.ts +82 -0
- package/dist/src/anatomy/anatomy-helpers.js +233 -0
- package/dist/src/anatomy/anatomy-schema.d.ts +28 -0
- package/dist/src/anatomy/anatomy-schema.js +388 -0
- package/dist/src/anatomy/index.d.ts +4 -0
- package/dist/src/anatomy/index.js +4 -0
- package/dist/src/archetypes.d.ts +87 -0
- package/dist/src/archetypes.js +285 -0
- package/dist/src/arena.d.ts +173 -0
- package/dist/src/arena.js +695 -0
- package/dist/src/bridge/bridge-engine.d.ts +46 -0
- package/dist/src/bridge/bridge-engine.js +252 -0
- package/dist/src/bridge/index.d.ts +4 -0
- package/dist/src/bridge/index.js +5 -0
- package/dist/src/bridge/interpolation.d.ts +64 -0
- package/dist/src/bridge/interpolation.js +130 -0
- package/dist/src/bridge/mapping.d.ts +33 -0
- package/dist/src/bridge/mapping.js +54 -0
- package/dist/src/bridge/types.d.ts +94 -0
- package/dist/src/bridge/types.js +2 -0
- package/dist/src/campaign.d.ts +141 -0
- package/dist/src/campaign.js +235 -0
- package/dist/src/channels.d.ts +15 -0
- package/dist/src/channels.js +20 -0
- package/dist/src/chronicle.d.ts +124 -0
- package/dist/src/chronicle.js +232 -0
- package/dist/src/collective-activities.d.ts +154 -0
- package/dist/src/collective-activities.js +247 -0
- package/dist/src/competence/acoustic.d.ts +101 -0
- package/dist/src/competence/acoustic.js +242 -0
- package/dist/src/competence/catalogue.d.ts +30 -0
- package/dist/src/competence/catalogue.js +241 -0
- package/dist/src/competence/crafting.d.ts +35 -0
- package/dist/src/competence/crafting.js +88 -0
- package/dist/src/competence/engineering.d.ts +53 -0
- package/dist/src/competence/engineering.js +108 -0
- package/dist/src/competence/framework.d.ts +68 -0
- package/dist/src/competence/framework.js +694 -0
- package/dist/src/competence/index.d.ts +12 -0
- package/dist/src/competence/index.js +13 -0
- package/dist/src/competence/interspecies.d.ts +81 -0
- package/dist/src/competence/interspecies.js +108 -0
- package/dist/src/competence/language.d.ts +79 -0
- package/dist/src/competence/language.js +115 -0
- package/dist/src/competence/naturalist.d.ts +97 -0
- package/dist/src/competence/naturalist.js +187 -0
- package/dist/src/competence/navigation.d.ts +24 -0
- package/dist/src/competence/navigation.js +48 -0
- package/dist/src/competence/performance.d.ts +125 -0
- package/dist/src/competence/performance.js +210 -0
- package/dist/src/competence/teaching.d.ts +64 -0
- package/dist/src/competence/teaching.js +121 -0
- package/dist/src/competence/willpower.d.ts +74 -0
- package/dist/src/competence/willpower.js +114 -0
- package/dist/src/crafting/index.d.ts +55 -0
- package/dist/src/crafting/index.js +229 -0
- package/dist/src/crafting/manufacturing.d.ts +83 -0
- package/dist/src/crafting/manufacturing.js +165 -0
- package/dist/src/crafting/materials.d.ts +53 -0
- package/dist/src/crafting/materials.js +120 -0
- package/dist/src/crafting/recipes.d.ts +75 -0
- package/dist/src/crafting/recipes.js +233 -0
- package/dist/src/crafting/workshops.d.ts +61 -0
- package/dist/src/crafting/workshops.js +170 -0
- package/dist/src/debug.d.ts +86 -0
- package/dist/src/debug.js +76 -0
- package/dist/src/derive.d.ts +21 -0
- package/dist/src/derive.js +88 -0
- package/dist/src/describe.d.ts +29 -0
- package/dist/src/describe.js +276 -0
- package/dist/src/dialogue.d.ts +122 -0
- package/dist/src/dialogue.js +266 -0
- package/dist/src/dist.d.ts +20 -0
- package/dist/src/dist.js +39 -0
- package/dist/src/downtime.d.ts +89 -0
- package/dist/src/downtime.js +391 -0
- package/dist/src/economy.d.ts +116 -0
- package/dist/src/economy.js +182 -0
- package/dist/src/emotional-contagion.d.ts +142 -0
- package/dist/src/emotional-contagion.js +274 -0
- package/dist/src/equipment.d.ts +206 -0
- package/dist/src/equipment.js +598 -0
- package/dist/src/faction.d.ts +102 -0
- package/dist/src/faction.js +237 -0
- package/dist/src/generate.d.ts +35 -0
- package/dist/src/generate.js +166 -0
- package/dist/src/index.d.ts +42 -0
- package/dist/src/index.js +54 -0
- package/dist/src/inheritance.d.ts +69 -0
- package/dist/src/inheritance.js +136 -0
- package/dist/src/inventory.d.ts +194 -0
- package/dist/src/inventory.js +637 -0
- package/dist/src/item-durability.d.ts +69 -0
- package/dist/src/item-durability.js +308 -0
- package/dist/src/legend.d.ts +97 -0
- package/dist/src/legend.js +269 -0
- package/dist/src/lod.d.ts +9 -0
- package/dist/src/lod.js +84 -0
- package/dist/src/metrics.d.ts +51 -0
- package/dist/src/metrics.js +91 -0
- package/dist/src/model3d.d.ts +138 -0
- package/dist/src/model3d.js +214 -0
- package/dist/src/mythology.d.ts +101 -0
- package/dist/src/mythology.js +308 -0
- package/dist/src/narrative-render.d.ts +42 -0
- package/dist/src/narrative-render.js +194 -0
- package/dist/src/narrative-stress.d.ts +123 -0
- package/dist/src/narrative-stress.js +183 -0
- package/dist/src/narrative.d.ts +44 -0
- package/dist/src/narrative.js +257 -0
- package/dist/src/party.d.ts +70 -0
- package/dist/src/party.js +226 -0
- package/dist/src/polity.d.ts +262 -0
- package/dist/src/polity.js +398 -0
- package/dist/src/presets.d.ts +42 -0
- package/dist/src/presets.js +170 -0
- package/dist/src/progression.d.ts +170 -0
- package/dist/src/progression.js +256 -0
- package/dist/src/quest-generators.d.ts +76 -0
- package/dist/src/quest-generators.js +534 -0
- package/dist/src/quest.d.ts +239 -0
- package/dist/src/quest.js +520 -0
- package/dist/src/relationships-effects.d.ts +75 -0
- package/dist/src/relationships-effects.js +219 -0
- package/dist/src/relationships.d.ts +104 -0
- package/dist/src/relationships.js +347 -0
- package/dist/src/replay.d.ts +47 -0
- package/dist/src/replay.js +82 -0
- package/dist/src/rng.d.ts +9 -0
- package/dist/src/rng.js +37 -0
- package/dist/src/settlement-services.d.ts +67 -0
- package/dist/src/settlement-services.js +267 -0
- package/dist/src/settlement.d.ts +143 -0
- package/dist/src/settlement.js +419 -0
- package/dist/src/sim/action.d.ts +28 -0
- package/dist/src/sim/action.js +12 -0
- package/dist/src/sim/aging.d.ts +95 -0
- package/dist/src/sim/aging.js +243 -0
- package/dist/src/sim/ai/decide.d.ts +10 -0
- package/dist/src/sim/ai/decide.js +267 -0
- package/dist/src/sim/ai/perception.d.ts +12 -0
- package/dist/src/sim/ai/perception.js +54 -0
- package/dist/src/sim/ai/personality.d.ts +54 -0
- package/dist/src/sim/ai/personality.js +202 -0
- package/dist/src/sim/ai/presets.d.ts +2 -0
- package/dist/src/sim/ai/presets.js +28 -0
- package/dist/src/sim/ai/system.d.ts +6 -0
- package/dist/src/sim/ai/system.js +13 -0
- package/dist/src/sim/ai/targeting.d.ts +8 -0
- package/dist/src/sim/ai/targeting.js +42 -0
- package/dist/src/sim/ai/types.d.ts +14 -0
- package/dist/src/sim/ai/types.js +1 -0
- package/dist/src/sim/body.d.ts +9 -0
- package/dist/src/sim/body.js +32 -0
- package/dist/src/sim/bodyplan.d.ts +161 -0
- package/dist/src/sim/bodyplan.js +677 -0
- package/dist/src/sim/capability.d.ts +135 -0
- package/dist/src/sim/capability.js +8 -0
- package/dist/src/sim/combat.d.ts +21 -0
- package/dist/src/sim/combat.js +77 -0
- package/dist/src/sim/commandBuilders.d.ts +11 -0
- package/dist/src/sim/commandBuilders.js +39 -0
- package/dist/src/sim/commands.d.ts +71 -0
- package/dist/src/sim/commands.js +8 -0
- package/dist/src/sim/condition.d.ts +35 -0
- package/dist/src/sim/condition.js +21 -0
- package/dist/src/sim/cone.d.ts +40 -0
- package/dist/src/sim/cone.js +44 -0
- package/dist/src/sim/context.d.ts +68 -0
- package/dist/src/sim/context.js +1 -0
- package/dist/src/sim/density.d.ts +14 -0
- package/dist/src/sim/density.js +33 -0
- package/dist/src/sim/disease.d.ts +141 -0
- package/dist/src/sim/disease.js +353 -0
- package/dist/src/sim/entity.d.ts +251 -0
- package/dist/src/sim/entity.js +19 -0
- package/dist/src/sim/events.d.ts +25 -0
- package/dist/src/sim/events.js +5 -0
- package/dist/src/sim/explosion.d.ts +40 -0
- package/dist/src/sim/explosion.js +40 -0
- package/dist/src/sim/formation-unit.d.ts +138 -0
- package/dist/src/sim/formation-unit.js +197 -0
- package/dist/src/sim/formation.d.ts +12 -0
- package/dist/src/sim/formation.js +54 -0
- package/dist/src/sim/frontage.d.ts +30 -0
- package/dist/src/sim/frontage.js +84 -0
- package/dist/src/sim/grapple.d.ts +100 -0
- package/dist/src/sim/grapple.js +480 -0
- package/dist/src/sim/hazard.d.ts +104 -0
- package/dist/src/sim/hazard.js +201 -0
- package/dist/src/sim/hydrostatic.d.ts +58 -0
- package/dist/src/sim/hydrostatic.js +117 -0
- package/dist/src/sim/impairment.d.ts +20 -0
- package/dist/src/sim/impairment.js +162 -0
- package/dist/src/sim/indexing.d.ts +7 -0
- package/dist/src/sim/indexing.js +7 -0
- package/dist/src/sim/injury.d.ts +54 -0
- package/dist/src/sim/injury.js +66 -0
- package/dist/src/sim/intent.d.ts +26 -0
- package/dist/src/sim/intent.js +7 -0
- package/dist/src/sim/kernel.d.ts +45 -0
- package/dist/src/sim/kernel.js +1992 -0
- package/dist/src/sim/kinds.d.ts +64 -0
- package/dist/src/sim/kinds.js +56 -0
- package/dist/src/sim/knockback.d.ts +50 -0
- package/dist/src/sim/knockback.js +82 -0
- package/dist/src/sim/limb.d.ts +48 -0
- package/dist/src/sim/limb.js +78 -0
- package/dist/src/sim/medical.d.ts +32 -0
- package/dist/src/sim/medical.js +33 -0
- package/dist/src/sim/morale.d.ts +69 -0
- package/dist/src/sim/morale.js +92 -0
- package/dist/src/sim/mount.d.ts +150 -0
- package/dist/src/sim/mount.js +225 -0
- package/dist/src/sim/nutrition.d.ts +74 -0
- package/dist/src/sim/nutrition.js +168 -0
- package/dist/src/sim/occlusion.d.ts +8 -0
- package/dist/src/sim/occlusion.js +71 -0
- package/dist/src/sim/push.d.ts +11 -0
- package/dist/src/sim/push.js +79 -0
- package/dist/src/sim/ranged.d.ts +44 -0
- package/dist/src/sim/ranged.js +69 -0
- package/dist/src/sim/seeds.d.ts +3 -0
- package/dist/src/sim/seeds.js +16 -0
- package/dist/src/sim/sensory-extended.d.ts +103 -0
- package/dist/src/sim/sensory-extended.js +181 -0
- package/dist/src/sim/sensory.d.ts +38 -0
- package/dist/src/sim/sensory.js +109 -0
- package/dist/src/sim/skills.d.ts +70 -0
- package/dist/src/sim/skills.js +69 -0
- package/dist/src/sim/sleep.d.ts +107 -0
- package/dist/src/sim/sleep.js +215 -0
- package/dist/src/sim/spatial.d.ts +8 -0
- package/dist/src/sim/spatial.js +59 -0
- package/dist/src/sim/step/capability.d.ts +8 -0
- package/dist/src/sim/step/capability.js +77 -0
- package/dist/src/sim/step/concentration.d.ts +9 -0
- package/dist/src/sim/step/concentration.js +25 -0
- package/dist/src/sim/step/effects.d.ts +17 -0
- package/dist/src/sim/step/effects.js +96 -0
- package/dist/src/sim/step/energy.d.ts +3 -0
- package/dist/src/sim/step/energy.js +31 -0
- package/dist/src/sim/step/hazards.d.ts +4 -0
- package/dist/src/sim/step/hazards.js +19 -0
- package/dist/src/sim/step/injury.d.ts +10 -0
- package/dist/src/sim/step/injury.js +353 -0
- package/dist/src/sim/step/morale.d.ts +11 -0
- package/dist/src/sim/step/morale.js +130 -0
- package/dist/src/sim/step/movement.d.ts +5 -0
- package/dist/src/sim/step/movement.js +172 -0
- package/dist/src/sim/step/push.d.ts +11 -0
- package/dist/src/sim/step/push.js +79 -0
- package/dist/src/sim/step/substances.d.ts +3 -0
- package/dist/src/sim/step/substances.js +75 -0
- package/dist/src/sim/substance.d.ts +38 -0
- package/dist/src/sim/substance.js +57 -0
- package/dist/src/sim/systemic-toxicology.d.ts +109 -0
- package/dist/src/sim/systemic-toxicology.js +263 -0
- package/dist/src/sim/team.d.ts +9 -0
- package/dist/src/sim/team.js +37 -0
- package/dist/src/sim/tech.d.ts +36 -0
- package/dist/src/sim/tech.js +46 -0
- package/dist/src/sim/terrain.d.ts +121 -0
- package/dist/src/sim/terrain.js +141 -0
- package/dist/src/sim/testing.d.ts +13 -0
- package/dist/src/sim/testing.js +100 -0
- package/dist/src/sim/thermoregulation.d.ts +77 -0
- package/dist/src/sim/thermoregulation.js +161 -0
- package/dist/src/sim/tick.d.ts +3 -0
- package/dist/src/sim/tick.js +3 -0
- package/dist/src/sim/toxicology.d.ts +52 -0
- package/dist/src/sim/toxicology.js +104 -0
- package/dist/src/sim/trace.d.ts +141 -0
- package/dist/src/sim/trace.js +1 -0
- package/dist/src/sim/tuning.d.ts +16 -0
- package/dist/src/sim/tuning.js +42 -0
- package/dist/src/sim/vec3.d.ts +14 -0
- package/dist/src/sim/vec3.js +31 -0
- package/dist/src/sim/weapon_dynamics.d.ts +102 -0
- package/dist/src/sim/weapon_dynamics.js +142 -0
- package/dist/src/sim/weather.d.ts +95 -0
- package/dist/src/sim/weather.js +105 -0
- package/dist/src/sim/world.d.ts +52 -0
- package/dist/src/sim/world.js +1 -0
- package/dist/src/sim/wound-aging.d.ts +120 -0
- package/dist/src/sim/wound-aging.js +223 -0
- package/dist/src/species.d.ts +106 -0
- package/dist/src/species.js +664 -0
- package/dist/src/story-arcs.d.ts +17 -0
- package/dist/src/story-arcs.js +276 -0
- package/dist/src/tech-diffusion.d.ts +80 -0
- package/dist/src/tech-diffusion.js +185 -0
- package/dist/src/traits.d.ts +25 -0
- package/dist/src/traits.js +178 -0
- package/dist/src/types.d.ts +117 -0
- package/dist/src/types.js +1 -0
- package/dist/src/units.d.ts +41 -0
- package/dist/src/units.js +64 -0
- package/dist/src/weapons.d.ts +20 -0
- package/dist/src/weapons.js +824 -0
- package/dist/src/world-generation.d.ts +52 -0
- package/dist/src/world-generation.js +301 -0
- package/package.json +74 -0
package/STABLE_API.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Ananke — Stable API Reference
|
|
2
|
+
|
|
3
|
+
This document defines the three stability tiers for Ananke's public API surface.
|
|
4
|
+
See [`docs/versioning.md`](docs/versioning.md) for the full versioning policy, upgrade
|
|
5
|
+
cadence, and commit-hash pinning guide.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Versioning policy (summary)
|
|
10
|
+
|
|
11
|
+
Ananke uses **semantic versioning (semver)** as its public contract. Tier 1 exports
|
|
12
|
+
will not break without a major version bump and migration guide. See
|
|
13
|
+
[`docs/versioning.md`](docs/versioning.md) for the complete policy.
|
|
14
|
+
|
|
15
|
+
Every export in `src/index.ts` is annotated with its tier via inline comments.
|
|
16
|
+
The tables below list key symbols by tier.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Tier 1 — Stable host API
|
|
21
|
+
|
|
22
|
+
These exports are safe to depend on. They will not change in a breaking way without a major
|
|
23
|
+
version bump and a migration guide in `CHANGELOG.md`.
|
|
24
|
+
|
|
25
|
+
### Fixed-point arithmetic (`src/units.ts`)
|
|
26
|
+
|
|
27
|
+
| Export | Description |
|
|
28
|
+
|--------|-------------|
|
|
29
|
+
| `type Q` | Dimensionless fixed-point scalar; `SCALE.Q == 1.0` |
|
|
30
|
+
| `type I32` | int32-safe number |
|
|
31
|
+
| `SCALE` | Unit scale constants: `SCALE.Q`, `SCALE.kg`, `SCALE.m`, `SCALE.mps`, `SCALE.J`, `SCALE.N`, `SCALE.W`, `SCALE.s` |
|
|
32
|
+
| `q(x)` | Convert a float to fixed-point Q |
|
|
33
|
+
| `qMul(a, b)` | Fixed-point multiply |
|
|
34
|
+
| `qDiv(a, b)` | Fixed-point divide |
|
|
35
|
+
| `clampQ(x, lo, hi)` | Clamp a Q value |
|
|
36
|
+
| `mulDiv(a, b, div)` | Integer multiply-then-divide with overflow safety |
|
|
37
|
+
| `to` | Conversion helpers: `to.kg(x)`, `to.m(x)`, `to.mps(x)`, `to.J(x)`, `to.N(x)`, `to.W(x)`, `to.s(x)` |
|
|
38
|
+
| `from` | Reverse converters: `from.kg(x)`, etc. |
|
|
39
|
+
| `sqrtQ(x)` | Fixed-point square root |
|
|
40
|
+
|
|
41
|
+
### Core simulation (`src/sim/kernel.ts`, `src/sim/world.ts`)
|
|
42
|
+
|
|
43
|
+
| Export | Description |
|
|
44
|
+
|--------|-------------|
|
|
45
|
+
| `stepWorld(world, cmds, ctx)` | Advance the world by one tick |
|
|
46
|
+
| `applyImpactToInjury(world, aId, bId, energy_J, channel)` | Apply kinetic impact |
|
|
47
|
+
| `applyFallDamage(entity, height_m)` | Apply fall damage to an entity |
|
|
48
|
+
| `applyExplosion(world, x, y, energy_J, radius_m, ctx)` | Blast AoE |
|
|
49
|
+
| `applyPayload(world, targetId, payload, ctx)` | Apply a capability payload |
|
|
50
|
+
| `applyCapabilityEffect(world, actorId, targetId, effect, ctx)` | Apply a capability effect |
|
|
51
|
+
| `WorldState` | World container type (`entities`, `spatialIndex`, `clock`) |
|
|
52
|
+
| `KernelContext` | Tick context (`worldSeed`, `techCtx`, `weather`) |
|
|
53
|
+
| `CommandMap` | Map of entity ID → command |
|
|
54
|
+
|
|
55
|
+
### Entity and attributes (`src/sim/entity.ts`, `src/types.ts`, `src/archetypes.ts`)
|
|
56
|
+
|
|
57
|
+
| Export | Description |
|
|
58
|
+
|--------|-------------|
|
|
59
|
+
| `Entity` | Core entity shape. **Stable fields:** `id`, `pos`, `mass_kg`, `attributes`, `injuries`, `fatigue`, `fluid`, `consciousness`, `shock`, `fear`, `team`, `dead`. Optional extension fields (mount, age, sleep, etc.) may gain new members in minor versions |
|
|
60
|
+
| `IndividualAttributes` | Physical attribute block (`peakForce_N`, `peakPower_W`, `continuousPower_W`, `reserveEnergy_J`, `reactionTime_s`, `controlQuality`, `stability`, `fineControl`, `stature_m`, `mass_kg`, …) |
|
|
61
|
+
| `Archetype` | Archetype baseline with variance fields |
|
|
62
|
+
| `BodyPlan` | Species body plan descriptor |
|
|
63
|
+
| `NarrativeBias` | Story-shaping bias for `generateIndividual` |
|
|
64
|
+
|
|
65
|
+
### Entity generation (`src/generate.ts`)
|
|
66
|
+
|
|
67
|
+
| Export | Description |
|
|
68
|
+
|--------|-------------|
|
|
69
|
+
| `generateIndividual(seed, archetype, bias?)` | Generate a physically plausible entity from an archetype |
|
|
70
|
+
|
|
71
|
+
### Presets and weapons (`src/presets.ts`, `src/weapons.ts`)
|
|
72
|
+
|
|
73
|
+
| Export | Description |
|
|
74
|
+
|--------|-------------|
|
|
75
|
+
| `mkKnight`, `mkBoxer`, `mkWrestler`, `mkOctopus`, `mkScubaDiver` | Named entity factories |
|
|
76
|
+
| `AMATEUR_BOXER`, `PRO_BOXER`, `GRECO_WRESTLER`, `KNIGHT_INFANTRY`, `LARGE_PACIFIC_OCTOPUS` | Validated archetypes |
|
|
77
|
+
| `WEAPONS` | Historical weapons database (~70 weapons, six eras) |
|
|
78
|
+
|
|
79
|
+
### Replay and serialization (`src/replay.ts`)
|
|
80
|
+
|
|
81
|
+
| Export | Description |
|
|
82
|
+
|--------|-------------|
|
|
83
|
+
| `ReplayRecorder` | Attach to a world to record all ticks |
|
|
84
|
+
| `replayTo(replay, tick, ctx)` | Replay to a target tick deterministically |
|
|
85
|
+
| `serializeReplay(replay)` | JSON-stringify a replay |
|
|
86
|
+
| `deserializeReplay(json)` | Restore a replay from JSON |
|
|
87
|
+
| `Replay`, `ReplayFrame` | Replay types |
|
|
88
|
+
|
|
89
|
+
### 3D integration and renderer bridge (`src/model3d.ts`, `src/bridge/`)
|
|
90
|
+
|
|
91
|
+
See [`docs/bridge-contract.md`](docs/bridge-contract.md) for the field-by-field contract
|
|
92
|
+
including `AnimationHints`, `GrapplePoseConstraint`, and `InterpolatedState`.
|
|
93
|
+
|
|
94
|
+
| Export | Description |
|
|
95
|
+
|--------|-------------|
|
|
96
|
+
| `extractRigSnapshots(world)` | Per-entity rig data snapshot for renderer use |
|
|
97
|
+
| `deriveAnimationHints(entity)` | Animation state hints |
|
|
98
|
+
| `derivePoseModifiers(entity)` | Per-region impairment pose weights |
|
|
99
|
+
| `deriveGrappleConstraint(entity)` | Grapple pose constraint for paired entities |
|
|
100
|
+
| `deriveMassDistribution(entity)` | Mass distribution for physics rigs |
|
|
101
|
+
| `deriveInertiaTensor(entity)` | Inertia tensor for physics rigs |
|
|
102
|
+
| `AnimationHints`, `PoseModifier`, `GrapplePoseConstraint`, `MassDistribution`, `InertiaTensor` | Types |
|
|
103
|
+
| `BridgeEngine` | Double-buffered renderer bridge engine |
|
|
104
|
+
| `BridgeConfig`, `BodyPlanMapping`, `InterpolatedState` | Bridge configuration and output types |
|
|
105
|
+
|
|
106
|
+
### Description layer (`src/describe.ts`)
|
|
107
|
+
|
|
108
|
+
| Export | Description |
|
|
109
|
+
|--------|-------------|
|
|
110
|
+
| `describeCharacter(attrs)` | Translate fixed-point attributes into rated descriptions |
|
|
111
|
+
| `formatCharacterSheet(desc)` | Multi-line formatted character sheet |
|
|
112
|
+
| `formatOneLine(desc)` | One-line summary |
|
|
113
|
+
| `CharacterDescription`, `AttributeRating` | Types |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Tier 2 — Experimental extension API
|
|
118
|
+
|
|
119
|
+
These exports are usable and tested but may change across minor versions.
|
|
120
|
+
A `CHANGELOG.md` entry will document any breaking change.
|
|
121
|
+
|
|
122
|
+
| Module | Key exports |
|
|
123
|
+
|--------|------------|
|
|
124
|
+
| `src/polity.ts` | `createPolity`, `createPolityRegistry`, `stepPolityDay`, `declareWar`, `areAtWar`, `Polity`, `PolityRegistry`, `PolityPair` |
|
|
125
|
+
| `src/tech-diffusion.ts` | `computeDiffusionPressure`, `stepTechDiffusion`, `totalInboundPressure`, `techEraName` |
|
|
126
|
+
| `src/emotional-contagion.ts` | `applyEmotionalContagion`, `stepEmotionalWaves`, `computeEmotionalSpread`, `triggerMilitaryRout`, `triggerVictoryRally`, `netEmotionalPressure` |
|
|
127
|
+
| `src/mythology.ts` | `compressMythsFromHistory`, `stepMythologyYear`, `aggregateFactionMythEffect`, `scaledMythEffect` |
|
|
128
|
+
| `src/narrative-stress.ts` | `runNarrativeStressTest`, `scoreNarrativePush` |
|
|
129
|
+
| `src/campaign.ts` | `Campaign`, `stepCampaignDay`, `advanceCampaignClock`, `serializeCampaign`, `deserializeCampaign` |
|
|
130
|
+
| `src/arena.ts` | Arena scenario DSL, `runArenaTrial`, `runArenaScenario` |
|
|
131
|
+
| `src/sim/aging.ts` | `applyAgingToAttributes`, `stepAging`, `deriveAgeMultipliers`, `getAgePhase` |
|
|
132
|
+
| `src/sim/sleep.ts` | `applySleepToAttributes`, `stepSleep`, `deriveSleepDeprivationMuls`, `circadianAlertness` |
|
|
133
|
+
| `src/sim/disease.ts` | `exposeToDisease`, `stepDiseaseForEntity`, `spreadDisease`, `computeTransmissionRisk` |
|
|
134
|
+
| `src/sim/mount.ts` | `checkMountStep`, `computeChargeBonus`, `deriveRiderHeightBonus` |
|
|
135
|
+
| `src/sim/hazard.ts` | `deriveHazardEffect`, `computeHazardExposure`, `stepHazardZone` |
|
|
136
|
+
| `src/dialogue.ts` | `resolveIntimidation`, `resolvePersuasion`, `resolveDeception`, `resolveTradeNegotiation` |
|
|
137
|
+
| `src/faction.ts` | `FactionRegistry`, `updateStanding`, `getFactionStanding` |
|
|
138
|
+
| `src/economy.ts` | `computeItemValue`, `applyWear`, `resolveDrops`, `evaluateTradeOffer` |
|
|
139
|
+
| `src/progression.ts` | `applyXP`, `applyTrainingDrift`, `computeMilestones` |
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Tier 3 — Internal kernel structures
|
|
144
|
+
|
|
145
|
+
These are implementation details. Do not import them directly; they may change at any time.
|
|
146
|
+
|
|
147
|
+
| Module | Why internal |
|
|
148
|
+
|--------|-------------|
|
|
149
|
+
| `src/rng.ts` | `makeRng`, `eventSeed`, `hashString` — RNG contract is internal; seed structure may change |
|
|
150
|
+
| `src/sim/push.ts` | Pair-based resolution internals |
|
|
151
|
+
| `src/sim/kernel.ts` (non-exported functions) | Step sub-phases, internal accumulators |
|
|
152
|
+
| `src/sim/seeds.ts` | Seed derivation utilities |
|
|
153
|
+
| `src/sim/ai/` | AI decision internals; host applications should use `buildAICommands()` via `src/sim/ai/system.ts` |
|
|
154
|
+
|
|
155
|
+
> `buildAICommands()` from `src/sim/ai/system.ts` is Experimental (Tier 2).
|
|
156
|
+
> The individual sub-modules (`decide.ts`, `perception.ts`, `targeting.ts`) are Tier 3.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## What constitutes a "breaking change"
|
|
161
|
+
|
|
162
|
+
| Tier 1 (breaking, requires major bump) | Tier 2 (documented in changelog) |
|
|
163
|
+
|---------------------------------------|----------------------------------|
|
|
164
|
+
| Removing or renaming a stable export | Removing or renaming an experimental export |
|
|
165
|
+
| Changing the signature of a stable function | Changing observable behaviour without a matching test update |
|
|
166
|
+
| Removing required fields from stable types | Changing field names in experimental types |
|
|
167
|
+
| Changing `stepWorld`'s observable output for identical inputs | Changing RNG consumption order in internal modules |
|
|
168
|
+
| Breaking `serializeReplay`/`deserializeReplay` round-trip | Changing undocumented default values |
|
|
169
|
+
|
|
170
|
+
Adding new **optional** fields to `Entity` or `IndividualAttributes` is never a breaking change.
|
|
171
|
+
Adding new exports is never a breaking change at any tier.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Entity and WorldState Field Tiers
|
|
176
|
+
|
|
177
|
+
Every field on `Entity` and `WorldState` carries a JSDoc annotation that identifies which
|
|
178
|
+
subsystem owns it and whether it is required by the kernel. There are three tiers:
|
|
179
|
+
|
|
180
|
+
### `@core` — Required by `stepWorld` every tick
|
|
181
|
+
|
|
182
|
+
These fields must always be present. Removing or renaming them is a Tier 1 breaking change.
|
|
183
|
+
|
|
184
|
+
**`Entity` core fields:**
|
|
185
|
+
|
|
186
|
+
| Field | Type | Description |
|
|
187
|
+
|-------|------|-------------|
|
|
188
|
+
| `id` | `number` | Unique entity identifier; stable across ticks |
|
|
189
|
+
| `teamId` | `number` | Combat team / allegiance for attack resolution and AI targeting |
|
|
190
|
+
| `attributes` | `IndividualAttributes` | Physical and cognitive capabilities |
|
|
191
|
+
| `energy` | `EnergyState` | Energy reserve and fatigue accumulator |
|
|
192
|
+
| `loadout` | `Loadout` | Equipped items: weapons, armour, held objects |
|
|
193
|
+
| `traits` | `TraitId[]` | Permanent trait flags |
|
|
194
|
+
| `position_m` | `Vec3` | World-space position (fixed-point, `SCALE.m` = 1 m) |
|
|
195
|
+
| `velocity_mps` | `Vec3` | Velocity (fixed-point, `SCALE.mps` = 1 m/s) |
|
|
196
|
+
| `intent` | `IntentState` | Movement and defence intent derived from the previous tick's commands |
|
|
197
|
+
| `action` | `ActionState` | Attack cooldowns, swing momentum, weapon-bind state |
|
|
198
|
+
| `condition` | `ConditionState` | Fear, morale, sensory modifiers, fatigue, thermal state |
|
|
199
|
+
| `injury` | `InjuryState` | Per-region damage, shock, consciousness, fluid loss, death flag |
|
|
200
|
+
| `grapple` | `GrappleState` | Active grapple relationships, grip strength, positional lock |
|
|
201
|
+
|
|
202
|
+
**`WorldState` core fields:**
|
|
203
|
+
|
|
204
|
+
| Field | Type | Description |
|
|
205
|
+
|-------|------|-------------|
|
|
206
|
+
| `tick` | `number` | Current tick count; incremented by `stepWorld` |
|
|
207
|
+
| `seed` | `number` | Deterministic RNG seed |
|
|
208
|
+
| `entities` | `Entity[]` | All live and dead entities |
|
|
209
|
+
|
|
210
|
+
### `@subsystem(name)` — Optional state consumed by a specific module
|
|
211
|
+
|
|
212
|
+
These fields are optional `?` properties. Omitting a subsystem field disables that module's
|
|
213
|
+
behaviour for the entity; the kernel continues to run correctly without it. Adding new
|
|
214
|
+
subsystem fields is never a breaking change.
|
|
215
|
+
|
|
216
|
+
**`Entity` subsystem fields:**
|
|
217
|
+
|
|
218
|
+
| Field | Module | Description |
|
|
219
|
+
|-------|--------|-------------|
|
|
220
|
+
| `willpower?` | `willpower` | Cognitive stamina reserve for concentration abilities |
|
|
221
|
+
| `skills?` | `skills` | Per-skill proficiency map for skill-contest resolution |
|
|
222
|
+
| `bodyPlan?` | `anatomy` | Body plan defining injury segments and mass distribution |
|
|
223
|
+
| `substances?` | `pharmacology` | Active pharmacological substances in the bloodstream |
|
|
224
|
+
| `foodInventory?` | `nutrition` | Consumable food items and counts |
|
|
225
|
+
| `molting?` | `anatomy` | Arthropod molting state (softening segments, repair cycles) |
|
|
226
|
+
| `ai?` | `ai` | AI decision state (target selection, threat map) |
|
|
227
|
+
| `capabilitySources?` | `capability` | Attached capability sources (mana pools, divine reserves) |
|
|
228
|
+
| `armourState?` | `armour` | Mutable resist state for ablative armour items |
|
|
229
|
+
| `pendingActivation?` | `capability` | In-flight capability cast |
|
|
230
|
+
| `activeConcentration?` | `capability` | Active concentration aura |
|
|
231
|
+
| `faction?` | `faction` | Faction membership identifier |
|
|
232
|
+
| `party?` | `party` | Adventuring party membership identifier |
|
|
233
|
+
| `reputations?` | `faction` | Entity-level faction-standing overrides |
|
|
234
|
+
| `physiology?` | `thermoregulation` | Species-level physiological overrides |
|
|
235
|
+
| `activeVenoms?` | `toxicology` | Active venom/toxin injections |
|
|
236
|
+
| `limbStates?` | `anatomy` | Per-limb state for multi-limb entities |
|
|
237
|
+
| `personality?` | `ai` | AI personality traits (aggression, caution, loyalty) |
|
|
238
|
+
| `extendedSenses?` | `sensory` | Extended sensory modalities (echolocation, olfaction) |
|
|
239
|
+
| `activeIngestedToxins?` | `toxicology` | Active ingested toxins (alcohol, sedatives, heavy metals) |
|
|
240
|
+
| `cumulativeExposure?` | `toxicology` | Cumulative lifetime dose records |
|
|
241
|
+
| `withdrawal?` | `toxicology` | Active withdrawal states |
|
|
242
|
+
| `traumaState?` | `wound-aging` | PTSD-like trauma state from severe shock events |
|
|
243
|
+
| `activeDiseases?` | `disease` | Active systemic disease states |
|
|
244
|
+
| `immunity?` | `disease` | Post-recovery immunity records |
|
|
245
|
+
| `age?` | `aging` | Elapsed life-seconds for aging calculations |
|
|
246
|
+
| `sleep?` | `sleep` | Sleep-phase state and debt accumulator |
|
|
247
|
+
| `mount?` | `mount` | Rider/mount pair state for mounted combat |
|
|
248
|
+
| `compiledAnatomy?` | `anatomy` | Internal anatomy cache — do not set manually |
|
|
249
|
+
| `anatomyHelpers?` | `anatomy` | Internal anatomy helper cache — do not set manually |
|
|
250
|
+
|
|
251
|
+
**`WorldState` subsystem fields:**
|
|
252
|
+
|
|
253
|
+
| Field | Module | Description |
|
|
254
|
+
|-------|--------|-------------|
|
|
255
|
+
| `activeFieldEffects?` | `capability` | Active suppression zones and field-effect modifiers |
|
|
256
|
+
| `__sensoryEnv?` | `sensory` | Ambient lighting and visibility environment |
|
|
257
|
+
| `__factionRegistry?` | `faction` | Global faction-standing registry |
|
|
258
|
+
| `__partyRegistry?` | `party` | Global party registry |
|
|
259
|
+
| `__relationshipGraph?` | `relationships` | Inter-entity relationship graph |
|
|
260
|
+
| `__nutritionAccum?` | `nutrition` | Cross-tick nutrition accumulator |
|
|
261
|
+
|
|
262
|
+
### `@extension` — Host-owned data
|
|
263
|
+
|
|
264
|
+
No built-in fields carry this tag. Hosts may add their own optional `?` fields to pass
|
|
265
|
+
renderer metadata, network session IDs, or other application-specific data alongside entities.
|
|
266
|
+
TypeScript's structural typing allows this without modifying `Entity`'s definition.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BodySegment } from "../sim/bodyplan.js";
|
|
2
|
+
import type { AnatomyCapabilities, AnatomyContracts, AnatomyIndexes, AnatomySegmentAugmentation, CompiledAnatomyModel, SegmentId } from "./anatomy-contracts.js";
|
|
3
|
+
import { type ExtendedBodyPlanDefinition, type ValidationIssue } from "./anatomy-schema.js";
|
|
4
|
+
export interface CompileAnatomyResult {
|
|
5
|
+
readonly ok: boolean;
|
|
6
|
+
readonly model?: CompiledAnatomyModel;
|
|
7
|
+
readonly issues: readonly ValidationIssue[];
|
|
8
|
+
}
|
|
9
|
+
export declare function compileAnatomyDefinition(input: unknown): CompileAnatomyResult;
|
|
10
|
+
export declare function compileAnatomyDefinitionOrThrow(input: unknown): CompiledAnatomyModel;
|
|
11
|
+
export declare function buildIndexes(plan: ExtendedBodyPlanDefinition): AnatomyIndexes;
|
|
12
|
+
export declare function buildSegmentData(plan: ExtendedBodyPlanDefinition, segmentsById: ReadonlyMap<SegmentId, BodySegment>): ReadonlyMap<SegmentId, AnatomySegmentAugmentation>;
|
|
13
|
+
export declare function deriveContracts(plan: ExtendedBodyPlanDefinition, segmentData: ReadonlyMap<SegmentId, AnatomySegmentAugmentation>, indexes: AnatomyIndexes): AnatomyContracts;
|
|
14
|
+
export declare function deriveCapabilities(plan: ExtendedBodyPlanDefinition, segmentData: ReadonlyMap<SegmentId, AnatomySegmentAugmentation>, contracts: AnatomyContracts): AnatomyCapabilities;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { validateExtendedBodyPlan, } from "./anatomy-schema.js";
|
|
2
|
+
export function compileAnatomyDefinition(input) {
|
|
3
|
+
const validated = validateExtendedBodyPlan(input);
|
|
4
|
+
if (!validated.ok || !validated.value) {
|
|
5
|
+
return { ok: false, issues: validated.issues };
|
|
6
|
+
}
|
|
7
|
+
const plan = validated.value;
|
|
8
|
+
const indexes = buildIndexes(plan);
|
|
9
|
+
const segmentData = buildSegmentData(plan, indexes.segmentsById);
|
|
10
|
+
const contracts = deriveContracts(plan, segmentData, indexes);
|
|
11
|
+
const capabilities = deriveCapabilities(plan, segmentData, contracts);
|
|
12
|
+
const model = {
|
|
13
|
+
plan,
|
|
14
|
+
segmentData,
|
|
15
|
+
indexes,
|
|
16
|
+
contracts,
|
|
17
|
+
capabilities,
|
|
18
|
+
targetProfiles: toProfileMap(plan.targetProfiles),
|
|
19
|
+
coverageProfiles: toCoverageMap(plan.coverageProfiles),
|
|
20
|
+
};
|
|
21
|
+
return { ok: true, model, issues: [] };
|
|
22
|
+
}
|
|
23
|
+
export function compileAnatomyDefinitionOrThrow(input) {
|
|
24
|
+
const result = compileAnatomyDefinition(input);
|
|
25
|
+
if (!result.ok || !result.model) {
|
|
26
|
+
const message = result.issues.map(issue => `${issue.path}: ${issue.message}`).join("\n");
|
|
27
|
+
throw new Error(`Invalid anatomy definition\n${message}`);
|
|
28
|
+
}
|
|
29
|
+
return result.model;
|
|
30
|
+
}
|
|
31
|
+
export function buildIndexes(plan) {
|
|
32
|
+
const segmentsById = new Map();
|
|
33
|
+
const childrenMutable = new Map();
|
|
34
|
+
const roots = [];
|
|
35
|
+
for (const segment of plan.segments) {
|
|
36
|
+
segmentsById.set(segment.id, segment);
|
|
37
|
+
childrenMutable.set(segment.id, []);
|
|
38
|
+
}
|
|
39
|
+
for (const segment of plan.segments) {
|
|
40
|
+
if (segment.parent === null)
|
|
41
|
+
roots.push(segment.id);
|
|
42
|
+
else
|
|
43
|
+
childrenMutable.get(segment.parent)?.push(segment.id);
|
|
44
|
+
}
|
|
45
|
+
const subtreeMutable = new Map();
|
|
46
|
+
const visit = (id) => {
|
|
47
|
+
const children = childrenMutable.get(id) ?? [];
|
|
48
|
+
const nested = children.flatMap(child => visit(child));
|
|
49
|
+
const subtree = [id, ...nested];
|
|
50
|
+
subtreeMutable.set(id, subtree);
|
|
51
|
+
return subtree;
|
|
52
|
+
};
|
|
53
|
+
for (const root of roots)
|
|
54
|
+
visit(root);
|
|
55
|
+
for (const id of segmentsById.keys())
|
|
56
|
+
if (!subtreeMutable.has(id))
|
|
57
|
+
visit(id);
|
|
58
|
+
const tags = new Map();
|
|
59
|
+
const functions = new Map();
|
|
60
|
+
for (const segment of plan.segments) {
|
|
61
|
+
const inferredTags = inferLegacySegmentTags(segment);
|
|
62
|
+
for (const tag of inferredTags)
|
|
63
|
+
pushIndex(tags, tag, segment.id);
|
|
64
|
+
for (const fnId of inferLegacyFunctionIds(segment)) {
|
|
65
|
+
pushIndex(functions, fnId, segment.id);
|
|
66
|
+
}
|
|
67
|
+
const explicit = plan.segmentData?.[segment.id];
|
|
68
|
+
for (const tag of explicit?.tags ?? []) {
|
|
69
|
+
pushIndex(tags, tag, segment.id);
|
|
70
|
+
}
|
|
71
|
+
for (const fn of explicit?.functions ?? []) {
|
|
72
|
+
pushIndex(functions, fn.id, segment.id);
|
|
73
|
+
}
|
|
74
|
+
for (const organ of explicit?.organs ?? []) {
|
|
75
|
+
for (const tag of organ.tags ?? []) {
|
|
76
|
+
pushIndex(tags, tag, segment.id);
|
|
77
|
+
}
|
|
78
|
+
for (const fnId of organ.functionIds ?? []) {
|
|
79
|
+
pushIndex(functions, fnId, segment.id);
|
|
80
|
+
}
|
|
81
|
+
if (organ.vital) {
|
|
82
|
+
pushIndex(functions, "vital", segment.id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
segmentsById,
|
|
88
|
+
childrenById: freezeIndex(childrenMutable),
|
|
89
|
+
subtreeById: freezeIndex(subtreeMutable),
|
|
90
|
+
segmentsByTag: freezeIndex(tags),
|
|
91
|
+
segmentsByFunction: freezeIndex(functions),
|
|
92
|
+
roots,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function buildSegmentData(plan, segmentsById) {
|
|
96
|
+
const out = new Map();
|
|
97
|
+
for (const [segmentId, segment] of segmentsById) {
|
|
98
|
+
const def = plan.segmentData?.[segmentId];
|
|
99
|
+
const inferredFunctions = inferLegacyFunctions(segment);
|
|
100
|
+
const mergedFunctions = mergeFunctions(inferredFunctions, def?.functions ?? []);
|
|
101
|
+
const mergedTags = unique([
|
|
102
|
+
...inferLegacySegmentTags(segment),
|
|
103
|
+
...(def?.tags ?? []),
|
|
104
|
+
...mergedFunctions.flatMap(fn => fn.tags ?? []),
|
|
105
|
+
...(def?.organs?.flatMap(organ => organ.tags ?? []) ?? []),
|
|
106
|
+
]);
|
|
107
|
+
out.set(segmentId, {
|
|
108
|
+
tags: mergedTags,
|
|
109
|
+
tissues: [...(def?.tissues ?? [])],
|
|
110
|
+
organs: [...(def?.organs ?? [])],
|
|
111
|
+
functions: mergedFunctions,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
export function deriveContracts(plan, segmentData, indexes) {
|
|
117
|
+
const ids = new Set();
|
|
118
|
+
const hasFunctions = [...segmentData.values()].some(seg => seg.functions.length > 0);
|
|
119
|
+
const hasVitalOrgans = [...segmentData.values()].some(seg => seg.organs.some(organ => organ.vital));
|
|
120
|
+
const hasManipulation = [...segmentData.values()].some(seg => seg.functions.some(fn => fn.id === "manipulation"));
|
|
121
|
+
const hasLocomotion = [...segmentData.values()].some(seg => seg.functions.some(fn => fn.id === "mobility"));
|
|
122
|
+
const hasWeaponMounts = [...segmentData.values()].some(seg => seg.functions.some(fn => fn.id === "weaponMount"));
|
|
123
|
+
const hasCoverage = (plan.coverageProfiles?.length ?? 0) > 0;
|
|
124
|
+
const hasHumanoidAliases = plan.contracts?.humanoidTargeting !== undefined;
|
|
125
|
+
const hasBilateral = plan.symmetry === "bilateral" || inferBilateral(indexes);
|
|
126
|
+
if (hasFunctions)
|
|
127
|
+
ids.add("functionalDamage");
|
|
128
|
+
if (hasVitalOrgans)
|
|
129
|
+
ids.add("vitalOrganWounding");
|
|
130
|
+
if (hasManipulation)
|
|
131
|
+
ids.add("manipulation");
|
|
132
|
+
if (hasLocomotion)
|
|
133
|
+
ids.add("locomotion");
|
|
134
|
+
if (hasCoverage)
|
|
135
|
+
ids.add("shieldCoverage");
|
|
136
|
+
if (hasWeaponMounts)
|
|
137
|
+
ids.add("weaponMounts");
|
|
138
|
+
if (hasBilateral)
|
|
139
|
+
ids.add("bilateralSides");
|
|
140
|
+
if (hasLocomotion && hasBilateral)
|
|
141
|
+
ids.add("stancePosture");
|
|
142
|
+
if (hasVitalOrgans)
|
|
143
|
+
ids.add("organMedicalModel");
|
|
144
|
+
if (hasHumanoidAliases)
|
|
145
|
+
ids.add("humanoidTargeting");
|
|
146
|
+
return {
|
|
147
|
+
ids,
|
|
148
|
+
humanoidTargeting: plan.contracts?.humanoidTargeting,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function deriveCapabilities(plan, segmentData, contracts) {
|
|
152
|
+
const hasCentralNervousSystem = [...segmentData.values()].some(seg => seg.functions.some(fn => fn.id === "cns")) || plan.cnsLayout.type === "centralized";
|
|
153
|
+
const hasManipulators = contracts.ids.has("manipulation");
|
|
154
|
+
const hasLocomotion = contracts.ids.has("locomotion");
|
|
155
|
+
const hasLateralSides = contracts.ids.has("bilateralSides");
|
|
156
|
+
const hasVitalOrgans = contracts.ids.has("vitalOrganWounding");
|
|
157
|
+
const supportsPostureModel = contracts.ids.has("stancePosture");
|
|
158
|
+
const supportsFineManipulation = [...segmentData.values()].some(seg => seg.functions.some(fn => fn.id === "manipulation" && (fn.role === "primary" || fn.weight === undefined || fn.weight >= 0.9)));
|
|
159
|
+
const supportsShieldCoverage = contracts.ids.has("shieldCoverage");
|
|
160
|
+
const supportsWeaponMounts = contracts.ids.has("weaponMounts");
|
|
161
|
+
const targetingModel = (plan.targetProfiles?.length ?? 0) > 0
|
|
162
|
+
? "profiles"
|
|
163
|
+
: contracts.ids.has("humanoidTargeting")
|
|
164
|
+
? "aliases"
|
|
165
|
+
: "segments";
|
|
166
|
+
return {
|
|
167
|
+
hasCentralNervousSystem,
|
|
168
|
+
hasManipulators,
|
|
169
|
+
hasLocomotion,
|
|
170
|
+
hasLateralSides,
|
|
171
|
+
hasVitalOrgans,
|
|
172
|
+
supportsPostureModel,
|
|
173
|
+
supportsFineManipulation,
|
|
174
|
+
supportsShieldCoverage,
|
|
175
|
+
supportsWeaponMounts,
|
|
176
|
+
impairmentModel: contracts.ids.has("functionalDamage") ? "functional" : plan.segments.length > 0 ? "segment" : "none",
|
|
177
|
+
targetingModel,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function inferLegacyFunctions(segment) {
|
|
181
|
+
const out = [];
|
|
182
|
+
if (segment.locomotionRole && segment.locomotionRole !== "none") {
|
|
183
|
+
out.push({
|
|
184
|
+
id: "mobility",
|
|
185
|
+
role: mapLegacyRole(segment.locomotionRole),
|
|
186
|
+
weight: segment.locomotionRole === "primary" ? 1.0 : 0.6,
|
|
187
|
+
tags: ["locomotor"],
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (segment.manipulationRole && segment.manipulationRole !== "none") {
|
|
191
|
+
out.push({
|
|
192
|
+
id: "manipulation",
|
|
193
|
+
role: mapLegacyRole(segment.manipulationRole),
|
|
194
|
+
weight: segment.manipulationRole === "primary" ? 1.0 : 0.6,
|
|
195
|
+
tags: ["manipulator"],
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (segment.cnsRole && segment.cnsRole !== "none") {
|
|
199
|
+
out.push({
|
|
200
|
+
id: "cns",
|
|
201
|
+
role: segment.cnsRole === "central" ? "primary" : "secondary",
|
|
202
|
+
weight: segment.cnsRole === "central" ? 1.0 : 0.6,
|
|
203
|
+
tags: ["cns"],
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
function inferLegacyFunctionIds(segment) {
|
|
209
|
+
return inferLegacyFunctions(segment).map(fn => fn.id);
|
|
210
|
+
}
|
|
211
|
+
function inferLegacySegmentTags(segment) {
|
|
212
|
+
const tags = new Set();
|
|
213
|
+
const id = segment.id.toLowerCase();
|
|
214
|
+
if (id.includes("left"))
|
|
215
|
+
tags.add("left");
|
|
216
|
+
if (id.includes("right"))
|
|
217
|
+
tags.add("right");
|
|
218
|
+
if (id.includes("head"))
|
|
219
|
+
tags.add("head");
|
|
220
|
+
if (id.includes("torso") || id.includes("chest") || id.includes("abdomen"))
|
|
221
|
+
tags.add("torso");
|
|
222
|
+
if (id.includes("arm") || id.includes("hand") || id.includes("forelimb") || id.includes("tentacle")) {
|
|
223
|
+
tags.add("manipulator");
|
|
224
|
+
}
|
|
225
|
+
if (id.includes("leg") || id.includes("foot") || id.includes("hindlimb") || id.includes("hoof")) {
|
|
226
|
+
tags.add("locomotor");
|
|
227
|
+
}
|
|
228
|
+
if (id.includes("wing"))
|
|
229
|
+
tags.add("wing");
|
|
230
|
+
if (id.includes("tail"))
|
|
231
|
+
tags.add("tail");
|
|
232
|
+
return [...tags];
|
|
233
|
+
}
|
|
234
|
+
function inferBilateral(indexes) {
|
|
235
|
+
const leftCount = (indexes.segmentsByTag.get("left") ?? []).length;
|
|
236
|
+
const rightCount = (indexes.segmentsByTag.get("right") ?? []).length;
|
|
237
|
+
return leftCount > 0 && leftCount === rightCount;
|
|
238
|
+
}
|
|
239
|
+
function mergeFunctions(inferred, explicit) {
|
|
240
|
+
const byId = new Map();
|
|
241
|
+
for (const fn of inferred)
|
|
242
|
+
byId.set(fn.id, { ...fn, tags: [...(fn.tags ?? [])] });
|
|
243
|
+
for (const fn of explicit) {
|
|
244
|
+
const prior = byId.get(fn.id);
|
|
245
|
+
byId.set(fn.id, {
|
|
246
|
+
id: fn.id,
|
|
247
|
+
role: fn.role ?? prior?.role ?? "none",
|
|
248
|
+
weight: fn.weight ?? prior?.weight ?? 0,
|
|
249
|
+
tags: unique([...(prior?.tags ?? []), ...(fn.tags ?? [])]),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return [...byId.values()];
|
|
253
|
+
}
|
|
254
|
+
function mapLegacyRole(role) {
|
|
255
|
+
if (role === "none")
|
|
256
|
+
return "none";
|
|
257
|
+
return role;
|
|
258
|
+
}
|
|
259
|
+
function toProfileMap(profiles) {
|
|
260
|
+
return new Map((profiles ?? []).map(profile => [profile.id, profile]));
|
|
261
|
+
}
|
|
262
|
+
function toCoverageMap(profiles) {
|
|
263
|
+
return new Map((profiles ?? []).map(profile => [profile.id, profile]));
|
|
264
|
+
}
|
|
265
|
+
function pushIndex(index, key, value) {
|
|
266
|
+
const prior = index.get(key);
|
|
267
|
+
if (prior)
|
|
268
|
+
prior.push(value);
|
|
269
|
+
else
|
|
270
|
+
index.set(key, [value]);
|
|
271
|
+
}
|
|
272
|
+
function freezeIndex(index) {
|
|
273
|
+
return new Map([...index.entries()].map(([key, value]) => [key, [...value]]));
|
|
274
|
+
}
|
|
275
|
+
function unique(values) {
|
|
276
|
+
return [...new Set(values)];
|
|
277
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { BodySegment } from "../sim/bodyplan.js";
|
|
2
|
+
import { ExtendedBodyPlanDefinition } from "./anatomy-schema.js";
|
|
3
|
+
export type SegmentId = BodySegment["id"];
|
|
4
|
+
export type AnatomyFunctionId = "mobility" | "manipulation" | "cns" | "vision" | "respiration" | "circulation" | "digestion" | "sensor" | "balance" | "weaponMount" | "vital";
|
|
5
|
+
export interface TissueLayerDefinition {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: "skin" | "fat" | "muscle" | "bone" | "shell" | "membrane" | "organ" | "other";
|
|
8
|
+
integrity?: number;
|
|
9
|
+
tags?: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export interface OrganDefinition {
|
|
12
|
+
id: string;
|
|
13
|
+
kind: string;
|
|
14
|
+
functionIds?: readonly AnatomyFunctionId[];
|
|
15
|
+
vital?: boolean;
|
|
16
|
+
paired?: boolean;
|
|
17
|
+
tags?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface SegmentFunctionDefinition {
|
|
20
|
+
id: AnatomyFunctionId | string;
|
|
21
|
+
role?: "primary" | "secondary" | "support" | "none";
|
|
22
|
+
weight?: number;
|
|
23
|
+
tags?: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
export interface SegmentTargetAliasBlock {
|
|
26
|
+
head?: readonly SegmentId[];
|
|
27
|
+
torso?: readonly SegmentId[];
|
|
28
|
+
leftArm?: readonly SegmentId[];
|
|
29
|
+
rightArm?: readonly SegmentId[];
|
|
30
|
+
leftLeg?: readonly SegmentId[];
|
|
31
|
+
rightLeg?: readonly SegmentId[];
|
|
32
|
+
}
|
|
33
|
+
export interface SegmentCoverageProfile {
|
|
34
|
+
id: string;
|
|
35
|
+
tags?: readonly string[];
|
|
36
|
+
selectors: readonly SegmentSelector[];
|
|
37
|
+
}
|
|
38
|
+
export interface SegmentTargetProfile {
|
|
39
|
+
id: string;
|
|
40
|
+
selectors: readonly WeightedSegmentSelector[];
|
|
41
|
+
}
|
|
42
|
+
export interface WeightedSegmentSelector extends SegmentSelector {
|
|
43
|
+
weight: number;
|
|
44
|
+
}
|
|
45
|
+
export interface SegmentSelector {
|
|
46
|
+
ids?: readonly SegmentId[];
|
|
47
|
+
tags?: readonly string[];
|
|
48
|
+
functionIds?: readonly string[];
|
|
49
|
+
subtreeOf?: SegmentId;
|
|
50
|
+
anyOf?: readonly SegmentSelector[];
|
|
51
|
+
allOf?: readonly SegmentSelector[];
|
|
52
|
+
exclude?: SegmentSelector;
|
|
53
|
+
}
|
|
54
|
+
export type AnatomyContractId = "functionalDamage" | "vitalOrganWounding" | "bilateralSides" | "manipulation" | "locomotion" | "stancePosture" | "shieldCoverage" | "humanoidTargeting" | "organMedicalModel" | "weaponMounts";
|
|
55
|
+
export interface AnatomyContracts {
|
|
56
|
+
readonly ids: ReadonlySet<AnatomyContractId>;
|
|
57
|
+
readonly humanoidTargeting?: SegmentTargetAliasBlock | undefined;
|
|
58
|
+
}
|
|
59
|
+
export interface AnatomyCapabilities {
|
|
60
|
+
readonly hasCentralNervousSystem: boolean;
|
|
61
|
+
readonly hasManipulators: boolean;
|
|
62
|
+
readonly hasLocomotion: boolean;
|
|
63
|
+
readonly hasLateralSides: boolean;
|
|
64
|
+
readonly hasVitalOrgans: boolean;
|
|
65
|
+
readonly supportsPostureModel: boolean;
|
|
66
|
+
readonly supportsFineManipulation: boolean;
|
|
67
|
+
readonly supportsShieldCoverage: boolean;
|
|
68
|
+
readonly supportsWeaponMounts: boolean;
|
|
69
|
+
readonly impairmentModel: "functional" | "segment" | "none";
|
|
70
|
+
readonly targetingModel: "profiles" | "aliases" | "segments";
|
|
71
|
+
}
|
|
72
|
+
export interface AnatomyIndexes {
|
|
73
|
+
readonly segmentsById: ReadonlyMap<SegmentId, BodySegment>;
|
|
74
|
+
readonly childrenById: ReadonlyMap<SegmentId, readonly SegmentId[]>;
|
|
75
|
+
readonly subtreeById: ReadonlyMap<SegmentId, readonly SegmentId[]>;
|
|
76
|
+
readonly segmentsByTag: ReadonlyMap<string, readonly SegmentId[]>;
|
|
77
|
+
readonly segmentsByFunction: ReadonlyMap<string, readonly SegmentId[]>;
|
|
78
|
+
readonly roots: readonly SegmentId[];
|
|
79
|
+
}
|
|
80
|
+
export interface AnatomySegmentAugmentation {
|
|
81
|
+
readonly tags: readonly string[];
|
|
82
|
+
readonly tissues: readonly TissueLayerDefinition[];
|
|
83
|
+
readonly organs: readonly OrganDefinition[];
|
|
84
|
+
readonly functions: readonly SegmentFunctionDefinition[];
|
|
85
|
+
}
|
|
86
|
+
export interface CompiledAnatomyModel {
|
|
87
|
+
readonly plan: ExtendedBodyPlanDefinition;
|
|
88
|
+
readonly segmentData: ReadonlyMap<SegmentId, AnatomySegmentAugmentation>;
|
|
89
|
+
readonly indexes: AnatomyIndexes;
|
|
90
|
+
readonly capabilities: AnatomyCapabilities;
|
|
91
|
+
readonly contracts: AnatomyContracts;
|
|
92
|
+
readonly targetProfiles: ReadonlyMap<string, SegmentTargetProfile>;
|
|
93
|
+
readonly coverageProfiles: ReadonlyMap<string, SegmentCoverageProfile>;
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|