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.
- package/design/00-process/README.md +49 -0
- package/design/00-process/composition.md +148 -0
- package/design/00-process/core-loop.md +146 -0
- package/design/00-process/intent-to-brief.md +128 -0
- package/design/00-process/pillars.md +139 -0
- package/design/00-process/refine-and-handoff.md +156 -0
- package/design/00-process/the-twist.md +108 -0
- package/design/10-anchors/README.md +99 -0
- package/design/10-anchors/age-of-empires.md +103 -0
- package/design/10-anchors/baba-is-you.md +127 -0
- package/design/10-anchors/balatro.md +132 -0
- package/design/10-anchors/celeste.md +136 -0
- package/design/10-anchors/civilization.md +101 -0
- package/design/10-anchors/dead-cells.md +125 -0
- package/design/10-anchors/factorio.md +100 -0
- package/design/10-anchors/hades.md +127 -0
- package/design/10-anchors/into-the-breach.md +125 -0
- package/design/10-anchors/it-takes-two.md +104 -0
- package/design/10-anchors/loop-hero.md +131 -0
- package/design/10-anchors/nuclear-throne.md +130 -0
- package/design/10-anchors/outer-wilds.md +107 -0
- package/design/10-anchors/overcooked.md +102 -0
- package/design/10-anchors/peggle.md +133 -0
- package/design/10-anchors/reigns.md +99 -0
- package/design/10-anchors/return-of-the-obra-dinn.md +108 -0
- package/design/10-anchors/rimworld.md +101 -0
- package/design/10-anchors/shadow-of-mordor.md +106 -0
- package/design/10-anchors/slay-the-spire.md +127 -0
- package/design/10-anchors/starcraft.md +98 -0
- package/design/10-anchors/stardew-valley.md +103 -0
- package/design/10-anchors/tetris.md +122 -0
- package/design/10-anchors/vampire-survivors.md +122 -0
- package/design/20-genres/README.md +62 -0
- package/design/20-genres/action-adventure.md +126 -0
- package/design/20-genres/auto-battler.md +121 -0
- package/design/20-genres/bullet-hell.md +123 -0
- package/design/20-genres/city-builder.md +124 -0
- package/design/20-genres/coop-chaos.md +124 -0
- package/design/20-genres/deckbuilder.md +122 -0
- package/design/20-genres/exploration.md +131 -0
- package/design/20-genres/farming-sim.md +122 -0
- package/design/20-genres/grid-puzzle.md +126 -0
- package/design/20-genres/horde-survival.md +128 -0
- package/design/20-genres/incremental.md +120 -0
- package/design/20-genres/match3.md +120 -0
- package/design/20-genres/metroidvania.md +132 -0
- package/design/20-genres/narrative-decisions.md +122 -0
- package/design/20-genres/physics-arcade.md +124 -0
- package/design/20-genres/precision-platformer.md +127 -0
- package/design/20-genres/racing.md +126 -0
- package/design/20-genres/rhythm.md +125 -0
- package/design/20-genres/roguelike.md +122 -0
- package/design/20-genres/rts.md +169 -0
- package/design/20-genres/stealth.md +125 -0
- package/design/20-genres/survival-horror.md +124 -0
- package/design/20-genres/tactics.md +123 -0
- package/design/20-genres/tower-defense.md +120 -0
- package/design/30-systems/README.md +69 -0
- package/design/30-systems/accessibility.md +110 -0
- package/design/30-systems/boss-design.md +126 -0
- package/design/30-systems/build-diversity.md +120 -0
- package/design/30-systems/collectibles.md +108 -0
- package/design/30-systems/combat-model.md +113 -0
- package/design/30-systems/coop-and-competition.md +118 -0
- package/design/30-systems/counter-systems.md +115 -0
- package/design/30-systems/crafting.md +115 -0
- package/design/30-systems/difficulty-and-dda.md +114 -0
- package/design/30-systems/economy.md +117 -0
- package/design/30-systems/emergent-systems.md +114 -0
- package/design/30-systems/encounter-design.md +107 -0
- package/design/30-systems/enemy-ai.md +121 -0
- package/design/30-systems/enemy-archetypes.md +117 -0
- package/design/30-systems/faction-asymmetry.md +144 -0
- package/design/30-systems/grace.md +124 -0
- package/design/30-systems/mastery-curve.md +116 -0
- package/design/30-systems/meta-progression.md +114 -0
- package/design/30-systems/onboarding.md +115 -0
- package/design/30-systems/procgen-design.md +118 -0
- package/design/30-systems/progression.md +120 -0
- package/design/30-systems/resource-loops.md +112 -0
- package/design/30-systems/reward-schedules.md +124 -0
- package/design/30-systems/save-and-checkpoint.md +113 -0
- package/design/30-systems/session-structure.md +113 -0
- package/design/30-systems/skill-trees.md +111 -0
- package/design/30-systems/status-effects.md +111 -0
- package/design/30-systems/tech-tree.md +112 -0
- package/design/30-systems/telegraphs.md +106 -0
- package/design/30-systems/unit-rosters.md +123 -0
- package/design/40-worldbuilding/README.md +49 -0
- package/design/40-worldbuilding/aesthetic-direction.md +155 -0
- package/design/40-worldbuilding/faction-identity.md +136 -0
- package/design/40-worldbuilding/naming-and-tone.md +130 -0
- package/design/40-worldbuilding/narrative-delivery.md +129 -0
- package/design/40-worldbuilding/theme-vectors.md +134 -0
- package/design/40-worldbuilding/worldbuilding-scaffold.md +132 -0
- package/design/50-patterns/README.md +54 -0
- package/design/50-patterns/anti-frustration.md +121 -0
- package/design/50-patterns/emergence.md +121 -0
- package/design/50-patterns/feedback-loops.md +121 -0
- package/design/50-patterns/juice-choreography.md +124 -0
- package/design/50-patterns/mastery-and-flow.md +121 -0
- package/design/50-patterns/pacing-and-tension.md +120 -0
- package/design/50-patterns/readability.md +121 -0
- package/design/50-patterns/risk-reward.md +120 -0
- package/design/CONTRIBUTING.md +183 -0
- package/design/INDEX.md +133 -0
- package/design/README.md +86 -0
- package/design/_TEMPLATE.md +69 -0
- package/design/index.json +2720 -0
- package/dist/anim/blend.d.ts +68 -0
- package/dist/anim/clip.d.ts +87 -0
- package/dist/anim/ik.d.ts +40 -0
- package/dist/anim/skeleton.d.ts +64 -0
- package/dist/hayao.global.js +12 -12
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1683 -516
- package/dist/index.js.map +4 -4
- package/dist/index.min.js +12 -12
- package/dist/render/canvas2d-core.d.ts +4 -0
- package/dist/render/commands.d.ts +19 -0
- package/dist/render/lightRun.d.ts +35 -0
- package/dist/render/svgString.d.ts +8 -3
- package/dist/scene/clipPlayer.d.ts +58 -0
- package/dist/scene/ikTarget.d.ts +25 -0
- package/dist/scene/light.d.ts +80 -0
- package/dist/scene/shadow2d.d.ts +25 -0
- package/dist/scene/skeletonDebug.d.ts +28 -0
- package/dist/verify/gates.d.ts +25 -0
- package/docs/API.md +66 -8
- package/docs/CONVENTIONS.md +56 -0
- 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.
|