@its-not-rocket-science/ananke 0.1.69 → 0.5.4
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 +288 -0
- package/README.md +150 -432
- package/STABLE_API.md +113 -490
- package/conformance/README.md +46 -44
- package/conformance/lockstep-sequence.json +395 -395
- package/conformance/phase-order.json +21 -0
- package/conformance/replay-parity.json +65 -65
- package/conformance/state-hash-regression.json +39 -0
- package/conformance/state-hash.json +23 -22
- package/dist/src/conformance.d.ts +8 -2
- package/dist/src/content/index.d.ts +3 -0
- package/dist/src/content/index.js +2 -0
- package/dist/src/content/injector.d.ts +19 -0
- package/dist/src/content/injector.js +61 -0
- package/dist/src/content/loader.d.ts +3 -0
- package/dist/src/content/loader.js +170 -0
- package/dist/src/content/types.d.ts +56 -0
- package/dist/src/content/types.js +1 -0
- package/dist/src/content/validator.d.ts +6 -0
- package/dist/src/content/validator.js +14 -0
- package/dist/src/content-pack.d.ts +3 -2
- package/dist/src/content-pack.js +205 -10
- package/dist/src/data-governance.d.ts +73 -0
- package/dist/src/data-governance.js +188 -0
- package/dist/src/debug.d.ts +6 -0
- package/dist/src/debug.js +9 -0
- package/dist/src/determinism.d.ts +12 -0
- package/dist/src/determinism.js +93 -0
- package/dist/src/dialogue.d.ts +41 -0
- package/dist/src/dialogue.js +113 -2
- package/dist/src/economy.d.ts +97 -3
- package/dist/src/economy.js +191 -37
- package/dist/src/history/autosave.d.ts +19 -0
- package/dist/src/history/autosave.js +98 -0
- package/dist/src/history/timetravel.d.ts +28 -0
- package/dist/src/history/timetravel.js +61 -0
- package/dist/src/index.d.ts +19 -31
- package/dist/src/index.js +20 -38
- package/dist/src/model3d.js +63 -2
- package/dist/src/narrative/combat-logger.d.ts +25 -0
- package/dist/src/narrative/combat-logger.js +97 -0
- package/dist/src/narrative/plausibility.d.ts +30 -0
- package/dist/src/narrative/plausibility.js +70 -0
- package/dist/src/narrative-layer.d.ts +2 -0
- package/dist/src/narrative-layer.js +2 -0
- package/dist/src/navigation/causal-chain.d.ts +26 -0
- package/dist/src/navigation/causal-chain.js +74 -0
- package/dist/src/netcode.d.ts +1 -1
- package/dist/src/netcode.js +1 -1
- package/dist/src/performance/adaptive-tick.d.ts +23 -0
- package/dist/src/performance/adaptive-tick.js +50 -0
- package/dist/src/plugins/loader.d.ts +23 -0
- package/dist/src/plugins/loader.js +86 -0
- package/dist/src/plugins/registry.d.ts +11 -0
- package/dist/src/plugins/registry.js +28 -0
- package/dist/src/plugins/types.d.ts +31 -0
- package/dist/src/plugins/types.js +7 -0
- package/dist/src/replay.js +5 -2
- package/dist/src/scenario.js +2 -1
- package/dist/src/serialization/binary.d.ts +5 -0
- package/dist/src/serialization/binary.js +193 -0
- package/dist/src/session.d.ts +115 -0
- package/dist/src/session.js +228 -0
- package/dist/src/sim/ai/decide.js +1 -1
- package/dist/src/sim/ai/personality.js +2 -2
- package/dist/src/sim/bodyplan.d.ts +30 -0
- package/dist/src/sim/context.d.ts +2 -0
- package/dist/src/sim/kernel.js +80 -1294
- package/dist/src/sim/normalization.d.ts +12 -0
- package/dist/src/sim/normalization.js +92 -0
- package/dist/src/sim/resolvers/attack-resolver.d.ts +30 -0
- package/dist/src/sim/resolvers/attack-resolver.js +310 -0
- package/dist/src/sim/resolvers/capability-resolver.d.ts +15 -0
- package/dist/src/sim/resolvers/capability-resolver.js +270 -0
- package/dist/src/sim/resolvers/grapple-resolver.d.ts +28 -0
- package/dist/src/sim/resolvers/grapple-resolver.js +70 -0
- package/dist/src/sim/resolvers/shoot-resolver.d.ts +27 -0
- package/dist/src/sim/resolvers/shoot-resolver.js +212 -0
- package/dist/src/sim/resolvers/treat-resolver.d.ts +16 -0
- package/dist/src/sim/resolvers/treat-resolver.js +77 -0
- package/dist/src/sim/step/apply/intents.d.ts +6 -0
- package/dist/src/sim/step/apply/intents.js +83 -0
- package/dist/src/sim/step/kernel-pipeline.d.ts +9 -0
- package/dist/src/sim/step/kernel-pipeline.js +15 -0
- package/dist/src/sim/step/phases/capability-phase.d.ts +8 -0
- package/dist/src/sim/step/phases/capability-phase.js +65 -0
- package/dist/src/sim/step/phases/cooldowns-phase.d.ts +3 -0
- package/dist/src/sim/step/phases/cooldowns-phase.js +37 -0
- package/dist/src/sim/step/phases/prepare-phase.d.ts +10 -0
- package/dist/src/sim/step/phases/prepare-phase.js +33 -0
- package/dist/src/sim/step/pipeline.d.ts +2 -0
- package/dist/src/sim/step/pipeline.js +15 -0
- package/dist/src/sim/step/resolvers/impact-resolver.d.ts +9 -0
- package/dist/src/sim/step/resolvers/impact-resolver.js +55 -0
- package/dist/src/sim/step/world-phases.d.ts +7 -0
- package/dist/src/sim/step/world-phases.js +15 -0
- package/dist/src/sim/step/world-step-context.d.ts +23 -0
- package/dist/src/sim/step/world-step-context.js +1 -0
- package/dist/src/sim/systemic-toxicology.js +1 -1
- package/dist/src/sim/team.js +2 -2
- package/dist/src/sim/testing.js +4 -3
- package/dist/src/sim/toxicology.d.ts +1 -1
- package/dist/src/sim/toxicology.js +1 -1
- package/dist/src/sim/world.d.ts +17 -24
- package/dist/src/snapshot.js +3 -6
- package/dist/src/tier2.d.ts +19 -0
- package/dist/src/tier2.js +21 -0
- package/dist/src/tier3.d.ts +10 -0
- package/dist/src/tier3.js +12 -0
- package/dist/src/version.d.ts +6 -0
- package/dist/src/version.js +8 -0
- package/dist/src/wasm/bridge.d.ts +14 -0
- package/dist/src/wasm/bridge.js +84 -0
- package/dist/src/wasm-kernel.d.ts +2 -0
- package/dist/src/wasm-kernel.js +1 -0
- package/dist/src/world-evolution-backend/engine.d.ts +4 -0
- package/dist/src/world-evolution-backend/engine.js +347 -0
- package/dist/src/world-evolution-backend/host-schema.d.ts +145 -0
- package/dist/src/world-evolution-backend/host-schema.js +375 -0
- package/dist/src/world-evolution-backend/index.d.ts +1 -0
- package/dist/src/world-evolution-backend/index.js +1 -0
- package/dist/src/world-evolution-backend/open-world-host-adapter.d.ts +96 -0
- package/dist/src/world-evolution-backend/open-world-host-adapter.js +208 -0
- package/dist/src/world-evolution-backend/profiles.d.ts +4 -0
- package/dist/src/world-evolution-backend/profiles.js +136 -0
- package/dist/src/world-evolution-backend/public.d.ts +11 -0
- package/dist/src/world-evolution-backend/public.js +7 -0
- package/dist/src/world-evolution-backend/reproducibility.d.ts +8 -0
- package/dist/src/world-evolution-backend/reproducibility.js +35 -0
- package/dist/src/world-evolution-backend/timeline.d.ts +6 -0
- package/dist/src/world-evolution-backend/timeline.js +337 -0
- package/dist/src/world-evolution-backend/types.d.ts +138 -0
- package/dist/src/world-evolution-backend/types.js +1 -0
- package/dist/src/world-evolution-host-backend.d.ts +51 -0
- package/dist/src/world-evolution-host-backend.js +97 -0
- package/dist/src/world-evolution.d.ts +201 -0
- package/dist/src/world-evolution.js +543 -0
- package/dist/src/world-factory.js +2 -1
- package/dist/tools/pack-cli.js +55 -2
- package/docs/bridge-contract.md +140 -332
- package/docs/completion-evidence-dashboard.md +63 -0
- package/docs/host-contract.md +86 -310
- package/docs/host-world-evolution-schema.md +155 -0
- package/docs/integration-primer.md +29 -22
- package/docs/migration-monolith-to-modular.md +102 -120
- package/docs/package-architecture.md +116 -323
- package/docs/plugins/README.md +42 -0
- package/docs/plugins/hooks.md +22 -0
- package/docs/plugins/publishing.md +29 -0
- package/docs/plugins/security-model.md +273 -0
- package/docs/project-overview.md +30 -30
- package/docs/release-dashboard.md +47 -0
- package/docs/session-api.md +127 -0
- package/docs/stable-api-manifest.json +52 -0
- package/docs/trust-dashboard.md +37 -0
- package/docs/versioning.md +256 -245
- package/docs/wire-protocol.md +140 -209
- package/docs/world-evolution-backend.md +200 -0
- package/docs/world-evolution-engine.md +150 -0
- package/docs/world-evolution-host-backend.md +70 -0
- package/docs/world-evolution-orchestration.md +248 -0
- package/package.json +125 -6
- package/schema/content-pack.schema.json +85 -0
- package/schema/plugin.schema.json +57 -0
- package/schema/world-evolution-input.schema.json +196 -0
package/README.md
CHANGED
|
@@ -1,432 +1,150 @@
|
|
|
1
|
-
# Ananke
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
### Reading injury state
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
for (const [region, inj] of Object.entries(entity.injury.regions)) {
|
|
155
|
-
const pct = (inj.surfaceDamage / SCALE.Q * 100).toFixed(0);
|
|
156
|
-
if (inj.surfaceDamage > 0)
|
|
157
|
-
console.log(` ${region}: ${pct}% surface damage${inj.infected ? " [infected]" : ""}`);
|
|
158
|
-
}
|
|
159
|
-
console.log(` dead: ${entity.injury.dead}`);
|
|
160
|
-
console.log(` shock: ${(entity.condition.shockQ / SCALE.Q * 100).toFixed(0)}%`);
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Using the narrative layer
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import {
|
|
167
|
-
CollectingTrace, renderChronicle,
|
|
168
|
-
} from "@its-not-rocket-science/ananke";
|
|
169
|
-
|
|
170
|
-
const trace = new CollectingTrace();
|
|
171
|
-
stepWorld(world, commands, { ...ctx, trace });
|
|
172
|
-
|
|
173
|
-
const log = renderChronicle(trace.events, world.entities, { verbosity: "normal" });
|
|
174
|
-
console.log(log);
|
|
175
|
-
// → "Knight strikes Brawler in the torso for 340 J. Brawler staggers."
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Quick start B — Campaign and world simulation
|
|
181
|
-
|
|
182
|
-
Advance two polities through 90 days with tech diffusion and emotional contagion:
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
import {
|
|
186
|
-
createPolityRegistry, stepPolityDay,
|
|
187
|
-
applyEmotionalContagion, stepTechDiffusion,
|
|
188
|
-
createEmotionalWave, FEAR_WAVE, q, SCALE,
|
|
189
|
-
} from "@its-not-rocket-science/ananke";
|
|
190
|
-
|
|
191
|
-
const WORLD_SEED = 1;
|
|
192
|
-
|
|
193
|
-
const registry = createPolityRegistry([
|
|
194
|
-
{ id: 1, name: "Ironhold", population: 50_000, techEra: 2, moraleQ: q(0.70) /* ... */ },
|
|
195
|
-
{ id: 2, name: "Ashfeld", population: 30_000, techEra: 1, moraleQ: q(0.55) /* ... */ },
|
|
196
|
-
]);
|
|
197
|
-
|
|
198
|
-
const pairs = [{ polityA: 1, polityB: 2, routeQuality_Q: q(0.60), atWar: false /* ... */ }];
|
|
199
|
-
|
|
200
|
-
for (let day = 1; day <= 90; day++) {
|
|
201
|
-
stepPolityDay(registry, WORLD_SEED, day);
|
|
202
|
-
stepTechDiffusion(registry, pairs, WORLD_SEED, day);
|
|
203
|
-
applyEmotionalContagion(registry, [createEmotionalWave(FEAR_WAVE, 1)], pairs);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
for (const p of registry.polities) {
|
|
207
|
-
console.log(`${p.name}: pop=${p.population} era=${p.techEra} morale=${(p.moraleQ / SCALE.Q).toFixed(2)}`);
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## Quick start C — Species and character generation
|
|
214
|
-
|
|
215
|
-
Generate individuals from a body-plan archetype, apply aging, and describe them:
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
import {
|
|
219
|
-
generateIndividual, applyAgingToAttributes,
|
|
220
|
-
describeCharacter, formatCharacterSheet,
|
|
221
|
-
} from "@its-not-rocket-science/ananke";
|
|
222
|
-
|
|
223
|
-
// Generate a 45-year-old knight
|
|
224
|
-
const base = generateIndividual("KNIGHT_INFANTRY", 1, 1);
|
|
225
|
-
const aged = applyAgingToAttributes(base.attributes, 45);
|
|
226
|
-
|
|
227
|
-
console.log(formatCharacterSheet({ ...base, attributes: aged }));
|
|
228
|
-
// → Strength: 1840 N [above average]
|
|
229
|
-
// Reaction: 0.21 s [average]
|
|
230
|
-
// ...
|
|
231
|
-
|
|
232
|
-
// Fantasy species
|
|
233
|
-
const elf = generateIndividual("ELF_ARCHER", 2, 2);
|
|
234
|
-
console.log(describeCharacter(elf));
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Available built-in archetypes: `KNIGHT_INFANTRY`, `PRO_BOXER`, `GRECO_WRESTLER`,
|
|
238
|
-
`AMATEUR_BOXER`, `LARGE_PACIFIC_OCTOPUS`, and all species defined in
|
|
239
|
-
[`src/species.ts`](src/species.ts) — humans, elves, dwarves, orcs, dragons,
|
|
240
|
-
Vulcans, Klingons, and more.
|
|
241
|
-
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
## The command system
|
|
245
|
-
|
|
246
|
-
`stepWorld` takes a `CommandMap` — a `Map<entityId, EntityCommand>`. You build it
|
|
247
|
-
manually, from your AI layer, or from the built-in AI system:
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
import type { EntityCommand } from "@its-not-rocket-science/ananke";
|
|
251
|
-
|
|
252
|
-
// Attack
|
|
253
|
-
const commands = new Map<number, EntityCommand>([
|
|
254
|
-
[entityId, { kind: "attack", targetId: opponentId, weapon: LONGSWORD }],
|
|
255
|
-
]);
|
|
256
|
-
|
|
257
|
-
// Move to a position
|
|
258
|
-
commands.set(entityId, {
|
|
259
|
-
kind: "move",
|
|
260
|
-
destination: { x: 5 * SCALE.m, y: 0, z: 0 },
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// Treat a wounded ally
|
|
264
|
-
commands.set(medicId, {
|
|
265
|
-
kind: "treat",
|
|
266
|
-
targetId: woundedId,
|
|
267
|
-
schedule: { care: "field_surgery", equipmentTier: 2 },
|
|
268
|
-
});
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
Valid `kind` values: `"attack"`, `"move"`, `"grapple"`, `"treat"`, `"use_capability"`,
|
|
272
|
-
`"signal"`, `"idle"`.
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
|
-
## Determinism
|
|
277
|
-
|
|
278
|
-
Ananke guarantees that `mkWorld(seed, entities)` followed by identical commands produces
|
|
279
|
-
identical `WorldState` at every tick, regardless of platform, JS engine, or execution time.
|
|
280
|
-
|
|
281
|
-
**Rules to preserve determinism in your host:**
|
|
282
|
-
|
|
283
|
-
1. Never use `Math.random()` — use `makeRng(eventSeed(...))` from the package instead
|
|
284
|
-
2. Iterate `world.entities` in insertion order (it is a stable array, not a Map)
|
|
285
|
-
3. Keep entity `id` values stable across ticks — IDs are used as RNG salts
|
|
286
|
-
4. Do not rely on wall-clock time inside the simulation loop
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
import { makeRng, eventSeed } from "@its-not-rocket-science/ananke";
|
|
290
|
-
|
|
291
|
-
// Deterministic RNG inside your AI or event code:
|
|
292
|
-
const rng = makeRng(eventSeed(world.seed, world.tick, entityId, 0, 42));
|
|
293
|
-
const roll = rng(); // float in [0, 1) — deterministic from inputs
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## Replay and serialisation
|
|
299
|
-
|
|
300
|
-
```typescript
|
|
301
|
-
import {
|
|
302
|
-
ReplayRecorder, serializeReplay, deserializeReplay, replayTo,
|
|
303
|
-
} from "@its-not-rocket-science/ananke";
|
|
304
|
-
|
|
305
|
-
// Record
|
|
306
|
-
const recorder = new ReplayRecorder();
|
|
307
|
-
for (let tick = 0; tick < N; tick++) {
|
|
308
|
-
const cmds = buildCommands(world);
|
|
309
|
-
recorder.record(tick, cmds);
|
|
310
|
-
stepWorld(world, cmds, ctx);
|
|
311
|
-
}
|
|
312
|
-
const json = serializeReplay(recorder.replay); // stable JSON string
|
|
313
|
-
|
|
314
|
-
// Replay to any tick
|
|
315
|
-
const replay = deserializeReplay(json);
|
|
316
|
-
const state = replayTo(replay, initialWorld, targetTick, ctx);
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
---
|
|
320
|
-
|
|
321
|
-
## 3D renderer bridge
|
|
322
|
-
|
|
323
|
-
Extract per-segment pose data for driving a humanoid rig at renderer frame rate:
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
import {
|
|
327
|
-
extractRigSnapshots, deriveAnimationHints, BridgeEngine,
|
|
328
|
-
} from "@its-not-rocket-science/ananke";
|
|
329
|
-
|
|
330
|
-
// Per-tick: get bone transforms
|
|
331
|
-
const snapshots = extractRigSnapshots(world.entities, bodyPlan);
|
|
332
|
-
// snapshots[entityId] → RigSnapshot { segments: Map<segmentId, { position_m, rotation }> }
|
|
333
|
-
|
|
334
|
-
// Per-tick: get animation state machine hints
|
|
335
|
-
const hints = deriveAnimationHints(entity);
|
|
336
|
-
// hints → { idle, walk, run, attacking, prone, unconscious, dead, shockQ, fearQ, ... }
|
|
337
|
-
|
|
338
|
-
// Or use BridgeEngine for double-buffered interpolation at renderer frame rate:
|
|
339
|
-
const bridge = new BridgeEngine(config);
|
|
340
|
-
bridge.writeSimFrame(world.tick, world.entities);
|
|
341
|
-
const interp = bridge.readInterpolated(rendererTimestamp);
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
See [`docs/bridge-contract.md`](docs/bridge-contract.md) for the full double-buffer
|
|
345
|
-
protocol and `AnimationHints` field-by-field contract.
|
|
346
|
-
|
|
347
|
-
---
|
|
348
|
-
|
|
349
|
-
## API stability tiers
|
|
350
|
-
|
|
351
|
-
| Tier | Guarantee | Examples |
|
|
352
|
-
|------|-----------|---------|
|
|
353
|
-
| **Tier 1 — Stable** | Breaking changes require major semver bump + migration guide | `stepWorld`, `generateIndividual`, `Entity`, `q`, `SCALE`, bridge module |
|
|
354
|
-
| **Tier 2 — Experimental** | May change in minor versions; CHANGELOG will note it | Campaign, polity, dialogue, faction, quest subsystems |
|
|
355
|
-
| **Tier 3 — Internal** | No stability guarantee; may change at any time | `makeRng`, `eventSeed`, kernel tuning constants, `mkHumanoidEntity` |
|
|
356
|
-
|
|
357
|
-
Full tier table: [`STABLE_API.md`](STABLE_API.md)
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## TypeScript
|
|
362
|
-
|
|
363
|
-
The package ships full `.d.ts` declarations. Key types to know:
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
import type {
|
|
367
|
-
Entity, // the simulated object
|
|
368
|
-
WorldState, // world.entities + world.tick + world.seed
|
|
369
|
-
KernelContext, // tractionCoeff, weather, etc. — passed to stepWorld
|
|
370
|
-
EntityCommand, // what an entity does this tick
|
|
371
|
-
IndividualAttributes, // physical stats (SI units)
|
|
372
|
-
InjuryState, // per-region damage
|
|
373
|
-
ConditionSnapshot, // shock, fear, fatigue
|
|
374
|
-
Q, // fixed-point number alias (just `number` at runtime)
|
|
375
|
-
Vec3, // { x, y, z } in fixed-point metres
|
|
376
|
-
} from "@its-not-rocket-science/ananke";
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
`Q` is a nominal alias for `number` — it carries no runtime overhead, but the `q()`
|
|
380
|
-
constructor and `SCALE` constants make the intent clear in every formula.
|
|
381
|
-
|
|
382
|
-
---
|
|
383
|
-
|
|
384
|
-
## Performance guidance
|
|
385
|
-
|
|
386
|
-
| Scenario | Recommended tick rate | Practical entity cap |
|
|
387
|
-
|---|---|---|
|
|
388
|
-
| Duel / 1v1 | 20 Hz | Unlimited |
|
|
389
|
-
| Skirmish (squads) | 20 Hz | ~300 |
|
|
390
|
-
| Battle (formations) | 10 Hz | ~500 |
|
|
391
|
-
| Siege / campaign | 1 Hz | ~1 000 |
|
|
392
|
-
| World simulation | 0.01 Hz (once/day) | ~10 000 |
|
|
393
|
-
|
|
394
|
-
Enable `buildSpatialIndex` when entities exceed ~50 and distances matter. Disable
|
|
395
|
-
expensive subsystems (disease O(n²) spread, thermoregulation) at high entity counts
|
|
396
|
-
unless required.
|
|
397
|
-
|
|
398
|
-
Full benchmark methodology and operational guide: [`docs/performance.md`](docs/performance.md)
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
## Validation and trust
|
|
403
|
-
|
|
404
|
-
Ananke's outputs are validated against historical and experimental sources:
|
|
405
|
-
|
|
406
|
-
- **Isolated sub-system validation** — compares physical constants against sport-science
|
|
407
|
-
and biomechanics datasets: `npm run run:validation`
|
|
408
|
-
- **Emergent validation** — four historical combat scenarios (du Picq, Keegan, Lanchester,
|
|
409
|
-
Raudzens) across 100 seeds each: `npm run run:emergent-validation`
|
|
410
|
-
- **Pinned baseline** — committed result summaries that CI guards against regression:
|
|
411
|
-
[`docs/emergent-validation-report.md`](docs/emergent-validation-report.md)
|
|
412
|
-
|
|
413
|
-
---
|
|
414
|
-
|
|
415
|
-
## Further reading
|
|
416
|
-
|
|
417
|
-
| Document | What's in it |
|
|
418
|
-
|---|---|
|
|
419
|
-
| [`docs/recipes-matrix.md`](docs/recipes-matrix.md) | **Start here** — use case → package → stability → example → performance in one table |
|
|
420
|
-
| [`docs/cookbook.md`](docs/cookbook.md) | Task-oriented recipes — duel, 500-agent battle, species, renderer, campaign, replay, and more |
|
|
421
|
-
| [`corpus/README.md`](corpus/README.md) | Scenario corpus — 5 canonical deterministic scenarios (tutorial, benchmark, validation, networking, bridge); run `npm run verify-corpus` |
|
|
422
|
-
| [`docs/module-index.md`](docs/module-index.md) | All 41 entry points — stability tier, use case, key exports, doc links |
|
|
423
|
-
| [`docs/core-guarantees.md`](docs/core-guarantees.md) | Core guarantees — determinism contract, API stability, validation philosophy, known limits |
|
|
424
|
-
| [`docs/maintenance-policy.md`](docs/maintenance-policy.md) | Maintenance commitments — docs reconciliation, issue triage, SDK parity, deprecation budget |
|
|
425
|
-
| [`docs/host-contract.md`](docs/host-contract.md) | Stable integration surface — everything needed to embed Ananke without reading `src/` |
|
|
426
|
-
| [`docs/integration-primer.md`](docs/integration-primer.md) | Data-flow diagrams, type glossary, gotchas |
|
|
427
|
-
| [`docs/bridge-contract.md`](docs/bridge-contract.md) | 3D renderer bridge protocol (AnimationHints, GrapplePoseConstraint) |
|
|
428
|
-
| [`STABLE_API.md`](STABLE_API.md) | Full tier table for every export |
|
|
429
|
-
| [`docs/versioning.md`](docs/versioning.md) | Semver policy, breaking-change tiers, upgrade cadence |
|
|
430
|
-
| [`docs/performance.md`](docs/performance.md) | Benchmark results, operational guide, entity caps |
|
|
431
|
-
| [`docs/emergent-validation-report.md`](docs/emergent-validation-report.md) | Historical scenario validation report |
|
|
432
|
-
| [`docs/project-overview.md`](docs/project-overview.md) | Full project overview — implementation status, entity model reference, design principles, architecture |
|
|
1
|
+
# Ananke
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
-brightgreen)
|
|
5
|
+
|
|
6
|
+
> Package: `@its-not-rocket-science/ananke`
|
|
7
|
+
> Stable API contract: [`STABLE_API.md`](STABLE_API.md)
|
|
8
|
+
> Status: active engineering project; stable root API, exploratory submodules
|
|
9
|
+
|
|
10
|
+
Ananke is a deterministic simulation kernel for host applications.
|
|
11
|
+
|
|
12
|
+
It is designed for projects that need a world state to evolve reproducibly while leaving rendering, persistence, networking, content authoring, and deployment under the control of the host application.
|
|
13
|
+
|
|
14
|
+
## Core contract
|
|
15
|
+
|
|
16
|
+
Given the same:
|
|
17
|
+
|
|
18
|
+
- initial world state,
|
|
19
|
+
- command stream,
|
|
20
|
+
- tick count, and
|
|
21
|
+
- engine version,
|
|
22
|
+
|
|
23
|
+
Ananke should produce the same outcome.
|
|
24
|
+
|
|
25
|
+
That makes it useful for replay, debugging, deterministic tests, lockstep-style simulation, audit trails, and host-controlled narrative or game systems.
|
|
26
|
+
|
|
27
|
+
## Use Ananke when
|
|
28
|
+
|
|
29
|
+
- you need a reproducible simulation loop;
|
|
30
|
+
- you want host-owned rendering and persistence;
|
|
31
|
+
- you need deterministic fixtures for tests or replays;
|
|
32
|
+
- you want a stable root import surface for long-lived integrations;
|
|
33
|
+
- you are comfortable treating advanced subpath modules as version-pinned or experimental.
|
|
34
|
+
|
|
35
|
+
## Do not use Ananke if
|
|
36
|
+
|
|
37
|
+
- you want a complete game engine;
|
|
38
|
+
- you need a visual editor;
|
|
39
|
+
- you want turnkey networking;
|
|
40
|
+
- you need a no-code simulation builder;
|
|
41
|
+
- you expect every exported internal module to be semver-stable.
|
|
42
|
+
|
|
43
|
+
## 10-minute success path
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install
|
|
47
|
+
npm run build
|
|
48
|
+
npm run example:first-hour
|
|
49
|
+
npm run test:first-hour-smoke
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Then follow the first-hour adopter path:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
docs/first-hour-adopter-path.md
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Minimal deterministic loop
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import {
|
|
62
|
+
createWorld,
|
|
63
|
+
q,
|
|
64
|
+
stepWorld,
|
|
65
|
+
type CommandMap,
|
|
66
|
+
} from "@its-not-rocket-science/ananke";
|
|
67
|
+
|
|
68
|
+
const world = createWorld(1337, [
|
|
69
|
+
{
|
|
70
|
+
id: 1,
|
|
71
|
+
teamId: 1,
|
|
72
|
+
seed: 10,
|
|
73
|
+
archetype: "KNIGHT_INFANTRY",
|
|
74
|
+
weaponId: "wpn_longsword",
|
|
75
|
+
armourId: "arm_mail",
|
|
76
|
+
x_m: -1.2,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 2,
|
|
80
|
+
teamId: 2,
|
|
81
|
+
seed: 11,
|
|
82
|
+
archetype: "HUMAN_BASE",
|
|
83
|
+
weaponId: "wpn_club",
|
|
84
|
+
x_m: 1.2,
|
|
85
|
+
},
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const commands: CommandMap = new Map([
|
|
89
|
+
[1, [{ kind: "attackNearest", mode: "strike", intensity: q(1.0) }]],
|
|
90
|
+
[2, [{ kind: "attackNearest", mode: "strike", intensity: q(1.0) }]],
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
stepWorld(world, commands, { tractionCoeff: q(0.9) });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Stable API promise
|
|
97
|
+
|
|
98
|
+
For semver stability, import from the package root only:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import {
|
|
102
|
+
createWorld,
|
|
103
|
+
stepWorld,
|
|
104
|
+
q,
|
|
105
|
+
type CommandMap,
|
|
106
|
+
} from "@its-not-rocket-science/ananke";
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Tier-1 root exports are documented in:
|
|
110
|
+
|
|
111
|
+
- [`STABLE_API.md`](STABLE_API.md)
|
|
112
|
+
- [`docs/public-contract.md`](docs/public-contract.md)
|
|
113
|
+
- [`docs/stable-api-manifest.json`](docs/stable-api-manifest.json)
|
|
114
|
+
|
|
115
|
+
Subpath modules are shipped and supported, but are not part of the Tier-1 semver contract unless explicitly called out as stable.
|
|
116
|
+
|
|
117
|
+
## What is stable today
|
|
118
|
+
|
|
119
|
+
Stable today means Tier-1 root exports from `@its-not-rocket-science/ananke`:
|
|
120
|
+
|
|
121
|
+
- fixed-point primitives and helpers (`q`, `SCALE`, related conversion and maths utilities);
|
|
122
|
+
- host-facing types (`Entity`, `WorldState`, `Command`, `CommandMap`, `KernelContext`);
|
|
123
|
+
- deterministic world and scenario entry points (`createWorld`, `loadScenario`, `validateScenario`);
|
|
124
|
+
- deterministic stepping (`stepWorld`);
|
|
125
|
+
- replay helpers (`ReplayRecorder`, `replayTo`, `serializeReplay`, `deserializeReplay`);
|
|
126
|
+
- bridge snapshot extraction (`extractRigSnapshots`, `deriveAnimationHints`).
|
|
127
|
+
|
|
128
|
+
If you need long-term compatibility, keep production integrations on this root Tier-1 surface.
|
|
129
|
+
|
|
130
|
+
## What is shipped but not semver-stable
|
|
131
|
+
|
|
132
|
+
These surfaces are available, but outside the Tier-1 stability promise unless separately documented:
|
|
133
|
+
|
|
134
|
+
- most subpath modules in `package.json#exports`, including `./combat`, `./character`, `./tier2`, `./tier3`, `./netcode`, and `./host-loop`;
|
|
135
|
+
- emerging or advanced modules that may change shape between minor releases;
|
|
136
|
+
- exploratory integration helpers and higher-order systems.
|
|
137
|
+
|
|
138
|
+
Treat these areas as adopt-with-version-pinning.
|
|
139
|
+
|
|
140
|
+
## Useful next files
|
|
141
|
+
|
|
142
|
+
- [`docs/PROJECT_STATUS.md`](docs/PROJECT_STATUS.md) — plain-English status for visitors
|
|
143
|
+
- [`docs/host-contract.md`](docs/host-contract.md) — host integration contract
|
|
144
|
+
- [`docs/bridge-contract.md`](docs/bridge-contract.md) — renderer bridge contract
|
|
145
|
+
- [`docs/support-boundaries.md`](docs/support-boundaries.md) — maintainer commitments and support boundaries
|
|
146
|
+
- [`docs/engineering-guarantees.md`](docs/engineering-guarantees.md) — explicit engineering guarantees
|
|
147
|
+
|
|
148
|
+
## Boundaries note
|
|
149
|
+
|
|
150
|
+
First-hour checks verify setup and basic deterministic behaviour. They do not validate your production integration. Host applications should keep their own regression suite and pin versions where deterministic behaviour is part of their product contract.
|