[Draft] Deckbuilder: create decks through a dedicated dialog, with a reworked hero picker - #64
Open
gjuillot wants to merge 5 commits into
Open
Conversation
The hero modal listed every printing of every hero as a separate unlabelled tile, in raw API order, so a hero reprinted across sets appeared several times scattered through the grid. Group printings by heroStableKey and show one named tile per hero, with the printings moved to an artwork strip below the grid — format rules key off the stable key, so the printing is purely cosmetic. The strip only appears when a hero has more than one printing, and reopening the picker lands on the hero and printing already on the deck. Drop the "all factions" tab in favour of per-faction browsing (Axiom by default), rendered as colour-coded faction tiles using the palette from altered.json. Also add EOLE and FUGUE to default_heroes.sets: the list was stale, which hid the heroes introduced in the latest set from the deckbuilder entirely (six heroes, one per faction). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A new deck used to drop the user straight into the builder, where the card search dominates and the deck's own fields (hero, name, format, visibility) sit in a side panel that is easy to miss — decks ended up saved under the "Unnamed" fallback. Reuse the hero picker as step 1 of a creation wizard, entered whenever the URL carries no ?id= and the builder is usable, so every entry point (deck list, empty state, direct URL, bookmark) goes through it. In wizard mode the modal is not an overlay on a working builder: the close button and the backdrop are equivalent to Cancel and return to the deck list. Also scroll the picked hero back into view when showing the artwork strip shortens the grid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Step 2 collects the deck's identity before the builder opens: name (required, empty), format (required, no preselection), visibility (private by default) and an optional description folded away behind a toggle. The chosen hero is recapped at the top with a Change button back to step 1. Format rows carry a one-line descriptor derived from the rules in altered.json rather than hardcoded copy, so they cannot drift from the data, plus the format's own colour as a left accent. The BGA tester format stays out. The wizard writes into the right-hand panel's controls, which remain the single source of truth for saving, then creates the deck. Autosave is suppressed while the wizard is open: picking a hero marks the deck dirty, and the 5s timer would otherwise create it under the "unnamed" fallback before step 2 was validated. If the API refuses a hero-only deck, the error is shown with an escape hatch into the builder instead of trapping the user in the wizard. Neither step dismisses on a backdrop click — closing abandons the deck, which is too destructive for a stray click. The picker keeps backdrop dismissal when it merely floats over a working builder. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ability Creation is a single form rather than a two-step flow: the hero becomes a field of the dialog, empty on open, and the picker opens over it as a sub-dialog. The hero row takes the artwork, name and faction of the hero once chosen, with the faction colour echoing the picker's faction buttons. Formats now declare BGA legality (bgalegal) and accept a bannedSets list for the set rotations to come, inert while empty. A hero is available in a format when at least one of its printings comes from a set that is both on BGA and allowed there, which gives three hero states: available in every BGA format, in some, or in none. Decks stay buildable in all cases — theory crafting is deliberate — but the dialog says so before the deck exists. Each format row resolves it, most blocking first: light red for a format BGA does not run, orange for a hero unusable there, green otherwise. The picker flags a hero unusable everywhere in orange and one usable only in some formats in yellow. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Board Game Arena runs its competitive Arena queue on one format at a time — Frontier today. The creation dialog now says which one, so a player building for competitive play does not have to look it up elsewhere. The pointer lives at the root of altered.json rather than on a format, since it is a single global choice that moves on BGA's schedule, not a property of any format: keeping it unique makes two formats flagged at once impossible, and the admin JSON editor can correct it without a deploy. The badge takes a colour of its own, outside the availability scale — it answers "is this the competitive format right now", not "can I play this on BGA" — and suppresses the redundant green pill on that row, while still letting a warning through. Formats are also ordered for the reader instead of following the reference data: Arena first, then the other BGA formats, then the unrestricted ones (Sandbox is a scratchpad, not something anyone plays), then the rest, each group alphabetical on the displayed name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Creating a deck drops the user straight into the full builder. Card search fills most
of the screen, and the deck's own fields — hero, name, format, visibility — sit in a
side panel that people don't notice. Decks end up saved under the "Unnamed" fallback,
in whatever format happened to be selected.
The hero picker compounds it. It lists every printing of every hero as a separate
unlabelled tile, in the order the API returns them, so a hero reprinted across sets
appears several times, scattered through the grid.
Creation dialog
A new deck now opens on a dialog that asks for what the deck needs before the builder
appears: hero, name, format, visibility, and an optional description folded away behind
a toggle. Nothing is preselected except visibility, which defaults to private.
The dialog is entered whenever a builder URL carries no
?id=, which covers everyentry point — deck list, empty state, guest button, direct URL, bookmark. The
?id=paths (edit, duplicate, import) are untouched.
The hero is a field of this form: clicking it opens the picker as a sub-dialog, and the
row then shows the hero's artwork, name and faction, with the faction colour echoing
the picker's faction buttons. Each format carries a one-line descriptor derived from the
rules in
altered.jsonrather than hardcoded copy, so the two cannot drift apart:The deck is created when the form is submitted, not before: the dialog writes into the
right-hand panel's controls, which stay the single source of truth for saving, and
autosave is held back until then. Closing is deliberate only — the close button and
Cancel, never a click on the backdrop, since leaving means abandoning the deck.
Hero picker
Printings are grouped by hero identity, so the grid holds one named tile per hero, and
the printing that lands on the deck is chosen deterministically. Browsing is per
faction, Axiom first, with the faction tiles taking the official colours from
altered.json.Board Game Arena availability
Some sets are absent from Board Game Arena, so some heroes cannot be played there, and
formats will start banning whole sets as rotations land. Those decks stay buildable —
theory crafting is deliberate — but the dialog says so before the deck exists.
Formats and sets both carry a
bgalegalflag; formats also accept abannedSetslist,inert while empty. A hero counts as available in a format when at least one of its
printings comes from a set that is both on BGA and allowed there, giving three hero
states: available in every BGA format, in some, or in none.
The format list resolves this per row, most blocking first:
Light red is reserved for the format level, the one refusal a user cannot work around
without changing format; orange marks what a different hero fixes. In the picker, a hero
unusable everywhere is flagged orange on its tile and one usable in only some formats
yellow, so the constraint is visible before the hero is even chosen.
BGA Arena format
Board Game Arena runs its competitive Arena queue on one format at a time — Frontier
today. The dialog flags it, so a player building for competitive play does not have to
look it up elsewhere. The pointer lives at the root of
altered.jsonrather than on aformat, since it is a single global choice that moves on BGA's schedule: keeping it
unique makes two flagged formats impossible, and the admin JSON editor can correct it
without a deploy.
The badge takes a colour of its own, outside the availability scale — it answers "is
this the competitive format right now", not "can I play this on BGA" — and suppresses
the redundant green pill on that row, while still letting a warning through.
Formats are ordered for the reader rather than following the reference data: Arena
first, then the other BGA formats, then the unrestricted ones, then the rest, each group
alphabetical on the displayed name.
Latest-set heroes were unreachable
default_heroes.setswas stale: the main setsEOLEandFUGUEwere missing from it.Six heroes — one per faction, including Sierra Navigatrice — did not appear in the
deckbuilder at all. Not a missing-artwork issue but missing content. Both sets are now
in the list.
Also fixed
grid-template-columns: repeat(n, 1fr)resolves its auto minimum to each cardimage's intrinsic width (~630px), which forced a single column. Now
minmax(0, 1fr).created the deck under the "Unnamed" fallback while the form was still being filled.
Known limitation
The hero banner in the right-hand panel does not reflect the printing stored on the
deck. It uses a dedicated wide-crop asset that the CDN does not have for promos, nor for
some BISE printings, hence a protective normalisation of the reference. Fixable with a
preload fallback chain; out of scope here.
Testing
No test suite covers this area. Verified by hand against the local development stack
with the real Keycloak and decks-api: creating a deck through the dialog, cancelling,
reopening the picker from an existing deck, and the BGA verdicts across all three hero
states. Hero grouping and availability were checked against live Cards API responses for
all six factions — 9 heroes unusable on BGA out of 36. Format ordering and descriptors
were verified against
altered.json. PHP and JavaScript both pass syntax checks.Set rotation itself is not shipped:
bannedSetsis empty everywhere, so theformat-dependent (yellow) state cannot occur in production yet. It was exercised locally
by filling that list, which is how the screenshots showing it were produced.