hayao 0.4.1 → 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 (110) 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/package.json +2 -1
@@ -0,0 +1,113 @@
1
+ ---
2
+ id: system-combat-model
3
+ title: Combat Model — the shape of a hit
4
+ kind: system
5
+ tags: [combat, damage, resolution, timing, real-time, turn-based, hit]
6
+ summary: The spine every fight sits on — how damage is computed, when it resolves, and whether the clock is frames or turns.
7
+ use-when: You have any fight — melee, ranged, tactical, brawler — and need to decide how a hit is computed and when it lands.
8
+ composes-with: [system-telegraphs, system-status-effects, system-counter-systems, system-grace, system-enemy-ai]
9
+ anchors: [anchor-into-the-breach, anchor-hades, anchor-slay-the-spire]
10
+ verify-with: docs/FUN.md#4-top-down-action-adventure-zelda-like
11
+ ---
12
+
13
+ # Combat Model — the shape of a hit
14
+
15
+ **What it is.** The **resolution rule** underneath every fight: the function that
16
+ turns *attacker + defender + context* into *a number and a moment*. Pick it before
17
+ you design a single enemy — the model decides whether combat is read-and-react,
18
+ plan-and-commit, or math-and-optimize, and every other combat system ([[system-telegraphs]],
19
+ [[system-status-effects]], [[system-counter-systems]]) hangs off it.
20
+
21
+ **Player fantasy / why it's fun.** A hit that *lands* — weight, consequence, a clean
22
+ line from your input to the enemy's flinch. Fun combat is legible cause and effect;
23
+ the model is where that legibility is either won or lost.
24
+
25
+ ## When to use / when NOT
26
+
27
+ | Use a formal combat model when… | Skip / simplify when… |
28
+ |---|---|
29
+ | Damage varies by matchup, position, or state | One-hit-kill or binary contact (a pure platformer) |
30
+ | The player makes per-hit decisions | Combat is a garnish, not a pillar |
31
+ | You need counters, statuses, or crits to interact | The "fight" is really a puzzle ([[genre-grid-puzzle]]) |
32
+
33
+ Don't bolt a deep damage formula onto a game whose fun is elsewhere. A Celeste-like
34
+ spike is `contact → death`; that *is* the model, and it's correct.
35
+
36
+ ## Variants
37
+
38
+ | Model | Clock | Damage shape | Anchor | Feels like |
39
+ |---|---|---|---|---|
40
+ | **Real-time reactive** | frames | fixed per-hit, telegraph-gated | [[anchor-shadow-of-mordor]], Zelda | read the tell, punish the gap |
41
+ | **Real-time attrition** | frames | many small ticks, DPS math | [[anchor-vampire-survivors]] | the tide vs your build |
42
+ | **Turn-based deterministic** | turns | shown = resolved, no rolls | [[anchor-into-the-breach]] | perfect-information chess |
43
+ | **Turn-based stochastic** | turns | dice / hit-chance | XCOM, roguelikes | budgeted luck, hedged plays |
44
+ | **Deckbuilt** | turns | numbers from cards + scaling | [[anchor-slay-the-spire]] | the deck *is* the weapon |
45
+ | **Combo / string** | frames | escalating multipliers per chain | [[anchor-hades]], brawlers | flow and cancels |
46
+
47
+ Blends are normal: Hades is reactive + combo; Slay the Spire is deckbuilt +
48
+ deterministic. Satisfy each parent's verify pattern ([[process-composition]]).
49
+
50
+ ## Tuning levers
51
+
52
+ | Lever | Does | Healthy range |
53
+ |---|---|---|
54
+ | **Time-to-kill (TTK)** | hits to drop a basic foe | 2–5 for reactive; the whole session for attrition |
55
+ | **Time-to-death (TTD)** | hits *you* survive | ≥ 2 before a wound; instadeath only with heavy telegraph |
56
+ | **Hit-stop** | freeze on impact — the weight | 3–8 frames; > 12 reads as a hitch (JUICE Part 2) |
57
+ | **i-frames** | invulnerable window after a hit | specced in frames, proven edge-in/edge-out |
58
+ | **Variance** | roll spread (stochastic only) | tight enough that plans hold; ≤ ±15% or shown-as-chance |
59
+ | **Crit rate / mult** | spike layer | rare + big, or frequent + small — not both |
60
+
61
+ Derive TTK/TTD from the fight length you want, not by eyeballing (FUN.md law 3).
62
+
63
+ ## How it wires to Hayao
64
+
65
+ - **Pure resolution.** Combat is a function over `world.state`; all rolls through
66
+ `world.rng`. The sim resolves *instantly* and returns choreography for the view
67
+ to replay (FUN.md law 6) — hit-stop and flash are cosmetic, never in `world.hash()`.
68
+ - **Reactive combat is telegraph-gated.** Every threat activation is preceded by a
69
+ tell; prove it with `telegraphIssues(timeline, minFrames)`. See [[system-telegraphs]].
70
+ - **Feel is a contract.** Declare a `FeedbackContract` (in `@hayao`) for `hit`,
71
+ `land`, `death`; gate hit-stop/shake with `feedbackIssues` (docs/JUICE.md Part 3).
72
+ - **Turn-based reuses the real-time stack** — an input edge is one world step
73
+ (FUN.md §10). Pure state gives clone-and-score bots for free: run the intended
74
+ line vs a null line and assert the gap (FUN.md law 2).
75
+ - Reference wiring: [`examples/updrift`](../../examples/updrift) for reactive feel;
76
+ the top-down §4 pattern for hit-stop + i-frames buffering inputs through the freeze.
77
+
78
+ ## Fails when…
79
+
80
+ - **Hit-stop eats inputs.** A freeze that doesn't buffer intent across it makes
81
+ attacks "randomly" vanish (FUN.md §4). Any pause must re-emit buffered input.
82
+ - **TTK too low both ways.** If you and the foe both die in one hit, there's no
83
+ combat — there's a coin flip. Give the loop room to *be* a loop.
84
+ - **Variance drowns skill.** Big rolls on top of a reactive read punish the correct
85
+ play. If it's stochastic, *show* the chance (intent honesty, FUN.md §11/§12).
86
+ - **Damage numbers with no resolution moment.** A number that ticks with no impact
87
+ frame reads as a spreadsheet, not a hit. Answer every hit on ≥ 2 senses (JUICE).
88
+
89
+ ## Verify
90
+
91
+ - Reactive: kiting-bot telemetry — win time, hp floor, 0 deaths; every threat
92
+ telegraphed → **[FUN.md §4](../../docs/FUN.md)**, `telegraphIssues`.
93
+ - Skill-delta: intended combat beats null (do-nothing / flail) by a margin →
94
+ **[FUN.md law 2](../../docs/FUN.md)**.
95
+ - Feel: `feedbackIssues` for hit/death; hit-stop ≤ 12 frames →
96
+ **[JUICE.md Part 3](../../docs/JUICE.md)**, **[VERIFICATION Channel 4](../../docs/VERIFICATION.md)**.
97
+ - Determinism: golden hash of a scripted fight; view-on == view-off hash.
98
+
99
+ ## Composes with
100
+
101
+ - [[system-telegraphs]] — reactive combat is *only* fair if threats announce; the
102
+ telegraph is half the model.
103
+ - [[system-status-effects]] — DoT/buffs/debuffs are damage that resolves over time;
104
+ they layer on the resolution rule.
105
+ - [[system-counter-systems]] — the matchup table that makes one hit mean more.
106
+ - [[system-grace]] — i-frames, hit-stop buffering, wound-before-death live here.
107
+ - [[system-boss-design]] — a boss is a combat model with phases and spectacle.
108
+
109
+ ## See also
110
+
111
+ - [`docs/FUN.md`](../../docs/FUN.md) §4, §6, §12 — the mechanical truths per clock.
112
+ - [`docs/JUICE.md`](../../docs/JUICE.md) — hit-stop/shake envelopes; the 2-senses contract.
113
+ - [`sandboxes/juice-lab`](../../sandboxes/juice-lab) — easing/spring feel for impacts.
@@ -0,0 +1,118 @@
1
+ ---
2
+ id: system-coop-and-competition
3
+ title: Co-op & Competition
4
+ kind: system
5
+ tags: [coop, pvp, competition, asymmetric, interdependence, rivalry, multiplayer, communication]
6
+ summary: Co-op and PvP hooks — asymmetric co-op, interdependence, and rivalry that make other players the most interesting system in the game.
7
+ use-when: The design has more than one player and you need to shape how they cooperate, compete, or depend on each other.
8
+ composes-with: [system-faction-asymmetry, system-encounter-design, genre-coop-chaos, pattern-emergence]
9
+ anchors: [anchor-overcooked, anchor-it-takes-two]
10
+ verify-with: docs/FUN.md#part-1--universal-laws
11
+ ---
12
+
13
+ # Co-op & Competition
14
+
15
+ **What it is.** The design of **other players** as a system. Two engines: **co-op**
16
+ (players pursue a shared goal) and **competition** (players pursue opposed goals) —
17
+ and the richest designs make players **interdependent** (co-op) or **rivalrous**
18
+ (PvP) rather than merely co-located. Overcooked forces *communication* by making one
19
+ person's job depend on another's; It Takes Two gives each player a *different verb*
20
+ so neither can proceed alone.
21
+
22
+ **Player fantasy / why it's fun.** *You needed me / I beat you.* Co-op's pull is
23
+ shared triumph and the panic-laughter of a plan under pressure; competition's is the
24
+ sharp joy of a read that beat a real mind. Both put the most reactive, least
25
+ predictable system in the room — a *person* — at the center.
26
+
27
+ ## When to use / when NOT
28
+
29
+ | Use it when | Skip it when |
30
+ |---|---|
31
+ | Two+ players share a screen/session | A solo experience — don't bolt on multiplayer |
32
+ | Interdependence or rivalry is the *point* | "Multiplayer" that's just two solo games side by side |
33
+ | Communication-under-pressure is the fun | Turn-based async where presence adds nothing |
34
+
35
+ > **Interdependence is the design, not the player count.** Two players who could
36
+ > each finish alone are playing *near* each other, not *with* each other. Force the
37
+ > dependency — split the verbs, split the resources, split the information — and
38
+ > co-op becomes a conversation ([[anchor-overcooked]], [[anchor-it-takes-two]]).
39
+
40
+ ## Variants
41
+
42
+ | Variant | Structure | Feels like | Anchor |
43
+ |---|---|---|---|
44
+ | **Symmetric co-op** | same abilities, shared goal | "divide the work" | most horde co-op |
45
+ | **Asymmetric co-op** | different verbs, shared goal | "I can't do your job" | [[anchor-it-takes-two]] |
46
+ | **Forced-comms co-op** | one's task gates another's | "TALK to me" | [[anchor-overcooked]] |
47
+ | **Symmetric PvP** | mirror match | "pure skill read" | fighting/RTS |
48
+ | **Asymmetric PvP** | different roles/goals | "hunter vs. hunted" | 1-vs-many |
49
+ | **Shared-world rivalry** | indirect competition | "I beat your score/ghost" | leaderboards, ghosts |
50
+
51
+ ## Tuning levers
52
+
53
+ | Lever | Effect | Watch for |
54
+ |---|---|---|
55
+ | **Interdependence depth** | how much players *need* each other | too much = one weak link stalls all; too little = parallel play |
56
+ | **Communication pressure** | how hard they must coordinate | time pressure forces talk (Overcooked); own it in [[genre-coop-chaos]] |
57
+ | **Asymmetry balance** | different roles, comparable impact | one role feeling like a passenger kills it |
58
+ | **Rivalry stakes** | what winning takes from the loser | too harsh = griefing; too soft = no bite |
59
+ | **Solo-fallback** | can one carry a struggling partner? | none = brittle; total = interdependence lost |
60
+
61
+ ## How it wires to Hayao
62
+
63
+ - **Multiple players = multiple input streams into one deterministic sim.** Each
64
+ player's intent flows as input *actions* on the shared `world.state`; because the
65
+ sim is pure and rolls through `world.rng`, a co-op or PvP session is one
66
+ deterministic, replayable artifact — the same seam Studio records
67
+ ([`docs/STUDIO.md`](../../docs/STUDIO.md), FUN.md law 7). *(Grep `docs/API.md`
68
+ before assuming any specific netcode primitive — Hayao's guarantee is the
69
+ deterministic sim, not a bundled transport.)*
70
+ - **Rollback-with-carryover is already here.** The knob-change / hot-swap
71
+ "snapshot → restore → `attach`" contract is the *same* contract rollback netplay
72
+ uses (STUDIO knob-change semantics) — the determinism you need for co-op is the
73
+ determinism the engine already enforces.
74
+ - **Asymmetric roles reuse faction design.** "Different but fair" is exactly
75
+ [[system-faction-asymmetry]] applied to players — assert each role's viability the
76
+ way you'd assert a faction's.
77
+ - **Shared encounters** are still [[system-encounter-design]] — pockets and exit
78
+ lanes now serve two bodies, not one.
79
+
80
+ ## Fails when…
81
+
82
+ - **Parallel play.** Players who never need each other are two solo games sharing a
83
+ screen — no co-op fun (interdependence missing).
84
+ - **A passenger role.** In asymmetric designs, a role with no real impact benches a
85
+ player — balance the roles like factions.
86
+ - **Griefing headroom.** PvP stakes so harsh (or tools so one-sided) that winning
87
+ means ruining someone's session.
88
+ - **Coordination with no pressure.** Co-op that *permits* silence rarely *creates*
89
+ talk — pressure (time, scarcity, split info) is what forces the conversation.
90
+ - **Non-determinism across clients.** Any wall-clock, `Math.random`, or
91
+ iteration-order drift and the shared sim desyncs (CLAUDE.md invariant 2).
92
+
93
+ ## Verify
94
+
95
+ - **Determinism across streams:** golden-hash a scripted two-player session; the
96
+ shared sim replays bit-exactly regardless of which player acted when
97
+ ([FUN.md law 7](../../docs/FUN.md#part-1--universal-laws)).
98
+ - **Every role viable (asymmetric):** assert each role's contribution clears a
99
+ floor — the faction-viability check applied per player
100
+ ([[system-faction-asymmetry]]; FUN.md law 2 skill-delta shape).
101
+ - **Interdependence proof:** a scripted "one player idles" run *fails* the shared
102
+ objective — if solo-carry always works, the dependency isn't real (FUN.md law 4
103
+ null-strategy shape).
104
+ - **Shared encounter fairness:** pockets/exit-lanes hold for the group
105
+ ([[system-encounter-design]], FUN.md §4/§5).
106
+
107
+ ## Composes with
108
+
109
+ - [[genre-coop-chaos]] — the genre where forced-comms co-op is the whole game.
110
+ - [[system-faction-asymmetry]] — asymmetric roles are player-side factions.
111
+ - [[system-encounter-design]] — fights now serve multiple bodies.
112
+ - [[pattern-emergence]] — the most emergent system in any game is another person.
113
+
114
+ ## See also
115
+
116
+ - [`docs/STUDIO.md`](../../docs/STUDIO.md) — deterministic sessions + the rollback-with-carryover contract.
117
+ - [`docs/FUN.md` law 7](../../docs/FUN.md#part-1--universal-laws) — pure state makes multiplayer replayable.
118
+ - [[anchor-overcooked]] · [[anchor-it-takes-two]] — forced communication and asymmetric interdependence.
@@ -0,0 +1,115 @@
1
+ ---
2
+ id: system-counter-systems
3
+ title: Counter Systems — the duel matrix
4
+ kind: system
5
+ tags: [counters, rock-paper-scissors, matchup, duel, near-hard, balance]
6
+ summary: Rock-paper-scissors with teeth — NEAR-HARD counters that stay decisive under scaling, so the answer to a threat is a choice, not a bigger number.
7
+ use-when: You have unit types, weapons, or tools that should beat each other, and you need the matchups to actually matter.
8
+ composes-with: [system-unit-rosters, system-faction-asymmetry, system-build-diversity, system-combat-model, system-status-effects]
9
+ anchors: [anchor-starcraft, anchor-age-of-empires]
10
+ verify-with: docs/FUN.md#8-tower-defense
11
+ ---
12
+
13
+ # Counter Systems — the duel matrix
14
+
15
+ **What it is.** The **matchup table**: the rule that pikes beat cavalry, air beats
16
+ ground, fire beats ice. A counter system makes the *right tool* a decision instead
17
+ of the *bigger stack* — it's what turns [[system-unit-rosters]] and
18
+ [[system-faction-asymmetry]] into a game of composition rather than accumulation.
19
+
20
+ **Player fantasy / why it's fun.** "I read your army and I built the answer." A
21
+ counter is a puzzle you solve with production, not reflexes — scouting, reacting,
22
+ and the small triumph of the hard counter arriving just in time.
23
+
24
+ ## When to use / when NOT
25
+
26
+ | Use counters when… | Skip when… |
27
+ |---|---|
28
+ | Multiple unit/weapon types coexist | There's one avatar and one attack |
29
+ | Composition should beat brute force | The fun is execution, not selection |
30
+ | Factions/rosters need internal tension | You have < 3 types (no matrix to speak of) |
31
+
32
+ ## Variants
33
+
34
+ | Shape | Counter strength | Anchor | Note |
35
+ |---|---|---|---|
36
+ | **Hard RPS** | A auto-beats B | fighting games, some RTS | decisive, can feel arbitrary |
37
+ | **Near-hard** | A *strongly* favored vs B | [[anchor-starcraft]], [[anchor-age-of-empires]] | the sweet spot — see below |
38
+ | **Soft resist** | A takes ~15% less from B | many RPGs | **erased by scaling** — avoid as the whole system |
39
+ | **Tag / type** | fire > ice > … cyclic | Pokémon | legible, teachable |
40
+ | **Positional** | flank/backstab/height | tactics | counter is *where*, not *what* |
41
+
42
+ ## The near-hard doctrine
43
+
44
+ FUN.md §8/§9 is blunt: **soft resists get erased by count-scaling.** A 15% resist
45
+ vanishes the moment the player fields ten of the resisting unit — the matchup stops
46
+ mattering, and the "counter" is decorative. Counters must be **near-hard**: strong
47
+ enough that the *right* unit meaningfully wins the duel even before you out-mass.
48
+
49
+ The design target is a duel you can prove:
50
+
51
+ > The counter unit wins its NvN duel at equal or lower cost; the countered unit,
52
+ > even with a *bigger budget*, loses it. (FUN.md §8: "mono build with a bigger
53
+ > budget fails; mixed build survives.")
54
+
55
+ Near-hard, not *hard*, because a pure auto-win removes the micro/positioning layer —
56
+ you want "strongly favored, still winnable with skill," not "the fight is decided
57
+ by the build screen."
58
+
59
+ ## Tuning levers
60
+
61
+ | Lever | Does | Healthy range |
62
+ |---|---|---|
63
+ | **Counter multiplier** | how much the favored unit wins by | near-hard: the duel flips outcome, not just shaves HP |
64
+ | **Matrix density** | how many pairs have a counter | every unit both counters and is countered — no pure winner |
65
+ | **Reveal cost** | how hard to scout the enemy comp | information *is* the counter game; make scouting real |
66
+ | **Reaction lead time** | build-time to answer a threat | long enough to punish greed, short enough to recover |
67
+ | **Cyclicity** | RPS loop closes (no dominant) | assert no unit sits outside all counters |
68
+
69
+ ## How it wires to Hayao
70
+
71
+ - **The duel is the test.** Pure state + `world.rng` means you clone the world, run
72
+ an NvN fight, and read the result (FUN.md law 7). Assert each counter edge wins its
73
+ duel from *both sides* (FUN.md §8/§9). RTS-lite exports arrival/tolerance constants
74
+ as API so the test shares the sim's constants (FUN.md §9).
75
+ - **Coverage is geometry** for ranged counters — range × distance-to-lane = the
76
+ fire-window chord (FUN.md §8). Draw the ring; it's the genre's key UI.
77
+ - **Mass pathing** for RTS counters uses cached flow fields (one BFS per goal,
78
+ *outside* state) — see [[system-unit-rosters]] and FUN.md §9. Grep [`docs/API.md`](../../docs/API.md)
79
+ for `astarGrid`/`floodFill` before citing a pathing call.
80
+ - Reference: FUN.md §9 RTS-lite (counter-edge NvN duels) and §8 tower-defense
81
+ (mixed beats mono).
82
+
83
+ ## Fails when…
84
+
85
+ - **Soft resists only.** Scaling erases them; the "counter system" evaporates by
86
+ midgame (the canonical §8/§9 failure).
87
+ - **A dominant unit.** One type outside the RPS loop becomes the answer to
88
+ everything — [[system-build-diversity]] and the whole matrix collapse.
89
+ - **Invisible matchups.** Counters the player can't scout or read are just
90
+ memorization tax. Surface the matrix (a range ring, a type icon).
91
+ - **Hard auto-wins everywhere.** Removes micro — the fight is settled off-screen.
92
+ Aim near-hard, keep a skill margin.
93
+
94
+ ## Verify
95
+
96
+ - **[FUN.md §8](../../docs/FUN.md)** — mixed build survives 10/10; mono build (bigger
97
+ budget) fails; bare lane falls early; counter duels from both sides.
98
+ - **[FUN.md §9](../../docs/FUN.md)** — every counter edge wins its NvN duel; the
99
+ intended composition beats attack-move.
100
+ - **[FUN.md law 2](../../docs/FUN.md)** — the countering strategy beats the null (mono)
101
+ strategy by a margin.
102
+ - Determinism: golden hash of a scripted duel set.
103
+
104
+ ## Composes with
105
+
106
+ - [[system-unit-rosters]] — the roster is the set of pieces the matrix connects.
107
+ - [[system-faction-asymmetry]] — factions counter *across* the mirror, not just within.
108
+ - [[system-build-diversity]] — near-hard counters are what keep multiple builds alive.
109
+ - [[system-status-effects]] — cleanse/resist/immunity are the status-layer counters.
110
+
111
+ ## See also
112
+
113
+ - [`docs/FUN.md`](../../docs/FUN.md) §8, §9 — the duel-from-both-sides proofs.
114
+ - [[anchor-starcraft]] — three rosters, near-hard counters, one balance.
115
+ - [`sandboxes/pathfinding-demo`](../../sandboxes/pathfinding-demo) — `astarGrid`/`floodFill` for mass counters.
@@ -0,0 +1,115 @@
1
+ ---
2
+ id: system-crafting
3
+ title: Crafting — Recipes & Combinatorial Depth
4
+ kind: system
5
+ tags: [crafting, recipes, combination, discovery, lookup, depth, materials]
6
+ summary: Combining inputs into outputs by recipe; combinatorial depth as content, and the discovery-vs-lookup axis that decides how the player learns it.
7
+ use-when: The design lets players combine materials/items into new ones and you need the recipe space to be deep, legible, and worth exploring.
8
+ composes-with: [system-resource-loops, system-economy, system-build-diversity, system-collectibles, system-tech-tree]
9
+ anchors: [anchor-factorio, anchor-stardew-valley]
10
+ verify-with: docs/FUN.md#1-grid-puzzle-sokoban
11
+ ---
12
+
13
+ # Crafting — Recipes & Combinatorial Depth
14
+
15
+ **What it is.** A **recipe system**: inputs (materials, items, ingredients) combine
16
+ by rule into outputs. The depth is combinatorial — a modest set of inputs and
17
+ recipes yields a large possibility space. The design choice is how the player
18
+ *learns* the space: handed the recipe (**lookup**) or finding it (**discovery**).
19
+
20
+ **Player fantasy / why it's fun.** "I turned these scraps into *that*." Crafting
21
+ rewards planning and packrat instinct; discovery crafting adds the "what if I
22
+ combine…" curiosity. The pull is the recipe you don't have yet — and the hunch
23
+ about what makes it.
24
+
25
+ ## When to use / when NOT
26
+
27
+ | Use it when | Skip it when |
28
+ |---|---|
29
+ | Combining things is a core verb (survival, sim, alchemy) | Items are found whole; no combination step |
30
+ | You want depth from few pieces via combinatorics | A flat shop ([[system-economy]]) covers acquisition |
31
+ | Recipe *discovery* can carry curiosity | Recipes would just be an inventory tax |
32
+
33
+ Crafting is the **convert** node of a **[[system-resource-loops]]** made
34
+ *combinatorial*. If there's exactly one useful recipe per material, you don't have
35
+ crafting — you have a conversion. Crafting earns its name when *choices between
36
+ recipes* exist.
37
+
38
+ ## Variants
39
+
40
+ | Variant | How the player learns | Depth from | Example |
41
+ |---|---|---|---|
42
+ | **Recipe list (lookup)** | Given the recipe book | Resource management | Minecraft (known), Stardew |
43
+ | **Discovery** | Experiment to find combos | Curiosity, "what if" | Little Alchemy; Doodle God |
44
+ | **Grid/shape** | Spatial arrangement matters | Pattern puzzles | Minecraft crafting grid |
45
+ | **Modifier/affix** | Base + modifiers roll | Build optimization | Diablo runewords; PoE crafting |
46
+ | **Emergent (systemic)** | Rules interact, no explicit recipes | Second-order surprise | Breath of the Wild elixirs; Noita |
47
+
48
+ The **discovery** and **emergent** variants trade legibility for wonder — powerful,
49
+ but they need a fallback so the player is never *stuck* (a hint, a partial reveal).
50
+
51
+ ## Tuning levers
52
+
53
+ | Lever | What it controls | Healthy range / rule |
54
+ |---|---|---|
55
+ | **Recipe count** | Breadth of the space | Enough to explore; each recipe must *do* something distinct |
56
+ | **Combinatorial fan-out** | Outputs per input set | High fan-out = deep from few pieces (the whole point) |
57
+ | **Discovery vs lookup** | How recipes are learned | Discovery for wonder; lookup for planning games. Mixing: teach basics, hide the exotic |
58
+ | **Ingredient scarcity** | Cost of a craft | Ties crafting to the economy — scarce inputs make recipes decisions |
59
+ | **Legibility** | Can the player *plan*? | Show what a recipe needs before they commit ingredients |
60
+ | **Dead-end density** | Useless recipes | Keep low — a discovered recipe that does nothing punishes curiosity |
61
+
62
+ ## How it wires to Hayao
63
+
64
+ - **Recipes are pure data + pure logic.** A recipe is `{inputs, output}`; crafting
65
+ is a **pure function** over inventory state in `world.state`, invoked by an
66
+ **input action**. This makes the recipe space *machine-checkable*: it's the same
67
+ shape as a `Puzzle<State, Move>` — you can solver-search "is item X craftable
68
+ from starting materials?" the way the grid-puzzle solver proves reachability
69
+ (**[[FUN.md §1]]**).
70
+ - **Prove reachability.** Assert every *intended* output is craftable from
71
+ obtainable inputs — a connectivity proof over the recipe graph, mirroring the
72
+ roguelike "all loot reachable" sweep (**[[FUN.md §10]]**). No orphan recipes.
73
+ - **The crafting UI is chrome.** The recipe book / bench menu is `showScreen()`
74
+ DOM; inventory *counts* are sim state, the panel is `cosmetic` (CLAUDE.md
75
+ invariant 4, **[[FUN.md law 6]]**).
76
+ - **Generate the recipe set as content.** Lean on `src/content/` to *generate*
77
+ balanced recipe trees and prove them reachable, rather than hand-authoring a
78
+ hundred recipes and hoping.
79
+
80
+ ## Fails when…
81
+
82
+ - **Orphan recipes.** An output nothing reaches, or an ingredient nothing uses —
83
+ dead weight. Prove the graph connected.
84
+ - **One true recipe.** If every craft has a single obvious answer, it's conversion
85
+ cosplaying as crafting. Add meaningful alternatives.
86
+ - **Discovery with no floor.** Pure discovery + no hints = players stuck, guessing.
87
+ Always give a nudge before frustration.
88
+ - **Illegible cost.** Committing ingredients before seeing the recipe wastes scarce
89
+ materials — feels like a trap.
90
+ - **Inventory tax.** Crafting that's mandatory busywork (craft to progress, no
91
+ choice) — cut it or make it optional.
92
+
93
+ ## Verify
94
+
95
+ - Recipe reachability as a connectivity/solver proof (every intended output
96
+ craftable): **[[FUN.md §10]]** (connectivity) and **[[FUN.md §1]]** (solver over
97
+ a `Puzzle`-shaped state).
98
+ - Determinism: same inputs → same output, replay-hash identical: **[[FUN.md law 7]]**.
99
+ - Ingredient economy stays in a pacing window: **[[FUN.md §14]]**.
100
+
101
+ ## Composes with
102
+
103
+ - [[system-resource-loops]] — crafting is the combinatorial *convert* step.
104
+ - [[system-economy]] — ingredients are currency; recipes are structured sinks.
105
+ - [[system-build-diversity]] — modifier/affix crafting is a build engine.
106
+ - [[system-collectibles]] — a recipe book is a set to complete.
107
+ - [[system-tech-tree]] — research unlocks new recipes.
108
+
109
+ ## See also
110
+
111
+ - [`docs/FUN.md`](../../docs/FUN.md) §1 (solver over pure state) · §10
112
+ (connectivity) — recipe reachability rides both.
113
+ - `src/content/generate.ts` — generate & prove a recipe/level space instead of
114
+ hand-authoring it.
115
+ - **[[anchor-factorio]]** — recipes as the production spine.
@@ -0,0 +1,114 @@
1
+ ---
2
+ id: system-difficulty-and-dda
3
+ title: Difficulty & Dynamic Difficulty
4
+ kind: system
5
+ tags: [difficulty, dda, curve, spikes, breathers, ai-director, assist, ramp, pacing]
6
+ summary: Difficulty curves that breathe — spikes and breathers, an AI director that authors pressure, and assist modes that never shame.
7
+ use-when: You need to shape challenge over a session, react to a player's skill, or offer honest difficulty options.
8
+ composes-with: [system-encounter-design, system-onboarding, system-accessibility, pattern-pacing-and-tension]
9
+ anchors: [anchor-rimworld, anchor-celeste]
10
+ verify-with: docs/FUN.md#8-tower-defense
11
+ ---
12
+
13
+ # Difficulty & Dynamic Difficulty
14
+
15
+ **What it is.** How hard the game is, *over time* and *per player*. Three tools:
16
+ a **difficulty curve** (a designed sequence of spikes and breathers), a **director**
17
+ (a system that spawns pressure in response to state), and **assist modes** (honest
18
+ knobs that let anyone find their edge). The goal is the **flow channel** — challenge
19
+ tracking skill, never far above or below ([[pattern-mastery-and-flow]]).
20
+
21
+ **Player fantasy / why it's fun.** Being *tested at exactly your level*. A curve
22
+ that breathes lets tension land — a boss hits harder after a quiet corridor. A
23
+ director makes a run feel *authored to you*. Assist modes let the humane version of
24
+ the fantasy exist (Celeste): the game meets you, it doesn't gate-keep you.
25
+
26
+ ## When to use / when NOT
27
+
28
+ | Tool | Reach for it when | Don't when |
29
+ |---|---|---|
30
+ | **Authored curve** | linear/campaign content; you control order | fully procedural — shape the *generator's* band instead |
31
+ | **Director (DDA)** | survival, colony sim, replayable runs; you want reactive pressure | tight puzzles — perfect information forbids hidden dials (§12) |
32
+ | **Assist modes** | any single-player skill game | competitive PvP where fairness is symmetry |
33
+
34
+ > **Two ditches.** Static difficulty leaves half your players bored and the other
35
+ > half walled out. A *hidden* rubber-band that punishes doing well ("do better,
36
+ > get punished") betrays trust the moment it's noticed. DDA must nudge, never lie.
37
+
38
+ ## Variants
39
+
40
+ | Variant | How it decides | Feels like | Anchor |
41
+ |---|---|---|---|
42
+ | **Authored curve** | fixed schedule of encounters | a designed rollercoaster | most campaigns |
43
+ | **Threat-budget director** | spends a rising budget on spawns | escalating siege | [[anchor-rimworld]]'s storyteller |
44
+ | **Performance DDA** | reads hp/deaths/time, adjusts spawns | "the game read me" | Left-4-Dead-style |
45
+ | **Player-chosen tiers** | difficulty menu | honest self-selection | Doom, most action games |
46
+ | **Assist toggles** | per-axis mercy (speed, i-frames, skip) | "I set my own edge" | [[anchor-celeste]] assist mode |
47
+
48
+ ## Tuning levers
49
+
50
+ | Lever | Effect | Watch for |
51
+ |---|---|---|
52
+ | **Spike/breather rhythm** | tension arc | monotone-rising = exhausting; flat = dull |
53
+ | **Director budget slope** | how fast pressure grows | superlinear needed to outpace build growth (§6) |
54
+ | **DDA sensitivity** | how sharply it reacts | too twitchy = visibly rubber-bandy |
55
+ | **DDA bounds** | floor/ceiling on adjustment | unbounded = trivializes or walls |
56
+ | **Assist granularity** | per-axis vs. one slider | one slider forces all-or-nothing |
57
+
58
+ ## How it wires to Hayao
59
+
60
+ - **The director already exists.** `initDirector(waves)` +
61
+ `pollDirector(waves, state, world.time, world.rng)` (grep `docs/API.md`,
62
+ [`src/content/dsl.ts`](../../src/content/dsl.ts)) is a deterministic pressure
63
+ authorer: waves fire on sim time, weighted spawns roll through `world.rng`, and
64
+ catch-up after a restore never drops spawns. Keep `DirectorState` in
65
+ `world.state` so pressure is hashed and replayable.
66
+ - **Performance DDA reads the probe.** The same numbers `world.probe()` exposes
67
+ (hp floor, time alive, deaths) are the DDA inputs — bounded, ordered, and part of
68
+ `world.hash()` so difficulty can't silently escape determinism.
69
+ - **The curve is checkable.** `assertRamp(difficulty, opts)` / `rampIssues` (grep
70
+ `docs/API.md`) assert the *shape* — a designed ramp with breathers, not
71
+ monotonicity. Author the sequence, then prove it breathes.
72
+ - **Assist modes are tuning.** Model them as declared `tuning:` knobs
73
+ ([`docs/STUDIO.md`](../../docs/STUDIO.md)); their resolved values live in
74
+ `world.hash()` via `world.tune(key)`, so an assisted run is still a first-class,
75
+ replayable artifact — not a second-class cheat path.
76
+
77
+ ## Fails when…
78
+
79
+ - **Monotone difficulty.** Always-harder with no breather has no arc — tension
80
+ can't spike without a valley (FUN.md §8, [[pattern-pacing-and-tension]]).
81
+ - **Visible rubber-band.** Players who notice they're punished for playing well
82
+ stop trying — the trust cost outweighs the smoothing.
83
+ - **Unbounded DDA.** No floor/ceiling and the director either trivializes the game
84
+ or spirals it out of reach.
85
+ - **Assist as shame.** Locking achievements or nagging on assist turns a humane
86
+ tool into a punishment. Assist is a *setting*, not a confession (Celeste).
87
+ - **Sublinear survival pressure.** In hordes, linear spawn loses to multiplicative
88
+ build growth — the ramp must be superlinear (§6).
89
+
90
+ ## Verify
91
+
92
+ - **Curve breathes:** `assertRamp`/`rampIssues` on the difficulty series — each
93
+ wave ≥ ~55% of prior, finale peaks ([FUN.md §8](../../docs/FUN.md#8-tower-defense)).
94
+ - **Win-rate window, not a point:** a competent bot should land *inside* a band
95
+ (e.g. 11–19 of 20) — both edges break CI ([FUN.md §11](../../docs/FUN.md#11-roguelike-deckbuilder)).
96
+ - **Null loses at every tier:** the do-nothing/undefended run fails on easy too
97
+ (FUN.md law 4).
98
+ - **Determinism under DDA:** golden-hash a scripted run at each setting; tuning
99
+ values are in `world.hash()` (STUDIO knob-change semantics).
100
+
101
+ ## Composes with
102
+
103
+ - [[system-encounter-design]] — the units a curve or director sequences.
104
+ - [[system-onboarding]] — the first ten minutes are the gentlest slope; the curve starts here.
105
+ - [[system-accessibility]] — assist modes are the accessible face of difficulty.
106
+ - [[pattern-pacing-and-tension]] — spikes/breathers are pacing made mechanical.
107
+ - [[pattern-mastery-and-flow]] — the flow channel is the target the curve tracks.
108
+
109
+ ## See also
110
+
111
+ - [`docs/FUN.md` §6/§8/§11](../../docs/FUN.md) — superlinear pressure, breathing waves, win-rate windows.
112
+ - [`src/content/dsl.ts`](../../src/content/dsl.ts) — the director primitive.
113
+ - [[anchor-rimworld]] — the AI storyteller as difficulty *and* narrative.
114
+ - [[anchor-celeste]] — assist mode as the humane difficulty floor.