You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The /reveals page (shown only during a set's reveal season, gated by VITE_IS_REVEAL_SEASON + RevealsGate) is currently a hero + per-franchise card grids. For Set 13 — "Attack of the Vine!" we want a richer, season-long page whose primary attraction is six per-color completion trackers (34 cards each, 204 total) that visibly fill and brighten as cards reveal, with the franchises and new mechanics as secondary draws.
A high-fidelity design was produced in Claude Design (desktop + mobile handoffs in apps/web/reveals page redesign/). This issue recreates that design inside the existing React codebase using real reveal data, preserving the current franchise-grid experience as a second, toggleable view (the new tracker view is the default). Success: a visitor lands on an immersive tracker showing all six inks' progress, can open any ink's diamond mosaic of real card art, read the new-franchises and "new this set" mechanic spotlights, and toggle to the classic franchise grid — all responsive from ~360px to desktop.
Prerequisites
Write access to Doberjohn/inkweave; work on a feature/<n>-reveals-redesign branch (source edits blocked on master by the branch-verification hook)
VITE_IS_REVEAL_SEASON=true in apps/web/.env.local (else /reveals redirects home)
Familiarity with the two handoff specs: apps/web/reveals page redesign/README.md (desktop) and .../design_handoff_reveals_page_mobile/README.md (mobile deltas)
Knowledge that preview cards use color/subtypes/fullText/rarity field names (vs engine ink/classifications/text)
Implementation Steps
Phase 0 — Data plumbing (engine + loader)
Step 1: Surface rarity on the card type
Add the field the diamond's rarity breakdown + per-card gem need.
Then carry it through the web loader (apps/web/src/features/cards/loader.ts) where preview cards are normalized, and confirm classifications (from preview subtypes) and the per-card cost/color already flow through.
Verify:pnpm build:engine succeeds; a loaded Set 13 card has rarity and classifications populated.
useRevealProgress replaces the prototype's fake revealPct: group revealed Set 13 cards by ink (split dual-ink), tally per-rarity from real card.rarity, and compute a deterministic scattered slot order per ink (stable hash seeded by ink key).
Verify: unit test asserts Σ per-ink counts === totalRevealed and rarity tallies sum correctly against fixture cards.
Step 4: Build ProgressRing, RarityGem, CardSlot under apps/web/src/features/reveals/, each reading theme.INK_COLORS and accepting size props (so desktop/mobile differ by token, not branching). RarityGem uses the clip-path shapes (circle/square/triangle/diamond/pentagon/hexagon + rainbow conic). CardSlot renders unrevealed (ink watermark placeholder) vs revealed (real AVIF via smallImageUrl + cost pip + rarity gem), and onClick opens the card modal via CardModalContext for revealed slots.
Verify: Storybook stories render each at desktop + mobile sizes; pnpm dev shows a revealed slot opening the modal on click.
Phase 2 — Tracker view
Step 5: RevealHero (eyebrow, Tinos title, intro, countdown + revealed stat panels, OverallProgressBar with six ink segments) — countdown/date from useCountdown/revealDates, totals from useRevealProgress.
Step 7: InkBoard (header with ink badge + count + "COLOR COMPLETE" ribbon at 34; CardMosaic diamond [4,6,7,7,6,4]; RarityBreakdown grid). Glow + bloom scale with fill = count/34.
Verify:pnpm dev → /reveals: selecting an ink swaps the board; revealed cards show real art; counts match useRevealProgress; screenshot at desktop width.
Phase 3 — Secondary sections
Step 8: NewFranchises — 3 cards using existing public/art/franchises/{up,monsters-inc,turning-red}.webp as the 210px/150px key-art regions, with ink-tinted bloom from the franchise→ink map.
Step 9: WhatsNewSection — curated content file apps/web/src/features/reveals/setSpotlights.ts driving 3 "new mechanic" cards (🌿 Vine & Floodborn Matters · 👥 Team Characters/Combo & Duo Shift · ⏳ Temporary Shift) + 2 "tribe spotlight" cards (🐼 Red Panda · 🍯 Hunny), each with icon, ★ NEW badge (Vineling/Team/Temporary Shift only), one-line summary, example card names. Static display in v1.
Verify: counts shown match data (Vineling 5, Team 11, Red Panda 7, Hunny 6, Temporary Shift 3).
Phase 4 — Two-view toggle + integration
Step 10: ViewToggle + RevealsPage orchestration. New "Tracker" view (Phases 2-3) is the default; "Franchises" view reuses the existing FranchiseTier + useRevealCards grid unchanged. Keep CompactHeader and reuse EtherealBackground.
Step 11: Apply the mobile delta table (hero 88→42px, trackers→2-col, ring 82→64, slots 58×80→46×64 gaps 7→5, rarity→3-col, franchises/mechanics→single column, drop release-date cell). Mosaic widest row = 7×46+6×5 = 352px must fit 390px with no horizontal page scroll (only the mosaic rail may scroll).
Verify: resize to 390px → no horizontal page scroll; screenshot mobile.
Phase 6 — Stories + tests
Step 12: A .stories.tsx for every new component (story-coverage gate blocks push otherwise); focused unit tests for useRevealProgress, rarity, scatter order. Run full gate.
Verify:pnpm check:stories, pnpm test, pnpm build all green.
/reveals defaults to the new Tracker view; a toggle switches to the existing franchise-grid view and back
Six ink trackers render real per-ink revealed counts out of 34; selecting one swaps the featured board (default Amethyst)
Diamond mosaic shows revealed slots with real card art + cost pip + real-rarity gem; unrevealed slots show the placeholder watermark; clicking a revealed slot opens the card modal
Rarity breakdown uses each card's real rarity (not the prototype's rank-faked rarity)
Hero stats + overall bar derive from the same per-ink counts
New-franchises section uses real art/franchises/*.webp with the franchise→ink bloom
"New this set" band shows the 3 mechanics + 2 tribe spotlights with correct counts and ★-new badges
Fully responsive ~360–430px and desktop; no horizontal page scroll on mobile
CompactHeader retained; EtherealBackground reused
Every new component has a story; pnpm test + pnpm build pass
Existing franchise-grid view (FranchiseTier/useRevealCards) preserved, not deleted
Rollback
Phase 0 (engine/loader):git revert the type/loader commit → rarity optional, no consumer breaks (additive field).
Tracker view / sections: new components are additive; revert their commits → no effect on other pages.
Toggle/integration (RevealsPage.tsx): revert to prior RevealsPage → page returns to franchise-only layout; or set the default-view constant back to 'franchises' to ship the toggle with the old view as default without a revert.
Kill switch: set VITE_IS_REVEAL_SEASON=false (Vercel env) → /reveals redirects home, hiding the feature entirely while a fix is prepared.
Full rollback: revert the feature PR (squash commit) → page restored to pre-redesign state; rarity field revert optional (harmless if left).
Current impl: apps/web/src/pages/RevealsPage.tsx, apps/web/src/features/reveals/{Hero,FranchiseTier,franchise,revealDates,useRevealCards,useRevealPhase,useCountdown}.{tsx,ts}
Context
The
/revealspage (shown only during a set's reveal season, gated byVITE_IS_REVEAL_SEASON+RevealsGate) is currently a hero + per-franchise card grids. For Set 13 — "Attack of the Vine!" we want a richer, season-long page whose primary attraction is six per-color completion trackers (34 cards each, 204 total) that visibly fill and brighten as cards reveal, with the franchises and new mechanics as secondary draws.A high-fidelity design was produced in Claude Design (desktop + mobile handoffs in
apps/web/reveals page redesign/). This issue recreates that design inside the existing React codebase using real reveal data, preserving the current franchise-grid experience as a second, toggleable view (the new tracker view is the default). Success: a visitor lands on an immersive tracker showing all six inks' progress, can open any ink's diamond mosaic of real card art, read the new-franchises and "new this set" mechanic spotlights, and toggle to the classic franchise grid — all responsive from ~360px to desktop.Prerequisites
Doberjohn/inkweave; work on afeature/<n>-reveals-redesignbranch (source edits blocked onmasterby the branch-verification hook)VITE_IS_REVEAL_SEASON=trueinapps/web/.env.local(else/revealsredirects home)apps/web/public/card-images-preview/13*.avif, committed in3380dcbfor Set 13 reveal season, preview-card parser, and Temporary Shift support #388)pnpm installdone; Playwright browsers installed for pre-push E2Eapps/web/reveals page redesign/README.md(desktop) and.../design_handoff_reveals_page_mobile/README.md(mobile deltas)color/subtypes/fullText/rarityfield names (vs engineink/classifications/text)Implementation Steps
Phase 0 — Data plumbing (engine + loader)
Step 1: Surface
rarityon the card typeAdd the field the diamond's rarity breakdown + per-card gem need.
Then carry it through the web loader (
apps/web/src/features/cards/loader.ts) where preview cards are normalized, and confirmclassifications(from previewsubtypes) and the per-cardcost/coloralready flow through.Verify:
pnpm build:enginesucceeds; a loaded Set 13 card hasrarityandclassificationspopulated.Step 2: Reveal-progress + set-composition logic
useRevealProgressreplaces the prototype's fakerevealPct: group revealed Set 13 cards by ink (split dual-ink), tally per-rarity from realcard.rarity, and compute a deterministic scattered slot order per ink (stable hash seeded by ink key).Verify: unit test asserts
Σ per-ink counts === totalRevealedand rarity tallies sum correctly against fixture cards.Step 3: Franchise→ink association
Verify:
pnpm test:webfor franchise tests passes.Phase 1 — Shared visual primitives
Step 4: Build
ProgressRing,RarityGem,CardSlotunderapps/web/src/features/reveals/, each readingtheme.INK_COLORSand accepting size props (so desktop/mobile differ by token, not branching).RarityGemuses the clip-path shapes (circle/square/triangle/diamond/pentagon/hexagon + rainbow conic).CardSlotrenders unrevealed (ink watermark placeholder) vs revealed (real AVIF viasmallImageUrl+ cost pip + rarity gem), andonClickopens the card modal viaCardModalContextfor revealed slots.Verify: Storybook stories render each at desktop + mobile sizes;
pnpm devshows a revealed slot opening the modal on click.Phase 2 — Tracker view
Step 5:
RevealHero(eyebrow, Tinos title, intro, countdown + revealed stat panels,OverallProgressBarwith six ink segments) — countdown/date fromuseCountdown/revealDates, totals fromuseRevealProgress.Step 6:
InkTrackerStrip+InkTrackerTile(6 tiles,ProgressRing+ name + count;auto-fit minmax(150px)desktop / fixed 2-col mobile; selected state glow; default selected = Amethyst).Step 7:
InkBoard(header with ink badge + count + "COLOR COMPLETE" ribbon at 34;CardMosaicdiamond[4,6,7,7,6,4];RarityBreakdowngrid). Glow + bloom scale withfill = count/34.Verify:
pnpm dev→/reveals: selecting an ink swaps the board; revealed cards show real art; counts matchuseRevealProgress; screenshot at desktop width.Phase 3 — Secondary sections
Step 8:
NewFranchises— 3 cards using existingpublic/art/franchises/{up,monsters-inc,turning-red}.webpas the 210px/150px key-art regions, with ink-tinted bloom from the franchise→ink map.Step 9:
WhatsNewSection— curated content fileapps/web/src/features/reveals/setSpotlights.tsdriving 3 "new mechanic" cards (🌿 Vine & Floodborn Matters · 👥 Team Characters/Combo & Duo Shift · ⏳ Temporary Shift) + 2 "tribe spotlight" cards (🐼 Red Panda · 🍯 Hunny), each with icon,★ NEWbadge (Vineling/Team/Temporary Shift only), one-line summary, example card names. Static display in v1.Verify: counts shown match data (Vineling 5, Team 11, Red Panda 7, Hunny 6, Temporary Shift 3).
Phase 4 — Two-view toggle + integration
Step 10:
ViewToggle+RevealsPageorchestration. New "Tracker" view (Phases 2-3) is the default; "Franchises" view reuses the existingFranchiseTier+useRevealCardsgrid unchanged. KeepCompactHeaderand reuseEtherealBackground.Verify: toggling swaps views without remount errors; default load shows Tracker.
Phase 5 — Responsive
Step 11: Apply the mobile delta table (hero 88→42px, trackers→2-col, ring 82→64, slots 58×80→46×64 gaps 7→5, rarity→3-col, franchises/mechanics→single column, drop release-date cell). Mosaic widest row = 7×46+6×5 = 352px must fit 390px with no horizontal page scroll (only the mosaic rail may scroll).
Verify: resize to 390px → no horizontal page scroll; screenshot mobile.
Phase 6 — Stories + tests
Step 12: A
.stories.tsxfor every new component (story-coverage gate blocks push otherwise); focused unit tests foruseRevealProgress,rarity, scatter order. Run full gate.Verify:
pnpm check:stories,pnpm test,pnpm buildall green.Files Affected
Created
apps/web/src/features/reveals/setComposition.tsapps/web/src/features/reveals/rarity.tsapps/web/src/features/reveals/useRevealProgress.tsapps/web/src/features/reveals/setSpotlights.tsapps/web/src/features/reveals/ProgressRing.tsx(+ stories)apps/web/src/features/reveals/RarityGem.tsx(+ stories)apps/web/src/features/reveals/CardSlot.tsx(+ stories)apps/web/src/features/reveals/CardMosaic.tsx(+ stories)[4,6,7,7,6,4]mosaicapps/web/src/features/reveals/InkBoard.tsx(+ stories)apps/web/src/features/reveals/InkTrackerStrip.tsx/InkTrackerTile.tsx(+ stories)apps/web/src/features/reveals/OverallProgressBar.tsx(+ stories)apps/web/src/features/reveals/RevealHero.tsx(+ stories)apps/web/src/features/reveals/NewFranchises.tsx(+ stories)apps/web/src/features/reveals/WhatsNewSection.tsx(+ stories)apps/web/src/features/reveals/ViewToggle.tsx(+ stories)Modified
packages/synergy-engine/src/types/card.tsrarity?: stringtoLorcanaCardapps/web/src/features/cards/loader.tsraritythrough; confirmclassifications/cost/colorapps/web/src/features/reveals/franchise.tsinkper franchise (up→sapphire, monsters-inc→emerald, turning-red→ruby)apps/web/src/pages/RevealsPage.tsxEtherealBackground/CompactHeaderapps/web/src/features/reveals/index.tsCLAUDE.md(design-system mirror section)Testing / Verification
Data
pnpm build:engine→ succeeds withrarityonLorcanaCarduseRevealProgressunit test → per-ink counts sum to total; rarity tallies correctTracker view (desktop)
/revealsdefaults to Tracker view → six rings show real per-ink counts /34Sections
Toggle + responsive
pnpm check:stories,pnpm test,pnpm buildgreen; pre-push E2E passesAcceptance Criteria
/revealsdefaults to the new Tracker view; a toggle switches to the existing franchise-grid view and backrarity(not the prototype's rank-faked rarity)art/franchises/*.webpwith the franchise→ink bloomCompactHeaderretained;EtherealBackgroundreusedpnpm test+pnpm buildpassFranchiseTier/useRevealCards) preserved, not deletedRollback
git revertthe type/loader commit →rarityoptional, no consumer breaks (additive field).RevealsPage.tsx): revert to priorRevealsPage→ page returns to franchise-only layout; or set the default-view constant back to'franchises'to ship the toggle with the old view as default without a revert.VITE_IS_REVEAL_SEASON=false(Vercel env) →/revealsredirects home, hiding the feature entirely while a fix is prepared.rarityfield revert optional (harmless if left).References
apps/web/reveals page redesign/README.md(desktop),.../design_handoff_reveals_page_mobile/README.md(mobile deltas),.../Reveals Page.dc.html(prototype logic:build_board/ring/gem)apps/web/src/pages/RevealsPage.tsx,apps/web/src/features/reveals/{Hero,FranchiseTier,franchise,revealDates,useRevealCards,useRevealPhase,useCountdown}.{tsx,ts}apps/web/public/data/previewCards.json; preview images committed in3380dcb(Set 13 reveal season, preview-card parser, and Temporary Shift support #388)packages/synergy-engine/SHIFT_TARGET_RULE.md(Shift variants), engine Shift-variant work commitsc627f6b/ff12db5apps/web/src/shared/constants/theme.ts(ink colors, easings); ink SVGsapps/web/src/assets/rule-candidate), Red Panda / Hunny tribal rules; reveals promo-card copy refresh; mechanics-card deep-linking; rarity-denominator confirmation when set completes