Skip to content

A locked tile names the card it is hiding - #482

Merged
maximsan merged 2 commits into
mainfrom
feat/collectible-tile
Sep 2, 2026
Merged

A locked tile names the card it is hiding#482
maximsan merged 2 commits into
mainfrom
feat/collectible-tile

Conversation

@maximsan

@maximsan maximsan commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Closes #434, whose body now carries the two corrections below and the artwork ruling.

Needs your sign-off

The module tag under each tile title is gone. #434 ticked that line as already matching the design — it does not: the prototype's tile renders only cc-title, and the CSS has no cc-tag (screens.jsx:2447, index.html:704). ADR-0009 backs removing it, and #385 removed the same line from the card sheet for the same reason, but it is a user-visible change the ticket said was fine as it was.

Two things #434 got wrong about the design

The locked silhouettes are unreachable. LockedSilhouette branches on 'silhouette' and 'dot', and is called with card.kindbotanical, burrs, roastcurve, never either. Every real locked tile falls through to the mono ?. Porting three shapes would have ported two the design never draws. Verified independently in review, against both the prototype and the shipped bank.

What review should look at

The offer ring marked one card where the design marks every one. challengeOpen (screens.jsx:1621) is earned, has a challenge, unbrewed; I had wired it to the single active challenge, which rings at most one tile and blinks off when its window lapses. Fixed in the second commit — and my own test had pinned the narrow behaviour.

I rewrote a border the repo already had. DashedRoundedBorder exists; mine broke the ShapeBorder contract four ways no test would catch (copyWith dropping its side, scale returning this, no ==, and the stroke half outside the shape). Deleted.

The tint table is generated from CARD_TINT, not transcribed — 38 entries over eight hues at 8–12%, checked entry for entry in review.

What defers

The artwork is #480, and it is not an art job. All thirty-seven CardArt* components are static SVG taking no props, and tool/extract_icons.js already bridges prototype SVG into bundled assets. Nobody has to draw anything; the extractor needs sentinels for the illustration palette. The VISUAL GUIDE top line is recorded too — no shipped collectible has that kind.

Checks

format, analyze, metrics clean; 2214 tests. Rebased onto the ADR renumbering pass.

The tile drew `???`. It draws `03 / 37` now — the card's place in the whole
catalogue, so a gap is a card the learner can go and earn rather than an
anonymous blank. With #396 leaving exactly one locked tile on screen, that
tile is always the next one.

Earned tiles gained the same line and their kind's own wash. The tint table
is **generated from `CARD_TINT`** rather than transcribed: thirty-eight
entries over eight hues at 8–12%, so a kind the design washes green cannot
drift red here. A brewed Coffee Challenge stamps the corner; a waiting one
rings it, dashed.

**Two things #434 said about the design were wrong.**

*The silhouettes are unreachable.* `LockedSilhouette` branches on
`'silhouette'` and `'dot'`, and is called with `card.kind` — which is
`botanical`, `burrs`, `roastcurve`, never either. Every real card falls
through to the mono `?`. Porting three shapes would have ported two the
design never renders.

*The tile prints no tag.* The ticket lists "title, then the tag" on both
sides and marks it as agreeing; the prototype draws only `cc-title`, and
the CSS has no `cc-tag`. So the module line goes, as it went from the sheet
in #385 — the card already says what it is. The test that pinned it now
makes the stronger claim: no module name anywhere, since one could only be
a section header.

`CoffeeCardModel` carries its `kind` — the collectible's own key, which the
assembly was dropping in favour of the module's icon, and which the tint is
keyed by. `cardsGridItems` hands each tile its catalogue place, because the
number is where the card sits in the set and not in the grid.

**The artwork is #480, and it is not an art job.** All thirty-seven
`CardArt*` components are static SVG taking no props, and the repo already
extracts the icon family from the prototype rather than redrawing it. That
ticket says so; the mark stands in here meanwhile.
…gn marks every one (#434)

**The offer ring was far too narrow.** The design's `challengeOpen`
(`screens.jsx:1621`) is *earned, has a challenge, has not brewed it* — so a
learner sees every card that still owes them a brew. I had wired it to the
single challenge the lifecycle happens to have active, which rings at most
one tile and blinks off when its window lapses. It reads the bank now, and
drops the `activeChallengeProvider` dependency entirely. My test had pinned
the narrow behaviour, so the fix failed it: it described what I built
rather than what the design asks for.

**I rewrote a border the repo already had.** `DashedRoundedBorder` exists
for exactly this. Mine broke the `ShapeBorder` contract four ways that no
test would have caught: `copyWith` dropped the side it was handed,
`scale(t)` returned `this` so any lerp jumped, no `==`/`hashCode` so the
decoration never compared equal and the box repainted every rebuild, and
the ring stroked *on* the radius, putting half the line outside the shape.
The design writes a bare `1px dashed` and names no pattern, so the corner
takes the app's own dash rhythm rather than a second invented one.

**A layering inversion:** `challenges/domain` imported a `cards/presentation`
file to learn `CardChallengeState`. The enum is a domain fact — none, open,
tried — and now lives in the challenges domain, with presentation importing
it.

`total` folds into `PlacedCard` instead of travelling beside it to every
call site, and `formatCardPlace` moves to `cards_grid.dart` with the rest of
the set arithmetic, where a unit test reaches it without pumping a widget.

Both design claims this branch rests on were verified independently: the
silhouette branches really are unreachable, and the design's tile really
prints no tag. The generated tint table was checked entry for entry.

Recorded, not silently dropped: the `VISUAL GUIDE` top line replaces
`CARD NN` for a kind no shipped collectible has.
@maximsan
maximsan merged commit 2debfd4 into main Sep 2, 2026
6 checks passed
@maximsan
maximsan deleted the feat/collectible-tile branch September 2, 2026 20:38
@maximsan maximsan mentioned this pull request Sep 2, 2026
27 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The collectible tile: locked shows '???' where the design shows its place in the set

1 participant