@jgengine/github 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.
@@ -0,0 +1,60 @@
1
+ # Composable systems (`defineSystem`)
2
+
3
+ Single public authoring path: `defineGame({ systems, loop?, … })` from `@jgengine/shell/defineGame` (or core). Systems are meaningful capabilities — not micro-ticks.
4
+
5
+ ## API
6
+
7
+ ```ts
8
+ import { defineSystem } from "@jgengine/core/game/defineSystem";
9
+ import { compileSystemSchedule, DEFAULT_FIXED_STAGES, DEFAULT_FRAME_STAGES } from "@jgengine/core/game/systemSchedule";
10
+ import { composeGameLoop, installSystems } from "@jgengine/core/game/systemRuntime";
11
+
12
+ export const combat = defineSystem({
13
+ id: "combat",
14
+ feature: "quest", // optional — enables ctx.game.quest without features: { quest: true }
15
+ dependsOn: ["movement"], // optional — must also be in systems[]
16
+ tick: {
17
+ type: "fixed", // | "frame" | "interval" | "manual"
18
+ rate: 60, // fixed only (Hz); default 60
19
+ every: 1, // interval only (game-seconds)
20
+ stage: "combat",
21
+ after: "movement", // optional local order within the stage
22
+ before: "cleanup",
23
+ },
24
+ create(ctx) {},
25
+ start(ctx) {},
26
+ update(ctx, dt) {},
27
+ events: {
28
+ "entity.died"(ctx, event) {},
29
+ },
30
+ save: { key: "combat", snapshot: () => state, hydrate: (data) => { state = data; } },
31
+ replicate: (ctx) => ({ key: "combat-pub", snapshot: () => pub, hydrate: (d) => { pub = d; } }),
32
+ reset(ctx) {},
33
+ dispose(ctx) {},
34
+ });
35
+ ```
36
+
37
+ `defineGame` OR-merges `feature` flags, then `composeGameLoop(systems, loop)` so systems install on `onInit` and tick before residual `loop.onTick`. Classic games migrate by moving fan-out out of `onTick` into systems while keeping boot in `loop`.
38
+
39
+ ## Timing channels
40
+
41
+ | `tick.type` | When it runs |
42
+ |-------------|--------------|
43
+ | `fixed` | Accumulator at `rate` Hz (default 60); multi-subscribe OK |
44
+ | `frame` | Once per `onTick` with the frame's game `dt` |
45
+ | `interval` | Every `every` game-seconds (own accumulator per system) |
46
+ | `manual` | Installed only; call `systemsOf(ctx)?.runManual(ctx, id)` |
47
+ | *(omit)* | Event-only — handlers in `events` |
48
+
49
+ Multiple systems may share a channel. Order is stage tables + optional `before`/`after` — **never import order**. `compileSystemSchedule` validates unique ids, `dependsOn`, and cycles.
50
+
51
+ Default stages: fixed `input → movement → combat → ai → activities → cleanup`; frame includes those plus `animation → camera → effects`.
52
+
53
+ ## Cartridge path
54
+
55
+ Cartridge remains a convenience wrapper. Express the same shape as ordinary systems (`runFlow`, wave director, combat) under `defineGame({ systems })` when you outgrow the cartridge schema — one authoring model, no rewrite cliff.
56
+
57
+ ## Ownership
58
+
59
+ - **Save / replicate** — system modules register via `ctx.game.registerSave` / `registerReplicate` at install.
60
+ - **Reset / dispose** — `loop.onReset` / `loop.onDispose` (composed) run system hooks.