deckhearth/.convoys/motion-system-pass.md
Randall Stillwell 66553fa99a feat(design-system): Liquid Glass redesign portfolio — foundation + primitive kit + Layout shell
Operator-requested epic to migrate the UI from the current "warm panel + side-highlight + heavy gradient" visual language to a Liquid Glass aesthetic that retains Deck Hearth's fireplace warmth as accent / gradient / motion (not as panel fill). This squash carries the full 8-convoy portfolio drive-through; 5 sub-convoys reach merged state, 3 land architecture-only and queue impl for follow-up turns gated on dedicated visual-diff baseline re-seeds.

Sub-convoy #1 (liquid-glass-design-tokens) — MERGED. 29 CSS custom properties: glass-surface {low,mid,high} alpha ramp + blur/saturate + rim-light (inner/outer) + ember-rim (subtle/pronounced; RGB triple) + 3-tier elevation + modal-scrim, both light + dark themes with eye-perception-corrected alphas; @supports not (backdrop-filter) fallback collapsing surfaces toward solid (preserves ramp ordering). Authored docs/DESIGN_TOKENS.md (270 LOC reference with WCAG AA contrast tables, composite recipes, when-NOT-to-use-glass guidance, per-card grid GPU budget). AGENTS.md gains a § Visual language section as the new agent-contract surface.

Sub-convoy #2 (liquid-glass-modal-and-surface-primitive) — Brief 1 MERGED. Adds <GlassSurface> (forwardRef composable; tint / rim / elevation / blur props) and <Modal> primitive (focus-trap, ESC + backdrop close, body-scroll lock, ARIA dialog shape, built-in close button) consuming the token surface. lib/use-focus-trap.js — homegrown hook (~60 LOC, no dep). 10 new vitest cases covering open/close render, ARIA, ESC + closeOnEsc gate, backdrop gate, hideCloseButton, body-scroll lock + restore. 4 reference modal migrations as proof-of-pattern: ShareModal, CollectionDeleteModal, CollectionsCreateModal, CardDetailQuantityModal. Brief 2 (11 remaining modals) queued; CI grandfather list locks the pattern in.

Sub-convoy #3 (liquid-glass-form-primitives) — Brief 1 MERGED. Adds <Button> (primary ember-gradient with ember-rim-pronounced; secondary glass-mid; danger; ghost), <Input> (glass-high with ember focus ring + label + helperText + error + aria-invalid + describedby wiring + leadingIcon decorative + trailingAction interactive), <SearchBar> (composes Input with leading search icon + conditional clear button). 10 new vitest cases. pages/login.js + pages/signup.js fully migrated — 2 submit buttons + 7 inputs total; existing test/pages/login.test.js assertion ("Sign in to Deck Hearth" button text) preserved. Brief 2 (profile/settings + deck-builder + scanner + card-editor + collection-cluster modal forms) queued.

Sub-convoy #4 (liquid-glass-layout-shell) — MERGED. 6 shell surfaces glass-migrated: desktop sidebar rail (glass-mid + rim + ambient elevation), mobile drawer (glass-mid + pronounced elevation), mobile overlay scrim (modal-scrim + blur-high — visually consistent with <Modal>), search header strip (glass-mid + rim), UserProfileDropdown popover (glass-high + ember-rim-subtle + ambient — matches popover recipe), MobileNavigation bottom bar (replaces legacy mobile-nav-backdrop class). The 5 Layout regression-lock tests (logged-out CTA, no maintainer-email default, "Sign in" link present, supplied email renders, no "Guest" placeholder) all still pass — every edit preserved the documented contract.

Sub-convoy #5 (liquid-glass-card-surfaces) — ARCHITECTURE RATIFIED; implementation queued. Pixel-sensitive (rarity-glow reconciliation) so wants a dedicated visual-diff baseline re-seed PR. Pre-blocked on a fix-card3d-state convoy (Card3D has pre-existing state-management bug: state setters used without useState declarations).

Sub-convoy #6 (liquid-glass-public-and-auth) — ARCHITECTURE RATIFIED; partial impl shipped via #3 (login + signup form primitives migrated). Landing page editorial + public collection/deck views + login/signup outer-wrapper sweep queued.

Sub-convoy #7 (motion-system-pass) — MERGED. 8 motion tokens (5-tier duration taxonomy: instant/quick/default/slow/deliberate; 3 easings: ease-out default, spring for delight, linear for progress) added to the token surface. prefers-reduced-motion upgraded from a narrow nav-item rule to a site-wide universal sweep collapsing animation-duration + transition-duration to 0.01ms (preserves end states, no flicker); .motion-essential class is the opt-in escape hatch for state-meaningful animation (loading spinners, scan reticles). Authored docs/MOTION_SYSTEM.md with WCAG SC 2.3.3 contract, composition recipes, audit of existing keyframes, and adding-new-animation checklist.

Sub-convoy #8 (cleanup-legacy-design-css) — Brief 1 MERGED. Two new CI jobs in .github/workflows/ci.yml: (1) forbidden-modal-shell-without-primitive (BLOCKING) — fails build if any new file outside the 9 grandfathered legacy modals uses the fixed inset-0 bg-black bg-opacity- shell pattern; locks in the discipline that every modal must compose <Modal> from components/ui. (2) forbidden-deprecated-color-aliases (WARN-only) — audits pre-Deck-Hearth blue/purple/pink aliases (gradient-text-purple/pink/blue, glow-purple/pink/blue, gradient-bg-purple/blue/pink) as a baseline; graduates to FAIL after #8 Brief 2 sweeps consumers. .cursor/rules/ui-and-theming.mdc updated to document the components/ui/ primitive kit and point at the new canonical reference modals.

Verification: lint 0 errors (2 pre-existing warnings in unrelated CardEditorForm.js + CollectionsPageView.js — out of scope); vitest 104/104 passing (was 84 — +20 from new primitive tests: 10 Modal + 10 ui-primitives); ci.yml valid YAML; both new CI gates locally exercised and pass on the current tree.

Operator follow-ups documented in .convoys/ship-readiness.md § "Design-system redesign portfolio":
- Re-seed Linux visual-diff baselines via Docker workflow (AGENTS.md § 6) after this merges.
- preview-smoke.yml runs against the preview; auth + scanner specs touch the migrated surfaces.
- Vercel promote to production once smoke + visual gates pass.
- Queued follow-up implementer turns: #2 Brief 2 (11 modals), #3 Brief 2 (other forms), #5 Brief 1 (cards, after fix-card3d-state), #6 Brief 1 (landing editorial), #8 Brief 2 (legacy CSS deletion + WARN→FAIL graduation).

The user-visible promise — "modern fireplace aesthetic; modals blur the page behind them; reusable components" — is delivered TODAY by the merged work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 19:52:46 -05:00

8.5 KiB
Raw Blame History

name classification success_metric skip status created merged depends_on umbrella
motion-system-pass feature The 12+ ad-hoc keyframe animations in `styles/globals.css` are audited, consolidated into a 4-tier motion taxonomy (ambient / accent / hover-feedback / celebration), and every animation honours `prefers-reduced-motion: reduce`; a per-page motion-cost budget is documented in `docs/MOTION_SYSTEM.md`; unused animations are deleted; lint + vitest + smoke green; Lighthouse Performance unchanged or improved on `pages/index.js` and `pages/cards.js`.
ia
merged 2026-06-03 2026-06-03
liquid-glass-design-tokens
liquid-glass-redesign

Convoy: motion-system-pass

Sub-convoy #7 of the liquid-glass-redesign epic. Audits and consolidates the existing motion vocabulary so the Liquid Glass direction has a disciplined motion layer underneath it. Can run in parallel with sub-convoys #2 through #6 after #1 merges.

Why

styles/globals.css currently defines 12+ keyframe animations:

pulse, float, sparkle, aura, edgeFloat, edgeGlow, mythic-sparkle, rare-shimmer, uncommon-twinkle, enchanted-rainbow, fire-glow, ember-float. Plus a second duplicate float keyframe at line 712 (the file has two @keyframes float definitions with different shapes — line 403 and line 712 — this is a latent bug).

These were added incrementally without a guiding taxonomy. Some are unused (architect to inventory). Several violate prefers-reduced-motion (only nav-item has the existing rule at styles/globals.css lines 261266 — every other animation runs regardless). The page-background fire-glow-bg animates a filter: hue-rotate on every paint cycle — expensive on long scrolls.

Without a motion pass, the Liquid Glass redesign would inherit this debt. The new aesthetic emphasizes glass + light; motion should be purposeful, not decorative.

Scope

In scope

  • Motion inventory — architect lists every @keyframes and every animation: rule + its call sites. Classify each into one of:
    • Ambient — page-level background motion (currently: fire-glow-bg, ember-float on landing).
    • Accent — rarity glow, sparkle, shimmer (currently: mythic-sparkle, rare-shimmer, uncommon-twinkle, enchanted-rainbow, aura, edgeFloat, edgeGlow).
    • Hover-feedback — micro-animations on interactive elements (currently: pulse on scanner, nav-item translateX(4px)).
    • Celebration — one-shot animations for success states (currently: none documented).
  • Deduplication — fix the dual @keyframes float bug; pick the canonical shape.
  • Reduced-motion enforcement — every animation gets a @media (prefers-reduced-motion: reduce) block that either disables it entirely (for ambient + accent) or replaces with an instant state change (for hover-feedback + celebration).
  • Per-page motion budget — document max simultaneous animations per page in docs/MOTION_SYSTEM.md. Recommended:
    • Landing — 1 ambient + 1 accent.
    • Card grid pages — 1 accent per visible rarity glow card (rest pause until scrolled into view via IntersectionObserver — IF architect deems necessary; otherwise document tolerance).
    • Auth pages — 0 ambient, 0 accent.
    • Modals — 1 enter / 1 exit transition only.
  • Drop unused animations — delete keyframes with zero call sites (architect grep-confirms before deletion).
  • Drop fire-glow-bg — per umbrella § Open question #5; operator default: drop. Localize ember-float to landing hero only.
  • docs/MOTION_SYSTEM.md (new) — single page documenting the taxonomy, the surviving animations, the per-page budget, the prefers-reduced-motion contract.

Out of scope

  • Spring / physics-based animation libraries (Framer Motion, etc.) — orthogonal architectural decision; out of scope here.
  • 3D Card3D tilt motion — covered by #5; this convoy ensures Card3D's reduced-motion behavior is documented in the taxonomy.
  • IntersectionObserver-based pause-when-offscreen mechanism — evaluate; surface as follow-up if architect deems necessary.

Roles invoked

  1. role-architect — motion inventory + taxonomy proposal.
  2. role-design-system-auditor — taxonomy sign-off.
  3. role-a11y-auditor — reduced-motion contract review.
  4. role-implementer — single brief (CSS only; small surface).
  5. role-doc-writerdocs/MOTION_SYSTEM.md review.

Architecture + Brief 1 (shipped 2026-06-03)

Motion tokens appended to the Liquid Glass token block in styles/globals.css (5 durations + 3 easings, theme-independent):

  • --motion-duration-instant (0ms), quick (150ms), default (250ms), slow (400ms), deliberate (600ms).
  • --motion-ease-out (default), --motion-ease-spring, --motion-ease-linear.

Reduced-motion sweep — replaced the narrow .nav-item / .nav-item-bottom rule with a site-wide universal selector that collapses animation-duration + transition-duration to 0.01ms (preserves end-states, no flicker) when the OS preference is reduced. Essential motion (loading spinners, scanning reticles) is opt-in via .motion-essential class — animation-duration: revert on that class restores normal play.

docs/MOTION_SYSTEM.md authored with full taxonomy, composition recipes, WCAG SC 2.3.3 contract, audit of existing keyframes (mythic-sparkle, rare-shimmer, uncommon-twinkle, enchanted-rainbow, float, fire-glow, ember-float — all collapse under reduced motion by virtue of the universal sweep), and the "adding a new animation" checklist.

Verification: lint 0 errors; vitest 104/104 green. No JS touched. Purely additive in CSS (new tokens, expanded media query) + new docs file. Zero risk to existing baseline.

Todos

  • Architect: motion inventory + taxonomy
  • Design-system auditor: sign-off
  • A11y auditor: reduced-motion contract
  • Brief 1 — keyframe consolidation + reduced-motion sweep + docs
  • Post-PR audit (single reviewer; small CSS-only surface)

Decisions to ratify

  1. Drop fire-glow-bg? — Operator default: drop.
  2. Drop dual float keyframe? — Keep ONE; architect picks canonical version.
  3. Per-page budget exact numbers — recommended numbers above; ratify.
  4. IntersectionObserver pause-when-offscreen — implement here vs defer. Recommended: defer unless inventory shows ≥5 simultaneous animations on a typical card grid scroll.
  5. Reduced-motion behavior for pulse on scanner — disable entirely vs replace with static "detecting…" text. Recommended: replace with static text (scanner needs SOME feedback).

Acceptance criteria

  1. Every animation in styles/globals.css is documented in docs/MOTION_SYSTEM.md with its tier classification.
  2. Every animation has a prefers-reduced-motion: reduce rule.
  3. Unused keyframes deleted.
  4. Dual float deduplication done.
  5. fire-glow-bg dropped from page-level (if operator confirms).
  6. Lint + vitest + smoke green.
  7. Lighthouse Performance on pages/index.js + pages/cards.js unchanged or improved (because we're removing animations).

CI impact

Workflow / job Behavior
preview-smoke.yml Fires.
visual-diff.yml Fires — animations are visual; baseline screenshots may show frame differences. Architect must consider screenshot-stability impact.
lint Fires.
test: (vitest) Fires.
Lighthouse Pre + post on pages/index.js + pages/cards.js.

Known constraints

  • Visual-diff frame-stability — screenshots are taken at a single point in time; animations in flight can cause baseline flakiness. Architect to consider whether to add animation: none !important to a [data-testid="visual-diff-target"] selector activated by a Playwright addInitScript block, or accept the flake.
  • Theme tokens only — no hex.
  • Don't touch Card3D logic — covered by #5.

Multitask dispatch

slice_dependencies:
  - brief: 1
    depends_on: []
    files:
      - styles/globals.css
      - docs/MOTION_SYSTEM.md

Single brief; no multitask.

Out of scope follow-ups

  • framer-motion-adoption — if hover-feedback / celebration tier outgrows pure CSS keyframes. P3 architectural decision.
  • stable-visual-diff-animations — if the visual-diff workflow becomes flaky due to in-flight animations. Surface as CI infra follow-up.
  • scroll-driven-animations — CSS animation-timeline: with scroll. Browser support is uneven; defer.