Step 2 rebuild — Skeleton sections
Concrete plan for restructuring index-step2.php to
host the four Skeleton-phase concepts (trackers, zones, win
conditions, effects vocabulary) as live
cross-referenced sections. Replaces today's
Resources / Life / Zones blocks with a unified, recipe-driven
editor that updates reactively as the schema grows.
Implementation status
What's shipped vs pending in this plan.
| Step | Subject | Status |
|---|---|---|
| F.0a | Schema store (js/step2-schema-store.js) + save endpoint (ajax-step2-save.php) |
shipped |
| F.0b | Step 2 page restructured with the Skeleton block + collapsible sections + status pill scaffolding | shipped |
| F.0c | Schema validator (js/step2-schema-validator.js) + status pill driver |
shipped |
| F.0d | Legacy migration on read | dropped — no active games exist; not needed |
| S.1 | Trackers section with 7 recipes (js/step2-section-trackers.js). Legacy Resources card hidden. |
shipped |
| S.2 | Zones section with 10 recipes (js/step2-section-zones.js). Legacy Game Zones card hidden. |
shipped |
| S.3 | Effects vocabulary multi-select with smart-disabled prerequisites. Saves to game_meta['enabled_mechanics'] (back-compat with existing AI-prompt code). Legacy "Enabled Mechanics" card hidden. |
shipped |
| S.4 | Win Conditions section with 6 recipes (combat, race_to_n, most_at_end, multi_source_score, weighted_score, last_standing) | shipped |
| P.1 | win_shape dropdown on Step 1 briefing |
dropped — the cross-reference architecture made the Step 1 dropdown unnecessary; recipe picker on Step 2 is self-sufficient. Briefing's free-text game_goal remains as the human label and feeds into AI autosuggest. |
A user can author trackers (life, resources, score, status, achievements) and zones (decks, hands, market, tableau) using recipe-based forms. All edits autosave; the validator surfaces errors and warnings as red/yellow badges; the status pill at the bottom summarises the schema state. The legacy Resources / Game Zones cards are hidden but their PHP scaffolding is left in place pending a downstream readers update (Steps 3/4/5 still read the legacy keys; trackers-only games will see empty resource state on those pages until those readers are migrated).
Several zone fields point at concepts authored in later
phases — constraints.accepts_types
(Card Types), auto_refill.trigger /
reset.trigger (Phases),
setup.start_filled_from (Decks). They're left
in the form deliberately. See
Appendix C.9
for the field-by-field map.
Why this needs its own plan
The roadmap's Phase 3 lists trackers (3.2), zones (3.3), and
win conditions (3.1) as separate steps. They are — but
they share UI surface (Step 2), share a client-side
architecture (the live schema store), and share a migration
concern (legacy game_parts /
game_meta['life_points'] reads). Building them
one at a time without a unified plan means redoing the
foundation three times.
This plan separates foundation (must ship first, locks the architecture) from sections (can ship in any order once the foundation is in place). The foundation is small and contained; the sections are the real feature work.
Architecture recap (live cross-references)
Step 2 is the game's live schema, not a sequential checklist. Sections cross-reference by id: adding a tracker makes it appear in every dropdown that lists trackers. The dependency order (trackers→zones→win conditions→effects) is suggestion, not constraint — users iterate in any order they want. See the conversation that landed this framing: For a game designer, plus the appendices A / B / C.
Three architectural commitments
-
One client-side store
(
window.gameSchema) holds the live shape. Sections render from it; saves write to it; cross-section dropdowns read from it. - Auto-save per section (debounced) replaces the "Save & Continue" button as the persistence mechanism. Continue becomes a navigation button only.
- Live validation, non-blocking. Broken cross-references (a win condition naming a deleted tracker) get red badges; user can keep editing. The "schema OK" status pill at the bottom of the page is the new "you're ready" signal.
Visual layout of the rebuilt Step 2
Foundation (must come first)
- Goal
- Lock the architecture before any section work. Without this, every section reinvents save / load / cross-reference / validation.
- Estimate
- ~3–5 days, focused.
- Deliverable
- Step 2 page renders with empty sections; the store + autosave + validator + migration all work end-to-end against a stub section.
Foundation steps
-
F.0a — Client-side schema store + autosave helper shippedWhat: A small JS module (
js/step2-schema-store.js) that holds the livegameSchemaobject, exposessaveSection(name, data)with debounced AJAX, and emits change events for reactive dropdowns.
API:SchemaStore.init(initialSchema)SchemaStore.get()— returns the live shapeSchemaStore.update(section, data)— updates + triggers saveSchemaStore.on(section, callback)— subscribe to changesSchemaStore.findReferencesTo(type, id)— returns sites referencing a given id
js/step2-schema-store.js(new),ajax-step2-save.php(new endpoint that accepts{section, data}, persists togame_meta).
Acceptance: with a stub section that writes{foo:"bar"}, hitting save in the browser persists to the DB; reload shows the value back; the store fires change events to subscribed dropdowns. -
F.0b — Step 2 page restructure (skeleton + collapsibles) shippedWhat: Replace the existing Step 2 layout with the four-section Skeleton hub above the existing Card Types / Families. Each section is a collapsible
<details>block with a stub body initially. Auto-save indicator + status pill at the bottom.
Files:index-step2.php(substantial rewrite of the form section, leaving Card Types / Families untouched).
Approach: keep all existing PHP state-loading logic intact; rebuild only the form HTML for the new sections. Old sections stay where they are.
Acceptance: page loads with four empty Skeleton sections + the existing Card Types / Families; existing data renders unchanged; the four stub sections are wired up to the store from F.0a. -
F.0c — Schema validator + reference finder shippedWhat: Two pieces, both in the same JS module:
SchemaValidator.validate(schema)— returns a list of{section, severity, message}issues. Severities:error(red badge) |warning(yellow). Non-blocking.SchemaStore.findReferencesTo(type, id)— walks the schema and returns places that reference a given tracker / zone / etc id. Used by delete confirmations.
js/step2-schema-validator.js(new).
Acceptance: after each save, validator runs and section badges update; deleting a referenced tracker shows a confirmation modal listing the referencing sites. -
F.0d — Legacy data migration on read droppedWhat: When the page loads and
game_meta['trackers']is missing, build it on the fly from existinggame_parts(part_type='resource')rows plusgame_meta['life_points']. Same pattern for zones (legacygame_meta['game_zones']blob → structured shape).
Files: a helperphp-includes/inc-step2-migrate.phpwith two functions:migrateLegacyTrackers($conn, $gameId): arrayandmigrateLegacyZones($conn, $gameId): array.
Approach: read-only migration. Don't write the new shape until the user actually saves a section through the new UI. That way existing games keep their legacy storage until they're touched, and we have a clear "user has migrated" signal.
Acceptance: a game created in the old UI loads correctly in the new UI with its resources / life / zones visible as trackers / zones; no DB writes happen on page load.
Sections (any order after foundation)
Once the foundation is shipped, the four Skeleton sections can be built independently. Each replaces a stub from F.0b with a real recipe-based form. They don't depend on each other for implementation — only at runtime through live cross-references, which the store handles.
Suggested order is by user value: trackers first (replaces a real bug today — Resources + Life duality), zones second (same recipe pattern, validates it generalises), effects third (small multi-select, no real complexity), win conditions last (depends on the JSON Logic evaluator from Roadmap step 3.1a, which can be built in parallel).
Section build steps
-
S.1 — Trackers section (Roadmap 3.2) shippedRead this first: Appendix B — Trackers (especially B.6 for UI / recipes).
What: Replace the stub Trackers section with: list view (rows showing icon + label + type/role badges + scope + edit/delete) + "+ Add tracker" button opening the recipe picker.
Recipes to ship: the seven from B.6 (life_points, generic_resource, victory_points, action_points, player_status, achievement_set, shared_threat) plus a "Custom" option for the full form.
v1 scope: the four types (counter / boolean / enum / set) and six roles. Defer derived trackers and per-card counters to v1.5 (Roadmap parking).
Acceptance: user can add a tracker via a recipe in 3 clicks, see it in the list, edit it inline, delete it (with reference-finder warning if it's referenced elsewhere). Saved togame_meta['trackers']via the store. -
S.2 — Zones section (Roadmap 3.3) shippedRead this first: Appendix C — Zones (especially C.5 for UI / recipes).
What: Same pattern as trackers: list + recipe picker + form. The 10 recipes from C.5 (personal_deck, hand, in_play, discard, shared_market, shared_deck, shared_pool, current_trick, won_tricks, tableau).
v1 scope: the four scopes / five visibilities / five orderings, the threeauto_refill.when_emptypolicies. Defer multi-zone selectors, hand-passing, per-card ownership / visibility in shared zones (all C.6 stretches) to v1.5.
Acceptance: user can add a zone via a recipe in 3 clicks. Saved togame_meta['game_zones']in the new structured shape (legacy reads still work via F.0d migration). -
S.3 — Effects vocabulary section shippedWhat: Multi-select checklist of effects from
assets/data/effects.json, grouped by mechanic family (deal_damage, gain_resource, draw_cards, etc). Each effect's checkbox is enabled only if the game has the trackers / zones it requires. Greyed-out effects show a tooltip explaining why ("requires a tracker with role: life").
Files: renders from$_game_defaults['effects']; saves togame_meta['enabled_effects']as an array ofeffect_keyvalues.
Smart filtering: a small inference step that reads each effect'sparamsand checks: do we have a tracker with the right role? a zone of the right scope? Disable the checkbox if not.
Acceptance: user can toggle effects on / off; disabled effects show why; the AI card-generation prompt later reads only the enabled set. -
S.4 — Win Conditions section (Roadmap 3.1) shippedPrerequisite: Roadmap step 3.1a (the JSON Logic evaluator,
inc-game-expressions.php) is already shipped. Can be built in parallel with foundation.
Read this first: Appendix A — Win conditions (A.0 architectural principle, A.5 recipes, A.7 worked examples).
What: Readswin_shapefrom Step 1, renders the shape-specific recipe form. Form dropdowns (tracker pickers, zone pickers) read live from the store — adding a tracker upstream immediately makes it selectable here.
v1 recipes: the six from A.9 v1 (combat, race_to_n, most_at_end, multi_source_score, weighted_score, last_standing). Defer cooperative / boss / team / hidden to later.
Output: JSON Logic stored ingame_meta['ending']per A.1 schema.
Natural-language preview: the form shows what the structured ending says in human terms ("Game ends when any player's Authority reaches 0. That player loses.") so the designer can sanity-check without reading JSON.
Acceptance: picking a recipe and filling its form generates a valid JSON Logic expression that the evaluator from 3.1a returns the expected boolean for, against a stub Game state.
Step 1 changes (parallel, small)
-
P.1 — Add
win_shapedropdown to Step 1 briefing droppedWhat: A single dropdown on the Step 1 form: "What kind of victory?" with the six recipe ids as options (combat, race_to_n, most_at_end, multi_source_score, weighted_score, last_standing). Free-textgame_goalstays as the human-readable label alongside.
Files:index.php(form),ajax-steps.php(save handler),game_meta['game_briefing']shape.
Why: Step 2's Win Conditions section (S.4) readswin_shapeto know which recipe form to render.
Acceptance: the dropdown saves; Step 2's Win Conditions section reads it correctly.
When to ship: any time before S.4. Could land in the same PR as F.0b or as its own tiny PR.
Definition of done
The Step 2 rebuild is complete when:
- A user can land on Step 2 with a fresh game and author trackers, zones, win conditions, and effects via recipe-based forms, in any order they choose.
- Existing games (legacy storage) load correctly without manual migration.
- The schema validator runs after each save; broken cross-references show inline; the bottom-of-page status pill reflects "schema valid" or "N issues".
- Card Types and Families still work as before, visually separated from the new Skeleton block.
- The simulator (when it exists, Roadmap 3.8+) can read
game_meta['trackers'],['game_zones'],['ending'],['enabled_effects']and build a runnable Game state from them.
Open Step 2, add a tracker via the life_points recipe, add a zone via the personal_deck recipe, scroll to Win Conditions, pick the combat recipe, and watch the tracker dropdown have life_points ready to pick — without any page reload between steps. That's the architecture working.
Mapping to the high-level roadmap
This plan is the implementation detail behind several Roadmap entries. The roadmap stays high-level; this plan is where the substeps live.
| Roadmap step | This plan covers |
|---|---|
| 3.1 — Structure win conditions | P.1 (Step 1 dropdown) + S.4 (Win Conditions section). Roadmap step 3.1a (the evaluator) is a prerequisite, not part of this plan. |
| 3.2 — Unify trackers | S.1 (Trackers section). |
| 3.3 — Promote zones | S.2 (Zones section). |
| (new — not in roadmap yet) | S.3 (Effects vocabulary section). Worth adding to the roadmap as 3.3.5 or absorbing into 3.3. |
| (implicit, foundational) | F.0a – F.0d (architecture). One-time cost; pays back across all four sections. |
The foundation work doesn't appear in the roadmap because it's architecture-not-feature. If you want it visible in the roadmap, add a 3.0 step ("Step 2 architecture: live schema store + autosave + validator") that links here.
This entire plan implements Phase B (Skeleton) from the designer order: the user-facing surface for trackers, zones, win conditions, and effects. Phase A (concept / briefing) is already shipped on Step 1; Phase C (anatomy: phases / actions / setup) and Phase D (content) come later. When this plan is done, the wizard can capture a complete game definition up to and including the skeleton — one short step away from being simulator-ready.