diff --git a/_bmad-output/planning-artifacts/ux-design-directions.html b/_bmad-output/planning-artifacts/ux-design-directions.html new file mode 100644 index 0000000..272cae6 --- /dev/null +++ b/_bmad-output/planning-artifacts/ux-design-directions.html @@ -0,0 +1,369 @@ + + + + + +2048 Clone - Design Direction + + + + + +
+
2048
+
+
+
Score
+
7832
+
+
+
Best
+
21504
+
+
+
+ + +
+
Join the numbers and get to the 2048 tile!
+ +
+ + +
+ +
+ + +
+

Game States Preview

+
+ + + + + +
+
+ Mid-Game: Player has built momentum. Multiple tile tiers visible, showing the color progression from beige (2-4) through orange (8-32) to gold (128+). Grid has breathing room — tension is building but not critical. +
+
+ + + + + diff --git a/_bmad-output/planning-artifacts/ux-design-specification.md b/_bmad-output/planning-artifacts/ux-design-specification.md new file mode 100644 index 0000000..4254969 --- /dev/null +++ b/_bmad-output/planning-artifacts/ux-design-specification.md @@ -0,0 +1,788 @@ +--- +stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] +lastStep: 14 +inputDocuments: + - '_bmad-output/planning-artifacts/prd.md' + - '_bmad-output/brainstorming/brainstorming-session-2026-04-12-001.md' +--- + +# UX Design Specification - try-bmad + +**Author:** MiTi +**Date:** 2026-04-12 + +--- + + + +## Executive Summary + +### Project Vision + +A faithful web-based recreation of the original 2048 puzzle game, built with Svelte + Tailwind CSS + Vite. The focus is on craft over novelty — deeply understanding and reproducing every detail of the original's mechanics and feel. The result serves as both a playable game and a learning artifact for modern web tooling. + +### Target Users + +- **Casual discoverers** — first-time players who expect intuitive, zero-instruction gameplay +- **Score chasers** — returning players who want persistent best scores and smooth "one more try" loops +- **Mobile players** — on-the-go users who need responsive touch controls and quick session support +- All users are general audience with no assumed technical knowledge; the game must teach itself through play + +### Key Design Challenges + +1. **Animation choreography** — slide, merge-bounce, pop, and score-float animations must layer cleanly at original timings (100ms/200ms) without visual conflict +2. **Input parity across devices** — swipe gestures must feel as precise and responsive as keyboard arrows; accidental swipes need mitigation (10px minimum threshold) +3. **State communication** — players must always see current score, best score, and game status (win/lose/in-progress); localStorage persistence must be invisible and reliable + +### Design Opportunities + +1. **Micro-interaction dopamine loop** — merge bounce + score float + tile pop create the satisfying feedback that drives "one more try" behavior +2. **Progressive visual feedback** — 12-tier tile color system and glow effects on 128+ tiles communicate progress without text, rewarding advancement naturally +3. **Zero-friction onboarding** — no tutorial needed; the UX stays out of the way and lets the game mechanics teach themselves + +## Core User Experience + +### Defining Experience + +The core experience is the **directional slide** — a single input (arrow key or swipe) that triggers a cascade: tiles slide, identical values merge, score updates, a new tile spawns. This atomic interaction is the entire game loop. Every UX decision must serve this moment — making it feel instant, satisfying, and predictable. + +### Platform Strategy + +- **Platform:** Web SPA — browser-based, no installation, fully client-side +- **Desktop input:** Arrow keys (primary), WASD and Vim keys (secondary) +- **Mobile input:** Single-finger swipe with 10px minimum threshold to prevent accidental moves +- **Offline:** Fully functional once loaded — no server dependency at any point +- **Technology:** Pure web standards — CSS transitions for animation, localStorage for persistence, pointer/touch events for input + +### Effortless Interactions + +- **Slide-merge-score** feels like one continuous motion, not three sequential events +- **Game state persistence** is silent — no save button, no confirmation; refresh and your game is there +- **New Game** is a single tap — no "are you sure?" dialogs +- **Win-to-continue** transition is seamless — victory overlay appears, dismiss to keep playing +- **Input switching** between keyboard and touch works without mode selection + +### Critical Success Moments + +1. **First merge** — new player slides, two tiles combine, score ticks up. "I get it" moment. +2. **Near-death board** — 15/16 cells filled, every move consequential. Tension must feel exciting, not frustrating. +3. **Reaching 2048** — victory overlay feels earned; "Keep going" option is immediately visible. +4. **Page refresh recovery** — returning to an intact game builds implicit trust in the product. + +### Experience Principles + +1. **Responsive immediacy** — every input gets instant visual feedback; no action feels ignored or delayed +2. **Invisible infrastructure** — persistence, state management, and platform adaptation are imperceptible to the player +3. **Escalating tension** — UX amplifies the natural difficulty curve through visual density and tile color progression +4. **Respectful simplicity** — no tutorials, tooltips, or onboarding; the grid and starting tiles communicate everything + +## Desired Emotional Response + +### Primary Emotional Goals + +- **Compulsive flow** — the player enters a rhythmic slide-merge-slide state where time blurs and "one more try" is the automatic response to every game over +- **Earned mastery** — each game teaches strategy implicitly; players feel themselves improving without instruction +- **Satisfying feedback** — every action produces visible, audible-feeling results; nothing feels ignored + +### Emotional Journey Mapping + +| Stage | Emotion | Design Driver | +|-------|---------|---------------| +| First open | Curiosity + clarity | Clean grid, two tiles, no clutter | +| First merge | Understanding + delight | Tile combine + score bump + pop animation | +| Mid-game | Focused absorption | Rhythmic input, rising numbers, pattern recognition | +| Near-death board | Thrilling tension | Board density signals urgency through visual weight | +| Game over | Brief disappointment → motivation | Score comparison triggers "I can beat that" | +| Reaching 2048 | Earned triumph | Victory overlay with seamless keep-going option | +| Return visit | Quiet trust | Game state intact on refresh | + +### Micro-Emotions + +- **Confidence over confusion** — the game never asks the player to figure out UI, only strategy +- **Accomplishment over frustration** — every game shows a score; every session has measurable progress +- **Excitement over anxiety** — tight boards feel thrilling, not punishing; color progression signals state naturally + +### Design Implications + +- **Flow state protection** → Animations must not block input; moves can queue during transitions to maintain rhythm +- **Merge delight** → Bounce animation (200ms) + score float create a micro-reward at the exact moment of success +- **Invisible trust** → localStorage persistence never surfaces; no save indicators, no failure states visible to player +- **Natural tension** → Tile color darkening and density communicate board state without explicit warnings or counters + +### Emotional Design Principles + +1. **Never break rhythm** — the player's input cadence is sacred; animations serve the flow, never interrupt it +2. **Reward every action** — even moves that don't merge should feel acknowledged through smooth tile sliding +3. **Signal through aesthetics** — color, size, and glow communicate game state; no text-based status needed +4. **Fail gracefully** — game over is a pause, not a punishment; the path to "try again" is instant + +## UX Pattern Analysis & Inspiration + +### Inspiring Products Analysis + +**Original 2048 (play2048.co)** — direct reference +- Zero-chrome interface: grid is the entire product, header holds only score + best + new game +- No onboarding: two tiles on a grid teach the game in one interaction +- Animations layer without blocking input; score updates feel causally connected to merges +- Tile color encodes value — experienced players read color before numbers + +**Wordle** — emotional arc reference +- Session structure creates anticipation; the attempt → result → retry loop drives retention +- Letter-by-letter reveal animation builds tension through pacing — analogous to merge-bounce micro-celebrations +- Minimal UI with maximum information density; every pixel serves gameplay + +**Threes!** — mobile interaction reference +- Buttery smooth swipe with slight overshoot easing — gold standard for touch-based puzzle input +- Warm color palette and tile personality create emotional attachment to game pieces +- "Next tile" preview at screen edge reduces frustration (not used in 2048 for fidelity, but noted as design choice) + +### Transferable UX Patterns + +**Interaction Patterns:** +- **Zero-chrome layout** (from 2048) — the game grid dominates; UI elements are minimal and peripheral +- **Non-blocking animations** (from 2048) — input is never locked during transitions; moves can queue +- **Weighted swipe** (from Threes!) — touch input has momentum and intentionality; prevents accidental triggers + +**Visual Patterns:** +- **Color-as-information** (from 2048) — tile color tiers encode value; players read color before number at higher levels +- **Micro-celebration timing** (from Wordle) — brief animation at moment of success creates dopamine without interrupting flow +- **Score causality** (from 2048) — "+N" float appears at merge location, visually linking action to reward + +**Retention Patterns:** +- **"One more try" loop** (from all three) — game over → score comparison → instant restart with zero friction +- **Implicit learning** (from 2048/Threes!) — players develop strategy through play, not instruction + +### Anti-Patterns to Avoid + +- **Interstitial ads or pauses** — any interruption between game over and restart kills the retry loop +- **Tutorial overlays** — explaining a self-teaching game insults the player and delays the first merge moment +- **Confirmation dialogs on New Game** — friction on restart breaks the "one more try" impulse +- **Over-animated transitions** — animations longer than 200ms feel sluggish and break flow state +- **Score without context** — showing score without best-score comparison removes the motivational anchor + +### Design Inspiration Strategy + +**Adopt directly:** +- Original 2048's zero-chrome layout, tile color system, and animation timings — this is a faithful clone +- Non-blocking input during animations — critical for flow state preservation +- Instant restart with no confirmation — supports the retry loop + +**Adapt for our stack:** +- CSS transitions in Svelte for slide/merge/pop — matching original timings (100ms/200ms) with Svelte's transition system +- Touch handling adapted from Threes! philosophy — weighted, intentional swipe with 10px threshold + +**Explicitly avoid:** +- Any UI element not present in the original (no settings, no themes, no undo) +- Any animation that blocks the next input +- Any text-based instruction or tutorial + +## Design System Foundation + +### Design System Choice + +**Tailwind CSS utility-first custom system** — no external component library. + +All UI elements in this project are game-specific (tile grid, score display, overlays) with no equivalent in standard component libraries. Tailwind provides the systematic foundation (spacing, colors, transitions, responsive utilities) while allowing fully custom game components. + +### Rationale for Selection + +1. **Already in tech stack** — Tailwind CSS chosen in PRD; no additional dependency +2. **No applicable component library** — game UI is entirely bespoke (tiles, grid, overlays); Material/Ant/Chakra components don't apply +3. **Fidelity requirement** — faithful clone means matching the original's exact visual language, not adapting a design system's defaults +4. **Utility-first speed** — responsive breakpoints, transition timings, and color values are expressible as Tailwind config without writing raw CSS +5. **Purge-friendly** — unused utilities are stripped at build time, keeping bundle under 50KB target + +### Implementation Approach + +- **Tailwind config** defines the game's design tokens: tile colors (12-tier), font sizes (55/45/35px), grid dimensions (500px/280px), transition durations (100ms/200ms) +- **Svelte components** own their structure; Tailwind classes handle all styling +- **No CSS-in-JS** — pure utility classes + minimal custom CSS for animations (keyframes for pop/bounce) +- **Responsive** via Tailwind's breakpoint system with single 520px custom breakpoint + +### Customization Strategy + +- **Custom color palette** in `tailwind.config.js` matching original 2048 tile colors exactly +- **Custom spacing/sizing** for grid cells and container dimensions +- **Custom transition utilities** for game-specific animation durations +- **Minimal `@apply`** — prefer inline utilities; extract only for highly repeated tile-state styles + +## Detailed Core User Experience + +### Defining Experience + +**"Slide tiles to merge and reach 2048."** The defining interaction is the directional slide that causes a merge — the moment two tiles combine into one higher number. Every UX decision serves this atomic moment: making it feel instant, predictable, and satisfying. + +### User Mental Model + +Players bring a spatial reasoning model: the grid is a physical space with gravity. "Push" all tiles in a direction. Same numbers touching after push = bigger number. The mental model matches the visual representation 1:1 — no abstraction layer, no learning curve. Players who have used any sliding puzzle or played the original 2048 have immediate transfer. + +### Success Criteria + +- **Input latency** < 16ms — slide must feel instant, never laggy +- **Merge position** matches expectation — result tile appears at leading edge of movement direction +- **Score causality** — "+N" float animation originates from merge location, visually linking action to reward +- **Sequence integrity** — new tile spawns after slide completes, never during; maintains predictable state +- **Input queuing** — next move can be registered during current animation; flow state never interrupted +- **State accuracy** — once-per-move merge rule enforced; no double-merges in single slide + +### Novel UX Patterns + +No novel patterns required. The directional grid slide is a fully established interaction pattern, perfected by the original 2048. Our approach is **faithful reproduction**, not innovation. The UX challenge is execution quality — matching the original's timings, easing curves, and feedback choreography — not inventing new interactions. + +### Experience Mechanics + +**1. Initiation** +- Desktop: Arrow key / WASD / Vim key press detected +- Mobile: Single-finger swipe exceeding 10px threshold in dominant direction +- Input ignored if no tiles can move in that direction (no state change = no animation) + +**2. Slide Phase (100ms)** +- All movable tiles translate simultaneously toward input direction +- Tiles stop at grid boundary or when blocked by a different-value tile +- CSS transition with ease-in-out timing + +**3. Merge Phase (200ms)** +- Identical adjacent tiles in movement path combine into sum value +- Merged tile plays bounce animation (scale 1.0 → 1.2 → 1.0) +- Only one merge per tile per move (once-per-move rule) +- Merge order: leading edge first (tiles closest to movement direction merge first) + +**4. Score Update (600ms)** +- "+N" float animation rises from merge position and fades out +- Current score counter increments +- Best score updates if current exceeds previous best + +**5. Spawn Phase (200ms)** +- Random empty cell selected for new tile +- 90% chance of value 2, 10% chance of value 4 +- New tile plays pop animation (scale 0 → 1.0 with slight overshoot) + +**6. State Evaluation (instant)** +- Check for 2048 tile → trigger win overlay (first time only) +- Check for available moves → if none, trigger game over overlay +- Save game state to localStorage + +## Visual Design Foundation + +### Color System + +**Page & Grid:** +- Page background: `#faf8ef` (warm cream) +- Grid background: `#bbada0` (warm grey-brown) +- Empty cell: `#cdc1b4` (light taupe) + +**Tile Color Tiers (12 levels):** + +| Value | Background | Text Color | Notes | +|-------|-----------|------------|-------| +| 2 | `#eee4da` | `#776e65` | Light beige, dark text | +| 4 | `#ede0c8` | `#776e65` | Slightly darker beige | +| 8 | `#f2b179` | `#f9f6f2` | Orange, white text | +| 16 | `#f59563` | `#f9f6f2` | Deeper orange | +| 32 | `#f67c5f` | `#f9f6f2` | Red-orange | +| 64 | `#f65e3b` | `#f9f6f2` | Bright red | +| 128 | `#edcf72` | `#f9f6f2` | Gold + glow shadow | +| 256 | `#edcc61` | `#f9f6f2` | Deeper gold + glow | +| 512 | `#edc850` | `#f9f6f2` | Rich gold + glow | +| 1024 | `#edc53f` | `#f9f6f2` | Intense gold + glow | +| 2048 | `#edc22e` | `#f9f6f2` | Brightest gold + glow | +| 4096+ | `#3c3a32` | `#f9f6f2` | Dark (super tiles) | + +**Glow effect** on 128+ tiles: `box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.4)` + +**UI Colors:** +- Header text: `#776e65` (warm dark brown) +- Score box background: `#bbada0` +- Score box text: `#f9f6f2` (off-white) +- Button background: `#8f7a66` (brown) +- Button text: `#f9f6f2` +- Game over overlay: `rgba(238, 228, 218, 0.73)` +- Win overlay: `rgba(237, 194, 46, 0.5)` + +### Typography System + +**Font Family:** Clear Sans, Helvetica Neue, Arial, sans-serif + +**Tile Number Sizes (dynamic by digit count):** +- 1 digit (2-8): `55px` bold +- 2 digits (16-64): `45px` bold +- 3 digits (128-512): `35px` bold +- 4 digits (1024-8192): `25px` bold +- 5+ digits: `15px` bold + +**UI Typography:** +- Game title: `80px` bold, `#776e65` +- Score label: `13px` uppercase, `#eee4da` +- Score value: `25px` bold, `#f9f6f2` +- Subtitle/instructions: `18px`, `#776e65` +- Button text: `18px` bold, `#f9f6f2` +- Overlay message: `60px` bold + +**Mobile scaling:** All tile font sizes reduce proportionally with the 280px/500px container ratio (0.56x) + +### Spacing & Layout Foundation + +**Desktop Layout (>520px):** +- Game container width: `500px`, centered +- Grid: `4x4`, cells `~106px` each +- Grid gap: `15px` +- Grid padding: `15px` +- Grid border-radius: `6px` +- Header padding: `0 0 40px 0` + +**Mobile Layout (≤520px):** +- Game container: `280px` width +- Grid cells: `~57px` each +- Grid gap: `10px` +- Grid padding: `10px` +- Proportional scaling of all spacing + +**Spacing Scale:** +- Base unit: `15px` (grid gap) +- Half: `8px` (inner tile padding) +- Double: `30px` (section gaps) +- Page margin: auto-centered with `max-width: 500px` + +### Accessibility Considerations + +- **Color contrast:** All tile text meets WCAG AA ratio against its background (dark text on light tiles, white text on dark tiles — transition happens at value 8) +- **Font sizing:** Minimum 15px even on smallest tiles; mobile sizes never drop below readable threshold +- **No color-only information:** Tile values are always displayed as numbers; color is supplementary, not the sole indicator +- **Keyboard accessible:** Full game playable with arrow keys; focus states for New Game button +- **Reduced motion:** Respect `prefers-reduced-motion` media query — disable animations, keep instant state updates + +## Design Direction Decision + +### Design Directions Explored + +Since this is a faithful 2048 clone, design direction exploration focused on verifying that our visual foundation (colors, typography, spacing) accurately reproduces the original's look and feel, rather than exploring divergent visual approaches. A single HTML mockup was generated showing all game states. + +**Mockup:** `_bmad-output/planning-artifacts/ux-design-directions.html` + +**States verified:** +- Early game (sparse board, calm start) +- Mid-game (multi-tier color progression, building momentum) +- Near-death (15/16 filled, visual density signals tension) +- Game over (translucent white overlay, prominent message) +- Win (gold overlay, "Keep going" option) + +### Chosen Direction + +**Faithful reproduction of the original 2048 visual language** — warm cream background, earthy tile color progression, zero-chrome layout with grid as dominant element. No alternative directions considered because fidelity to the original is a core project requirement. + +### Design Rationale + +1. **Fidelity is the goal** — this project exists to faithfully recreate 2048, not to reinterpret it +2. **Proven visual language** — the original's color system, typography, and layout have been validated by millions of players +3. **Learning focus** — implementation quality matters more than design originality; the challenge is reproducing these visuals in Svelte + Tailwind +4. **Emotional alignment** — the warm, earthy palette supports the calm-to-tense emotional journey we defined + +### Implementation Approach + +- **Svelte components:** `App`, `Grid`, `Tile`, `ScoreBoard`, `GameMessage` — each owns its visual rendering +- **Tailwind config:** Custom color palette, font sizes, spacing scale, and transition durations matching original values +- **CSS animations:** Keyframe definitions for pop (new tile), bounce (merge), and fade (overlays) in global stylesheet +- **Responsive:** Single `@media (max-width: 520px)` breakpoint scales all dimensions proportionally + +## User Journey Flows + +### Journey 1: Core Gameplay Loop + +The universal interaction cycle shared by all user personas. + +```mermaid +flowchart TD + A[Player Input] --> B{Valid direction?} + B -->|No tiles can move| A + B -->|Tiles can move| C[Slide all tiles in direction] + C --> D{Any merges?} + D -->|Yes| E[Merge matching tiles] + E --> F[Update score + float animation] + F --> G[Spawn new tile] + D -->|No merges| G + G --> H{Board full?} + H -->|No| A + H -->|Yes| I{Any valid moves remain?} + I -->|Yes| A + I -->|No| J[Game Over] + E --> K{Created 2048 tile?} + K -->|Yes, first time| L[Win Overlay] + K -->|No| G + L --> M{Player choice} + M -->|Keep going| A + M -->|New game| N[Reset board] + N --> A +``` + +**Key UX decisions in this flow:** +- Invalid moves (no tiles can move in direction) produce no animation, no state change — silent rejection +- Merge check happens during slide, not after — tiles merge as they collide +- Win detection only triggers once per game; subsequent 2048+ merges don't re-trigger +- Score float animation runs concurrently with spawn, not sequentially + +### Journey 2: Game Lifecycle + +Complete flow from app open to session end. + +```mermaid +flowchart TD + A[Open App] --> B{Saved game in localStorage?} + B -->|Yes| C[Restore game state] + B -->|No| D[Initialize new game] + D --> E[Spawn 2 random tiles] + C --> F[Display restored board + scores] + E --> F2[Display fresh board] + F --> G[Gameplay Loop] + F2 --> G + G --> H{Game ends} + H -->|Win| I[Win Overlay - 800ms fade] + H -->|Game Over| J[Game Over Overlay - 800ms fade] + I --> K[Keep going / New Game] + J --> L[Try Again] + K -->|Keep going| G + K -->|New Game| M[Clear localStorage game state] + L --> M + M --> D + + G -->|User clicks New Game mid-play| M + G -->|User closes tab| N[Auto-save to localStorage] +``` + +**Key UX decisions in this flow:** +- No "welcome screen" or splash — straight to game +- Saved game restores silently; player sees their board, not a loading screen +- New Game button works mid-game with no confirmation dialog +- Auto-save happens after every move, not on tab close (beforeunload is unreliable) + +### Journey 3: Input Handling (Cross-Platform) + +Detailed input flow covering keyboard and touch parity. + +```mermaid +flowchart TD + A[Input Event] --> B{Input type?} + B -->|Keyboard| C{Key mapping} + C -->|Arrow keys| D[Map to direction] + C -->|WASD| D + C -->|Vim hjkl| D + C -->|Other key| E[Ignore] + B -->|Touch| F[Record touch start position] + F --> G[Touch move / Touch end] + G --> H{Distance > 10px?} + H -->|No| E + H -->|Yes| I{Dominant axis?} + I -->|Horizontal| J{deltaX direction} + I -->|Vertical| K{deltaY direction} + J -->|Positive| L[Right] + J -->|Negative| M[Left] + K -->|Positive| N[Down] + K -->|Negative| O[Up] + L & M & N & O --> D + D --> P{Animation in progress?} + P -->|No| Q[Execute move immediately] + P -->|Yes| R[Queue move, execute after current animation] +``` + +**Key UX decisions in this flow:** +- Touch uses dominant axis (larger delta) to determine direction — prevents diagonal ambiguity +- 10px minimum threshold prevents accidental swipes +- Input queuing during animations preserves flow state — player never feels "dropped" +- All keyboard mappings produce identical behavior — no preferential treatment + +### Journey Patterns + +**Feedback Pattern: Immediate Visual Response** +Every valid input produces visible change within one frame (16ms). Invalid inputs produce no change — silence is the feedback for "that didn't work." + +**State Pattern: Invisible Persistence** +Game state saves after every move. Restore is silent. The player never interacts with save/load — it's infrastructure, not a feature. + +**Recovery Pattern: Zero-Friction Restart** +From any state (mid-game, game over, win), one tap/click reaches a fresh board. No confirmation, no "are you sure," no transition screen. + +### Flow Optimization Principles + +1. **Minimum path to value:** App open → playing in 0 steps (restored game) or 0 steps (new game auto-starts) +2. **No dead ends:** Every terminal state (win, game over) has an immediate forward path (keep going, try again, new game) +3. **Silent error handling:** Invalid moves don't produce error messages; absence of response IS the feedback +4. **Concurrent animations:** Score float, tile spawn, and merge bounce can overlap — sequential would feel sluggish + +## Component Strategy + +### Design System Components + +No external component library used. All components are custom Svelte components styled with Tailwind CSS utilities. The "design system" is the Tailwind config (custom colors, spacing, transitions) plus 5 game-specific components. + +### Custom Components + +#### `App.svelte` — Root Container + +**Purpose:** Top-level layout orchestrator; holds game state, routes keyboard input, manages overlays +**Anatomy:** Header (title + scores) → subtitle row (instructions + New Game button) → Grid → GameMessage overlay +**States:** Playing, Won (overlay visible), Game Over (overlay visible) +**Interaction:** Listens for keyboard events on `window`; passes direction to game logic +**Accessibility:** `tabindex` on container for keyboard focus; `role="application"` for game context + +#### `Grid.svelte` — Game Board + +**Purpose:** Renders the 4x4 grid background with empty cell placeholders; positions Tile components +**Anatomy:** 4x4 CSS grid with `15px` gap; empty cells as background; tiles positioned absolutely over cells +**States:** Single state — always renders 16 cell backgrounds; tile count varies +**Props:** `tiles` array (each tile has `value`, `row`, `col`, `id`, `isNew`, `isMerged`) +**Interaction:** None — purely presentational; touch events handled at App level +**Accessibility:** `role="grid"`, `aria-label="Game board"` + +#### `Tile.svelte` — Individual Tile + +**Purpose:** Renders a single numbered tile with value-based color, font size, and animations +**Anatomy:** Rounded rectangle with centered number; color from 12-tier system +**States:** +- **Default:** Positioned at grid cell, value-based color and font size +- **Sliding:** CSS transition `transform` over 100ms to new position +- **New (spawning):** Pop animation — scale 0 → 1.0 over 200ms +- **Merged:** Bounce animation — scale 1.0 → 1.2 → 1.0 over 200ms +- **Glowing:** 128+ values get `box-shadow` glow effect +**Props:** `value`, `row`, `col`, `isNew`, `isMerged` +**Dynamic styling:** Font size tier (55/45/35/25/15px) based on digit count; background/text color from value lookup +**Accessibility:** `role="gridcell"`, `aria-label` with tile value + +#### `ScoreBoard.svelte` — Score Display + +**Purpose:** Shows current score and best score in styled boxes; animates score additions +**Anatomy:** Two side-by-side boxes — each with label ("SCORE"/"BEST") and numeric value +**States:** +- **Default:** Static display of score values +- **Score added:** "+N" float animation rises from score box and fades (600ms) +**Props:** `score`, `bestScore`, `scoreAddition` (triggers float animation) +**Accessibility:** `aria-live="polite"` on score value for screen reader updates + +#### `GameMessage.svelte` — Overlay + +**Purpose:** Displays win or game-over message with action buttons +**Anatomy:** Full-grid overlay with centered message text + action button(s) +**States:** +- **Hidden:** `opacity: 0`, `pointer-events: none` +- **Win:** Gold background overlay, "You win!" text, "Keep going" + "New Game" buttons +- **Game Over:** White semi-transparent overlay, "Game over!" text, "Try again" button +- **Transition:** 800ms opacity fade-in +**Props:** `type` ("win" | "gameover" | null), `onKeepGoing`, `onNewGame` +**Accessibility:** `role="alertdialog"`, `aria-modal="true"`, auto-focus on primary action button + +### Component Implementation Strategy + +**Build order follows dependency chain:** +1. `Tile` first — atomic unit, no dependencies, most complex styling +2. `Grid` — depends on Tile, handles positioning logic +3. `ScoreBoard` — independent, simple state +4. `GameMessage` — independent, overlay logic +5. `App` — orchestrates all components, owns game state + +**Styling approach:** +- Tailwind utility classes for layout, spacing, colors +- Svelte `class:` directives for conditional tile states +- CSS `@keyframes` in `