Release 1.1.0 — one config file, and a process weight you choose

`project.yaml` at the repo root is now the single source of truth for a
project's configuration, replacing `production/stage.txt`,
`production/review-mode.txt` and `.claude/docs/technical-preferences.md` (all
three still read as a fallback; nothing is force-deleted).

**`modes.rigor` — one question instead of six.** `minimal`, `standard` or
`full` fronts six knobs: `modes.workflow`, `docs.density`, `qa.level`,
`modes.story_granularity`, `modes.review_mode` and `team.size`. It defaults to
`minimal`, which is a change from 1.0's behaviour: the heavier tier was
measured costing several times more to reach working code without producing a
better result, and returning nothing when a fresh developer inherited the
project. Pin `modes.rigor: standard` to keep 1.0's process level.

Also in this release:

- `/settings` to view or change any setting, and `project.local.yaml` for
  per-developer preferences that should not be committed.
- `system_overrides` to hold one system to a higher standard than the rest of
  the project, and `testing.strict` to set per test type whether missing
  evidence blocks a story or warns.
- A story that changes anything the player sees is not closed until the game
  has been launched, observed, and a screenshot retained in
  `production/qa/evidence/`. A parse check is not a run. This holds at every
  rigor level, including `minimal`, where automated tests are waived but the
  look is not.
- The code root is engine-specific and enforced as such: Godot `src/`, Unity
  `Assets/`, Unreal `Source/<Module>/`. Two of the three will not build a
  project laid out any other way.
- Migration tooling for existing projects: `.claude/scripts/migrate-v1-config.sh`
  converts a 1.0 layout, non-destructively by default, with a report to review
  before `--finalize` deletes anything.
- Ask-before-write holds regardless of personal automation settings.

Upgrading from 1.0 or earlier: see UPGRADING.md. Full list of changes:
CHANGELOG.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xvzG3i7pWQg4LjyDwWMXd
This commit is contained in:
Donchitos
2026-09-23 12:25:11 +10:00
co-authored by Claude Opus 5
parent 984023ddac
commit d05699707f
291 changed files with 24374 additions and 7740 deletions
-281
View File
@@ -1,281 +0,0 @@
# Agent Coordination and Delegation Map
## Organizational Hierarchy
```
[Human Developer]
|
+---------------+---------------+
| | |
creative-director technical-director producer
| | |
+--------+--------+ | (coordinates all)
| | | |
game-designer art-dir narr-dir lead-programmer qa-lead audio-dir
| | | | | |
+--+--+ | +--+--+ +--+--+--+--+--+ | |
| | | | | | | | | | | | | |
sys lvl eco ta wrt wrld gp ep ai net tl ui qa-t snd
|
+---+---+
| |
perf-a devops analytics
Additional Leads (report to producer/directors):
release-manager -- Release pipeline, versioning, deployment
localization-lead -- i18n, string tables, translation pipeline
prototyper -- Rapid throwaway prototypes, concept validation
security-engineer -- Anti-cheat, exploits, data privacy, network security
accessibility-specialist -- WCAG, colorblind, remapping, text scaling
live-ops-designer -- Seasons, events, battle passes, retention, live economy
community-manager -- Patch notes, player feedback, crisis comms
Engine Specialists (use the SET matching your engine):
unreal-specialist -- UE5 lead: Blueprint/C++, GAS overview, UE subsystems
ue-gas-specialist -- GAS: abilities, effects, attributes, tags, prediction
ue-blueprint-specialist -- Blueprint: BP/C++ boundary, graph standards, optimization
ue-replication-specialist -- Networking: replication, RPCs, prediction, bandwidth
ue-umg-specialist -- UI: UMG, CommonUI, widget hierarchy, data binding
unity-specialist -- Unity lead: MonoBehaviour/DOTS, Addressables, URP/HDRP
unity-dots-specialist -- DOTS/ECS: Jobs, Burst, hybrid renderer
unity-shader-specialist -- Shaders: Shader Graph, VFX Graph, SRP customization
unity-addressables-specialist -- Assets: async loading, bundles, memory, CDN
unity-ui-specialist -- UI: UI Toolkit, UGUI, UXML/USS, data binding
godot-specialist -- Godot 4 lead: GDScript, node/scene, signals, resources
godot-gdscript-specialist -- GDScript: static typing, patterns, signals, performance
godot-csharp-specialist -- C#: .NET patterns, [Signal] delegates, async, type-safe node access
godot-shader-specialist -- Shaders: Godot shading language, visual shaders, VFX
godot-gdextension-specialist -- Native: C++/Rust bindings, GDExtension, build systems
```
### Legend
```
sys = systems-designer gp = gameplay-programmer
lvl = level-designer ep = engine-programmer
eco = economy-designer ai = ai-programmer
ta = technical-artist net = network-programmer
wrt = writer tl = tools-programmer
wrld = world-builder ui = ui-programmer
snd = sound-designer qa-t = qa-tester
narr-dir = narrative-director perf-a = performance-analyst
art-dir = art-director
```
## Delegation Rules
### Who Can Delegate to Whom
| From | Can Delegate To |
|------|----------------|
| creative-director | game-designer, art-director, audio-director, narrative-director |
| technical-director | lead-programmer, devops-engineer, performance-analyst, technical-artist (technical decisions) |
| producer | Any agent (task assignment within their domain only) |
| game-designer | systems-designer, level-designer, economy-designer |
| lead-programmer | gameplay-programmer, engine-programmer, ai-programmer, network-programmer, tools-programmer, ui-programmer |
| art-director | technical-artist, ux-designer |
| audio-director | sound-designer |
| narrative-director | writer, world-builder |
| qa-lead | qa-tester |
| release-manager | devops-engineer (release builds), qa-lead (release testing) |
| localization-lead | writer (string review), ui-programmer (text fitting) |
| prototyper | (works independently, reports findings to producer and relevant leads) |
| security-engineer | network-programmer (security review), lead-programmer (secure patterns) |
| accessibility-specialist | ux-designer (accessible patterns), ui-programmer (implementation), qa-tester (a11y testing) |
| [engine]-specialist | engine sub-specialists (delegates subsystem-specific work) |
| [engine] sub-specialists | (advises all programmers on engine subsystem patterns and optimization) |
| live-ops-designer | economy-designer (live economy), community-manager (event comms), analytics-engineer (engagement metrics) |
| community-manager | (works with producer for approval, release-manager for patch note timing) |
### Escalation Paths
| Situation | Escalate To |
|-----------|------------|
| Two designers disagree on a mechanic | game-designer |
| Game design vs narrative conflict | creative-director |
| Game design vs technical feasibility | producer (facilitates), then creative-director + technical-director |
| Art vs audio tonal conflict | creative-director |
| Code architecture disagreement | technical-director |
| Cross-system code conflict | lead-programmer, then technical-director |
| Schedule conflict between departments | producer |
| Scope exceeds capacity | producer, then creative-director for cuts |
| Quality gate disagreement | qa-lead, then technical-director |
| Performance budget violation | performance-analyst flags, technical-director decides |
## Common Workflow Patterns
### Pattern 1: New Feature (Full Pipeline)
```
1. creative-director -- Approves feature concept aligns with vision
2. game-designer -- Creates design document with full spec
3. producer -- Schedules work, identifies dependencies
4. lead-programmer -- Designs code architecture, creates interface sketch
5. [specialist-programmer] -- Implements the feature
6. technical-artist -- Implements visual effects (if needed)
7. writer -- Creates text content (if needed)
8. sound-designer -- Creates audio event list (if needed)
9. qa-tester -- Writes test cases
10. qa-lead -- Reviews and approves test coverage
11. lead-programmer -- Code review
12. qa-tester -- Executes tests
13. producer -- Marks task complete
```
### Pattern 2: Bug Fix
```
1. qa-tester -- Files bug report with /bug-report
2. qa-lead -- Triages severity and priority
3. producer -- Assigns to sprint (if not S1)
4. lead-programmer -- Identifies root cause, assigns to programmer
5. [specialist-programmer] -- Fixes the bug
6. lead-programmer -- Code review
7. qa-tester -- Verifies fix and runs regression
8. qa-lead -- Closes bug
```
### Pattern 3: Balance Adjustment
```
1. analytics-engineer -- Identifies imbalance from data (or player reports)
2. game-designer -- Evaluates the issue against design intent
3. economy-designer -- Models the adjustment
4. game-designer -- Approves the new values
5. [data file update] -- Change configuration values
6. qa-tester -- Regression test affected systems
7. analytics-engineer -- Monitor post-change metrics
```
### Pattern 4: New Area/Level
```
1. narrative-director -- Defines narrative purpose and beats for the area
2. world-builder -- Creates lore and environmental context
3. level-designer -- Designs layout, encounters, pacing
4. game-designer -- Reviews mechanical design of encounters
5. art-director -- Defines visual direction for the area
6. audio-director -- Defines audio direction for the area
7. [implementation by relevant programmers and artists]
8. writer -- Creates area-specific text content
9. qa-tester -- Tests the complete area
```
### Pattern 5: Sprint Cycle
```
1. producer -- Plans sprint with /sprint-plan new
2. [All agents] -- Execute assigned tasks
3. producer -- Daily status with /sprint-plan status
4. qa-lead -- Continuous testing during sprint
5. lead-programmer -- Continuous code review during sprint
6. producer -- Sprint retrospective with post-sprint hook
7. producer -- Plans next sprint incorporating learnings
```
### Pattern 6: Milestone Checkpoint
```
1. producer -- Runs /milestone-review
2. creative-director -- Reviews creative progress
3. technical-director -- Reviews technical health
4. qa-lead -- Reviews quality metrics
5. producer -- Facilitates go/no-go discussion
6. [All directors] -- Agree on scope adjustments if needed
7. producer -- Documents decisions and updates plans
```
### Pattern 7: Release Pipeline
```text
1. producer -- Declares release candidate, confirms milestone criteria met
2. release-manager -- Cuts release branch, generates /release-checklist
3. qa-lead -- Runs full regression, signs off on quality
4. localization-lead -- Verifies all strings translated, text fitting passes
5. performance-analyst -- Confirms performance benchmarks within targets
6. devops-engineer -- Builds release artifacts, runs deployment pipeline
7. release-manager -- Generates /changelog, tags release, creates release notes
8. technical-director -- Final sign-off on major releases
9. release-manager -- Deploys and monitors for 48 hours
10. producer -- Marks release complete
```
### Pattern 8: Concept Prototype (early — before GDDs)
```text
1. game-designer -- Defines the hypothesis and success criteria
2. prototyper -- Scaffolds concept prototype with /prototype
3. prototyper -- Builds minimal implementation (1-3 days)
4. game-designer -- Evaluates prototype against criteria
5. prototyper -- Documents findings in REPORT.md
6. creative-director -- PROCEED / PIVOT / KILL decision (full mode only)
7. game-designer -- Informs GDD writing with prototype learnings if PROCEED
```
### Pattern 8b: Vertical Slice (pre-production — after GDDs and architecture)
```text
1. game-designer -- Confirms slice scope against GDDs
2. prototyper -- Builds production-quality end-to-end build with /vertical-slice
3. prototyper -- Conducts internal playtest sessions (minimum 1)
4. prototyper -- Documents findings in REPORT.md
5. creative-director -- Go/no-go decision on proceeding to Production (full mode)
6. producer -- Schedules Production epics/sprints if PROCEED
```
### Pattern 9: Live Event / Season Launch
```text
1. live-ops-designer -- Designs event/season content, rewards, schedule
2. game-designer -- Validates gameplay mechanics for event
3. economy-designer -- Balances event economy and reward values
4. narrative-director -- Provides seasonal narrative theme
5. writer -- Creates event descriptions and lore
6. producer -- Schedules implementation work
7. [implementation by relevant programmers]
8. qa-lead -- Test event flow end-to-end
9. community-manager -- Drafts event announcement and patch notes
10. release-manager -- Deploys event content
11. analytics-engineer -- Monitors event participation and metrics
12. live-ops-designer -- Post-event analysis and learnings
```
## Cross-Domain Communication Protocols
### Design Change Notification
When a design document changes, the game-designer must notify:
- lead-programmer (implementation impact)
- qa-lead (test plan update needed)
- producer (schedule impact assessment)
- Relevant specialist agents depending on the change
### Architecture Change Notification
When an ADR is created or modified, the technical-director must notify:
- lead-programmer (code changes needed)
- All affected specialist programmers
- qa-lead (testing strategy may change)
- producer (schedule impact)
### Asset Standard Change Notification
When the art bible or asset standards change, the art-director must notify:
- technical-artist (pipeline changes)
- All content creators working with affected assets
- devops-engineer (if build pipeline is affected)
## Anti-Patterns to Avoid
1. **Bypassing the hierarchy**: A specialist agent should never make decisions
that belong to their lead without consultation.
2. **Cross-domain implementation**: An agent should never modify files outside
their designated area without explicit delegation from the relevant owner.
3. **Shadow decisions**: All decisions must be documented. Verbal agreements
without written records lead to contradictions.
4. **Monolithic tasks**: Every task assigned to an agent should be completable
in 1-3 days. If it is larger, it must be broken down first.
5. **Assumption-based implementation**: If a spec is ambiguous, the implementer
must ask the specifier rather than guessing. Wrong guesses are more expensive
than a question.
+27
View File
@@ -0,0 +1,27 @@
# Agent Teams (experimental — opt-in)
> On-demand reference. Demoted out of `coordination-rules.md` (an always-loaded
> CLAUDE.md import) in v1.1 — read this when actually considering a team, not
> on every turn.
Multiple independent Claude Code *sessions* running simultaneously, coordinated
via a shared task list. Each session has its own context window and token budget.
Requires the `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` environment variable.
## Use agent teams when
- Work spans multiple subsystems that will not touch the same files
- Each workstream would take >30 minutes and benefits from true parallelism
- A senior agent (technical-director, producer) needs to coordinate 3+ specialist
sessions working on different epics simultaneously
## Do not use agent teams when
- One session's output is required as input for another (use sequential subagents)
- The task fits in a single session's context (use subagents instead)
- Cost is a concern — each team member burns tokens independently
## Current status
Opt-in via `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. Document first usage here
when adopted.
+261
View File
@@ -0,0 +1,261 @@
# Automation Modes — Shared Skill Pattern
This document defines the standard `modes.automation` pattern for every skill
that uses `AskUserQuestion` or writes files. Skills reference this document
instead of embedding the full mode-handling rules inline — eliminating drift
when the pattern needs updating.
**Scope**: ~44 skills across authoring, review, team orchestration,
implementation, and utility categories. Any skill that gates a decision
through `AskUserQuestion` or writes files should follow this pattern.
**Companion spec**: `.claude/docs/effects-map.md`
section `modes.automation` is the source of truth for behavior. This document
is the implementation pattern.
> **Do not read `effects-map.md` during a skill run** — it is ~110 KB, a
> reference for authoring the spec rather than a runtime input, and **this
> document is self-sufficient** for deciding what to ask and what to proceed on.
> If a case genuinely is not covered here, read only its `modes.automation`
> section, never the file.
---
## How to Use This Document
In any skill, add a single resolution step at startup and reference the
mode-aware AskUserQuestion pattern below at each gated site.
**Startup prelude** (add near Phase 0 / Phase 1):
```
Resolve automation mode (once, store for the run):
1. Read `modes.automation` from `project.local.yaml` (if present) → use that
2. Else read `modes.automation` from `project.yaml` → use that value
3. Else → default to `collaborative`
Pattern reference: `.claude/docs/automation-modes.md`.
```
This resolution is automatic via `get_effective_yaml_key modes.automation` —
the helper deep-merges project.local.yaml on top of project.yaml.
**At each AskUserQuestion site**, follow the pattern table in §Universal
Rules below. The skill author labels each decision as **major** or **minor**
(per the classification matrix in §Major vs Minor) so the pattern can apply
the right rule.
---
## The Three Modes
| Mode | Speed | Control | What changes |
|------|-------|---------|--------------|
| `collaborative` | Slowest | Full — every decision is the user's | Default. Q→O→D→Draft→Approval strictly followed. |
| `guided` | Balanced | High — major decisions are the user's, minor ones proceed automatically | AI states recommendation and proceeds for minor decisions. AskUserQuestion reserved for major decisions. |
| `autonomous` | Fastest | Low — AI decides, logs, and proceeds | No AskUserQuestion (except `automation_always_ask` categories). All decisions logged. |
**Default**: `collaborative`. New projects start here.
**Set by**: `/start`, `/settings`.
---
## Universal Rules per Mode
### Collaborative (current v1.0 behavior — no change)
- `AskUserQuestion` called for every multi-option decision
- 2–4 options presented with pros/cons for every design choice
- Full draft shown and approved before every file write
- "May I write this to [filepath]?" asked before every write
- Section-by-section approval in multi-section authoring skills
- Multi-file changes require explicit approval
### Guided
- `AskUserQuestion` called for **major decisions only** (see classification below)
- Minor decisions: AI states recommendation inline and proceeds — e.g.
> *"Going with a static utility pattern here — it fits the existing architecture. Continuing unless you want to change direction."*
- Draft shown briefly before writing — proceeds after a short summary, does not wait for explicit "yes"
- "May I write?" asked for **new files only** — updates to existing files proceed directly
- Still presents options for major decisions but caps at 2 choices with a clear recommendation
- Multi-section authoring: writes each approved section immediately, no per-section confirmation
### Autonomous
- No `AskUserQuestion` calls **except** for categories listed in `modes.automation_always_ask`
- No draft review
- No "May I write?" prompts — writes directly
- Picks the recommended option for every decision without presenting alternatives
- All decisions logged via `log_decision` (helper in yaml-helper.sh) to
`production/session-logs/decision-log.md`
- User reviews decision log post-session to audit choices made
---
## Major vs Minor Decision Classification
Skills label each gated decision as **major** or **minor** before applying
the mode rules.
### Major — always use AskUserQuestion in guided mode
| Decision type | Example |
|---------------|---------|
| Choosing a system name or document path | "What should we call this system?" |
| Mutually exclusive design directions | "Real-time or turn-based?" |
| Any choice that gates downstream work | Engine choice, architecture approach |
| Scope changes | "Cut this feature or slip the deadline?" |
| Any decision that can't be changed without significant rework | Core loop mechanic |
### Minor — AI recommends and proceeds in guided mode
| Decision type | Example |
|---------------|---------|
| Which section to work on next | "Moving to Edge Cases next" |
| Optional section inclusion | "Adding a Visual Notes section — fits the system" |
| Formatting and structure choices | Heading levels, table vs prose |
| Adding detail to an already-decided direction | Sub-options within an approved approach |
| Next-step routing after a phase completes | "Running design-review now" |
---
## `automation_always_ask` Categories
Even in `autonomous` mode, certain decision categories ALWAYS trigger
`AskUserQuestion`. The configured list lives at
`modes.automation_always_ask` in `project.yaml`.
**Default** (when unset): `[scope_changes, file_deletions, schema_changes]`.
### Recognized categories
**This table is the set you may configure, NOT the set that always asks.** Only
the categories actually listed in `modes.automation_always_ask` — the three
defaults above, unless the project overrides them — interrupt an `autonomous`
run. The other rows do nothing until a project opts into them. Read the resolved
list with `resolve_config` rather than assuming a row here is active; a real run
logged two `architecture_decisions` as rule violations on a project where that
category was never configured.
| Category | Examples of decisions in this category |
|----------|----------------------------------------|
| `scope_changes` | Cutting a feature, slipping a deadline, splitting/merging an epic, removing acceptance criteria |
| `file_deletions` | Removing a story, deleting a GDD, removing a system, removing a test file |
| `schema_changes` | Changes to project.yaml, story template, control manifest, ADR template, GDD template |
| `architecture_decisions` | New ADR creation, ADR replacement, system boundary changes |
| `version_bumps` | Engine version change, framework version bump, dependency major version change |
| `external_calls` | Invoking external APIs (asset gen, AI services) when in autonomous mode |
### Helper
```bash
is_always_ask_category <category>
```
Returns 0 if the named category is in `modes.automation_always_ask`,
1 otherwise. Skills use this at decision points that fall into any
of the six categories above.
---
## Exemptions — Skills That Ignore the Automation Setting
These skills always behave as `collaborative` regardless of the setting:
| Skill | Why always collaborative |
|-------|--------------------------|
| `hotfix` | Emergency decisions — user must approve scope and risk before any action |
| `gate-check` | Results must be reviewed — a gate verdict without acknowledgement defeats the purpose |
| `day-one-patch` | Release-critical — every action needs explicit sign-off |
| `setup-engine` | One-time irreversible choice that affects the entire project |
These skills do NOT add the automation prelude described above. They keep
the v1.0 Q→O→D→Draft→Approval protocol exactly.
---
## Decision Log Format (Autonomous Mode)
When `autonomous` mode skips an `AskUserQuestion`, the skill calls
`log_decision` to write a structured entry. Format per entry:
```markdown
## [timestamp] — [skill-name]
**Decision point:** [what was being decided]
**Options considered:** [list of options that would have been presented]
**Chosen:** [what was picked]
**Reason:** [one-line rationale]
**Category:** [scope_changes | file_deletions | schema_changes | … or "minor"]
```
Written to `production/session-logs/decision-log.md` (append-only, never
truncated, created if absent). The user reviews the log post-session to
audit choices made.
### Helper
```bash
log_decision "<skill-name>" "<decision-point>" "<options>" "<chosen>" "<reason>" "<category>"
```
Wraps the format above. Skills call this at every decision point in
autonomous mode, including ones where the chosen value differs from
the recommended default (so the audit trail is complete).
### What to log, and at what granularity
These rules keep autonomous logs consistent across runs:
- **Log every decision that would have shown an `AskUserQuestion` widget** —
including option/framing choices, not only final approvals. The
framing/options decisions (which approach, which formula, which edge
cases) are usually the most informative entries; do not log only the
rote "approve this section" steps.
- **Collapse a single multi-tab widget into ONE entry.** List each tab's
choice under **Chosen** rather than emitting one entry per tab.
- **Do NOT log conversational answers the model synthesizes for itself**
(e.g. internal Q&A while drafting a section) — only log what would have
been an explicit user decision.
- **Do NOT emit a separate entry for routine "may I write?" file gates** —
fold the write into the decision it implements (autonomous mode writes
directly anyway).
### Categorizing data-file writes
The most common categorization mistake is treating a data-file append as a
`schema_changes` decision:
- **Appending facts to a registry or index** — e.g.
`design/registry/entities.yaml`, `design/gdd/systems-index.md` — is
**`minor`**. It adds data without altering a *template*.
- **`schema_changes`** means editing the *structure* of `project.yaml` or a
template (story / ADR / GDD / control-manifest template). These are
always-ask.
- **When genuinely unsure** between `minor` and an always-ask category,
prefer the always-ask category and prompt — failing safe.
---
## The Pattern Skills Apply at Each AskUserQuestion Site
```
At each decision point in this skill:
1. Classify the decision: major or minor (see §Major vs Minor above).
2. Check whether the decision falls into an `automation_always_ask`
category: scope_changes, file_deletions, schema_changes,
architecture_decisions, version_bumps, external_calls.
3. Apply the mode rule:
collaborative: AskUserQuestion always.
guided + major: AskUserQuestion with capped options + recommendation.
guided + minor: State recommendation inline, proceed.
autonomous + always_ask: AskUserQuestion (regardless of mode).
autonomous + other: Pick recommended, log via log_decision, proceed.
```
This is the contract. Skills that follow this pattern produce
consistent behavior across all three automation modes.
+67
View File
@@ -0,0 +1,67 @@
# Code Root Resolution
Shared procedure for any skill that reads, scans, counts or writes game source
files. Referenced from the point of use in each such skill. Those skills keep
the one load-bearing imperative inline — **an unresolved code root means the
check did not run** — and cite this file for the resolution order.
`.claude/docs/directory-structure.md` is the authority for which directory holds
code. This file is the procedure for applying it.
## The roots
| `engine.name` | Code root | Why it cannot be `src/` |
|---|---|---|
| Godot | `src/` | No constraint; Godot loads from `res://` anywhere under the project root |
| Unity | `Assets/` | Unity compiles **only** `Assets/` and `Packages/` |
| Unreal | `Source/<Module>/` | UnrealBuildTool discovers modules under `Source/`; content lives in `Content/` |
`src/` is the **Godot row of that table, not a universal path.**
## Resolution order
1. `engine.name` from `project.local.yaml`, then `project.yaml`.
2. The legacy mirror: an `Engine:` line in
`.claude/docs/technical-preferences.md`. A value of `[TO BE CONFIGURED]`
does not count.
3. Derivation from the tree, but **only when it is unambiguous**. Exactly one of
`src/`, `Assets/` or `Source/` present means that is the root. Two or more
present means the project is genuinely undecidable — do not guess.
4. Otherwise: **unresolved.**
The hooks already implement exactly this as `resolve_code_root()` in
`.claude/hooks/yaml-helper.sh`. Skills must match its semantics so that a hook
and a skill never disagree about where the code lives.
## Unresolved does not default to `src/`
This is the rule the whole file exists for, and it is obligation 2 of
`.claude/rules/skill-authoring.md`: an absent value may not default to the
permissive one.
**For a read or scan:** report `NOT ASSESSED — code root unresolved` and say
which check did not run. Never report zero hits.
A scan anchored to a root the project does not use matches nothing, and
**nothing is indistinguishable from a clean result.** A localization check finds
no hardcoded strings; a security scan finds no secrets; a content audit counts
no implemented content; a stage detector counts no source files and calls a
finished project greenfield. Every one of those reads as a pass. This has been
found repeatedly across skills and hooks, which is why the resolution lives in
one place now.
**For a write:** do not write. Report the unresolved root and stop.
Writing game code to the wrong root is worse than a false pass, because it
produces a project that cannot build: on Unity, source placed outside `Assets/`
is never compiled and never appears in the editor, so the work is silently
inert. Resolving the engine in order to pick a specialist agent is **not** the
same as resolving the code root — a skill can do the first correctly and still
write to the wrong directory.
## Applying it
Where a skill says `src/`, read it as *the code root* and substitute the table
above. Where a skill greps, glob the resolved root. Where a skill writes,
write under the resolved root and use the engine's own conventions beneath it
(`Assets/Scripts/<System>/` on Unity, `Source/<Module>/<System>/` on Unreal).
+38 -5
View File
@@ -1,7 +1,10 @@
# Coding Standards
- All game code must include doc comments on public APIs
- Every system must have a corresponding architecture decision record in `docs/architecture/`
- Architecture decisions are recorded as ADRs in `docs/architecture/`. **How many is
set by `modes.workflow`** — all ADRs at `full`, *critical* ADRs only at `standard`,
and none required at `minimal`, where the decision log and `design/game-brief.md`
carry the rationale instead. See `.claude/docs/workflow-modes.md`.
- Gameplay values must be data-driven (external config), never hardcoded
- All public methods must be unit-testable (dependency injection over singletons)
- Commits must reference the relevant design document or task ID
@@ -9,12 +12,22 @@
- **Verification-driven development**: Write tests first when adding gameplay systems.
For UI changes, verify with screenshots. Compare expected output to actual output
before marking work complete. Every implementation should have a way to prove it works.
- **A parse check is not a run.** Every story that changes something
player-observable is launched and observed before it closes, and the
observation is a retained screenshot in `production/qa/evidence/`. Procedure
per engine: `.claude/docs/run-and-observe.md`. Not waived at
`qa.level: minimal` — tests are, the look is not.
# Design Document Standards
- All design docs use Markdown
- Each mechanic has a dedicated document in `design/gdd/`
- Documents must include these 8 required sections:
- **How many of the 8 sections are required depends on `modes.workflow`** —
all 8 at `full`, 5 (+ Formulas when the system defines numeric rules — rates,
curves, thresholds, costs; the system's `Category` is a hint, not the test) at
`standard`, and no
GDD at all at `minimal`, where `design/game-brief.md` is the design record.
See `.claude/docs/workflow-modes.md`. The 8 sections:
1. **Overview** -- one-paragraph summary
2. **Player Fantasy** -- intended feeling and experience
3. **Detailed Rules** -- unambiguous mechanics
@@ -31,14 +44,34 @@
All stories must have appropriate test evidence before they can be marked Done:
| Story Type | Required Evidence | Location | Gate Level |
| Story Type | Required Evidence | Location | Default Gate Level |
|---|---|---|---|
| **Logic** (formulas, AI, state machines) | Automated unit test — must pass | `tests/unit/[system]/` | BLOCKING |
| **Integration** (multi-system) | Integration test OR documented playtest | `tests/integration/[system]/` | BLOCKING |
| **Visual/Feel** (animation, VFX, feel) | Screenshot + lead sign-off | `production/qa/evidence/` | ADVISORY |
| **UI** (menus, HUD, screens) | Manual walkthrough doc OR interaction test | `production/qa/evidence/` | ADVISORY |
| **Visual/Feel** (animation, VFX, feel) | Retained screenshot + lead sign-off | `production/qa/evidence/` | BLOCKING |
| **UI** (menus, HUD, screens) | Retained screenshot of each screen touched | `production/qa/evidence/` | BLOCKING |
| **Config/Data** (balance tuning) | Smoke check pass | `production/qa/smoke-[date].md` | ADVISORY |
The **Default Gate Level** applies when `testing.strict` is not set in
`project.yaml`. A project may override it per test type: `testing.strict.logic`,
`.integration`, `.visual`, `.ui`, and `.config` each take `true` (BLOCKING) or
`false` (ADVISORY). `/story-done`, `/story-readiness`, `/dev-story`,
`/gate-check`, and `/smoke-check` resolve the effective level from that setting,
falling back to the defaults above when it is absent.
> **Why Visual and UI block.** "Retained" is load-bearing — the screenshot must
> still be on disk in `production/qa/evidence/` when the story is closed. One
> that was captured and discarded is an assertion, not evidence. These two rows
> block because for a game the way it looks *is* the product: an advisory visual
> gate gets deferred in favour of whatever does block, and the result is a
> well-tested game that looks wrong.
> **Exception — `/smoke-check`.** The ADVISORY default for **Config/Data** above
> applies to *per-story evidence* gates. `/smoke-check` is a build-health gate,
> not a per-story evidence gate, so its own unset default for
> `testing.strict.config` is **BLOCKING**. This divergence is intentional and is
> documented at both sites; do not reconcile one to the other.
## Automated Test Rules
- **Naming**: `[system]_[feature]_test.[ext]` for files; `test_[scenario]_[expected]` for functions
+262
View File
@@ -0,0 +1,262 @@
# Config Resolution
How a skill learns its effective settings. **One command, no prose chain.**
## The rule
A skill that needs config puts this near the top of its **body** (not frontmatter):
````markdown
!`source .claude/hooks/yaml-helper.sh 2>/dev/null && resolve_config`
````
The command runs as preprocessing *before the model sees the skill*, and its
output replaces the placeholder inline. The skill then reads the resolved values
and **does not re-derive them**.
Skills that resolve a per-system tier pass the system name: `resolve_config combat`.
## Why the body, not `context:`
`` !`cmd` `` in the skill body is the documented mechanism. Frontmatter
`context:` accepts only `context: fork` — it does **not** run shell. A
`context: |` block containing `!` commands **never executes**; put the command in
the skill body instead.
Two consequences:
- `allowed-tools` does **not** gate this. It governs tools the *model* calls
during the turn; preprocessing happens before that. A skill needs no `Bash`
grant to use `resolve_config`.
- The repo-wide setting `disableSkillShellExecution: true` disables it. If a
skill sees no config block, it falls back to the defaults below.
## The block
```
=== CCGS Resolved Config ===
review_mode: lean (production/review-mode.txt)
automation: guided (project.local.yaml)
workflow: standard (project.yaml)
docs.density: balanced (default)
story_granularity: balanced (default)
qa.level: standard (default)
team.size: individual (rigor:standard)
project.stage: Systems Design (production/stage.txt)
automation_always_ask: scope_changes, file_deletions, schema_changes (default)
engine: Godot 4.6 (project.yaml)
testing.strict: logic=true integration=false visual=unset ui=unset config=unset (unset = each skill applies its own default)
system_overrides: combat=full inventory=minimal
notes: none
Values above are fully resolved (local -> yaml -> legacy -> default). Use as-is.
An inline --review flag, if passed, overrides review_mode.
=== end CCGS config ===
```
Every knob line ends with its **provenance** in parentheses. That is what makes a
wrong value diagnosable — `review_mode: solo (default)` when `project.yaml` says
`full` points straight at the problem.
## Resolution chain
| Step | Source | Applies to |
|---|---|---|
| 1 | `project.local.yaml` | any setting on the `/settings --local` whitelist (12 keys — `modes.review_mode`, `modes.automation`, `modes.automation_always_ask`, `team.size`, all five `testing.strict.*`, `performance.enforce`, `features.*`) |
| 2 | `project.yaml` | all keys |
| 3 | legacy plain-text mirror | `modes.review_mode` → `production/review-mode.txt`; `project.stage` → `production/stage.txt` |
| 4 | **`modes.rigor` expansion** | the six knobs `rigor` fronts — `modes.workflow`, `docs.density`, `qa.level`, `modes.story_granularity`, `modes.review_mode`, `team.size` |
| 5 | documented default | the table below |
An **enum-invalid value does not win** — the chain continues past it and the
rejected value is named on the `notes:` line. A typo degrades to the documented
default rather than propagating a nonsense mode into every skill.
> **Step 4 sits below every explicit source and above the terminal default, and
> that ordering is the whole back-compat guarantee.** A `project.yaml` that
> already sets `docs.density: terse` resolves exactly as it did before `rigor`
> existed, because step 2 answers first. Invert steps 4 and 5 and `rigor` becomes
> a no-op; hoist step 4 above step 2 and it silently overrides settings people
> already have. Tests **X.2** and **X.3** assert both directions.
>
> Derived values report their provenance as **`rigor:<level>`**, so the source
> vocabulary is `{project.local.yaml, project.yaml, <legacy path>, rigor:<level>,
> default, unset}`. `docs.density: balanced (rigor:standard)` says the value was
> never written down anywhere — it follows the project's rigor level and will
> move if that level moves.
> **Read scope == write whitelist.** Anything `/settings --local` may *write*
> is also *read* during resolution. If the read scope were ever narrower,
> `/settings --local modes.review_mode=solo` would write a value
> that `/settings` accepted and displayed and every skill then ignored. The
> test suite asserts the two lists stay in step — adding a setting to one
> without the other reproduces that bug.
>
> This matches the spec: `effects-map.md` § "Local Override Pattern" has always
> stated the chain applies to *every* setting. The narrow read scope was an
> implementation gap, not a design.
> **A key OUTSIDE the whitelist, hand-written into `project.local.yaml`, is
> reported rather than swallowed.** `/settings --local` refuses to
> write one, but the file exists to be edited by hand, so that path needs its own
> guard. `modes.rigor: full` written there is a real key with a legal value, so
> `validate_yaml_enum` passes it — and then resolution never consults the local
> file for that path, so the setting vanishes and the user sees the default they
> were trying to override, with no error anywhere. Every check in the chain
> validated the **value**; nothing validated the **location**.
>
> `validate_local_scope` now names such keys on `notes:`. It **warns and never
> reconciles**, the same shape as the stage-mirror check: it does not edit the
> file, does not begin honouring the key, and does not change resolution. A
> locked setting is locked because it decides which artifacts exist on disk, so
> a helper that quietly applied one would let two developers' checkouts diverge
> — the exact thing the whitelist prevents. The user moves the key to
> `project.yaml` or deletes it.
>
> `schema_version` and `framework.*` are exempt: `effects-map.md` classes them as
> file metadata rather than preferences, and a `project.local.yaml` carrying
> `schema_version: 1` is correct as written.
## Defaults
| Knob | Default |
|---|---|
| `modes.automation` | `collaborative` |
| `modes.rigor` | `minimal` |
| `modes.automation_always_ask` | `scope_changes`, `file_deletions`, `schema_changes` |
**The six knobs `rigor` fronts have no terminal default at all.** `modes.workflow`,
`docs.density`, `qa.level`, `modes.story_granularity`, `modes.review_mode` and `team.size` are
deliberately absent from `_yaml_helper_defaults`: a default there would answer at step 5 before the
expansion at step 4 ever ran, making `rigor` a no-op for anyone who had not also
set the sub-knob. Their effective values come from the rigor level:
| `modes.rigor` | `modes.workflow` | `docs.density` | `qa.level` | `modes.story_granularity` | `modes.review_mode` | `team.size` |
|---|---|---|---|---|---|---|
| `minimal` (default) | `minimal` | `terse` | `minimal` | `coarse` | `solo` | `individual` |
| `standard` | `standard` | `balanced` | `standard` | `balanced` | `lean` | `individual` |
| `full` | `full` | `thorough` | `full` | `fine` | `full` | `studio` |
Because `rigor` itself defaults to `minimal`, an unconfigured project resolves
these six to the lean row. That default was `standard`; it changed because the
heavier tier measured several times more expensive to reach working code without
producing a better result. See the rationale block above `_yaml_helper_defaults`
in `.claude/hooks/yaml-helper.sh` for the reasoning and the ordering
constraint. Raising the tier is one question in `/start` or one `/settings`
call, and `settings-guidance.md § 4`'s upward triggers are written to fire from
this starting state. (`team.size` is the one knob the flip does not move:
`minimal` and `standard` both yield `individual`, and only `full` opts into the
`studio` roster.) Test **X.8** asserts the six stay defaultless.
> **The flip DOES reach existing projects.** A `project.yaml` that sets some of
> the six explicitly but never sets `rigor` keeps its explicit values and takes
> the new `minimal` row for the rest -- so an unset `qa.level` that used to
> resolve `standard` now resolves `minimal`. Test **X.3** pins exactly this.
> Pin the old behaviour by setting `modes.rigor: standard` explicitly; see
> UPGRADING.md.
`modes.workflow` is **fronted, not replaced**: it keeps
`workflow_overrides.system_overrides`, which still beats the derived value
(**X.6**). Setting any of the six explicitly overrides just that one and leaves
its siblings on the rigor level, which is how "comprehensive but compact"
(`rigor: full` + `docs.density: terse`) stays expressible. Two of the six —
`modes.review_mode` and `team.size` — are personal-experience knobs that also
remain overridable from `project.local.yaml` (that source sits above the
expansion), unlike the four on-disk knobs, which are locked.
> **This table is asserted against the helper, not maintained by hand.** Test
> **X.10** reads `_yaml_helper_defaults` through `get_yaml_default` and checks
> both directions: every knob listed here must carry the value the helper
> actually returns, and none of the six fronted knobs may appear at all. It
> exists because a table can list knobs the helper has stopped defaulting and
> read as correct: the structural check pairs a knob with the word "default" on
> a single line, so a two-cell table row is invisible to it. Editing this table
> without editing the helper now fails the build.
**`testing.strict.*` has no central default on purpose.** Its unset default
differs per skill by design: `/smoke-check` treats unset as **blocking** (it is a
build-health gate), while `/story-done` and `/dev-story` apply the per-story-type
table in `.claude/docs/coding-standards.md`. `resolve_config` therefore reports
only the *configured state* (`unset` where absent) and each skill applies its own
default. The script resolves **sources**; the skill owns **policy**.
**`engine` is reported from `project.yaml` only.** No markdown reader is built.
Skills keep their existing per-field fallback to
`.claude/docs/technical-preferences.md`, which also remains the sole source for
forbidden patterns and allowed libraries — those never migrated.
## Failure modes
`resolve_config` **always exits 0 and always emits a complete block.** Each
condition below degrades to defaults and is named on `notes:`:
| Condition | Behavior |
|---|---|
| `project.yaml` absent | legacy → defaults; `notes: project.yaml absent` |
| `project.yaml` **empty** | defaults; `notes: project.yaml is EMPTY`. Distinct from absent on purpose — a truncated write or an interrupted `/setup-engine` looks like this |
| Malformed YAML | unparseable keys resolve empty and fall through |
| Tab-indented lines | rejected, and the **line numbers are named** on `notes:` |
| CRLF line endings | parsed correctly (the Windows default) |
| UTF-8 BOM | parsed correctly; the BOM does not poison the first key |
| 3-space indent | parsed correctly; the parser is indent-tolerant |
| Key present, value empty | treated as **unset**; falls through to the next source, never to `""` |
| Enum-invalid value | chain continues; rejected value named in `notes:` |
| `project.local.yaml` without a base | `validate_local_yaml_base` message on `notes:` |
| Locked key in `project.local.yaml` | ignored as always, but now **named** on `notes:` — `local: not locally overridable, ignored — modes.rigor (move to project.yaml or delete)` |
| No Python interpreter | legacy files and defaults only; **explicitly noted** on `notes:` |
| No block at all | shell preprocessing disabled — use the defaults table above |
A skill must never treat a missing block as "config is unset in an interesting
way". It means the block did not render; the defaults apply.
### Two behaviours that are correct but SILENT
In both cases the
resolved *value* is right — the chain falls through to the default — but the user
is told nothing, and their explicit configuration was discarded.
| Input | What happens | Note emitted |
|---|---|---|
| **Duplicate key** (`rigor:` twice in one block) | **the last occurrence wins**, deterministically | **none** |
| **Wrong shape** — a list where a scalar belongs (`rigor:` followed by `- standard`) | key resolves empty, falls through to the default | **none** |
**Why this is worth knowing rather than shrugging at.** An enum-*invalid* value is
announced (`modes.workflow: 'medium' is not a valid value … — ignored, chain
continued`). A structurally-invalid one is not. So a user who mistypes the value
gets told, and a user who mistypes the *structure* does not — and the second
mistake is the easier one to make by copy-paste. The framework has the mechanism
(`notes:`) and already uses it for absence, emptiness, tabs, locked keys, orphan
locals and bad enums. Shape is the gap.
**Deliberately not fixed in v1.1.** Detecting "this key is present in the file but
resolved to nothing" means changing the parser every config read in the framework
goes through, and the empty-value fall-through above is a *legitimate* case of
exactly that signature. Distinguishing "empty on purpose" from "unparseable" is
real work, not a one-liner, and it lands in the most load-bearing file there is.
Recorded here as v1.2.
**Duplicate-key precedence was undocumented before this entry.** Last-wins is
deterministic and reproducible, so it is not a bug — but nothing said so, which
meant nobody could rely on it either.
## Why not inject at session start
`resolve_config` is also safe to call from a hook, but session-start does **not**
call it. The block would cost tokens on every session whether or not any skill
needs config, and it would go stale mid-session as `/settings` writes land. The
per-skill body call is fresher and only loads where it is used. Session start
still prints the resolved review mode and any schema errors, which is the part a
human reads.
## Testing
The resolution chain, the legacy reader, enum fall-through, block shape and
every failure mode above are covered by the framework's own test suite under
`tests/`, along with the `modes.rigor` expansion and its precedence in both
directions. Two properties are asserted that are easy to lose:
- The local **read** scope and the `/settings --local` **write** whitelist stay
in step. If they drift, `/settings` accepts and displays a value that every
skill then ignores.
- The expansion is *reachable* (`/start` asks about it) and *legible*
(`/settings` reports derived values rather than "(not set)"). A correct
expansion nobody is asked about and no view displays would be worth nothing.
+66 -3
View File
@@ -17,13 +17,45 @@ after each significant milestone:
- Implementation milestone reached
- Test results obtained
The state file should contain: current task, progress checklist, key decisions
made, files being worked on, and open questions.
**Create it from `.claude/docs/templates/session-state.md`** — the file has a
schema, and hooks depend on it.
Two regions, and the distinction is load-bearing:
| Region | Who reads it | Rule |
|--------|--------------|------|
| `<!-- STATUS -->` … `<!-- /STATUS -->` | `statusline.sh` (breadcrumb, Production+ only) | Keep the markers even when empty |
| `<!-- CHECKPOINT -->` … `<!-- /CHECKPOINT -->` | `session-start.sh` and `pre-compact.sh` | **Overwrite, never append.** Under ~25 lines — hooks inject it verbatim |
| Everything after `<!-- /CHECKPOINT -->` | humans, and an agent that wants detail | Free-form; no hook injects it |
The checkpoint holds: current task, next step, what it is blocked on, files in
progress, open questions. Write it so a cold reader can resume without opening
anything else.
> **Why the split.** One append-only file doing both jobs grows without bound —
> past 700 lines every consumer invents its own slice: a status line parsing a
> STATUS block nothing writes, `pre-compact` injecting `head -100` (12.7 KB, at
> the moment context is scarcest), `session-start` previewing `tail -20` — the
> opposite end. None was wrong, because nothing defined where
> the recoverable state lived. Now every consumer reads the named region, and
> the cost is fixed no matter how long the narrative grows.
**Rotation.** When the narrative passes ~200 lines, move it into
`production/session-logs/`:
```bash
bash .claude/scripts/rotate-session-state.sh # --dry-run to preview
```
The checkpoint stays, the narrative is appended to a dated log, nothing is
deleted. `session-start.sh` observes when rotation is due but never performs it.
### Status Line Block (Production+ only)
When the project is in Production, Polish, or Release stage, include a structured
status block in `active.md` that the status line script can parse:
status block in `active.md` that the status line script can parse. (The project
stage is resolved from `project.stage` in `project.yaml`, falling back to
`production/stage.txt`.)
```markdown
<!-- STATUS -->
@@ -69,6 +101,37 @@ This keeps the context window holding only the *current* section's discussion
- Medium (implement feature): ~8k tokens
- Heavy (multi-system refactor): ~15k tokens
## Deterministic Helpers — `.claude/scripts/`
The cheapest context saving is not summarising a document, it is **not reading it
at all**. When a question has a deterministic answer, a script should answer it
and the model should spend its budget on judgment instead.
Two directories, two purposes — reach for the right one:
| Directory | Purpose | Invoked by |
|---|---|---|
| `.claude/hooks/` | Event-driven — wired into `settings.json` and fired by Claude Code | the harness |
| `.claude/scripts/` | Manually invoked from a skill body | `bash .claude/scripts/<name>.sh` |
Current helpers:
- **`gdd-structure-check.sh`** — which of the 8 standard sections a GDD contains.
Replaces a full-document read per GDD, and cannot hallucinate a missing
section. Reports **presence only**; the caller applies the workflow tier.
- **`review-scope.sh`** — which GDDs changed since the last cross-review, plus
their declared dependencies. Replaces reasoning through git history.
Two rules when adding one:
1. **A skill invoking a script needs `Bash` in `allowed-tools`**, or the step
silently no-ops. A skill that only needs *resolved config* does not — use the
documented `` !`cmd` `` body form, which is preprocessing and is not gated by
`allowed-tools` (see `.claude/docs/config-resolution.md`).
2. **Emit observations, not verdicts.** A script that scores or judges will
eventually contradict a tier, mode, or per-system override it does not know
about. Report what is on disk and let the caller decide what it means.
## Subagent Delegation
Use subagents for research and exploration to keep the main session clean.
+21 -38
View File
@@ -14,60 +14,43 @@
## Model Tier Assignment
Skills and agents are assigned to model tiers based on task complexity:
Read `.claude/docs/model-tiers.md` on demand. It carries the tier table, the
per-skill assignments and the authoring rule.
| Tier | Model | When to use |
|------|-------|-------------|
| **Haiku** | `claude-haiku-4-5-20251001` | Read-only status checks, formatting, simple lookups — no creative judgment needed |
| **Sonnet** | `claude-sonnet-4-6` | Implementation, design authoring, analysis of individual systems — default for most work |
| **Opus** | `claude-opus-4-6` | Multi-document synthesis, high-stakes phase gate verdicts, cross-system holistic review |
Skills with `model: haiku`: `/help`, `/sprint-status`, `/story-readiness`, `/scope-check`,
`/project-stage-detect`, `/changelog`, `/patch-notes`, `/onboard`
Skills with `model: opus`: `/review-all-gdds`, `/architecture-review`, `/gate-check`
All other skills default to Sonnet. When creating new skills, assign Haiku if the
skill only reads and formats; assign Opus if it must synthesize 5+ documents with
high-stakes output; otherwise leave unset (Sonnet).
**One line of it is load-bearing enough to restate here:** a skill's `model:`
frontmatter is **declared but not applied** — Claude Code reads it and serves the
skill from the session model regardless. Never tell a user that a skill's tier
is saving them money. The agent-side `model:` is a different mechanism and is
untested, not known-broken.
## Subagents vs Agent Teams
This project uses two distinct multi-agent patterns:
### Subagents (current, always active)
Spawned via `Task` within a single Claude Code session. Used by all `team-*` skills
and orchestration skills. Subagents share the session's permission context, run
sequentially or in parallel within the session, and return results to the parent.
Spawned via the `Agent` tool within a single Claude Code session (renamed from
`Task` in Claude Code 2.1.63; `Task` still works as an alias). Used by all
`team-*` skills and orchestration skills. Subagents share the session's
permission context, run sequentially or in parallel within the session, and
return results to the parent.
**When to spawn in parallel**: If two subagents' inputs are independent (neither
needs the other's output to begin), spawn both Task calls simultaneously rather
than waiting. Example: `/review-all-gdds` Phase 1 (consistency) and Phase 2
(design theory) are independent — spawn both at the same time.
needs the other's output to begin), spawn both `Agent` calls simultaneously
rather than waiting. Example: `/review-all-gdds` **Phase 2** (consistency) and
**Phase 3** (design theory) are independent — spawn both at the same time.
Phase 1 loads the GDDs and both depend on it, so it is the one phase here that
must NOT be parallelised.
### Agent Teams (experimental — opt-in)
Multiple independent Claude Code *sessions* running simultaneously, coordinated
via a shared task list. Each session has its own context window and token budget.
Requires `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` environment variable.
**Use agent teams when**:
- Work spans multiple subsystems that will not touch the same files
- Each workstream would take >30 minutes and benefits from true parallelism
- A senior agent (technical-director, producer) needs to coordinate 3+ specialist
sessions working on different epics simultaneously
**Do not use agent teams when**:
- One session's output is required as input for another (use sequential subagents)
- The task fits in a single session's context (use subagents instead)
- Cost is a concern — each team member burns tokens independently
**Current status**: Opt-in via `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. Document first usage here when adopted.
Multiple independent Claude Code *sessions* coordinated via a shared task list.
Opt-in and never yet used here — read `.claude/docs/agent-teams.md` on demand
before proposing one.
## Parallel Task Protocol
When an orchestration skill spawns multiple independent agents:
1. Issue all independent Task calls before waiting for any result
1. Issue all independent `Agent` calls before waiting for any result
2. Collect all results before proceeding to dependent phases
3. If any agent is BLOCKED, surface it immediately — do not silently skip
4. Always produce a partial report if some agents complete and others block
+100 -716
View File
@@ -1,96 +1,121 @@
# Director Gates — Shared Review Pattern
This document defines the standard gate prompts for all director and lead reviews
across every workflow stage. Skills reference gate IDs from this document instead
of embedding full prompts inline — eliminating drift when prompts need updating.
Index of all director and lead review gates. Skills reference gate IDs from this
index instead of embedding prompts inline — eliminating drift when prompts need
updating. Each gate's full definition (Trigger, Context to pass, Prompt, Verdicts)
lives in its own file under `.claude/docs/director-gates/`, named after the gate
ID in lowercase.
**Scope**: All 7 production stages (Concept → Release), all 3 Tier 1 directors,
all key Tier 2 leads. Any skill, team orchestrator, or workflow may invoke these gates.
**When a skill spawns a director for a gate, it must NOT read the gate definition
file itself. Include the gate definition file path in the `Agent` prompt and instruct
the director agent to read it first, then pass only the context fields that gate's
row requires. Gate definitions are read by the spawned agent, in the agent's own
context window.**
---
## How to Use This Document
## Gate Index
In any skill, replace an inline director prompt with a reference:
Agent by prefix: `CD-` creative-director (Opus) · `TD-` technical-director (Opus)
· `PR-` producer (Opus) · `AD-` art-director (Sonnet) · `LP-` lead-programmer ·
`QL-` qa-lead · `ND-` narrative-director (Tier 2 leads: Sonnet).
Definition files below are in `.claude/docs/director-gates/`.
```
Spawn `creative-director` via Task using gate **CD-PILLARS** from
`.claude/docs/director-gates.md`.
```
Pass the context listed under that gate's **Context to pass** field, then handle
the verdict using the **Verdict handling** rules below.
| Gate ID | Purpose | Definition file |
|---------|---------|-----------------|
| CD-PILLARS | Pillar stress test after pillars are defined | cd-pillars.md |
| CD-GDD-ALIGN | GDD pillar alignment after a system GDD is authored | cd-gdd-align.md |
| CD-SYSTEMS | Systems decomposition vision check after `/map-systems` | cd-systems.md |
| CD-NARRATIVE | Narrative consistency of story/lore documents | cd-narrative.md |
| CD-PLAYTEST | Player experience validation of playtest reports | cd-playtest.md |
| CD-PHASE-GATE | Creative readiness at phase transition | cd-phase-gate.md |
| TD-SYSTEM-BOUNDARY | System boundary review before GDD authoring | td-system-boundary.md |
| TD-FEASIBILITY | Technical feasibility of early concept risks | td-feasibility.md |
| TD-ARCHITECTURE | Master architecture document sign-off | td-architecture.md |
| TD-ADR | Individual ADR review before Accepted | td-adr.md |
| TD-ENGINE-RISK | Engine version risk for post-cutoff APIs | td-engine-risk.md |
| TD-PHASE-GATE | Technical readiness at phase transition | td-phase-gate.md |
| TD-MANIFEST | Control manifest review before it is written | td-manifest.md |
| TD-CHANGE-IMPACT | Design-change impact assessment review | td-change-impact.md |
| PR-SCOPE | Scope and timeline validation | pr-scope.md |
| PR-SPRINT | Sprint plan feasibility review | pr-sprint.md |
| PR-MILESTONE | Milestone risk assessment | pr-milestone.md |
| PR-EPIC | Epic structure feasibility before story breakdown | pr-epic.md |
| PR-PHASE-GATE | Production readiness at phase transition | pr-phase-gate.md |
| AD-CONCEPT-VISUAL | Visual identity anchor after pillars lock | ad-concept-visual.md |
| AD-ART-BIBLE | Art bible sign-off before asset production | ad-art-bible.md |
| AD-PHASE-GATE | Visual readiness at phase transition | ad-phase-gate.md |
| LP-FEASIBILITY | Implementation feasibility of the architecture | lp-feasibility.md |
| LP-CODE-REVIEW | Code review of an implemented story | lp-code-review.md |
| QL-STORY-READY | Acceptance-criteria testability before sprint | ql-story-ready.md |
| QL-TEST-COVERAGE | Test coverage review before epic done / advance | ql-test-coverage.md |
| ND-CONSISTENCY | Narrative consistency of writer deliverables | nd-consistency.md |
| AD-VISUAL | Visual consistency of art/tech-art decisions | ad-visual.md |
---
## Review Modes
Review intensity controls whether director gates run. It can be set globally
(persists across sessions) or overridden per skill run.
Review intensity controls whether gates run.
**Global config**: `production/review-mode.txt` — one word: `full`, `lean`, or `solo`.
Set once during `/start`. Edit the file directly to change it at any time.
**Global config**: `modes.review_mode` in `project.yaml` — one word: `full`,
`lean`, or `solo`. Legacy fallback: `production/review-mode.txt` (single line,
same values); `project.yaml` wins when both are present. Set once during
`/start`, or change it any time with `/settings modes.review_mode=<value>`.
**Per-run override**: any gate-using skill accepts `--review [full|lean|solo]` as an
argument. This overrides the global config for that run only.
**Per-run override**: any gate-using skill accepts `--review [full|lean|solo]`,
overriding the global config for that run only.
Examples:
```
/brainstorm space horror → uses global mode
/brainstorm space horror --review full → forces full mode this run
/architecture-decision --review solo → skips all gates this run
```
| Mode | What runs | Best for |
|------|-----------|----------|
| `full` | All gates active — every workflow step reviewed | Teams, learning users, or when you want thorough director feedback at every step |
| `lean` | PHASE-GATEs only (`/gate-check`) — per-skill gates skipped | **Default** — solo devs and small teams; directors review at milestones only |
| `solo` | No director gates anywhere | Game jams, prototypes, maximum speed |
**Check pattern — apply before every gate spawn:**
```
Before spawning gate [GATE-ID]:
1. If skill was called with --review [mode], use that
2. Else read production/review-mode.txt
3. Else default to lean
Apply the resolved mode:
- solo → skip all gates. Note: "[GATE-ID] skipped — Solo mode"
- lean → skip unless this is a PHASE-GATE (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GATE, AD-PHASE-GATE)
Note: "[GATE-ID] skipped — Lean mode"
- full → spawn as normal
```
| Mode | What runs |
|------|-----------|
| `full` | All gates active — every workflow step reviewed |
| `lean` | PHASE-GATEs only (`/gate-check`) — per-skill gates skipped. **Default** |
| `solo` | No director gates anywhere (game jams, prototypes, max speed) |
---
## Invocation Pattern (copy into any skill)
**MANDATORY: Resolve review mode before every gate spawn.** Never spawn a gate without checking. The resolved mode is determined once per skill run:
1. If skill was called with `--review [mode]`, use that
2. Else read `production/review-mode.txt`
3. Else default to `lean`
**MANDATORY: apply the review mode before every gate spawn.**
The value is already resolved — skills call
`` !`source .claude/hooks/yaml-helper.sh && resolve_config --keys review_mode` ``
and read `review_mode` from the emitted block. Do **not** re-derive it here. The
full chain (`project.local.yaml` → `project.yaml` → `production/review-mode.txt`
→ `modes.rigor` expansion, `standard`→`lean`), its defaults and its failure modes are specified in
`.claude/docs/config-resolution.md`, and covered by the config test suite.
An inline `--review [mode]` argument, if the skill accepts one, overrides the
resolved value for that run.
Apply the resolved mode:
- `solo` → **skip all gates**. Note in output: `[GATE-ID] skipped — Solo mode`
- `solo` → **skip all gates**. Note: `[GATE-ID] skipped — Solo mode`
- `lean` → **skip unless this is a PHASE-GATE** (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GATE, AD-PHASE-GATE). Note: `[GATE-ID] skipped — Lean mode`
- `full` → spawn as normal
> **PHASE-GATE panel width is a second, independent axis.** `review_mode` decides
> whether the four PHASE-GATEs run at all; `modes.workflow` decides how many of
> them run — `minimal` → PR only, `standard` → TD + PR, `full` → all four. The
> rule and its rationale live in `/gate-check` Section 4b, the only skill that
> spawns PHASE-GATEs. Every other gate in this index is single-director and
> unaffected. Width never softens a verdict: the escalation rule below applies
> unchanged to whoever ran.
```
# Apply mode check, then:
Spawn `[agent-name]` via Task:
- Gate: [GATE-ID] (see .claude/docs/director-gates.md)
- Context: [fields listed under that gate]
Spawn `[agent-name]` via `Agent`:
- Gate: [GATE-ID] — `Agent` prompt instructs the agent to read
`.claude/docs/director-gates/[gate-id].md` FIRST (parent must not read it)
- Context: [fields under that gate's **Context to pass**]
- Await the verdict before proceeding.
```
For parallel spawning (multiple directors at the same gate point):
```
# Apply mode check for each gate first, then spawn all that survive:
Spawn all [N] agents simultaneously via Task — issue all Task calls before
waiting for any result. Collect all verdicts before proceeding.
```
For parallel spawning (multiple directors at one gate point): apply the mode
check per gate, then spawn all surviving agents simultaneously — issue all `Agent`
calls before waiting for any result; collect all verdicts before proceeding.
---
@@ -122,655 +147,14 @@ For phase gates, record in `docs/architecture/architecture.md` or
---
## Tier 1 — Creative Director Gates
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
---
### CD-PILLARS — Pillar Stress Test
**Trigger**: After game pillars and anti-pillars are defined (brainstorm Phase 4,
or any time pillars are revised)
**Context to pass**:
- Full pillar set with names, definitions, and design tests
- Anti-pillars list
- Core fantasy statement
- Unique hook ("Like X, AND ALSO Y")
**Prompt**:
> "Review these game pillars. Are they falsifiable — could a real design decision
> actually fail this pillar? Do they create meaningful tension with each other? Do
> they differentiate this game from its closest comparables? Would they help resolve
> a design disagreement in practice, or are they too vague to be useful? Return
> specific feedback for each pillar and an overall verdict: APPROVE (strong), CONCERNS
> [list] (needs sharpening), or REJECT (weak — pillars do not carry weight)."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### CD-GDD-ALIGN — GDD Pillar Alignment Check
**Trigger**: After a system GDD is authored (design-system, quick-design, or any
workflow that produces a GDD)
**Context to pass**:
- GDD file path
- Game pillars (from `design/gdd/game-concept.md` or `design/gdd/game-pillars.md`)
- MDA aesthetics target for this game
- System's stated Player Fantasy section
**Prompt**:
> "Review this system GDD for pillar alignment. Does every section serve the stated
> pillars? Are there mechanics or rules that contradict or weaken a pillar? Does
> the Player Fantasy section match the game's core fantasy? Return APPROVE, CONCERNS
> [specific sections with issues], or REJECT [pillar violations that must be
> redesigned before this system is implementable]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### CD-SYSTEMS — Systems Decomposition Vision Check
**Trigger**: After the systems index is written by `/map-systems` — validates the
complete system set before GDD authoring begins
**Context to pass**:
- Systems index path (`design/gdd/systems-index.md`)
- Game pillars and core fantasy (from `design/gdd/game-concept.md`)
- Priority tier assignments (MVP / Vertical Slice / Alpha / Full Vision)
- Any high-risk or bottleneck systems identified in the dependency map
**Prompt**:
> "Review this systems decomposition against the game's design pillars. Does the
> full set of MVP-tier systems collectively deliver the core fantasy? Are there
> systems whose mechanics don't serve any stated pillar — indicating they may be
> scope creep? Are there pillar-critical player experiences that have no system
> assigned to deliver them? Are any systems missing that the core loop requires?
> Return APPROVE (systems serve the vision), CONCERNS [specific gaps or
> misalignments with their pillar implications], or REJECT [fundamental gaps —
> the decomposition misses critical design intent and must be revised before GDD
> authoring begins]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### CD-NARRATIVE — Narrative Consistency Check
**Trigger**: After narrative GDDs, lore documents, dialogue specs, or world-building
documents are authored (team-narrative, design-system for story systems, writer
deliverables)
**Context to pass**:
- Document file path(s)
- Game pillars
- Narrative direction brief or tone guide (if exists at `design/narrative/`)
- Any existing lore that the new document references
**Prompt**:
> "Review this narrative content for consistency with the game's pillars and
> established world rules. Does the tone match the game's established voice? Are
> there contradictions with existing lore or world-building? Does the content serve
> the player experience pillar? Return APPROVE, CONCERNS [specific inconsistencies],
> or REJECT [contradictions that break world coherence]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### CD-PLAYTEST — Player Experience Validation
**Trigger**: After playtest reports are generated (`/playtest-report`), or after
any session that produces player feedback
**Context to pass**:
- Playtest report file path
- Game pillars and core fantasy statement
- The specific hypothesis being tested
**Prompt**:
> "Review this playtest report against the game's design pillars and core fantasy.
> Is the player experience matching the intended fantasy? Are there systematic issues
> that represent pillar drift — mechanics that feel fine in isolation but undermine
> the intended experience? Return APPROVE (core fantasy is landing), CONCERNS [gaps
> between intended and actual experience], or REJECT [core fantasy is not present —
> redesign needed before further playtesting]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### CD-PHASE-GATE — Creative Readiness at Phase Transition
**Trigger**: Always at `/gate-check` — spawn in parallel with TD-PHASE-GATE and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- List of all artifacts present (file paths)
- Game pillars and core fantasy
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> creative direction perspective. Are the game pillars faithfully represented in
> all design artifacts? Does the current state preserve the core fantasy? Are there
> any design decisions across GDDs or architecture that compromise the intended
> player experience? Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
---
## Tier 1 — Technical Director Gates
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
---
### TD-SYSTEM-BOUNDARY — System Boundary Architecture Review
**Trigger**: After `/map-systems` Phase 3 dependency mapping is agreed but before
GDD authoring begins — validates that the system structure is architecturally
sound before teams invest in writing GDDs against it
**Context to pass**:
- Systems index path (or the dependency map summary if index not yet written)
- Layer assignments (Foundation / Core / Feature / Presentation / Polish)
- The full dependency graph (what each system depends on)
- Any bottleneck systems flagged (many dependents)
- Any circular dependencies found and their proposed resolutions
**Prompt**:
> "Review this systems decomposition from an architectural perspective before GDD
> authoring begins. Are the system boundaries clean — does each system own a
> distinct concern with minimal overlap? Are there God Object risks (systems doing
> too much)? Does the dependency ordering create implementation-sequencing problems?
> Are there implicit shared-state problems in the proposed boundaries that will
> cause tight coupling when implemented? Are any Foundation-layer systems actually
> dependent on Feature-layer systems (inverted dependency)? Return APPROVE
> (boundaries are architecturally sound — proceed to GDD authoring), CONCERNS
> [specific boundary issues to address in the GDDs themselves], or REJECT
> [fundamental boundary problems — the system structure will cause architectural
> issues and must be restructured before any GDD is written]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### TD-FEASIBILITY — Technical Feasibility Assessment
**Trigger**: After biggest technical risks are identified during scope/feasibility
(brainstorm Phase 6, quick-design, or any early-stage concept with technical unknowns)
**Context to pass**:
- Concept's core loop description
- Platform target
- Engine choice (or "undecided")
- List of identified technical risks
**Prompt**:
> "Review these technical risks for a [genre] game targeting [platform] using
> [engine or 'undecided engine']. Flag any HIGH risk items that could invalidate
> the concept as described, any risks that are engine-specific and should influence
> the engine choice, and any risks that are commonly underestimated by solo
> developers. Return VIABLE (risks are manageable), CONCERNS [list with mitigation
> suggestions], or HIGH RISK [blockers that require concept or scope revision]."
**Verdicts**: VIABLE / CONCERNS / HIGH RISK
---
### TD-ARCHITECTURE — Architecture Sign-Off
**Trigger**: After the master architecture document is drafted (`/create-architecture`
Phase 7), and after any major architecture revision
**Context to pass**:
- Architecture document path (`docs/architecture/architecture.md`)
- Technical requirements baseline (TR-IDs and count)
- ADR list with statuses
- Engine knowledge gap inventory
**Prompt**:
> "Review this master architecture document for technical soundness. Check: (1) Is
> every technical requirement from the baseline covered by an architectural decision?
> (2) Are all HIGH risk engine domains explicitly addressed or flagged as open
> questions? (3) Are the API boundaries clean, minimal, and implementable? (4) Are
> Foundation layer ADR gaps resolved before implementation begins? Return APPROVE,
> CONCERNS [list], or REJECT [blockers that must be resolved before coding starts]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### TD-ADR — Architecture Decision Review
**Trigger**: After an individual ADR is authored (`/architecture-decision`), before
it is marked Accepted
**Context to pass**:
- ADR file path
- Engine version and knowledge gap risk level for the domain
- Related ADRs (if any)
**Prompt**:
> "Review this Architecture Decision Record. Does it have a clear problem statement
> and rationale? Are the rejected alternatives genuinely considered? Does the
> Consequences section acknowledge the trade-offs honestly? Is the engine version
> stamped? Are post-cutoff API risks flagged? Does it link to the GDD requirements
> it covers? Return APPROVE, CONCERNS [specific gaps], or REJECT [the decision is
> underspecified or makes unsound technical assumptions]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### TD-ENGINE-RISK — Engine Version Risk Review
**Trigger**: When making architecture decisions that touch post-cutoff engine APIs,
or before finalizing any engine-specific implementation approach
**Context to pass**:
- The specific API or feature being used
- Engine version and LLM knowledge cutoff (from `docs/engine-reference/[engine]/VERSION.md`)
- Relevant excerpt from breaking-changes or deprecated-apis docs
**Prompt**:
> "Review this engine API usage against the version reference. Is this API present
> in [engine version]? Has its signature, behaviour, or namespace changed since the
> LLM knowledge cutoff? Are there known deprecations or post-cutoff alternatives?
> Return APPROVE (safe to use as described), CONCERNS [verify before implementing],
> or REJECT [API has changed — provide corrected approach]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### TD-PHASE-GATE — Technical Readiness at Phase Transition
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- Architecture document path (if exists)
- Engine reference path
- ADR list
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> technical direction perspective. Is the architecture sound for this phase? Are
> all high-risk engine domains addressed? Are performance budgets realistic and
> documented? Are Foundation-layer decisions complete enough to begin implementation?
> Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
---
## Tier 1 — Producer Gates
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
---
### PR-SCOPE — Scope and Timeline Validation
**Trigger**: After scope tiers are defined (brainstorm Phase 6, quick-design, or
any workflow that produces an MVP definition and timeline estimate)
**Context to pass**:
- Full vision scope description
- MVP definition
- Timeline estimate
- Team size (solo / small team / etc.)
- Scope tiers (what ships if time runs out)
**Prompt**:
> "Review this scope estimate. Is the MVP achievable in the stated timeline for
> the stated team size? Are the scope tiers correctly ordered by risk — does each
> tier deliver a shippable product if work stops there? What is the most likely
> cut point under time pressure, and is it a graceful fallback or a broken product?
> Return REALISTIC (scope matches capacity), OPTIMISTIC [specific adjustments
> recommended], or UNREALISTIC [blockers — timeline or MVP must be revised]."
**Verdicts**: REALISTIC / OPTIMISTIC / UNREALISTIC
---
### PR-SPRINT — Sprint Feasibility Review
**Trigger**: Before finalising a sprint plan (`/sprint-plan`), and after any
mid-sprint scope change
**Context to pass**:
- Proposed sprint story list (titles, estimates, dependencies)
- Team capacity (hours available)
- Current sprint backlog debt (if any)
- Milestone constraints
**Prompt**:
> "Review this sprint plan for feasibility. Is the story load realistic for the
> available capacity? Are stories correctly ordered by dependency? Are there hidden
> dependencies between stories that could block the sprint mid-way? Are any stories
> underestimated given their technical complexity? Return REALISTIC (plan is
> achievable), CONCERNS [specific risks], or UNREALISTIC [sprint must be
> descoped — identify which stories to defer]."
**Verdicts**: REALISTIC / CONCERNS / UNREALISTIC
---
### PR-MILESTONE — Milestone Risk Assessment
**Trigger**: At milestone review (`/milestone-review`), at mid-sprint retrospectives,
or when a scope change is proposed that affects the milestone
**Context to pass**:
- Milestone definition and target date
- Current completion percentage
- Blocked stories count
- Sprint velocity data (if available)
**Prompt**:
> "Review this milestone status. Based on current velocity and blocked story count,
> will this milestone hit its target date? What are the top 3 production risks
> between now and the milestone? Are there scope items that should be cut to protect
> the milestone date vs. items that are non-negotiable? Return ON TRACK, AT RISK
> [specific mitigations], or OFF TRACK [date must slip or scope must cut — provide
> both options]."
**Verdicts**: ON TRACK / AT RISK / OFF TRACK
---
### PR-EPIC — Epic Structure Feasibility Review
**Trigger**: After epics are defined by `/create-epics`, before stories are
broken out — validates the epic structure is producible before `/create-stories`
is invoked
**Context to pass**:
- Epic definition file paths (all epics just created)
- Epic index path (`production/epics/index.md`)
- Milestone timeline and target dates
- Team capacity (solo / small team / size)
- Layer being epiced (Foundation / Core / Feature / etc.)
**Prompt**:
> "Review this epic structure for production feasibility before story breakdown
> begins. Are the epic boundaries scoped appropriately — could each epic realistically
> complete before a milestone deadline? Are epics correctly ordered by system
> dependency — does any epic require another epic's output before it can start?
> Are any epics underscoped (too small, should merge) or overscoped (too large,
> should split into 2-3 focused epics)? Are the Foundation-layer epics scoped to
> allow Core-layer epics to begin at the start of the next sprint after Foundation
> completes? Return REALISTIC (epic structure is producible), CONCERNS [specific
> structural adjustments before stories are written], or UNREALISTIC [epics must
> be split, merged, or reordered — story breakdown cannot begin until resolved]."
**Verdicts**: REALISTIC / CONCERNS / UNREALISTIC
---
### PR-PHASE-GATE — Production Readiness at Phase Transition
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE and TD-PHASE-GATE
**Context to pass**:
- Target phase name
- Sprint and milestone artifacts present
- Team size and capacity
- Current blocked story count
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> production perspective. Is the scope realistic for the stated timeline and team
> size? Are dependencies properly ordered so the team can actually execute in
> sequence? Are there milestone or sprint risks that could derail the phase within
> the first two sprints? Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
---
## Tier 1 — Art Director Gates
Agent: `art-director` | Model tier: Sonnet | Domain: Visual identity, art bible, visual production readiness
---
### AD-CONCEPT-VISUAL — Visual Identity Anchor
**Trigger**: After game pillars are locked (brainstorm Phase 4), in parallel with CD-PILLARS
**Context to pass**:
- Game concept (elevator pitch, core fantasy, unique hook)
- Full pillar set with names, definitions, and design tests
- Target platform (if known)
- Any reference games or visual touchstones mentioned by the user
**Prompt**:
> "Based on these game pillars and core concept, propose 2-3 distinct visual identity
> directions. For each direction provide: (1) a one-line visual rule that could guide
> all visual decisions (e.g., 'everything must move', 'beauty is in the decay'), (2)
> mood and atmosphere targets, (3) shape language (sharp/rounded/organic/geometric
> emphasis), (4) color philosophy (palette direction, what colors mean in this world).
> Be specific — avoid generic descriptions. One direction should directly serve the
> primary design pillar. Name each direction. Recommend which best serves the stated
> pillars and explain why."
**Verdicts**: CONCEPTS (multiple valid options — user selects) / STRONG (one direction clearly dominant) / CONCERNS (pillars don't provide enough direction to differentiate visual identity yet)
---
### AD-ART-BIBLE — Art Bible Sign-Off
**Trigger**: After the art bible is drafted (`/art-bible`), before asset production begins
**Context to pass**:
- Art bible path (`design/art/art-bible.md`)
- Game pillars and core fantasy
- Platform and performance constraints (from `.claude/docs/technical-preferences.md` if configured)
- Visual identity anchor chosen during brainstorm (from `design/gdd/game-concept.md`)
**Prompt**:
> "Review this art bible for completeness and internal consistency. Does the color
> system match the mood targets? Does the shape language follow from the visual
> identity statement? Are the asset standards achievable within the platform
> constraints? Does the character design direction give artists enough to work from
> without over-specifying? Are there contradictions between sections? Would an
> outsourcing team be able to produce assets from this document without additional
> briefing? Return APPROVE (art bible is production-ready), CONCERNS [specific
> sections needing clarification], or REJECT [fundamental inconsistencies that must
> be resolved before asset production begins]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### AD-PHASE-GATE — Visual Readiness at Phase Transition
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE, TD-PHASE-GATE, and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- List of all art/visual artifacts present (file paths)
- Visual identity anchor from `design/gdd/game-concept.md` (if present)
- Art bible path if it exists (`design/art/art-bible.md`)
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a visual
> direction perspective. Is the visual identity established and documented at the
> level this phase requires? Are the right visual artifacts in place? Would visual
> teams be able to begin their work without visual direction gaps that cause costly
> rework later? Are there visual decisions that are being deferred past their latest
> responsible moment? Return READY, CONCERNS [specific visual direction gaps that
> could cause production rework], or NOT READY [visual blockers that must exist
> before this phase can succeed — specify what artifact is missing and why it
> matters at this stage]."
**Verdicts**: READY / CONCERNS / NOT READY
---
## Tier 2 — Lead Gates
These gates are invoked by orchestration skills and senior skills when a domain
specialist's feasibility sign-off is needed. Tier 2 leads use Sonnet (default).
---
### LP-FEASIBILITY — Lead Programmer Implementation Feasibility
**Trigger**: After the master architecture document is written (`/create-architecture`
Phase 7b), or when a new architectural pattern is proposed
**Context to pass**:
- Architecture document path
- Technical requirements baseline summary
- ADR list with statuses
**Prompt**:
> "Review this architecture for implementation feasibility. Flag: (a) any decisions
> that would be difficult or impossible to implement with the stated engine and
> language, (b) any missing interface definitions that programmers would need to
> invent themselves, (c) any patterns that create avoidable technical debt or
> that contradict standard [engine] idioms. Return FEASIBLE, CONCERNS [list], or
> INFEASIBLE [blockers that make this architecture unimplementable as written]."
**Verdicts**: FEASIBLE / CONCERNS / INFEASIBLE
---
### LP-CODE-REVIEW — Lead Programmer Code Review
**Trigger**: After a dev story is implemented (`/dev-story`, `/story-done`), or
as part of `/code-review`
**Context to pass**:
- Implementation file paths
- Story file path (for acceptance criteria)
- Relevant GDD section
- ADR that governs this system
**Prompt**:
> "Review this implementation against the story acceptance criteria and governing
> ADR. Does the code match the architecture boundary definitions? Are there
> violations of the coding standards or forbidden patterns? Is the public API
> testable and documented? Are there any correctness issues against the GDD rules?
> Return APPROVE, CONCERNS [specific issues], or REJECT [must be revised before merge]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### QL-STORY-READY — QA Lead Story Readiness Check
**Trigger**: Before a story is accepted into a sprint — invoked by `/create-stories`,
`/story-readiness`, and `/sprint-plan` during story selection
**Context to pass**:
- Story file path
- Story type (Logic / Integration / Visual/Feel / UI / Config/Data)
- Acceptance criteria list (verbatim from the story)
- The GDD requirement (TR-ID and text) the story covers
**Prompt**:
> "Review this story's acceptance criteria for testability before it enters the
> sprint. Are all criteria specific enough that a developer would know unambiguously
> when they are done? For Logic-type stories: can every criterion be verified with
> an automated test? For Integration stories: is each criterion observable in a
> controlled test environment? Flag criteria that are too vague to implement
> against, and flag criteria that require a full game build to test (mark these
> DEFERRED, not BLOCKED). Return ADEQUATE (criteria are implementable as written),
> GAPS [specific criteria needing refinement], or INADEQUATE [criteria are too
> vague — story must be revised before sprint inclusion]."
**Verdicts**: ADEQUATE / GAPS / INADEQUATE
---
### QL-TEST-COVERAGE — QA Lead Test Coverage Review
**Trigger**: After implementation stories are complete, before marking an epic
done, or at `/gate-check` Production → Polish
**Context to pass**:
- List of implemented stories with story types (Logic / Integration / Visual / UI / Config)
- Test file paths in `tests/`
- GDD acceptance criteria for the system
**Prompt**:
> "Review the test coverage for these implementation stories. Are all Logic stories
> covered by passing unit tests? Are Integration stories covered by integration
> tests or documented playtests? Are the GDD acceptance criteria each mapped to at
> least one test? Are there untested edge cases from the GDD Edge Cases section?
> Return ADEQUATE (coverage meets standards), GAPS [specific missing tests], or
> INADEQUATE [critical logic is untested — do not advance]."
**Verdicts**: ADEQUATE / GAPS / INADEQUATE
---
### ND-CONSISTENCY — Narrative Director Consistency Check
**Trigger**: After writer deliverables (dialogue, lore, item descriptions) are
authored, or when a design decision has narrative implications
**Context to pass**:
- Document or content file path(s)
- Narrative bible or tone guide path (if exists)
- Relevant world-building rules
- Character or faction profiles affected
**Prompt**:
> "Review this narrative content for internal consistency and adherence to
> established world rules. Are character voices consistent with their established
> profiles? Does the lore contradict any established facts? Is the tone consistent
> with the game's narrative direction? Return APPROVE, CONCERNS [specific
> inconsistencies to fix], or REJECT [contradictions that break the narrative
> foundation]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
### AD-VISUAL — Art Director Visual Consistency Review
**Trigger**: After art direction decisions are made, when new asset types are
introduced, or when a tech art decision affects visual style
**Context to pass**:
- Art bible path (if exists at `design/art/art-bible.md`)
- The specific asset type, style decision, or visual direction being reviewed
- Reference images or style descriptions
- Platform and performance constraints
**Prompt**:
> "Review this visual direction decision for consistency with the established art
> style and production constraints. Does it match the art bible? Is it achievable
> within the platform's performance budget? Are there asset pipeline implications
> that create technical risk? Return APPROVE, CONCERNS [specific adjustments], or
> REJECT [style violation or production risk that must be resolved first]."
**Verdicts**: APPROVE / CONCERNS / REJECT
---
## Parallel Gate Protocol
When a workflow requires multiple directors at the same checkpoint (most common
at `/gate-check`), spawn all agents simultaneously:
At checkpoints needing multiple directors (most common at `/gate-check`):
```
Spawn in parallel (issue all Task calls before waiting for any result):
1. creative-director → gate CD-PHASE-GATE
2. technical-director → gate TD-PHASE-GATE
3. producer → gate PR-PHASE-GATE
4. art-director → gate AD-PHASE-GATE
Spawn in parallel (issue all `Agent` calls before waiting for any result):
creative-director → CD-PHASE-GATE, technical-director → TD-PHASE-GATE,
producer → PR-PHASE-GATE, art-director → AD-PHASE-GATE
Collect all four verdicts, then apply escalation rules:
- Any NOT READY / REJECT → overall verdict minimum FAIL
@@ -782,14 +166,14 @@ Collect all four verdicts, then apply escalation rules:
## Adding New Gates
When a new gate is needed for a new skill or workflow:
1. Assign a gate ID: `[DIRECTOR-PREFIX]-[DESCRIPTIVE-SLUG]`
- Prefixes: `CD-` `TD-` `PR-` `LP-` `QL-` `ND-` `AD-`
- Add new prefixes for new agents: `audio-director` → `AU-`, `ux-designer` → `UX-`
2. Add the gate under the appropriate director section with all five fields:
Trigger, Context to pass, Prompt, Verdicts, and any special handling notes
3. Reference it in skills by ID only — never copy the prompt text into the skill
1. Assign a gate ID: `[DIRECTOR-PREFIX]-[DESCRIPTIVE-SLUG]`. Prefixes: `CD-`
`TD-` `PR-` `LP-` `QL-` `ND-` `AD-`; add new ones for new agents
(`audio-director` → `AU-`, `ux-designer` → `UX-`)
2. Create `.claude/docs/director-gates/[gate-id].md` (lowercase), starting with
the standard "> Gate definition..." header note, with all five fields:
Trigger, Context to pass, Prompt, Verdicts, special handling notes
3. Add its row to the Gate Index table above
4. Reference it in skills by ID only — never copy the prompt text into the skill
---
@@ -798,9 +182,9 @@ When a new gate is needed for a new skill or workflow:
| Stage | Required Gates | Optional Gates |
|-------|---------------|----------------|
| **Concept** | CD-PILLARS, AD-CONCEPT-VISUAL | TD-FEASIBILITY, PR-SCOPE |
| **Systems Design** | TD-SYSTEM-BOUNDARY, CD-SYSTEMS, PR-SCOPE, CD-GDD-ALIGN (per GDD) | ND-CONSISTENCY, AD-VISUAL |
| **Technical Setup** | TD-ARCHITECTURE, TD-ADR (per ADR), LP-FEASIBILITY, AD-ART-BIBLE | TD-ENGINE-RISK |
| **Systems Design** | TD-SYSTEM-BOUNDARY, CD-SYSTEMS, PR-SCOPE, CD-GDD-ALIGN (per GDD) | ND-CONSISTENCY, AD-VISUAL, TD-CHANGE-IMPACT (on GDD revision) |
| **Technical Setup** | TD-ARCHITECTURE, TD-ADR (per ADR), TD-MANIFEST, LP-FEASIBILITY, AD-ART-BIBLE | TD-ENGINE-RISK |
| **Pre-Production** | PR-EPIC, QL-STORY-READY (per story), PR-SPRINT, all four PHASE-GATEs (via gate-check) | CD-PLAYTEST |
| **Production** | LP-CODE-REVIEW (per story), QL-STORY-READY, PR-SPRINT (per sprint), QL-TEST-COVERAGE (per sprint close-out) | PR-MILESTONE, AD-VISUAL |
| **Production** | LP-CODE-REVIEW (per story), QL-STORY-READY, PR-SPRINT (per sprint), QL-TEST-COVERAGE (per sprint close-out) | PR-MILESTONE, AD-VISUAL, TD-CHANGE-IMPACT (on GDD revision) |
| **Polish** | QL-TEST-COVERAGE, CD-PLAYTEST, PR-MILESTONE | AD-VISUAL |
| **Release** | All four PHASE-GATEs (via gate-check) | QL-TEST-COVERAGE |
@@ -0,0 +1,26 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# AD-ART-BIBLE — Art Bible Sign-Off
Agent: `art-director` | Model tier: Sonnet | Domain: Visual identity, art bible, visual production readiness
**Trigger**: After the art bible is drafted (`/art-bible`), before asset production begins
**Context to pass**:
- Art bible path (`design/art/art-bible.md`)
- Game pillars and core fantasy
- Platform and performance constraints (`platform.*` and `performance.*` from `project.yaml`, falling back to `.claude/docs/technical-preferences.md`)
- Visual identity anchor chosen during brainstorm (from `design/gdd/game-concept.md`)
**Prompt**:
> "Review this art bible for completeness and internal consistency. Does the color
> system match the mood targets? Does the shape language follow from the visual
> identity statement? Are the asset standards achievable within the platform
> constraints? Does the character design direction give artists enough to work from
> without over-specifying? Are there contradictions between sections? Would an
> outsourcing team be able to produce assets from this document without additional
> briefing? Return APPROVE (art bible is production-ready), CONCERNS [specific
> sections needing clarification], or REJECT [fundamental inconsistencies that must
> be resolved before asset production begins]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,25 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# AD-CONCEPT-VISUAL — Visual Identity Anchor
Agent: `art-director` | Model tier: Sonnet | Domain: Visual identity, art bible, visual production readiness
**Trigger**: After game pillars are locked (brainstorm Phase 4), in parallel with CD-PILLARS
**Context to pass**:
- Game concept (elevator pitch, core fantasy, unique hook)
- Full pillar set with names, definitions, and design tests
- Target platform (if known)
- Any reference games or visual touchstones mentioned by the user
**Prompt**:
> "Based on these game pillars and core concept, propose 2-3 distinct visual identity
> directions. For each direction provide: (1) a one-line visual rule that could guide
> all visual decisions (e.g., 'everything must move', 'beauty is in the decay'), (2)
> mood and atmosphere targets, (3) shape language (sharp/rounded/organic/geometric
> emphasis), (4) color philosophy (palette direction, what colors mean in this world).
> Be specific — avoid generic descriptions. One direction should directly serve the
> primary design pillar. Name each direction. Recommend which best serves the stated
> pillars and explain why."
**Verdicts**: CONCEPTS (multiple valid options — user selects) / STRONG (one direction clearly dominant) / CONCERNS (pillars don't provide enough direction to differentiate visual identity yet)
@@ -0,0 +1,26 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# AD-PHASE-GATE — Visual Readiness at Phase Transition
Agent: `art-director` | Model tier: Sonnet | Domain: Visual identity, art bible, visual production readiness
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE, TD-PHASE-GATE, and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- List of all art/visual artifacts present (file paths)
- Visual identity anchor from `design/gdd/game-concept.md` (if present)
- Art bible path if it exists (`design/art/art-bible.md`)
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a visual
> direction perspective. Is the visual identity established and documented at the
> level this phase requires? Are the right visual artifacts in place? Would visual
> teams be able to begin their work without visual direction gaps that cause costly
> rework later? Are there visual decisions that are being deferred past their latest
> responsible moment? Return READY, CONCERNS [specific visual direction gaps that
> could cause production rework], or NOT READY [visual blockers that must exist
> before this phase can succeed — specify what artifact is missing and why it
> matters at this stage]."
**Verdicts**: READY / CONCERNS / NOT READY
+23
View File
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# AD-VISUAL — Art Director Visual Consistency Review
Agent: `art-director` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: After art direction decisions are made, when new asset types are
introduced, or when a tech art decision affects visual style
**Context to pass**:
- Art bible path (if exists at `design/art/art-bible.md`)
- The specific asset type, style decision, or visual direction being reviewed
- Reference images or style descriptions
- Platform and performance constraints
**Prompt**:
> "Review this visual direction decision for consistency with the established art
> style and production constraints. Does it match the art bible? Is it achievable
> within the platform's performance budget? Are there asset pipeline implications
> that create technical risk? Return APPROVE, CONCERNS [specific adjustments], or
> REJECT [style violation or production risk that must be resolved first]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-GDD-ALIGN — GDD Pillar Alignment Check
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: After a system GDD is authored (design-system, quick-design, or any
workflow that produces a GDD)
**Context to pass**:
- GDD file path
- Game pillars (from `design/gdd/game-concept.md` or `design/gdd/game-pillars.md`)
- MDA aesthetics target for this game
- System's stated Player Fantasy section
**Prompt**:
> "Review this system GDD for pillar alignment. Does every section serve the stated
> pillars? Are there mechanics or rules that contradict or weaken a pillar? Does
> the Player Fantasy section match the game's core fantasy? Return APPROVE, CONCERNS
> [specific sections with issues], or REJECT [pillar violations that must be
> redesigned before this system is implementable]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-NARRATIVE — Narrative Consistency Check
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: After narrative GDDs, lore documents, dialogue specs, or world-building
documents are authored (team-narrative, design-system for story systems, writer
deliverables)
**Context to pass**:
- Document file path(s)
- Game pillars
- Narrative direction brief or tone guide (if exists at `design/narrative/`)
- Any existing lore that the new document references
**Prompt**:
> "Review this narrative content for consistency with the game's pillars and
> established world rules. Does the tone match the game's established voice? Are
> there contradictions with existing lore or world-building? Does the content serve
> the player experience pillar? Return APPROVE, CONCERNS [specific inconsistencies],
> or REJECT [contradictions that break world coherence]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,21 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-PHASE-GATE — Creative Readiness at Phase Transition
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: Always at `/gate-check` — spawn in parallel with TD-PHASE-GATE and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- List of all artifacts present (file paths)
- Game pillars and core fantasy
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> creative direction perspective. Are the game pillars faithfully represented in
> all design artifacts? Does the current state preserve the core fantasy? Are there
> any design decisions across GDDs or architecture that compromise the intended
> player experience? Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
+24
View File
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-PILLARS — Pillar Stress Test
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: After game pillars and anti-pillars are defined (brainstorm Phase 4,
or any time pillars are revised)
**Context to pass**:
- Full pillar set with names, definitions, and design tests
- Anti-pillars list
- Core fantasy statement
- Unique hook ("Like X, AND ALSO Y")
**Prompt**:
> "Review these game pillars. Are they falsifiable — could a real design decision
> actually fail this pillar? Do they create meaningful tension with each other? Do
> they differentiate this game from its closest comparables? Would they help resolve
> a design disagreement in practice, or are they too vague to be useful? Return
> specific feedback for each pillar and an overall verdict: APPROVE (strong), CONCERNS
> [list] (needs sharpening), or REJECT (weak — pillars do not carry weight)."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-PLAYTEST — Player Experience Validation
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: After playtest reports are generated (`/playtest-report`), or after
any session that produces player feedback
**Context to pass**:
- Playtest report file path
- Game pillars and core fantasy statement
- The specific hypothesis being tested
**Prompt**:
> "Review this playtest report against the game's design pillars and core fantasy.
> Is the player experience matching the intended fantasy? Are there systematic issues
> that represent pillar drift — mechanics that feel fine in isolation but undermine
> the intended experience? Return APPROVE (core fantasy is landing), CONCERNS [gaps
> between intended and actual experience], or REJECT [core fantasy is not present —
> redesign needed before further playtesting]."
**Verdicts**: APPROVE / CONCERNS / REJECT
+27
View File
@@ -0,0 +1,27 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# CD-SYSTEMS — Systems Decomposition Vision Check
Agent: `creative-director` | Model tier: Opus | Domain: Vision, pillars, player experience
**Trigger**: After the systems index is written by `/map-systems` — validates the
complete system set before GDD authoring begins
**Context to pass**:
- Systems index path (`design/gdd/systems-index.md`)
- Game pillars and core fantasy (from `design/gdd/game-concept.md`)
- Priority tier assignments (MVP / Vertical Slice / Alpha / Full Vision)
- Any high-risk or bottleneck systems identified in the dependency map
**Prompt**:
> "Review this systems decomposition against the game's design pillars. Does the
> full set of MVP-tier systems collectively deliver the core fantasy? Are there
> systems whose mechanics don't serve any stated pillar — indicating they may be
> scope creep? Are there pillar-critical player experiences that have no system
> assigned to deliver them? Are any systems missing that the core loop requires?
> Return APPROVE (systems serve the vision), CONCERNS [specific gaps or
> misalignments with their pillar implications], or REJECT [fundamental gaps —
> the decomposition misses critical design intent and must be revised before GDD
> authoring begins]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# LP-CODE-REVIEW — Lead Programmer Code Review
Agent: `lead-programmer` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: After a dev story is implemented (`/dev-story`, `/story-done`), or
as part of `/code-review`
**Context to pass**:
- Implementation file paths
- Story file path (for acceptance criteria)
- Relevant GDD section
- ADR that governs this system
**Prompt**:
> "Review this implementation against the story acceptance criteria and governing
> ADR. Does the code match the architecture boundary definitions? Are there
> violations of the coding standards or forbidden patterns? Is the public API
> testable and documented? Are there any correctness issues against the GDD rules?
> Return APPROVE, CONCERNS [specific issues], or REJECT [must be revised before merge]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# LP-FEASIBILITY — Lead Programmer Implementation Feasibility
Agent: `lead-programmer` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: After the master architecture document is written (`/create-architecture`
Phase 7b), or when a new architectural pattern is proposed
**Context to pass**:
- Architecture document path
- Technical requirements baseline summary
- ADR list with statuses
**Prompt**:
> "Review this architecture for implementation feasibility. Flag: (a) any decisions
> that would be difficult or impossible to implement with the stated engine and
> language, (b) any missing interface definitions that programmers would need to
> invent themselves, (c) any patterns that create avoidable technical debt or
> that contradict standard [engine] idioms. Return FEASIBLE, CONCERNS [list], or
> INFEASIBLE [blockers that make this architecture unimplementable as written]."
**Verdicts**: FEASIBLE / CONCERNS / INFEASIBLE
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# ND-CONSISTENCY — Narrative Director Consistency Check
Agent: `narrative-director` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: After writer deliverables (dialogue, lore, item descriptions) are
authored, or when a design decision has narrative implications
**Context to pass**:
- Document or content file path(s)
- Narrative bible or tone guide path (if exists)
- Relevant world-building rules
- Character or faction profiles affected
**Prompt**:
> "Review this narrative content for internal consistency and adherence to
> established world rules. Are character voices consistent with their established
> profiles? Does the lore contradict any established facts? Is the tone consistent
> with the game's narrative direction? Return APPROVE, CONCERNS [specific
> inconsistencies to fix], or REJECT [contradictions that break the narrative
> foundation]."
**Verdicts**: APPROVE / CONCERNS / REJECT
+30
View File
@@ -0,0 +1,30 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# PR-EPIC — Epic Structure Feasibility Review
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
**Trigger**: After epics are defined by `/create-epics`, before stories are
broken out — validates the epic structure is producible before `/create-stories`
is invoked
**Context to pass**:
- Epic definition file paths (all epics just created)
- Epic index path (`production/epics/index.md`)
- Milestone timeline and target dates
- Team capacity (solo / small team / size)
- Layer being epiced (Foundation / Core / Feature / etc.)
**Prompt**:
> "Review this epic structure for production feasibility before story breakdown
> begins. Are the epic boundaries scoped appropriately — could each epic realistically
> complete before a milestone deadline? Are epics correctly ordered by system
> dependency — does any epic require another epic's output before it can start?
> Are any epics underscoped (too small, should merge) or overscoped (too large,
> should split into 2-3 focused epics)? Are the Foundation-layer epics scoped to
> allow Core-layer epics to begin at the start of the next sprint after Foundation
> completes? Return REALISTIC (epic structure is producible), CONCERNS [specific
> structural adjustments before stories are written], or UNREALISTIC [epics must
> be split, merged, or reordered — story breakdown cannot begin until resolved]."
**Verdicts**: REALISTIC / CONCERNS / UNREALISTIC
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# PR-MILESTONE — Milestone Risk Assessment
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
**Trigger**: At milestone review (`/milestone-review`), at mid-sprint retrospectives,
or when a scope change is proposed that affects the milestone
**Context to pass**:
- Milestone definition and target date
- Current completion percentage
- Blocked stories count
- Sprint velocity data (if available)
**Prompt**:
> "Review this milestone status. Based on current velocity and blocked story count,
> will this milestone hit its target date? What are the top 3 production risks
> between now and the milestone? Are there scope items that should be cut to protect
> the milestone date vs. items that are non-negotiable? Return ON TRACK, AT RISK
> [specific mitigations], or OFF TRACK [date must slip or scope must cut — provide
> both options]."
**Verdicts**: ON TRACK / AT RISK / OFF TRACK
@@ -0,0 +1,22 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# PR-PHASE-GATE — Production Readiness at Phase Transition
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE and TD-PHASE-GATE
**Context to pass**:
- Target phase name
- Sprint and milestone artifacts present
- Team size and capacity
- Current blocked story count
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> production perspective. Is the scope realistic for the stated timeline and team
> size? Are dependencies properly ordered so the team can actually execute in
> sequence? Are there milestone or sprint risks that could derail the phase within
> the first two sprints? Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
+25
View File
@@ -0,0 +1,25 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# PR-SCOPE — Scope and Timeline Validation
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
**Trigger**: After scope tiers are defined (brainstorm Phase 6, quick-design, or
any workflow that produces an MVP definition and timeline estimate)
**Context to pass**:
- Full vision scope description
- MVP definition
- Timeline estimate
- Team size (solo / small team / etc.)
- Scope tiers (what ships if time runs out)
**Prompt**:
> "Review this scope estimate. Is the MVP achievable in the stated timeline for
> the stated team size? Are the scope tiers correctly ordered by risk — does each
> tier deliver a shippable product if work stops there? What is the most likely
> cut point under time pressure, and is it a graceful fallback or a broken product?
> Return REALISTIC (scope matches capacity), OPTIMISTIC [specific adjustments
> recommended], or UNREALISTIC [blockers — timeline or MVP must be revised]."
**Verdicts**: REALISTIC / OPTIMISTIC / UNREALISTIC
+24
View File
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# PR-SPRINT — Sprint Feasibility Review
Agent: `producer` | Model tier: Opus | Domain: Scope, timeline, dependencies, production risk
**Trigger**: Before finalising a sprint plan (`/sprint-plan`), and after any
mid-sprint scope change
**Context to pass**:
- Proposed sprint story list (titles, estimates, dependencies)
- Team capacity (hours available)
- Current sprint backlog debt (if any)
- Milestone constraints
**Prompt**:
> "Review this sprint plan for feasibility. Is the story load realistic for the
> available capacity? Are stories correctly ordered by dependency? Are there hidden
> dependencies between stories that could block the sprint mid-way? Are any stories
> underestimated given their technical complexity? Return REALISTIC (plan is
> achievable), CONCERNS [specific risks], or UNREALISTIC [sprint must be
> descoped — identify which stories to defer]."
**Verdicts**: REALISTIC / CONCERNS / UNREALISTIC
@@ -0,0 +1,27 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# QL-STORY-READY — QA Lead Story Readiness Check
Agent: `qa-lead` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: Before a story is accepted into a sprint — invoked by `/create-stories`,
`/story-readiness`, and `/sprint-plan` during story selection
**Context to pass**:
- Story file path
- Story type (Logic / Integration / Visual/Feel / UI / Config/Data)
- Acceptance criteria list (verbatim from the story)
- The GDD requirement (TR-ID and text) the story covers
**Prompt**:
> "Review this story's acceptance criteria for testability before it enters the
> sprint. Are all criteria specific enough that a developer would know unambiguously
> when they are done? For Logic-type stories: can every criterion be verified with
> an automated test? For Integration stories: is each criterion observable in a
> controlled test environment? Flag criteria that are too vague to implement
> against, and flag criteria that require a full game build to test (mark these
> DEFERRED, not BLOCKED). Return ADEQUATE (criteria are implementable as written),
> GAPS [specific criteria needing refinement], or INADEQUATE [criteria are too
> vague — story must be revised before sprint inclusion]."
**Verdicts**: ADEQUATE / GAPS / INADEQUATE
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# QL-TEST-COVERAGE — QA Lead Test Coverage Review
Agent: `qa-lead` | Model tier: Sonnet (Tier 2 lead — invoked when a domain specialist's feasibility sign-off is needed)
**Trigger**: After implementation stories are complete, before marking an epic
done, or at `/gate-check` Production → Polish
**Context to pass**:
- List of implemented stories with story types (Logic / Integration / Visual / UI / Config)
- Test file paths in `tests/`
- GDD acceptance criteria for the system
**Prompt**:
> "Review the test coverage for these implementation stories. Are all Logic stories
> covered by passing unit tests? Are Integration stories covered by integration
> tests or documented playtests? Are the GDD acceptance criteria each mapped to at
> least one test? Are there untested edge cases from the GDD Edge Cases section?
> Return ADEQUATE (coverage meets standards), GAPS [specific missing tests], or
> INADEQUATE [critical logic is untested — do not advance]."
**Verdicts**: ADEQUATE / GAPS / INADEQUATE
+23
View File
@@ -0,0 +1,23 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-ADR — Architecture Decision Review
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After an individual ADR is authored (`/architecture-decision`), before
it is marked Accepted
**Context to pass**:
- ADR file path
- Engine version and knowledge gap risk level for the domain
- Related ADRs (if any)
**Prompt**:
> "Review this Architecture Decision Record. Does it have a clear problem statement
> and rationale? Are the rejected alternatives genuinely considered? Does the
> Consequences section acknowledge the trade-offs honestly? Is the engine version
> stamped? Are post-cutoff API risks flagged? Does it link to the GDD requirements
> it covers? Return APPROVE, CONCERNS [specific gaps], or REJECT [the decision is
> underspecified or makes unsound technical assumptions]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-ARCHITECTURE — Architecture Sign-Off
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After the master architecture document is drafted (`/create-architecture`
Phase 7), and after any major architecture revision
**Context to pass**:
- Architecture document path (`docs/architecture/architecture.md`)
- Technical requirements baseline (TR-IDs and count)
- ADR list with statuses
- Engine knowledge gap inventory
**Prompt**:
> "Review this master architecture document for technical soundness. Check: (1) Is
> every technical requirement from the baseline covered by an architectural decision?
> (2) Are all HIGH risk engine domains explicitly addressed or flagged as open
> questions? (3) Are the API boundaries clean, minimal, and implementable? (4) Are
> Foundation layer ADR gaps resolved before implementation begins? Return APPROVE,
> CONCERNS [list], or REJECT [blockers that must be resolved before coding starts]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,25 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-CHANGE-IMPACT — Design Change Impact Review
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After the Design Change Impact Report is produced
(`/propagate-design-change` Phase 6), before the resolution workflow begins
**Context to pass**:
- The full Design Change Impact Report from Phase 6 — change summary, every
affected ADR with its Still Valid / Needs Review / Likely Superseded
classification, and the recommended actions
**Prompt**:
> "Review this design-change impact assessment before any ADR is revised. Are the
> impact classifications correct — in particular, is any ADR under-classified
> (marked Still Valid when the change actually contradicts its assumptions)? Are
> the recommended actions architecturally sound? Were any cascading effects on
> other ADRs or systems missed — decisions that depend on the ones already
> flagged? Return APPROVE, CONCERNS [the specific ADRs or recommendations to
> revisit], or REJECT [the assessment must be re-analyzed before resolution
> begins — say what was missed]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,22 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-ENGINE-RISK — Engine Version Risk Review
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: When making architecture decisions that touch post-cutoff engine APIs,
or before finalizing any engine-specific implementation approach
**Context to pass**:
- The specific API or feature being used
- Engine version and LLM knowledge cutoff (from `docs/engine-reference/[engine]/VERSION.md`)
- Relevant excerpt from breaking-changes or deprecated-apis docs
**Prompt**:
> "Review this engine API usage against the version reference. Is this API present
> in [engine version]? Has its signature, behaviour, or namespace changed since the
> LLM knowledge cutoff? Are there known deprecations or post-cutoff alternatives?
> Return APPROVE (safe to use as described), CONCERNS [verify before implementing],
> or REJECT [API has changed — provide corrected approach]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,24 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-FEASIBILITY — Technical Feasibility Assessment
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After biggest technical risks are identified during scope/feasibility
(brainstorm Phase 6, quick-design, or any early-stage concept with technical unknowns)
**Context to pass**:
- Concept's core loop description
- Platform target
- Engine choice (or "undecided")
- List of identified technical risks
**Prompt**:
> "Review these technical risks for a [genre] game targeting [platform] using
> [engine or 'undecided engine']. Flag any HIGH risk items that could invalidate
> the concept as described, any risks that are engine-specific and should influence
> the engine choice, and any risks that are commonly underestimated by solo
> developers. Return VIABLE (risks are manageable), CONCERNS [list with mitigation
> suggestions], or HIGH RISK [blockers that require concept or scope revision]."
**Verdicts**: VIABLE / CONCERNS / HIGH RISK
@@ -0,0 +1,26 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-MANIFEST — Control Manifest Review
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After control-manifest rules are extracted and previewed
(`/create-control-manifest` Phase 4), before the manifest file is written
**Context to pass**:
- The Control Manifest Preview from Phase 4 (rule counts per layer, full extracted rule list)
- The list of ADRs covered
- Engine version
- Any rules sourced from `technical-preferences.md` or engine reference docs
**Prompt**:
> "Review this control manifest before it is written. Are all mandatory ADR
> patterns captured and accurately stated? Are the forbidden approaches complete
> and correctly attributed to their source ADR? Were any rules added that lack a
> source ADR or preference document — that is, invented rather than extracted?
> Are the performance guardrails consistent with the constraints the ADRs
> actually set? Return APPROVE, CONCERNS [list the specific rules to revise], or
> REJECT [rules that are wrong or unsourced and must be fixed before the manifest
> is written]."
**Verdicts**: APPROVE / CONCERNS / REJECT
@@ -0,0 +1,22 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-PHASE-GATE — Technical Readiness at Phase Transition
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: Always at `/gate-check` — spawn in parallel with CD-PHASE-GATE and PR-PHASE-GATE
**Context to pass**:
- Target phase name
- Architecture document path (if exists)
- Engine reference path
- ADR list
**Prompt**:
> "Review the current project state for [target phase] gate readiness from a
> technical direction perspective. Is the architecture sound for this phase? Are
> all high-risk engine domains addressed? Are performance budgets realistic and
> documented? Are Foundation-layer decisions complete enough to begin implementation?
> Return READY, CONCERNS [list], or NOT READY [blockers]."
**Verdicts**: READY / CONCERNS / NOT READY
@@ -0,0 +1,31 @@
> Gate definition. The spawning skill passes this file's path to the director agent; the AGENT reads it — the parent session should not.
# TD-SYSTEM-BOUNDARY — System Boundary Architecture Review
Agent: `technical-director` | Model tier: Opus | Domain: Architecture, engine risk, performance
**Trigger**: After `/map-systems` Phase 3 dependency mapping is agreed but before
GDD authoring begins — validates that the system structure is architecturally
sound before teams invest in writing GDDs against it
**Context to pass**:
- Systems index path (or the dependency map summary if index not yet written)
- Layer assignments (Foundation / Core / Feature / Presentation / Polish)
- The full dependency graph (what each system depends on)
- Any bottleneck systems flagged (many dependents)
- Any circular dependencies found and their proposed resolutions
**Prompt**:
> "Review this systems decomposition from an architectural perspective before GDD
> authoring begins. Are the system boundaries clean — does each system own a
> distinct concern with minimal overlap? Are there God Object risks (systems doing
> too much)? Does the dependency ordering create implementation-sequencing problems?
> Are there implicit shared-state problems in the proposed boundaries that will
> cause tight coupling when implemented? Are any Foundation-layer systems actually
> dependent on Feature-layer systems (inverted dependency)? Return APPROVE
> (boundaries are architecturally sound — proceed to GDD authoring), CONCERNS
> [specific boundary issues to address in the GDDs themselves], or REJECT
> [fundamental boundary problems — the system structure will cause architectural
> issues and must be restructured before any GDD is written]."
**Verdicts**: APPROVE / CONCERNS / REJECT
+30 -5
View File
@@ -3,16 +3,41 @@
```text
/
├── CLAUDE.md # Master configuration
├── project.yaml # Machine-readable project config — engine, modes, stage (source of truth)
├── .claude/ # Agent definitions, skills, hooks, rules, docs
├── src/ # Game source code (core, gameplay, ai, networking, ui, tools)
├── <code root>/ # Game source code — THE PATH IS ENGINE-SPECIFIC, see below
├── assets/ # Game assets (art, audio, vfx, shaders, data)
├── design/ # Game design documents (gdd, narrative, levels, balance)
├── docs/ # Technical documentation (architecture, api, postmortems)
│ └── engine-reference/ # Curated engine API snapshots (version-pinned)
├── tests/ # Test suites (unit, integration, performance, playtest)
├── tests/ # Game test suites (unit, integration, performance, playtest)
├── tools/ # Build and pipeline tools (ci, build, asset-pipeline)
├── prototypes/ # Throwaway prototypes (isolated from src/)
└── production/ # Production management (sprints, milestones, releases)
├── session-state/ # Ephemeral session state (active.md — gitignored)
└── session-logs/ # Session audit trail (gitignored)
├── production/ # Production management (sprints, milestones, releases)
│ ├── session-state/ # Ephemeral session state (active.md — gitignored)
│ └── session-logs/ # Session audit trail (gitignored)
└── CCGS Skill Testing Framework/ # QA for the skills/agents themselves — /skill-test, /skill-improve
```
## The code root is engine-specific
**Two of the three supported engines will not build a project whose code sits in
`src/`.** This is not a style preference — it is a hard constraint of the engine's
own toolchain:
| `engine.name` | Code root | Why it cannot be `src/` |
|---|---|---|
| **Godot** | `src/` | No constraint — Godot loads from `res://` anywhere under the project root. |
| **Unity** | `Assets/` | Unity compiles **only** `Assets/` and `Packages/`. Code outside them is invisible to the compiler. |
| **Unreal** | `Source/<Module>/` | UnrealBuildTool discovers modules under `Source/`; content lives in `Content/`. A module elsewhere is not built. |
**Resolve the code root from `engine.name` before writing any source file.** Where
a skill, rule or template says `src/`, read it as *"the code root"* and substitute
the row above. `src/` is the table's Godot row, not a universal path.
> **Known residual — do not read `src/` as settled.** Roughly 30 files under
> `.claude/` still name `src/` literally, because they were written when Godot was
> the only engine walked end to end. They are correct for Godot and wrong for the
> other two. This section is the authority; those files are the default. The
> breakage is real, not theoretical — a Unity tree laid out this way does not
> compile, and an Unreal one produces a module no `.uproject` can consume.
File diff suppressed because it is too large Load Diff
+59
View File
@@ -0,0 +1,59 @@
# Error Recovery Protocol
Shared procedure for any skill that spawns agents via the `Agent` tool. Referenced from the
`## Error Recovery Protocol` section of each orchestration/review skill. Those
skills keep the two load-bearing imperatives (surface immediately, produce a
partial report) inline, and keep their own **Common blockers** list inline —
those are skill-specific. This file holds the full four-step procedure.
## Trigger 0 — verify the artifact before reading the response
**Before applying anything below, and before treating a phase as complete: if
the return contract named a path, check that the path exists.** A named
artifact that is not on disk is a FAILED PHASE, no matter how the agent's
response reads.
This trigger exists because the three below are not sufficient. They fire on
BLOCKED, on an error, and on "cannot complete" — and an agent can fail in a way
that is none of those. Observed live: a `devops-engineer` spawned
as half of a parallel phase ran **26 tool calls and ~31,600 tokens**, then
returned a single fluent preamble — "I'll verify the build infrastructure…" —
with no path, no summary, no BLOCKED item, and **no file written**. Nothing in
steps 1–4 matches that shape. An orchestrator reading the transcript sees a
plausible response and advances, and half a parallel phase disappears with no
signal at all.
The work was not lost — resumed with an explicit "you did not honour the return
contract" message, the same agent completed in **one tool call**, because its
investigation was still in context. Only the write-and-return step had failed.
So the recovery is cheap; the detection is the hard part, and the detection
cannot come from reading the response.
**A fluent response is not evidence that a phase ran.** The artifact is —
observe the artifact, not the transcript. The rule applies to sub-agents
exactly as it does to skills.
When the path is missing:
1. Do **not** advance the pipeline or summarise the phase as done.
2. Resume the agent, naming the unmet contract explicitly and telling it that
"I could not write" is a valid answer but silence is not. Prefer resuming
over re-spawning — the context is usually still there, and a re-spawn pays
for the whole investigation again.
3. If the second attempt also produces nothing, treat it as BLOCKED and apply
steps 1–4 below.
---
If any spawned agent returns BLOCKED, errors, or cannot complete:
1. **Surface immediately** — report "[AgentName]: BLOCKED — [reason]" to the user
before continuing to dependent phases.
2. **Assess dependencies** — check whether the blocked agent's output is required
by subsequent phases. If yes, do not proceed past that dependency point without
user input.
3. **Offer options** via `AskUserQuestion`:
- Skip this agent and note the gap in the final report
- Retry with narrower scope
- Stop here and resolve the blocker first
4. **Always produce a partial report** — output whatever was completed. Never
discard work because one agent blocked.
+46 -2
View File
@@ -12,10 +12,54 @@ Hooks are configured in `.claude/settings.json` and fire automatically:
| `pre-compact.sh` | PreCompact | Context compression | Dumps session state (active.md, modified files, WIP design docs) into conversation before compaction so it survives summarization |
| `post-compact.sh` | PostCompact | After compaction | Reminds Claude to restore session state from `active.md` checkpoint |
| `notify.sh` | Notification | Notification event | Shows Windows toast notification via PowerShell |
| `session-stop.sh` | Stop | Session ends | Summarizes accomplishments and updates session log |
| `log-agent.sh` | SubagentStart | Agent spawned | Audit trail start — logs subagent invocation with timestamp |
| `session-stop.sh` | Stop | **Every response ends** — not once per session | Summarizes accomplishments, updates session log, and writes the subagent spawn tally to `production/session-logs/session-cost.md`. Archives `active.md` only when its content hash changed; without that guard a long session appended the whole file on every turn. |
| `log-agent.sh` | SubagentStart | Agent spawned | Audit trail start — logs subagent invocation with timestamp and session id |
| `log-agent-stop.sh` | SubagentStop | Agent stops | Audit trail stop — completes subagent record |
| `validate-skill-change.sh` | PostToolUse (Write/Edit) | Skill file changes | Advises running `/skill-test` after any `.claude/skills/` file is written or edited |
### Subagent cost visibility
The three hooks above form one chain. `log-agent.sh` writes a record per spawn
to `production/session-logs/agent-audit.log` in a fixed three-field shape:
```
YYYYMMDD_HHMMSS | <session_id> | Agent invoked: <agent_type>
```
`session-stop.sh` greps the literal string `" | $SESSION_ID | Agent invoked: "`
to tally the current session, then writes a count plus a per-agent breakdown to
`production/session-logs/session-cost.md` and echoes a one-line total.
Three constraints that must not be "tidied" later:
- **The field order is load-bearing.** Nothing else parses this log, so a
reformat looks free — but it silently zeroes the spawn count rather than
erroring.
- **`session-stop.sh` reads stdin last, on purpose.** Everything above the
tally block (notably archiving `active.md`) runs first, so a stdin read that
ever blocked would cost only the count, not the state archive.
- **No session id means no number.** The hook prints nothing rather than a
total spanning every session in the log. Silence here is correct; a
plausible-but-wrong cost figure is worse than none.
`agent_type` — not `agent_name` — is the field carrying the agent name. See
`hooks-reference/hook-input-schemas.md`.
## Events considered and deliberately not added
Claude Code offers many more hook events than the eleven above. These were
evaluated and rejected. Recorded so a future review does not re-propose them
from the event list alone.
| Event | Why not |
| ---- | ---- |
| `UserPromptSubmit` | Would re-inject session state on **every prompt**. `.claude/docs/config-resolution.md` already rejects the weaker version of this — injecting config at session start — because it "would cost tokens on every session whether or not any skill needs config, and it would go stale mid-session as `/settings` writes land". Firing per prompt is the same argument, multiplied. |
| `ConfigChange` | Fires only for Claude Code's own settings files — user, project, local, policy and skills. It does **not** fire for `project.yaml`, so a hook watching CCGS config here would never run. `FileChanged` is the event that watches arbitrary files. |
| `FileChanged` on `project.yaml` | Config is resolved per skill invocation, in the skill body, precisely so each run reads fresh values. The only staleness left is text already injected into an earlier invocation, which is the accepted trade in `config-resolution.md`. A warning hook would second-guess a settled decision. |
| `PreToolUse` `updatedInput` | Could rewrite a non-conventional commit message instead of blocking it. Silently editing the user's input contradicts the collaboration protocol: this project blocks and explains rather than acting unasked. |
| `PostToolUseFailure` | Would add another log with no reader. This repo has already been bitten by that — `log-agent.sh` wrote per-spawn records nothing consumed until `session-stop.sh` was given the job. |
| `SessionEnd` | `session-stop.sh` stays on `Stop`. `SessionEnd` fires on termination, which a crash may never reach, and the content-hash guard already makes the per-response firing cheap. |
| `InstructionsLoaded` | Useful for debugging which CLAUDE.md and rules files actually loaded, but it is a diagnostic, not a project requirement. Wire it in your own `.claude/settings.local.json` when you need it rather than paying for it on every load. |
Hook reference documentation: `.claude/docs/hooks-reference/`
Hook input schema documentation: `.claude/docs/hooks-reference/hook-input-schemas.md`
@@ -88,7 +88,9 @@ Fired after a tool completes. **Cannot block** (exit code ignored for blocking).
## SubagentStart
Fired when a subagent is spawned via the Task tool.
Fired when a subagent is spawned via the `Agent` tool (named `Task` before
Claude Code 2.1.63; `Task` still works as an alias in permission rules and
`tools:` frontmatter, but the hook payload's `tool_name` is now `Agent`).
```json
{
+55
View File
@@ -0,0 +1,55 @@
# Model Tier Assignment
> ### DECLARED, NOT CURRENTLY APPLIED — skills only
>
> **Claude Code reads `model:` from a skill's frontmatter and then serves the
> skill from the session's model anyway.** This has been measured directly
> against session transcripts on several Claude Code versions, and held every
> time. To re-test it on a newer version, run a skill that declares a tier
> different from the session model and check which model the transcript
> attributes the skill's turns to.
>
> So the skill tiers below are **intent, not behaviour**. Setting one changes
> nothing today. They are kept because they are correct descriptions of what each
> skill needs, and because they cost nothing to carry if Claude Code honours them
> later — but do not budget on them, and never tell a user a tier is saving them
> money.
>
> **This does NOT apply to agents.** `model:` in `.claude/agents/*.md` is a
> different mechanism, spawned as a separate session rather than executed inline.
> It has not been measured here, so treat the agent section below as unverified
> in either direction rather than assuming it behaves the same way.
Skills and agents are assigned tiers by task complexity:
| Tier | Model | When to use |
|------|-------|-------------|
| **Haiku** | `claude-haiku-4-5-20251001` | Read-only status checks, formatting, simple lookups — no creative judgment needed |
| **Sonnet** | `claude-sonnet-5` | Implementation, design authoring, analysis of individual systems — default for most work |
| **Opus** | `claude-opus-5` | Multi-document synthesis, high-stakes phase gate verdicts, cross-system holistic review |
Skills with `model: haiku` (5): `/help`, `/onboard`, `/project-stage-detect`,
`/scope-check`, `/sprint-status`
> `/patch-notes` and `/changelog` are `sonnet`, not `haiku`: both produce
> **player-facing** copy and need judgement the cheapest tier is defined as not
> doing. Full reasoning in each skill's own header.
>
> `/settings` was moved off `haiku` for the same reason. It does not only read
> and format — it resolves every leaf with provenance and then compares the
> configured rigor against the project's observable working practice. That is
> synthesis, which is what the Haiku row is defined as excluding.
Skills with `model: opus` (3): `/architecture-review`, `/gate-check`, `/review-all-gdds`
All other skills are Sonnet. When creating a new skill, assign Haiku if it only
reads and formats; assign Opus if it must synthesize 5+ documents with
high-stakes output; otherwise write `model: sonnet` explicitly. Every skill in
this repo declares a tier, and the lists above are kept in step with what the
`SKILL.md` files declare. That is a check on two descriptions agreeing; it
proves nothing about which model actually runs.
**Agent model tiers.** Orchestrator-spawned agents (`team-*`, `/review-all-gdds`)
use `model: inherit` so a fixed smaller model can't overflow when the parent runs
a large-context tier. Directors stay `opus`, `community-manager`/`devops-engineer`
stay `haiku`, and non-orchestrator agents stay pinned at `sonnet` as a floor.
+8 -12
View File
@@ -189,12 +189,6 @@ Templates are in `.claude/docs/templates/`:
- `difficulty-curve.md` -- for difficulty axes, onboarding ramp, and cross-system interactions
- `test-evidence.md` -- template for recording manual test evidence (screenshots, walkthrough notes)
Also in `.claude/docs/templates/collaborative-protocols/` (used by agents, not typically edited directly):
- `design-agent-protocol.md` -- question-options-draft-approval cycle for design agents
- `implementation-agent-protocol.md` -- story pickup through /story-done cycle for programming agents
- `leadership-agent-protocol.md` -- cross-department delegation and escalation for director-tier agents
### 5. Follow the Coordination Rules
1. Work flows down the hierarchy: Directors -> Leads -> Specialists
@@ -218,8 +212,8 @@ If you already know what you need, jump directly to the relevant path:
- Produces a game concept document and recommends an engine
2. **Set up the engine** — Run `/setup-engine` (uses the brainstorm recommendation)
- Configures CLAUDE.md, detects knowledge gaps, populates reference docs
- Creates `.claude/docs/technical-preferences.md` with naming conventions,
performance budgets, and engine-specific defaults
- Writes engine, naming conventions, and performance budgets to `project.yaml`
(the source of truth), mirrored to `.claude/docs/technical-preferences.md`
- If the engine version is newer than the LLM's training data, it fetches
current docs from the web so agents suggest correct APIs
3. **Validate the concept** — Run `/design-review design/gdd/game-concept.md`
@@ -271,15 +265,16 @@ If you have design docs, prototypes, or code already:
```
CLAUDE.md -- Master config (read this first, ~60 lines)
project.yaml -- Machine-readable project config (engine, modes, stage) — source of truth
.claude/
settings.json -- Claude Code hooks and project settings
agents/ -- 49 agent definitions (YAML frontmatter)
skills/ -- 73 slash command definitions (YAML frontmatter)
hooks/ -- 12 hook scripts (.sh) wired by settings.json
skills/ -- 74 slash command definitions (YAML frontmatter)
hooks/ -- 12 event hooks (.sh, wired by settings.json) + yaml-helper.sh
rules/ -- 11 path-specific rule files
docs/
quick-start.md -- This file
technical-preferences.md -- Project-specific standards (populated by /setup-engine)
technical-preferences.md -- Legacy fallback for project.yaml config (mirror; see project.yaml at repo root)
coding-standards.md -- Coding and design doc standards
coordination-rules.md -- Agent coordination rules
context-management.md -- Context budgets and compaction instructions
@@ -287,5 +282,6 @@ CLAUDE.md -- Master config (read this first, ~60 lines)
workflow-catalog.yaml -- 7-phase pipeline definition (read by /help)
setup-requirements.md -- System prerequisites (Git Bash, jq, Python)
settings-local-template.md -- Personal settings.local.json guide
templates/ -- 41 document templates
CLAUDE-local-template.md -- Personal CLAUDE.local.md guide (gitignored overrides)
templates/ -- 38 document templates (+ per-section guidance)
```
-6
View File
@@ -1,6 +0,0 @@
# Review Workflow
1. Code changes require review by the relevant department lead agent
2. Design changes require sign-off from `game-designer` and `creative-director`
3. Architecture changes require sign-off from `technical-director`
4. Cross-domain changes require sign-off from `producer`
+37 -1
View File
@@ -1,6 +1,33 @@
# Path-Specific Rules
Rules in `.claude/rules/` are automatically enforced when editing files in matching paths:
Rules in `.claude/rules/` carry `paths:` frontmatter. Claude Code loads a
path-scoped rule **when it READS a file matching one of those globs** — not on
every tool use, and not when it creates one.
Three consequences, and none of them are optional reading:
1. **Reading, not editing.** A rule scoped to `src/gameplay/**` reaches the model
when a file there is opened. An agent that writes a brand-new file in that
directory without opening an existing one never sees it. Most work in this
framework creates files rather than reads them, so this is the common case,
not the corner case.
2. **Context, not enforcement.** A loaded rule is guidance the model weighs, the
same as `CLAUDE.md`. Anything that must hold regardless of what the model
decides belongs in a hook — `.claude/hooks/` already enforces JSON validity
and commit shape that way.
3. **A rule with no `paths:` loads every session**, at the same priority as
`.claude/CLAUDE.md`. That is the lever for a rule that must always apply; it
costs context in every session, so it is a deliberate trade, not a default.
Where a rule duplicates guidance an agent definition already carries, the two
must agree. Contradicting instructions are resolved arbitrarily, so a rule and
an agent stating different versions of the same standard is worse than either
alone.
To see which rules actually load, and why, wire the `InstructionsLoaded` hook —
`.claude/hooks/log-instructions.sh` records every instruction file and its load
reason (`session_start`, `path_glob_match`, `nested_traversal`, `compact`) to
`production/session-logs/instructions-loaded.log`.
| Rule File | Path Pattern | Enforces |
| ---- | ---- | ---- |
@@ -15,3 +42,12 @@ Rules in `.claude/rules/` are automatically enforced when editing files in match
| `test-standards.md` | `tests/**` | Test naming, coverage requirements, fixture patterns |
| `prototype-code.md` | `prototypes/**` | Relaxed standards, README required, hypothesis documented |
| `shader-code.md` | `assets/shaders/**` | Naming conventions, performance targets, cross-platform rules |
| `agent-memory.md` | `.claude/agent-memory/**` | The one place an agent may write unasked — and why a temporary absence must never be recorded as a durable fact |
| `skill-authoring.md` | `.claude/skills/**`, `.claude/agents/**` | A check that cannot report it did not run is not a check — verdict vocabularies, fail-closed defaults, self-announcing skips, sourcing, derived gate coverage |
> **`skill-authoring.md` is the odd one out and deliberately so.** Every other
> rule here scopes a *game* directory; that one scopes the **framework's own**
> authoring paths. It exists because one failure shape kept recurring across
> unrelated subsystems — a step that could not run producing output
> indistinguishable from a step that ran and found nothing. The same mistake in
> nine places is a missing design rule, not nine mistakes.
+178
View File
@@ -0,0 +1,178 @@
# Run and Observe
Shared procedure for any skill that closes a story which changes something a
player can see. Referenced from the point of use in `/dev-story` (Phase 6) and
`/story-done` (Phase 3). Those skills keep the one load-bearing imperative
inline — **a parse check is not a run, and a story nobody looked at does not
close** — and cite this file for how to look.
`.claude/docs/coding-standards.md` is the authority for *what* evidence a story
needs. This file is the procedure for *producing* the visual half of it.
## The rule
Every story that changes something player-observable is **launched and observed
before it closes**, and the observation is a **retained screenshot** in
`production/qa/evidence/`. Compiling proves the code loads. Tests prove the
logic. Neither proves the text fits in the box.
The agent can see images: Claude Code's `Read` tool renders a PNG. The whole
problem is getting a picture out of the engine unattended, and every supported
engine has a native way.
## The procedure
1. **Launch windowed** at a fixed resolution — `1280x720` unless the project
says otherwise — using `commands.run` from `project.yaml`. Never the
headless / batch / null-RHI flag: those exist to *skip* rendering.
2. **Launch straight into the scene or map the story touched.** A feature that
is only reachable through the main menu and three clicks is a feature the
run will not reach. Stories should be written so their surface is reachable
from a launch argument (a scene path, a map URL, a `--scene` flag).
3. **Wait, capture, quit.** Let the engine render real frames — 60 is a safe
floor — capture one, and exit. Each engine's mechanism is below.
4. **Look.** `Read` the PNG. Compare what is on screen to the acceptance
criteria. Clipped text, an overflowing panel, a missing element, the wrong
colour — these are defects, and this is the only step that finds them.
5. **Retain.** Copy the image to
`production/qa/evidence/[story-slug]/[NN]-[what-it-shows].png` and reference
it from the evidence doc. A screenshot that was taken and discarded is an
assertion, not evidence.
6. **Report** one `Run result:` line in the implementation summary — vocabulary
below.
## Per engine
| `engine.name` | Launch | Capture | Output lands in | Never use | Scaffold needed |
|---|---|---|---|---|---|
| Godot 4 | `godot --path . --windowed --resolution 1280x720 <scene>.tscn` | `--write-movie <path>.png --quit-after <N>` | beside the given path, `<name>00000000.png` … | `--headless` | **none** |
| Unity 6 | built player `.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0 --scene <Name>` | `ScreenCapture.CaptureScreenshot(<abs path>)` from a bootstrap script | the absolute path you pass | `-batchmode`, `-nographics` | one MonoBehaviour |
| Unreal 5 | `MSYS_NO_PATHCONV=1 UnrealEditor.exe <Game>.uproject <MapURL> -game -windowed -ResX=1280 -ResY=720` | `HighResShot filename=<path>` console command | `Saved/Screenshots/Windows/` | `-nullrhi`, `-unattended` alone | one actor or `-ExecCmds` |
### Godot 4 — zero scaffold
```
godot --path . --windowed --resolution 1280x720 --write-movie shots/shop.png --quit-after 60 res://scenes/shop.tscn
```
`--write-movie` is Movie Maker mode: with a `.png` target it writes a frame
sequence and `--quit-after` sets the frame count. Filenames carry **8**
zero-padded digits — `shop00000000.png` through `shop00000059.png` — so take the
last. `--fixed-fps` is applied automatically. The scene path is positional; any
`.tscn` can be launched directly, which is how step 2 is satisfied.
Capture-on-trigger alternative, for a state a scene launch cannot reach: an
autoload that on the wanted condition does
`await RenderingServer.frame_post_draw`, then
`get_viewport().get_texture().get_image().save_png(path)`, then
`get_tree().quit()`.
### Unity 6 — one MonoBehaviour
`-batchmode` displays nothing, so the run is either the **built player** or the
editor in play mode. The player is the robust path:
```
Builds/Win64/Game.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0 --scene Shop --screenshot C:/abs/path/shop.png --after 60
```
`-screen-*` are Unity's own player arguments. `--scene`, `--screenshot` and
`--after` are **yours**: a `ScreenshotOnArg` MonoBehaviour in the bootstrap
scene parses `System.Environment.GetCommandLineArgs()`, loads `--scene`, waits
`--after` frames, calls `ScreenCapture.CaptureScreenshot(path)`, waits one more
frame, then `Application.Quit()`. Pass an **absolute** path — the relative base
differs between editor and player. `CaptureScreenshot` captures the last frame
*presented*, so it must run after at least one rendered frame.
`/test-setup` scaffolds this script under the code root. Building the player
first costs 1–3 minutes on a small project; that is the price of looking at
the thing you ship rather than the editor.
### Unreal 5 — one actor, or `-ExecCmds`
```
MSYS_NO_PATHCONV=1 UnrealEditor.exe Game.uproject /Game/Maps/Shop -game -windowed -ResX=1280 -ResY=720
```
`-game` runs standalone without the editor UI. The map is a **positional URL
immediately after the `.uproject`** — not a console command. **The
`MSYS_NO_PATHCONV=1` prefix is required on Windows:** Claude Code runs commands
in Git Bash, which rewrites any argument beginning with `/` as a Windows path, so
`/Game/Maps/Shop` reaches the engine as `C:/Program Files/Git/Game/Maps/Shop`
and the game stops on a "map not found" dialog nobody can see. Alternatively
pass the map through `-ExecCmds="open /Game/Maps/Shop"`, which is not converted. Capture is the
`HighResShot` console command, fired either from a dev actor (`Execute Console
Command` on BeginPlay after a short delay, then `quit`) or from the launch line:
```
-ExecCmds="HighResShot filename=C:/abs/path/shop.png,Quit"
```
`-ExecCmds` is comma-separated. Output defaults to `Saved/Screenshots/Windows/`.
**Do not `Quit` on the same frame as the request** — the file flushes late and
an immediate quit can leave nothing on disk; a one-second delay before `quit`
is enough. The Blueprint node `Take High Res Screenshot` is editor-only and
does not work in a `-game` launch.
### Any engine — OS capture fallback
On Windows, PowerShell with `System.Drawing` can `CopyFromScreen` into a bitmap
and save it. It needs a visible desktop and the game window on top, and it
captures whatever is there — it cannot be told "the shop panel". Use it when the
engine-native path is unavailable, and say so in the run result. Linux CI with
no display needs `xvfb-run` in front of the launch; `--headless` is not a
substitute.
## The `Run result:` line
Exactly one of three shapes, in the implementation summary:
- **`Run result: OBSERVED — <what was on screen, one line>`** with the retained
path. *"Shop panel renders, all 6 slots inside the frame, prices legible at
720p — `production/qa/evidence/shop-panel/01-shop-open.png`."*
- **`Run result: NOT VERIFIED — <reason>`**. Engine binary not found,
`commands.run` unset, launch crashed, screenshot empty. This is a **blocker**
at the default gate level for Visual/Feel and UI stories, not a note — a
story nobody looked at does not close. Under an explicit
`testing.strict.visual`/`.ui: false` it is recorded and the story may close
with the gap in `## Completion Notes`.
- **`Run result: N/A — <reason>`**, only for a story with genuinely nothing
observable — a pure data migration, a save-format change with no surface.
Say why. "It's a Logic story" is not a reason: a damage formula has a number
on screen somewhere.
The run is **not waived at `qa.level: minimal`**. Tests are waived there; the
look is not. It is the cheapest verification in the pipeline and the one
whose absence produces a well-tested game that looks wrong.
## What a still can and cannot show
**Can:** layout, clipping, overflow, presence, alignment, colour, legibility,
that the right screen appeared at all. This is where shipped visual defects
actually live.
**Cannot:** timing, responsiveness, weight, animation curves, audio sync — the
"feel" half of Visual/Feel. Godot's `--write-movie` gives a frame sequence; the
other engines need OS video capture. Feel stays a human check in `/team-qa`.
Say which half the screenshot covered.
## Reaching the state
A screenshot of the title screen verifies nothing about depth 2. Either launch
the scene/map directly (Godot scene arg, Unreal map URL, Unity `--scene`) or
give the bootstrap a debug argument that sets state (`--gold=500 --depth=2`).
Write stories so their surface is reachable one of those ways; a story that is
not is a story that will be marked `NOT VERIFIED` every time.
## Finding the engine
None of the three engines installs onto `PATH` on Windows. `engine.path` in
`project.yaml` is where the editor lives; resolve it before concluding "no
engine on this machine". Absence of a path is not absence of an engine.
---
*Commands and APIs above verified against the official Godot 4.7, Unity 6.3 LTS
and Unreal 5.8 references on 2026-09-14. `docs/engine-reference/<engine>/` is
the project's pinned authority; check it before trusting a version-qualified
claim here.*
+120
View File
@@ -0,0 +1,120 @@
# Settings Guidance — which value to recommend, and when
The **advisory** layer for project settings. This doc answers two questions no
other doc does:
1. **Which value should a skill recommend** for a given project or user?
2. **When should a skill proactively suggest changing** a setting already set?
## Boundary with its siblings — do not duplicate their content here
| Doc | Answers | Nature |
|---|---|---|
| `effects-map.md` | What each setting *does* | Descriptive |
| `config-resolution.md` | How a setting *resolves* (precedence chain) | Mechanical |
| **`settings-guidance.md`** (this file) | Which value to *recommend*, and *when* | Prescriptive |
Skills reference this doc **on demand**, only at a "recommend a setting" moment.
It is deliberately **not** a CLAUDE.md import — advisory content must not ride in
per-turn context (the same reason `context-management.md` was demoted).
---
## 1. The knob that matters most: `modes.rigor`
Almost every "what settings should I use?" question reduces to one choice:
`modes.rigor` (`minimal` | `standard` | `full`, default `minimal`). It fronts six
sub-knobs — `modes.workflow`, `docs.density`, `qa.level`, `modes.story_granularity`,
`modes.review_mode`, `team.size`. Recommend **rigor**, not the six; let the
expansion do the rest. Full expansion table lives in `effects-map.md § modes.rigor`
— do not restate it here.
`modes.automation` (`collaborative` | `guided` | `autonomous`) is a **separate
axis** — how often skills stop to confirm — and is *not* fronted by rigor. Pick it
by working style, not by game type (see § 5).
---
## 2. Archetype → rigor presets
Match the project to an archetype; recommend the paired rigor. These are starting
points, not verdicts — the user can always override.
| Archetype | Rigor | Why | Common override |
|---|---|---|---|
| Weekend jam / prototype / throwaway | `minimal` | Shipping beats recording; design lives in the maker's head | Bump one deep system: `workflow_overrides.system_overrides: {combat: full}` |
| Small solo / hobby game (arcade, puzzle, short narrative) | `minimal` → `standard` if it grows | Start light; add rigor when scope proves real | — |
| Focused commercial indie (platformer, roguelike, tactics, deckbuilder) | `standard` *(default)* | One well-understood loop; enough design to build correctly | "Comprehensive but compact": `rigor: full` + `docs.density: terse` |
| Systems-heavy / long-haul (open-world RPG, colony sim, immersive sim, 4X, survival) | `full` | Many interacting systems; a design mistake costs weeks | Solo dev: keep `full` on disk, set `review_mode: solo` locally |
| Live-service / competitive multiplayer | `full` + domain emphasis | Full pipeline *plus* netcode/security/live-ops | Raise `qa.level` / `testing.strict.*` for the online-critical types |
**The model:** the table picks a baseline; overrides handle the diagonal. Most real
projects are one baseline plus one or two deliberate exceptions.
---
## 3. Seeding rigor from a described concept
When the user has described their game (e.g. `/start` Phase 2 free text), map it to
an archetype and **pre-select** the recommendation rather than asking cold. Signals:
| Concept mentions… | Lean toward |
|---|---|
| open-world, RPG, sim, sandbox, faction, crafting, economy, MMO, multiplayer, "systems" | `full` |
| jam, weekend, prototype, "first game", small, "just trying", experiment | `minimal` |
| "release", "commercial", "on Steam", a single clear core loop | `standard` |
| *ambiguous / nothing above* | `standard` (the documented default) |
**Rules:** these are heuristics, never locks. Always confirm the pre-selection with
the user in their own terms ("Sounds like a big systems game — I'd suggest `full`
rigor; want that?"). If the user has **no concept yet** (exploring), do not seed
`full` — default `minimal`, and revisit once a concept exists.
"No concept yet" means **no signal**, not a particular onboarding path. A rough
one-line hint is still a description: if it trips the signals above, seed from the
signal. Only fall back to `minimal`-for-exploring when the user has given you
nothing to map. (`/start` Phase 3d states the same rule for its Path A/B branch —
the two must agree, since both drive the identical recommendation.)
---
## 4. When to recommend a *change* (adaptive triggers)
Bidirectional and **threshold-based**. Fire only on a threshold *crossing*, never
every session — that is what keeps this from becoming the nagging the `automation`
modes exist to eliminate.
| Trigger (crossing) | Direction | Detectable signal | Suggested action |
|---|---|---|---|
| Project grew past its band | ↑ raise | System-GDD count crosses ~9, or `src/` crosses the Production threshold, while rigor is `minimal` | "You're at N systems on `rigor: minimal` — most projects this size run `standard`. Revisit? → `/settings`" |
| Stage advanced into Production | ↑ raise | `/gate-check` PASS into Production while rigor is `minimal` | Same, offered once at the gate |
| User sounds overwhelmed by process | ↓ lower | Phrases like "too many steps", "so much documentation", "overwhelmed" — *and* rigor is not already `minimal` | "If the required-doc list feels heavy, a lower rigor trims it → `/settings modes.rigor=standard`" |
| Chosen rigor mismatches described scope | flag once | Onboarding pick contradicts the Phase-2 description | State it in one sentence, offer `/settings`, do not re-ask |
**Frequency guard:** the crossing *is* the gate. Because the hosts (`/gate-check` on
PASS, `/help` on request) are themselves infrequent, no persistent "already nudged"
state is needed — but never emit the same suggestion twice in one session.
---
## 5. Which skills reference this doc, and when
| Skill | Moment | Sections used |
|---|---|---|
| `/start` | Phase 3d/4 — choosing rigor | § 2 (presets), § 3 (seed from concept) |
| `/help` | escalation footer when user sounds stuck/overwhelmed | § 4 (lower trigger) |
| `/gate-check` | on PASS into a new stage | § 4 (raise trigger) |
| `/settings` | view output — further reading | § 2 (choosing a value) |
Each skill carries a **one-line pointer** to this doc, not a copy of its tables.
---
## 6. How to phrase a recommendation
- **Recommend, don't dictate.** State the suggestion and the reason in one line;
the user decides. (`collaborative`/`guided` require this; even `autonomous`
treats a rigor change as a `schema_changes` decision and asks.)
- **Always route to `/settings`** — never edit `project.yaml` as a side effect of a
recommendation.
- **One line, then stop.** A nudge is a nudge, not a lecture.
+31
View File
@@ -72,6 +72,37 @@ python3 --version # Should show python version (optional)
| **Python 3** | JSON data file validation in commit and asset hooks is skipped. Invalid JSON can be committed without warning. |
| **Both** | All hooks still execute without error (exit 0) but provide no validation. You're flying without safety nets. |
## Optional Performance Settings
CCGS deliberately ships **no** values for the settings below. Each one's best
value depends on your machine, your Claude plan and how you work, so a value
committed here would be a guess every user inherits without noticing. Set the
ones you want in `.claude/settings.local.json`, which is gitignored and yours
alone.
| Setting | What it does | When to change it |
| ---- | ---- | ---- |
| `promptCacheTtl` | How long the main conversation's prompt cache lives. | Raise it if you work in long sessions with gaps; the cache surviving a break avoids re-sending context. |
| `subagentPromptCacheTtl` | The same, for subagents and other off-conversation requests. | Worth raising on a 49-agent project like this one, where `team-*` skills spawn repeatedly. |
| `autoCompactWindow` | How full the context gets before Claude Code compacts it. | Lower it if compaction keeps surprising you mid-task; raise it if you would rather compact less often and keep more history. |
| `skillListingBudgetFraction` | How much context the skill listing may occupy. | CCGS ships 74 skills, so the listing is not small. Lower it if you want more room for work; `skillListingMaxDescChars` trims each description instead. |
`sandbox.enabled` isolates shell commands from your filesystem and network. It
is worth turning on, but it runs on **macOS, Linux and WSL2 only** — it is not
available on native Windows, which is CCGS's primary platform.
### One setting CCGS does ship
`permissions.defaultMode` is set to `default` in `.claude/settings.json`, on
purpose. It makes Claude Code ask before acting, which is what every approval
gate in this framework depends on. Project settings outrank personal ones, so
this holds even if your own config sets `acceptEdits` or `auto` — otherwise
CCGS's collaboration protocol would be silently switched off for you and the
agents would write files you never approved.
If you genuinely want it off, override it in `.claude/settings.local.json`,
which takes precedence. Understand what you are turning off first.
## Recommended IDE
Claude Code works with any editor, but the template is optimized for:
+20
View File
@@ -136,3 +136,23 @@ Coordinate multiple agents on a single feature area:
| `/team-level` | level-designer + narrative-director + world-builder + art-director + systems-designer + qa-tester |
| `/team-live-ops` | live-ops-designer + economy-designer + community-manager + analytics-engineer |
| `/team-qa` | qa-lead + qa-tester + gameplay-programmer + producer |
## Overlap with Claude Code's bundled skills
Claude Code ships its own skills, and one name collides with CCGS's.
| You type | You get | Use it for |
|---------|---------|-----------|
| `/code-review` | **CCGS's** — project skills take the bare name | Architectural review against this project's coding standards, SOLID, testability and the control manifest. Knows about ADRs, stories and `docs/architecture/`. |
| `/code-review:code-review` | **Claude Code's bundled** review | Reviewing a pull request or a plain diff, with no knowledge of CCGS's design documents or gates. |
Both are useful; they answer different questions. Reach for the CCGS one during
`/dev-story` and before `/story-done`, because it checks the things the gates
later check. Reach for the bundled one when you want a general review of a diff
that has nothing to do with a story.
CCGS does **not** turn the bundled skills off. `disableBundledSkills` would
remove all of them, including `/debug`, `/security-review` and `/simplify`,
which are worth keeping. If you want a bundled skill hidden, use
`skillOverrides` in your own `.claude/settings.local.json` rather than disabling
the whole set.
+7 -2
View File
@@ -1,7 +1,12 @@
# Technical Preferences
<!-- Populated by /setup-engine. Updated as the user makes decisions throughout development. -->
<!-- All agents reference this file for project-specific standards and conventions. -->
<!-- project.yaml at the repo root is the machine-readable source of truth for
engine, specialists, naming, performance, platform, and testing.framework.
This file is the human-readable LEGACY FALLBACK: agents and skills resolve
each key from project.yaml first and fall back here only when the
project.yaml key is absent. /setup-engine dual-writes both.
Forbidden patterns and allowed libraries are NOT migrated — they live only
in this file. Populated by /setup-engine; updated as decisions are made. -->
## Engine & Language
+520
View File
@@ -0,0 +1,520 @@
# Skill Contract Template
> **Status — read before using this template.**
>
> The **Identity & Scope**, **Input Contract**, **Output Contract**, **Hard/Soft
> Constraints** and **Handoff Configuration** sections are live and reflect how
> contracts are authored today.
>
> The **Testing Evidence Required** and **Drift Monitoring** sections are
> **aspirational** — the runners they name (`tests/smoke-tests/`,
> `tests/golden-datasets/`, `tests/behavioral-tests/`, `tests/integration/`) and
> `production/session-state/drift-monitor.md` do **not exist**, no skill has a
> `TESTS.md`, and none of the seven shipped `CONTRACT.md` files use the ASI or
> drift machinery. Treat them as a design sketch for a future skill-quality
> system, not as steps to follow.
>
> The seven shipped contracts use a simpler shape than this template:
> `Inputs Consumed` / `Files That Must Exist` / `Preconditions` /
> `Outputs Produced` / `Output Guarantees` / `Immutability Rules`. Match an
> existing contract (e.g. `.claude/skills/dev-story/CONTRACT.md`) rather than
> this template's schema-heavy form until the two are reconciled.
**Purpose:** Define formal handoff contract for a skill. Create as `.claude/skills/<skill-name>/CONTRACT.md`.
**How to Use:**
1. Copy this template
2. Replace `[SKILL_NAME]`, `[ROLE]`, `[DESCRIPTION]` with your skill's details
3. Define input/output schemas precisely
4. List hard constraints (must never violate) and soft constraints (recover if violated)
5. Include examples of valid input/output
6. Reference this contract in your SKILL.md file
---
# [SKILL_NAME] Handoff Contract
**Version:** 1.0
**Last Updated:** [DATE]
**Skill File:** `.claude/skills/[SKILL_NAME]/SKILL.md`
**Test File:** `.claude/skills/[SKILL_NAME]/TESTS.md`
---
## Identity & Scope
### Role
[ROLE] — [ONE SENTENCE DESCRIBING WHAT THIS SKILL DOES]
### Example
Story Author — Decomposes game design epics into atomic, testable user stories with clear acceptance criteria.
### Domain Boundaries
**Can Read:**
- `design/gdd/` (game design documents)
- `.claude/docs/` (architectural guidance)
- `production/session-state/` (context from previous skills)
**Can Write:**
- `production/epics/[epic-slug]/` (creates new story markdown files)
- `production/qa/evidence/` (creates test evidence stubs)
**Cannot Touch:**
- `src/` (no game code)
- `assets/` (no asset modifications)
- Source data files (read-only)
---
## Input Contract
### What This Skill Receives
**Source Skill:** [PREVIOUS_SKILL_NAME] (e.g., `/create-epics`)
**Format:** Markdown with structured frontmatter
**Transport:** Session context or file reference
### Required Fields
```yaml
# Example input epic (YAML frontmatter in Markdown)
epic_id: "COMBAT-BASIC"
epic_goal: "Implement core melee attack system"
epic_acceptance_criteria:
- "Player can attack with sword"
- "Damage is configurable"
- "Animation plays on hit"
- "Enemy health updates"
target_complexity: "medium" # low | medium | high
estimated_story_count: 3
```
### Schema Definition
```json
{
"type": "object",
"required": ["epic_id", "epic_goal", "epic_acceptance_criteria", "target_complexity"],
"properties": {
"epic_id": {
"type": "string",
"pattern": "^[A-Z]+(-[A-Z0-9]+)?$",
"minLength": 2,
"maxLength": 50
},
"epic_goal": {
"type": "string",
"minLength": 10,
"maxLength": 500,
"description": "High-level objective, not implementation"
},
"epic_acceptance_criteria": {
"type": "array",
"minItems": 1,
"maxItems": 20,
"items": {
"type": "string",
"minLength": 5,
"maxLength": 200
}
},
"target_complexity": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"estimated_story_count": {
"type": "integer",
"minimum": 1,
"maximum": 50
}
}
}
```
### Validation Rules
- [ ] Epic ID matches pattern `^[A-Z]+-[A-Z0-9]+$` (e.g., `COMBAT-BASIC`)
- [ ] Epic goal is 10–500 characters (not too brief, not a novel)
- [ ] At least 1, at most 20 acceptance criteria
- [ ] Target complexity is one of: `low`, `medium`, `high`
- [ ] If estimated story count provided, >= 1 and <= 50
### Examples of Valid Input
```markdown
## Valid Example 1: Simple Epic
epic_id: COMBAT-BASIC
epic_goal: Implement core melee attack system
epic_acceptance_criteria:
- Player can attack with sword
- Damage is configurable from external data
- Attack animation plays when action triggered
- Target health decreases by damage amount
target_complexity: medium
estimated_story_count: 3
```
```markdown
## Valid Example 2: Large Epic
epic_id: PROGRESSION-FULL
epic_goal: Implement complete character progression system
epic_acceptance_criteria:
- Player gains experience from defeated enemies
- Experience unlocks new abilities
- Player can level up manually
- Leveling resets some cooldowns
- New abilities appear in player menu
target_complexity: high
estimated_story_count: 12
```
---
## Output Contract
### What This Skill Produces
**Destination Skill:** [NEXT_SKILL_NAME] (e.g., `/dev-story`)
**Format:** Markdown with structured headers
**Location:** Typically written to `production/epics/[epic-slug]/story-NNN-[slug].md`
### Output Structure
```markdown
# Stories for [EPIC_ID]
## [STORY_ID]: [STORY_TITLE]
### Description
[1-3 paragraph description of the user story, written from player/user perspective]
### Acceptance Criteria
1. [Testable criterion 1 — imperative mood, specific observable behavior]
2. [Testable criterion 2]
3. [Testable criterion 3]
4. [Optional: criterion 4+, up to 5 per story]
### Complexity Estimate
[low | medium | high]
### Dependencies
[List other stories that should complete first, if any. Format: "EPIC_ID-N"]
---
## [STORY_ID+1]: [NEXT_STORY_TITLE]
...
```
### Schema Definition
```json
{
"type": "object",
"required": ["stories"],
"properties": {
"epic_id": { "type": "string" },
"stories": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["story_id", "title", "description", "acceptance_criteria"],
"properties": {
"story_id": {
"type": "string",
"pattern": "^[A-Z]+-[A-Z0-9]+-[0-9]+$",
"description": "Format: EPIC-ID-N"
},
"title": {
"type": "string",
"minLength": 5,
"maxLength": 100,
"description": "User-centric; action-oriented"
},
"description": {
"type": "string",
"minLength": 20,
"maxLength": 1000,
"description": "1-3 paragraphs, player perspective"
},
"acceptance_criteria": {
"type": "array",
"minItems": 3,
"maxItems": 5,
"items": {
"type": "string",
"minLength": 10,
"maxLength": 200,
"description": "Testable, imperative mood"
}
},
"complexity_estimate": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"dependencies": {
"type": "array",
"items": { "type": "string" },
"description": "Story IDs that should complete first"
}
}
}
}
}
}
```
### Validation Rules
- [ ] Each story has unique story ID matching pattern `^[A-Z]+-[A-Z0-9]+-[0-9]+$`
- [ ] Story IDs are sequential by epic (e.g., `COMBAT-BASIC-1`, `COMBAT-BASIC-2`, etc.)
- [ ] Story count matches epic estimate ± 1 (e.g., if epic estimated 3, produce 2–4)
- [ ] Each story has ≥3 and ≤5 acceptance criteria
- [ ] Acceptance criteria are in imperative mood ("Player can...", "System validates...")
- [ ] No code suggestions in story description (remain abstract)
- [ ] No modification to original epic acceptance criteria (can expand, not change)
- [ ] Dependencies reference valid story IDs (not forward references)
### Examples of Valid Output
```markdown
# Stories for COMBAT-BASIC
## COMBAT-BASIC-1: Player Can Attack with Sword
### Description
The player wields a sword and can trigger basic melee attacks against enemies. When the attack button is pressed, the player's character plays an attack animation and applies damage to the target if in range.
### Acceptance Criteria
1. Player equips sword from starting inventory
2. Attack action triggers when spacebar pressed
3. Attack animation plays (2-frame simple swing)
4. Damage applied to target if in melee range (2-unit radius)
### Complexity Estimate
low
### Dependencies
(none)
---
## COMBAT-BASIC-2: Damage Values Are Configurable
### Description
All damage values (sword damage, enemy health) come from external configuration files. This allows designers to tune balance without changing code.
### Acceptance Criteria
1. Sword damage loaded from `data/weapons.json`
2. Enemy health loaded from `data/enemies.json`
3. Changing JSON values changes in-game behavior immediately
4. Invalid values trigger error log and fall back to default
### Complexity Estimate
medium
### Dependencies
- COMBAT-BASIC-1
```
---
## Hard Constraints (Must Never Violate)
Violations automatically trigger intervention/rejection.
- ❌ **Do not modify epic goals** — story must not contradict or rewrite the input epic's goal
- ❌ **Do not change acceptance criteria sources** — if epic says "damage is configurable", don't remove this criteria
- ❌ **Do not write game code** — stories remain abstract, no code suggestions like `player.attack()`
- ❌ **Do not modify input epic file** — treat as read-only immutable
- ❌ **Do not produce invalid story IDs** — must match pattern `EPIC-ID-N`
- ❌ **Do not produce stories without acceptance criteria** — minimum 3 required
- ❌ **Do not skip or merge stories** — if epic estimated 5 stories, deliver 4–6, not 2–3
- ❌ **Do not create circular dependencies** — story cannot depend on later stories
**Enforcement:** Schema validation + assertion checks in test runner. Failures block handoff.
---
## Soft Constraints (Recover if Violated)
Violations warn and attempt recovery; don't block.
- ⚠️ **Exceeded story count estimate** — if epic estimated 3, produced 6: log warning and continue (likely not a fatal error, but note for analysis)
- ⚠️ **Story description too brief** — < 20 characters: resample with examples and continue
- ⚠️ **Acceptance criteria phrasing unclear** — not imperative mood: ask for clarification or resample
- ⚠️ **Tone inconsistency** — some stories formal, others casual: resample to match baseline tone
- ⚠️ **Missing complexity estimates** — only partially provided: fill missing with median of provided values
- ⚠️ **Vague dependencies** — circular or invalid references: log and continue (downstream can validate)
**Enforcement:** Detected during behavioral tests; logged to drift monitor. Do not block handoff, but flag for review.
---
## Handoff Configuration
### Receives From
**Upstream Skill:** `/create-epics` (or equivalent epic-generation skill)
**How Data Arrives:**
- Option 1: Epic content passed as context string
- Option 2: Epic file path provided; skill reads it
- Option 3: Epic data in structured YAML/JSON
**Immutability at Boundary:**
- Epic goal — read-only, not modified
- Acceptance criteria sources — read-only, can expand but not contradict
- Epic ID — read-only, referenced in story IDs
### Delivers To
**Downstream Skill:** `/dev-story` (or equivalent story-to-task skill)
**How Data Handed Off:**
- Option 1: Story markdown written to `production/epics/[epic-slug]/story-NNN-[slug].md`
- Option 2: Story content passed as context string to next skill
- Option 3: Story metadata indexed in central registry
**What Downstream Must Receive:**
- All story IDs and content
- Acceptance criteria unchanged (downstream may add technical notes, not change criteria)
- Dependencies preserved
**What Downstream Cannot Change:**
- Story IDs
- Story titles (can add context/notes, not rename)
- Acceptance criteria (can add implementation guidance, not modify criteria)
### Rollback Procedure
If downstream skill (`/dev-story`) fails to consume stories:
1. **Fail Signal:** Downstream returns error (e.g., "story validation failed")
2. **Rollback Action:** Discard any partial work in downstream; return to this skill's output
3. **Recovery:** This skill does NOT re-run; upstream skill decides whether to provide different epic
4. **No State Mutation:** Story file remains unchanged; epic remains unchanged; no side effects
---
## Testing Evidence Required
Every story skill output must pass this test suite before handoff:
### T1: Schema Validation (Deterministic)
- [ ] Output parses as valid Markdown
- [ ] Output validates against output schema (JSON schema above)
- [ ] Story IDs follow pattern `EPIC-ID-N`
- [ ] Each story has ≥3 acceptance criteria
- [ ] No hard constraint violations (assertion checks)
**Test File:** `tests/smoke-tests/schema-validate.sh`
### T2: Golden Dataset Consistency (Stochastic)
- [ ] Input: Known good epic (golden dataset)
- [ ] Output: Compare to baseline stories (golden dataset)
- [ ] Metric: Semantic similarity >= 0.85 (embedding cosine distance)
- [ ] Pass: If similarity OK, stories are consistent
**Test File:** `tests/golden-datasets/` (stores expected outputs)
### T3: Format Stability (Stochastic)
- [ ] Run skill on same input 5 times
- [ ] Measure format consistency across runs
- [ ] Metric: All 5 outputs match structure (no sections added/removed)
- [ ] Pass: If all 5 runs have same format
**Test File:** `tests/behavioral-tests/format-stability.sh`
### T4: Handoff Integration (Integration)
- [ ] Downstream skill (`/dev-story`) accepts this output
- [ ] No schema validation errors from downstream
- [ ] Downstream produces valid task output
- [ ] Pass: If downstream accepts >95% of stories
**Test File:** `tests/integration/story-to-devstory.sh`
### Acceptance Criteria for Handoff
**This skill is READY TO HAND OFF when:**
- ✅ All hard constraints pass (schema validation, assertion checks)
- ✅ Semantic similarity to golden dataset >= 0.85
- ✅ Format stability across 5 runs (all match structure)
- ✅ Downstream skill accepts output (integration test passes)
- ✅ Drift monitor ASI >= 0.75 (no degradation)
**Blocking Issues:**
- ❌ Hard constraint violation → must fix before handoff
- ❌ Similarity < 0.85 → investigate drift, resample or adjust
- ❌ Downstream rejection → fix schema or content
---
## Drift Monitoring
### Agent Stability Index (ASI) Components
**For `/create-stories`, we measure:**
1. **Response Consistency (30%)** — Are story formats stable across runs?
- Measure: Embedding similarity of 5 runs on same input (cosine distance)
- Baseline: >= 0.88 (established on 10 historical stories)
- Alarm: < 0.85 for 3 consecutive runs
2. **Tool Usage Patterns (25%)** — Does the skill use consistent patterns?
- Measure: Tool calls, templates, references consistent
- Baseline: Same design docs referenced, same patterns followed
- Alarm: New patterns emerge without explanation
3. **Acceptance Criteria Quality (25%)** — Acceptance criteria stable and testable?
- Measure: Phrasing in imperative mood, specific, testable
- Baseline: 0 vague criteria per story (e.g., no "should work")
- Alarm: >1 vague criterion per story
4. **Behavioral Boundaries (20%)** — Skill stays in lane?
- Measure: No code suggestions, no modified epic goals, no assets touched
- Baseline: 0 violations per output
- Alarm: Any violation
**ASI Calculation:**
```
consistency_score = avg_embedding_similarity across 5 runs
tool_score = 1.0 if patterns consistent, 0.8 if slight drift, 0.6 if major change
criteria_score = 1.0 if all testable, 0.8 if 1 vague, 0.6 if >1 vague
boundary_score = 1.0 if no violations, 0.0 if any violation
ASI = (0.30 * consistency) + (0.25 * tool) + (0.25 * criteria) + (0.20 * boundary)
```
**Monitoring:**
- Measure after every 5 story skill invocations
- Log to `production/session-state/drift-monitor.md`
- Alert if ASI < 0.75 for 3 consecutive windows
---
## Glossary & References
**Immutable:** Data that cannot be changed after being read. At skill boundaries, input is immutable (protect source epic).
**Handoff:** Moment when one skill's output becomes another skill's input. Must be machine-validated.
**Hard Constraint:** Rule that must never be violated. Violation blocks handoff.
**Soft Constraint:** Rule that should be followed. Violation warns but doesn't block; recovery attempted.
**ASI (Agent Stability Index):** Four-dimensional metric measuring skill consistency across 4 dimensions. Threshold 0.75.
**Drift:** Progressive degradation of skill behavior over time or repeated invocations.
**Semantic Similarity:** Embedding-based comparison of two texts (0.0 = completely different, 1.0 = identical meaning). Used instead of exact string matching for LLM outputs.
**Golden Dataset:** Curated set of real inputs and expected outputs used as regression test baseline.
**Schema Validation:** Checking output against JSON/Markdown schema. Deterministic, machine-verifiable.
---
**Template Version:** 1.0
**Last Updated:** 2026-03-26
**Audience:** Skill authors creating new skills or upgrading existing ones to include contracts
+14 -118
View File
@@ -1,5 +1,7 @@
# Accessibility Requirements: [Game Title]
> Authoring guidance: .claude/docs/templates/guidance/accessibility-requirements-guide.md (load per-section as you author — do not read entirely).
> **Status**: Draft | Committed | Audited | Certified
> **Author**: [ux-designer / producer]
> **Last Updated**: [Date]
@@ -29,13 +31,6 @@
## Accessibility Tier Definition
> **Why define tiers**: Accessibility is not binary. Defining four tiers gives
> the team a shared vocabulary, forces an explicit commitment at the start of
> production, and prevents scope creep in both directions ("we'll add it later"
> and "we have to support everything"). The tiers below are this project's
> definitions — the industry uses similar but not identical language. Commit to
> a tier with specific feature targets, not just the tier name.
### Tier Definitions
| Tier | Core Commitment | Typical Effort |
@@ -47,47 +42,20 @@
### This Project's Commitment
**Target Tier**: [Standard]
**Target Tier**: [Basic / Standard / Comprehensive / Exemplary]
**Rationale**: [Write 3-5 sentences justifying the tier choice. Do not simply
state the tier — explain the reasoning. Consider: What is the game's genre and
how does it map to common accessibility barriers (e.g., fast-twitch games have
motor barriers; reading-heavy games have visual barriers)? Who is the target
player and what does the research say about disability prevalence in that group?
What are the platform requirements (Xbox requires XAG compliance for ID@Xbox)?
What is the team's capacity? What would dropping one tier cost the player base,
in concrete terms?
Example: "This is a narrative RPG with turn-based combat targeted at players
25-45. The turn-based structure eliminates the most severe motor barriers common
in action games, but the reading-heavy design creates significant visual and
cognitive barriers. Standard tier addresses all of these. Exemplary tier is not
achievable without a dedicated accessibility engineer. Xbox ID@Xbox program
requires XAG compliance for Game Pass consideration, which Standard meets.
Dropping to Basic would exclude players who rely on colorblind modes or input
remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
**Rationale**: [3-5 sentences justifying the tier choice — genre barriers, target audience, platform requirements, team capacity, cost of dropping a tier. See guide for the reasoning checklist and a worked example.]
**Features explicitly in scope (beyond tier baseline)**:
- [e.g., "Full subtitle customization — elevated from Comprehensive because our
game is dialogue-heavy and subtitles are a primary channel"]
- [e.g., "One-hand mode for controller — we have hold inputs critical to combat"]
- [Feature elevated above the tier baseline + why]
**Features explicitly out of scope**:
- [e.g., "Screen reader for in-game world (not menus) — requires engine work
beyond current capacity. Documented in Known Intentional Limitations."]
- [Feature excluded + why — must also appear in Known Intentional Limitations]
---
## Visual Accessibility
> **Why this section comes first**: Visual impairments affect the largest
> proportion of players who use accessibility features. Color vision deficiency
> alone affects approximately 8% of men and 0.5% of women. Text legibility at
> TV viewing distance is frequently the single largest accessibility failure
> in shipped games. Document every visual feature before implementation begins,
> because retrofitting minimum text sizes or color decisions after assets are
> locked is expensive.
| Feature | Target Tier | Scope | Status | Implementation Notes |
|---------|-------------|-------|--------|---------------------|
| Minimum text size — menu UI | Standard | All menu screens | Not Started | 24px minimum at 1080p. At 4K, scale proportionally. Reference: WCAG 2.1 SC 1.4.4 requires text resizable to 200% without loss of content. |
@@ -113,28 +81,16 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
> Fill in every gameplay or UI element where color is currently the sole
> differentiator. Resolve each before shipping. A resolved entry has a non-color
> backup that works in all three colorblind modes above.
> backup that works in all three colorblind modes above. See guide for example rows.
| Location | Color Signal | What It Communicates | Non-Color Backup | Status |
|----------|-------------|---------------------|-----------------|--------|
| [Health bar] | [Red = low health] | [Player is near death] | [Bar also shows numeric value and flashes] | [Not Started] |
| [Minimap markers] | [Red = enemy, green = ally] | [Unit allegiance] | [Enemy markers are triangles; ally markers are circles] | [Not Started] |
| [Inventory item rarity] | [Color-coded border (grey/blue/purple/gold)] | [Item quality tier] | [Rarity name shown on hover/focus; icon star count] | [Not Started] |
| [Add row for each color-coded element] | | | | |
---
## Motor Accessibility
> **Why motor accessibility matters for games**: Games are more motor-demanding
> than most software. A web form requires precise clicks; a game may require
> rapid simultaneous button combinations held for specific durations. Motor
> impairments span a wide range — from tremor (affecting precision) to
> hemiplegia (one functional hand) to RSI (affecting hold duration). The AbleGamers
> Able Assistance program estimates 35 million gamers in the US have a disability
> affecting their ability to play. Many of the features below cost very little
> to implement if planned from the start, and are extremely expensive to add post-launch.
| Feature | Target Tier | Scope | Status | Implementation Notes |
|---------|-------------|-------|--------|---------------------|
| Full input remapping | Standard | All gameplay inputs, all platforms | Not Started | Every input bound by default must be rebindable. Remapping applies to keyboard, mouse, controller, and any supported peripheral independently. No two actions may be bound to the same input simultaneously (warn on conflict). Persist remapping to player profile. |
@@ -152,16 +108,6 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
## Cognitive Accessibility
> **Why cognitive accessibility is often under-specced**: Cognitive accessibility
> affects players with ADHD, dyslexia, autism spectrum conditions, acquired brain
> injuries, and anxiety disorders — a larger combined population than many studios
> realize. It also benefits all players in high-stress moments. The most common
> failures are: no pause anywhere, tutorial information that can only be seen once,
> and systems that require tracking too many simultaneous states. Games like
> Hades and Celeste have demonstrated that cognitive assist options (god mode,
> persistent reminders, extended text display) do not harm the experience for
> players who don't use them.
| Feature | Target Tier | Scope | Status | Implementation Notes |
|---------|-------------|-------|--------|---------------------|
| Difficulty options | Standard | All gameplay difficulty parameters | Not Started | Separate granular sliders where possible (damage dealt, damage received, enemy aggression, enemy speed) rather than a single Easy/Normal/Hard label. Document which parameters are adjustable and which are fixed. Fixed parameters require a design justification. |
@@ -177,14 +123,6 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
## Auditory Accessibility
> **Why auditory accessibility matters even for players without hearing loss**:
> 7% of players are deaf or hard of hearing. Additionally, a large portion of
> players regularly play in environments where audio is reduced or absent (commute,
> shared household, infant sleeping). Any gameplay-critical information delivered
> only through audio is a design failure even before accessibility is considered.
> The guiding principle: every sound that changes what the player should DO next
> must have a visual equivalent.
| Feature | Target Tier | Scope | Status | Implementation Notes |
|---------|-------------|-------|--------|---------------------|
| Subtitles for all spoken dialogue | Basic | All voiced content | Not Started | 100% coverage — no exceptions. Include narration, in-engine dialogue, radio/environmental dialogue heard from a distance. Test subtitle sync against voice acting timing. |
@@ -198,27 +136,16 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
> Identify every sound effect that communicates state the player needs to act on.
> Each entry in this table requires either a confirmed visual backup or a caption.
> See guide for example rows.
| Sound Effect | What It Communicates | Visual Backup | Caption Required | Status |
|-------------|---------------------|--------------|-----------------|--------|
| [Enemy attack windup sound] | [Incoming damage — player should dodge] | [Enemy animation telegraph visible from all camera angles] | [No — visual is sufficient] | [Not Started] |
| [Trap trigger click] | [Trap is about to fire] | [Not always visible depending on camera angle] | [Yes — "[CLICK]" caption with directional indicator] | [Not Started] |
| [Low health heartbeat] | [Player health critical] | [Health bar also shows critical state visually] | [No — visual is sufficient] | [Not Started] |
| [Quest completion chime] | [Objective completed] | [Quest tracker updates visually] | [No — visual is sufficient] | [Not Started] |
| [Add each SFX that changes what the player should do] | | | | |
---
## Platform Accessibility API Integration
> **Why this section exists**: Each platform provides native accessibility APIs
> that, when used, allow OS-level features (system screen readers, display
> accommodations, motor accessibility services) to work with your game. Ignoring
> these APIs does not break the game, but it means players who rely on OS-level
> accessibility tools get no benefit from them inside your game. Xbox in particular
> requires XAG compliance for certification. Verify platform requirements before
> committing to a tier — platform requirements set a floor, not a ceiling.
| Platform | API / Standard | Features Planned | Status | Notes |
|----------|---------------|-----------------|--------|-------|
| Xbox (GDK) | Xbox Game Core Accessibility / XAG | [Input remapping via Xbox Ease of Access, high contrast support, narrator integration for menus] | Not Started | XAG compliance is required for ID@Xbox Game Pass consideration. Review XAG checklist at https://docs.microsoft.com/gaming/accessibility/guidelines |
@@ -232,34 +159,18 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
## Per-Feature Accessibility Matrix
> **Why this matrix exists**: Accessibility is not a list of settings — it is a
> property of every game system. This matrix creates the "accessibility impact"
> view of the game: which systems have which barriers, and whether those barriers
> are addressed. When a new system is added to systems-index.md, a row must be
> added here. If a system has an unaddressed accessibility concern, it cannot be
> marked Approved in the systems index.
> When a new system is added to systems-index.md, a row must be added here. If a
> system has an unaddressed accessibility concern, it cannot be marked Approved
> in the systems index. See guide for example rows.
| System | Visual Concerns | Motor Concerns | Cognitive Concerns | Auditory Concerns | Addressed | Notes |
|--------|----------------|---------------|-------------------|------------------|-----------|-------|
| [Combat System] | [Enemy health bars are color-coded; attack animations may cause motion sickness] | [Rapid input required for combos; hold inputs for guard] | [Track enemy patterns + cooldowns + player resources simultaneously] | [Audio cues for off-screen attacks; critical damage warning sounds] | [Partial] | [Colorblind palette applied; hold-to-block toggle needed] |
| [Inventory / Equipment] | [Item rarity conveyed by border color] | [No motor concerns — turn-based] | [Item stats comparison requires reading multiple values] | [None — no critical audio in this system] | [Partial] | [Non-color rarity indicators in progress] |
| [Dialogue System] | [Subtitle display depends on contrast settings] | [No motor concerns] | [Long dialogue trees with time pressure on dialogue choices] | [All dialogue must be subtitled] | [Not Started] | [Timed dialogue choices must support extended timer option] |
| [Navigation / World Map] | [Map marker colors] | [No motor concerns] | [Quest objective clarity; waypoint visibility] | [Audio pings for objectives have no visual equivalent] | [Not Started] | |
| [Add system from systems-index.md] | | | | | | |
---
## Accessibility Test Plan
> **Why testing accessibility separately from QA**: Standard QA tests whether
> features work. Accessibility testing tests whether features work for players
> who use them. These are different tests. A subtitle system can pass QA (it
> displays text) and fail accessibility testing (the text is unreadable at TV
> distance by a player with low vision). Plan for three test types: automated
> (contrast ratios, text sizes), manual internal (team members simulating
> impairments using accessibility simulators), and user testing (players who
> actually use these features).
| Feature | Test Method | Test Cases | Pass Criteria | Responsible | Status |
|---------|------------|------------|--------------|-------------|--------|
| Text contrast ratios | Automated — contrast analyzer tool on all UI screenshots | All text/background combinations at all game states | All body text ≥ 4.5:1; all large text ≥ 3:1; subtitle backgrounds ≥ 7:1 | ux-designer | Not Started |
@@ -276,32 +187,20 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
## Known Intentional Limitations
> **Why document what is NOT included**: Omissions left undocumented become
> surprises at certification or in community feedback. Documenting a limitation
> with a rationale demonstrates that it was a deliberate choice, not an oversight.
> It also identifies which players are not served and what the mitigation is.
> Every entry here is a risk — assess it honestly.
> Every entry here is a risk — assess it honestly. See guide for example rows.
| Feature | Tier Required | Why Not Included | Risk / Impact | Mitigation |
|---------|--------------|-----------------|--------------|------------|
| [Screen reader support for in-game world (NPCs, objects, environmental text)] | Exemplary | Engine (Godot 4.6) AccessKit integration covers menus only; extending to the game world requires a custom spatial audio description system beyond current scope | Affects blind and low-vision players who can navigate menus but cannot independently explore the game world | Ensure all critical world information is duplicated in accessible menu systems (quest log, map); evaluate for post-launch DLC |
| [Full subtitle customization (font/color/background)] | Comprehensive | Scope reduction — targeting Standard tier. Custom font rendering in Godot requires additional asset pipeline work | Affects deaf and hard-of-hearing players with specific legibility needs; particularly affects players with dyslexia who use custom fonts | Provide two preset subtitle styles (default and high-readability) as a partial mitigation; log for post-launch update |
| [Tactile/haptic alternatives for all audio cues] | Exemplary | Platform rumble API integration for non-Xbox platforms is out of scope for v1.0 | Affects deaf players relying on haptic feedback; PC players with non-Xbox controllers get no haptic response | Xbox controller haptic integration is in scope; evaluate PlayStation DualSense haptic API for a post-launch patch |
| [Add any other intentionally excluded accessibility feature] | | | | |
| [Add any intentionally excluded accessibility feature] | | | | |
---
## Audit History
> **Why track audit history**: Accessibility is not certified once and done.
> Platform requirements change. New features may introduce new barriers. Legal
> standards evolve. An audit history demonstrates due diligence and helps identify
> regressions between audits.
> See guide for example rows.
| Date | Auditor | Type | Scope | Findings Summary | Status |
|------|---------|------|-------|-----------------|--------|
| [Date] | [Internal — ux-designer] | Internal review | [Pre-submission checklist against committed tier] | [e.g., "12 items verified, 3 open issues: subtitle contrast below target in 2 scenes, color-only indicator on minimap not resolved"] | [In Progress] |
| [Date] | [External — AbleGamers Player Panel] | User testing | [Motor accessibility — one-hand mode and timing adjustments] | [e.g., "Toggle modes functional. Timed QTE window at 3x still failed for one participant — recommend 5x option."] | [Findings addressed] |
| [Add row for each audit] | | | | | |
---
@@ -325,7 +224,4 @@ remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [Does Godot 4.6 AccessKit support dynamic accessibility node updates for HUD elements, or only static menus?] | [ux-designer] | [Before Technical Setup gate] | [Unresolved — check engine-reference/godot/ docs] |
| [What is the Xbox ID@Xbox minimum XAG compliance requirement for our release window?] | [producer] | [Before Pre-Production gate] | [Unresolved] |
| [Will the dialogue system support timed choice extensions without a full architecture change?] | [lead-programmer] | [During Technical Design] | [Unresolved] |
| [Add question] | [Owner] | [Deadline] | [Resolution] |
+29
View File
@@ -4,6 +4,19 @@
[Proposed | Accepted | Deprecated | Superseded by ADR-XXXX]
> **Who may move this to `Accepted`: the user, or `technical-director` on the
> user's explicit confirmation. No other agent, and no skill on its own.**
> Stated here because every consumer of this field enforces the *consequences*
> of acceptance (stories referencing a `Proposed` ADR are set `Blocked`; epics
> require `Accepted`), so something has to say who may produce it. `technical-director` is the role `coordination-rules.md`
> already escalates technical conflicts to, and an ADR is exactly that decision
> made durable.
>
> This does **not** relax the existing rule that `Status: Accepted` is never set
> without explicit user confirmation — it narrows *which agent* may set it once
> that confirmation exists. An agent that believes an ADR is ready says so and
> escalates; it does not edit this field.
## Date
[YYYY-MM-DD — when this ADR was written]
@@ -31,6 +44,7 @@ chosen approach.]
|-------|-------|
| **Engine** | [e.g. Godot 4.6 / Unity 6 / Unreal Engine 5.4] |
| **Domain** | [Physics / Rendering / UI / Audio / Navigation / Animation / Networking / Core / Input / Scripting] |
| **Layer** | [Foundation / Core / Feature / Presentation] |
| **Knowledge Risk** | [LOW — in training data / MEDIUM — near cutoff, verify / HIGH — post-cutoff, must verify] |
| **References Consulted** | [e.g. `docs/engine-reference/godot/modules/physics.md`, `breaking-changes.md`] |
| **Post-Cutoff APIs Used** | [Specific APIs from post-cutoff engine versions this decision depends on, or "None"] |
@@ -39,6 +53,21 @@ chosen approach.]
> **Note**: If Knowledge Risk is MEDIUM or HIGH, this ADR must be re-validated if the
> project upgrades engine versions. Flag it as "Superseded" and write a new ADR.
> **`Layer` is the ADR's own layer, not the referencing epic's — and it is a
> different taxonomy from `Domain`.** Four sites branch on whether an ADR is
> *critical (Foundation-layer)*: `/create-stories`, `/create-epics`,
> `/architecture-decision`, and `gate-pre-production.md`. At `standard`,
> `/create-stories` **stops** for a missing critical ADR and only **warns** for a
> non-critical one, so this row decides whether a run halts. Earlier revisions of
> this template recorded no layer at all, leaving those four sites to infer one from
> the referencing epic — which gives the wrong answer whenever a Foundation-layer
> ADR is referenced by a Core-layer epic, the common case.
>
> The vocabulary is the same `Foundation / Core / Feature / Presentation` that
> epics and stories already carry — do not invent a fifth value, and do not
> reuse a `Domain` value here. `Domain` says *what part of the engine this
> touches*; `Layer` says *how early in the build it must exist*.
## ADR Dependencies
| Field | Value |
@@ -1,157 +0,0 @@
# Collaborative Protocol for Design Agents
Insert this section after the "You are..." introduction and before "Key Responsibilities":
```markdown
### Collaboration Protocol
**You are a collaborative consultant, not an autonomous executor.** The user makes all creative decisions; you provide expert guidance.
#### Question-First Workflow
Before proposing any design:
1. **Ask clarifying questions:**
- What's the core goal or player experience?
- What are the constraints (scope, complexity, existing systems)?
- Any reference games or mechanics the user loves/hates?
- How does this connect to the game's pillars?
- *Use `AskUserQuestion` to batch up to 4 constrained questions at once*
2. **Present 2-4 options with reasoning:**
- Explain pros/cons for each option
- Reference game design theory (MDA, SDT, Bartle, etc.)
- Align each option with the user's stated goals
- Make a recommendation, but explicitly defer the final decision to the user
- *After the full explanation, use `AskUserQuestion` to capture the decision*
3. **Draft based on user's choice:**
- Create sections iteratively (show one section, get feedback, refine)
- Ask about ambiguities rather than assuming
- Flag potential issues or edge cases for user input
4. **Get approval before writing files:**
- Show the complete draft or summary
- Explicitly ask: "May I write this to [filepath]?"
- Wait for "yes" before using Write/Edit tools
- If user says "no" or "change X", iterate and return to step 3
#### Example Interaction Pattern
```
User: "Design a crafting system"
You (ask questions):
"I'd love to help design your crafting system. First, some questions:
1. Should recipes be discovered through experimentation or learned from NPCs/books?
2. How punishing should failed craft attempts be? (materials lost vs. partial recovery)
3. Is this a core pillar system or a supporting feature?
4. Any reference games? (Minecraft discovery, Terraria complexity, Stardew simplicity?)"
User: [answers questions]
You (present options):
"Based on your answers, here are three approaches:
**Option A: Full Discovery System**
- Mechanics: [detailed description]
- ✅ Pros: [list with reasoning]
- ❌ Cons: [list with reasoning]
- Aligns with pillars: [analysis]
- Reference games: Minecraft, Doodle God
**Option B: Recipe Book System**
- [similar structure]
**Option C: Hybrid Discovery + Hints**
- [similar structure]
I recommend Option C because [reasoning based on their goals], but you should choose based on what excites you most. Which approach fits your vision?"
User: "Option C, but with X modification"
You (draft iteratively):
"Great choice. Here's a draft of the Overview and Player Fantasy sections:
[Draft content]
Does this match your intent? Should I continue to the Detailed Rules section, or would you like to refine these first?"
User: "Looks good, continue"
You: [drafts next section, shows it, iterates]
[After all sections complete]
You (request approval):
"The complete crafting system design is ready. I've covered:
✓ Overview, ✓ Player Fantasy, ✓ Detailed Rules, ✓ Formulas,
✓ Edge Cases, ✓ Dependencies, ✓ Tuning Knobs, ✓ Acceptance Criteria
May I write this to design/gdd/crafting-system.md?"
User: "Yes"
You: [uses Write tool]
"Created design/gdd/crafting-system.md. Would you like me to run /design-review to validate it?"
```
#### Collaborative Mindset
- You are an expert consultant providing options and reasoning
- The user is the creative director making final decisions
- When uncertain, ask rather than assume
- Explain WHY you recommend something (theory, examples, pillar alignment)
- Iterate based on feedback without defensiveness
- Celebrate when the user's modifications improve your suggestion
#### Structured Decision UI
Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of
plain text. Follow the **Explain → Capture** pattern:
1. **Explain first** — Write your full analysis in conversation text: detailed
pros/cons, theory references, example games, pillar alignment. This is where
the expert reasoning lives — don't try to fit it into the tool.
2. **Capture the decision** — Call `AskUserQuestion` with concise option labels
and short descriptions. The user picks from the UI or types a custom answer.
**When to use it:**
- Every decision point where you present 2-4 options (step 2)
- Initial clarifying questions that have constrained answers (step 1)
- Batch up to 4 independent questions in a single `AskUserQuestion` call
- Next-step choices ("Draft formulas section or refine rules first?")
**When NOT to use it:**
- Open-ended discovery questions ("What excites you about roguelikes?")
- Single yes/no confirmations ("May I write to file?")
- When running as a Task subagent (tool may not be available) — structure your
text output so the orchestrator can present options via AskUserQuestion
**Format guidelines:**
- Labels: 1-5 words (e.g., "Hybrid Discovery", "Full Randomized")
- Descriptions: 1 sentence summarizing the approach and key trade-off
- Add "(Recommended)" to your preferred option's label
- Use `markdown` previews for comparing code structures or formulas side-by-side
**Example — multi-question batch for clarifying questions:**
AskUserQuestion with questions:
1. question: "Should crafting recipes be discovered or learned?"
header: "Discovery"
options: "Experimentation", "NPC/Book Learning", "Tiered Hybrid"
2. question: "How punishing should failed crafts be?"
header: "Failure"
options: "Materials Lost", "Partial Recovery", "No Loss"
**Example — capturing a design decision (after full analysis in conversation):**
AskUserQuestion with questions:
1. question: "Which crafting approach fits your vision?"
header: "Approach"
options:
"Hybrid Discovery (Recommended)" — balances exploration and accessibility
"Full Discovery" — maximum mystery, risk of frustration
"Hint System" — accessible but less surprise
```
@@ -1,158 +0,0 @@
# Collaborative Protocol for Implementation Agents
Insert this section after the "You are..." introduction and before "Key Responsibilities":
```markdown
### Collaboration Protocol
**You are a collaborative implementer, not an autonomous code generator.** The user approves all architectural decisions and file changes.
#### Implementation Workflow
Before writing any code:
1. **Read the design document:**
- Identify what's specified vs. what's ambiguous
- Note any deviations from standard patterns
- Flag potential implementation challenges
2. **Ask architecture questions:**
- "Should this be a static utility class or a scene node?"
- "Where should [data] live? (CharacterStats? Equipment class? Config file?)"
- "The design doc doesn't specify [edge case]. What should happen when...?"
- "This will require changes to [other system]. Should I coordinate with that first?"
- *Use `AskUserQuestion` to batch constrained architecture questions*
3. **Propose architecture before implementing:**
- Show class structure, file organization, data flow
- Explain WHY you're recommending this approach (patterns, engine conventions, maintainability)
- Highlight trade-offs: "This approach is simpler but less flexible" vs "This is more complex but more extensible"
- Ask: "Does this match your expectations? Any changes before I write the code?"
4. **Implement with transparency:**
- If you encounter spec ambiguities during implementation, STOP and ask
- If rules/hooks flag issues, fix them and explain what was wrong
- If a deviation from the design doc is necessary (technical constraint), explicitly call it out
5. **Get approval before writing files:**
- Show the code or a detailed summary
- Explicitly ask: "May I write this to [filepath(s)]?"
- For multi-file changes, list all affected files
- Wait for "yes" before using Write/Edit tools
6. **Complete the story with `/story-done`:**
- When implementation (and tests, if written) is complete, invoke `/story-done [story-file-path]`
- This verifies acceptance criteria, checks for GDD/ADR deviations, prompts code review, and updates the story status
- Do NOT mark a story complete manually — always go through `/story-done`
- If no story file exists for this work (ad-hoc task), offer `/code-review` directly instead
#### Example Interaction Pattern
```
User: "Implement the damage calculation system per design/gdd/combat-system.md"
You (read and analyze):
[Reads design doc]
"I've read the combat system design. The damage formula is:
final_damage = base_damage * weapon_multiplier * crit_multiplier * (1 - resistance)
Before I implement, a few architectural questions:
1. Should DamageCalculator be a static utility or an autoload singleton?
2. Where should weapon data live? (Equipment class? CharacterStats? Separate WeaponData resource?)
3. The design doc doesn't specify rounding behavior. Round down, round up, or keep decimal damage?
4. Should we emit a signal when damage is calculated (for VFX/SFX hookup)?"
User: "Static utility in src/gameplay/combat/. Weapon data in Equipment class. Round down to int. Yes, emit signal."
You (propose architecture):
"Got it. Here's the proposed structure:
```
# src/gameplay/combat/damage_calculator.gd
class_name DamageCalculator
extends RefCounted
signal damage_calculated(target: Node, final_damage: int, is_crit: bool)
static func calculate_damage(attacker: CharacterStats, target: CharacterStats, weapon: Equipment) -> int:
var base_damage: float = attacker.get_attack_power()
var weapon_mult: float = weapon.damage_multiplier
var crit_mult: float = 2.0 if _roll_crit(attacker.crit_chance) else 1.0
var resistance: float = target.get_resistance(weapon.damage_type)
var final_damage: int = floor(base_damage * weapon_mult * crit_mult * (1.0 - resistance))
damage_calculated.emit(target, final_damage, crit_mult > 1.0)
return final_damage
```
Constants like crit_mult (2.0) will move to assets/data/combat_config.json per the data-driven rule.
Does this match your expectations? Any changes before I write the code?"
User: "Looks good. Implement it."
You (implement):
[Writes code]
[gameplay-code rule flags hardcoded crit multiplier]
"Implemented src/gameplay/combat/damage_calculator.gd.
The gameplay-code rule flagged one issue: crit multiplier was hardcoded (2.0).
I moved it to assets/data/combat_config.json as 'critical_damage_multiplier': 2.0.
File is ready. Would you like me to:
A) Write tests now (recommended)
B) Let you review the code first
C) Run /code-review for architecture validation"
User: "A, write tests"
You: [creates tests/combat/test_damage_calculator.gd]
"Created test file with 6 test cases covering the acceptance criteria from the design doc.
All tests passing.
Running /story-done to verify acceptance criteria and close out the story."
[/story-done runs — verifies criteria, checks deviations, prompts code review, updates story status]
```
#### Collaborative Mindset
- Clarify before assuming — specs are never 100% complete
- Propose architecture, don't just implement — show your thinking
- Explain trade-offs transparently — there are always multiple valid approaches
- Flag deviations from design docs explicitly — designer should know if implementation differs
- Rules are your friend — when they flag issues, they're usually right
- Tests prove it works — offer to write them proactively
- Story completion is explicit — use `/story-done` to close every story, never assume done because code is written
#### Structured Decision UI
Use the `AskUserQuestion` tool for architecture decisions and next-step choices.
Follow the **Explain → Capture** pattern:
1. **Explain first** — Describe the architectural options and trade-offs in
conversation text.
2. **Capture the decision** — Call `AskUserQuestion` with concise option labels.
**When to use it:**
- Architecture questions with constrained answers (step 2)
- Next-step choices ("Write tests, review code, or run code-review?")
- Batch up to 4 independent architecture questions in one call
**When NOT to use it:**
- Open-ended spec clarifications — use conversation
- Single confirmations ("May I write to file?")
- When running as a Task subagent — structure text for orchestrator
**Example — architecture questions (batch):**
AskUserQuestion with questions:
1. question: "Where should DamageCalculator live?"
header: "Architecture"
options: "Static Utility (Recommended)", "Autoload Singleton", "Scene Node"
2. question: "How should damage be rounded?"
header: "Rounding"
options: "Floor to Int (Recommended)", "Round to Int", "Keep Decimal"
```
@@ -1,181 +0,0 @@
# Collaborative Protocol for Leadership Agents
Insert this section after the "You are..." introduction and before "Key Responsibilities":
```markdown
### Collaboration Protocol
**You are the highest-level consultant, but the user makes all final strategic decisions.** Your role is to present options, explain trade-offs, and provide expert recommendations — then the user chooses.
#### Strategic Decision Workflow
When the user asks you to make a decision or resolve a conflict:
1. **Understand the full context:**
- Ask questions to understand all perspectives
- Review relevant docs (pillars, constraints, prior decisions)
- Identify what's truly at stake (often deeper than the surface question)
- *Use `AskUserQuestion` to batch up to 4 constrained questions at once*
2. **Frame the decision:**
- State the core question clearly
- Explain why this decision matters (what it affects downstream)
- Identify the evaluation criteria (pillars, budget, quality, scope, vision)
3. **Present 2-3 strategic options:**
- For each option:
- What it means concretely
- Which pillars/goals it serves vs. which it sacrifices
- Downstream consequences (technical, creative, schedule, scope)
- Risks and mitigation strategies
- Real-world examples (how other games handled similar decisions)
- *After the full analysis, use `AskUserQuestion` to capture the decision*
4. **Make a clear recommendation:**
- "I recommend Option [X] because..."
- Explain your reasoning using theory, precedent, and project-specific context
- Acknowledge the trade-offs you're accepting
- But explicitly: "This is your call — you understand your vision best."
5. **Support the user's decision:**
- Once decided, document the decision (ADR, pillar update, vision doc)
- Cascade the decision to affected departments
- Set up validation criteria: "We'll know this was right if..."
#### Example Interaction Pattern
```
User: "The game-designer wants complex crafting but the lead-programmer says it will take 3 weeks and we only have 2 weeks before Alpha. What should we do?"
You (understand context):
"I need to understand both sides fully before making a recommendation.
Let me read:
- design/gdd/crafting-system.md (what's designed)
- production/sprints/sprint-current.md (what's planned)
- design/pillars.md (what's non-negotiable)
[Reads docs]
I also need to clarify:
1. Is crafting a core pillar feature or a nice-to-have?
2. What's the minimum crafting system that still serves the pillar (if it's core)?
3. Can we slip Alpha by 1 week, or is that date hard?
4. What breaks if crafting is cut entirely?"
User: [answers: crafting is pillar 2 "emergent discovery", Alpha date is hard (investor demo), minimum is recipe discovery without complex UI]
You (frame and present options):
"Thank you. Here's the core decision:
**The Question:** Do we deliver full crafting for Alpha, accept schedule slip, or simplify crafting to meet deadline?
**What's at Stake:** This affects:
- Pillar 2 ("Emergent Discovery") representation at the investor demo
- Schedule integrity and team trust
- Technical debt if we rush complex systems
**Option A: Implement Full Crafting (3 weeks, slip Alpha)**
- ✅ Pillar 2 fully represented
- ✅ No design compromises
- ❌ Misses investor demo date
- ❌ May damage relationship with investor
- Risk: High — could lose funding opportunity
**Option B: Simplify Crafting to Core (1.5 weeks, make Alpha)**
- Scope: Recipe discovery only, no UI polish, 10 recipes instead of 30
- ✅ Pillar 2 still represented (core mechanic intact)
- ✅ Makes investor demo
- ✅ Can polish post-Alpha
- ❌ First impression is "rough"
- Risk: Medium — demo may not wow, but pillar is visible
**Option C: Cut Crafting Entirely (0 weeks, make Alpha)**
- ✅ Makes deadline with polish
- ✅ Team focuses on core combat (Pillar 1)
- ❌ Pillar 2 not represented
- ❌ Game identity incomplete
- Risk: High — investor won't see 50% of the vision
**My Recommendation: Option B (Simplify to Core)**
Reasoning:
1. The investor demo needs to show ALL pillars, even if rough. A polished half-game is worse than a playable full-game.
2. Recipe discovery is the SOUL of the crafting pillar — the UI is just presentation. Core > polish for a vertical slice.
3. This protects schedule (team morale) and pillar integrity (investor confidence).
4. We can polish post-Alpha and show progression: "Here's Alpha vs. Beta" is a compelling narrative.
References: Hades showed rough vertical slices in Early Access and iterated — investors loved the pillar demonstration over polish.
Trade-offs I'm accepting: The demo won't look AAA-polished, but it will feel complete.
**But this is your call.** You know the investor relationship better than I do. If they value polish over completeness, Option C might be right. If they're technical and want to see systems depth, Option A might be worth the risk.
What's your decision?"
User: "Option B. Let's simplify the scope."
You (support decision):
"Excellent. I'll document this decision and cascade it:
1. Creating ADR: docs/architecture/adr-005-alpha-crafting-scope-reduction.md
2. Updating design/gdd/crafting-system.md with Alpha scope markers
3. Notifying game-designer and lead-programmer to align on new 1.5-week plan
4. Adding to production/milestones/alpha.md as success criteria: 'Crafting pillar demonstrated via core discovery mechanic'
Validation criteria: We'll know this was right if:
- Investor demo shows both Pillar 1 (combat) and Pillar 2 (discovery) in playable form
- Team hits Alpha deadline without crunch
- Post-Alpha sprint can polish crafting without rework
May I proceed with documentation?"
User: "Yes"
You: [Creates ADR, updates docs, notifies relevant agents]
```
#### Collaborative Mindset
- You provide strategic analysis, the user provides final judgment
- Present options clearly — don't make the user drag it out of you
- Explain trade-offs honestly — acknowledge what each option sacrifices
- Use theory and precedent, but defer to user's contextual knowledge
- Once decided, commit fully — document and cascade the decision
- Set up success metrics — "we'll know this was right if..."
#### Structured Decision UI
Use the `AskUserQuestion` tool to present strategic decisions as a selectable UI.
Follow the **Explain → Capture** pattern:
1. **Explain first** — Write full strategic analysis in conversation: options with
pillar alignment, downstream consequences, risk assessment, recommendation.
2. **Capture the decision** — Call `AskUserQuestion` with concise option labels.
**When to use it:**
- Every strategic decision point (options in step 3, context questions in step 1)
- Batch up to 4 independent questions in one call
- Next-step choices after a decision is made
**When NOT to use it:**
- Open-ended context gathering ("Tell me about the investor relationship")
- Single confirmations ("May I document this decision?")
- When running as a Task subagent — structure text for orchestrator
**Format guidelines:**
- Labels: 1-5 words. Descriptions: 1 sentence with key trade-off.
- Add "(Recommended)" to your preferred option's label
- Use `markdown` previews for comparing architectural approaches
**Example — strategic decision (after full analysis in conversation):**
AskUserQuestion with questions:
1. question: "How should we handle crafting scope for Alpha?"
header: "Scope"
options:
"Simplify to Core (Recommended)" — makes deadline, pillar visible
"Full Implementation" — slips Alpha by 1 week
"Cut Entirely" — deadline met, pillar missing
```
+41
View File
@@ -0,0 +1,41 @@
# Game Brief: [Working Title]
<!--
THE ONE-PAGE BRIEF. At the `minimal` workflow tier this is the ENTIRE design doc —
it replaces the full concept doc, systems decomposition, and per-system GDDs.
Keep it to one screen. If a field needs a second paragraph, you're writing a GDD,
not a brief. Fill every REQUIRED field; the two RECOMMENDED one-liners are cheap
but optional. Engine is set separately (project.yaml / /setup-engine) — don't restate it.
Field set grounded in industry practice — Tim Ryan (*Anatomy of a Design Document*),
Stone Librande (GDC *One-Page Designs*: the one-page constraint forces the real
thinking and cuts ceremony), and lean/agile GDD practice.
-->
**One-sentence pitch:** [Describe the game in one excited sentence. If it takes two, cut until it's one — "the longer your pitch, the more diluted your vision."]
## Core loop
<!-- The cycle the player repeats. What they do → what they get → why they do it again. 2–4 bullets. -->
-
## Player goal & fail state — what "working" looks like
<!-- What the player is trying to achieve (the win, the score, or the point) and how a run ends or fails. Even a cozy or sandbox game has a "a session feels complete when…". This is the one field your stories' ACCEPTANCE CRITERIA trace back to — it turns "the game works" into something testable. One or two lines. -->
-
## MVP — what must exist to be the game
<!-- The ruthlessly short list of features without which this ISN'T the game yet. Each one becomes a story. Longer than ~7 and it's not an MVP. -->
-
## Out of scope — not building this
<!-- What you're deliberately NOT doing. The list that saves the project. Be specific: "no multiplayer", "no save system", "one level only". -->
-
## Build order
<!-- The sequence to build the MVP. Risky / core-fun thing FIRST — prove it's fun before you polish. -->
1.
---
<!-- RECOMMENDED — one line each, delete a line only if it's truly N/A for this game. -->
**Who it's for / what they feel:** [One line: the player and the feeling. e.g. "solo puzzle fans who want a cozy 20-minute sitting."]
**Art & audio direction:** [One line of aesthetic intent — drives asset choices. e.g. "flat pastel vector art, lo-fi ambient."]
@@ -0,0 +1,210 @@
> Authoring guidance for accessibility-requirements.md. Load only the part covering the section currently being authored — not the whole file at once.
# Accessibility Requirements Template — Authoring Guidance
Guidance is organized by template section. When authoring a section of a
project's accessibility requirements document, read only that section's
guidance below. The feature tables themselves (Visual / Motor / Cognitive /
Auditory), the platform API table, the test plan, and the external resources
remain in the template — they are the requirement catalog, not guidance.
---
## Accessibility Tier Definition
> **Why define tiers**: Accessibility is not binary. Defining four tiers gives
> the team a shared vocabulary, forces an explicit commitment at the start of
> production, and prevents scope creep in both directions ("we'll add it later"
> and "we have to support everything"). The tiers below are this project's
> definitions — the industry uses similar but not identical language. Commit to
> a tier with specific feature targets, not just the tier name.
**Authoring the commitment rationale**:
[Write 3-5 sentences justifying the tier choice. Do not simply
state the tier — explain the reasoning. Consider: What is the game's genre and
how does it map to common accessibility barriers (e.g., fast-twitch games have
motor barriers; reading-heavy games have visual barriers)? Who is the target
player and what does the research say about disability prevalence in that group?
What are the platform requirements (Xbox requires XAG compliance for ID@Xbox)?
What is the team's capacity? What would dropping one tier cost the player base,
in concrete terms?
Example: "This is a narrative RPG with turn-based combat targeted at players
25-45. The turn-based structure eliminates the most severe motor barriers common
in action games, but the reading-heavy design creates significant visual and
cognitive barriers. Standard tier addresses all of these. Exemplary tier is not
achievable without a dedicated accessibility engineer. Xbox ID@Xbox program
requires XAG compliance for Game Pass consideration, which Standard meets.
Dropping to Basic would exclude players who rely on colorblind modes or input
remapping, estimated at 8-12% of the target audience based on AbleGamers data."]
**Example in-scope / out-of-scope entries**:
Features explicitly in scope (beyond tier baseline):
- [e.g., "Full subtitle customization — elevated from Comprehensive because our
game is dialogue-heavy and subtitles are a primary channel"]
- [e.g., "One-hand mode for controller — we have hold inputs critical to combat"]
Features explicitly out of scope:
- [e.g., "Screen reader for in-game world (not menus) — requires engine work
beyond current capacity. Documented in Known Intentional Limitations."]
---
## Visual Accessibility
> **Why this section comes first**: Visual impairments affect the largest
> proportion of players who use accessibility features. Color vision deficiency
> alone affects approximately 8% of men and 0.5% of women. Text legibility at
> TV viewing distance is frequently the single largest accessibility failure
> in shipped games. Document every visual feature before implementation begins,
> because retrofitting minimum text sizes or color decisions after assets are
> locked is expensive.
**Worked example rows — Color-as-Only-Indicator Audit**:
| Location | Color Signal | What It Communicates | Non-Color Backup | Status |
|----------|-------------|---------------------|-----------------|--------|
| [Health bar] | [Red = low health] | [Player is near death] | [Bar also shows numeric value and flashes] | [Not Started] |
| [Minimap markers] | [Red = enemy, green = ally] | [Unit allegiance] | [Enemy markers are triangles; ally markers are circles] | [Not Started] |
| [Inventory item rarity] | [Color-coded border (grey/blue/purple/gold)] | [Item quality tier] | [Rarity name shown on hover/focus; icon star count] | [Not Started] |
---
## Motor Accessibility
> **Why motor accessibility matters for games**: Games are more motor-demanding
> than most software. A web form requires precise clicks; a game may require
> rapid simultaneous button combinations held for specific durations. Motor
> impairments span a wide range — from tremor (affecting precision) to
> hemiplegia (one functional hand) to RSI (affecting hold duration). The AbleGamers
> Able Assistance program estimates 35 million gamers in the US have a disability
> affecting their ability to play. Many of the features below cost very little
> to implement if planned from the start, and are extremely expensive to add post-launch.
---
## Cognitive Accessibility
> **Why cognitive accessibility is often under-specced**: Cognitive accessibility
> affects players with ADHD, dyslexia, autism spectrum conditions, acquired brain
> injuries, and anxiety disorders — a larger combined population than many studios
> realize. It also benefits all players in high-stress moments. The most common
> failures are: no pause anywhere, tutorial information that can only be seen once,
> and systems that require tracking too many simultaneous states. Games like
> Hades and Celeste have demonstrated that cognitive assist options (god mode,
> persistent reminders, extended text display) do not harm the experience for
> players who don't use them.
---
## Auditory Accessibility
> **Why auditory accessibility matters even for players without hearing loss**:
> 7% of players are deaf or hard of hearing. Additionally, a large portion of
> players regularly play in environments where audio is reduced or absent (commute,
> shared household, infant sleeping). Any gameplay-critical information delivered
> only through audio is a design failure even before accessibility is considered.
> The guiding principle: every sound that changes what the player should DO next
> must have a visual equivalent.
**Worked example rows — Gameplay-Critical SFX Audit**:
| Sound Effect | What It Communicates | Visual Backup | Caption Required | Status |
|-------------|---------------------|--------------|-----------------|--------|
| [Enemy attack windup sound] | [Incoming damage — player should dodge] | [Enemy animation telegraph visible from all camera angles] | [No — visual is sufficient] | [Not Started] |
| [Trap trigger click] | [Trap is about to fire] | [Not always visible depending on camera angle] | [Yes — "[CLICK]" caption with directional indicator] | [Not Started] |
| [Low health heartbeat] | [Player health critical] | [Health bar also shows critical state visually] | [No — visual is sufficient] | [Not Started] |
| [Quest completion chime] | [Objective completed] | [Quest tracker updates visually] | [No — visual is sufficient] | [Not Started] |
---
## Platform Accessibility API Integration
> **Why this section exists**: Each platform provides native accessibility APIs
> that, when used, allow OS-level features (system screen readers, display
> accommodations, motor accessibility services) to work with your game. Ignoring
> these APIs does not break the game, but it means players who rely on OS-level
> accessibility tools get no benefit from them inside your game. Xbox in particular
> requires XAG compliance for certification. Verify platform requirements before
> committing to a tier — platform requirements set a floor, not a ceiling.
---
## Per-Feature Accessibility Matrix
> **Why this matrix exists**: Accessibility is not a list of settings — it is a
> property of every game system. This matrix creates the "accessibility impact"
> view of the game: which systems have which barriers, and whether those barriers
> are addressed. When a new system is added to systems-index.md, a row must be
> added here. If a system has an unaddressed accessibility concern, it cannot be
> marked Approved in the systems index.
**Worked example rows**:
| System | Visual Concerns | Motor Concerns | Cognitive Concerns | Auditory Concerns | Addressed | Notes |
|--------|----------------|---------------|-------------------|------------------|-----------|-------|
| [Combat System] | [Enemy health bars are color-coded; attack animations may cause motion sickness] | [Rapid input required for combos; hold inputs for guard] | [Track enemy patterns + cooldowns + player resources simultaneously] | [Audio cues for off-screen attacks; critical damage warning sounds] | [Partial] | [Colorblind palette applied; hold-to-block toggle needed] |
| [Inventory / Equipment] | [Item rarity conveyed by border color] | [No motor concerns — turn-based] | [Item stats comparison requires reading multiple values] | [None — no critical audio in this system] | [Partial] | [Non-color rarity indicators in progress] |
| [Dialogue System] | [Subtitle display depends on contrast settings] | [No motor concerns] | [Long dialogue trees with time pressure on dialogue choices] | [All dialogue must be subtitled] | [Not Started] | [Timed dialogue choices must support extended timer option] |
| [Navigation / World Map] | [Map marker colors] | [No motor concerns] | [Quest objective clarity; waypoint visibility] | [Audio pings for objectives have no visual equivalent] | [Not Started] | |
---
## Accessibility Test Plan
> **Why testing accessibility separately from QA**: Standard QA tests whether
> features work. Accessibility testing tests whether features work for players
> who use them. These are different tests. A subtitle system can pass QA (it
> displays text) and fail accessibility testing (the text is unreadable at TV
> distance by a player with low vision). Plan for three test types: automated
> (contrast ratios, text sizes), manual internal (team members simulating
> impairments using accessibility simulators), and user testing (players who
> actually use these features).
---
## Known Intentional Limitations
> **Why document what is NOT included**: Omissions left undocumented become
> surprises at certification or in community feedback. Documenting a limitation
> with a rationale demonstrates that it was a deliberate choice, not an oversight.
> It also identifies which players are not served and what the mitigation is.
> Every entry here is a risk — assess it honestly.
**Worked example rows**:
| Feature | Tier Required | Why Not Included | Risk / Impact | Mitigation |
|---------|--------------|-----------------|--------------|------------|
| [Screen reader support for in-game world (NPCs, objects, environmental text)] | Exemplary | Engine (Godot 4.6) AccessKit integration covers menus only; extending to the game world requires a custom spatial audio description system beyond current scope | Affects blind and low-vision players who can navigate menus but cannot independently explore the game world | Ensure all critical world information is duplicated in accessible menu systems (quest log, map); evaluate for post-launch DLC |
| [Full subtitle customization (font/color/background)] | Comprehensive | Scope reduction — targeting Standard tier. Custom font rendering in Godot requires additional asset pipeline work | Affects deaf and hard-of-hearing players with specific legibility needs; particularly affects players with dyslexia who use custom fonts | Provide two preset subtitle styles (default and high-readability) as a partial mitigation; log for post-launch update |
| [Tactile/haptic alternatives for all audio cues] | Exemplary | Platform rumble API integration for non-Xbox platforms is out of scope for v1.0 | Affects deaf players relying on haptic feedback; PC players with non-Xbox controllers get no haptic response | Xbox controller haptic integration is in scope; evaluate PlayStation DualSense haptic API for a post-launch patch |
---
## Audit History
> **Why track audit history**: Accessibility is not certified once and done.
> Platform requirements change. New features may introduce new barriers. Legal
> standards evolve. An audit history demonstrates due diligence and helps identify
> regressions between audits.
**Worked example rows**:
| Date | Auditor | Type | Scope | Findings Summary | Status |
|------|---------|------|-------|-----------------|--------|
| [Date] | [Internal — ux-designer] | Internal review | [Pre-submission checklist against committed tier] | [e.g., "12 items verified, 3 open issues: subtitle contrast below target in 2 scenes, color-only indicator on minimap not resolved"] | [In Progress] |
| [Date] | [External — AbleGamers Player Panel] | User testing | [Motor accessibility — one-hand mode and timing adjustments] | [e.g., "Toggle modes functional. Timed QTE window at 3x still failed for one participant — recommend 5x option."] | [Findings addressed] |
---
## Open Questions
**Worked example questions**:
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [Does Godot 4.6 AccessKit support dynamic accessibility node updates for HUD elements, or only static menus?] | [ux-designer] | [Before Technical Setup gate] | [Unresolved — check engine-reference/godot/ docs] |
| [What is the Xbox ID@Xbox minimum XAG compliance requirement for our release window?] | [producer] | [Before Pre-Production gate] | [Unresolved] |
| [Will the dialogue system support timed choice extensions without a full architecture change?] | [lead-programmer] | [During Technical Design] | [Unresolved] |
+380
View File
@@ -0,0 +1,380 @@
> Authoring guidance for hud-design.md. Load only the part covering the section currently being authored — not the whole file at once.
# HUD Design Template — Authoring Guidance
Guidance is organized by template section number. When authoring a section of a
project's HUD design document, read only that section's guidance below.
---
## Section 1 — HUD Philosophy
> **Why this section exists**: The HUD design philosophy is not decoration — it is a
> design constraint that every subsequent decision is measured against. Without a
> philosophy, individual elements get added on request ("the quest tracker wants a
> bigger icon") without any principled way to push back. With a philosophy, there is
> a shared, explicit standard. More importantly, the philosophy prevents the HUD from
> slowly growing to cover the game world while each individual addition seemed
> reasonable in isolation. Write this before specifying any elements.
**Authoring the philosophy statement**:
[One paragraph. This is a design statement, not a description of features. Consider
the game's genre, pacing, and player fantasy. A stealth game's HUD philosophy might
be: "The world is the interface. If the player has to look away from the environment
to survive, the HUD has failed." A tactics game might say: "Complete situational
awareness is the game. The HUD is not an overlay — it is the battlefield."
Reference comparable games if helpful, but describe your specific stance:
Example — diegetic-first action RPG: "We treat screen information as a concession,
not a feature. Every HUD element must earn its pixel space by answering the question:
would the player make demonstrably worse decisions without this information visible?
If the answer is 'they'd adapt,' we put it in the environment instead."]
**Authoring the visibility principle**:
[State the default resolution for ambiguous cases. Options:
- Default to HIDE: information is available on demand (e.g., Dark Souls — no quest tracker, no minimap, stats are in a menu)
- Default to SHOW: players prefer to be informed; cluttered is better than uncertain
- Default to CONTEXTUAL: information appears when it becomes relevant and fades when it does not
Most games benefit from contextual defaults. State your game's default clearly so every element decision is consistent.]
**Authoring the Rule of Necessity**:
[Complete this sentence: "A HUD element earns its place when ______________."
Example: "...the player would have to stop playing to find the same information
elsewhere, or would make meaningfully worse decisions without it."
Example: "...removing it in playtesting causes measurable frustration or confusion
in more than 25% of testers within the first hour of play."
This rule is the veto power over feature requests to add HUD elements. Document it
so it can be cited in design reviews.]
---
## Section 2 — Information Architecture
> **Why this section exists**: Before specifying any HUD element's visual design,
> position, or behavior, you must answer a more fundamental question: should this
> information be on the HUD at all? This section is a forcing function — it requires
> you to categorize EVERY piece of information the game world generates and make an
> explicit, intentional decision about how each is presented. "We'll figure that out
> later" is how games end up with 18 elements competing for the player's peripheral
> vision. This table is the master inventory of game information, not just HUD information.
**Worked example table** (typical information types and categorization reasoning):
| Information Type | Always Show | Contextual (show when relevant) | On Demand (menu/button) | Hidden (environmental / diegetic) | Reasoning |
|-----------------|-------------|--------------------------------|------------------------|----------------------------------|-----------|
| [Health / Vitality] | [X if action game — player needs constant awareness] | [X if exploration game — show only when injured] | [ ] | [ ] | [Example: always visible because health decisions (retreat, heal) must be instant in combat] |
| [Primary resource (mana / stamina / ammo)] | [ ] | [X — show when resource is being consumed or is critically low] | [ ] | [ ] | [Example: contextual because stable resource levels are not decision-relevant] |
| [Secondary resource (currency / materials)] | [ ] | [ ] | [X — check in inventory] | [ ] | [Example: on-demand because resource totals don't affect immediate gameplay decisions] |
| [Minimap / Compass] | [X] | [ ] | [ ] | [ ] | [Example: always visible because navigation decisions are constant during exploration] |
| [Quest objective] | [ ] | [X — show when objective changes or player is near it] | [ ] | [ ] | [Example: contextual — player knows their objective; only remind at key moments] |
| [Enemy health bar] | [ ] | [X — show only during combat encounters] | [ ] | [ ] | [Example: contextual because enemy health is irrelevant outside combat] |
| [Status effects (buffs/debuffs)] | [ ] | [X — show when active] | [ ] | [ ] | [Example: contextual because status effects only affect decisions when present] |
| [Dialogue subtitles] | [X when dialogue is playing] | [ ] | [ ] | [ ] | [Example: always show while dialogue is active — accessibility requirement] |
| [Combo / streak counter] | [ ] | [X — show while combo is active, hide on reset] | [ ] | [ ] | [Example: contextual because it communicates active performance, not baseline state] |
| [Timer] | [ ] | [X — show only in timed sequences] | [ ] | [ ] | [Example: contextual because timers only exist in specific encounter types] |
| [Tutorial prompts] | [ ] | [X — show for first-time situations only] | [ ] | [ ] | [Example: contextual and one-time; never repeat to experienced players] |
| [Score / points] | [ ] | [X — show in score-relevant modes only] | [ ] | [ ] | [Example: contextual by game mode; hidden in modes where score is irrelevant] |
| [XP / level progress] | [ ] | [ ] | [X — available via character screen] | [ ] | [Example: on-demand because progression does not affect in-moment gameplay decisions] |
| [Waypoint / objective marker] | [ ] | [X — show when player is navigating to objective] | [ ] | [ ] | [Example: contextual — suppress during cutscenes, cinematic moments, and free exploration] |
---
## Section 3 — Layout Zones
> **Why this section exists**: The game world is the primary content — the HUD is a
> frame around it. Before placing any element, divide the screen into named zones
> with explicit positions and safe zone margins. This section prevents two failure
> modes: (1) elements placed ad-hoc until the screen is cluttered, and (2) elements
> that overlap platform-required safe zones and get rejected in certification.
> Every element in Section 4 must be assigned to a zone defined here.
**Worked example — zone specification table**:
| Zone Name | Screen Position | Safe Zone Compliant | Primary Elements | Max Simultaneous Elements | Notes |
|-----------|----------------|---------------------|-----------------|--------------------------|-------|
| [Top Left] | [Top-left corner, within safe margin] | [Yes — 10% from top, 10% from left] | [Health bar, stamina bar, shield bar] | [3] | [Vital status — player's own resources. Priority zone for player state.] |
| [Top Center] | [Top edge, centered horizontally] | [Yes — 10% from top] | [Quest objective, area name (on enter)] | [1 — only one message at a time] | [Use for narrative context, not mechanical information. Keep text minimal.] |
| [Top Right] | [Top-right corner, within safe margin] | [Yes — 10% from top, 10% from right] | [Ammo count, ability cooldowns] | [2] | [Weapon/ability state. Most relevant during active combat.] |
| [Center] | [Screen center ±15%] | [N/A — not a margin zone] | [Crosshair, interaction prompt, hit marker] | [1 active at a time] | [CRITICAL: Nothing persistent here. Only momentary indicators.] |
| [Bottom Left] | [Bottom-left corner, within safe margin] | [Yes — 10% from bottom, 10% from left] | [Minimap, ability icons] | [2] | [Navigation and ability readout. Small, non-intrusive.] |
| [Bottom Center] | [Bottom edge, centered horizontally] | [Yes — 10% from bottom] | [Subtitles, tutorial prompts] | [2 — subtitle + tutorial may coexist] | [Highest-priority accessibility zone. Never place other elements here.] |
| [Bottom Right] | [Bottom-right corner, within safe margin] | [Yes — 10% from bottom, 10% from right] | [Notification toasts, pick-up feedback] | [3 stacked] | [Transient notifications. Stack vertically. Oldest disappears first.] |
**Worked example — safe zone margins by platform**:
| Platform | Top | Bottom | Left | Right | Notes |
|----------|-----|--------|------|-------|-------|
| [PC — windowed] | [0% — no safe zone required] | [0%] | [0%] | [0%] | [But respect minimum resolution — elements must not crowd at 1280x720] |
| [PC — fullscreen] | [3%] | [3%] | [3%] | [3%] | [Slight margin for 4K TV-connected PCs] |
| [Console — TV] | [10%] | [10%] | [10%] | [10%] | [Action-safe zone for broadcast-spec TVs. Some TVs overscan beyond this.] |
| [Steam Deck] | [5%] | [5%] | [5%] | [5%] | [Small screen; safe zone is smaller but crowding risk is higher] |
| [Mobile — portrait] | [15% top] | [10% bottom] | [5%] | [5%] | [15% top avoids notch/camera cutout on most devices] |
| [Mobile — landscape] | [5%] | [5%] | [15% left] | [15% right] | [Thumb placement on landscape — side zones are obscured by hands] |
---
## Section 4 — HUD Element Specifications
> **Why this section exists**: Each HUD element needs its own specification to be
> built correctly. Ad-hoc implementation of HUD elements produces inconsistent
> sizing, mismatched update frequencies, missing urgency states, and accessibility
> failures. This section is the implementation brief for every element — fill it
> completely before any element moves into development.
**Worked example — element overview table (4.1)**:
| Element Name | Zone | Always Visible | Visibility Trigger | Data Source | Update Frequency | Max Size (% screen W) | Min Readable Size | Overlap Priority | Accessibility Alt |
|-------------|------|---------------|-------------------|-------------|-----------------|----------------------|------------------|-----------------|------------------|
| [Health Bar] | [Top Left] | [Yes] | [N/A] | [PlayerStats] | [On value change] | [20%] | [120px wide] | [1 — highest] | [Numerical text label showing current/max: "80/100"] |
| [Stamina Bar] | [Top Left] | [No — context] | [Show when consuming stamina; hide 3s after full] | [PlayerStats] | [Realtime during use] | [15%] | [80px wide] | [2] | [Numerical label, or hide if full (accessible assumption)] |
| [Shield Indicator] | [Top Left] | [No — context] | [Show when shield is active or recently hit] | [PlayerStats] | [On value change] | [20%] | [120px wide] | [3] | [Numerical label. Must not use color alone — add shield icon.] |
| [Ammo Counter] | [Top Right] | [No — context] | [Show when weapon is equipped; hide when unarmed] | [WeaponSystem] | [On fire / on reload] | [10%] | ["88/888" readable at game's min resolution] | [4] | [Text-only fallback: "32 / 120"] |
| [Minimap] | [Bottom Left] | [Yes] | [N/A — but suppressed in cinematic mode] | [NavigationSystem] | [Realtime] | [18%] | [150x150px] | [5] | [Cardinal direction compass strip as fallback; must be toggleable] |
| [Quest Objective] | [Top Center] | [No — context] | [Show on objective change; show when near objective location; hide after 5s] | [QuestSystem] | [On event] | [30%] | [Legible at body text size] | [6] | [Read aloud on objective change via screen reader] |
| [Crosshair] | [Center] | [No — context] | [Show when ranged weapon equipped; hide in melee or unarmed] | [WeaponSystem / AimSystem] | [Realtime] | [3%] | [12px diameter minimum] | [1 — center zone priority] | [Reduce motion: static crosshair only. Option to enlarge.] |
| [Interaction Prompt] | [Center] | [No — context] | [Show when player is within interaction range of an interactive object] | [InteractionSystem] | [On enter/exit interaction range] | [15%] | [24px icon + readable text] | [2 — center zone] | [Text description of interaction always present, not icon-only] |
| [Subtitles] | [Bottom Center] | [No — always on when dialogue plays, if setting enabled] | [Show during any voiced line or ambient dialogue] | [DialogueSystem] | [Per dialogue line] | [60%] | [Minimum 24px font] | [1 — highest in zone] | [This IS the accessibility feature — see Section 8 for subtitle spec] |
| [Damage Numbers] | [World-space / anchored to entity] | [No — context] | [Show on any damage event; duration 800ms] | [CombatSystem] | [On event] | [5% per number] | [18px minimum] | [3] | [Option to disable; numbers can overwhelm for photosensitive players] |
| [Status Effect Icons] | [Top Left — below health bar] | [No — context] | [Show when any status effect is active on player] | [StatusSystem] | [On effect add/remove] | [3% per icon] | [24px per icon] | [3] | [Icon + text label on hover/focus. Never icon-only.] |
| [Notification Toast] | [Bottom Right] | [No — event-driven] | [On loot, XP gain, achievement, quest update] | [Multiple — see Section 6] | [On event] | [25%] | [Legible at body text size] | [7 — lowest] | [Queued; never overlapping. Read by screen reader if subtitle mode on.] |
**Worked example — element detail blocks (4.2)**:
---
**Health Bar**
- Visual description: [Horizontal fill bar. Left-to-right fill direction. Segmented at 25/50/75% to aid reading at a glance. Background: dark semi-transparent (40% opacity). Fill color: context-dependent — see Urgency States.]
- Data displayed: [Current HP as fill percentage. Numerical value displayed as text below bar at all times: "80 / 100".]
- Update behavior: [Bar fill decreases or increases smoothly using a lerp over 150ms per change. Large damage (>25% single hit) triggers a brief flash (1 frame white, then drain).]
- Urgency states:
- Normal (>50% HP): [Green fill, no special behavior]
- Caution (25–50% HP): [Yellow fill, low warning pulse every 4 seconds]
- Critical (<25% HP): [Red fill, persistent slow pulse (1 Hz), vignette appears at screen edges]
- Zero (0% HP): [Bar empties and turns grey; death state begins]
- Interaction: [Display only. Not interactive. Player cannot click, hover, or focus this element as an action target.]
- Player customization: [Opacity adjustable (see Section 7 Tuning Knobs). Can be repositioned to any corner by player in accessibility settings.]
---
**Minimap**
- Visual description: [Circular mask, radius = 75px at reference resolution 1920x1080. Player icon at center. North always up unless player has unlocked "Rotate minimap" setting. Range = configurable, default 80 world units radius.]
- Data displayed: [Player position, nearby enemies (if detection perk unlocked), quest markers within range, points of interest icons, traversal obstacles (walls, drops).]
- Update behavior: [Realtime. Updates every frame. Enemy icons fade in/out as they enter/leave detection range over 300ms.]
- Urgency states: [None for the map itself. Enemy icons turn red when they are in combat-alert state.]
- Interaction: [Not interactive in-game. Press dedicated Map button to open the full map screen (separate UX spec).]
- Player customization: [Size: S/M/L (70/90/110px radius). Opacity: 30–100%. Rotation: locked-north or player-relative. Can be disabled entirely (compass strip shows as fallback).]
---
## Section 5 — HUD States by Gameplay Context
> **Why this section exists**: The HUD is not a static overlay — it is a dynamic
> system that must adapt to what the player is doing. A HUD designed only for
> standard gameplay will look wrong in cutscenes, feel cluttered in exploration,
> and occlude critical information in boss fights. This section defines the
> transformations the HUD undergoes in each gameplay context. It is also the spec
> for the system that manages HUD visibility — the HUD state machine.
**Worked example table**:
| Context | Elements Shown | Elements Hidden | Elements Modified | Transition Into This State |
|---------|---------------|-----------------|------------------|---------------------------|
| [Exploration — no threats] | [Minimap, Quest Objective (faded, 60%), Subtitles (if active)] | [Ammo Counter, Crosshair, Damage Numbers, Status Effects (if none active)] | [Health Bar fades to 40% opacity — visible but not dominant] | [Fade transition, 500ms, when no enemies detected for 10s] |
| [Combat — active threat] | [Health Bar (full opacity), Stamina Bar (when used), Ammo Counter, Crosshair, Damage Numbers, Status Effects, Enemy Health Bars] | [Quest Objective (temporarily hidden), Notification Toasts (paused queue)] | [Minimap scales down 15% and raises opacity to 100%] | [Immediate snap in on first enemy detection — no fade. Combat readiness requires instant info.] |
| [Dialogue / Cutscene] | [Subtitles, Dialogue speaker name] | [All gameplay HUD elements: health, ammo, minimap, crosshair, damage numbers] | [N/A] | [All gameplay elements fade out over 300ms when cutscene flag is set] |
| [Cinematic (scripted camera sequence)] | [Subtitles only] | [Everything else including speaker name] | [Letterbox bars appear (if applicable to this game's style)] | [Immediate on cinematic flag; letterbox slides in from top/bottom over 400ms] |
| [Inventory / Menu open] | [None — inventory renders full-screen or as overlay] | [All HUD elements] | [Game world visible but paused behind inventory screen] | [All HUD elements hide over 150ms as menu opens] |
| [Death / Respawn pending] | [Death screen overlay — separate spec] | [All gameplay HUD elements] | [Screen desaturates and darkens over 800ms] | [Death state begins when HP reaches 0 — HUD elements fade over 600ms] |
| [Loading / Transition] | [Loading indicator, tip text] | [All gameplay HUD elements] | [N/A] | [Instant on level transition trigger] |
| [Tutorial — new mechanic] | [Standard context HUD + Tutorial Prompt overlay] | [Nothing additional hidden] | [Tutorial prompt dims background subtly to draw attention to prompt] | [Tutorial system fires ShowTutorial event; prompt fades in over 200ms] |
| [Boss Encounter] | [Boss health bar appears (large, bottom of screen or top center), all combat elements] | [Quest Objective] | [Boss bar renders in a distinct visual style — must not be confused with player health] | [Boss health bar slides in on boss encounter trigger over 400ms] |
---
## Section 6 — Information Hierarchy
> **Why this section exists**: Not all HUD information is equally important. When
> screen space is limited, when the player is under high stress, or when elements
> compete for the same zone, there must be a principled priority order that governs
> which elements survive and which get suppressed. This section formalizes that
> hierarchy so it can be enforced systematically and not just "feels obvious" decisions
> made at implementation time.
**Worked example table**:
| Element | Priority Tier | Reasoning | What Replaces It If Hidden |
|---------|--------------|-----------|---------------------------|
| [Subtitles] | [MUST KEEP — never hide during dialogue] | [Accessibility requirement. Legal requirement in some markets. Story clarity.] | [N/A — nothing replaces subtitles] |
| [Health Bar] | [MUST KEEP — during any state where the player can be damaged] | [Without health visibility, survival decisions become impossible] | [Auditory cues (heartbeat, breathing) supplement but do not replace] |
| [Crosshair] | [MUST KEEP — while aiming with a ranged weapon] | [Targeting without a crosshair is a precision failure, not a difficulty feature] | [Alternative: dot-only mode for minimalists; never fully hidden while aiming] |
| [Interaction Prompt] | [MUST KEEP — when player is in interaction range] | [Without it, interactive objects are invisible to the player] | [Environmental visual cues can supplement but interaction affordance must be explicit] |
| [Ammo Counter] | [SHOULD KEEP] | [Low ammo decisions (switch weapon, reload) require awareness; can be contextual] | [Auditory "click" on empty chamber is acceptable fallback for experienced players] |
| [Minimap] | [SHOULD KEEP] | [Navigation requires spatial awareness; loss forces repeated map opens] | [Compass strip (simplified directional indicator) is acceptable fallback] |
| [Status Effects] | [SHOULD KEEP — while active] | [Active debuffs change what actions are viable; invisible debuffs feel unfair] | [Character animation states can partially communicate status effects (limping, sparks)] |
| [Quest Objective] | [CAN HIDE] | [Player can hold objective in memory for extended periods; contextual is correct default] | [Player remembers objective from context] |
| [Damage Numbers] | [CAN HIDE] | [Feedback element, not decision-critical. Many players turn these off.] | [Hit sounds and enemy reactions communicate hit registration] |
| [Notification Toasts] | [CAN HIDE in high-intensity moments] | [Mid-combat "You gained 50 XP" is noise, not signal. Queue and show after combat.] | [Queue held and released when combat ends] |
| [Combo Counter] | [ALWAYS HIDE when combo resets or player is not attacking] | [Stale combo information is actively misleading] | [N/A — simply hidden] |
---
## Section 7 — Visual Budget
> **Why this section exists**: Without explicit budget constraints, HUD elements
> accumulate until the game world is nearly invisible. These numbers are hard limits,
> not guidelines. Every element addition that would breach a limit requires explicit
> approval and must displace or reduce an existing element.
> **How to apply these budgets**: For every new HUD element proposed during
> production, require the proposer to state (1) which budget line it affects,
> (2) what the new total will be, and (3) what existing element will be reduced or
> made contextual to stay within budget. "It's a small icon" is not an analysis.
---
## Section 8 — Feedback & Notification Systems
> **Why this section exists**: Notifications are the most frequently-added and
> worst-controlled part of most HUDs. Every system wants to tell the player
> something. Without explicit rules about notification priority, stacking limits,
> and queue behavior, the notification zone becomes a firehose of overlapping
> toasts that players learn to ignore entirely. This section establishes the
> notification contract for all systems.
**Worked example table**:
| Notification Type | Trigger System | Screen Position | Duration (ms) | Animation In / Out | Max Simultaneous | Priority | Queue Behavior | Dismissible? |
|------------------|---------------|-----------------|--------------|-------------------|-----------------|----------|---------------|-------------|
| [Item Pickup] | [InventorySystem] | [Bottom Right — toast] | [2000] | [Slide in from right 200ms / fade out 300ms] | [3 stacked] | [Low] | [FIFO queue; older toasts pushed up as new ones enter] | [No — auto-dismiss] |
| [XP Gain] | [ProgressionSystem] | [Bottom Right — toast, below item toasts] | [1500] | [Fade in 150ms / fade out 300ms] | [1 — XP messages merge: "XP +150"] | [Very Low — suppress during combat, queue for post-combat] | [Combat-aware queue] | [No] |
| [Level Up] | [ProgressionSystem] | [Center screen — persistent until dismissed] | [Persistent — requires input to dismiss] | [Scale up from 80% + fade in 400ms] | [1] | [High — interrupts normal toasts] | [Pauses all other notifications until dismissed] | [Yes — any input] |
| [Quest Update] | [QuestSystem] | [Top Center] | [4000] | [Slide down from top 250ms / fade out 400ms] | [1 — top center is single-message zone] | [Medium] | [If quest update arrives while previous is visible, extend duration by 2000ms; do not stack] | [No] |
| [Objective Complete] | [QuestSystem] | [Top Center] | [3000] | [Same as Quest Update but with additional completion sound] | [1] | [Medium-High — preempts Quest Update] | [Preempts any queued top-center message] | [No] |
| [Critical Warning (low health, hazard)] | [CombatSystem / EnvironmentSystem] | [Screen edge vignette + text at center-bottom] | [Persistent while condition active] | [Fade in 200ms; fades out 500ms when condition clears] | [1 per warning type] | [Critical — never suppressed] | [Renders immediately, bypasses all queues] | [No] |
| [Achievement Unlocked] | [AchievementSystem] | [Bottom Right — distinct from item toasts] | [4000] | [Slide in from right with icon expansion 300ms / fade out 400ms] | [1] | [Low] | [Queues behind item toasts; never more than one achievement toast at a time] | [No] |
| [Hint / Tutorial] | [TutorialSystem] | [Bottom Center] | [Persistent — until player performs the action or dismisses] | [Fade in 300ms] | [1] | [Medium] | [Only one tutorial hint at a time; queue others] | [Yes — B button / Esc] |
**Worked example — notification queue rules**:
1. Combat-aware queue: notifications tagged as Low priority are queued, not displayed, when the player is in combat state. The queue is flushed in a batch when the player exits combat, with a max of 3 items displayed in sequence.
2. Merge rule: identical notification types that fire within 500ms of each other are merged into a single notification with a combined value (e.g., "Item Pickup x3" rather than three separate toasts).
3. Critical notifications (health warning, environmental hazard) are never queued, never merged, and always displayed immediately regardless of combat state or existing notifications.
---
## Section 9 — Platform Adaptation
> **Why this section exists**: A HUD designed at 1920x1080 on a monitor may be
> illegible on a 55-inch TV at 4K, broken at 1280x720 on Steam Deck, or hidden
> behind a notch on mobile. Platform adaptation is not optional post-ship work —
> it is a design requirement that must be specified before implementation so the
> architecture can support it from the start. Every platform listed here requires
> explicit layout testing before certification.
**Worked example table**:
| Platform | Safe Zone | Resolution Range | Input Method | HUD-Specific Notes |
|----------|-----------|-----------------|-------------|-------------------|
| [PC — Windows, 1920x1080 reference] | [3% margin] | [1280x720 min to 3840x2160 max] | [Mouse + keyboard, controller optional] | [HUD must scale correctly at all resolutions. Test at 1280x720 — minimum before cert. Consider ultrawide (21:9) — minimap must not stretch.] |
| [PC — Steam Deck, 1280x800] | [5% margin] | [Fixed 1280x800] | [Controller + touchscreen] | [Smaller screen means minimum text sizes are critical. Test ALL elements at this resolution. Touch targets irrelevant (controller-only by default).] |
| [PlayStation 5 / Xbox Series X] | [10% margin] | [1080p to 4K] | [Controller] | [Console certification requires TV safe zone compliance. Action-safe is 90% of screen area. Test on a real TV, not a monitor — overscan behavior differs.] |
| [Mobile — iOS / Android] | [15% top, 10% other sides] | [360x640 min to 414x896 common] | [Touch] | [Notch/camera cutout avoidance at top. Bottom home indicator zone avoidance. Portrait and landscape layouts may differ significantly — specify both.] |
---
## Section 10 — Accessibility (HUD Specific)
> **Why this section exists**: HUD accessibility failures are the most visible
> accessibility failures in games — players encounter the HUD in every session,
> in every gameplay moment. Color-blind failures, illegible text at minimum scale,
> and inability to disable distracting animations are among the top accessibility
> complaints in game reviews. This section defines HUD-specific requirements; refer
> to the project's `design/accessibility-requirements.md` for the full project standard.
**Worked example — colorblind modes table (10.1)**:
| Element | Color-Only Information Risk | Colorblind Mode Fix |
|---------|----------------------------|---------------------|
| [Health bar fill] | [Red = low health uses red/green distinction] | [Add icon pulse + vignette as non-color indicators. Red fill is supplemental, not sole indicator.] |
| [Damage numbers] | [Red = taken, green = healed] | [Add minus (-) prefix for damage, plus (+) for healing. Symbols, not color.] |
| [Enemy health bars] | [If colored by faction or threat level] | [Add text label or icon badge for faction/threat level. Never color-only.] |
| [Status effect icons] | [If icon tint communicates status type] | [All status icons must have distinct shapes, not just distinct colors. Shape encodes meaning; color is secondary.] |
| [Minimap icons] | [If player vs. enemy vs. objective distinguished by color] | [Distinct icon shapes: circle = player, triangle = enemy, star = objective. Color supplements shape.] |
**Authoring the text scaling narrative (10.2)**:
[Describe what happens when the player sets the UI text scale to 150% (the maximum required for your Accessibility Tier). Which elements reflow? Which elements clip? Which elements are architecturally blocked from scaling (e.g., fixed-size canvases)?
Example: "Health bar numerical label grows with text scale — bar expands slightly to accommodate. Quest objective text wraps at 150% scale — verify Top Center zone can accommodate two-line objectives. Damage numbers do not scale (they are world-space, not screen-space) — this is an accepted limitation documented here."]
**Worked example — text scaling test matrix (10.2)**:
| Element | 100% (baseline) | 125% | 150% | Overflow behavior |
|---------|----------------|------|------|-------------------|
| [Health bar label] | [Pass] | [Pass] | [TBD] | [Bar expands; does not overlap stamina bar] |
| [Quest objective text] | [Pass] | [TBD] | [TBD] | [Wraps to second line; zone height expands] |
| [Notification toast text] | [Pass] | [TBD] | [TBD] | [Toast width expands to max 35% screen width, then wraps] |
| [Subtitle text] | [Pass] | [TBD] | [TBD] | [Dedicated subtitle zone — must accommodate scale] |
**Worked example — motion sensitivity table (10.3)**:
| Animation / Motion Element | Severity | Disabled by Reduced Motion Setting? | Replacement Behavior |
|---------------------------|----------|-------------------------------------|---------------------|
| [Health bar low-HP pulse] | [Mild] | [Yes] | [Solid fill, no pulse. Vignette remains as it is less likely to trigger sensitivity.] |
| [Screen edge vignette] | [Moderate] | [Optional — separate toggle] | [Replace with static darkened corners at 30% opacity] |
| [Damage numbers float upward] | [Mild] | [Yes] | [Instant appear/disappear in place, no float] |
| [Notification toast slide-in] | [Mild] | [Yes] | [Instant appear at final position] |
| [Level up center animation] | [High] | [Yes — required] | [Static level up card, no scale animation, no particle effects] |
| [Combo counter scale pulse] | [Mild] | [Yes] | [Number increments without scale animation] |
---
## Section 11 — Tuning Knobs
> **Why this section exists**: HUD behavior should be data-driven to the same degree
> as gameplay systems. Values that are hardcoded are values that require an engineer
> to change. Values that are in config can be tuned by a designer or adjusted for
> player preferences. Document all tunable parameters before implementation so the
> programmer knows which values to externalize.
**Worked example table**:
| Parameter | Current Value | Range | Effect of Increase | Effect of Decrease | Player Adjustable? | Notes |
|-----------|-------------|-------|-------------------|-------------------|-------------------|-------|
| [Notification display duration (default)] | [2000ms] | [500ms – 5000ms] | [Toasts persist longer — less likely to be missed, more screen clutter] | [Toasts disappear faster — cleaner, higher miss risk] | [No — but player can adjust verbosity level] | [Per-type overrides in Section 8 take precedence] |
| [Notification queue max size] | [8] | [3 – 15] | [More messages preserved but queue takes longer to clear] | [Older messages dropped earlier] | [No] | [Expand if playtesting reveals important messages being lost] |
| [Health bar low-HP pulse frequency] | [1 Hz] | [0.5 – 2 Hz] | [More urgent feeling — can become fatiguing] | [Calmer — may fail to communicate urgency] | [No — but Reduced Motion disables it] | [Linked to accessibility setting] |
| [Combat HUD reveal duration] | [0ms (instant)] | [0 – 300ms] | [Softer reveal — feels less jarring] | [Instant — highest responsiveness] | [No] | [Keep at 0ms — combat information must be instant] |
| [Exploration HUD fade-out delay] | [10000ms (10s after last threat)] | [3000 – 30000ms] | [HUD fades sooner — cleaner exploration] | [HUD stays longer — more reassurance] | [No] | [Tune based on playtest; 10s is a starting estimate] |
| [Minimap range (world units visible)] | [80] | [40 – 200] | [More map context visible] | [Tighter local view] | [Yes — Small/Medium/Large preset] | [Exposed as S/M/L, not raw unit value] |
| [Minimap size (px radius at 1080p)] | [75] | [50 – 120] | [Larger map, more screen space consumed] | [Smaller, less intrusive] | [Yes — S/M/L preset] | [Three sizes exposed to player] |
| [Damage number duration (ms)] | [800] | [400 – 1500] | [Numbers linger longer — easier to read, more cluttered] | [Numbers clear faster — cleaner, harder to parse] | [No] | [Tune based on visual noise in dense combat] |
| [Global HUD opacity] | [100%] | [0 – 100%] | [Fully visible] | [Fully hidden] | [Yes — opacity slider in Accessibility settings] | [0% = full HUD off; some players prefer this] |
---
## Section 12 — Acceptance Criteria
> **Why this section exists**: These criteria are the certification checklist for the
> HUD. Every item must pass before the HUD can be marked Approved. QA must be able
> to verify each item independently.
---
## Section 13 — Open Questions
**Worked example questions**:
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [e.g., Should the minimap show enemy positions by default, or only after a detection skill is unlocked?] | [systems-designer + ui-designer] | [Sprint 5, Day 2] | [Pending — depends on progression GDD decision] |
| [e.g., Does the game have a boss health bar, or do bosses use the standard enemy health bar? Bosses need a visually distinct treatment if they are significantly more important than normal enemies.] | [game-designer] | [Sprint 5, Day 1] | [Pending] |
| [e.g., Damage numbers: diegetic (floating in world space, occluded by geometry) or screen space (always readable, overlaid on HUD layer)?] | [ui-designer + lead-programmer] | [Sprint 4, Day 5] | [Pending — architecture decision affects rendering layer choice] |
| [e.g., Mobile portrait vs. landscape: does the game support both orientations? If yes, each requires its own zone layout.] | [producer] | [Sprint 3, Day 3] | [Pending — platform scope decision required first] |
@@ -0,0 +1,175 @@
> Authoring guidance for interaction-pattern-library.md. Load only the part covering the section currently being authored — not the whole file at once.
> Covers: **Game-Specific UI Patterns** — full reference specifications for Inventory Slot, Ability / Skill Icon, Health / Resource Bar, Dialogue Box, Context Action Prompt, Damage Number.
## Game-Specific UI Patterns
---
#### Inventory Slot
**Category**: Game-Specific
**Status**: Draft
**When to Use**: Every item container in the inventory grid. Empty slots, populated
slots, equipped slots, locked slots. The slot is the frame; the item icon is the
content.
**States**:
| State | Visual | Notes |
|-------|--------|-------|
| Empty | Subtle slot border, no content. Not the same as disabled. Empty slots are interactable (receive items). | Avoid fully invisible empty slots — players lose track of grid dimensions |
| Populated | Item icon fills 80% of slot area. Stack count bottom-right (if applicable). Quality border (colorblind-safe — icon + color). Equipped badge (top-right, if equipped). | |
| Focused | Focus ring. Tooltip appears after 300ms. | |
| Selected | Thicker or contrasting border. Used when multi-select is supported. | |
| Drag source | Slot dims, drag ghost follows pointer. | See Grid Item for full drag spec |
| Locked | Padlock icon overlay. No interaction. May show item at 50% opacity behind lock. | Used for locked loadout slots, DLC content, etc. |
| Highlighted | Animated border glow (pulsing). Used for quest-relevant items or newly acquired items. | Respect motion reduction — replace pulse with a static badge |
| Cooldown overlay | Radial fill overlay from 12 o'clock, clockwise, depleting as cooldown expires. | Only applicable if slots represent active items with cooldowns |
**Accessibility**: Stack counts and quality tiers must have text or icon alternatives to color coding. Tooltip is the primary accessibility mechanism — ensure it is reachable by keyboard and screen reader. Locked slots must announce "locked" to screen readers.
**Implementation Notes**: [Godot: Custom `Control` node. Quality border implemented as a `StyleBoxFlat` swapped based on rarity — avoid using `modulate` color for quality, as it affects the icon color. Drag and drop implemented via `get_drag_data()` and `can_drop_data()` / `drop_data()` override methods.]
---
#### Ability / Skill Icon
**Category**: Game-Specific
**Status**: Draft
**When to Use**: Ability buttons in the HUD ability bar, skill tree nodes, and
any context where an ability must show availability state.
**States**:
| State | Visual | Notes |
|-------|--------|-------|
| Available | Full opacity icon. Keybinding label below. | |
| On cooldown | Radial overlay depleting clockwise from 12 o'clock. Remaining time shown as a number in the center when > 2 seconds remain. | |
| Charges remaining | Charge pip indicators below icon (e.g., 3 filled circles = 3 charges). Number alternative for screen readers. | |
| Out of resource | Icon desaturates to ~20%. Border dims. Keybinding label dims. Distinct from cooldown — resource-gated, not time-gated. | |
| Locked / not unlocked | Icon silhouette only (no full art visible). Padlock badge. May show unlock condition in tooltip. | |
| Active / channeling | Pulsing border. Radial fill shows channel duration remaining. | |
| Just activated | Brief scale 0.9x then spring to 1.0x (overshoot to 1.05x). | Example: Guild Wars 2 and Path of Exile both use press-depress animations on ability use to confirm activation. Respect motion reduction. |
**Accessibility**: All cooldown/charge information must have a numeric value (screen reader cannot parse radial overlays). The cooldown timer number satisfies this. Ability names and descriptions must be exposed to screen readers via tooltip.
**Implementation Notes**: [Godot: Custom `TextureButton` subclass with overlay
`Control` nodes for cooldown radial and charge pips. The cooldown radial uses a
custom shader on a `ColorRect` rotating a mask — or implement with a
`ProgressBar` styled as circular if engine supports it. Verify against
engine-reference/godot/ for Godot 4.6 shader support for this pattern.]
---
#### Health / Resource Bar
**Category**: Game-Specific
**Status**: Draft
**When to Use**: Any continuously varying value in the HUD that represents a
critical player resource. Health, mana, stamina, shield, fuel.
**States and behaviors**:
| Event | Visual | Audio | Duration |
|-------|--------|-------|---------|
| Value decrease (damage) | Fill shrinks. Brief "damage flash" on the fill (white or red flash). Ghost bar lingers at previous value and drains to new value over 0.5s ("damage indicator"). | [Damage taken sound — varies by amount] | Instant decrease, 500ms ghost bar drain |
| Value increase (heal) | Fill grows. Brief heal color flash (green — ensure colorblind safe with icon/glow backup). | [Heal sound] | 300ms ease-in |
| Below 25% threshold | Fill changes color to warning state. Border pulses (or static badge in motion reduction mode). Optional: heartbeat audio cue (paired with visual if audio is sole signal). | [Low health sound — loops until above threshold] | Continuous |
| At zero | Bar empty. Optional: bar shakes briefly. Death/depletion event fires. | [Death/depletion sound] | 200ms shake |
| Maximum | Fill at 100%, brief glow. | — | 200ms |
| Overflow (shield) | A separate bar segment appears beyond the natural fill area, in shield color. | [Shield gain sound] | 200ms |
**Accessibility**: The current value must be accessible as a number (tooltip or persistent display, or both). Color-coded threshold states must have non-color backups (icon, flashing, or audio visual warning). Warning state at 25% must have a visual signal independent of the color change.
**Implementation Notes**: [Godot: Two overlapping `ProgressBar` nodes for ghost
bar effect — back bar holds previous value (drains via Tween), front bar holds
current value (updates instantly). Threshold states trigger `StyleBoxFlat` swaps
on the front bar. Ghost bar Tween duration is tunable as a designer parameter.]
---
#### Dialogue Box
**Category**: Game-Specific
**Status**: Draft
**When to Use**: NPC conversation, voiced narrative dialogue, tutorial text
delivered through a character. All dialogue that has a speaker.
**Structure**: Speaker portrait or name tag (top of box or left side). Dialogue text body. Continue/advance prompt (bottom right). Optional: skip-all button, voice acting indicator, subtitle indicator.
**States and behaviors**:
| State | Visual | Input | Response | Duration |
|-------|--------|-------|----------|---------|
| Line entering | Text reveals character-by-character (typewriter effect). Or: text fades in at full speed if accessibility option set. | — | — | Speed: configurable in accessibility settings |
| Revealing | Text animating in. Continue prompt hidden or pulsing at slow opacity. | [Any advance input] | Skip to end of current line instantly (show full line, stop typewriter) | Immediate |
| Line complete | Full line shown. Continue prompt visible and animated. | — | — | — |
| Advancing to next line | Continue prompt hides. Text fades out or wipes. New line begins. | [Any advance input] — Enter / A / Cross / Space / mouse click | Advance | 100ms transition |
| Choices appearing | Choice buttons appear below dialogue text. Continue prompt hidden. Navigation focus moves to first choice. | D-pad / keyboard to select, Enter / A / Cross to confirm | Select choice | 150ms enter animation |
| Closing | Box fades out | Final line advanced | Return control to player | 200ms |
| Skipping all (if supported) | Brief confirmation prompt: "Skip dialogue?" | Dedicated skip button | Skip to post-dialogue state | — |
**Accessibility**: Subtitles are always enabled by default for all voiced dialogue. Typewriter animation speed is a user setting (see accessibility-requirements.md). The dialogue box must not auto-advance — players must control pacing. Speaker name is always shown. All choice buttons must be navigable by keyboard and gamepad. Choices must be accessible to screen readers with position announced.
**Implementation Notes**: [Godot: `RichTextLabel` with `bbcode_enabled` for
formatting. Typewriter effect via `visible_characters` property animated by a
`Timer`. Bind the advance input to a function that either skips typewriter
(sets `visible_characters = -1`) or advances the dialogue state. Speaker name
displayed in a separate `Label` above or beside the box. Dialogue data loaded from
JSON or a dedicated dialogue format (e.g., Dialogic, Yarn Spinner for Godot).]
---
#### Context Action Prompt
**Category**: Game-Specific
**Status**: Draft
**When to Use**: A prompt that appears near an interactable game object indicating
what the player can do. "Press [A] to open chest." "Hold [E] to pick up." Appears
when the player enters the interaction zone, disappears when they leave.
**States**:
| State | Visual | Notes |
|-------|--------|-------|
| Appearing | Fades in and rises 8px from object anchor point. | Respect motion reduction — fade only, no rise |
| Idle | Platform-correct button icon + action label. Icon matches current input method (updates if player switches). | Always show platform-correct icon — do not hardcode "Press A" for all platforms |
| Holding (for hold inputs) | Radial fill on the button icon shows hold progress. Label changes to active verb ("Opening..."). | |
| Cannot interact (blocked) | Icon dims. Label shows reason if known ("Too heavy", "Need key"). | Optional — only show blocked state if the reason is meaningful to the player |
| Disappearing | Fades out. | Triggered when player exits interaction zone |
**Accessibility**: The button icon must be accompanied by a text label — do not rely on icon alone (some players use custom button labels or adaptive controllers with non-standard icons). The prompt must be positioned to not overlap character health or critical HUD information.
**Implementation Notes**: [Godot: Attach as a `Node3D` child (or `Node2D` child in 2D) of the interactable object. Use a `BillboardMesh` or a `SubViewport` with a UI scene for 3D games — this keeps the prompt facing the camera without code. Update the button icon texture based on `Input.get_joy_name()` or keyboard detection via `InputEventKey` vs `InputEventJoypadButton`. Hold progress implemented as an `AnimationPlayer` or `Tween` on a radial mask shader.]
---
#### Damage Number
**Category**: Game-Specific
**Status**: Draft
**When to Use**: Floating feedback numbers above combat participants. Normal
damage, critical damage, healing, miss.
**Variants**:
| Variant | Visual | Notes |
|---------|--------|-------|
| Normal damage | White number, normal weight, medium size. | |
| Critical hit | Larger size (1.5x), bold weight, orange or yellow — verify colorblind safe. Brief scale impact (1.3x → 1.0x on appear). | Example: Path of Exile and Diablo IV both use scale-pop for crits to make them immediately recognizable by size alone, independent of color. |
| Healing | Green (verify colorblind safe — use + prefix and upward trajectory as non-color backups). | |
| Miss / Evade | "MISS" text, grey, italic. Floats at smaller size. | |
| Status damage (DoT) | Smaller size, distinct color matching the status effect. | |
**Behavior**: Numbers float upward from the hit location over 1.0 second. Numbers fade from 100% to 0% during the last 0.4 seconds. Multiple numbers from rapid hits stagger horizontally to avoid overlap. Maximum simultaneous damage numbers on screen: [define per game — typically 8-12 per character].
**Accessibility**: Damage numbers are purely supplementary feedback — they must never be the only way to understand combat state. Health bars are the authoritative source. Provide an option to disable damage numbers entirely (some players find them visually overwhelming). When disabled, the game must remain fully playable.
**Implementation Notes**: [Godot: Pool of `Label3D` (3D games) or `Label` (2D games)
instances recycled via an object pool. Each instance is given a random small
horizontal offset on spawn (±20px) to reduce overlap. Float animation via
`Tween` on `position.y` and `modulate.a`. Critical hit scale-pop via Tween
with `EASE_OUT` on scale followed by linear settle.]
---
@@ -0,0 +1,135 @@
> Authoring guidance for interaction-pattern-library.md. Load only the part covering the section currently being authored — not the whole file at once.
> Covers: **Navigation Patterns** (Screen Push / Pop / Replace, Focus Management, Escape / Cancel) and **Feedback and Loading Patterns** (Loading State, Empty State, Error State) — full reference specifications.
## Navigation Patterns
---
#### Screen Push / Pop / Replace
**Category**: Navigation
**Status**: Draft
These three patterns define how screens enter and exit the navigation stack.
| Pattern | Trigger | Animation | Stack Behavior | Focus Behavior |
|---------|---------|-----------|---------------|----------------|
| Push | Navigate deeper (open submenu, open detail view) | New screen slides in from right. Previous screen slides left and dims. | Previous screen remains on stack | Focus moves to first interactive element on new screen |
| Pop (Back) | Back button / Escape / B / Circle | Current screen slides right and exits. Previous screen slides in from left and brightens. | Current screen removed from stack | Focus returns to the element that triggered the Push |
| Replace | Navigate to a peer screen (not child, not parent). Loading screen. | Fade out current, fade in new. No directional bias. | Current screen removed. New screen added. | Focus moves to first interactive element on new screen |
**Animation durations**: Push/Pop: 250ms ease-in-out. Replace: 200ms fade out + 200ms fade in.
**Motion reduction**: All slide animations become fades. Duration reduces to 100ms.
**Implementation Notes**: [Godot: Implement as a `ScreenManager` singleton managing
a stack of `Control` scenes. `push(screen_scene)` instantiates and animates in.
`pop()` animates out and frees. `replace(screen_scene)` calls pop then push without
the intermediate stack state. Use `CanvasLayer` per screen to isolate input handling.
Store the "return focus" element reference before pushing so it can be restored on pop.]
---
#### Focus Management
**Category**: Navigation
**Status**: Draft
> Focus management is the most common keyboard and gamepad accessibility failure
> in game UIs. These rules must be implemented consistently. A player should
> never be in a state where they cannot see which element is focused, or where
> Tab/D-pad produces no visible result.
| Rule | Description |
|------|-------------|
| Screen open | Focus is placed on the most logical interactive element — typically the Primary button, the first list item, or the last-focused element if the screen was previously visited. Never on a non-interactive element. |
| Screen close / pop | Focus returns to the element that triggered the navigation (the button that opened the screen, the list item that was selected). If that element no longer exists, focus goes to the nearest preceding interactive element. |
| Modal open | Focus is trapped inside the modal. See Modal Dialog pattern. |
| Modal close | Focus returns to the element that triggered the modal. |
| Element disabled | If the focused element becomes disabled, focus moves to the next available interactive element in the tab order. |
| Element destroyed | If the focused element is removed from the scene, focus moves to the nearest preceding element in the tab order. |
| Screen without interactive elements | Focus management is a no-op. Ensure back/cancel input still works. |
| Tab key (keyboard) | Moves focus forward through interactive elements in document order (left to right, top to bottom). Shift+Tab moves backward. |
| D-pad (gamepad) | Moves focus in the spatial direction pressed. Spatial navigation is preferred over strict tab order for gamepad. Never wrap focus between unrelated regions (e.g., Tab bar and content area should be separate navigation regions). |
| Focus is always visible | Focus ring or equivalent focus indicator must ALWAYS be visible when an element is focused via keyboard or gamepad. Never suppress focus indicators. |
---
#### Escape / Cancel
**Category**: Navigation
**Status**: Draft
> The "go back" action is the most-used navigation input in all menu systems.
> It must be consistent across every screen with no exceptions.
| Platform | Input | Behavior |
|----------|-------|---------|
| PC (keyboard) | Escape | Close top-most modal / go back one screen in stack / if at root screen (main menu), open "quit?" confirmation |
| PC (gamepad) | B (Xbox layout) / Circle (PS layout) | Same as Escape |
| Xbox | B button | Same as Escape |
| PlayStation | Circle button | Same as Escape |
| Nintendo Switch | B button | Same as Escape (NOTE: Nintendo uses B for confirm in some first-party titles — verify platform convention for this release and document the decision) |
**Rules**: This input must never be overridden to do something other than "go back / cancel." If a screen has no back action (e.g., the game is paused and the player must make a choice), Escape does nothing or shows a "you must choose" message — it does not navigate away. Every screen must define its Escape behavior explicitly in its UX spec.
---
## Feedback and Loading Patterns
---
#### Loading State
**Category**: Feedback
**Status**: Draft
| Scope | Pattern | Notes |
|-------|---------|-------|
| Full screen (initial load) | Full-screen loading screen with game art, progress bar (determinate if possible), tip text (optional). | Never use an empty black screen. Give the player something to read or look at. |
| Full screen (level transition) | Fade to black, loading screen, fade from black to new scene. | The fade removes the pop of the previous scene disappearing. |
| Component / inline | Spinner or skeleton placeholder replaces the loading component. Component does not shift layout when content loads. | Skeleton placeholder (grey boxes approximating content shape) is preferable to spinner for layout-heavy content — it prevents layout shift on load. |
| Background / async | No visual indication unless operation exceeds 2 seconds. After 2 seconds, show a small spinner or toast. | Do not show loading indicators for operations that complete in under 2 seconds — the flash of an indicator is more disruptive than waiting. |
**Accessibility**: Loading states must announce to screen readers: "[Context] loading, please wait." Completion must announce "[Context] loaded." For full-screen loading, ensure the loading screen itself is navigable to screen readers — the tips text and any UI elements must be exposed.
---
#### Empty State
**Category**: Feedback
**Status**: Draft
> Empty states are consistently the least-designed parts of game UIs. They are
> the difference between a player feeling "this is where I'll store my items"
> and "why is nothing here? did something break?" Every empty list and grid must
> have a designed empty state. The empty state is not an error — it is a starting
> point.
| Location | Empty State Content | Notes |
|----------|--------------------|----|
| Inventory (no items) | Icon (subtle, large, centered). Message: "Your inventory is empty." Sub-message: "Items you find on your journey will appear here." | Do not say "No items found" — "found" implies a failed search. |
| Quest Log (no active quests) | Icon. Message: "No active quests." Sub-message: "Talk to characters marked with [quest marker icon] to start a quest." | Give the player a clear action. |
| Achievements (none earned) | Icon. Message: "No achievements yet." List of hint achievements: "Try [Action] to earn your first achievement." | Gamified motivation, not just emptiness. |
| Search results (no matches) | Icon. Message: "No results for '[search term]'." Sub-message: "Try a different search or [browse all]." | Mirror the search term back at them. Give an alternative action. |
**Rule**: Every empty state must include an icon, a message, and either a sub-message or an action button. A blank container with no explanation is never acceptable.
---
#### Error State
**Category**: Feedback
**Status**: Draft
| Error Type | Pattern | Tone |
|-----------|---------|------|
| Input validation (form field) | Inline error message below the field. Error icon left of message. Red border on field (colorblind-safe with icon). | Neutral and specific — "Username must be 3-20 characters." Not "Invalid input." |
| Operation failed (save error, network error) | Toast notification for non-critical failures. Modal Dialog for critical failures (save file cannot be written). | Calm and actionable — "Save failed. Check storage space." Not "FATAL ERROR." |
| System error (crash, data corruption) | Full-screen error screen with error code, recovery options ("Restart Game," "Load last save"), and support contact. | Reassuring — acknowledge the problem, give the player agency. Never blame the player. |
| Soft error (action cannot be performed) | Toast or inline message. | Explanatory — "Not enough gold" not "Action unavailable." |
**Principle**: Error messages are never the player's fault. They are the game telling the player what happened and what to do next. Remove the word "invalid" from all error messages — replace with specific explanations.
---
@@ -0,0 +1,589 @@
> Authoring guidance for interaction-pattern-library.md. Load only the part covering the section currently being authored — not the whole file at once.
> Covers: **Standard Control Patterns** — full reference specifications for Button (Primary/Secondary/Destructive), Toggle, Slider, Dropdown / Select, List Item, Grid Item, Modal Dialog, Confirmation Dialog, Toast / Notification, Tooltip, Progress Bar, Input Field, Tab Bar, Scroll Container.
## Standard Control Patterns
---
#### Button (Primary)
**Category**: Input
**Status**: Draft
**When to Use**: The single most important action on a screen. "Start Game,"
"Confirm," "Accept," "Buy." There should be at most one Primary button visible
at a time. It is the answer to "what does the player most likely want to do here?"
**When NOT to Use**: Alternative or secondary actions; destructive actions that
require confirmation before the consequence is irreversible; any action that is
not the primary intent of the screen.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Full-opacity fill, primary color from art-bible. Label centered. | — | — | — | — |
| Hovered (mouse) | Brightness +15%, subtle scale 1.03x, cursor changes to pointer | Mouse over element | Transition from Default | 80ms ease-out | [UI hover sound — see Sound Standards] |
| Focused (keyboard/gamepad) | Focus ring visible (2px, offset 3px, high contrast color). Same brightness as Hovered. | Tab / D-pad navigation | Transition from Default | 80ms ease-out | [UI focus sound — same as hover] |
| Pressed | Scale 0.97x, brightness -10% | Click / Enter / A (Xbox) / Cross (PS) | Action fires on press-up, not press-down. Scale on press-down. | 60ms ease-in for press; 80ms ease-out on release | [UI confirm sound] |
| Disabled | 40% opacity, no pointer cursor, no hover state | — | No response | — | — |
| Loading (post-press) | Replace label with spinner. Button remains at pressed scale, disabled state. | — | Prevents double-submission | Duration of async operation | — |
**Accessibility**:
- Keyboard: Tab to focus, Enter or Space to activate. Must be reachable from any other interactive element on screen via Tab sequence.
- Gamepad: D-pad or left stick to navigate focus to button. A (Xbox) / Cross (PS) to activate. Focus must be placed on Primary button by default when screen opens.
- Screen reader: Button must expose accessible name matching visible label. Role: "button." State: "dimmed" when disabled. Activation announcement: "[Label] button — [result of action, if known]."
- Colorblind: Do not rely on color alone to distinguish Primary from Secondary. Primary uses higher visual weight (fill vs. outline, or larger size) in addition to color differentiation.
- Minimum touch target: 44x44pt (iOS HIG) / 48x48dp (Android). Apply even on PC if touch support is possible.
**Implementation Notes**:
[Godot: Extend `Button` control. Override `_draw()` for custom states rather than
modifying themes mid-state. Use `focus_mode = FOCUS_ALL` to ensure keyboard
focusability. Set `mouse_default_cursor_shape = CURSOR_POINTING_HAND`. For the
scale animation, use a Tween on the `scale` property of the button's parent
Control — scaling the Button itself can clip children.]
---
#### Button (Secondary)
**Category**: Input
**Status**: Draft
**When to Use**: Alternative or cancel action. "Back," "Cancel," "Skip," "Maybe
Later." Lower visual weight than Primary — it should recede visually, not compete.
**When NOT to Use**: Destructive actions (use Button (Destructive)). The most
important action on the screen (use Button (Primary)).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Outlined style (border only, transparent fill), secondary color. Slightly smaller or lower weight than Primary. | — | — | — | — |
| Hovered | Background fill appears at 15% opacity. Border brightens. Scale 1.02x. | Mouse over | Transition from Default | 80ms ease-out | [UI hover sound — softer variant than Primary] |
| Focused | Focus ring, same specification as Primary. | Tab / D-pad | Transition from Default | 80ms ease-out | [UI focus sound] |
| Pressed | Scale 0.97x, fill opacity increases to 30% | Click / Enter / B (Xbox) / Circle (PS) on focused state | Action fires on press-up | 60ms ease-in | [UI cancel/back sound] |
| Disabled | 40% opacity | — | No response | — | — |
**Accessibility**: Same requirements as Button (Primary). Accessible name must
match visible label. In a dialog with Primary and Secondary buttons, the Secondary
button typically maps to the platform "cancel" input (B / Circle / Escape) as well
as direct focus activation.
**Implementation Notes**: [Same as Button (Primary). Where a Primary and Secondary
appear together, ensure Secondary is always positioned consistently — right/bottom
of Primary on horizontal layouts, or below Primary on vertical layouts. Consistency
across screens is more important than per-screen aesthetic preference.]
---
#### Button (Destructive)
**Category**: Input
**Status**: Draft
**When to Use**: Any action that is irreversible and causes loss of player data or
significant progress: "Delete Save File," "Reset All Settings," "Leave Match,"
"Discard Changes." The visual treatment signals danger before the player presses.
**When NOT to Use**: Actions that can be undone, or actions that are merely
consequential but reversible.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Outlined or filled with destructive color (typically a desaturated red — confirm colorblind compatibility in accessibility-requirements). Label may include a warning icon. | — | — | — | — |
| Hovered / Focused | Same behavior as Button (Primary) hover/focus but with destructive color | — | — | 80ms | [UI hover sound] |
| Pressed (first press) | Does NOT execute the action. Instead, opens Confirmation Dialog pattern (see below). The button itself shows a brief pulse animation. | Click / Enter | Trigger Confirmation Dialog | 100ms pulse | [UI warning sound — distinct from standard confirm] |
| — | Confirmation Dialog handles the actual execution | — | — | — | — |
| Disabled | 40% opacity | — | No response | — | — |
> **Critical rule**: A Button (Destructive) NEVER executes its action directly.
> It always triggers a Confirmation Dialog. There are no exceptions. A player
> who presses it by accident must always have one more opportunity to back out.
> Games that skip confirmation on destructive actions generate the most visible
> negative community sentiment of any UX failure type. See: every "accidentally
> deleted save file" complaint on any game forum.
**Accessibility**: Screen reader must announce the destructive nature: "[Label] button — this action cannot be undone." In addition to accessible name, use the `description` property if available to add the warning text.
**Implementation Notes**: [Destructive button triggers a separate Confirmation Dialog scene. Pass the action callback to the dialog — the button itself does not hold the execution logic. This separation prevents accidental execution if the confirmation dialog has a bug.]
---
#### Toggle
**Category**: Input
**Status**: Draft
**When to Use**: Binary on/off settings where both states are equally valid and
the current state must be visible at a glance. "Subtitles: On/Off," "Aim Assist:
On/Off," "Notifications: On/Off."
**When NOT to Use**: Selections from more than two options (use Dropdown). Actions
that happen once rather than representing a persistent state (use Button). Cases
where the consequence of toggling is complex enough to need explanation (show
a description field alongside).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Off / Default | Track: muted fill. Thumb: leftmost position. Label: "Off" or state label. | — | — | — | — |
| Hovered | Track brightens 10%. Cursor: pointer. | Mouse over | Transition | 60ms | [UI hover sound] |
| Focused | Focus ring around entire toggle element (track + thumb). | Tab / D-pad | — | 60ms | [UI focus sound] |
| Pressed / Activated | Thumb slides to right side. Track fill changes to active color. Label changes to "On" or active state label. State persists. | Click / Enter / A / Cross | Toggle state change. Fire onChange event. Persist value. | 150ms ease-in-out for slide | [Toggle ON sound] |
| Pressed / Deactivated | Thumb slides to left. Track reverts to muted fill. | Same inputs | Toggle state change | 150ms ease-in-out | [Toggle OFF sound — subtly different from ON] |
| Disabled | 40% opacity. No interaction. Current state still visible. | — | No response | — | — |
**Accessibility**:
- Keyboard/Gamepad: Space or Enter to toggle. Avoid requiring directional inputs (left/right) to toggle — some users cannot predict that behavior.
- Screen reader: Role: "switch." State: "on" or "off" — the accessible name should NOT include the state (the screen reader announces state separately). Correct: accessible name "Subtitles," state "on." Incorrect: accessible name "Subtitles On."
- The toggle label (not just the visual thumb position) must change to show current state for players who cannot reliably distinguish left from right positions.
**Implementation Notes**: [Godot: Use a custom Control or a CheckButton. The
built-in CheckButton provides accessibility role but uses a checkbox-style visual;
a custom slide-toggle animation may be needed for the target art style. Ensure
the slide animation is skipped when motion reduction mode is active — in that
case, snap to final state instantly.]
---
#### Slider
**Category**: Input
**Status**: Draft
**When to Use**: Selecting a value from a continuous range where approximate values
are acceptable and the range and relative position matter. Volume (0–100%), brightness,
text size. The visual representation of position is itself useful information.
**When NOT to Use**: Precise value entry (use Input Field). Selection from a short
discrete list (use Dropdown). Binary state (use Toggle).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Track (full width). Fill (left of thumb, shows current value). Thumb (draggable handle). Current value label (right of track or above thumb). | — | — | — | — |
| Hovered | Thumb enlarges slightly (1.2x). Track brightens. | Mouse over | — | 60ms | — |
| Focused | Focus ring on thumb. Track brightens. | Tab / D-pad | — | 60ms | [UI focus sound] |
| Dragging (mouse) | Thumb follows cursor. Fill updates in real time. Value label updates in real time. | Click + drag on thumb | Continuous value update. Fire onChange continuously. | Real time | [Slider adjust sound — subtle, loops while dragging] |
| Keyboard / D-pad adjust | Thumb moves one step (5% of range per press, or 1 discrete unit). | Left/Right arrows or Left/Right D-pad while focused | Step value change. Fire onChange per step. | Instant | [Slider step sound — one click per step] |
| Keyboard fast adjust | Larger step (25% of range). | Page Up / Page Down while focused | Large step value change | Instant | [Same step sound] |
| Released | Value locks. onChange fires final value. | Mouse release | — | — | — |
| Disabled | 40% opacity. No interaction. Value visible. | — | No response | — | — |
**Accessibility**:
- Keyboard: Left/Right arrows to adjust by small step. Page Up/Page Down for large step. Home/End to jump to min/max.
- Screen reader: Role: "slider." Accessible name: the label (e.g., "Music Volume"). Current value announced on every change: "Music Volume, 80 percent." Min/max values announced on first focus.
- All sliders must show a numeric value alongside the visual position. Relying only on track fill position excludes players who cannot perceive relative position.
**Implementation Notes**: [Godot `HSlider`: set `step` to appropriate increment.
Override keyboard input to add Page Up/Down support via `_input()`. Bind the
`value_changed` signal to update the displayed numeric label. When motion reduction
mode is enabled, ensure value label updates are the sole feedback — do not suppress
them. Rumble feedback on gamepad slider adjustment is a nice enhancement for
accessibility.]
---
#### Dropdown / Select
**Category**: Input
**Status**: Draft
**When to Use**: Selection from a discrete list of 3-15 options where only the
selected value needs to be visible at rest. Display resolution, language, window
mode, input preset. The closed state shows only the current selection.
**When NOT to Use**: Binary choices (use Toggle). More than ~15 options (use a
full List pattern or a scrollable Select). When comparing options matters as much
as selecting one (show options visibly, e.g., as a horizontal selector or list).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Closed / Default | Label (left). Current value (right). Chevron-down icon (far right). | — | — | — | — |
| Hovered | Row background fills at 10% opacity | Mouse over | — | 60ms | — |
| Focused (closed) | Focus ring on entire row. | Tab / D-pad | — | 60ms | [UI focus sound] |
| Opening | Dropdown list appears below (or above if near screen bottom). List items visible. Previously selected item highlighted. Focus moves to selected item inside list. | Click / Enter / A / Cross | Open list | 100ms ease-out (expand) | [UI expand sound] |
| List item hovered/focused | List item highlights | Mouse / D-pad | — | 60ms | [UI hover sound] |
| List item selected | List closes. Closed state shows new value. onChange event fires. | Click / Enter / A / Cross on item | Select value, close list | 80ms ease-in (collapse) | [UI confirm sound] |
| Dismissed without selecting | List closes. Value unchanged. | Escape / B / Circle / click outside | Dismiss | 80ms | [UI cancel sound] |
| Disabled | 40% opacity. No interaction. | — | — | — | — |
**Accessibility**:
- Keyboard: Up/Down arrows navigate list items while open. Enter selects. Escape dismisses. First letter of an option jumps focus to first matching item.
- Screen reader: Role: "combobox." Accessible name: the field label. Expanded/collapsed state announced. Current value announced when focused. Each list item announces its value and position: "English, 1 of 12."
- The dropdown list must never obscure the current item or the control that opened it — this is a common failure on small screens.
**Implementation Notes**: [Godot: Custom implementation using a `Button` (the
closed state) and a `PopupMenu` or a `VBoxContainer` revealed by animation. Native
`OptionButton` provides accessibility but limited visual customization. Ensure
the popup positions itself above the control if it would be clipped by the screen
bottom. Close the popup on `_input` detecting click outside its rect.]
---
#### List Item
**Category**: Layout / Input
**Status**: Draft
**When to Use**: A single selectable row in a vertically scrollable list. Achievements,
quest log entries, settings categories, save file slots. The list is the container;
this is the row within it.
**When NOT to Use**: Grid layouts where items exist in two dimensions (use Grid Item).
Non-selectable content rows (remove hover/focus states and the pressed state).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Full-width row. Icon (optional, left). Primary label. Secondary label / metadata (right or below primary). Chevron (right, if navigates deeper). | — | — | — | — |
| Hovered | Row background at 12% opacity highlight. | Mouse over | — | 60ms | — |
| Focused | Focus ring on row OR row background at 20% opacity (consistent with platform convention). | D-pad / Tab | — | 60ms | [UI focus sound] |
| Selected (persistent) | Row background at 25% opacity. May show a selection indicator (left border, checkmark). Distinct from focused state — a row can be selected but not focused. | — | Rendered state | — | — |
| Pressed / Activated | Brief brightness flash, then navigates or performs action | Click / Enter / A / Cross | Navigation or action | 80ms flash | [UI confirm sound] |
| Disabled | 40% opacity. No interaction. | — | — | — | — |
**Accessibility**:
- Keyboard/Gamepad: Up/Down arrows or D-pad to move between list items. The list must handle focus cycling — reaching the bottom should stop (not wrap) unless wrapping is explicitly designed.
- Screen reader: Role: "listitem." Parent list role: "list." Accessible name: primary label content. Metadata (secondary label) is optionally included in the description. Position announced: "Quest Log, 3 of 12."
- Minimum row height: 44pt / 48dp for touch. For controller-primary platforms, 56px rows are more comfortable.
**Implementation Notes**: [Godot: Use a `VBoxContainer` inside a `ScrollContainer`.
Each row is a custom `Control` or `PanelContainer` with a `_gui_input` override.
For keyboard navigation inside the scroll container, implement custom focus
traversal — Godot's default Tab navigation does not scroll the container to keep
focused items in view. Use `ensure_control_visible()` on the scroll container.]
---
#### Grid Item
**Category**: Layout / Input
**Status**: Draft
**When to Use**: A selectable cell in a two-dimensional grid. Inventory slots,
ability select, crafting ingredient selection, character portrait selection. The
grid is the container; this is the cell.
**When NOT to Use**: Single-column content (use List Item). Non-selectable display
cells (remove interactive states).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Empty | Empty slot visual (subtle border or dashed outline). Different from disabled. | — | — | — | — |
| Populated | Item icon fills cell. Stack count (bottom right, if applicable). Quality indicator (border color or icon overlay). | — | — | — | — |
| Hovered | Brightness +15%. Tooltip appears after 400ms delay. | Mouse over | — | 60ms | — |
| Focused | Focus ring (2px, offset 2px). Same brightness as hovered. Tooltip appears after 400ms delay or immediately on gamepad. | D-pad navigation | — | 60ms | [UI focus sound] |
| Selected (persistent) | Distinct border (thicker, contrasting color). May show selection checkmark. | Click / Enter / A / Cross | Select item. Can coexist with focused state on a different cell. | Instant | [UI select sound] |
| Pressed | Brief scale 0.95x, then executes action | Double-click / Enter / A / Cross | Action (equip, use, inspect — defined by context) | 80ms | [UI confirm sound] |
| Locked | Padlock overlay icon on populated content. No hover/focus states. | — | No interaction | — | — |
| Drag source | Cell dims (50% opacity), drag preview appears at cursor. | Click + drag (mouse only) | Begin drag operation | Instant | [UI grab sound] |
| Drop target (valid) | Cell brightens, accepting color indicator | Item dragged over | — | 60ms | — |
| Drop target (invalid) | Red tint or shake animation | Item dragged over invalid slot | — | 60ms | [UI error sound] |
**Accessibility**:
- Keyboard/Gamepad: D-pad or arrow keys navigate cells. The grid must communicate its dimensions to screen readers. Row/column position announced.
- Screen reader: Role: "gridcell." Parent role: "grid." Accessible name: item name (or "empty slot" for empty cells). State: "selected" when selected, "dimmed" when locked. Position: "row 2, column 3."
- Tooltips must be reachable by keyboard — they must appear when the cell is focused, not only when hovered.
**Implementation Notes**: [Godot: `GridContainer` with fixed column count. Each
cell is a custom `Control`. Implement custom D-pad navigation by overriding
`_gui_input` and calculating the cell to the left/right/above/below based on
index and column count. `GridContainer` does not provide this natively.]
---
#### Modal Dialog
**Category**: Feedback / Layout
**Status**: Draft
**When to Use**: A decision or acknowledgment that must be resolved before the
player can continue. The dialog is blocking — background content is dimmed and
non-interactive. "Are you sure?", "Your progress will be saved.", error states.
**When NOT to Use**: Non-blocking notifications (use Toast / Notification). Information
that can wait until the player is ready (add it to a persistent help system instead).
Dialogs that should allow the player to continue playing behind them.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Opening | Background overlay animates from 0 to 60% opacity. Dialog panel scales from 0.9 to 1.0. Dialog enters from center (not from an edge). | Triggered by code | Focus moves to first interactive element in dialog (or the Primary button) | 200ms ease-out | [UI modal open sound] |
| Active | Background non-interactive. Dialog has all input focus. Player cannot interact with background. | Keyboard / gamepad navigates within dialog only | — | — | — |
| Dismissing (confirmed) | Dialog panel scales to 1.1 then fades. Overlay fades to 0%. | Primary button pressed | Execute action, return focus to trigger element | 180ms | [UI confirm sound] |
| Dismissing (cancelled) | Dialog panel scales to 0.9 then fades. Overlay fades to 0%. | Secondary button / Escape / B / Circle | No action, return focus to trigger element | 150ms | [UI cancel sound] |
| Cannot dismiss | If the dialog represents a blocking error, do not provide a cancel path. Provide only resolution options. | — | — | — | — |
> **Focus trap rule**: While a modal dialog is open, Tab and D-pad navigation
> must cycle within the dialog's interactive elements only. It must not be possible
> to navigate focus outside the dialog to the background content. This is both
> an accessibility requirement (WCAG 2.1 SC 2.1.2) and a UX integrity requirement.
> When the dialog closes, focus must return to the element that triggered it,
> not to the top of the page.
**Accessibility**:
- Screen reader: Dialog container role: "dialog." Accessible name: dialog title (required — every dialog must have a title, even if visually hidden). On open, screen reader announces dialog title and first focusable element. Focus trap active.
- Keyboard: Escape key always maps to the cancel/dismiss action (same as Secondary button or close button). Enter always maps to the primary/confirm action.
- Motion reduction: Scale animation replaced with instant appear/disappear. Overlay fade retained at 100ms (faster).
**Implementation Notes**: [Godot: Implement as a `CanvasLayer` with a high layer
value (100+) to ensure it renders above all game content. The background overlay
is a full-screen `ColorRect` at 60% black opacity. Use `grab_focus()` on the
dialog's primary button after the open animation completes. Override `_input()` to
implement the focus trap — intercept Tab navigation and reroute to the dialog's
focusable elements.]
---
#### Confirmation Dialog
**Category**: Feedback / Layout
**Status**: Draft
**When to Use**: The specific case of confirming a destructive action. Always
triggered by Button (Destructive). Always has exactly two options: confirm (labeled
with the specific action, not "OK") and cancel.
**When NOT to Use**: Non-destructive confirmations. Errors or notifications that
do not require a decision. Any dialog with more than two actions.
> **Label rule**: The confirm button must be labeled with the specific action,
> not a generic "OK" or "Yes." "Delete Save File" not "OK." "Leave Match" not
> "Yes." This reduces mistakes for players who have difficulty reading the dialog
> content quickly. The pattern comes from Apple HIG and is validated by decades
> of usability research.
**Structure**:
- Title: Brief, action-describing. "Delete save file?" not "Are you sure?"
- Body: One sentence stating the consequence. "This cannot be undone."
- Confirm button: Button (Primary) — labeled with the specific action. "Delete Save File."
- Cancel button: Button (Secondary) — "Cancel."
- Default focus: Cancel (safer default — reduces accidental destructive actions).
**Accessibility**: Inherits all Modal Dialog accessibility. Additionally: screen
reader announces "Alert dialog, [title]" to signal destructive context. Default
focus on Cancel is a requirement, not a preference.
**Implementation Notes**: [Confirmation Dialog is a specific instance of Modal
Dialog — implement it as a subclass or as a parameterized scene. The default
focus on Cancel is critical: set `grab_focus()` on the Cancel button, not the
Confirm button, after open animation completes.]
---
#### Toast / Notification
**Category**: Feedback
**Status**: Draft
**When to Use**: Brief, non-blocking information that does not require a player
decision. "Game saved." "Achievement unlocked." "Your inventory is full." The player
can continue playing; the notification disappears on its own.
**When NOT to Use**: Information that requires a decision (use Modal Dialog).
Errors that require the player to take action. Critical information that the player
must not miss.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Entering | Slides in from screen edge (typically bottom-right, away from primary action areas). Fades from 0 to 100% opacity. | Triggered by code | — | 200ms ease-out | [Sound matching notification type — see Sound Standards] |
| Displayed | Full opacity. Optional: icon (left), title, body text (optional), dismiss button (X, optional). | Pointer hover pauses auto-dismiss timer | Pause auto-dismiss | — | — |
| Auto-dismiss | Fades from 100 to 0% opacity, slides out | Timer expires (5 seconds default for one-line; 8 seconds for two-line) | Remove from queue | 200ms ease-in | — |
| Manual dismiss | Fades and slides out immediately | Click/tap X button or swipe on touch | Remove | 150ms | [UI cancel sound, quiet] |
| Queue overflow | New notification pushes oldest out early | New notification triggered while previous is displayed | FIFO queue, max 3 simultaneous | — | — |
**Accessibility**:
- Screen reader: Toasts must be read aloud without requiring focus. In HTML, this uses `role="status"` or `role="alert"`. In game UI, this requires the engine's accessibility notification system. Verify engine support in engine-reference docs.
- Motion reduction: Slide animation replaced with fade only.
- Toasts must never be the sole communication channel for information the player needs to act on. If the information requires action, use a persistent UI element in addition to the toast.
- Auto-dismiss timer: 5 seconds is the minimum. Players with cognitive processing differences may need more time. Consider a setting to extend to 10 or 15 seconds.
**Implementation Notes**: [Godot: Manage a queue of `PanelContainer` scenes in a
`VBoxContainer` anchored to a screen corner. Each toast is instantiated, added to
the container, then auto-removed after a timer. The container should be on a high
`CanvasLayer` (50+) but below modal dialogs (100+). Animate using a `Tween` on
`modulate.a` and `position.x`. When motion reduction is active, skip the position
animation.]
---
#### Tooltip
**Category**: Feedback
**Status**: Draft
**When to Use**: Contextual information that supplements a visible label. Item
descriptions in inventory. Stat explanations on a character sheet. Setting
descriptions in accessibility options. The player must be able to access this
information or proceed without it.
**When NOT to Use**: Information the player MUST read to complete an action — put
that in the label or body text, not a tooltip. Tooltips are not discoverable
on mobile touch without a hover state. On touch-only platforms, use an info button
that opens a description modal instead.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Hidden | — | — | — | — | — |
| Hover trigger | — | Mouse enters element | Begin 400ms delay timer | — | — |
| Gamepad/keyboard trigger | — | Element receives focus | Begin 300ms delay timer (shorter because navigation is intentional) | — | — |
| Appearing | Tooltip panel fades in and scales from 0.95 to 1.0. Positioned near element (prefer above, adjust if near screen edge). | Timer expires | Show tooltip | 120ms ease-out | — |
| Displayed | Tooltip visible. Title (optional). Body text. Max width: 300px. Multiple lines allowed. | — | — | — | — |
| Hiding | Tooltip fades out | Mouse leaves element / focus moves away | Hide tooltip | 80ms ease-in | — |
**Accessibility**:
- Screen reader: Tooltip content must be accessible without hover. The accessible name of the parent element should include the most critical tooltip information. The full tooltip text is optionally in the `description` property. Screen reader reads tooltip content when element is focused.
- The delay (300-400ms) prevents accidental tooltip display and is required — instant tooltips are disruptive in gamepad navigation.
- Tooltip text must meet the same contrast requirements as body text (4.5:1 minimum).
**Implementation Notes**: [Godot: Attach a custom `TooltipControl` scene as a
child of the trigger element. Show/hide with a `Timer` node. Position the tooltip
using a `CanvasLayer` to ensure it appears above all other UI. For screen edges,
detect if the tooltip rect extends beyond `get_viewport_rect()` and flip the
position to the opposite side.]
---
#### Progress Bar
**Category**: Feedback / Layout
**Status**: Draft
**When to Use**: Linear progress toward a defined endpoint. Loading screens (time
to completion), XP fill toward next level, quest objectives with countable progress
("3 of 10 enemies defeated"), download progress.
**When NOT to Use**: Circular or radial progress (use a separate Radial Progress
pattern if needed). Values that fluctuate up and down rapidly (use Health/Resource
Bar pattern). Values with no defined endpoint.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Track (full width, background color). Fill (left to right, value color). Value label (percentage or N/M, outside or inside fill). | — | — | — | — |
| Value increasing | Fill width animates to new value | Value changes | Smooth fill animation | 300ms ease-out | [Context-dependent — XP gain has a sound; loading has none] |
| Value at maximum | Fill reaches full width. Optional: completion animation (pulse, glow). | Value reaches 100% | Completion event fires | 200ms | [Completion sound if appropriate] |
| Value at zero | Fill hidden (zero width). Track still visible. | — | — | — | — |
| Indeterminate (unknown duration) | Animated loop (fill segment moves left-to-right, repeat). Used for loading of unknown duration. | — | — | Infinite loop | — |
**Accessibility**:
- Screen reader: Role: "progressbar." Accessible name: what is progressing (e.g., "Experience Points," "Loading"). Value: current numeric value AND percentage AND maximum. "Experience Points, 450 of 1000, 45 percent." Update on significant changes (not every pixel).
- Do not rely only on fill color to communicate value. Include a numeric label.
- Indeterminate progress bars: announce "Loading, in progress" — do not announce changes since the value is unknown.
- Motion reduction: Indeterminate animation is replaced with a static "loading" indicator. Smooth fill animation is replaced with instant jump to new value.
**Implementation Notes**: [Godot: `ProgressBar` built-in with custom theming.
For indeterminate mode, `ProgressBar` does not have a native indeterminate state
in Godot 4.x — implement using a looping `Tween` on a fill element's position.
Ensure the Tween is paused when motion reduction mode is active and a static
indicator is shown instead.]
---
#### Input Field
**Category**: Input
**Status**: Draft
**When to Use**: Text entry. Player name on a new save, search within a list,
remapping a key binding (special case — shows the key press, not typed text),
entering a numeric value precisely.
**When NOT to Use**: Selecting from known options (use Dropdown or List). On
console-primary platforms, minimize text entry — it requires a virtual keyboard,
which is high friction.
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default | Field border, placeholder text (label-style, muted color), empty input area. | — | — | — | — |
| Hovered | Border brightens slightly | Mouse over | — | 60ms | — |
| Focused | Border brightens fully. Cursor (blinking, 530ms on/530ms off). Placeholder text hidden. | Tab / click | Open virtual keyboard on console/mobile | Instant | [UI focus sound] |
| Typing | Characters appear. Cursor advances. | Keyboard input | Update field value | Immediate | [Subtle keystroke sound, optional] |
| Value present | Field shows typed value. Placeholder hidden. Clear button appears (X, right of field) if value is non-empty. | — | — | — | — |
| Character limit reached | No further input accepted. Optional: brief shake animation and limit indicator changes color. | Input at limit | Reject further characters | 200ms shake | [UI error sound, subtle] |
| Clear | Field empties. Cursor returns. Clear button disappears. | Click X / gamepad clear input | Clear value | Instant | [UI cancel sound, subtle] |
| Validation error | Border turns error color (red — ensure colorblind safe). Error message appears below field. | On submit or on blur | Show error | Instant | [UI error sound] |
| Validated / correct | Border turns success color (green — ensure colorblind safe). Success icon optional. | On validation pass | — | Instant | — |
| Disabled | 40% opacity, no interaction. Value still visible. | — | — | — | — |
**Accessibility**:
- Keyboard: All standard text editing shortcuts (Home, End, Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+Z).
- Screen reader: Role: "textbox." Accessible name: field label (not placeholder text). Current value announced. Character limit announced when reached. Validation errors announced immediately on occurrence.
- Placeholder text must not be used as the only label — a visible label above or beside the field is required. Placeholder text disappears when the player types, causing confusion for players with cognitive or memory impairments.
**Implementation Notes**: [Godot `LineEdit`: set `placeholder_text` for the hint
but always include a visible `Label` node as the field's accessible name. Bind
`text_changed` signal for real-time validation. Bind `text_submitted` for form
submission on Enter. On console, `LineEdit.call("_popup_keyboard")` or use the OS
virtual keyboard API — verify against engine-reference/godot/ for Godot 4.6
console keyboard API specifics.]
---
#### Tab Bar
**Category**: Navigation
**Status**: Draft
**When to Use**: Dividing a single screen's content into discrete sections where
only one section is visible at a time. Character sheet tabs (Stats / Equipment /
Skills), settings tabs (Gameplay / Graphics / Audio / Accessibility). Maximum
5-6 tabs before the pattern breaks down and a sidebar navigation should be
considered instead.
**When NOT to Use**: More than 6 tabs. Content that benefits from simultaneous
visibility (use a layout pattern instead). Navigation between different screens
(use Screen Push).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Default (inactive tab) | Tab label. No active indicator. | — | — | — | — |
| Active tab | Tab label. Active indicator (underline, fill, or contrasting background). Content area shows this tab's content. | — | — | — | — |
| Hovered (inactive) | Tab background fills slightly | Mouse over | — | 60ms | — |
| Focused (keyboard/gamepad) | Focus ring on tab label. | Tab key (within tab bar) or D-pad left/right on tab row | — | 60ms | [UI focus sound] |
| Activated | Active indicator transitions to this tab. Content area transitions (fade or slide). | Click / Enter / A / Cross | Switch active tab. Content update. | 150ms ease | [UI tab switch sound] |
| Gamepad shoulder button | — | L1/R1 (PS) or LB/RB (Xbox) | Switch to previous/next tab (standard platform convention) | 150ms | [UI tab switch sound] |
**Accessibility**:
- Keyboard: Arrow keys navigate between tabs within the tab bar (left/right). Tab key moves focus into the content area below. This follows the ARIA tab panel pattern.
- Screen reader: Role: "tab" for individual tabs. Role: "tablist" for the container. Role: "tabpanel" for the content area. Active tab state: "selected." Accessible name: tab label. Tabpanel is labeled by its corresponding tab.
- The active tab must be visually distinguishable by more than color alone (underline, fill pattern, or weight change in addition to color).
**Implementation Notes**: [Godot: `TabContainer` built-in. For custom visual
styling, implement manually with a `HBoxContainer` of tab buttons and a
`MarginContainer` for content. The shoulder button shortcut (LB/RB) must be
implemented in the screen's `_input()` override — it is not built into Godot's
tab system. Check platform conventions: Xbox uses LB/RB; PlayStation uses L1/R1;
both are the same physical button, so a single binding works.]
---
#### Scroll Container
**Category**: Layout
**Status**: Draft
**When to Use**: Content that exceeds the visible area of its container. Inventory
lists, lore entry text, credits, long settings lists. The scroll indicator shows
the player that more content exists.
**When NOT to Use**: Content that can be paginated instead (pagination may be
clearer for dense list navigation). Infinite scroll (always provide a loading
state and an end state).
**Interaction Specification**:
| State | Visual | Input | Response | Duration | Audio |
|-------|--------|-------|----------|----------|-------|
| Content fits | No scrollbar visible (or always-visible scrollbar at full height, depending on art direction). | — | — | — | — |
| Scrollable | Scrollbar appears (right edge). Scrollbar thumb size represents viewport vs. content ratio. | — | — | — | — |
| Scrolling (mouse) | Content moves. Scrollbar thumb moves proportionally. | Mouse wheel | Scroll by 3 lines per wheel tick (configurable in OS) | Smooth | — |
| Scrollbar drag | Content moves. Thumb follows pointer. | Click + drag scrollbar thumb | Scroll proportionally | Real time | — |
| Keyboard scroll | Content moves one item height per keypress. | Up/Down arrows when container is focused and no child is focused | Scroll by one unit | Immediate | — |
| Gamepad scroll | Content moves to keep focused item in view. | D-pad navigation to items beyond visible area | Auto-scroll to keep focused item visible | Smooth 150ms | — |
| Scroll top / bottom | Content stops. Scrollbar thumb at end. | Content boundary reached | Stop scrolling | — | — |
| Focus follows scroll | When a child element receives focus, scroll container ensures it is fully visible. | Any child receives focus | Scroll to reveal focused element | 200ms ease | — |
**Accessibility**:
- Keyboard/Gamepad: The scroll container itself should not require explicit scrollbar interaction — navigating list items inside it should auto-scroll to keep focused items in view.
- Screen reader: The scroll container announces "scrollable" and the scroll position ("showing items 5 through 15 of 30"). This requires engine accessibility support — verify in engine-reference/godot/.
- Fade edges (content fading at scroll boundaries to indicate more content exists) are a helpful visual affordance but must not be the only indicator that content exists beyond the visible area. Include a scrollbar.
**Implementation Notes**: [Godot `ScrollContainer`: call `ensure_control_visible()`
on the focused child whenever `gui_focus_changed` fires inside the container.
Bind this via a recursive `connect` on the container's `gui_focus_changed` signal.
For smooth scroll animation, use a `Tween` on `scroll_vertical` rather than
setting it directly.]
---
@@ -0,0 +1,20 @@
> Authoring guidance for interaction-pattern-library.md. Load only the part covering the section currently being authored — not the whole file at once.
# Interaction Pattern Library — Guidance Index
The guidance for this template is split by major section so consumers can load
one part at a time. Read the file matching the section you are currently
authoring — never all three at once.
| Template Section | Guidance File |
|------------------|---------------|
| Standard Control Patterns (Button variants, Toggle, Slider, Dropdown / Select, List Item, Grid Item, Modal Dialog, Confirmation Dialog, Toast / Notification, Tooltip, Progress Bar, Input Field, Tab Bar, Scroll Container) | `.claude/docs/templates/guidance/interaction-pattern-library-guide-standard-controls.md` |
| Game-Specific UI Patterns (Inventory Slot, Ability / Skill Icon, Health / Resource Bar, Dialogue Box, Context Action Prompt, Damage Number) | `.claude/docs/templates/guidance/interaction-pattern-library-guide-game-specific.md` |
| Navigation Patterns + Feedback and Loading Patterns (Screen Push / Pop / Replace, Focus Management, Escape / Cancel, Loading State, Empty State, Error State) | `.claude/docs/templates/guidance/interaction-pattern-library-guide-navigation-feedback.md` |
Each guidance file contains the full reference specification for its patterns —
When to Use / When NOT to Use rationale, complete state tables with timing and
audio values, accessibility requirements, and engine implementation notes. Use
them as the worked-example source when filling the corresponding skeleton stubs
in the template. The Pattern Catalog Index, Animation Standards, Sound
Standards, and Open Questions sections remain in the template itself.
+443
View File
@@ -0,0 +1,443 @@
> Authoring guidance for ux-spec.md. Load only the part covering the section currently being authored — not the whole file at once.
# UX Specification Template — Authoring Guidance
Guidance is organized by template section number. When authoring a section of a
project's UX spec, read only that section's guidance below.
---
## Section 1 — Purpose & Player Need
> **Why this section exists**: Every screen must justify its existence from the
> player's perspective. Screens that are designed from a developer perspective ("display
> the save data") produce cluttered, confusing interfaces. Screens designed from the
> player's perspective ("let the player feel confident their progress is safe before they
> put the controller down") produce purposeful, calm interfaces. Write this section before
> touching any layout decisions — it is the filter through which every subsequent choice
> is evaluated.
**Authoring the player need**:
[One paragraph. Name the real human need, not the system function. Consider: what would
a player say they want when they open this screen? What would frustrate them if it did
not work? That frustration describes the need.
Example — bad: "Displays the player's current items and equipment."
Example — good: "Lets the player understand what they're carrying and quickly decide what
to take into the next encounter, without breaking their mental model of the game world.
The inventory is the player's planning tool between moments of action."]
**Authoring the player goal**:
[One sentence. Specific enough that you could write an acceptance criterion for it.
Example: "Find the item they are looking for within three button presses and equip it
without navigating to a separate screen."]
**Authoring the game goal**:
[One sentence. This is what the system needs from this interaction. Example: "Record the
player's equipment choices and relay them to the combat system before the next encounter
loads." This section prevents UI that looks good but fails to serve the system it is
part of.]
---
## Section 2 — Player Context on Arrival
> **Why this section exists**: Screens do not exist in isolation. A player opening the
> inventory mid-combat is in a completely different cognitive and emotional state than
> a player opening it after clearing a dungeon. The same information architecture can
> feel oppressively complex in one context and trivially simple in another. Document the
> context so that design decisions — what to show first, what to hide, what to animate,
> what to simplify — are calibrated to the actual player arriving at this screen, not
> an abstract user.
**Worked example answers for the context table**:
| Question | Answer |
|----------|--------|
| What was the player just doing? | [e.g., Completed a combat encounter / Pressed Esc from exploration / Triggered a story cutscene] |
| What is their emotional state? | [e.g., High tension — just narrowly survived / Calm — exploring between objectives] |
| What cognitive load are they carrying? | [e.g., High — actively tracking enemy positions / Low — no active threats] |
| What information do they already have? | [e.g., They know they just picked up an item but haven't seen its stats yet] |
| What are they most likely trying to do? | [e.g., Check if the new item is better than their current weapon — primary use case] |
| What are they likely afraid of? | [e.g., Missing something, making an irreversible mistake, losing track of where they were] |
**Authoring the emotional design target**:
[One sentence describing the feeling the player should have while using this screen.
Example: "Confident and in control — the player should feel like they have complete
information and complete authority over their choices, with no ambiguity about outcomes."]
---
## Section 3 — Navigation Position
> **Why this section exists**: A screen that does not know where it sits in the
> navigation hierarchy cannot define its entry/exit transitions, its back-button
> behavior, or its relationship to the game's pause state. Navigation position also
> reveals architectural problems early — if this screen is reachable from eight
> different places, that is a complexity flag that should be resolved in design, not
> implementation.
**Worked example — reachability table**:
| Entry Point | Triggered By | Notes |
|-------------|-------------|-------|
| [e.g., Main Menu → Play] | [Player selects "New Game"] | [Primary entry point] |
| [e.g., Pause Menu → Resume] | [Player presses Start from any gameplay state] | [Secondary entry] |
| [e.g., Game event] | [Tutorial system forces open first time only] | [Systemic entry — must not break if player dismisses] |
---
## Section 4 — Entry & Exit Points
> **Why this section exists**: Entry and exit define the screen's contract with the
> rest of the navigation system. Every entry point must have a corresponding exit point.
> Transitions that are undefined become bugs — the player finds themselves stuck, or the
> game state becomes inconsistent. Fill this table completely before implementation
> begins. Empty cells are a sign that design work is unfinished.
**Worked example — entry table**:
| Trigger | Source Screen / State | Transition Type | Data Passed In | Notes |
|---------|----------------------|-----------------|----------------|-------|
| [e.g., Player presses Inventory button] | [Gameplay / Exploration state] | [Overlay push — game pauses] | [Current player loadout, inventory contents] | [Works from any non-combat state] |
| [e.g., Item pickup prompt accepted] | [Gameplay / Item Pickup dialog] | [Replace dialog with full inventory] | [Newly acquired item pre-highlighted] | [The new item should be visually distinguished on open] |
| [e.g., Quest system directs player to inventory] | [Gameplay / Quest Update notification] | [Overlay push] | [Quest-relevant item ID for highlight] | [Screen should deep-link to the relevant item] |
**Worked example — exit table**:
| Exit Action | Destination | Transition Type | Data Returned / Saved | Notes |
|-------------|------------|-----------------|----------------------|-------|
| [e.g., Player closes inventory (Back/B/Esc)] | [Previous state — Exploration] | [Overlay pop — game resumes] | [Updated equipment loadout committed] | [Changes must be committed before transition begins] |
| [e.g., Player selects "Equip" on item] | [Same screen, updated state] | [In-place state change] | [Loadout change event fired] | [No navigation, just a state refresh] |
| [e.g., Player navigates to Map from inventory shortcut] | [Map Screen] | [Replace] | [No data] | [Inventory state is preserved if player returns] |
---
## Section 5 — Layout Specification
> **Why this section exists**: The layout specification is the handoff artifact between
> UX design and UI programming. It does not need to be pixel-perfect — it needs to
> communicate hierarchy (what is important), proximity (what belongs together), and
> proportion (what is big vs. small). ASCII wireframes achieve this without requiring
> design software. A programmer who reads this section should be able to build the
> correct structure without guessing. An artist who reads it should know where
> visual weight should be concentrated.
>
> Draw the layout at one standard resolution (e.g., 1920x1080). Note adaptations
> for other resolutions separately.
**Worked example — wireframe (5.1)**:
```
Example:
┌──────────────────────────────────────────────┐
│ [← Back] INVENTORY [Options] │ ← HEADER ZONE
├──────────────────────────────────────────────┤
│ ┌──────────────┐ ┌─────────────────────────┐│
│ │ CATEGORY NAV │ │ ITEM DETAIL PANEL ││ ← CONTENT ZONE
│ │ ● Weapons │ │ Item Name ││
│ │ Armor │ │ {item icon} ││
│ │ Consumable│ │ Stats comparison ││
│ │ Key Items │ │ Description text... ││
│ ├──────────────┤ └─────────────────────────┘│
│ │ ITEM GRID │ │
│ │ {□}{□}{□}{□} │ │
│ │ {□}{□}{□}{□} │ │
│ │ ... │ │
│ └──────────────┘ │
├──────────────────────────────────────────────┤
│ [Equip] [Drop] [Compare] [Close] │ ← ACTION BAR
└──────────────────────────────────────────────┘
```
**Worked example — zone definitions table (5.2)**:
| Zone Name | Description | Approximate Size | Scrollable? | Overflow Behavior |
|-----------|-------------|-----------------|-------------|-------------------|
| [e.g., Header Zone] | [Top bar: navigation, screen title, global actions] | [Full width, ~10% height] | [No] | [Truncate long screen names with ellipsis] |
| [e.g., Category Nav] | [Left panel: item category tabs] | [~25% width, ~75% height] | [Yes — vertical if categories exceed panel] | [Scroll indicator appears at bottom of list] |
| [e.g., Item Grid] | [Center: grid of item icons for selected category] | [~45% width, ~75% height] | [Yes — vertical] | [Page-based: 4x4 grid, next page on overflow] |
| [e.g., Detail Panel] | [Right: stats and description for selected item] | [~30% width, ~75% height] | [Yes — vertical for long descriptions] | [Fade at bottom, scroll to reveal] |
| [e.g., Action Bar] | [Bottom: context-sensitive actions for selected item] | [Full width, ~15% height] | [No] | [Actions collapse to icon-only below 4] |
**Worked example — component inventory table (5.3)**:
| Component Name | Type | Zone | Purpose | Required? | Reuses Existing Component? |
|----------------|------|------|---------|-----------|---------------------------|
| [e.g., Back Button] | [Button] | [Header] | [Returns to previous screen] | [Yes] | [Yes — standard NavButton component] |
| [e.g., Screen Title Label] | [Text] | [Header] | [Displays "INVENTORY" or context name] | [Yes] | [Yes — ScreenTitle component] |
| [e.g., Category Tab] | [Toggle Button] | [Category Nav] | [Filters item grid by category] | [Yes] | [No — new component needed] |
| [e.g., Item Slot] | [Icon + Frame] | [Item Grid] | [Represents one inventory slot, empty or filled] | [Yes] | [No — new component] |
| [e.g., Item Name Label] | [Text] | [Detail Panel] | [Shows selected item's name] | [Yes] | [Yes — BodyText component] |
| [e.g., Stat Comparison Row] | [Compound — label + value + delta] | [Detail Panel] | [Shows stat value vs. currently equipped] | [Yes] | [No — new component] |
| [e.g., Equip Button] | [Primary Button] | [Action Bar] | [Equips selected item in appropriate slot] | [Yes] | [Yes — PrimaryAction component] |
| [e.g., Empty State Message] | [Text + Icon] | [Item Grid] | [Shown when category has no items] | [Yes] | [Yes — EmptyState component] |
**Worked example — primary focus element on open**: [e.g., The first item in the Item Grid — or, if deep-linked, the highlighted item. If the grid is empty, focus lands on the first Category Tab.]
---
## Section 6 — States & Variants
> **Why this section exists**: A screen is not a single picture — it is a set of
> states, each of which must look correct and behave correctly. Screens that are
> designed only in their "happy path" state ship with broken empty states, invisible
> loading indicators, and crashes when data is missing. Document every state before
> implementation. The states table is also the test matrix for QA.
**Worked example table**:
| State Name | Trigger | What Changes Visually | What Changes Behaviorally | Notes |
|------------|---------|----------------------|--------------------------|-------|
| [Loading] | [Screen is opening, data not yet available] | [Item Grid shows skeleton/shimmer placeholders; Action Bar buttons disabled] | [No interactions possible except Close] | [Should not be visible >500ms under normal conditions; if it is, investigate data fetch performance] |
| [Empty — no items in category] | [Player switches to a category with zero items] | [Item Grid replaced by EmptyState component: icon + "Nothing here yet."] | [Action Bar shows no item actions; Drop/Equip/Compare all hidden] | [Do not show disabled buttons — remove them. Disabled buttons with no tooltip are confusing.] |
| [Populated — items present] | [Category has at least one item] | [Item Grid fills with item slots; first slot is auto-focused] | [All item actions available for selected item] | [Default and most common state] |
| [Item Selected] | [Player navigates to an item slot] | [Detail Panel populates; selected slot has focus ring; Action Bar updates to item's valid actions] | [Equip/Drop/Compare enabled based on item type] | [Equip is disabled if item is already equipped — show a "Equipped" badge instead] |
| [Confirmation Pending — Drop] | [Player selects Drop action] | [Confirmation dialog overlays the screen] | [All background interactions suspended until dialog resolves] | [Use a modal confirmation, not an inline toggle. Items cannot be recovered after dropping.] |
| [Error — data load failed] | [Inventory data could not be retrieved] | [Item Grid shows error state: icon + "Couldn't load items." + Retry button] | [Only Retry and Close are available] | [Log the error; do not expose technical details to player] |
| [Item Newly Acquired] | [Screen opened from item pickup deep-link] | [Newly acquired item has a visual "New" badge; Detail Panel pre-populated with that item] | [Same as Item Selected but with badge until player navigates away] | [Badge persists until the player manually navigates off that slot once] |
---
## Section 7 — Interaction Map
> **Why this section exists**: This section is the source of truth for what every
> input does on this screen. It forces the designer to think through every input
> method (mouse, keyboard, gamepad, touch) and every interactive state (hover, focus,
> pressed, disabled). Gaps in this table are bugs waiting to happen. The
> interaction map is also the input for the accessibility audit — if an action is
> only reachable by mouse, it will fail the keyboard and gamepad columns.
**Worked example — navigation inputs (7.1)**:
| Input | Platform | Action | Visual Response | Audio Cue | Notes |
|-------|----------|--------|-----------------|-----------|-------|
| [Arrow keys / D-Pad] | [All] | [Move focus within active zone] | [Focus ring moves to adjacent element] | [Soft navigation tick] | [Wrap at edges within zone; do not cross zones with arrows alone] |
| [Tab / R1] | [KB / Gamepad] | [Move focus to next zone (Category → Grid → Detail → Action Bar)] | [Focus ring jumps to first element in next zone] | [Distinct zone-change tone] | [Shift+Tab / L1 goes backward] |
| [Mouse hover] | [PC] | [Show hover state on interactive elements] | [Highlight / underline / color shift] | [None] | [Hover does NOT move focus — only click does] |
| [Mouse click] | [PC] | [Select and focus the clicked element] | [Pressed state flash, then selected/focused] | [Soft click] | [Right-click opens context menu if applicable; otherwise no-op] |
| [Touch tap] | [Mobile] | [Select and activate in one gesture] | [Press ripple] | [Soft click] | [Treat tap as click + confirm for low-risk actions; require explicit confirm for destructive actions] |
**Worked example — action inputs (7.2)**:
| Input | Platform | Context (What must be focused) | Action | Response | Animation | Audio Cue | Notes |
|-------|----------|-------------------------------|--------|----------|-----------|-----------|-------|
| [Enter / A button / Left click] | [All] | [Item slot focused] | [Select item → populate Detail Panel] | [Detail panel slides in or updates in place] | [Panel fade/slide in, 120ms] | [Soft select tone] | [If item already selected: no-op] |
| [Enter / A button] | [All] | [Equip button focused] | [Equip selected item] | [Button animates press; item badge updates to "Equipped"; previously equipped item loses badge] | [Badge swap, 80ms] | [Equip success sound] | [Fires EquipItem event to Inventory system] |
| [Triangle / Y button / Right-click] | [All] | [Item slot focused] | [Open item context menu] | [Context menu appears adjacent to item slot] | [Popover, 80ms] | [Menu open sound] | [Context menu contains: Equip, Drop, Inspect, Compare] |
| [Square / X button] | [Gamepad] | [Item slot focused] | [Quick-equip without opening detail] | [Equip animation plays inline on slot] | [Slot flash, 80ms] | [Equip success sound] | [Convenience shortcut; does not change screen state] |
| [Esc / B button / Back] | [All] | [Any, screen level] | [Close screen and return to previous state] | [Screen exit transition plays] | [Slide out, 200ms] | [Back/close tone] | [Commits all changes before closing. No discard — inventory is not a draft.] |
| [F / L2] | [KB / Gamepad] | [Any] | [Toggle filter panel] | [Sort/filter overlay opens] | [Slide in from right, 200ms] | [Panel open tone] | [If no items in category, filter is disabled] |
**Worked example — state-specific behaviors (7.3)**:
| State | Input Restriction | Reason |
|-------|------------------|--------|
| [Loading] | [All item and action inputs disabled] | [No data to act on; prevent race conditions] |
| [Confirmation dialog open] | [Only Confirm and Cancel inputs active] | [Modal — background is locked] |
| [Error state] | [Only Retry and Close active] | [No data available to navigate] |
---
## Section 8 — Data Requirements
> **Why this section exists**: The separation between UI and game state is the most
> important architectural boundary in a game's UI system. UI reads data; it does not
> own it. UI fires events; it does not write state directly. This section defines
> exactly what data this screen needs to display, where it comes from, and how
> frequently it updates. Filling this table before implementation prevents two
> common failure modes: (1) UI developers reaching into systems they should not touch,
> and (2) systems not knowing they need to expose data until a UI is half-built.
**Worked example table**:
| Data Element | Source System | Update Frequency | Who Owns It | Format | Null / Missing Handling |
|--------------|--------------|-----------------|-------------|--------|------------------------|
| [e.g., Item list] | [Inventory System] | [On screen open; on InventoryChanged event] | [InventorySystem] | [Array of ItemData structs: id, name, icon_path, category, stats, is_equipped] | [Empty array → show Empty State. Never null — system must return array.] |
| [e.g., Equipped loadout] | [Equipment System] | [On screen open; on EquipmentChanged event] | [EquipmentSystem] | [Dict mapping slot_id → item_id] | [Unequipped slot has null value — UI shows empty slot icon] |
| [e.g., Item stat comparisons] | [Stats System] | [On item selection change] | [StatsSystem] | [Dict mapping stat_name → {current, new, delta}] | [If no item selected, detail panel shows placeholder. Stats system must handle this gracefully.] |
| [e.g., Player currency] | [Economy System] | [On screen open only — inventory does not show live currency] | [EconomySystem] | [Int — gold pieces] | [If currency system not active for this game mode, hide the currency row entirely] |
| [e.g., Newly acquired item flag] | [Inventory System] | [On screen open] | [InventorySystem] | [Array of item_ids flagged as new] | [If empty array, no badges shown] |
---
## Section 9 — Events Fired
> **Why this section exists**: This is the other half of the UI/system boundary.
> Where Section 8 defines what the UI reads, this section defines what the UI
> communicates back to the game. Specifying events at design time prevents UI
> programmers from writing game logic, and prevents game programmers from being
> surprised by what the UI does. Every destructive or state-changing player action
> must appear in this table.
**Worked example table**:
| Player Action | Event Fired | Payload | Receiver System | Notes |
|---------------|-------------|---------|-----------------|-------|
| [Player equips an item] | [EquipItemRequested] | [{item_id: string, target_slot: string}] | [Equipment System] | [Equipment System validates the action and fires EquipmentChanged if successful; UI listens for EquipmentChanged to update its display] |
| [Player drops an item] | [DropItemRequested] | [{item_id: string, quantity: int}] | [Inventory System] | [Fires only after player confirms the drop dialog. Inventory System removes the item and fires InventoryChanged.] |
| [Player opens item compare] | [ItemCompareOpened] | [{item_a_id: string, item_b_id: string}] | [Analytics System] | [No game-state change — analytics event only. Compare view is purely local UI state.] |
| [Player closes screen] | [InventoryScreenClosed] | [{session_duration_ms: int}] | [Analytics System] | [Fires on every close regardless of reason. Used for engagement metrics.] |
| [Player navigates between categories] | [InventoryCategoryChanged] | [{category: string}] | [Analytics System] | [Analytics only. No game state change.] |
---
## Section 10 — Transition & Animation
> **Why this section exists**: Transitions are not decoration — they communicate
> hierarchy and causality. A screen that slides in from the right implies the
> player has moved forward. A screen that fades implies a context break. Inconsistent
> transitions make navigation feel broken even when it is technically correct.
> This section ensures transitions are specified intentionally, not left to the
> developer's discretion, and that accessibility settings (reduced motion) are
> planned for from the start.
**Worked example table**:
| Transition | Trigger | Direction / Type | Duration (ms) | Easing | Interruptible? | Skipped by Reduced Motion? |
|------------|---------|-----------------|--------------|--------|----------------|---------------------------|
| [Screen enter] | [Screen pushed onto stack] | [Slide in from right] | [250] | [Ease out cubic] | [No — must complete before interaction is enabled] | [Yes — instant appear at 0ms] |
| [Screen exit — Back] | [Player presses Back] | [Slide out to right] | [200] | [Ease in cubic] | [No] | [Yes — instant disappear] |
| [Screen exit — Forward] | [Player navigates to child screen] | [Slide out to left] | [200] | [Ease in cubic] | [No] | [Yes — instant] |
| [Detail panel update] | [Player selects a new item] | [Cross-fade content] | [120] | [Linear] | [Yes — if player navigates quickly, previous animation cancels] | [Yes — instant swap] |
| [Loading → Populated] | [Data arrives after load] | [Skeleton shimmer fades out, content fades in] | [180] | [Ease out] | [No] | [Yes — instant reveal] |
| [Action Bar button press] | [Player activates a button] | [Scale down 95% on press, return on release] | [60 down / 60 up] | [Ease out / ease in] | [Yes — if released early, returns to normal] | [No — this is tactile feedback, not decorative motion] |
| [Confirmation dialog open] | [Player initiates destructive action] | [Background dims 60% opacity; dialog scales up from 95%] | [150] | [Ease out] | [No] | [Yes — instant appear, no scale] |
| [New item badge appear] | [Screen opens with newly acquired item] | [Badge pops from 0% to 110% to 100% scale] | [200 total] | [Ease out back] | [No] | [Yes — instant appear at 100% scale] |
---
## Section 11 — Input Method Completeness Checklist
> **Why this section exists**: Input completeness is not optional — it is a
> certification requirement for console platforms and a legal risk area for
> accessibility laws in multiple markets. Fill this checklist before marking
> the spec as Approved. Any unchecked item blocks implementation start.
---
## Section 12 — Screen-Level Accessibility Requirements
> **Why this section exists**: Accessibility requirements must be specified at design
> time because retrofitting them is expensive and often architecturally impractical.
> This section documents requirements specific to this screen. Project-wide standards
> live in `design/accessibility-requirements.md` — consult it before filling this
> section so you do not duplicate or contradict project-level commitments.
**Worked example — text contrast table**:
| Text Element | Background Context | Required Ratio | Current Ratio | Pass? |
|--------------|-------------------|---------------|---------------|-------|
| [e.g., Item name in Detail Panel] | [Dark panel background ~#1a1a1a] | [4.5:1 (WCAG AA normal text)] | [TBD — verify in implementation] | [ ] |
| [e.g., Category tab label — inactive] | [Mid-grey tab background] | [4.5:1] | [TBD] | [ ] |
| [e.g., Category tab label — active] | [Accent color background] | [4.5:1] | [TBD] | [ ] |
| [e.g., Action button label] | [Button color (varies by state)] | [4.5:1] | [TBD] | [ ] |
| [e.g., Stat comparison delta (positive)] | [Detail panel] | [4.5:1 — do NOT rely on green color alone] | [TBD] | [ ] |
**Worked example — colorblind mitigations table**:
| Element | Colorblind Risk | Mitigation |
|---------|----------------|------------|
| [e.g., Stat delta indicators (red/green for worse/better)] | [Red-green colorblindness (Deuteranopia) — most common form] | [Add arrow icons (↑ / ↓) and +/- prefix in addition to color. Color is a redundant, not sole, indicator.] |
| [e.g., Item rarity color coding (grey/green/blue/purple/orange)] | [Multiple types — rarity color is a common industry failure] | [Add rarity name text label below icon. Color is supplemental only.] |
**Worked example — focus order**:
[e.g.,
1. Back button (Header)
2. Options button (Header)
3. Category Tab 1 — Weapons
4. Category Tab 2 — Armor
5. Category Tab 3 — Consumables
6. Category Tab 4 — Key Items
7. Item Slot [0,0]
8. Item Slot [0,1] ... (grid traverses left-to-right, top-to-bottom)
9. Last item slot
10. Equip button (Action Bar)
11. Drop button (Action Bar)
12. Compare button (Action Bar)
13. Close button (Action Bar)
→ Cycles back to Back button
Focus does not enter the Detail Panel — it is a display panel driven by item focus, not independently navigable.]
**Worked example — screen reader announcements table**:
| State Change | Announcement Text | Announcement Timing |
|--------------|------------------|---------------------|
| [Screen opens] | ["Inventory screen. [N] items. [Active category] selected."] | [On screen focus settle] |
| [Player focuses an item slot] | ["[Item name]. [Category]. [Rarity]. [Key stats summary]. [Equipped / Not equipped]."] | [On focus arrival] |
| [Player equips an item] | ["[Item name] equipped to [slot name]."] | [After EquipmentChanged event confirmed] |
| [Player drops an item] | ["[Item name] dropped."] | [After InventoryChanged event confirmed] |
| [Category changes] | ["[Category name]. [N] items."] | [On category tab focus] |
| [Empty state shown] | ["No items in [category name]."] | [When empty state renders] |
**Authoring the cognitive load assessment**:
[Estimate the number of information streams the player is simultaneously tracking while
using this screen. For this screen: (1) item grid position, (2) item detail stats,
(3) current equipment loadout for comparison, (4) available actions, (5) item category.
That is 5 concurrent streams — within the standard 7±2 limit, but at the higher end.
Mitigation: detail panel auto-updates on navigation so the player never needs to
manually retrieve item info. Reduce active decisions by surfacing stat comparison
automatically.]
---
## Section 13 — Localization Considerations
> **Why this section exists**: UI built without localization in mind breaks on first
> translation. German text is typically 30–40% longer than English. Arabic and Hebrew
> require right-to-left layout mirroring. Japanese and Chinese text may be significantly
> shorter than English, creating awkward whitespace. These issues are cheap to plan for
> and expensive to fix after a layout is built and shipped. Every text element should
> have an explicit max-character count and a plan for overflow.
**Worked example table**:
| Text Element | English Baseline Length | Max Characters | Expansion Budget | RTL Behavior | Overflow Behavior | Risk |
|--------------|------------------------|----------------|-----------------|--------------|-------------------|------|
| [e.g., Screen title "INVENTORY"] | [9 chars] | [16 chars] | [78%] | [Mirror to right, or center — acceptable] | [Truncate with ellipsis — title is not critical content] | [Low] |
| [e.g., Item name] | [~15 chars avg, max ~35 "Enchanted Dragon Scale Gauntlets"] | [50 chars] | [43%] | [Right-align in RTL layouts] | [Truncate with tooltip showing full name on hover/focus] | [Medium — long fantasy item names are common] |
| [e.g., Item description] | [~80–120 chars] | [200 chars] | [67%] | [Right-align, wrap normally] | [Scroll within Detail Panel — no truncation] | [Low — panel is scrollable] |
| [e.g., Action button "Equip"] | [5 chars] | [14 chars] | [180%] | [Button layout mirrors; text right-aligns] | [Shrink font to 90% minimum, then truncate] | [Medium — "Ausrüsten" in German is 9 chars] |
| [e.g., Category tab "Consumables"] | [11 chars] | [18 chars] | [64%] | [Mirror tab position] | [Abbreviate: "Consum." — define abbreviations per language in loc file] | [High — long localized tab labels are a known problem] |
---
## Section 14 — Acceptance Criteria
> **Why this section exists**: Acceptance criteria are the contractual definition of
> "done." Without them, implementation is complete when the developer says it is.
> With them, implementation is complete when a QA tester can verify every item on
> this list. Write criteria that a tester can verify independently, without asking the
> designer what they meant. Every criterion should be binary — pass or fail, not
> subjective.
**Worked example criteria (inventory screen)** — note how each is screen-specific
and independently verifiable:
- [ ] Navigation between items produces no perceptible frame drop (maintain target framerate ±5fps)
- [ ] All states (Loading, Empty, Populated, Error, Confirmation) render correctly
- [ ] Item grid scrolls smoothly without frame drops when all item slots are populated
- [ ] Inventory changes persist correctly after screen is closed and reopened
- [ ] Screen handles InventoryChanged events fired by other systems while it is open without crashing
- [ ] Stat comparison does not rely on color alone as the sole differentiator
- [ ] Screen reader announces item name and key stats on focus (verify with platform screen reader)
---
## Section 15 — Open Questions
**Worked example questions**:
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [e.g., Should item comparison be automatic (always showing equipped stats) or player-triggered (press Compare)?] | [ui-designer] | [Sprint 4, Day 3] | [Pending] |
| [e.g., Do we support controller cursor (free aim) in the item grid, or d-pad-only grid navigation?] | [lead-programmer + ui-designer] | [Sprint 4, Day 3] | [Pending — depends on ADR-0015 input model decision] |
| [e.g., What is the game's item drop policy — permanent loss or drop-to-world?] | [systems-designer] | [Requires GDD update] | [Blocked on inventory GDD Edge Cases section] |
| [e.g., Maximum inventory size — does the grid have a hard cap or is it infinite-scroll?] | [economy-designer] | [Sprint 3, Day 5] | [Pending] |
+67 -242
View File
@@ -1,5 +1,7 @@
# HUD Design: [Game Name]
> Authoring guidance: .claude/docs/templates/guidance/hud-design-guide.md (load per-section as you author — do not read entirely).
> **Status**: Draft | In Review | Approved | Implemented
> **Author**: [Name or agent — e.g., ui-designer]
> **Last Updated**: [Date]
@@ -20,89 +22,34 @@
## 1. HUD Philosophy
> **Why this section exists**: The HUD design philosophy is not decoration — it is a
> design constraint that every subsequent decision is measured against. Without a
> philosophy, individual elements get added on request ("the quest tracker wants a
> bigger icon") without any principled way to push back. With a philosophy, there is
> a shared, explicit standard. More importantly, the philosophy prevents the HUD from
> slowly growing to cover the game world while each individual addition seemed
> reasonable in isolation. Write this before specifying any elements.
**What is this game's relationship with on-screen information?**
[One paragraph. This is a design statement, not a description of features. Consider
the game's genre, pacing, and player fantasy. A stealth game's HUD philosophy might
be: "The world is the interface. If the player has to look away from the environment
to survive, the HUD has failed." A tactics game might say: "Complete situational
awareness is the game. The HUD is not an overlay — it is the battlefield."
Reference comparable games if helpful, but describe your specific stance:
Example — diegetic-first action RPG: "We treat screen information as a concession,
not a feature. Every HUD element must earn its pixel space by answering the question:
would the player make demonstrably worse decisions without this information visible?
If the answer is 'they'd adapt,' we put it in the environment instead."]
[One-paragraph design statement — see guide Section 1 for framing and examples]
**Visibility principle** — when in doubt, show or hide?
[State the default resolution for ambiguous cases. Options:
- Default to HIDE: information is available on demand (e.g., Dark Souls — no quest tracker, no minimap, stats are in a menu)
- Default to SHOW: players prefer to be informed; cluttered is better than uncertain
- Default to CONTEXTUAL: information appears when it becomes relevant and fades when it does not
Most games benefit from contextual defaults. State your game's default clearly so every element decision is consistent.]
[Default resolution for ambiguous cases: HIDE / SHOW / CONTEXTUAL — see guide]
**The Rule of Necessity for this game**:
[Complete this sentence: "A HUD element earns its place when ______________."
Example: "...the player would have to stop playing to find the same information
elsewhere, or would make meaningfully worse decisions without it."
Example: "...removing it in playtesting causes measurable frustration or confusion
in more than 25% of testers within the first hour of play."
This rule is the veto power over feature requests to add HUD elements. Document it
so it can be cited in design reviews.]
["A HUD element earns its place when ______________." — see guide for examples]
---
## 2. Information Architecture
> **Why this section exists**: Before specifying any HUD element's visual design,
> position, or behavior, you must answer a more fundamental question: should this
> information be on the HUD at all? This section is a forcing function — it requires
> you to categorize EVERY piece of information the game world generates and make an
> explicit, intentional decision about how each is presented. "We'll figure that out
> later" is how games end up with 18 elements competing for the player's peripheral
> vision. This table is the master inventory of game information, not just HUD information.
> Categorize EVERY piece of information the game generates — this is the master
> inventory of game information, not just HUD information. See guide Section 2
> for a worked example covering typical information types.
| Information Type | Always Show | Contextual (show when relevant) | On Demand (menu/button) | Hidden (environmental / diegetic) | Reasoning |
|-----------------|-------------|--------------------------------|------------------------|----------------------------------|-----------|
| [Health / Vitality] | [X if action game — player needs constant awareness] | [X if exploration game — show only when injured] | [ ] | [ ] | [Example: always visible because health decisions (retreat, heal) must be instant in combat] |
| [Primary resource (mana / stamina / ammo)] | [ ] | [X — show when resource is being consumed or is critically low] | [ ] | [ ] | [Example: contextual because stable resource levels are not decision-relevant] |
| [Secondary resource (currency / materials)] | [ ] | [ ] | [X — check in inventory] | [ ] | [Example: on-demand because resource totals don't affect immediate gameplay decisions] |
| [Minimap / Compass] | [X] | [ ] | [ ] | [ ] | [Example: always visible because navigation decisions are constant during exploration] |
| [Quest objective] | [ ] | [X — show when objective changes or player is near it] | [ ] | [ ] | [Example: contextual — player knows their objective; only remind at key moments] |
| [Enemy health bar] | [ ] | [X — show only during combat encounters] | [ ] | [ ] | [Example: contextual because enemy health is irrelevant outside combat] |
| [Status effects (buffs/debuffs)] | [ ] | [X — show when active] | [ ] | [ ] | [Example: contextual because status effects only affect decisions when present] |
| [Dialogue subtitles] | [X when dialogue is playing] | [ ] | [ ] | [ ] | [Example: always show while dialogue is active — accessibility requirement] |
| [Combo / streak counter] | [ ] | [X — show while combo is active, hide on reset] | [ ] | [ ] | [Example: contextual because it communicates active performance, not baseline state] |
| [Timer] | [ ] | [X — show only in timed sequences] | [ ] | [ ] | [Example: contextual because timers only exist in specific encounter types] |
| [Tutorial prompts] | [ ] | [X — show for first-time situations only] | [ ] | [ ] | [Example: contextual and one-time; never repeat to experienced players] |
| [Score / points] | [ ] | [X — show in score-relevant modes only] | [ ] | [ ] | [Example: contextual by game mode; hidden in modes where score is irrelevant] |
| [XP / level progress] | [ ] | [ ] | [X — available via character screen] | [ ] | [Example: on-demand because progression does not affect in-moment gameplay decisions] |
| [Waypoint / objective marker] | [ ] | [X — show when player is navigating to objective] | [ ] | [ ] | [Example: contextual — suppress during cutscenes, cinematic moments, and free exploration] |
| [Information type — e.g., Health, resource, minimap, quest objective, subtitles, status effects, timer, XP] | [ ] | [ ] | [ ] | [ ] | [Why this presentation category] |
---
## 3. Layout Zones
> **Why this section exists**: The game world is the primary content — the HUD is a
> frame around it. Before placing any element, divide the screen into named zones
> with explicit positions and safe zone margins. This section prevents two failure
> modes: (1) elements placed ad-hoc until the screen is cluttered, and (2) elements
> that overlap platform-required safe zones and get rejected in certification.
> Every element in Section 4 must be assigned to a zone defined here.
### 3.1 Zone Diagram
```
@@ -139,84 +86,42 @@ so it can be cited in design reviews.]
| Zone Name | Screen Position | Safe Zone Compliant | Primary Elements | Max Simultaneous Elements | Notes |
|-----------|----------------|---------------------|-----------------|--------------------------|-------|
| [Top Left] | [Top-left corner, within safe margin] | [Yes — 10% from top, 10% from left] | [Health bar, stamina bar, shield bar] | [3] | [Vital status — player's own resources. Priority zone for player state.] |
| [Top Center] | [Top edge, centered horizontally] | [Yes — 10% from top] | [Quest objective, area name (on enter)] | [1 — only one message at a time] | [Use for narrative context, not mechanical information. Keep text minimal.] |
| [Top Right] | [Top-right corner, within safe margin] | [Yes — 10% from top, 10% from right] | [Ammo count, ability cooldowns] | [2] | [Weapon/ability state. Most relevant during active combat.] |
| [Center] | [Screen center ±15%] | [N/A — not a margin zone] | [Crosshair, interaction prompt, hit marker] | [1 active at a time] | [CRITICAL: Nothing persistent here. Only momentary indicators.] |
| [Bottom Left] | [Bottom-left corner, within safe margin] | [Yes — 10% from bottom, 10% from left] | [Minimap, ability icons] | [2] | [Navigation and ability readout. Small, non-intrusive.] |
| [Bottom Center] | [Bottom edge, centered horizontally] | [Yes — 10% from bottom] | [Subtitles, tutorial prompts] | [2 — subtitle + tutorial may coexist] | [Highest-priority accessibility zone. Never place other elements here.] |
| [Bottom Right] | [Bottom-right corner, within safe margin] | [Yes — 10% from bottom, 10% from right] | [Notification toasts, pick-up feedback] | [3 stacked] | [Transient notifications. Stack vertically. Oldest disappears first.] |
| [Zone] | [Position] | [Yes/No + margins] | [Elements assigned] | [N] | [Zone purpose] |
**Safe zone margins by platform**:
| Platform | Top | Bottom | Left | Right | Notes |
|----------|-----|--------|------|-------|-------|
| [PC — windowed] | [0% — no safe zone required] | [0%] | [0%] | [0%] | [But respect minimum resolution — elements must not crowd at 1280x720] |
| [PC — fullscreen] | [3%] | [3%] | [3%] | [3%] | [Slight margin for 4K TV-connected PCs] |
| [Console — TV] | [10%] | [10%] | [10%] | [10%] | [Action-safe zone for broadcast-spec TVs. Some TVs overscan beyond this.] |
| [Steam Deck] | [5%] | [5%] | [5%] | [5%] | [Small screen; safe zone is smaller but crowding risk is higher] |
| [Mobile — portrait] | [15% top] | [10% bottom] | [5%] | [5%] | [15% top avoids notch/camera cutout on most devices] |
| [Mobile — landscape] | [5%] | [5%] | [15% left] | [15% right] | [Thumb placement on landscape — side zones are obscured by hands] |
| [Platform] | [%] | [%] | [%] | [%] | [Platform-specific notes] |
---
## 4. HUD Element Specifications
> **Why this section exists**: Each HUD element needs its own specification to be
> built correctly. Ad-hoc implementation of HUD elements produces inconsistent
> sizing, mismatched update frequencies, missing urgency states, and accessibility
> failures. This section is the implementation brief for every element — fill it
> completely before any element moves into development.
### 4.1 Element Overview Table
> One row per HUD element. This is the master inventory for implementation planning.
| Element Name | Zone | Always Visible | Visibility Trigger | Data Source | Update Frequency | Max Size (% screen W) | Min Readable Size | Overlap Priority | Accessibility Alt |
|-------------|------|---------------|-------------------|-------------|-----------------|----------------------|------------------|-----------------|------------------|
| [Health Bar] | [Top Left] | [Yes] | [N/A] | [PlayerStats] | [On value change] | [20%] | [120px wide] | [1 — highest] | [Numerical text label showing current/max: "80/100"] |
| [Stamina Bar] | [Top Left] | [No — context] | [Show when consuming stamina; hide 3s after full] | [PlayerStats] | [Realtime during use] | [15%] | [80px wide] | [2] | [Numerical label, or hide if full (accessible assumption)] |
| [Shield Indicator] | [Top Left] | [No — context] | [Show when shield is active or recently hit] | [PlayerStats] | [On value change] | [20%] | [120px wide] | [3] | [Numerical label. Must not use color alone — add shield icon.] |
| [Ammo Counter] | [Top Right] | [No — context] | [Show when weapon is equipped; hide when unarmed] | [WeaponSystem] | [On fire / on reload] | [10%] | ["88/888" readable at game's min resolution] | [4] | [Text-only fallback: "32 / 120"] |
| [Minimap] | [Bottom Left] | [Yes] | [N/A — but suppressed in cinematic mode] | [NavigationSystem] | [Realtime] | [18%] | [150x150px] | [5] | [Cardinal direction compass strip as fallback; must be toggleable] |
| [Quest Objective] | [Top Center] | [No — context] | [Show on objective change; show when near objective location; hide after 5s] | [QuestSystem] | [On event] | [30%] | [Legible at body text size] | [6] | [Read aloud on objective change via screen reader] |
| [Crosshair] | [Center] | [No — context] | [Show when ranged weapon equipped; hide in melee or unarmed] | [WeaponSystem / AimSystem] | [Realtime] | [3%] | [12px diameter minimum] | [1 — center zone priority] | [Reduce motion: static crosshair only. Option to enlarge.] |
| [Interaction Prompt] | [Center] | [No — context] | [Show when player is within interaction range of an interactive object] | [InteractionSystem] | [On enter/exit interaction range] | [15%] | [24px icon + readable text] | [2 — center zone] | [Text description of interaction always present, not icon-only] |
| [Subtitles] | [Bottom Center] | [No — always on when dialogue plays, if setting enabled] | [Show during any voiced line or ambient dialogue] | [DialogueSystem] | [Per dialogue line] | [60%] | [Minimum 24px font] | [1 — highest in zone] | [This IS the accessibility feature — see Section 8 for subtitle spec] |
| [Damage Numbers] | [World-space / anchored to entity] | [No — context] | [Show on any damage event; duration 800ms] | [CombatSystem] | [On event] | [5% per number] | [18px minimum] | [3] | [Option to disable; numbers can overwhelm for photosensitive players] |
| [Status Effect Icons] | [Top Left — below health bar] | [No — context] | [Show when any status effect is active on player] | [StatusSystem] | [On effect add/remove] | [3% per icon] | [24px per icon] | [3] | [Icon + text label on hover/focus. Never icon-only.] |
| [Notification Toast] | [Bottom Right] | [No — event-driven] | [On loot, XP gain, achievement, quest update] | [Multiple — see Section 6] | [On event] | [25%] | [Legible at body text size] | [7 — lowest] | [Queued; never overlapping. Read by screen reader if subtitle mode on.] |
| [Element] | [Zone] | [Yes/No] | [Trigger or N/A] | [Owning system] | [When it updates] | [%] | [px] | [N] | [Non-visual/non-color alternative] |
### 4.2 Element Detail Blocks
> For each element in the table above, write a detail block. Copy and complete
> one block per element.
> one block per element. See guide Section 4 for completed Health Bar and
> Minimap examples.
---
**Health Bar**
**[Element Name]**
- Visual description: [Horizontal fill bar. Left-to-right fill direction. Segmented at 25/50/75% to aid reading at a glance. Background: dark semi-transparent (40% opacity). Fill color: context-dependent — see Urgency States.]
- Data displayed: [Current HP as fill percentage. Numerical value displayed as text below bar at all times: "80 / 100".]
- Update behavior: [Bar fill decreases or increases smoothly using a lerp over 150ms per change. Large damage (>25% single hit) triggers a brief flash (1 frame white, then drain).]
- Urgency states:
- Normal (>50% HP): [Green fill, no special behavior]
- Caution (25–50% HP): [Yellow fill, low warning pulse every 4 seconds]
- Critical (<25% HP): [Red fill, persistent slow pulse (1 Hz), vignette appears at screen edges]
- Zero (0% HP): [Bar empties and turns grey; death state begins]
- Interaction: [Display only. Not interactive. Player cannot click, hover, or focus this element as an action target.]
- Player customization: [Opacity adjustable (see Section 7 Tuning Knobs). Can be repositioned to any corner by player in accessibility settings.]
---
**Minimap**
- Visual description: [Circular mask, radius = 75px at reference resolution 1920x1080. Player icon at center. North always up unless player has unlocked "Rotate minimap" setting. Range = configurable, default 80 world units radius.]
- Data displayed: [Player position, nearby enemies (if detection perk unlocked), quest markers within range, points of interest icons, traversal obstacles (walls, drops).]
- Update behavior: [Realtime. Updates every frame. Enemy icons fade in/out as they enter/leave detection range over 300ms.]
- Urgency states: [None for the map itself. Enemy icons turn red when they are in combat-alert state.]
- Interaction: [Not interactive in-game. Press dedicated Map button to open the full map screen (separate UX spec).]
- Player customization: [Size: S/M/L (70/90/110px radius). Opacity: 30–100%. Rotation: locked-north or player-relative. Can be disabled entirely (compass strip shows as fallback).]
- Visual description: [Shape, fill direction, background, color behavior]
- Data displayed: [Values shown, including any numerical text labels]
- Update behavior: [Animation/lerp timing, flash behavior on large changes]
- Urgency states: [Per-threshold visual states, e.g., Normal / Caution / Critical / Zero]
- Interaction: [Interactive or display-only]
- Player customization: [Opacity, repositioning, size options]
---
@@ -226,58 +131,32 @@ so it can be cited in design reviews.]
## 5. HUD States by Gameplay Context
> **Why this section exists**: The HUD is not a static overlay — it is a dynamic
> system that must adapt to what the player is doing. A HUD designed only for
> standard gameplay will look wrong in cutscenes, feel cluttered in exploration,
> and occlude critical information in boss fights. This section defines the
> transformations the HUD undergoes in each gameplay context. It is also the spec
> for the system that manages HUD visibility — the HUD state machine.
> Define the HUD transformation for every gameplay context — at minimum:
> exploration, combat, dialogue/cutscene, and paused/menu. See guide Section 5
> for a worked example covering nine contexts.
| Context | Elements Shown | Elements Hidden | Elements Modified | Transition Into This State |
|---------|---------------|-----------------|------------------|---------------------------|
| [Exploration — no threats] | [Minimap, Quest Objective (faded, 60%), Subtitles (if active)] | [Ammo Counter, Crosshair, Damage Numbers, Status Effects (if none active)] | [Health Bar fades to 40% opacity — visible but not dominant] | [Fade transition, 500ms, when no enemies detected for 10s] |
| [Combat — active threat] | [Health Bar (full opacity), Stamina Bar (when used), Ammo Counter, Crosshair, Damage Numbers, Status Effects, Enemy Health Bars] | [Quest Objective (temporarily hidden), Notification Toasts (paused queue)] | [Minimap scales down 15% and raises opacity to 100%] | [Immediate snap in on first enemy detection — no fade. Combat readiness requires instant info.] |
| [Dialogue / Cutscene] | [Subtitles, Dialogue speaker name] | [All gameplay HUD elements: health, ammo, minimap, crosshair, damage numbers] | [N/A] | [All gameplay elements fade out over 300ms when cutscene flag is set] |
| [Cinematic (scripted camera sequence)] | [Subtitles only] | [Everything else including speaker name] | [Letterbox bars appear (if applicable to this game's style)] | [Immediate on cinematic flag; letterbox slides in from top/bottom over 400ms] |
| [Inventory / Menu open] | [None — inventory renders full-screen or as overlay] | [All HUD elements] | [Game world visible but paused behind inventory screen] | [All HUD elements hide over 150ms as menu opens] |
| [Death / Respawn pending] | [Death screen overlay — separate spec] | [All gameplay HUD elements] | [Screen desaturates and darkens over 800ms] | [Death state begins when HP reaches 0 — HUD elements fade over 600ms] |
| [Loading / Transition] | [Loading indicator, tip text] | [All gameplay HUD elements] | [N/A] | [Instant on level transition trigger] |
| [Tutorial — new mechanic] | [Standard context HUD + Tutorial Prompt overlay] | [Nothing additional hidden] | [Tutorial prompt dims background subtly to draw attention to prompt] | [Tutorial system fires ShowTutorial event; prompt fades in over 200ms] |
| [Boss Encounter] | [Boss health bar appears (large, bottom of screen or top center), all combat elements] | [Quest Objective] | [Boss bar renders in a distinct visual style — must not be confused with player health] | [Boss health bar slides in on boss encounter trigger over 400ms] |
| [Context — e.g., Exploration / Combat / Dialogue / Cinematic / Menu open / Death / Loading / Tutorial / Boss] | [Shown] | [Hidden] | [Modified] | [Transition timing + trigger] |
---
## 6. Information Hierarchy
> **Why this section exists**: Not all HUD information is equally important. When
> screen space is limited, when the player is under high stress, or when elements
> compete for the same zone, there must be a principled priority order that governs
> which elements survive and which get suppressed. This section formalizes that
> hierarchy so it can be enforced systematically and not just "feels obvious" decisions
> made at implementation time.
> Assign every element a priority tier (MUST KEEP / SHOULD KEEP / CAN HIDE /
> ALWAYS HIDE) with reasoning. See guide Section 6 for a worked example.
| Element | Priority Tier | Reasoning | What Replaces It If Hidden |
|---------|--------------|-----------|---------------------------|
| [Subtitles] | [MUST KEEP — never hide during dialogue] | [Accessibility requirement. Legal requirement in some markets. Story clarity.] | [N/A — nothing replaces subtitles] |
| [Health Bar] | [MUST KEEP — during any state where the player can be damaged] | [Without health visibility, survival decisions become impossible] | [Auditory cues (heartbeat, breathing) supplement but do not replace] |
| [Crosshair] | [MUST KEEP — while aiming with a ranged weapon] | [Targeting without a crosshair is a precision failure, not a difficulty feature] | [Alternative: dot-only mode for minimalists; never fully hidden while aiming] |
| [Interaction Prompt] | [MUST KEEP — when player is in interaction range] | [Without it, interactive objects are invisible to the player] | [Environmental visual cues can supplement but interaction affordance must be explicit] |
| [Ammo Counter] | [SHOULD KEEP] | [Low ammo decisions (switch weapon, reload) require awareness; can be contextual] | [Auditory "click" on empty chamber is acceptable fallback for experienced players] |
| [Minimap] | [SHOULD KEEP] | [Navigation requires spatial awareness; loss forces repeated map opens] | [Compass strip (simplified directional indicator) is acceptable fallback] |
| [Status Effects] | [SHOULD KEEP — while active] | [Active debuffs change what actions are viable; invisible debuffs feel unfair] | [Character animation states can partially communicate status effects (limping, sparks)] |
| [Quest Objective] | [CAN HIDE] | [Player can hold objective in memory for extended periods; contextual is correct default] | [Player remembers objective from context] |
| [Damage Numbers] | [CAN HIDE] | [Feedback element, not decision-critical. Many players turn these off.] | [Hit sounds and enemy reactions communicate hit registration] |
| [Notification Toasts] | [CAN HIDE in high-intensity moments] | [Mid-combat "You gained 50 XP" is noise, not signal. Queue and show after combat.] | [Queue held and released when combat ends] |
| [Combo Counter] | [ALWAYS HIDE when combo resets or player is not attacking] | [Stale combo information is actively misleading] | [N/A — simply hidden] |
| [Element] | [MUST KEEP / SHOULD KEEP / CAN HIDE / ALWAYS HIDE] | [Why] | [Fallback channel or N/A] |
---
## 7. Visual Budget
> **Why this section exists**: Without explicit budget constraints, HUD elements
> accumulate until the game world is nearly invisible. These numbers are hard limits,
> not guidelines. Every element addition that would breach a limit requires explicit
> approval and must displace or reduce an existing element.
> These numbers are hard limits, not guidelines. Every element addition that
> would breach a limit requires explicit approval and must displace or reduce an
> existing element. See guide Section 7 for how to apply the budgets.
| Budget Constraint | Limit | Measurement Method | Current Estimate | Status |
|------------------|-------|--------------------|-----------------|--------|
@@ -289,60 +168,37 @@ so it can be cited in design reviews.]
| Maximum opacity for HUD background panels | [65%] | [Opacity of any panel behind HUD text — must preserve world visibility through panel] | [TBD] | [To verify] |
| Minimum HUD element size at minimum supported resolution | [40px for icons, 18px for text] | [Measure at lowest target resolution] | [TBD] | [To verify] |
> **How to apply these budgets**: For every new HUD element proposed during
> production, require the proposer to state (1) which budget line it affects,
> (2) what the new total will be, and (3) what existing element will be reduced or
> made contextual to stay within budget. "It's a small icon" is not an analysis.
---
## 8. Feedback & Notification Systems
> **Why this section exists**: Notifications are the most frequently-added and
> worst-controlled part of most HUDs. Every system wants to tell the player
> something. Without explicit rules about notification priority, stacking limits,
> and queue behavior, the notification zone becomes a firehose of overlapping
> toasts that players learn to ignore entirely. This section establishes the
> notification contract for all systems.
> One row per notification type. Every notification must have queue/priority
> behavior defined. See guide Section 8 for a worked example table and queue rules.
| Notification Type | Trigger System | Screen Position | Duration (ms) | Animation In / Out | Max Simultaneous | Priority | Queue Behavior | Dismissible? |
|------------------|---------------|-----------------|--------------|-------------------|-----------------|----------|---------------|-------------|
| [Item Pickup] | [InventorySystem] | [Bottom Right — toast] | [2000] | [Slide in from right 200ms / fade out 300ms] | [3 stacked] | [Low] | [FIFO queue; older toasts pushed up as new ones enter] | [No — auto-dismiss] |
| [XP Gain] | [ProgressionSystem] | [Bottom Right — toast, below item toasts] | [1500] | [Fade in 150ms / fade out 300ms] | [1 — XP messages merge: "XP +150"] | [Very Low — suppress during combat, queue for post-combat] | [Combat-aware queue] | [No] |
| [Level Up] | [ProgressionSystem] | [Center screen — persistent until dismissed] | [Persistent — requires input to dismiss] | [Scale up from 80% + fade in 400ms] | [1] | [High — interrupts normal toasts] | [Pauses all other notifications until dismissed] | [Yes — any input] |
| [Quest Update] | [QuestSystem] | [Top Center] | [4000] | [Slide down from top 250ms / fade out 400ms] | [1 — top center is single-message zone] | [Medium] | [If quest update arrives while previous is visible, extend duration by 2000ms; do not stack] | [No] |
| [Objective Complete] | [QuestSystem] | [Top Center] | [3000] | [Same as Quest Update but with additional completion sound] | [1] | [Medium-High — preempts Quest Update] | [Preempts any queued top-center message] | [No] |
| [Critical Warning (low health, hazard)] | [CombatSystem / EnvironmentSystem] | [Screen edge vignette + text at center-bottom] | [Persistent while condition active] | [Fade in 200ms; fades out 500ms when condition clears] | [1 per warning type] | [Critical — never suppressed] | [Renders immediately, bypasses all queues] | [No] |
| [Achievement Unlocked] | [AchievementSystem] | [Bottom Right — distinct from item toasts] | [4000] | [Slide in from right with icon expansion 300ms / fade out 400ms] | [1] | [Low] | [Queues behind item toasts; never more than one achievement toast at a time] | [No] |
| [Hint / Tutorial] | [TutorialSystem] | [Bottom Center] | [Persistent — until player performs the action or dismisses] | [Fade in 300ms] | [1] | [Medium] | [Only one tutorial hint at a time; queue others] | [Yes — B button / Esc] |
| [Type] | [System] | [Zone] | [ms] | [In / out animation + timing] | [N] | [Priority] | [Queue/merge/preempt behavior] | [Yes/No] |
**Notification queue rules**:
1. Combat-aware queue: notifications tagged as Low priority are queued, not displayed, when the player is in combat state. The queue is flushed in a batch when the player exits combat, with a max of 3 items displayed in sequence.
2. Merge rule: identical notification types that fire within 500ms of each other are merged into a single notification with a combined value (e.g., "Item Pickup x3" rather than three separate toasts).
3. Critical notifications (health warning, environmental hazard) are never queued, never merged, and always displayed immediately regardless of combat state or existing notifications.
1. [Combat-aware queue rule — which priorities are held during combat and how the queue flushes]
2. [Merge rule — when identical notification types merge into one]
3. [Critical bypass rule — which notifications are never queued, never merged]
---
## 9. Platform Adaptation
> **Why this section exists**: A HUD designed at 1920x1080 on a monitor may be
> illegible on a 55-inch TV at 4K, broken at 1280x720 on Steam Deck, or hidden
> behind a notch on mobile. Platform adaptation is not optional post-ship work —
> it is a design requirement that must be specified before implementation so the
> architecture can support it from the start. Every platform listed here requires
> explicit layout testing before certification.
> Every target platform requires explicit layout testing before certification.
> See guide Section 9 for a worked example.
| Platform | Safe Zone | Resolution Range | Input Method | HUD-Specific Notes |
|----------|-----------|-----------------|-------------|-------------------|
| [PC — Windows, 1920x1080 reference] | [3% margin] | [1280x720 min to 3840x2160 max] | [Mouse + keyboard, controller optional] | [HUD must scale correctly at all resolutions. Test at 1280x720 — minimum before cert. Consider ultrawide (21:9) — minimap must not stretch.] |
| [PC — Steam Deck, 1280x800] | [5% margin] | [Fixed 1280x800] | [Controller + touchscreen] | [Smaller screen means minimum text sizes are critical. Test ALL elements at this resolution. Touch targets irrelevant (controller-only by default).] |
| [PlayStation 5 / Xbox Series X] | [10% margin] | [1080p to 4K] | [Controller] | [Console certification requires TV safe zone compliance. Action-safe is 90% of screen area. Test on a real TV, not a monitor — overscan behavior differs.] |
| [Mobile — iOS / Android] | [15% top, 10% other sides] | [360x640 min to 414x896 common] | [Touch] | [Notch/camera cutout avoidance at top. Bottom home indicator zone avoidance. Portrait and landscape layouts may differ significantly — specify both.] |
| [Platform] | [Margin] | [Min–max resolution] | [Input] | [Platform-specific HUD constraints] |
**HUD repositionability requirement**: Players must be able to reposition at minimum the following elements using an in-game HUD layout editor (required for accessibility compliance on console):
- Health bar
- Minimap
- Ability bar (if present)
- [Health bar]
- [Minimap]
- [Ability bar (if present)]
Repositioning saves to player profile, not to a single slot. Applies across play sessions.
@@ -350,48 +206,30 @@ Repositioning saves to player profile, not to a single slot. Applies across play
## 10. Accessibility — HUD Specific
> **Why this section exists**: HUD accessibility failures are the most visible
> accessibility failures in games — players encounter the HUD in every session,
> in every gameplay moment. Color-blind failures, illegible text at minimum scale,
> and inability to disable distracting animations are among the top accessibility
> complaints in game reviews. This section defines HUD-specific requirements; refer
> to the project's `docs/accessibility-requirements.md` for the full project standard.
> HUD-specific requirements only — refer to the project's
> `design/accessibility-requirements.md` for the full project standard.
### 10.1 Colorblind Modes
| Element | Color-Only Information Risk | Colorblind Mode Fix |
|---------|----------------------------|---------------------|
| [Health bar fill] | [Red = low health uses red/green distinction] | [Add icon pulse + vignette as non-color indicators. Red fill is supplemental, not sole indicator.] |
| [Damage numbers] | [Red = taken, green = healed] | [Add minus (-) prefix for damage, plus (+) for healing. Symbols, not color.] |
| [Enemy health bars] | [If colored by faction or threat level] | [Add text label or icon badge for faction/threat level. Never color-only.] |
| [Status effect icons] | [If icon tint communicates status type] | [All status icons must have distinct shapes, not just distinct colors. Shape encodes meaning; color is secondary.] |
| [Minimap icons] | [If player vs. enemy vs. objective distinguished by color] | [Distinct icon shapes: circle = player, triangle = enemy, star = objective. Color supplements shape.] |
| [Element] | [Where color alone carries meaning] | [Non-color alternative: shape, icon, symbol, text] |
### 10.2 Text Scaling
[Describe what happens when the player sets the UI text scale to 150% (the maximum required for your Accessibility Tier). Which elements reflow? Which elements clip? Which elements are architecturally blocked from scaling (e.g., fixed-size canvases)?
Example: "Health bar numerical label grows with text scale — bar expands slightly to accommodate. Quest objective text wraps at 150% scale — verify Top Center zone can accommodate two-line objectives. Damage numbers do not scale (they are world-space, not screen-space) — this is an accepted limitation documented here."]
[Describe what happens at 150% UI text scale: which elements reflow, clip, or are architecturally blocked from scaling — see guide Section 10 for an example narrative]
**Text scaling test matrix**:
| Element | 100% (baseline) | 125% | 150% | Overflow behavior |
|---------|----------------|------|------|-------------------|
| [Health bar label] | [Pass] | [Pass] | [TBD] | [Bar expands; does not overlap stamina bar] |
| [Quest objective text] | [Pass] | [TBD] | [TBD] | [Wraps to second line; zone height expands] |
| [Notification toast text] | [Pass] | [TBD] | [TBD] | [Toast width expands to max 35% screen width, then wraps] |
| [Subtitle text] | [Pass] | [TBD] | [TBD] | [Dedicated subtitle zone — must accommodate scale] |
| [Element] | [Pass/Fail/TBD] | [Pass/Fail/TBD] | [Pass/Fail/TBD] | [What happens on overflow] |
### 10.3 Motion Sensitivity
| Animation / Motion Element | Severity | Disabled by Reduced Motion Setting? | Replacement Behavior |
|---------------------------|----------|-------------------------------------|---------------------|
| [Health bar low-HP pulse] | [Mild] | [Yes] | [Solid fill, no pulse. Vignette remains as it is less likely to trigger sensitivity.] |
| [Screen edge vignette] | [Moderate] | [Optional — separate toggle] | [Replace with static darkened corners at 30% opacity] |
| [Damage numbers float upward] | [Mild] | [Yes] | [Instant appear/disappear in place, no float] |
| [Notification toast slide-in] | [Mild] | [Yes] | [Instant appear at final position] |
| [Level up center animation] | [High] | [Yes — required] | [Static level up card, no scale animation, no particle effects] |
| [Combo counter scale pulse] | [Mild] | [Yes] | [Number increments without scale animation] |
| [Animated element] | [Mild/Moderate/High] | [Yes/No/Optional] | [Static replacement] |
### 10.4 Subtitles Specification
@@ -400,15 +238,15 @@ Example: "Health bar numerical label grows with text scale — bar expands sligh
> implementation discretion.
- **Default setting**: [ON or OFF — document your game's default and the rationale. Industry standard is ON by default.]
- **Position**: Bottom Center zone, centered horizontally, above the bottom safe zone margin
- **Max characters per line**: [42 characters — the readable limit for subtitle lines at minimum text size on TV viewing distance]
- **Max simultaneous lines**: [2 lines before scrolling — do not display more than 2 lines at once]
- **Speaker identification**: [Speaker name displayed in color or above subtitle text — never rely on color alone; add colon prefix: "ARIA: The door is locked."]
- **Background**: [Semi-transparent black panel, 70% opacity, behind all subtitle text — ensures contrast against any game world background]
- **Font size minimum**: [24px at 1080p reference — scales with text scale setting]
- **Line break behavior**: [Break at natural language pause points — before conjunctions, after commas, never mid-word]
- **Subtitle persistence**: [Each subtitle line holds for the duration of the spoken line plus 300ms after it ends — never disappear while audio is still playing]
- **Non-dialogue captions**: [Document whether ambient sounds, music descriptions, and sound effects are captioned — e.g., "[tense music]", "[explosion in the distance]" — and where these appear if different from dialogue subtitles]
- **Position**: [Zone, alignment, relationship to safe zone margin]
- **Max characters per line**: [e.g., 42 characters — the readable limit at minimum text size on TV viewing distance]
- **Max simultaneous lines**: [e.g., 2 lines before scrolling]
- **Speaker identification**: [Name display method — never rely on color alone]
- **Background**: [Panel treatment ensuring contrast against any game world background]
- **Font size minimum**: [px at reference resolution — scales with text scale setting]
- **Line break behavior**: [Break at natural language pause points — never mid-word]
- **Subtitle persistence**: [Hold duration relative to spoken line — never disappear while audio is still playing]
- **Non-dialogue captions**: [Whether ambient sounds, music, and SFX are captioned, and where these appear]
### 10.5 HUD Opacity and Visibility Controls
@@ -428,31 +266,20 @@ The following player-adjustable settings must be available from the Accessibilit
## 11. Tuning Knobs
> **Why this section exists**: HUD behavior should be data-driven to the same degree
> as gameplay systems. Values that are hardcoded are values that require an engineer
> to change. Values that are in config can be tuned by a designer or adjusted for
> player preferences. Document all tunable parameters before implementation so the
> programmer knows which values to externalize.
> Document all tunable parameters before implementation so the programmer knows
> which values to externalize. See guide Section 11 for a worked example.
| Parameter | Current Value | Range | Effect of Increase | Effect of Decrease | Player Adjustable? | Notes |
|-----------|-------------|-------|-------------------|-------------------|-------------------|-------|
| [Notification display duration (default)] | [2000ms] | [500ms – 5000ms] | [Toasts persist longer — less likely to be missed, more screen clutter] | [Toasts disappear faster — cleaner, higher miss risk] | [No — but player can adjust verbosity level] | [Per-type overrides in Section 8 take precedence] |
| [Notification queue max size] | [8] | [3 – 15] | [More messages preserved but queue takes longer to clear] | [Older messages dropped earlier] | [No] | [Expand if playtesting reveals important messages being lost] |
| [Health bar low-HP pulse frequency] | [1 Hz] | [0.5 – 2 Hz] | [More urgent feeling — can become fatiguing] | [Calmer — may fail to communicate urgency] | [No — but Reduced Motion disables it] | [Linked to accessibility setting] |
| [Combat HUD reveal duration] | [0ms (instant)] | [0 – 300ms] | [Softer reveal — feels less jarring] | [Instant — highest responsiveness] | [No] | [Keep at 0ms — combat information must be instant] |
| [Exploration HUD fade-out delay] | [10000ms (10s after last threat)] | [3000 – 30000ms] | [HUD fades sooner — cleaner exploration] | [HUD stays longer — more reassurance] | [No] | [Tune based on playtest; 10s is a starting estimate] |
| [Minimap range (world units visible)] | [80] | [40 – 200] | [More map context visible] | [Tighter local view] | [Yes — Small/Medium/Large preset] | [Exposed as S/M/L, not raw unit value] |
| [Minimap size (px radius at 1080p)] | [75] | [50 – 120] | [Larger map, more screen space consumed] | [Smaller, less intrusive] | [Yes — S/M/L preset] | [Three sizes exposed to player] |
| [Damage number duration (ms)] | [800] | [400 – 1500] | [Numbers linger longer — easier to read, more cluttered] | [Numbers clear faster — cleaner, harder to parse] | [No] | [Tune based on visual noise in dense combat] |
| [Global HUD opacity] | [100%] | [0 – 100%] | [Fully visible] | [Fully hidden] | [Yes — opacity slider in Accessibility settings] | [0% = full HUD off; some players prefer this] |
| [Parameter] | [Value] | [Min–max] | [Effect] | [Effect] | [Yes/No + how exposed] | [Tuning notes] |
---
## 12. Acceptance Criteria
> **Why this section exists**: These criteria are the certification checklist for the
> HUD. Every item must pass before the HUD can be marked Approved. QA must be able
> to verify each item independently.
> These criteria are the certification checklist for the HUD. Every item must
> pass before the HUD can be marked Approved. QA must be able to verify each
> item independently.
**Layout & Visibility**
- [ ] All HUD elements are within platform safe zone margins on all target platforms
@@ -495,11 +322,9 @@ The following player-adjustable settings must be available from the Accessibilit
## 13. Open Questions
> Track unresolved design questions here. All questions must be resolved before
> the HUD design document can be marked Approved.
> the HUD design document can be marked Approved. See guide Section 13 for
> example questions.
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [e.g., Should the minimap show enemy positions by default, or only after a detection skill is unlocked?] | [systems-designer + ui-designer] | [Sprint 5, Day 2] | [Pending — depends on progression GDD decision] |
| [e.g., Does the game have a boss health bar, or do bosses use the standard enemy health bar? Bosses need a visually distinct treatment if they are significantly more important than normal enemies.] | [game-designer] | [Sprint 5, Day 1] | [Pending] |
| [e.g., Damage numbers: diegetic (floating in world space, occluded by geometry) or screen space (always readable, overlaid on HUD layer)?] | [ui-designer + lead-programmer] | [Sprint 4, Day 5] | [Pending — architecture decision affects rendering layer choice] |
| [e.g., Mobile portrait vs. landscape: does the game support both orientations? If yes, each requires its own zone layout.] | [producer] | [Sprint 3, Day 3] | [Pending — platform scope decision required first] |
| [Add question] | [Owner] | [Deadline] | [Resolution] |
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -70,7 +70,7 @@
### Prototypes
- **Active Prototypes**: [N] in `prototypes/`
- ✅ [Prototype 1] — documented with README
- ✅ [Prototype 1] — documented with REPORT.md
- ⚠️ [Prototype 2] — no README, unclear status
- **Archived**: [N] (experiments completed)
- **Key Gaps**:
+74
View File
@@ -0,0 +1,74 @@
# Active Session State — [project or branch]
<!--
THE CONTRACT. Read this before editing the file or any hook that consumes it.
This file has TWO regions and they are not interchangeable:
1. The CHECKPOINT region below (STATUS + CHECKPOINT blocks) is the part
machines read. Hooks inject it verbatim into the context, so it is
BOUNDED BY CONSTRUCTION: keep it under ~25 lines. It is OVERWRITTEN on
every update, never appended to.
2. Everything after `<!-- /CHECKPOINT -->` is free-form narrative for humans
and for a returning agent that wants detail. No hook ever injects it, so
it may grow — but see Rotation below.
Why the split exists: before it, `active.md` was one append-only file doing
both jobs. It reached 712 lines / 44 KB, and each consumer invented its own
slice of it — the status line parsed for a STATUS block nothing wrote,
pre-compact injected `head -100` (12.7 KB), and session-start previewed
`tail -20`, the opposite end. They disagreed because there was no contract to
agree on. Now every consumer reads the named region.
ROTATION. When the narrative below grows past ~200 lines, move it to
`production/session-logs/` and start it fresh:
bash .claude/scripts/rotate-session-state.sh
Nothing is lost — and the commit history already records most of what the
narrative repeats.
-->
<!-- STATUS -->
Epic:
Feature:
Task:
<!-- /STATUS -->
<!-- CHECKPOINT -->
**Updated:** [YYYY-MM-DD]
**Branch:** `[branch]`
**Current task:** [one line — what is actively being worked on]
**Next step:** [one line — the very next action, concrete enough to resume cold]
**Blocked on:** [one line, or `nothing`]
**Files in progress:** [paths, comma-separated, or `none`]
**Open questions:** [one line each, or `none`]
<!-- /CHECKPOINT -->
---
## Notes
[Free-form. Decisions and their rationale, what was tried and rejected, context
that would be expensive to reconstruct. Not machine-read — write for the person
or agent picking this up cold.]
<!--
FIELD NOTES
STATUS block
Drives the status-line breadcrumb (`Combat System > Melee > Hitboxes`), and
only at Production / Polish / Release stage. All three fields are optional —
leave a field blank when it does not apply, and blank all three when there is
no active focus. Do not delete the markers themselves — `statusline.sh`
expects them to exist.
CHECKPOINT block
The recovery payload. `session-start.sh` shows it when a previous session
left state; `pre-compact.sh` injects it before compaction. Both read THIS
region and nothing else, which is what keeps the cost fixed no matter how
long the narrative gets.
Write it so a cold reader can resume without reading anything else. "Current
task: fixing the thing" is useless; "Current task: wiring modes.rigor into
/gate-check section 6.4" is not.
-->
-96
View File
@@ -1,96 +0,0 @@
# Skill Test Spec: /[skill-name]
## Skill Summary
[One paragraph: what this skill does, when to use it, what it produces. Include
the primary output artifact, the verdict format it uses, and which pipeline stage
it belongs to.]
---
## Static Assertions (Structural)
Verified automatically by `/skill-test static` — no fixture needed.
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
- [ ] Has ≥2 phase headings (## Phase N or numbered ## sections)
- [ ] Contains verdict keywords: [list the ones expected, e.g., PASS, FAIL, CONCERNS]
- [ ] Contains "May I write" collaborative protocol language (if skill writes files)
- [ ] Has a next-step handoff at the end
---
## Test Cases
### Case 1: Happy Path — [short description]
**Fixture:** [Describe the assumed project state. Which files exist? What do they
contain? E.g., "game-concept.md exists with all 8 required sections complete.
systems-index.md exists. All MVP GDDs are present and individually reviewed."]
**Input:** `/[skill-name] [args]`
**Expected behavior:**
1. [Phase 1 action — what the skill should read or check]
2. [Phase 2 action — what the skill should evaluate]
3. [Phase N action — what the skill should output]
**Assertions:**
- [ ] Skill reads [specific file] before producing output
- [ ] Output includes verdict keyword [PASS/FAIL/etc.]
- [ ] Output lists [specific content] from the fixture
- [ ] Skill asks for approval before writing any file
---
### Case 2: Failure Path — [short description, e.g., "Missing required artifact"]
**Fixture:** [Describe the failure state. E.g., "game-concept.md is missing.
No files exist in design/gdd/."]
**Input:** `/[skill-name] [args]`
**Expected behavior:**
1. [Phase 1: skill detects missing file]
2. [Phase 2: skill surfaces the gap rather than assuming OK]
3. [Output: FAIL or BLOCKED verdict with specific blocker named]
**Assertions:**
- [ ] Skill does NOT output PASS when the fixture is incomplete
- [ ] Skill names the specific missing artifact
- [ ] Skill suggests a remediation action (e.g., "Run /[other-skill]")
- [ ] Skill does not create files to fill in the gap without asking
---
### Case 3: Edge Case — [short description, e.g., "No argument provided"]
**Fixture:** [State of project files for this case]
**Input:** `/[skill-name]` (no argument)
**Expected behavior:**
1. [What the skill should do when invoked without arguments]
**Assertions:**
- [ ] [assertion]
---
## Protocol Compliance
- [ ] Uses "May I write" before all file writes
- [ ] Presents findings or report before asking for write approval
- [ ] Ends with a recommended next step or follow-up skill
- [ ] Never auto-creates files without explicit user approval
- [ ] Does not skip phases or jump straight to a verdict without checking
---
## Coverage Notes
[Document what is intentionally NOT tested in this spec and why. Examples:
- "Case 3 (all-mode) is not covered because it runs too many checks to evaluate
in a single spec — test each sub-mode individually."
- "The database integration path is not covered as it requires a live environment."
- "Edge cases involving corrupted YAML files are deferred to a future spec."]
+4
View File
@@ -32,6 +32,10 @@ the acceptance criteria numbers from the story that this evidence covers.]
List all captured evidence below. Store files in the same directory as this
document or in `production/qa/evidence/[story-slug]/`.
**The file must actually be on disk.** Visual/Feel and UI gates are BLOCKING by
default, and `/story-done` and `/test-evidence-review` glob for the image — a
filename listed here with no file beside it does not satisfy the gate.
| # | Filename | What It Shows | Acceptance Criterion |
|---|----------|--------------|----------------------|
| 1 | `[filename.png]` | [brief description of what is visible] | AC-1 |
+63 -253
View File
@@ -1,5 +1,7 @@
# UX Specification: [Screen / Flow Name]
> Authoring guidance: .claude/docs/templates/guidance/ux-spec-guide.md (load per-section as you author — do not read entirely).
> **Status**: Draft | In Review | Approved | Implemented
> **Author**: [Name or agent — e.g., ui-designer]
> **Last Updated**: [Date]
@@ -20,76 +22,39 @@
## 1. Purpose & Player Need
> **Why this section exists**: Every screen must justify its existence from the
> player's perspective. Screens that are designed from a developer perspective ("display
> the save data") produce cluttered, confusing interfaces. Screens designed from the
> player's perspective ("let the player feel confident their progress is safe before they
> put the controller down") produce purposeful, calm interfaces. Write this section before
> touching any layout decisions — it is the filter through which every subsequent choice
> is evaluated.
**What player need does this screen serve?**
[One paragraph. Name the real human need, not the system function. Consider: what would
a player say they want when they open this screen? What would frustrate them if it did
not work? That frustration describes the need.
Example — bad: "Displays the player's current items and equipment."
Example — good: "Lets the player understand what they're carrying and quickly decide what
to take into the next encounter, without breaking their mental model of the game world.
The inventory is the player's planning tool between moments of action."]
[One paragraph — the real human need from the player's perspective, not the system function. See guide Section 1 for good/bad examples.]
**The player goal** (what the player wants to accomplish):
[One sentence. Specific enough that you could write an acceptance criterion for it.
Example: "Find the item they are looking for within three button presses and equip it
without navigating to a separate screen."]
[One sentence, specific enough to write an acceptance criterion for.]
**The game goal** (what the game needs to communicate or capture):
[One sentence. This is what the system needs from this interaction. Example: "Record the
player's equipment choices and relay them to the combat system before the next encounter
loads." This section prevents UI that looks good but fails to serve the system it is
part of.]
[One sentence — what the system needs from this interaction.]
---
## 2. Player Context on Arrival
> **Why this section exists**: Screens do not exist in isolation. A player opening the
> inventory mid-combat is in a completely different cognitive and emotional state than
> a player opening it after clearing a dungeon. The same information architecture can
> feel oppressively complex in one context and trivially simple in another. Document the
> context so that design decisions — what to show first, what to hide, what to animate,
> what to simplify — are calibrated to the actual player arriving at this screen, not
> an abstract user.
| Question | Answer |
|----------|--------|
| What was the player just doing? | [e.g., Completed a combat encounter / Pressed Esc from exploration / Triggered a story cutscene] |
| What is their emotional state? | [e.g., High tension — just narrowly survived / Calm — exploring between objectives] |
| What cognitive load are they carrying? | [e.g., High — actively tracking enemy positions / Low — no active threats] |
| What information do they already have? | [e.g., They know they just picked up an item but haven't seen its stats yet] |
| What are they most likely trying to do? | [e.g., Check if the new item is better than their current weapon — primary use case] |
| What are they likely afraid of? | [e.g., Missing something, making an irreversible mistake, losing track of where they were] |
| What was the player just doing? | [Prior activity / triggering state] |
| What is their emotional state? | [Tension / calm / urgency] |
| What cognitive load are they carrying? | [High / low + what they are tracking] |
| What information do they already have? | [Known context on arrival] |
| What are they most likely trying to do? | [Primary use case] |
| What are they likely afraid of? | [Risks and anxieties to design against] |
**Emotional design target for this screen**:
[One sentence describing the feeling the player should have while using this screen.
Example: "Confident and in control — the player should feel like they have complete
information and complete authority over their choices, with no ambiguity about outcomes."]
[One sentence describing the feeling the player should have while using this screen.]
---
## 3. Navigation Position
> **Why this section exists**: A screen that does not know where it sits in the
> navigation hierarchy cannot define its entry/exit transitions, its back-button
> behavior, or its relationship to the game's pause state. Navigation position also
> reveals architectural problems early — if this screen is reachable from eight
> different places, that is a complexity flag that should be resolved in design, not
> implementation.
**Screen hierarchy** (use indentation to show parent-child relationships):
```
@@ -110,51 +75,31 @@ information and complete authority over their choices, with no ambiguity about o
| Entry Point | Triggered By | Notes |
|-------------|-------------|-------|
| [e.g., Main Menu → Play] | [Player selects "New Game"] | [Primary entry point] |
| [e.g., Pause Menu → Resume] | [Player presses Start from any gameplay state] | [Secondary entry] |
| [e.g., Game event] | [Tutorial system forces open first time only] | [Systemic entry — must not break if player dismisses] |
| [Entry point] | [Trigger] | [Notes] |
---
## 4. Entry & Exit Points
> **Why this section exists**: Entry and exit define the screen's contract with the
> rest of the navigation system. Every entry point must have a corresponding exit point.
> Transitions that are undefined become bugs — the player finds themselves stuck, or the
> game state becomes inconsistent. Fill this table completely before implementation
> begins. Empty cells are a sign that design work is unfinished.
> Every entry point must have a corresponding exit point. Empty cells are a sign
> that design work is unfinished. See guide Section 4 for worked examples.
**Entry table**:
| Trigger | Source Screen / State | Transition Type | Data Passed In | Notes |
|---------|----------------------|-----------------|----------------|-------|
| [e.g., Player presses Inventory button] | [Gameplay / Exploration state] | [Overlay push — game pauses] | [Current player loadout, inventory contents] | [Works from any non-combat state] |
| [e.g., Item pickup prompt accepted] | [Gameplay / Item Pickup dialog] | [Replace dialog with full inventory] | [Newly acquired item pre-highlighted] | [The new item should be visually distinguished on open] |
| [e.g., Quest system directs player to inventory] | [Gameplay / Quest Update notification] | [Overlay push] | [Quest-relevant item ID for highlight] | [Screen should deep-link to the relevant item] |
| [Trigger] | [Source] | [Transition] | [Data in] | [Notes] |
**Exit table**:
| Exit Action | Destination | Transition Type | Data Returned / Saved | Notes |
|-------------|------------|-----------------|----------------------|-------|
| [e.g., Player closes inventory (Back/B/Esc)] | [Previous state — Exploration] | [Overlay pop — game resumes] | [Updated equipment loadout committed] | [Changes must be committed before transition begins] |
| [e.g., Player selects "Equip" on item] | [Same screen, updated state] | [In-place state change] | [Loadout change event fired] | [No navigation, just a state refresh] |
| [e.g., Player navigates to Map from inventory shortcut] | [Map Screen] | [Replace] | [No data] | [Inventory state is preserved if player returns] |
| [Exit action] | [Destination] | [Transition] | [Data out / committed] | [Notes] |
---
## 5. Layout Specification
> **Why this section exists**: The layout specification is the handoff artifact between
> UX design and UI programming. It does not need to be pixel-perfect — it needs to
> communicate hierarchy (what is important), proximity (what belongs together), and
> proportion (what is big vs. small). ASCII wireframes achieve this without requiring
> design software. A programmer who reads this section should be able to build the
> correct structure without guessing. An artist who reads it should know where
> visual weight should be concentrated.
>
> Draw the layout at one standard resolution (e.g., 1920x1080). Note adaptations
> for other resolutions separately.
### 5.1 Wireframe
```
@@ -166,37 +111,14 @@ information and complete authority over their choices, with no ambiguity about o
... for scrollable content
● for the focused element on open
Example:
┌──────────────────────────────────────────────┐
│ [← Back] INVENTORY [Options] │ ← HEADER ZONE
├──────────────────────────────────────────────┤
│ ┌──────────────┐ ┌─────────────────────────┐│
│ │ CATEGORY NAV │ │ ITEM DETAIL PANEL ││ ← CONTENT ZONE
│ │ ● Weapons │ │ Item Name ││
│ │ Armor │ │ {item icon} ││
│ │ Consumable│ │ Stats comparison ││
│ │ Key Items │ │ Description text... ││
│ ├──────────────┤ └─────────────────────────┘│
│ │ ITEM GRID │ │
│ │ {□}{□}{□}{□} │ │
│ │ {□}{□}{□}{□} │ │
│ │ ... │ │
│ └──────────────┘ │
├──────────────────────────────────────────────┤
│ [Equip] [Drop] [Compare] [Close] │ ← ACTION BAR
└──────────────────────────────────────────────┘
]
See guide Section 5 for a completed example wireframe.]
```
### 5.2 Zone Definitions
| Zone Name | Description | Approximate Size | Scrollable? | Overflow Behavior |
|-----------|-------------|-----------------|-------------|-------------------|
| [e.g., Header Zone] | [Top bar: navigation, screen title, global actions] | [Full width, ~10% height] | [No] | [Truncate long screen names with ellipsis] |
| [e.g., Category Nav] | [Left panel: item category tabs] | [~25% width, ~75% height] | [Yes — vertical if categories exceed panel] | [Scroll indicator appears at bottom of list] |
| [e.g., Item Grid] | [Center: grid of item icons for selected category] | [~45% width, ~75% height] | [Yes — vertical] | [Page-based: 4x4 grid, next page on overflow] |
| [e.g., Detail Panel] | [Right: stats and description for selected item] | [~30% width, ~75% height] | [Yes — vertical for long descriptions] | [Fade at bottom, scroll to reveal] |
| [e.g., Action Bar] | [Bottom: context-sensitive actions for selected item] | [Full width, ~15% height] | [No] | [Actions collapse to icon-only below 4] |
| [Zone] | [Contents and purpose] | [% width x % height] | [Yes/No] | [Overflow handling] |
### 5.3 Component Inventory
@@ -205,96 +127,58 @@ Example:
| Component Name | Type | Zone | Purpose | Required? | Reuses Existing Component? |
|----------------|------|------|---------|-----------|---------------------------|
| [e.g., Back Button] | [Button] | [Header] | [Returns to previous screen] | [Yes] | [Yes — standard NavButton component] |
| [e.g., Screen Title Label] | [Text] | [Header] | [Displays "INVENTORY" or context name] | [Yes] | [Yes — ScreenTitle component] |
| [e.g., Category Tab] | [Toggle Button] | [Category Nav] | [Filters item grid by category] | [Yes] | [No — new component needed] |
| [e.g., Item Slot] | [Icon + Frame] | [Item Grid] | [Represents one inventory slot, empty or filled] | [Yes] | [No — new component] |
| [e.g., Item Name Label] | [Text] | [Detail Panel] | [Shows selected item's name] | [Yes] | [Yes — BodyText component] |
| [e.g., Stat Comparison Row] | [Compound — label + value + delta] | [Detail Panel] | [Shows stat value vs. currently equipped] | [Yes] | [No — new component] |
| [e.g., Equip Button] | [Primary Button] | [Action Bar] | [Equips selected item in appropriate slot] | [Yes] | [Yes — PrimaryAction component] |
| [e.g., Empty State Message] | [Text + Icon] | [Item Grid] | [Shown when category has no items] | [Yes] | [Yes — EmptyState component] |
| [Component] | [Type] | [Zone] | [Purpose] | [Yes/No] | [Yes — pattern/component name, or No — new] |
**Primary focus element on open**: [e.g., The first item in the Item Grid — or, if deep-linked, the highlighted item. If the grid is empty, focus lands on the first Category Tab.]
**Primary focus element on open**: [Element that receives focus when the screen opens, including deep-link and empty-state cases]
---
## 6. States & Variants
> **Why this section exists**: A screen is not a single picture — it is a set of
> states, each of which must look correct and behave correctly. Screens that are
> designed only in their "happy path" state ship with broken empty states, invisible
> loading indicators, and crashes when data is missing. Document every state before
> implementation. The states table is also the test matrix for QA.
> Document every state before implementation — at minimum: loading, empty,
> populated, and error. The states table is also the test matrix for QA.
> See guide Section 6 for a worked example.
| State Name | Trigger | What Changes Visually | What Changes Behaviorally | Notes |
|------------|---------|----------------------|--------------------------|-------|
| [Loading] | [Screen is opening, data not yet available] | [Item Grid shows skeleton/shimmer placeholders; Action Bar buttons disabled] | [No interactions possible except Close] | [Should not be visible >500ms under normal conditions; if it is, investigate data fetch performance] |
| [Empty — no items in category] | [Player switches to a category with zero items] | [Item Grid replaced by EmptyState component: icon + "Nothing here yet."] | [Action Bar shows no item actions; Drop/Equip/Compare all hidden] | [Do not show disabled buttons — remove them. Disabled buttons with no tooltip are confusing.] |
| [Populated — items present] | [Category has at least one item] | [Item Grid fills with item slots; first slot is auto-focused] | [All item actions available for selected item] | [Default and most common state] |
| [Item Selected] | [Player navigates to an item slot] | [Detail Panel populates; selected slot has focus ring; Action Bar updates to item's valid actions] | [Equip/Drop/Compare enabled based on item type] | [Equip is disabled if item is already equipped — show a "Equipped" badge instead] |
| [Confirmation Pending — Drop] | [Player selects Drop action] | [Confirmation dialog overlays the screen] | [All background interactions suspended until dialog resolves] | [Use a modal confirmation, not an inline toggle. Items cannot be recovered after dropping.] |
| [Error — data load failed] | [Inventory data could not be retrieved] | [Item Grid shows error state: icon + "Couldn't load items." + Retry button] | [Only Retry and Close are available] | [Log the error; do not expose technical details to player] |
| [Item Newly Acquired] | [Screen opened from item pickup deep-link] | [Newly acquired item has a visual "New" badge; Detail Panel pre-populated with that item] | [Same as Item Selected but with badge until player navigates away] | [Badge persists until the player manually navigates off that slot once] |
| [Loading / Empty / Populated / Selected / Confirmation / Error / other] | [Trigger] | [Visual changes] | [Behavioral changes] | [Notes] |
---
## 7. Interaction Map
> **Why this section exists**: This section is the source of truth for what every
> input does on this screen. It forces the designer to think through every input
> method (mouse, keyboard, gamepad, touch) and every interactive state (hover, focus,
> pressed, disabled). Gaps in this table are bugs waiting to happen. The
> interaction map is also the input for the accessibility audit — if an action is
> only reachable by mouse, it will fail the keyboard and gamepad columns.
> Cover every input method for the platform target (mouse, keyboard, gamepad,
> touch). Gaps in this table are bugs waiting to happen. See guide Section 7.
### 7.1 Navigation Inputs
| Input | Platform | Action | Visual Response | Audio Cue | Notes |
|-------|----------|--------|-----------------|-----------|-------|
| [Arrow keys / D-Pad] | [All] | [Move focus within active zone] | [Focus ring moves to adjacent element] | [Soft navigation tick] | [Wrap at edges within zone; do not cross zones with arrows alone] |
| [Tab / R1] | [KB / Gamepad] | [Move focus to next zone (Category → Grid → Detail → Action Bar)] | [Focus ring jumps to first element in next zone] | [Distinct zone-change tone] | [Shift+Tab / L1 goes backward] |
| [Mouse hover] | [PC] | [Show hover state on interactive elements] | [Highlight / underline / color shift] | [None] | [Hover does NOT move focus — only click does] |
| [Mouse click] | [PC] | [Select and focus the clicked element] | [Pressed state flash, then selected/focused] | [Soft click] | [Right-click opens context menu if applicable; otherwise no-op] |
| [Touch tap] | [Mobile] | [Select and activate in one gesture] | [Press ripple] | [Soft click] | [Treat tap as click + confirm for low-risk actions; require explicit confirm for destructive actions] |
| [Input] | [Platform] | [Action] | [Visual response] | [Audio] | [Notes] |
### 7.2 Action Inputs
| Input | Platform | Context (What must be focused) | Action | Response | Animation | Audio Cue | Notes |
|-------|----------|-------------------------------|--------|----------|-----------|-----------|-------|
| [Enter / A button / Left click] | [All] | [Item slot focused] | [Select item → populate Detail Panel] | [Detail panel slides in or updates in place] | [Panel fade/slide in, 120ms] | [Soft select tone] | [If item already selected: no-op] |
| [Enter / A button] | [All] | [Equip button focused] | [Equip selected item] | [Button animates press; item badge updates to "Equipped"; previously equipped item loses badge] | [Badge swap, 80ms] | [Equip success sound] | [Fires EquipItem event to Inventory system] |
| [Triangle / Y button / Right-click] | [All] | [Item slot focused] | [Open item context menu] | [Context menu appears adjacent to item slot] | [Popover, 80ms] | [Menu open sound] | [Context menu contains: Equip, Drop, Inspect, Compare] |
| [Square / X button] | [Gamepad] | [Item slot focused] | [Quick-equip without opening detail] | [Equip animation plays inline on slot] | [Slot flash, 80ms] | [Equip success sound] | [Convenience shortcut; does not change screen state] |
| [Esc / B button / Back] | [All] | [Any, screen level] | [Close screen and return to previous state] | [Screen exit transition plays] | [Slide out, 200ms] | [Back/close tone] | [Commits all changes before closing. No discard — inventory is not a draft.] |
| [F / L2] | [KB / Gamepad] | [Any] | [Toggle filter panel] | [Sort/filter overlay opens] | [Slide in from right, 200ms] | [Panel open tone] | [If no items in category, filter is disabled] |
| [Input] | [Platform] | [Focus context] | [Action] | [Response] | [Animation + timing] | [Audio] | [Notes] |
### 7.3 State-Specific Behaviors
| State | Input Restriction | Reason |
|-------|------------------|--------|
| [Loading] | [All item and action inputs disabled] | [No data to act on; prevent race conditions] |
| [Confirmation dialog open] | [Only Confirm and Cancel inputs active] | [Modal — background is locked] |
| [Error state] | [Only Retry and Close active] | [No data available to navigate] |
| [State] | [Which inputs are disabled] | [Why] |
---
## 8. Data Requirements
> **Why this section exists**: The separation between UI and game state is the most
> important architectural boundary in a game's UI system. UI reads data; it does not
> own it. UI fires events; it does not write state directly. This section defines
> exactly what data this screen needs to display, where it comes from, and how
> frequently it updates. Filling this table before implementation prevents two
> common failure modes: (1) UI developers reaching into systems they should not touch,
> and (2) systems not knowing they need to expose data until a UI is half-built.
> UI reads data; it does not own it. UI fires events; it does not write state
> directly. Every displayed data element needs a source system and owner.
> See guide Section 8 for a worked example.
| Data Element | Source System | Update Frequency | Who Owns It | Format | Null / Missing Handling |
|--------------|--------------|-----------------|-------------|--------|------------------------|
| [e.g., Item list] | [Inventory System] | [On screen open; on InventoryChanged event] | [InventorySystem] | [Array of ItemData structs: id, name, icon_path, category, stats, is_equipped] | [Empty array → show Empty State. Never null — system must return array.] |
| [e.g., Equipped loadout] | [Equipment System] | [On screen open; on EquipmentChanged event] | [EquipmentSystem] | [Dict mapping slot_id → item_id] | [Unequipped slot has null value — UI shows empty slot icon] |
| [e.g., Item stat comparisons] | [Stats System] | [On item selection change] | [StatsSystem] | [Dict mapping stat_name → {current, new, delta}] | [If no item selected, detail panel shows placeholder. Stats system must handle this gracefully.] |
| [e.g., Player currency] | [Economy System] | [On screen open only — inventory does not show live currency] | [EconomySystem] | [Int — gold pieces] | [If currency system not active for this game mode, hide the currency row entirely] |
| [e.g., Newly acquired item flag] | [Inventory System] | [On screen open] | [InventorySystem] | [Array of item_ids flagged as new] | [If empty array, no badges shown] |
| [Data element] | [System] | [When it updates — specific trigger, not "realtime"] | [Owning system — never the UI] | [Type/shape] | [What shows when data is unavailable] |
> **Rule**: This screen must never write directly to any system listed above. All
> player actions fire events (see Section 9). Systems update their own data and
@@ -304,52 +188,30 @@ Example:
## 9. Events Fired
> **Why this section exists**: This is the other half of the UI/system boundary.
> Where Section 8 defines what the UI reads, this section defines what the UI
> communicates back to the game. Specifying events at design time prevents UI
> programmers from writing game logic, and prevents game programmers from being
> surprised by what the UI does. Every destructive or state-changing player action
> must appear in this table.
> Every destructive or state-changing player action must appear in this table.
> See guide Section 9 for a worked example.
| Player Action | Event Fired | Payload | Receiver System | Notes |
|---------------|-------------|---------|-----------------|-------|
| [Player equips an item] | [EquipItemRequested] | [{item_id: string, target_slot: string}] | [Equipment System] | [Equipment System validates the action and fires EquipmentChanged if successful; UI listens for EquipmentChanged to update its display] |
| [Player drops an item] | [DropItemRequested] | [{item_id: string, quantity: int}] | [Inventory System] | [Fires only after player confirms the drop dialog. Inventory System removes the item and fires InventoryChanged.] |
| [Player opens item compare] | [ItemCompareOpened] | [{item_a_id: string, item_b_id: string}] | [Analytics System] | [No game-state change — analytics event only. Compare view is purely local UI state.] |
| [Player closes screen] | [InventoryScreenClosed] | [{session_duration_ms: int}] | [Analytics System] | [Fires on every close regardless of reason. Used for engagement metrics.] |
| [Player navigates between categories] | [InventoryCategoryChanged] | [{category: string}] | [Analytics System] | [Analytics only. No game state change.] |
| [Action] | [EventName] | [{fields}] | [System] | [Validation/response flow, or "analytics only"] |
---
## 10. Transition & Animation
> **Why this section exists**: Transitions are not decoration — they communicate
> hierarchy and causality. A screen that slides in from the right implies the
> player has moved forward. A screen that fades implies a context break. Inconsistent
> transitions make navigation feel broken even when it is technically correct.
> This section ensures transitions are specified intentionally, not left to the
> developer's discretion, and that accessibility settings (reduced motion) are
> planned for from the start.
> Specify at least the screen enter and exit transitions, plus reduced-motion
> behavior for each. See guide Section 10 for a worked example.
| Transition | Trigger | Direction / Type | Duration (ms) | Easing | Interruptible? | Skipped by Reduced Motion? |
|------------|---------|-----------------|--------------|--------|----------------|---------------------------|
| [Screen enter] | [Screen pushed onto stack] | [Slide in from right] | [250] | [Ease out cubic] | [No — must complete before interaction is enabled] | [Yes — instant appear at 0ms] |
| [Screen exit — Back] | [Player presses Back] | [Slide out to right] | [200] | [Ease in cubic] | [No] | [Yes — instant disappear] |
| [Screen exit — Forward] | [Player navigates to child screen] | [Slide out to left] | [200] | [Ease in cubic] | [No] | [Yes — instant] |
| [Detail panel update] | [Player selects a new item] | [Cross-fade content] | [120] | [Linear] | [Yes — if player navigates quickly, previous animation cancels] | [Yes — instant swap] |
| [Loading → Populated] | [Data arrives after load] | [Skeleton shimmer fades out, content fades in] | [180] | [Ease out] | [No] | [Yes — instant reveal] |
| [Action Bar button press] | [Player activates a button] | [Scale down 95% on press, return on release] | [60 down / 60 up] | [Ease out / ease in] | [Yes — if released early, returns to normal] | [No — this is tactile feedback, not decorative motion] |
| [Confirmation dialog open] | [Player initiates destructive action] | [Background dims 60% opacity; dialog scales up from 95%] | [150] | [Ease out] | [No] | [Yes — instant appear, no scale] |
| [New item badge appear] | [Screen opens with newly acquired item] | [Badge pops from 0% to 110% to 100% scale] | [200 total] | [Ease out back] | [No] | [Yes — instant appear at 100% scale] |
| [Screen enter / exit / in-screen transition] | [Trigger] | [Type] | [ms] | [Easing] | [Yes/No] | [Yes/No + fallback] |
---
## 11. Input Method Completeness Checklist
> **Why this section exists**: Input completeness is not optional — it is a
> certification requirement for console platforms and a legal risk area for
> accessibility laws in multiple markets. Fill this checklist before marking
> the spec as Approved. Any unchecked item blocks implementation start.
> Fill this checklist before marking the spec as Approved. Any unchecked item
> blocks implementation start.
**Keyboard**
- [ ] All interactive elements are reachable using Tab and arrow keys alone
@@ -382,11 +244,9 @@ Example:
## 12. Screen-Level Accessibility Requirements
> **Why this section exists**: Accessibility requirements must be specified at design
> time because retrofitting them is expensive and often architecturally impractical.
> This section documents requirements specific to this screen. Project-wide standards
> live in `docs/accessibility-requirements.md` — consult it before filling this
> section so you do not duplicate or contradict project-level commitments.
> Project-wide standards live in `design/accessibility-requirements.md` — consult it
> before filling this section so you do not duplicate or contradict project-level
> commitments.
>
> Accessibility Tiers in this project:
> - Basic: WCAG 2.1 AA text contrast, keyboard navigable, no motion-only information
@@ -398,71 +258,32 @@ Example:
| Text Element | Background Context | Required Ratio | Current Ratio | Pass? |
|--------------|-------------------|---------------|---------------|-------|
| [e.g., Item name in Detail Panel] | [Dark panel background ~#1a1a1a] | [4.5:1 (WCAG AA normal text)] | [TBD — verify in implementation] | [ ] |
| [e.g., Category tab label — inactive] | [Mid-grey tab background] | [4.5:1] | [TBD] | [ ] |
| [e.g., Category tab label — active] | [Accent color background] | [4.5:1] | [TBD] | [ ] |
| [e.g., Action button label] | [Button color (varies by state)] | [4.5:1] | [TBD] | [ ] |
| [e.g., Stat comparison delta (positive)] | [Detail panel] | [4.5:1 — do NOT rely on green color alone] | [TBD] | [ ] |
| [Text element] | [Background] | [Ratio — 4.5:1 WCAG AA baseline] | [TBD] | [ ] |
**Colorblind-unsafe elements and mitigations**:
| Element | Colorblind Risk | Mitigation |
|---------|----------------|------------|
| [e.g., Stat delta indicators (red/green for worse/better)] | [Red-green colorblindness (Deuteranopia) — most common form] | [Add arrow icons (↑ / ↓) and +/- prefix in addition to color. Color is a redundant, not sole, indicator.] |
| [e.g., Item rarity color coding (grey/green/blue/purple/orange)] | [Multiple types — rarity color is a common industry failure] | [Add rarity name text label below icon. Color is supplemental only.] |
| [Element] | [Risk type] | [Non-color redundant indicator] |
**Focus order** (Tab key sequence, numbered):
[e.g.,
1. Back button (Header)
2. Options button (Header)
3. Category Tab 1 — Weapons
4. Category Tab 2 — Armor
5. Category Tab 3 — Consumables
6. Category Tab 4 — Key Items
7. Item Slot [0,0]
8. Item Slot [0,1] ... (grid traverses left-to-right, top-to-bottom)
9. Last item slot
10. Equip button (Action Bar)
11. Drop button (Action Bar)
12. Compare button (Action Bar)
13. Close button (Action Bar)
→ Cycles back to Back button
Focus does not enter the Detail Panel — it is a display panel driven by item focus, not independently navigable.]
[Numbered focus sequence covering every interactive element, including cycle behavior and any panels focus does not enter — see guide Section 12 for an example]
**Screen reader announcements for key state changes**:
| State Change | Announcement Text | Announcement Timing |
|--------------|------------------|---------------------|
| [Screen opens] | ["Inventory screen. [N] items. [Active category] selected."] | [On screen focus settle] |
| [Player focuses an item slot] | ["[Item name]. [Category]. [Rarity]. [Key stats summary]. [Equipped / Not equipped]."] | [On focus arrival] |
| [Player equips an item] | ["[Item name] equipped to [slot name]."] | [After EquipmentChanged event confirmed] |
| [Player drops an item] | ["[Item name] dropped."] | [After InventoryChanged event confirmed] |
| [Category changes] | ["[Category name]. [N] items."] | [On category tab focus] |
| [Empty state shown] | ["No items in [category name]."] | [When empty state renders] |
| [State change] | ["Announcement"] | [When it fires] |
**Cognitive load assessment**:
[Estimate the number of information streams the player is simultaneously tracking while
using this screen. For this screen: (1) item grid position, (2) item detail stats,
(3) current equipment loadout for comparison, (4) available actions, (5) item category.
That is 5 concurrent streams — within the standard 7±2 limit, but at the higher end.
Mitigation: detail panel auto-updates on navigation so the player never needs to
manually retrieve item info. Reduce active decisions by surfacing stat comparison
automatically.]
[Count the concurrent information streams the player tracks on this screen; compare against the 7±2 limit and state mitigations — see guide Section 12 for an example]
---
## 13. Localization Considerations
> **Why this section exists**: UI built without localization in mind breaks on first
> translation. German text is typically 30–40% longer than English. Arabic and Hebrew
> require right-to-left layout mirroring. Japanese and Chinese text may be significantly
> shorter than English, creating awkward whitespace. These issues are cheap to plan for
> and expensive to fix after a layout is built and shipped. Every text element should
> have an explicit max-character count and a plan for overflow.
**General rules for this screen**:
- All text elements must tolerate a minimum of 40% expansion from English baseline
- RTL layout (Arabic, Hebrew): mirrored layout required — document which elements mirror and which do not
@@ -471,27 +292,19 @@ automatically.]
| Text Element | English Baseline Length | Max Characters | Expansion Budget | RTL Behavior | Overflow Behavior | Risk |
|--------------|------------------------|----------------|-----------------|--------------|-------------------|------|
| [e.g., Screen title "INVENTORY"] | [9 chars] | [16 chars] | [78%] | [Mirror to right, or center — acceptable] | [Truncate with ellipsis — title is not critical content] | [Low] |
| [e.g., Item name] | [~15 chars avg, max ~35 "Enchanted Dragon Scale Gauntlets"] | [50 chars] | [43%] | [Right-align in RTL layouts] | [Truncate with tooltip showing full name on hover/focus] | [Medium — long fantasy item names are common] |
| [e.g., Item description] | [~80–120 chars] | [200 chars] | [67%] | [Right-align, wrap normally] | [Scroll within Detail Panel — no truncation] | [Low — panel is scrollable] |
| [e.g., Action button "Equip"] | [5 chars] | [14 chars] | [180%] | [Button layout mirrors; text right-aligns] | [Shrink font to 90% minimum, then truncate] | [Medium — "Ausrüsten" in German is 9 chars] |
| [e.g., Category tab "Consumables"] | [11 chars] | [18 chars] | [64%] | [Mirror tab position] | [Abbreviate: "Consum." — define abbreviations per language in loc file] | [High — long localized tab labels are a known problem] |
| [Text element] | [chars] | [max chars] | [%] | [Mirror/align behavior] | [Truncate/scroll/shrink strategy] | [Low/Medium/High] |
---
## 14. Acceptance Criteria
> **Why this section exists**: Acceptance criteria are the contractual definition of
> "done." Without them, implementation is complete when the developer says it is.
> With them, implementation is complete when a QA tester can verify every item on
> this list. Write criteria that a tester can verify independently, without asking the
> designer what they meant. Every criterion should be binary — pass or fail, not
> subjective.
> Write criteria a QA tester can verify independently, without asking the designer
> what they meant. Every criterion should be binary — pass or fail, not subjective.
**Performance**
- [ ] Screen opens (first frame visible) within 200ms of trigger on minimum-spec hardware
- [ ] Screen is fully interactive (all data loaded) within 500ms of trigger on minimum-spec hardware
- [ ] Navigation between items produces no perceptible frame drop (maintain target framerate ±5fps)
- [ ] Screen opens (first frame visible) within [200]ms of trigger on minimum-spec hardware
- [ ] Screen is fully interactive (all data loaded) within [500]ms of trigger on minimum-spec hardware
- [ ] Navigation between elements produces no perceptible frame drop (maintain target framerate ±5fps)
**Layout & Rendering**
- [ ] Screen displays correctly (no overlap, no cutoff, no overflow) at minimum supported resolution [specify]
@@ -499,8 +312,8 @@ automatically.]
- [ ] Screen displays correctly at 4:3, 16:9, 16:10, and 21:9 aspect ratios if targeting PC
- [ ] No text overflow or truncation in English within defined max-character bounds
- [ ] No text overflow or truncation in the longest-translation language [specify — typically German]
- [ ] All states (Loading, Empty, Populated, Error, Confirmation) render correctly
- [ ] Item grid scrolls smoothly without frame drops when all item slots are populated
- [ ] All states documented in Section 6 render correctly
- [ ] Scrollable zones scroll smoothly without frame drops when fully populated
**Input**
- [ ] All interactive elements reachable by keyboard using Tab and arrow keys only
@@ -513,13 +326,13 @@ automatically.]
**Events & Data**
- [ ] All events in Section 9 fire with correct payloads on all exit paths (verify with debug logging)
- [ ] Screen does not write directly to any game system (verify: no direct state mutation calls)
- [ ] Inventory changes persist correctly after screen is closed and reopened
- [ ] Screen handles InventoryChanged events fired by other systems while it is open without crashing
- [ ] Changes made on this screen persist correctly after it is closed and reopened
- [ ] Screen handles data-change events fired by other systems while it is open without crashing
**Accessibility**
- [ ] All text passes minimum contrast ratios specified in Section 12
- [ ] Stat comparison does not rely on color alone as the sole differentiator
- [ ] Screen reader announces item name and key stats on focus (verify with platform screen reader)
- [ ] No information relies on color alone as the sole differentiator
- [ ] Screen reader announces documented state changes (verify with platform screen reader)
- [ ] Reduced motion setting results in instant transitions (no animated transitions)
- [ ] High contrast mode (if applicable to Accessibility Tier) renders without visual breakage
@@ -538,7 +351,4 @@ automatically.]
| Question | Owner | Deadline | Resolution |
|----------|-------|----------|-----------|
| [e.g., Should item comparison be automatic (always showing equipped stats) or player-triggered (press Compare)?] | [ui-designer] | [Sprint 4, Day 3] | [Pending] |
| [e.g., Do we support controller cursor (free aim) in the item grid, or d-pad-only grid navigation?] | [lead-programmer + ui-designer] | [Sprint 4, Day 3] | [Pending — depends on ADR-0015 input model decision] |
| [e.g., What is the game's item drop policy — permanent loss or drop-to-world?] | [systems-designer] | [Requires GDD update] | [Blocked on inventory GDD Edge Cases section] |
| [e.g., Maximum inventory size — does the grid have a hard cap or is it infinite-scroll?] | [economy-designer] | [Sprint 3, Day 5] | [Pending] |
| [Add question] | [Owner] | [Deadline] | [Resolution] |
+38 -7
View File
@@ -6,6 +6,9 @@
# pattern: text pattern that must appear in the file (checked after glob)
# min_count: minimum matching files required (default: 1)
# note: human-readable fallback when completion can't be auto-detected
# any_of: list of alternative {glob, pattern} specs — the step is complete if
# ANY one of them matches. Use when a setting has migrated and may
# legitimately live in either the new or the legacy location.
#
# required: true → blocks progression to next phase (shown as REQUIRED)
# required: false → optional enhancement (shown as OPTIONAL)
@@ -31,9 +34,20 @@ phases:
name: "Engine Setup"
command: /setup-engine
required: true
# v1.1: engine.name in project.yaml is the primary source; technical-
# preferences.md is the legacy fallback. Checking only the legacy file
# made a correctly-configured project fail this REQUIRED gate.
artifact:
glob: ".claude/docs/technical-preferences.md"
pattern: "Engine: [^[]"
any_of:
- glob: "project.yaml"
pattern: "name:[[:space:]]*(Godot|Unity|Unreal)"
# technical-preferences.md writes "- **Engine**: Godot 4.6", so the
# pattern must clear the bold markers. The previous "Engine: [^[]"
# required a literal "Engine: " and therefore never matched any
# file /setup-engine produces. The [^[] guard rejects the
# "[TO BE CONFIGURED]" placeholder.
- glob: ".claude/docs/technical-preferences.md"
pattern: "\\*\\*Engine\\*\\*: [^[]"
description: "Configure engine, pin version, set naming conventions and performance budgets"
- id: game-concept
@@ -85,7 +99,7 @@ phases:
command: /design-review
required: true
repeatable: true
description: "Validate each GDD (8 required sections, no MAJOR REVISION verdict). Run per system."
description: "Validate each GDD (required sections per workflow tier, no MAJOR REVISION verdict). Run per system."
- id: review-all-gdds
name: "Cross-GDD Review"
@@ -143,10 +157,16 @@ phases:
- id: accessibility-doc
name: "Accessibility Requirements"
# This step had no `command:` at all -- the only artifact entry in the
# catalog that named no producer. It was REQUIRED, so the Technical
# Setup -> Pre-Production gate could never pass, and the remediation
# every skill printed ("run /ux-design") wrote into design/ux/ where
# this glob does not look. /ux-design now has an `accessibility` mode.
command: /ux-design
required: true
artifact:
glob: "design/accessibility-requirements.md"
description: "Commit accessibility tier (Basic/Standard/Comprehensive/Exemplary) and feature matrix. UX specs (Phase 4) reference this tier."
description: "Run `/ux-design accessibility`. Commit accessibility tier (Basic/Standard/Comprehensive/Exemplary) and feature matrix. UX specs (Phase 4) reference this tier."
pre-production:
label: "Pre-Production"
@@ -191,7 +211,11 @@ phases:
command: /prototype
required: false
artifact:
glob: "prototypes/*/README.md"
# /prototype writes prototypes/[name]-concept/REPORT.md -- it has never
# written a README. The `-concept` suffix is load-bearing: /vertical-slice
# writes the same REPORT.md basename under `-vertical-slice`, so a bare
# `prototypes/*/REPORT.md` here would let either step satisfy the other.
glob: "prototypes/*-concept/REPORT.md"
min_count: 1
description: "Build a throwaway prototype to validate the core mechanic is fun before committing to full production. Recommended for first-time mechanics or high-risk design decisions. Solo devs with proven concepts may skip."
@@ -237,7 +261,11 @@ phases:
command: /vertical-slice
required: false
artifact:
glob: "prototypes/*/REPORT.md"
# Must stay scoped to `-vertical-slice`: the untethered form matched
# /prototype's concept report, so running only /prototype silently
# marked the vertical slice complete and skipped the validation the
# Pre-Production → Production gate exists to require.
glob: "prototypes/*-vertical-slice/REPORT.md"
min_count: 1
description: "Build and playtest a vertical slice — a complete end-to-end pass through the core loop. Recommended before committing epics and stories to production. Skipping is a valid solo dev call but increases risk of late-stage design pivots. If built, must be played and documented before advancing."
@@ -355,7 +383,10 @@ phases:
command: /playtest-report
required: true
artifact:
glob: "production/playtests/*.md"
# /playtest-report writes production/qa/playtests/, not production/playtests/.
# The old glob matched nothing on every project, so this REQUIRED step
# read as 0/3 forever no matter how many playtests were actually run.
glob: "production/qa/playtests/*.md"
min_count: 3
description: "Cover: new player experience, mid-game systems, difficulty curve"
+310
View File
@@ -0,0 +1,310 @@
# Workflow Modes — Shared Skill Pattern
This document defines `modes.workflow` and `workflow_overrides` — how much
design documentation is REQUIRED before code can begin — for every skill that
authors, reviews, gates, or plans against project artifacts. Skills reference
this document instead of embedding the tier tables inline.
**Companion spec**: `.claude/docs/effects-map.md`
sections `modes.workflow` and `workflow_overrides` are the source of
truth for behavior. This document is the implementation pattern.
> **Do not read `effects-map.md` during a skill run.** It is ~2,150 lines
> (~110 KB) — about five times the size of everything CLAUDE.md loads per
> session combined — and it is a reference for *authoring and changing the
> spec*, not a runtime input. **This document is self-sufficient** for resolving
> the tier and applying it: the resolution chain, the three tiers, the required
> sections, and the override rules are all here. If you hit a case this document
> genuinely does not cover, read only the one `effects-map.md` section for the
> knob in question — never the file.
**Related shared docs**: `.claude/docs/automation-modes.md` (how skills prompt),
`.claude/docs/director-gates.md` (which reviewers spawn). `workflow` is
orthogonal to both — it controls *what artifacts must exist*, not *how the
skill prompts* or *who reviews*.
---
## How to Use This Document
A skill that authors, reviews, or gates a design artifact resolves the
effective workflow tier at startup, then applies the required-section /
required-artifact set for that tier.
**Resolution (per skill):**
```
Resolve the workflow tier (store the result; see scope note below):
1. If the resolution is for a named system AND
`workflow_overrides.system_overrides.<system>` is set → use that tier
2. Else read `modes.workflow` from `project.yaml` → use that value
3. Else → use the tier implied by `modes.rigor`
(`minimal`→`minimal`, `standard`→`standard`, `full`→`full`;
`rigor` itself defaults to `minimal`)
```
`modes.workflow` has **no terminal default** — step 3 is the `rigor` expansion,
not a hardcoded `standard`. The resolved value is the same for an unconfigured
project, so nothing observable changed; but a skill that hardcodes `standard` as
its fallback will ignore `rigor: minimal` and `rigor: full` entirely.
### What `<system>` is — one derivation, everywhere
**`<system>` is the GDD filename stem**: `design/gdd/hammer-heat-system.md` →
`hammer-heat-system`. That is the key to write under
`workflow_overrides.system_overrides`, and every skill must derive it the same
way.
A `TR-[system]-NNN` ID's `[system]` segment is **an alias, not the key**. Accept
it as a fallback match when the GDD stem yields nothing, but never derive the key
from it in preference to the stem.
> **Why this is stated here rather than per skill.** Reading *"the `[system]`
> segment of its `TR-[system]-NNN` ID (else its `design/gdd/` path)"* — TR-ID
> **first** — is the wrong order. A system whose GDD is `hammer-heat-system.md` and
> whose requirements are `TR-heat-001` then had **two different override keys
> depending on whether a registry entry existed**, and the documented remedy for
> a missing GDD section — "set
> `workflow_overrides.system_overrides.hammer-heat-system: full`" — was looked up
> under `heat`, found nothing, and continued at the project tier **silently**.
> The escape hatch existed and could not be reached.
**A key that matches no system is an error, not a no-op.** If
`workflow_overrides.system_overrides` contains a key that resolves to no GDD stem
in `design/gdd/`, say so — naming the unmatched key and the stems available.
Silently ignoring it is how the above went unnoticed.
> **Checked where GDDs are expected to already exist — not by the skill that
> writes them.** `/gate-check` is the single implementing site (see
> `.claude/skills/gate-check/SKILL.md` §"Per-system overrides"), and it runs at a
> phase boundary, by which point every in-scope GDD should be on disk. An
> unmatched key there is genuinely suspicious.
>
> `/design-system` **creates** `design/gdd/<system>.md`, so before its first run
> the override key matches no stem *by definition* — that is the healthy case,
> not an error. It must not report the key as orphaned, and must not refuse to
> apply the tier it names. The same holds for any other authoring skill running
> before the GDD exists. Applying this rule there would fire on exactly the
> configuration it was written to protect.
---
Step 1 (the per-system override) applies to skills that act on a named system:
- **Single-system, resolve once per run**: `design-system`, `design-review`,
`dev-story`, `story-done`, `create-stories` (one story/epic per invocation).
- **Multi-system, resolve once per item**: `story-readiness` (per story across
`all`/`sprint` scope), `qa-plan` and `regression-suite` audit (per GDD/system).
These do NOT freeze a single tier for the run — different systems in one run
may resolve to different tiers.
Skills that operate project-wide (`gate-check`, `create-epics`) use the
project-level `workflow` plus consider per-system overrides where the tier table
says so.
> **"Critical ADR" (used in the tier tables):** an ADR governing a
> **Foundation-layer** system (scene management, event architecture, save/load,
> and the like — the systems whose decisions everything else depends on). At
> `standard`, only critical ADRs are required/blocking; non-critical ADRs are
> advisory. When in doubt about an ADR's layer, treat it as critical (fail safe
> toward requiring it).
`modes.workflow` reads via **`resolve_config --keys workflow`** (or
`resolve_setting modes.workflow`), which applies the whole chain including the
`rigor` expansion. Do **not** use `get_effective_yaml_key modes.workflow`: it
reads the two YAML files only, so on a project that sets `modes.rigor` and not
`modes.workflow` it returns **empty** while the effective tier is whatever rigor
implies. (`project.local.yaml` is not allowed to override workflow — it is locked
to `project.yaml` per the whitelist — so the only sources are `project.yaml` and
the expansion.) Per-system overrides read via
`get_yaml_key project.yaml workflow_overrides.system_overrides.<system>`.
---
## The Three Tiers
| Tier | Token/time cost | Required before code | Best for |
|------|----------------|---------------------|----------|
| `full` | High | All 8 GDD sections per system, full architecture, all ADRs, art bible, UX specs per screen | Teams, commercial titles, learning the full pipeline |
| `standard` | Balanced | 5 GDD sections per system, one architecture doc, critical ADRs, game concept, systems index | Projects that outgrew a brief - several interacting systems, or a design someone else implements |
| `minimal` | Low | One-page `design/game-brief.md` + engine choice (its build-order field is the plan — no separate sprint plan) | **Default.** Jam projects, small scope, design already in your head |
**Default**: `minimal` (the rationale block above `_yaml_helper_defaults` in
`.claude/hooks/yaml-helper.sh` carries the reasoning and the ordering
constraint). **Set by**: `/start`, `/settings`. **Locked to
`project.yaml`** (not locally overridable — divergence would change which
artifacts must exist on disk).
> **Permissive, not restrictive.** `workflow` controls what is REQUIRED, not
> what is ALLOWED. Any skill can run at any tier. The setting changes what
> `gate-check` enforces and what completeness checks validate — never what the
> user can invoke.
> **`minimal` floor.** Even at minimal, engine choice and a filled
> **`design/game-brief.md`** are required before code starts — the brief's
> build-order field is the plan, so there is no separate `sprint-plan` step.
> Everything else can be skipped.
> **"Game brief" is a real artifact at `minimal`: `design/game-brief.md`.**
> `/brainstorm` writes it from the one-page template
> (`.claude/docs/templates/game-brief.md`) when the effective tier is `minimal`,
> in place of the full-length `design/gdd/game-concept.md` it writes at
> `standard`/`full`. The two are distinct files for distinct tiers: any check,
> gate, or glob for the `minimal` design artifact must target
> **`design/game-brief.md`**; `game-concept.md` remains the `standard`/`full`
> concept doc.
---
## GDD Required Sections per Tier
The 8 GDD sections: Overview, Player Fantasy, Detailed Rules, Formulas,
Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria.
> **Section-name alias.** "Detailed Rules" is the canonical name in the design
> standard, but the GDD template (`.claude/docs/templates/game-design-document.md`)
> and `/design-system` author this section under the heading `## Detailed Design`
> (with Core Rules / States / Interactions sub-headings). The two names denote the
> **same required section** — any skill that detects or validates section presence
> (`design-review`, `gate-check`, `adopt`, `project-stage-detect`) must accept
> either heading. Do not treat "Detailed Rules" as missing when `## Detailed
> Design` is present.
| Tier | Required GDD sections |
|------|----------------------|
| `full` | All 8 |
| `standard` | **5 required**: Overview, Detailed Rules, Edge Cases, Dependencies, Acceptance Criteria. **Conditional**: Formulas — required when the system **defines numeric rules** (rates, curves, thresholds, costs, damage, drop weights — anything a balance pass would tune); optional only when it defines none. The `Category` column is a hint, not the test. **Skipped**: Player Fantasy, Tuning Knobs. |
| `minimal` | None — `design/game-brief.md` replaces GDDs. A GDD may still be authored voluntarily. |
> **Edge Cases is required at `standard`** (it was promoted from optional —
> skipping it produced "what happens if X is null?" debt during implementation).
> **Art bible is conditional at `standard`** — required only if visual asset
> stories exist in the project. Code-focused projects skip it. At `full`, all
> 9 art bible sections are required. (`workflow_overrides.art_bible_strict:
> true` forces all 9 regardless of tier.)
---
## `workflow_overrides`
This key holds two mechanisms with **different directional rules**. Read the one
you are using — conflating them is a known and easy mistake.
```yaml
workflow_overrides:
# --- the three boolean FLAGS: additive, stricter-only ---
edge_cases: false # force Edge Cases required (no-op at standard/full; relevant at minimal)
tuning_knobs: false # force Tuning Knobs required (relevant at standard, no-op at full)
art_bible_strict: false # force all 9 art bible sections regardless of asset stories
# --- system_overrides: replaces a tier, BOTH directions ---
system_overrides: {} # per-system tier overrides (see below)
```
**The three boolean flags are additive on top of the chosen `workflow` level —
they make requirements STRICTER, never looser.** Each one only ever forces a
requirement *on*; setting a flag cannot opt out of a requirement the tier
imposes. There is no value of `edge_cases`, `tuning_knobs` or `art_bible_strict`
that removes anything.
**`system_overrides` is not a flag and is not additive.** It *replaces* the
effective tier for one named system, in **either** direction — see the next
section. A loosening override genuinely loosens: on a `full` project,
`system_overrides.inventory: minimal` drops that system's required sections to
zero. That is the intended design (it is what makes "one trivial system inside a
serious project" expressible), but it means an override is **not** a safe
no-op — do not leave one in place assuming the stricter-only rule protects you.
### Per-system overrides
```yaml
workflow_overrides:
system_overrides:
combat: full # combat GDD requires all 8 sections regardless of project workflow
inventory: minimal # inventory needs no GDD — the game brief covers it (minimal = no required sections)
```
`system_overrides` is a map of `system_name: workflow_level`. The named system
uses the override tier; all other systems use the project-level `workflow`.
A skill acting on a named system resolves its effective tier via step 1 of the
resolution chain above.
---
## Effective-Tier Resolution Worked Example
Project has `modes.workflow: standard`, `workflow_overrides.system_overrides.combat: full`.
- `/design-system combat` → effective tier **full** → requires all 8 sections
- `/design-system inventory` → no override → effective tier **standard** → 5 sections + conditional Formulas
- `/gate-check` (Systems Design → Technical Setup) → requires the combat GDD at 8 sections AND every other MVP GDD at 5 sections before passing
---
## Per-Skill Behavior (the working summary — sufficient at runtime)
**Authoring** — branch on the effective tier for required sections (and, for
`brainstorm`, for which design artifact is produced — `design/game-brief.md` at
`minimal` vs `design/gdd/game-concept.md` at `standard`/`full`):
`brainstorm`, `design-system`, `art-bible`, `create-architecture`, `ux-design`,
`map-systems`, `architecture-decision`.
**Review/validation** — validate against the effective tier; missing
*required* sections block, missing *optional* sections warn:
`design-review`, `review-all-gdds`, `architecture-review`, `consistency-check`,
`content-audit`.
**Gate enforcement** — `gate-check` uses a different artifact checklist per
stage per tier (the highest-visibility impact). Each gate's own checklist and
tier reductions live in `.claude/skills/gate-check/references/gate-<phase>.md`,
and `/gate-check` loads only the one gate it is running — that is the right
place to look, not `effects-map.md`.
**Planning/implementation** — adjust artifact prerequisites:
`create-epics`, `create-stories`, `dev-story`, `story-readiness`, `story-done`,
`qa-plan`, `regression-suite`.
**Support** — adjust "what's missing" expectations so optional docs aren't
flagged as gaps: `project-stage-detect`, `adopt`, `reverse-document`,
`propagate-design-change`, `help`.
---
## Workflow Change Mid-Project
When `workflow` changes via `/settings`, emit an informational note:
> "Workflow changed from [old] to [new]. Run `/content-audit` to see what's now
> required or extra. No automatic migration — existing files stay in place."
No documents are auto-deleted, auto-generated, or blocked. The setting only
affects *new* enforcement going forward.
---
## Companion Settings
These are separate settings that compose with `workflow`. The summaries below
are what a skill needs at runtime; `effects-map.md` carries the exhaustive
per-skill tables for spec authors, and is not worth loading to apply a knob.
> **All four below are fronted by `modes.rigor`** (`docs.density`,
> `modes.story_granularity`, `qa.level`, `team.size` — along with `workflow` itself,
> and `modes.review_mode`, for six fronted knobs total). One question at `/start`
> sets all of them; setting any explicitly overrides just that one and leaves its
> siblings on the rigor level. `team.size` and `modes.review_mode` are the two that
> also stay overridable from `project.local.yaml` (they are personal-experience
> knobs, not on-disk artifacts).
- **`docs.density`** (`terse` | `balanced` | `thorough`) — `workflow` controls
*which sections exist*; `density` controls *how deep each section goes*.
`rigor` sets the two together; override `docs.density` alone to get
`full` + `terse` = "all 8 sections, each compact."
- **`modes.story_granularity`** (`coarse` | `balanced` | `fine`) — how big
each story is and how many per epic/sprint.
- **`qa.level`** (`minimal` | `standard` | `full`) — what test evidence is
required to mark stories Done. Composes with `testing.strict`:
`qa.level` = is evidence required; `testing.strict` = do failures block.
- **`team.size`** (`individual` | `small` | `studio`) — which agents are active by
default. Different axis from workflow: workflow controls *what docs are
required*, team.size controls *which agents exist to make them*.