iching-divination-coin-ui
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
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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
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.