--- name: iching-divination-coin-ui description: Implement and polish a mobile-first I Ching divination flow with animated three-coin tosses, six-line hexagram construction, and automatic routing to the matching hexagram page. --- # When to use Use this when adding or improving the coin-based divination flow in the I Ching Study app, especially when the user wants richer visuals, better physics, clearer Yin/Yang signaling, or mobile-first fullscreen ritual UX. # Context The I Ching app lives at `/home/avalon/apps/iching-study` and is a React + Vite + TypeScript frontend with an Express backend and SQLite, deployed via PM2 on `iching-study.apps.poofc.com`. # Goals - Add a sidebar entry point for divination. - Present a fullscreen/minimal divination mode optimized for mobile. - Use three coins per throw, six throws total, building lines bottom-up. - Map coin faces exactly: - Yang / heads = 3 - Yin / tails = 2 - Sum the three coin values per throw; odd totals create Yang lines, even totals create Yin lines. - After six throws, resolve the matching hexagram and open its info page. - Make the coins feel premium, not placeholder. # Implementation checklist 1. **Read the current app structure first** - Review `src/App.tsx`, `src/index.css`, `src/lib/deck.ts`, `src/data/hexagrams.ts`, and existing tests. - Confirm how the app currently navigates between views and displays the selected hexagram. 2. **Create divination domain logic in a library file** - Add a helper like `src/lib/divination.ts`. - Implement: - coin result representation - three-coin throw generation - total calculation - odd/even -> Yang/Yin line mapping - six-line -> hexagram lookup based on the app's line ordering - Keep line ordering explicit: throws build from bottom line upward. - Add unit tests for totals, line parity, and hexagram resolution. 3. **Add a dedicated divination view/state in `App.tsx`** - Add a sidebar button like `Start divination`. - Add a fullscreen/minimal mode with only: - discreet top-left sidebar/menu button - main ritual area - large CTA button (`Cast coins` / `Throw coins`) - Keep it mobile-first; assume portrait mobile layout. 4. **Build the coin toss UI component behavior** - Render three large ancient Chinese cash coins with: - circular body - square center hole - rim / metallic shading / patina - visible Yin/Yang side treatment - Make sides obvious using: - Chinese labels: `陰` / `陽` - English labels: `Yin` / `Yang` - optional gender markers if requested: `♀` for Yin, `♂` for Yang - Use richer visual composition so the coins feel ceremonial/premium. 5. **Animation / physics polish** - Coins should toss high, then fall fast. - Randomize each coin's: - horizontal drift - rotation/spin - launch timing - depth/scale impression - bounce amount - settle rotation - final landing position - Avoid the coins landing in the same pile every time. - The toss should feel more like a ritual cast than a generic CSS float. - Favor deterministic randomization per cast if needed for stable React rendering. 6. **Draw lines after each throw** - After each resolved throw, append the resulting line to a six-line stack at the bottom. - Show lines building from bottom to top. - Yin line = broken line, Yang line = solid line. - Keep visuals large enough for mobile readability. 7. **Complete divination flow** - Repeat until six throws are collected. - Resolve the finished six-line pattern to a hexagram from `src/data/hexagrams.ts`. - Automatically route/open the corresponding hexagram info page/card already used by the app. 8. **Testing and verification** - Run the test suite. - Run a production build. - Deploy/restart the app process. - Verify live behavior in-browser: - sidebar entry exists - minimal fullscreen divination view opens - toss animation runs - line stack updates correctly - completed divination opens the matching hexagram # Design notes / pitfalls - The user strongly dislikes animations that look generic, cheap, repetitive, or janky. - Coins should feel intentionally designed; use ancient Chinese cash coin motifs, not plain circular tokens. - Make Yin/Yang side identity unmistakable at a glance. - Do not rely on color or tiny engraved coin details alone. The most readable pattern is redundant signaling: - explicit point values on the coins (`2` / `3`) - explicit line-shape cues (solid vs broken) - post-cast chip breakdown showing each coin contribution and the summed total - Important UX finding: even if an inline legend improves readability, the user may dislike it if it pollutes the ritual/minimal casting screen. Prefer keeping the main divination view sparse and moving teaching content behind a top-right `Learn` button that opens a focused panel or drawer. - The `Learn` panel should contain: - a very succinct explanation of coins, values, line formation, and bottom-up hexagram building - a readable historical background section - a second section on Chinese cultural/philosophical relevance with stronger emphasis on the mystical dimension of the Tao - Do NOT leave extra chip-like labels floating above or below each coin. The cleaner winning pattern was: - keep the main `Yin` / `Yang` word on the coin face - keep a small numeric badge (`2` / `3`) - keep the line-shape cue on the coin face - remove extra top/bottom label pills that clutter the toss stage - Yin should be visually cooler/darker and Yang warmer/brighter, but color is secondary to the line-shape + numeric cues. - If browser/visual QA says readability is only moderate, first increase coin size, label size, chip contrast, and the exaggeration of the broken-line gap before adding more always-visible instructional UI. - The user prefers impressive, high-effort microinteraction polish, especially on mobile. - For animation quality, a key root-cause lesson: if the final coin face is rendered from frame 1, the cast feels spoiled and fake. The better pattern is to make each coin truly double-sided in the DOM/UI structure: - front face = Yang / heads - back face = Yin / tails - animate coin flight separately from coin-body flipping - resolve the final result by ending rotation, not by showing the chosen face immediately - A single overloaded CSS transform tends to feel jerky/staged. A better structure is: - outer wrapper handles toss trajectory, drift, bounce, and settle - inner coin body handles continuous 3D flip rotation - front/back faces use `backface-visibility: hidden` - When the user explicitly wants a stronger non-CSS animation approach, move the toss to GSAP timelines rather than trying to over-tune keyframes. - use `useLayoutEffect` + refs for the coin shell, coin body, and shadow - animate flight path and body flip on separate GSAP tracks - keep test mode simple/bypassed so fake timers do not get stuck on animation internals - For realism/readability at rest, all coins should settle onto the same flat landing plane even if they overlap visually. - keep per-coin horizontal spread - use a shared or near-shared final `settleY` - let overlap happen through x/z composition, not by leaving coins at obviously different resting heights - Add visible thickness layers beneath the coin face so the coins read as solid metal discs rather than flat stickers. - subtle underside ring - inner thickness band - stronger contact shadow under each coin or cluster - To prevent the button/status stack from jumping during a cast, reserve fixed vertical space for: - cast count/status text - result line text - breakdown/hint area Use fixed-height slots so transitions between `Casting coins…`, score text, and chip breakdowns do not move the CTA. - Browser screenshots often miss transient animation frames. When visually checking live motion, supplement screenshots with DOM inspection (for example confirming `.coin-body.spinning` / throwing classes while a cast is active) rather than assuming a post-animation screenshot proves the motion quality. - Keep the screen uncluttered during divination; ceremonial focus matters. - If implementing classic changing lines later, keep current parity-based line generation isolated so it can be extended. # Verification commands ```bash cd /home/avalon/apps/iching-study npm test npm run build ``` Then redeploy using the app's existing PM2 workflow and verify the live site.