hayao 0.4.0 → 0.4.2

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 (131) hide show
  1. package/design/00-process/README.md +49 -0
  2. package/design/00-process/composition.md +148 -0
  3. package/design/00-process/core-loop.md +146 -0
  4. package/design/00-process/intent-to-brief.md +128 -0
  5. package/design/00-process/pillars.md +139 -0
  6. package/design/00-process/refine-and-handoff.md +156 -0
  7. package/design/00-process/the-twist.md +108 -0
  8. package/design/10-anchors/README.md +99 -0
  9. package/design/10-anchors/age-of-empires.md +103 -0
  10. package/design/10-anchors/baba-is-you.md +127 -0
  11. package/design/10-anchors/balatro.md +132 -0
  12. package/design/10-anchors/celeste.md +136 -0
  13. package/design/10-anchors/civilization.md +101 -0
  14. package/design/10-anchors/dead-cells.md +125 -0
  15. package/design/10-anchors/factorio.md +100 -0
  16. package/design/10-anchors/hades.md +127 -0
  17. package/design/10-anchors/into-the-breach.md +125 -0
  18. package/design/10-anchors/it-takes-two.md +104 -0
  19. package/design/10-anchors/loop-hero.md +131 -0
  20. package/design/10-anchors/nuclear-throne.md +130 -0
  21. package/design/10-anchors/outer-wilds.md +107 -0
  22. package/design/10-anchors/overcooked.md +102 -0
  23. package/design/10-anchors/peggle.md +133 -0
  24. package/design/10-anchors/reigns.md +99 -0
  25. package/design/10-anchors/return-of-the-obra-dinn.md +108 -0
  26. package/design/10-anchors/rimworld.md +101 -0
  27. package/design/10-anchors/shadow-of-mordor.md +106 -0
  28. package/design/10-anchors/slay-the-spire.md +127 -0
  29. package/design/10-anchors/starcraft.md +98 -0
  30. package/design/10-anchors/stardew-valley.md +103 -0
  31. package/design/10-anchors/tetris.md +122 -0
  32. package/design/10-anchors/vampire-survivors.md +122 -0
  33. package/design/20-genres/README.md +62 -0
  34. package/design/20-genres/action-adventure.md +126 -0
  35. package/design/20-genres/auto-battler.md +121 -0
  36. package/design/20-genres/bullet-hell.md +123 -0
  37. package/design/20-genres/city-builder.md +124 -0
  38. package/design/20-genres/coop-chaos.md +124 -0
  39. package/design/20-genres/deckbuilder.md +122 -0
  40. package/design/20-genres/exploration.md +131 -0
  41. package/design/20-genres/farming-sim.md +122 -0
  42. package/design/20-genres/grid-puzzle.md +126 -0
  43. package/design/20-genres/horde-survival.md +128 -0
  44. package/design/20-genres/incremental.md +120 -0
  45. package/design/20-genres/match3.md +120 -0
  46. package/design/20-genres/metroidvania.md +132 -0
  47. package/design/20-genres/narrative-decisions.md +122 -0
  48. package/design/20-genres/physics-arcade.md +124 -0
  49. package/design/20-genres/precision-platformer.md +127 -0
  50. package/design/20-genres/racing.md +126 -0
  51. package/design/20-genres/rhythm.md +125 -0
  52. package/design/20-genres/roguelike.md +122 -0
  53. package/design/20-genres/rts.md +169 -0
  54. package/design/20-genres/stealth.md +125 -0
  55. package/design/20-genres/survival-horror.md +124 -0
  56. package/design/20-genres/tactics.md +123 -0
  57. package/design/20-genres/tower-defense.md +120 -0
  58. package/design/30-systems/README.md +69 -0
  59. package/design/30-systems/accessibility.md +110 -0
  60. package/design/30-systems/boss-design.md +126 -0
  61. package/design/30-systems/build-diversity.md +120 -0
  62. package/design/30-systems/collectibles.md +108 -0
  63. package/design/30-systems/combat-model.md +113 -0
  64. package/design/30-systems/coop-and-competition.md +118 -0
  65. package/design/30-systems/counter-systems.md +115 -0
  66. package/design/30-systems/crafting.md +115 -0
  67. package/design/30-systems/difficulty-and-dda.md +114 -0
  68. package/design/30-systems/economy.md +117 -0
  69. package/design/30-systems/emergent-systems.md +114 -0
  70. package/design/30-systems/encounter-design.md +107 -0
  71. package/design/30-systems/enemy-ai.md +121 -0
  72. package/design/30-systems/enemy-archetypes.md +117 -0
  73. package/design/30-systems/faction-asymmetry.md +144 -0
  74. package/design/30-systems/grace.md +124 -0
  75. package/design/30-systems/mastery-curve.md +116 -0
  76. package/design/30-systems/meta-progression.md +114 -0
  77. package/design/30-systems/onboarding.md +115 -0
  78. package/design/30-systems/procgen-design.md +118 -0
  79. package/design/30-systems/progression.md +120 -0
  80. package/design/30-systems/resource-loops.md +112 -0
  81. package/design/30-systems/reward-schedules.md +124 -0
  82. package/design/30-systems/save-and-checkpoint.md +113 -0
  83. package/design/30-systems/session-structure.md +113 -0
  84. package/design/30-systems/skill-trees.md +111 -0
  85. package/design/30-systems/status-effects.md +111 -0
  86. package/design/30-systems/tech-tree.md +112 -0
  87. package/design/30-systems/telegraphs.md +106 -0
  88. package/design/30-systems/unit-rosters.md +123 -0
  89. package/design/40-worldbuilding/README.md +49 -0
  90. package/design/40-worldbuilding/aesthetic-direction.md +155 -0
  91. package/design/40-worldbuilding/faction-identity.md +136 -0
  92. package/design/40-worldbuilding/naming-and-tone.md +130 -0
  93. package/design/40-worldbuilding/narrative-delivery.md +129 -0
  94. package/design/40-worldbuilding/theme-vectors.md +134 -0
  95. package/design/40-worldbuilding/worldbuilding-scaffold.md +132 -0
  96. package/design/50-patterns/README.md +54 -0
  97. package/design/50-patterns/anti-frustration.md +121 -0
  98. package/design/50-patterns/emergence.md +121 -0
  99. package/design/50-patterns/feedback-loops.md +121 -0
  100. package/design/50-patterns/juice-choreography.md +124 -0
  101. package/design/50-patterns/mastery-and-flow.md +121 -0
  102. package/design/50-patterns/pacing-and-tension.md +120 -0
  103. package/design/50-patterns/readability.md +121 -0
  104. package/design/50-patterns/risk-reward.md +120 -0
  105. package/design/CONTRIBUTING.md +183 -0
  106. package/design/INDEX.md +133 -0
  107. package/design/README.md +86 -0
  108. package/design/_TEMPLATE.md +69 -0
  109. package/design/index.json +2720 -0
  110. package/dist/anim/blend.d.ts +68 -0
  111. package/dist/anim/clip.d.ts +87 -0
  112. package/dist/anim/ik.d.ts +40 -0
  113. package/dist/anim/skeleton.d.ts +64 -0
  114. package/dist/hayao.global.js +12 -12
  115. package/dist/index.d.ts +11 -1
  116. package/dist/index.js +1683 -516
  117. package/dist/index.js.map +4 -4
  118. package/dist/index.min.js +12 -12
  119. package/dist/render/canvas2d-core.d.ts +4 -0
  120. package/dist/render/commands.d.ts +19 -0
  121. package/dist/render/lightRun.d.ts +35 -0
  122. package/dist/render/svgString.d.ts +8 -3
  123. package/dist/scene/clipPlayer.d.ts +58 -0
  124. package/dist/scene/ikTarget.d.ts +25 -0
  125. package/dist/scene/light.d.ts +80 -0
  126. package/dist/scene/shadow2d.d.ts +25 -0
  127. package/dist/scene/skeletonDebug.d.ts +28 -0
  128. package/dist/verify/gates.d.ts +25 -0
  129. package/docs/API.md +66 -8
  130. package/docs/CONVENTIONS.md +56 -0
  131. package/package.json +2 -1
@@ -0,0 +1,117 @@
1
+ ---
2
+ id: system-economy
3
+ title: Economy — Faucets, Sinks & the Pacing Window
4
+ kind: system
5
+ tags: [economy, currency, faucets, sinks, inflation, balance, pacing, incremental]
6
+ summary: Currencies flowing in through faucets and out through sinks; keeping the two in tension so the player is always almost-able-to-afford the next thing.
7
+ use-when: The design has resources or currency the player earns and spends, and you need them to stay meaningful instead of trivial or crushing.
8
+ composes-with: [system-resource-loops, system-progression, system-crafting, system-reward-schedules, system-meta-progression]
9
+ anchors: [anchor-factorio, anchor-stardew-valley, anchor-civilization]
10
+ verify-with: docs/FUN.md#14-incrementalidle
11
+ ---
12
+
13
+ # Economy — Faucets, Sinks & the Pacing Window
14
+
15
+ **What it is.** Every currency is a bucket with **faucets** (where it flows in)
16
+ and **sinks** (where it drains out). The economy is the *ratio* between them over
17
+ time. Get the ratio right and the player lives in a productive tension — always
18
+ almost able to afford the next thing. Get it wrong and money is either worthless
19
+ or a wall.
20
+
21
+ **Player fantasy / why it's fun.** "I can *almost* afford it — one more run."
22
+ A good economy makes desire renewable: the moment you can buy the thing, a better
23
+ thing is just out of reach. The pull is the **pacing window** itself.
24
+
25
+ ## When to use / when NOT
26
+
27
+ | Use it when | Skip it when |
28
+ |---|---|
29
+ | Earning and spending is a core loop (RPG, sim, incremental) | The game has no persistent resource (pure arcade, puzzle) |
30
+ | You want the player pacing themselves via what they can afford | A flat unlock list reads clearer than a currency |
31
+ | Multiple currencies segment progress into tracks | One currency would do — don't invent five |
32
+
33
+ **Currency count is a tax.** Each currency the player must track is cognitive
34
+ overhead. Add a second only when it *segments* meaningfully (soft vs premium,
35
+ common vs prestige, run vs meta). Civilization's gold/science/culture each gate a
36
+ different track; that earns its complexity.
37
+
38
+ ## Variants
39
+
40
+ | Variant | Shape | Best for | Watch for |
41
+ |---|---|---|---|
42
+ | **Single currency** | One in, one out | Small games; clarity | Boredom if one sink dominates |
43
+ | **Multi-currency** | Parallel buckets, separate tracks | Sims, 4X, gacha | Confusion; conversion loopholes |
44
+ | **Convertible chain** | A → B → C ([[system-resource-loops]]) | Crafting, production | Bottleneck placement is the whole game |
45
+ | **Closed loop** | Fixed total, only moves | Auto-battler gold; poker chips | No growth fantasy |
46
+ | **Open (growth)** | Faucets > sinks by design | Incrementals, idlers | Inflation → late-game money is meaningless |
47
+
48
+ ## Tuning levers
49
+
50
+ | Lever | What it controls | Healthy range / rule |
51
+ |---|---|---|
52
+ | **Faucet rate** | Income per unit time/effort | Tie to *effort/skill*, not idle time, or you've built a clock |
53
+ | **Sink appetite** | How fast money leaves | Sinks must scale *with* faucets or inflation eats meaning |
54
+ | **Payback ratio** (cost ÷ production) | Time to recoup a purchase | Keep ~flat per tier (**~15–25s** in idlers). Rising payback strangles the late game (**[[FUN.md §14]]**) |
55
+ | **First-buy time** | The onboarding hook | Fast — the first affordable purchase within the first minute |
56
+ | **Inflation control** | Whether late money matters | New, costlier sinks per era; or a prestige reset ([[system-meta-progression]]) |
57
+ | **Currency count** | Cognitive load | As few as segment the game meaningfully |
58
+
59
+ The discipline that defines a healthy economy is the **pacing window**: state the
60
+ payback inequality as a law-3 constraint and *assert it holds across the whole
61
+ arc* — no tier where the next purchase is a desert, none where it's instant
62
+ (**[[FUN.md §14]]**, law 3).
63
+
64
+ ## How it wires to Hayao
65
+
66
+ - **The ledger is state.** Balances live in `world.state`; every earn and spend is
67
+ an **input action** (`input.press`), *never* a direct mutation — this is the
68
+ exact rule incremental/idle lives by so replays don't lie (**[[FUN.md §14]]**).
69
+ - **Balance-sim the whole arc.** Because state is pure JSON and rng flows through
70
+ `world.rng`, script a bot that plays the economy start-to-finish and assert the
71
+ pacing windows, monotone production, and *no unlock deserts* — the incremental
72
+ verify pattern. Grep `docs/API.md` for the ramp/pacing helpers
73
+ (`assertRamp`/`rampIssues`).
74
+ - **The HUD is cosmetic.** Balance labels, floating "+N", coin sprites render on
75
+ `LAYER_HUD` and are `cosmetic = true` — deletable without changing
76
+ `world.hash()` (**[[FUN.md law 6]]**). The city-builder truth applies: the live
77
+ "+N under the cursor" is a *pure* score serving sim, bot, test, and label at
78
+ once (**[[FUN.md §17]]**).
79
+ - **Shops/upgrade menus are chrome** — `showScreen()` DOM (CLAUDE.md invariant 4).
80
+
81
+ ## Fails when…
82
+
83
+ - **Inflation.** Faucets outrun sinks; late-game money is meaningless and every
84
+ purchase is trivial. Scale sinks with faucets; add prestige resets.
85
+ - **A desert.** A tier where the next thing costs far more than income can reach in
86
+ a fun span — the player grinds a solved loop. The payback assertion catches it.
87
+ - **Idle-not-effort faucets.** Income from waiting, not playing, turns the game
88
+ into a timer. Tie faucets to skill/effort.
89
+ - **Currency soup.** Five currencies where one would do; players lose the thread.
90
+ - **A conversion loophole.** A → B → A at profit breaks a multi-currency economy —
91
+ prove no cycle nets positive.
92
+
93
+ ## Verify
94
+
95
+ - Pacing windows, monotone production, no deserts, no click-softlock — the
96
+ incremental balance-sim: **[[FUN.md §14]]**.
97
+ - Payback ratio as an asserted law-3 inequality across tiers: **[[FUN.md law 3]]**.
98
+ - The exposed score as one pure function (sim = bot = test = label):
99
+ **[[FUN.md §17]]** (city-builder).
100
+ - Reinvest-vs-hoard skill delta (740 vs 236): **[[FUN.md §15]]** (farming).
101
+
102
+ ## Composes with
103
+
104
+ - [[system-resource-loops]] — the gather→convert→spend cycles the economy prices.
105
+ - [[system-progression]] — XP/levels are one faucet–sink pair among many.
106
+ - [[system-crafting]] — recipes are structured sinks with combinatorial payoff.
107
+ - [[system-reward-schedules]] — the drip that fills the faucet.
108
+ - [[system-meta-progression]] — prestige/meta currency as an inflation reset.
109
+ - [[pattern-feedback-loops]] — income→buy→more income is the runaway loop to tame.
110
+
111
+ ## See also
112
+
113
+ - [`docs/FUN.md`](../../docs/FUN.md) §14 (incremental pacing) · §15 (farming
114
+ solvency) · §17 (exposed score) — the three economy proofs.
115
+ - `src/content/` + `assertRamp` — pace-as-data; balance-sim the arc, don't vibe it.
116
+ - **[[anchor-factorio]]** (production economy) · **[[anchor-civilization]]**
117
+ (multi-currency tracks).
@@ -0,0 +1,114 @@
1
+ ---
2
+ id: system-emergent-systems
3
+ title: Emergent Systems
4
+ kind: system
5
+ tags: [emergence, nemesis, memory, relationships, reputation, systemic-story, story-generator, second-order]
6
+ summary: Nemesis-style memory, relationships, and reputation — systemic story generators where the game remembers you and interactions author drama.
7
+ use-when: You want stories the designer didn't script — rivalries, grudges, and reputations that arise from the player's own play.
8
+ composes-with: [system-enemy-ai, system-faction-asymmetry, pattern-emergence, world-narrative-delivery]
9
+ anchors: [anchor-shadow-of-mordor, anchor-rimworld]
10
+ verify-with: docs/FUN.md#7-pure-data-state-pays-compound-interest
11
+ ---
12
+
13
+ # Emergent Systems
14
+
15
+ **What it is.** Systems that **remember and relate** so the game authors stories no
16
+ designer wrote. The exemplar is Shadow of Mordor's **nemesis system**: an orc that
17
+ kills you gets promoted, scars, and a grudge — and when you meet again, *the game
18
+ remembers*. The family includes relationships (who likes whom), reputation (how the
19
+ world treats you), and any **systemic memory** that turns a one-off event into an
20
+ ongoing thread.
21
+
22
+ **Player fantasy / why it's fun.** *A story that's mine because it happened to me.*
23
+ Emergent drama beats scripted drama on ownership: the rival who humiliated you three
24
+ runs ago carries weight no cutscene can. The pull is a world that reacts to your
25
+ history, not a script that ignores it.
26
+
27
+ ## When to use / when NOT
28
+
29
+ | Use it when | Skip it when |
30
+ |---|---|
31
+ | Replayability + memorable specific antagonists/allies | A tight linear story — scripting owns it |
32
+ | The world should react to *your* history | Pure skill games where memory adds noise, not meaning |
33
+ | You want stories from interaction, not authoring | You can't afford the systemic-consequence budget (it must *ripple*) |
34
+
35
+ > **Memory only matters if it changes play.** A tracked grudge that never alters an
36
+ > encounter is a stat, not a story. The nemesis is fun because the promoted orc is
37
+ > genuinely *tougher and taunts you* — the memory has mechanical teeth
38
+ > ([[process-the-twist]]: cosmetic signatures don't carry a game).
39
+
40
+ ## Variants
41
+
42
+ | Variant | Remembers | Expresses as | Anchor |
43
+ |---|---|---|---|
44
+ | **Nemesis / rival** | who bested/fled whom | promoted, scarred, taunting foes | [[anchor-shadow-of-mordor]] |
45
+ | **Relationship web** | who likes/loathes whom | mood, cooperation, feuds | [[anchor-rimworld]] pawns |
46
+ | **Reputation** | your deeds toward a group | prices, aggression, access | RPG factions |
47
+ | **World state memory** | choices & consequences | changed places, remembered NPCs | narrative games |
48
+ | **Ecology / rivalry** | predator/prey, territory | shifting balance you disturbed | sim sandboxes |
49
+
50
+ ## Tuning levers
51
+
52
+ | Lever | Effect | Watch for |
53
+ |---|---|---|
54
+ | **Memory salience** | how much the game references history | too little = forgettable; too much = nagging |
55
+ | **Consequence magnitude** | how hard memory hits play | cosmetic memory = no story; brutal = punishing |
56
+ | **Promotion/decay rules** | how relationships evolve | no decay = the web ossifies |
57
+ | **Legibility of memory** | can the player *see* the history? | invisible memory reads as randomness |
58
+
59
+ ## How it wires to Hayao
60
+
61
+ - **Memory is pure data.** Grudges, relationships, and reputation are plain JSON in
62
+ `world.state`, advanced through `dmath`, rolled through `world.rng` — so a
63
+ nemesis roster is part of `world.hash()`, saves, and replays for free (FUN.md
64
+ law 7). "Pure-data state pays compound interest": the *same* property that makes
65
+ a story generator deterministic makes it save/loadable and testable.
66
+ - **The behavior hangs off [[system-enemy-ai]].** A promoted rival is an archetype
67
+ with a memory-derived stat block and a targeting bias toward *you* — same brain,
68
+ history-tuned numbers.
69
+ - **Ordered iteration is mandatory.** Relationship/promotion resolution must iterate
70
+ in a deterministic order (by id), never by insertion or hash order, or the story
71
+ diverges between machines (CLAUDE.md invariant 2).
72
+ - **Expression is often systemic narrative** — the memory shows up in the world,
73
+ not a text dump ([[world-narrative-delivery]]).
74
+ - **A director can dramatize it.** `pollDirector` ([[system-difficulty-and-dda]])
75
+ can weight spawns toward a remembered rival's return.
76
+
77
+ ## Fails when…
78
+
79
+ - **Memory with no mechanical consequence.** A tracked history that never changes an
80
+ encounter is a spreadsheet, not a saga.
81
+ - **Non-deterministic resolution.** Iteration-order or wall-clock in the memory
82
+ update breaks `world.hash()` and desyncs the story.
83
+ - **Illegible memory.** If the player can't perceive *why* a foe hates them, the
84
+ emergent story reads as random difficulty ([[pattern-readability]]).
85
+ - **Runaway feuds.** No decay or bounds and relationships spiral into an unreadable
86
+ tangle ([[pattern-feedback-loops]]).
87
+ - **Over-narration.** The system reminding you of every past event constantly kills
88
+ the surprise it exists to create.
89
+
90
+ ## Verify
91
+
92
+ - **Determinism of the story:** golden-hash a scripted multi-run sequence; the
93
+ nemesis/relationship state must replay bit-exactly
94
+ ([FUN.md law 7](../../docs/FUN.md#part-1--universal-laws)).
95
+ - **Save round-trip:** snapshot→restore→hash the memory state — a rivalry survives a
96
+ save intact (CONVENTIONS; [[system-save-and-checkpoint]]).
97
+ - **Consequence delta:** assert a remembered rival is measurably harder / behaves
98
+ differently than a fresh spawn — memory has teeth (FUN.md law 2 skill-delta shape).
99
+ - **Bounded evolution:** relationship/reputation values stay inside bounds across a
100
+ long sim (no runaway, per [[pattern-feedback-loops]]).
101
+
102
+ ## Composes with
103
+
104
+ - [[system-enemy-ai]] — the behavior a memory-tuned rival runs.
105
+ - [[system-faction-asymmetry]] — reputation and relationships across distinct groups.
106
+ - [[pattern-emergence]] — the second-order design this is the flagship case of.
107
+ - [[world-narrative-delivery]] — how the remembered story reaches the player.
108
+ - [[system-difficulty-and-dda]] — a director can stage a rival's return.
109
+
110
+ ## See also
111
+
112
+ - [`docs/FUN.md` law 7](../../docs/FUN.md#part-1--universal-laws) — pure-data state as the enabler.
113
+ - [[anchor-shadow-of-mordor]] — the nemesis system, distilled.
114
+ - [[anchor-rimworld]] — relationships + a director as a story engine.
@@ -0,0 +1,107 @@
1
+ ---
2
+ id: system-encounter-design
3
+ title: Encounter Design
4
+ kind: system
5
+ tags: [encounter, combat, pacing, pressure, safe-pocket, exit-lane, waves, composition]
6
+ summary: Composing archetypes into a fight — pressure and safe pockets, exit lanes, and a wave curve that breathes.
7
+ use-when: You have enemy roles and need to arrange them into a specific fight that reads, pressures, and resolves fairly.
8
+ composes-with: [system-enemy-archetypes, system-enemy-ai, system-difficulty-and-dda, system-boss-design]
9
+ anchors: [anchor-into-the-breach, anchor-vampire-survivors]
10
+ verify-with: docs/FUN.md#5-stealth
11
+ ---
12
+
13
+ # Encounter Design
14
+
15
+ **What it is.** The **arrangement** of enemies, space, and time into a single
16
+ fight. If [[system-enemy-archetypes]] is the alphabet, an encounter is the
17
+ *sentence*: which roles, in what count, entering from where, with what geometry —
18
+ and crucially, where the player can **breathe**. A fight is a rhythm of **pressure
19
+ and pocket**, not a constant scream.
20
+
21
+ **Player fantasy / why it's fun.** The satisfaction of *reading a room and solving
22
+ it live*. A great encounter poses a legible problem, ramps the pressure, gives one
23
+ honest window to recover, then peaks. FUN.md §5's "plannable danger" is the whole
24
+ ideal: the player should be able to route the fight, not just survive noise.
25
+
26
+ ## When to use / when NOT
27
+
28
+ | Use it when | Skip it when |
29
+ |---|---|
30
+ | Hand-authoring set-piece fights or rooms | Endless horde — that's a *pressure curve* (§6), tune the director not the room |
31
+ | A boss arena with adds | The fight IS one entity — go to [[system-boss-design]] |
32
+ | Roguelike rooms assembled from parts | Pure puzzle levels — that's solver-authored (§1) |
33
+
34
+ ## The anatomy of an encounter
35
+
36
+ | Element | The design question | Failure mode |
37
+ |---|---|---|
38
+ | **Composition** | which archetypes, how many? | all-tank slog / all-swarm noise |
39
+ | **Ingress** | where do they enter, in what order? | everything at once → no read |
40
+ | **Pressure curve** | does intensity rise, then peak? | flat = boring; monotone-hard = unfair |
41
+ | **Safe pocket** | where can the player recover mid-fight? | none = a war of attrition, not a fight (§5) |
42
+ | **Exit lanes** | are doors/escape routes obstacle-free? | cover in the door row = **softlock** (§4) |
43
+ | **Resolution** | how does it end — clear, timer, objective? | ambiguous end = the fight overstays |
44
+
45
+ ## Tuning levers
46
+
47
+ | Lever | Turns up… | Watch for |
48
+ |---|---|---|
49
+ | **Enemy budget** (a points cost per role) | raw difficulty | cheap way to overshoot — cap it |
50
+ | **Ingress cadence** | how fast the room fills | dumping all at frame 0 kills the read |
51
+ | **Pocket size / duration** | recovery generosity | zero pocket = frustration; huge pocket = no tension |
52
+ | **Arena geometry** (pillars, funnels) | kiting arcs & LoS breaks | a pillar in an exit lane softlocks (§4) |
53
+ | **Composition ratio** | the *kind* of pressure | shift ratios to reface a reused arena |
54
+
55
+ ## How it wires to Hayao
56
+
57
+ - **Encounters are data.** A room is a list of spawns + positions in `world.state`,
58
+ fed to the shared archetype behaviors. Timed ingress rides
59
+ `pollDirector(waves, state, world.time, world.rng)` — a repeating wave with an
60
+ `end` is a controlled trickle, a one-shot wave is an ambush
61
+ ([`src/content/dsl.ts`](../../src/content/dsl.ts)).
62
+ - **Geometry legibility** is a lint, not a vibe: `astarGrid`/`connectedComponents`
63
+ (grep `docs/API.md`) prove exit lanes stay traversable and every enemy can reach
64
+ the player — cover in a door row shows up as an unreachable path.
65
+ - **Procedural rooms** compose from proven parts: `generateDungeon` /
66
+ `generateLevels` (see [[system-procgen-design]]) with a per-room accept rule that
67
+ every spawn is reachable and a pocket exists.
68
+ - **Wave curve** shares the tower-defense breather math — see
69
+ [[system-difficulty-and-dda]] for `assertRamp`/`rampIssues`.
70
+
71
+ ## Fails when…
72
+
73
+ - **No safe pocket.** A long fight with nowhere to recover is attrition, not
74
+ skill — FUN.md §5 requires a pocket at the *midpoint* of any long traversal.
75
+ - **Blocked exit lanes.** A pillar or an enemy parked in a door row is a softlock;
76
+ keep door rows/columns clear (§4).
77
+ - **Everything at once.** Simultaneous ingress erases the read — the player never
78
+ gets to *solve* the room, only flail.
79
+ - **Flat pressure.** No rise, no peak → the fight is texture, not an arc
80
+ ([[pattern-pacing-and-tension]]).
81
+ - **Joint-phase waits** (stealth): chaining two guard windows that must *both*
82
+ align makes wait times explode (§5) — chain single windows.
83
+
84
+ ## Verify
85
+
86
+ - **Both-ways affordance / safe pocket:** the stealth proof pattern — punished
87
+ exposure AND concealment-holds AND a mid-path pocket
88
+ ([FUN.md §5](../../docs/FUN.md#5-stealth)).
89
+ - **Beatable:** a bot clears the encounter deathless with hp floor ≥ comfortable
90
+ ([FUN.md §4](../../docs/FUN.md#4-top-down-action-adventure-zelda-like)).
91
+ - **Curve breathes:** assert the pressure *shape* (each wave ≥ ~55% of prior,
92
+ finale peaks) with `rampIssues`, not monotonicity ([FUN.md §8](../../docs/FUN.md#8-tower-defense)).
93
+ - **Exit lanes clear:** reachability lint over the actual room geometry (FUN.md Part 3).
94
+
95
+ ## Composes with
96
+
97
+ - [[system-enemy-archetypes]] — the letters this arranges into sentences.
98
+ - [[system-enemy-ai]] — the behaviors that animate each spawn.
99
+ - [[system-difficulty-and-dda]] — encounters are the units a director sequences.
100
+ - [[system-boss-design]] — a boss arena is an encounter with a super-archetype.
101
+ - [[pattern-pacing-and-tension]] — pressure/pocket is pacing at fight scale.
102
+
103
+ ## See also
104
+
105
+ - [`docs/FUN.md` §4/§5/§8](../../docs/FUN.md) — readable combat, plannable danger, breathing waves.
106
+ - [`src/content/dsl.ts`](../../src/content/dsl.ts) — director-driven ingress.
107
+ - [[anchor-into-the-breach]] — the perfectly legible, fully telegraphed encounter.
@@ -0,0 +1,121 @@
1
+ ---
2
+ id: system-enemy-ai
3
+ title: Enemy AI
4
+ kind: system
5
+ tags: [ai, behavior, aggro, threat, steering, flow-field, pathfinding, kiting, telegraph]
6
+ summary: Readable, beatable enemy minds — aggro/threat, steering, and pathing that the player can predict, route around, and outplay.
7
+ use-when: A design needs enemies that move and decide, and you want them to feel intelligent without being unfair or opaque.
8
+ composes-with: [system-enemy-archetypes, system-encounter-design, system-telegraphs, system-difficulty-and-dda]
9
+ anchors: [anchor-nuclear-throne, anchor-shadow-of-mordor]
10
+ verify-with: docs/FUN.md#4-top-down-action-adventure-zelda-like
11
+ ---
12
+
13
+ # Enemy AI
14
+
15
+ **What it is.** The **decision + movement** an enemy runs each tick: who to
16
+ target, whether to press or retreat, and how to get there without walking into a
17
+ wall. Good enemy AI is not *smart* — it is **legible**. The player must be able to
18
+ read its intent, predict its next move, and beat it with position and timing.
19
+
20
+ **Player fantasy / why it's fun.** The fantasy is *outwitting a mind*. That only
21
+ lands if the mind is knowable: a shark that telegraphs its lunge is thrilling; one
22
+ that teleports behind you is cheap. The skill the player buys is *reading and
23
+ routing* — FUN.md §4's kiting bot exists because "the enemy is beatable by
24
+ positioning" is a provable claim.
25
+
26
+ ## When to use / when NOT
27
+
28
+ | Use it when | Skip it / go simpler when |
29
+ |---|---|
30
+ | Enemies must chase, flank, or hold ground | Bullet-hell foes: they emit **patterns**, not decisions (§7) — script the pattern, not a brain |
31
+ | The player's skill is spacing & threat-reading | Pure puzzle enemies: they're **rules**, deterministic and solver-legible (§1, §12) |
32
+ | You want emergent pressure from a few archetypes | A single scripted boss: hand-author phases ([[system-boss-design]]), don't build a general AI |
33
+ | Mass units under command (RTS) | One enemy, one behavior: a state flag beats a behavior tree |
34
+
35
+ > **Never build a mind the player can't read.** Perfect aim, wall-hacks, and
36
+ > reaction-time-zero are the difficulty of a slot machine. Difficulty comes from
37
+ > *count, geometry, and telegraph windows* — not from the AI cheating.
38
+
39
+ ## Variants
40
+
41
+ | Variant | The mind | Reads as | Best for |
42
+ |---|---|---|---|
43
+ | **Direct seeker** | steer straight at the target | "it wants me" | swarms, zombies (§6) |
44
+ | **Flow-field mass** | one BFS per goal, every unit follows the field | "the tide is coming" | RTS-lite, hordes (§9) |
45
+ | **Kiter / spacer** | hold a preferred range, back off when close | "keep your distance" | archers, ranged skirmishers (§4) |
46
+ | **Ambusher** | wait in a state until a trigger, then commit | "don't step there" | stealth, traps (§5) |
47
+ | **State-machine bruiser** | idle → aggro → windup → attack → recover | "here comes the swing" | melee bosses, mini-bosses (§4) |
48
+ | **Threat-driven** | pick target by an aggro/threat score, not proximity | "I pulled it" | party fights, taunt play |
49
+
50
+ ## Tuning levers
51
+
52
+ | Lever | Turns up… | Watch for |
53
+ |---|---|---|
54
+ | **Aggro radius** | when the enemy notices you | too large = no safe pockets ([[system-encounter-design]]) |
55
+ | **Threat weights** | *who* it targets (damage dealt, distance, taunt) | must be deterministic & ordered — ties break by entity id, never by iteration order |
56
+ | **Preferred range** (kiters) | the spacing the fight settles at | range < player reach = it's just a melee foe |
57
+ | **Windup / telegraph frames** | the reaction window before a hit | too short = unreadable; own this in [[system-telegraphs]] |
58
+ | **Steering deadzone** | jitter vs. commitment near the target | too tight = enemies vibrate on the spot |
59
+ | **Repath cadence** | how fast it reacts to you moving | every frame = twitchy & expensive; every N frames = readable |
60
+
61
+ ## How it wires to Hayao
62
+
63
+ - **Pathing:** `astarGrid` and `floodFill` (grep `docs/API.md`) give per-enemy
64
+ paths and wall-aware reachability. For **mass** pathing, one BFS per goal tile
65
+ cached *outside* `world.state` is the flow field (FUN.md §9) — hundreds of units
66
+ share it. `connectedComponents` proves a goal is even reachable before you spawn
67
+ a chaser that would path into nothing.
68
+ - **Steering:** `steer2D(px,py,tx,ty,out,dead)` emits the same action strings a
69
+ human would press, so an enemy and a bot driver share one movement path — and
70
+ the enemy replays deterministically. The `dead` deadzone is your jitter lever.
71
+ - **Threat/aggro:** plain data in `world.state` — a per-enemy target id and score,
72
+ advanced through `dmath`, ordered iteration for ties. No wall-clock, all rolls
73
+ through `world.rng`.
74
+ - **See it in isolation:** [`sandboxes/pathfinding-demo`](../../sandboxes/pathfinding-demo/)
75
+ — `astarGrid`/`floodFill` with paintable walls and a movable goal, no genre
76
+ attached. Learn the primitive there, not from a whole game.
77
+
78
+ ## Fails when…
79
+
80
+ - **The mind cheats.** Perfect prediction, seeing through walls, or homing that
81
+ can't be dodged. The FUN.md §7 dodge-bot exists precisely to prove a human
82
+ *can* survive; an enemy that beats the bot is unfair to people too.
83
+ - **No safe pocket.** Every enemy aggros at once with no gap to breathe → it's a
84
+ wall of pressure, not a fight ([[system-encounter-design]], FUN.md §5).
85
+ - **Iteration-order targeting.** Picking a target by array order leaks
86
+ non-determinism into the sim and breaks `world.hash()`. Order by an explicit
87
+ key.
88
+ - **Repathing every frame** — cost spikes and the enemy twitches; humans read
89
+ *committed* motion, not a gradient-follower recomputing constantly.
90
+ - **Melee foes that outrun you with no telegraph** — the fight becomes a coin
91
+ flip, not a read.
92
+
93
+ ## Verify
94
+
95
+ - **Beatable by positioning:** the kiting-bot telemetry pattern — win time, hp
96
+ floor ≥ comfortable, **0 deaths** — is the proof an enemy roster is fair
97
+ ([FUN.md §4](../../docs/FUN.md#4-top-down-action-adventure-zelda-like)).
98
+ - **Reachability first:** `connectedComponents` / flow-field over the actual
99
+ geometry before spawning chasers ([FUN.md §9](../../docs/FUN.md#9-rts-lite)).
100
+ - **Feel floor:** every attack telegraphs before its hitbox goes live — the
101
+ readability gate in [`src/verify/gates.ts`](../../src/verify/gates.ts) checks it.
102
+ - **Determinism:** golden-hash a scripted encounter; targeting and steering must
103
+ replay bit-exactly (FUN.md law 6/7).
104
+
105
+ ## Composes with
106
+
107
+ - [[system-enemy-archetypes]] — AI is the *how it moves*; archetypes are the
108
+ *what role it plays*. Same brain, different stats, different feel.
109
+ - [[system-telegraphs]] — a readable mind is mostly a well-telegraphed one; the
110
+ windup frames live here.
111
+ - [[system-encounter-design]] — one enemy is a behavior; a fight is a *composition*
112
+ of them with pressure and pockets.
113
+ - [[system-difficulty-and-dda]] — aggro radius and count are the director's dials.
114
+ - [[pattern-readability]] — the salience floor that makes a mind knowable.
115
+
116
+ ## See also
117
+
118
+ - [`docs/FUN.md` §4/§7/§9](../../docs/FUN.md) — kiting, dodge-bot fairness, flow fields.
119
+ - [`sandboxes/pathfinding-demo`](../../sandboxes/pathfinding-demo/) — the pathing primitive alone.
120
+ - [[anchor-nuclear-throne]] — tight-loop enemies whose danger is *count + read*, never cheating.
121
+ - [[anchor-shadow-of-mordor]] — where a readable mind grows a *history* ([[system-emergent-systems]]).
@@ -0,0 +1,117 @@
1
+ ---
2
+ id: system-enemy-archetypes
3
+ title: Enemy Archetypes
4
+ kind: system
5
+ tags: [enemy, archetypes, roles, tank, skirmisher, artillery, swarm, support, roster]
6
+ summary: The enemy alphabet — tank/skirmisher/artillery/swarm/support — a small set of roles that combine into fights bigger than their parts.
7
+ use-when: You need a legible enemy roster where each foe demands a different answer and pairs interact.
8
+ composes-with: [system-enemy-ai, system-encounter-design, system-unit-rosters, system-counter-systems]
9
+ anchors: [anchor-vampire-survivors, anchor-into-the-breach]
10
+ verify-with: docs/FUN.md#4-top-down-action-adventure-zelda-like
11
+ ---
12
+
13
+ # Enemy Archetypes
14
+
15
+ **What it is.** A **role vocabulary** for enemies, not a bestiary. Five roles cover
16
+ almost every action game: **tank** (soaks, blocks lanes), **skirmisher** (fast,
17
+ flanks, punishes greed), **artillery** (ranged, forces you to close or break line
18
+ of sight), **swarm** (individually trivial, dangerous in numbers), **support**
19
+ (buffs/heals/shields others — the *priority* target). The alphabet is small on
20
+ purpose: a player learns five answers, then every fight is a *sentence* of them.
21
+
22
+ **Player fantasy / why it's fun.** Recognition, then adaptation. Seeing an
23
+ artillery unit behind a tank behind a swarm is a *puzzle you read at a glance* —
24
+ the fun is choosing the order to solve it. FUN.md §4's whole claim is "readable
25
+ combat"; archetypes are how a fight becomes readable before it becomes hard.
26
+
27
+ ## When to use / when NOT
28
+
29
+ | Use it when | Skip it when |
30
+ |---|---|
31
+ | Combat has ≥3 enemy types and you want them to *combine* | A single-enemy game (one boss, one rival) — design that fight directly |
32
+ | You need difficulty from *composition*, not stat inflation | Puzzle "enemies" that are really rules ([[genre-grid-puzzle]], §12) |
33
+ | The player should learn one answer per role | Pure horde where the enemy is *count itself* — one type, superlinear spawn (§6) |
34
+
35
+ ## Variants
36
+
37
+ The five roles and what each *demands*:
38
+
39
+ | Role | Job in the fight | Player answer | Signature knob |
40
+ |---|---|---|---|
41
+ | **Tank** | control space, absorb, block a lane | reposition or burst; don't trade | HP + a lane it denies |
42
+ | **Skirmisher** | punish overextension, flank | spacing, patience, don't chase | speed > player, low HP |
43
+ | **Artillery** | force movement, deny camping | close the gap or break LoS | range + a telegraph ([[system-telegraphs]]) |
44
+ | **Swarm** | overwhelm, chip, cover others | AoE, funnels, kiting arcs (§6) | trivial each, superlinear count |
45
+ | **Support** | multiply everyone else | **kill it first** — it's the priority | a buff radius you can see |
46
+
47
+ **Compositions** are where the alphabet earns its keep:
48
+
49
+ | Pair | Emergent problem |
50
+ |---|---|
51
+ | Tank + artillery | the tank buys the artillery time; you're pressured while you dig |
52
+ | Support + swarm | the swarm won't die until the support does — inverts your target order |
53
+ | Skirmisher + tank | the tank pins you where the skirmisher wants you |
54
+ | Artillery + skirmisher | ranged forces motion, flanker punishes it — a positioning vice |
55
+
56
+ ## Tuning levers
57
+
58
+ | Lever | Effect | Watch for |
59
+ |---|---|---|
60
+ | **Role stat ratios** (HP/speed/range) | how sharply a role reads | roles that overlap muddy the read — keep silhouettes distinct |
61
+ | **Threat priority** (support first) | the target-order puzzle | if killing in any order works, the roles aren't interacting |
62
+ | **Count per role** | swarm-ness vs. elite-ness | one "swarm" unit is just a weak melee foe |
63
+ | **Telegraph length by role** | reaction budget | artillery needs the longest tell; skirmishers the shortest |
64
+
65
+ ## How it wires to Hayao
66
+
67
+ - An archetype is **data**: a stat block in `world.state` (`hp`, `speed`, `range`,
68
+ `role`) driving the shared behaviors from [[system-enemy-ai]]. Same brain,
69
+ different numbers — a tank is a seeker with high HP and a wide body; a kiter is
70
+ the ranged archetype.
71
+ - **Spawning by role** rides the director: `WaveDef.spawn` takes a weighted set,
72
+ so `pollDirector(waves, state, world.time, world.rng)` (grep `docs/API.md`) can
73
+ roll "2 swarm + 1 support" per firing, deterministically. See
74
+ [`src/content/dsl.ts`](../../src/content/dsl.ts).
75
+ - **Silhouette & palette** carry the read — distinct shapes and Kentō-palette
76
+ hues per role ([[world-aesthetic-direction]], JUDGE). The player must name the
77
+ role from the silhouette alone.
78
+ - **Roster legibility** shares the design of [[system-unit-rosters]] — the enemy
79
+ roster is a roster with the same "one glance, one role" bar.
80
+
81
+ ## Fails when…
82
+
83
+ - **Stat-only enemies.** Five foes that differ only in HP are one enemy with a
84
+ slider. Roles must demand *different answers*, not different patience.
85
+ - **No priority target.** Without support (or an equivalent "kill this first"),
86
+ every fight is a spray — order stops mattering.
87
+ - **Illegible silhouettes.** If you can't tell artillery from tank at a glance,
88
+ the read collapses ([[pattern-readability]], JUDGE).
89
+ - **Swarm that isn't a swarm.** Too few, too tanky, and it's just chip damage with
90
+ extra steps — swarm fun is *many trivial* (§6).
91
+
92
+ ## Verify
93
+
94
+ - **Each role beatable with its answer:** kiting-bot telemetry per archetype —
95
+ 0 deaths, hp floor ≥ comfortable
96
+ ([FUN.md §4](../../docs/FUN.md#4-top-down-action-adventure-zelda-like)).
97
+ - **Composition, not inflation:** assert a *skill delta* — the correct target
98
+ order clears far faster than a naive one (FUN.md law 2). If order doesn't
99
+ matter, the roles don't interact.
100
+ - **Swarm pressure holds:** `peak alive ≥ N` so the horde feel can't silently
101
+ regress ([FUN.md §6](../../docs/FUN.md#6-twin-stick-horde-survival-vampire-survivors-like)).
102
+ - **Readability gate:** telegraph-before-hitbox in [`src/verify/gates.ts`](../../src/verify/gates.ts).
103
+
104
+ ## Composes with
105
+
106
+ - [[system-enemy-ai]] — the shared brain each archetype re-skins with stats.
107
+ - [[system-encounter-design]] — archetypes are letters; encounters are the words.
108
+ - [[system-counter-systems]] — roles imply near-hard counters (AoE vs. swarm).
109
+ - [[system-unit-rosters]] — the same legibility discipline, player-side.
110
+ - [[system-boss-design]] — a boss is often a super-archetype with phases.
111
+
112
+ ## See also
113
+
114
+ - [`docs/FUN.md` §4/§6](../../docs/FUN.md) — readable combat; horde pressure.
115
+ - [`src/content/dsl.ts`](../../src/content/dsl.ts) — `WaveDef`/`pollDirector` role spawning.
116
+ - [[anchor-vampire-survivors]] — the swarm archetype as the *whole* game.
117
+ - [[anchor-into-the-breach]] — every enemy role telegraphed as a solvable board.