diff --git a/.agents/skills/world-design-review/SKILL.md b/.agents/skills/world-design-review/SKILL.md new file mode 100644 index 00000000..44750f04 --- /dev/null +++ b/.agents/skills/world-design-review/SKILL.md @@ -0,0 +1,176 @@ +--- +name: world-design-review +description: Review a world file, floor schedule, arc or world-generation change for design — playability, fairness, pacing, layout and variety — against VISION.md and the engine's own checks. Use when authoring or reviewing db/seeds/worlds/*.yml or lib/engine_sweep/worlds/*.yml, a floor: block, guards, an arc, or anything that decides what a world contains; not for prompt wording (that is EVALUATION.md's). +--- + +# Review a world for design + +A world is the one place a design mistake becomes durable: a place is generated +once and kept, so a world file that cannot be finished, or that kills a player +without warning, stays that way for every game played in it. This skill asks +the design questions of a world and insists that every answer rests on +something the engine or a command can show. + +**Evidence is a doctor finding, a sweep assertion, a fight-simulator result or +a lab score — never "it reads better".** A claim with none of those behind it +is labelled a hand trace, and says so. This is the project's standing +constraint (`AGENTS.md`, "The standing constraint") applied to design. + +## The rulings come first + +Read these before any lens below; a lens never outranks them. Where outside +design advice (`references/principles.md`) disagrees with a ruling, the ruling +stands and the review says so rather than reopening it. + +- [VISION.md](../../../VISION.md), guiding principles 1 (the engine is the + source of truth; models never set a number), 2 (the narrator is never told + the dice), 5 (danger is real), 6 (worlds stay varied; the engine's dice place + things, not the file), 7 (a place is generated once and left alone; the + engine may only *add* a person or enemy), 8 (hand-made worlds meet the same + standard as generated ones), and the non-goals. +- [AGENTS.md](../../../AGENTS.md): "A world supplies parameters, never + behaviour"; a new per-row parameter ships inert; "Adding a parameter to a + checked-in world changes every sweep script that walks it"; "An engine change + earns a sweep script, not only a unit test". +- The world file's own format and its rules: `db/seeds/worlds/README.md`. + +## The lenses + +Each lens is a question, where to look for the answer, and what counts as +evidence. Not every lens applies to every change; say which were skipped and +why. + +### Goal and legibility — does the player always know what the story asks of them? + +- **Look at:** the arc (`quests:` and their steps), and the doctor's playability + properties P1–P4 in the header above `Story::Doctor#unreachable_quest_targets` + (`app/models/story/doctor.rb`). +- **Ask:** does the goal exist as a row before the frontier runs out (P1)? Does + the frontier keep pointing at it (P2)? Is there an ending to reach (P4)? Is + there more than one way to learn where the next beat is — the glance's next + beat, a person who knows (`app/models/character/desires.rb`), the direction + the exits point? +- **Evidence:** `rake game:doctor` on the loaded world, with no finding from + `#unbound_quest_steps`, `#stories_that_cannot_progress`, + `#frontier_turned_away_from_the_goal` or `#quests_without_an_outcome`. + +### Fairness — Tough, never Nasty + +On Plotkin's cruelty scale (see `references/principles.md`) a game with +permadeath is at best *Tough*: you can get stuck, but it is obvious beforehand. +*Nasty* — the cause is only obvious afterwards — is a defect. + +- **Look at:** every way this world can end a game: zero hit points, a floor + falling, a toll on a doorway (`app/models/playthrough/hazards.rb`, + `app/models/playthrough/toll.rb`), a deadline (`app/models/quest/deadline.rb`). +- **Ask:** for each one, where does the player see it coming *in the engine's + own words*? The narrator is never told dice or checks, so the warning cannot + be left to prose: it has to be a glance line, a refusal + (`app/models/playthrough/refusal.rb`) or the end notice + (`app/models/playthrough/end_notice.rb`). After this death, could the player + say what they would do differently? Is every fight escapable by leaving? +- **Evidence:** a sweep script that walks to the danger and asserts the warning + appears before it lands (`lib/engine_sweep/scripts/`; see + `a-floor-falls-behind-you.yml` and `death-ends-a-playthrough.yml` for the + shape). + +### Layout — can it be finished, and is it worth walking? + +- **Look at:** `locations:` and `connections:` (their `barrier` and + `key_template`), a + `floor:` block (`rooms`, `down`, `guards`), and how the engine lays a floor + out — the header of the pinned engine's `src/floor.rs` and `src/interior.rs` + (the pin is in `ext/renderedstep/Cargo.toml`). +- **Ask:** + - **Is every key reachable without first passing the lock it opens?** This + is the softlock a dependency chart exists to catch. The doctor's + lock-aware reachability finding answers it; run `rake game:doctor`. Where a + question it does not cover remains, trace it by hand and label the trace. + - **What is the critical path** from arrival to the goal or the way down, + and is anything on it a guess? + - **Is there more than one way?** Loops spare backtracking. A floor gets + loops by construction (extra doors in `src/interior.rs`); a hand-written + world gets them only if its `connections:` draw them. A deliberately + linear chain of locks — one per floor, key beside its lock — is a valid + crawler shape; say so rather than "fixing" it. + - **Does a dead end pay?** A long branch that ends in nothing is a cost. + - **Is any of it a maze** — rooms that differ in fact but not in what the + player can tell apart? Placeholder room names are where that creeps in. +- **Evidence:** the doctor; a sweep script that walks the critical path to + its end (see `two-floors-and-a-key.yml`, `a-guarded-stair.yml` and + `a-key-for-the-other-door.yml` under `lib/engine_sweep/worlds/` for keyed + layouts, and `a-floor-laid-out-to-its-count.yml` under + `lib/engine_sweep/scripts/`). + +### Pacing — where are the valleys? + +The engine may add a threat but never remove one (VISION principle 7), so the +"relax" half of a tension cycle cannot come from the engine taking enemies +away. It has to be built into the place. + +- **Look at:** safe rooms (`safe_rooms` in a `floor:` block; nothing hostile is + born in one), rest (`resting-in-a-safe-room.yml`), a floor's countdown + (`waiting-out-a-floor.yml`), scheduled events (`app/models/world_event.rb`). +- **Ask:** after each peak, is there somewhere to recover, and can the player + reach it? Is the countdown-versus-rest trade visible, so resting is a choice + rather than a trap? If a threat is injected into a room already generated, + is it foreshadowed — through a doorway the player can see, announced in the + engine's words — rather than appearing whatever route was taken? +- **Evidence:** a sweep script that walks the trade (rest, then see the clock); + for anything the engine does not yet do, an owner's-call finding, not an + assertion. + +### Variety — does each place feel like a different place? + +- **Look at:** what the file fixes and what it leaves to the engine's dice + (VISION principle 6). On a floor, every room shares the floor's `danger` and + `hazard`; kinds are dealt per room and the room writer names and describes + each. +- **Ask:** is sameness a risk here? Is anything preset in the file that the + engine should roll? +- **Evidence:** do not judge generated prose yourself. Ask the owner for a lab + sample (`app/models/lab/realization.rb`, `app/models/lab/exits.rb`; + `rake eval:realization`), which the owner scores. Prompt wording that a + sample points at is EVALUATION.md's, not this skill's. + +### Difficulty — is every number checked? + +- **Look at:** guard and boss stats, a floor's level, healing and safe-room + counts, minutes on a clock, rest. +- **Ask:** was this number chosen by running the engine's fight simulator, with + the target stated before the run? +- **Evidence:** a simulator run attached to the change. Every difficulty number + goes to the engine repository's `fight-numbers` skill; never estimate one + here, and never ask a model for one (VISION principle 1). + +### Every lens — what is the player deciding? + +A fight leaves few choices inside it by design; the interesting ones are +outside it: whether to enter, to run, to drink now or later, to rest while the +clock runs, which way to go. For each feature, name the decision it creates and +whether the player can see what they need to make it. A feature that serves no +decision and none of the aims in VISION's purpose is a candidate to cut. + +## Output + +Sort every finding into one of three groups, each with its evidence or its +labelled hand trace: + +1. **The engine already enforces this** — name the check (a doctor method, a + loader validation, an engine invariant) so nobody re-litigates it. +2. **A doctor finding or a sweep should enforce this** — a candidate backlog + item: the property, the world that would trip it, and where the check + belongs (`app/models/story/doctor.rb` or a script under + `lib/engine_sweep/scripts/`). +3. **The owner's call** — a decision with its options, the ruling it touches, + and what each option costs. Do not decide these. + +Lead with anything that makes the world unfinishable or unfair; style comes +last. + +## References + +- `references/principles.md` — the design research behind each lens, every + entry with its source. +- `references/borrowed.md` — checklist items adapted from MIT and Apache-2.0 + licensed skills, with their licence notices. diff --git a/.agents/skills/world-design-review/references/borrowed.md b/.agents/skills/world-design-review/references/borrowed.md new file mode 100644 index 00000000..819a8fa8 --- /dev/null +++ b/.agents/skills/world-design-review/references/borrowed.md @@ -0,0 +1,96 @@ +# Borrowed checklist items, with their licences + +Some review questions in `SKILL.md` are adapted from two openly licensed agent +skills. Nothing here is installed or vendored: the items below are rewritten +for this game's records and commands, and each says where it came from and +what changed. Only MIT and Apache-2.0 sources are adapted. + +## From Scouten2/LevelDesignSkill (MIT) + +Source: https://github.com/Scouten2/LevelDesignSkill, `skills/level-design/SKILL.md` +and `skills/level-design/scripts/graph_check.py`. + +- **"Count, don't eyeball; verify, don't assert."** The original's core rule: + never claim a level is solvable, reachable or of a given difficulty without a + script result or an explicitly labelled hand trace. *Adapted as* the rule + that evidence is a doctor finding, a sweep assertion, a fight-simulator + result or a lab score, and anything else is a labelled hand trace. +- **Lock-and-key graph checks** — reachability, key before its door, dead ends, + loops. *Adapted as* the layout lens's questions, answered by this repo's own + doctor and sweeps over records rather than by the original's script. +- **"A dead end must pay"** and **"prefer circuits and shortcuts back to + safety"** (the original's rhythm-and-loops rule). *Adapted as* the layout + lens's dead-end and more-than-one-way questions. +- **"Alternate tension and release."** *Adapted as* the pacing lens, with the + release built into the layout because the engine may only add a threat. + +Licence notice, as the source carries it: + +```text +MIT License + +Copyright (c) 2026 Scouten2 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + +## From Youtouch/Game-Design-Skills (Apache-2.0) + +Source: https://github.com/Youtouch/Game-Design-Skills, +`skills/puzzle-design/SKILL.md` and `skills/quest-design/SKILL.md`. + +- **Check soft-locks** (puzzle-design): can the player consume, move or + trigger something that makes the goal unreachable? *Adapted as* the layout + lens's key-before-its-lock question and the fairness lens's "obvious + beforehand". +- **Map dependencies, working backwards from the goal**, and look for + bottlenecks and dead ends (puzzle-design, after Gilbert). *Adapted as* the + critical-path question. +- **Locate the key inference; check its evidence is perceivable and available + before it is needed** (puzzle-design). *Adapted as* the goal-and-legibility + lens's "more than one way to learn where the next beat is". +- **Check objective clarity: at each step the player can find what to do next, + why and where** (quest-design). *Adapted as* the goal-and-legibility lens, + answered by the doctor's P1 and P2. +- **A consequence the player never perceives does not make the choice + meaningful** (quest-design). *Adapted as* "what is the player deciding, and + can they see what they need to decide it?" +- **List failure states: is failure signalled, and does it lead somewhere?** + (quest-design). *Adapted as* the fairness lens's "where does the player see + it coming, in the engine's own words?" + +Changes: the items are paraphrased and re-pointed at this repository's +records, doctor and sweep scripts; the original procedures and output formats +are not reproduced. Licence notice: + +```text +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` + +The full licence text is in the source repository's `LICENSE` file. diff --git a/.agents/skills/world-design-review/references/principles.md b/.agents/skills/world-design-review/references/principles.md new file mode 100644 index 00000000..3d7279e1 --- /dev/null +++ b/.agents/skills/world-design-review/references/principles.md @@ -0,0 +1,189 @@ +# Design principles behind the lenses + +Outside game-design and level-design writing that the lenses in `SKILL.md` +draw on, each with its source and where it bears on this game. These are +review questions, never rules: where one disagrees with a ruling in +`VISION.md` or `AGENTS.md`, the ruling stands, and the entry says so. + +## Text adventure and interactive-fiction craft + +**The Bill of Player's Rights.** Graham Nelson, *The Craft of Adventure* +(1995), https://www.ifarchive.org/if-archive/info/Craft.Of.Adventure.txt. +Among them: "Not to be killed without warning", "Not to have the game closed +off without warning", "To have a good reason why something is impossible", +"To know how the game is getting on", "Not to depend much on luck", "To be able +to win without experience of past lives". +*Here:* warnings and reasons come from the engine's own words — refusals +(`app/models/playthrough/refusal.rb`), the glance, the end notice +(`app/models/playthrough/end_notice.rb`) — because the narrator is never told +the dice (VISION principle 2). "Not to depend much on luck" and "win without +past lives" meet "Danger is real" (VISION principle 5) and permadeath: the +rulings stand. The lever is information, not fewer dice; what a past life +teaches should be knowledge of the place, never a requirement. + +**The cruelty scale.** Andrew Plotkin, https://www.ifwiki.org/Cruelty_scale. +Merciful ("Can never die or get stuck"), Polite ("Can die, but cannot get +stuck"), Tough ("Can get stuck, but this is obvious beforehand"), Nasty +("…obvious afterward"), Cruel ("…not obvious afterward"). +*Here:* with permadeath, a death is being stuck, so the target is Tough: +every ending obvious beforehand. The fairness lens. + +**Rules of thumb.** Ron Gilbert (1989), +https://grumpygamer.com/why_adventure_games_suck. "End objective needs to be +clear", "Sub-goals need to be obvious", "Real time is bad drama", "Reward +intent", "Give the player options", "Live and learn". +*Here:* a clear goal is the doctor's P1 and P2 (`app/models/story/doctor.rb`, +the playability header). A floor's countdown runs on story time, which moves +only when the player acts, so it is a resource rather than a real-time clock. +"Live and learn" (no death needed to learn) meets VISION principle 5; the +ruling stands, and "obvious beforehand" is the bridge. + +**Puzzle dependency charts.** Ron Gilbert (2014), +https://grumpygamer.com/puzzle_dependency_charts. "Flowcharts are great if +you're trying to solve a game, dependency charts are great if you're trying to +design a game." The chart shows what must happen before what; its warning +signs are a chart too linear, and dead ends. +*Here:* an arc's steps and a world's keyed doorways together are such a chart. +The layout lens's key-before-its-lock question comes from here. + +**Mazes.** Nelson, same source: "Difficulty and tedium shouldn't be the goal"; +offer a shortcut, or omit the maze. +*Here:* a large floor whose rooms the player cannot tell apart is a maze in +effect, whatever the layout code guarantees. + +**A model as the parser.** intfiction.org, "Why can't the parser just be an +LLM?" (2023), https://intfiction.org/t/why-cant-the-parser-just-be-an-llm/64001. +Replies point to the "lack of world state" and favour a model layer that maps +commands onto the game's own events. +*Here:* that is this project's standing constraint (`AGENTS.md`): the model +picks from a closed set and the engine acts. + +## Dungeon and level layout + +**Xandering (formerly "Jaquaying") the dungeon.** Justin Alexander (2010), +https://thealexandrian.net/wordpress/13085/roleplaying-games/jaquaying-the-dungeon. +Multiple entrances, multiple paths between levels, loops, so that "the +environment isn't forcing them along a pre-designed path". +*Here:* the "more than one way" question. A floor gets loops from the extra +doors in the engine's `src/interior.rs`; a way between floors is whatever the +world file draws. + +**Missions and spaces.** Joris Dormans, "Adventures in level design: +generating missions and spaces for action adventure games" (PCG workshop +2010), https://doi.org/10.1145/1814256.1814257; the cyclic generator of +*Unexplored*, explained by Boris the Brave, +https://www.boristhebrave.com/2021/04/10/dungeon-generation-in-unexplored/. +Generate what must be done (locks and keys) apart from the space, then fit one +to the other; Unexplored keeps an edge from each key to its lock so a blocked +path can be detected. +*Here:* the world file and arc are the mission and the engine's floor layout is +the space. The doctor reads a key and its lock as a check, never as a +mechanism that changes a world. + +**Lock-and-key graphs.** Mark Brown's "Boss Keys" notation, summarised in Boris +the Brave, "Lock and Key Dungeons" (2021), +https://www.boristhebrave.com/2021/02/27/lock-and-key-dungeons/. A tall, thin +graph is a linear dungeon, and many that feel complex are fixed-order beneath. +*Here:* a chain of floors, each key beside its lock, is linear by design; a +review names that rather than "fixing" it. + +**A guaranteed solution path first.** Darius Kazemi on Spelunky's generator, +http://tinysubversions.com/spelunkyGen/. Trace the solution path, then fill the +rest with rooms that cannot block it. +*Here:* the engine guarantees a floor's rooms are connected (the header of its +`src/floor.rs`); the critical path's *length* is not controlled, and is a +pacing fact to measure, not a defect. + +**Generate, test, discard.** Josh Ge (Cogmind), +https://www.gridsagegames.com/blog/2014/06/procedural-map-generation/: "A map +with few or no loops in its layout will require lots of backtracking, and +backtracking is not fun!" and "Long paths that lead to dead ends had better at +least contain treasure or access to a new area." +https://www.gridsagegames.com/blog/2019/03/roguelike-level-design-addendum-procedural-layouts/: +reachability and shape are tested on completion and the map thrown out if out +of range. +*Here:* the doctor and the sweeps are the test half. Discarding a layout would +change every floor's dice; that is the owner's call, not a review fix. + +**The five-room dungeon.** Johnn Four, Roleplaying Tips (2006), +https://www.roleplayingtips.com/rptn/5-room-dungeons-contest/. Entrance and +guardian; puzzle; setback; climax; reward or twist. +*Here:* a vocabulary for what the people on a small floor are for. The engine +still lays the rooms out. + +**Ten principles of good level design.** Dan Taylor (GDC 2013), +https://www.gamedeveloper.com/design/ten-principles-of-good-level-design-part-1- +and https://www.gamedeveloper.com/design/ten-principles-of-good-level-design-part-2-. +Among them: "tells the player what to do, but not how to do it", "is +surprising", "lets the player control the difficulty". +*Here:* surprise is VISION principle 7; controlling the difficulty is the +countdown-versus-rest trade. + +## Pacing, difficulty and fairness + +**Adaptive dramatic pacing.** Michael Booth, "The AI Systems of Left 4 Dead" +(AIIDE 2009), +https://steamcdn-a.akamaihd.net/apps/valve/2009/ai_systems_of_l4d_mike_booth.pdf. +A director cycles Build Up, Sustain Peak, Peak Fade and Relax; Relax holds a +minimal threat "until Survivors have traveled far enough toward the next safe +room". +*Here:* the relax phase *removes* threats, and VISION principle 7 lets the +engine only add one. The ruling stands, so the valleys come from layout: safe +rooms and escapable fights. + +**Interesting decisions.** Sid Meier (GDC 2012), +https://gdcvault.com/play/1015756/Interesting. "Good decisions are +situational." +*Here:* the "what is the player deciding?" question asked of every lens. + +**Failure that feels like your own.** Jesper Juul, *The Art of Failure* (MIT +Press, 2013), +https://www.jesperjuul.net/ludologist/2013/02/25/the-art-of-failure/. +*Here:* permadeath motivates only if the player can see why they died — the +end notice and the engine's own act lines. + +**The Three Clue Rule and the quantum ogre.** Justin Alexander, "Three Clue +Rule" (2008), +https://thealexandrian.net/wordpress/1118/roleplaying-games/three-clue-rule; +"Smart Prep", +https://thealexandrian.net/wordpress/39893/roleplaying-games/smart-prep-part-2-the-principles-of-smart-prep; +Hack & Slash, "On Slaying the Quantum Ogre" (2011), +http://hackslashmaster.blogspot.com/2011/09/on-slaying-quantum-ogre.html: +"Without information, they cannot make a choice with intent." +*Here:* more than one route to knowing where a goal is; an added enemy +foreshadowed rather than placed whatever the player chose. + +## Generation that stays playable + +**The 10,000 bowls of oatmeal.** Kate Compton, "So you want to build a +generator…" (2016), +https://galaxykate0.tumblr.com/post/139774965871/so-you-want-to-build-a-generator: +"Perceptual uniqueness is the real metric, and it's darn tough." +*Here:* the variety lens. Perceived sameness is measured by a lab sample the +owner scores, not by a reviewer's reading. + +**Expressive range.** Gillian Smith and Jim Whitehead, "Analyzing the +expressive range of a level generator" (PCG workshop 2010), +https://doi.org/10.1145/1814256.1814260. Plot many generated artifacts on two +metrics to expose a generator's biases. +*Here:* the method for measuring what a layout does across seeds, offline. + +**The PCG textbook.** Shaker, Togelius and Nelson, *Procedural Content +Generation in Games* (2016), https://www.pcgbook.com/. Constructive, +search-based and constraint-based generation, and evaluating generators. +*Here:* the engine's floor layout is constructive with guarantees; the doctor +and sweeps are the test of generate-and-test. + +**LLM-built worlds.** Word2World (Nasir, James and Togelius, 2024), +https://arxiv.org/abs/2405.06686, checks playability with an agent that plays +the world — what `lib/engine_sweep/` does. Story2Game (Zhou et al., 2025), +https://arxiv.org/abs/2505.03547, has a model write the game's action code; +that breaks "A world supplies parameters, never behaviour" (`AGENTS.md`) and is +the road not taken. + +**MDA.** Hunicke, LeBlanc and Zubek (2004), +https://users.cs.northwestern.edu/~hunicke/MDA.pdf. Designers reason from +mechanics to dynamics to aesthetics; players meet them the other way round. +*Here:* VISION's "fun, exciting and heartbreaking", with companions not all of +whom make it, is Challenge, Narrative, Discovery and Fellowship; a feature that +serves none of them is a candidate to cut. diff --git a/.claude/skills/world-design-review b/.claude/skills/world-design-review new file mode 120000 index 00000000..31b8afdd --- /dev/null +++ b/.claude/skills/world-design-review @@ -0,0 +1 @@ +../../.agents/skills/world-design-review \ No newline at end of file