Pages  ›  Pieces

index-step2.php — Game Pieces (Step 2)

Where the briefing stops being prose and starts becoming building blocks. The briefing said what the game is; Step 2 asks what the game is made of — the resources, card archetypes, families, zones, and setup rules the rest of the wizard will fill.

1636 lines PHP + heavy inline JS 5 concerns on one page

What this page is, conceptually

If Step 1 was the creative brief, Step 2 is the parts list. The assistant (and the user, guided by it) chooses the concrete building blocks that will later be shaped into decks and cards:

  • Resources — what economies exist (Mana, Coins, Energy, Influence…)
  • Mechanics / effects — what the cards can do (deal damage, draw, counter…)
  • Card archetypes & behaviours — what kinds of cards exist (Unit, Structure, Event…) and how each behaves (Permanent, Instant, Targetable…)
  • Card families — optional faction/guild grouping that crosses archetype lines
  • Zones — where cards physically live during play (deck, hand, discard, battlefield, market…)
  • Setup rules — AI-generated starting configuration (shuffle, deal, place)

The mental model is engine-like: Step 2 defines the schema for the cards. Step 3 (decks) and Step 4 (cards) then populate that schema. Everything that lands on a physical card at print time — a stat, a cost, a keyword, a zone reference — traces back to a choice made on this page.

The user's journey on this page

  1. Arrival. User comes from Step 1 via the "Continue" button (or from My Games via the "Pieces" link). The page opens with a large, vertically-stacked form.
  2. Resources block. A two-column UI: available resources on the left, selected on the right. Ticking a checkbox "moves" the card across (animated). Each selected resource has a Customize disclosure with initial / max / regeneration knobs.
  3. Enabled mechanics. A checkbox list of effect types the cards can use (damage, draw, counter, etc.) — populated from $_game_defaults['mechanics-effect'].
  4. Archetype library. A table of card subtypes (Permanent Unit, Strike Unit, Instant Event…) with tick-boxes, per-row label / description / depicts overrides opened through a modal. Advanced users can create brand-new archetypes from a behaviour grid.
  5. Card families. Optional. Enable a checkbox and fill two family rows (name + description). IA Suggestions button fills both with AI-generated factions.
  6. Rarity. Greyed-out, permanently "Disabled" badge. A feature tease without a ship date.
  7. Zones. Checkbox list of default zones, each showing its JSON shape in a code-like <pre>. The raw JSON is visible to the end user.
  8. Rules. Empty container with a single "Reload Rules" button. Clicking it asks the server to generate a starting setup. No indication of what this does before clicking.
  9. Save. The single "Save" button at the bottom posts the entire form (resources, mechanics, archetypes, families, zones) to ajax-steps.php?method=full-form, then redirects to Step 3 (index-decks.php).

What's really captured (by intent)

Same approach as the onboarding doc: group by what question the AI needs answered, not by field name.

Economy — “What do players spend and manage?”

Resources, their initial / max values, regeneration policy.

Players pick from a seeded pool of resources (Mana, Coins, Life…). Each selected resource becomes a currency the card costs can reference later. The quantity of distinct resources is the strongest knob for how "economic" the game feels — a 1-resource game plays very differently from a 4-resource one.

Vocabulary — “What verbs can the cards use?”

Enabled mechanics / effects: Deal damage, Draw, Counter, Reveal, etc.

This is the set of primitive actions the AI may combine when it writes individual card rules. Limiting this set is a design lever — a tight vocabulary produces a tighter-feeling game.

Taxonomy — “What kinds of cards exist, and how do they behave?”

Archetypes (Unit / Structure / Event / Item / Location) with parent-child subtypes and behaviour flags.

The richest data model on the page. Each archetype (e.g. unit) has a set of fields (cost, attack, health, effects) and a list of allowed behaviours (Permanent, Strike). Sub-types specialise the parent by forcing behaviours on — e.g. a "Strike Unit" is a Unit with Strike behaviour permanently enabled.

Conceptually this is a mixin system: archetypes are classes, behaviours are traits, subtypes are concrete configurations. Users can define entirely new archetypes via a modal — which is impressive and heavy (see "What's rough").

Identity — “Which factions / guilds span the card set?”

Card families. Optional. Capped at 2 in the current beta.

Families are a thematic grouping that cuts across archetypes — all four members of the "Red Dragons" family can be any mix of Unit / Structure / Event, sharing lore and synergies. This is where the game's personality gets encoded once the mechanical bones are set.

Topology — “Where do cards live during play?”

Zones: deck, hand, discard, trash, market, battlefield, etc.

Zones define the physical layout of gameplay. Each zone has an owner (player / shared), visibility rules, and ordering semantics (stack vs. unordered). The rest of the engine (move/shuffle actions, initial hand size, setup) refers back to zones by ID.

Choreography — “How does a game start?”

Rules: AI-generated JSON setup actions (move N cards from X to Y, shuffle Z).

The only generative section on the page — nothing is pre-filled. Clicking "Reload Rules" asks the AI to propose a setup sequence based on everything above. This is the product's first moment of pure "the assistant does the work for you".

What happens when they hit Save

  1. JS collects the selected zones and dumps them into a hidden zones_json textarea (because the zone JSONs live in <pre> blocks, not form fields).
  2. SweetAlert spinner modal appears.
  3. Form posts to ajax-steps.php?method=full-form.
  4. The server:
    • walks game_resources[selected_ids], copying each chosen resource's content into an array of final resources, with custom settings applied;
    • persists card_types overrides, custom_card_subtypes, card_families, enabled_mechanics, card_behaviours, and game_zones into meta;
    • keeps the briefing untouched.
  5. Returns { success, gameUniqueId }; the user is offered a "Continue" button that goes to index-decks.php.

ALT-clicking Save opens the same POST in a new tab with is_debug=1 so the response is human-readable. Same pattern as Step 1.

How the pieces feed the rest of the app

Step 2 writes into several meta keys — each is a contract with a specific downstream consumer:

Meta keyRead byUsed for
card_types + custom_card_subtypesStep 3 (decks), Step 4 (cards)Deciding what fields a card has, validating AI-generated cards against their archetype
enabled_mechanicsStep 4 (card autogenerate)Constraining which verbs the AI can use when writing card rules
card_behavioursStep 4 + renderingKnowing whether a card is Permanent, Instant, etc.
card_familiesStep 3 + Step 4Distributing cards across families and tagging them thematically
game_zonesRules generator, Step 4 play-testTargets for move/shuffle actions, validating card references
Selected resources (game_parts)Card generation, card renderingCard costs, resource icons on each card
Rules / setup JSONFuture play-simulation stepGame state initialisation

The amount of downstream dependence is the main reason Step 2 feels heavy: every box ticked here constrains what Steps 3 and 4 can produce.

What works well, conceptually

  • The archetype-with-behaviours model is powerful. Splitting "what kind of thing is this card?" (archetype) from "how does it act mechanically?" (behaviour) lets one archetype spawn many subtypes without duplication. This is the right shape.
  • Two-column resource UI. Available → Selected is a direct visual metaphor for the actual decision ("I'm choosing from a menu"). Better than a flat checklist.
  • Simple vs. Expert modes. Presets ("Permanent Unit", "Strike Unit") hide the behaviour grid from novices; expert mode reveals it. Classic progressive disclosure.
  • Custom archetype modal. The option to say "I want a 'Guardian' archetype that's like a Unit but always Targetable" is a strong power-user feature. The data model supports it cleanly.
  • Data-driven defaults. Card types, zones, effects, behaviours all live in JSON under assets/data/ with schema siblings. Low friction to extend.
  • Rules as a generative surface. The "Reload Rules" button is the product's first moment where the assistant does meaningful design work end-to-end. Great proof-of-value.
  • IA Suggestions is reused. The same click handler from Step 1 works here for families. Good sign of a reusable primitive.

What's rough, conceptually

The whole ontology is a fantasy combat deck-builder

Look at the defaults: archetypes are Unit / Structure / Event / Item / Location; behaviours are Permanent / Strike / Targetable / Outpost / Instant / Lingering; default resources include Mana and Life Points; default zones include Battlefield. This is Magic / Star Realms DNA.

A user who picked Trick-Taking at Step 1 arrives here and is asked to pick between Units and Structures. A Set Collection user doesn't want any of this — they want suits, ranks, collectible sets. Even though I fixed the opening AI prompt so it talks about trick-taking, the data model this page exposes still hard-codes one genre. That's the single biggest conceptual gap in the codebase.

Five concerns on one page, no structure

Resources / mechanics / archetypes / families / zones / rules all live in one long vertical scroll with no tabs, no sections, no completeness meter. Step 1 carefully grouped Core / Flavor / Business; Step 2 just piles six sections on top of each other with inconsistent headings. Users have no sense of how far through they are.

Naming collisions blur the model

“Mechanic” at Step 1 = the top-level genre (Deck-Builder, Trick-Taking…). “Mechanic” at Step 2 = a per-card effect (Deal damage, Counter…). Same word, unrelated meanings, both in the UI. Users will conflate them.

Same with archetype, card type, and subtype: the code uses them interchangeably in places and distinctly in others. The glossary is inside people's heads.

Permanent “Disabled” placeholders leak through the UI

The Rarity card renders with a greyed checkbox and a Disabled-style badge. Card Families carries a "beta — limited to two" disclaimer. Step 1 had "team play (coming soon)". Each one is a little UX smell that says "this is a WIP product". If they're not shipping, remove them; if they are, give them a date.

Zone JSON is exposed as raw code

Each zone is shown as a pretty-printed JSON blob in a <pre> tag. That's readable to engineers and intimidating to everyone else. Zones are fundamental (every gameplay event moves a card between them) but the UI treats them as a configuration file for the user to stare at.

Rules appears empty until you click

The Rules panel loads blank, with a single "Reload Rules" button and no explanation. It is the most magical thing on the page (AI-generates setup rules for your game) but presents as the most inert. A user might never click it.

No guardrails on "how many is too many"

Users can pick 7 resources, enable 12 effects, tick 8 archetypes, define 2 families, and generate rules for a game that is mechanically unplayable. Nothing in the UI pushes back. The completeness meter from Step 1 was coaching in both directions ("you need this" / "you've given enough"); Step 2 has no such coach.

Save is all-or-nothing

No autosave, no save-and-stay, no per-section save. Drafting a game in Step 2 means keeping the browser tab open or losing everything. Given how many decisions are captured here, that's high-stakes for a creative tool.

No "here's the shape of your game" summary

After clicking Save, the user is kicked straight to Step 3. There's no moment where the page says "You've defined a 2-resource engine-building game with 3 archetypes (Unit, Event, Item), 4 zones, and no families. Ready to build decks?". That missing checkpoint is where the assistant should reflect what it understood — same gap we flagged on Step 1.

Structural smell: ~1636 lines, mostly mixed PHP + inline JS

Same shape as index.php. The form body is ~450 lines, the JS tail is ~900. Most of the JS is the shared IA-Suggestions handler + response renderers, duplicated verbatim from Step 1. A js/shared-ia-suggestions.js would retire ~400 lines from each page immediately.

Conceptual suggestions

1. Split Step 2 into sub-steps or tabs

Resources / Mechanics / Archetypes / Families / Zones / Rules are cognitively distinct and have different levels of depth. Tabs (top of the page) or a sub-wizard (Continue-style) would both work — either reduces overwhelm and lets the completeness idea from Step 1 come back.

2. Make Step 2 mechanic-aware

The mechanic chosen at Step 1 should shape this page:

  • Trick-Taking → hide Resources, hide Archetypes, surface a Suits/Ranks builder instead.
  • Set Collection → hide combat behaviours, surface a "collectable sets" definition.
  • Draft → collapse Families, surface "pack size / draft direction" instead.
  • Deck-Builder → everything as today.

This is the concrete unlock for the broader product goal ("any card-based board game"). Without it, the data model is still a deck-builder engine with a marketing wrapper.

3. Replace zone JSON with a zone visualiser

Zones are spatial — they deserve a spatial UI. A simple board-mock with labelled rectangles (Deck, Hand, Discard, Battlefield, Market) per player would land the concept in two seconds, where JSON currently takes thirty. The JSON can stay as an "Expert" toggle.

4. Introduce a "Game Shape" preview

Live summary in the page footer, updating as the user clicks: "2 resources · 3 archetypes (Unit, Event, Item) · 2 families · 5 zones · rules: not generated yet". Doubles as the missing completeness coach.

5. Rename to kill the "mechanic" collision

Step 2's "Enabled mechanics" should be renamed — "Card Effects", "Card Verbs", or "Capabilities". "Mechanic" stays at Step 1 as the genre choice.

6. Make Rules less magical, more inviting

Swap the solitary "Reload Rules" button for a small explainer + a button that says "Generate a starting setup for this game →". After generation, show the setup as a checklist of actions ("Shuffle player deck", "Deal 5 cards to each player") not a JSON blob.

7. Delete permanent "Disabled" placeholders

Rarity, team play, the "limited to 2 families" copy — either ship them or remove them. Persistent WIP markers erode trust.

8. Extract the shared IA-Suggestions JS

The ~400 lines of suggestion-rendering JS are duplicated between index.php and index-step2.php. One js/shared/ia-suggestions.js module removes it from both. Not conceptual, but shipping every other improvement on top of duplicated code is a tax.

TODOs

Lighter than the onboarding doc — this page is earlier in the analysis lifecycle.

Conceptual, in priority order

  • Make Step 2 mechanic-aware
    Conditional sections based on game_briefing.mechanic. Deck-Builder → current UI; others hide / replace sections. Biggest concrete lever for the "any card-based game" thesis.
  • Break the page into tabs or sub-steps
    Resources / Mechanics / Archetypes / Families / Zones / Rules. Each with its own Save and completeness signal.
  • Rename Step 2 "Enabled mechanics" → "Card Effects" (or similar)
    Removes the "mechanic" terminology collision with Step 1.
  • Visual zone layout instead of JSON <pre>
    Labelled rectangles on a player-mat mock. JSON available behind an "Advanced" toggle. See the full zones schema review in the schema doc — deferred with game mechanics.
  • Live "game shape" summary + completeness indicator
    Footer strip that updates as choices change. Doubles as the "here's what I understood" checkpoint before Step 3.
  • Reframe "Reload Rules" as a first-class generate action
    Explainer text + explicit button. Render output as a checklist, not JSON.
  • Remove permanent “Disabled” placeholders
    Rarity card, team-play checkbox, "limited to 2 families" copy. Ship or cut.

Minor / cleanup

  • Extract shared IA-Suggestions JS into a module
    Same ~400 lines are duplicated in index.php and index-step2.php. js/shared/ia-suggestions.js would cover both.
  • Replace FILTER_SANITIZE_STRING
    Line 27. Deprecated in PHP 8.1.
  • Clean up leftover .step-1 / .step-2 / .step-3 wrapper classes
    Holdover from the old single-page wizard. Now misleading (Resources wraps in .step-2, mechanics wraps in .step-3, zones also in .step-3).
  • Sort out the orphaned .use-this-resource handler
    POSTs to method=add-resource; confirm whether that case is wired up or dead.

Open questions for the product

  • Is the archetype / behaviour model meant to stay combat-centric, or do we generalise it? If we generalise, what's the replacement data model?
  • Does "Mechanic" (Step 1) imply the set of archetypes, or are they independent knobs?
  • Should Step 2 be a wizard, tabs, or stay a single long form?
  • Is the Rules generator intended to be the main authoring surface for setup, or a starting point the user then edits?
  • Card families capped at 2 — is that a beta limitation or a product decision?