Chapter 2 Β· the apps
The current app is v4 (/v4, apps/sot/) β the Source-of-Truth app on Engine V4, documented first below with its critical states. Beneath it, the preserved v1 reference build at /figma-app: the founder's Figma file rebuilt as a navigable offline PWA, battle screens running the real 300-era engine (state in localStorage["rwf.figma.v1"]), gold theme, hash router, installable, fully offline via service worker. v2 (board) and v3 (3D course) have their own chapter on The four versions.
Every screenshot below comes from a headless E2E walk that plays the real product (v4: e2e.mjs 120 checks + e2e-states.mjs 59 checks; v1: e2e.mjs + e2e-daily.mjs). If a screen below exists, a test walked through it.
Ben's master spec as a working product: 5-tab nav per the SOT (Battle / Feed / central LOG / Power-Ups / Profile), near-black + gold loot presentation, hero numerals, and the full daily-battle β season β stake loop on the shared Engine V4. Onboarding through create-wizard (11 condensed steps), join-by-code with stake agreement, and the demo jump that seeds a live crew in one tap.






The journey a test walks: welcome + 3 explainers β profile (name / badge / tone) β create wizard (mode, identity, invite, battle days, 200 target, handicap review, exercises, season length, stake, power-up toggles, review) β group created with invite code + QR-style share β season live β Battle Home (adjusted hero, DZ ramp, close-call, live bombs) β Rep Steal (pure gain, asserted in state) β quick log with undo β keypad to 200 β first Daily Win (confetti, canvas PNG share card) β rival banks the day (streak) β deadline β failed days recorded β recap β season hub (1:1 standings, pot maths) β Surprise Bomb HIT and MISS β Lightning Γ3 on a real log β second Daily Win β season ends β charity chooser ($38.00 after the disclosed $2.00 fee) β receipt β join flow as a second player β language + console gates.
Where the copy rules live: tone-aware lines (cheeky / neutral / corporate-safe) on every winner and failure moment; "reps" always, RUF never (enforced by the e2e's language gate).
The SOT's screen inventory flags the states a product needs when things aren't sunny: the realtime link drops (#103), logs race each other (#105, #119), today isn't a battle day (#29, #101), and the day's winner is known while the season runs on (#102). All four exist in v4 as real states with their own e2e walk (e2e-states.mjs, 59 checks).








Offline / reconnecting (#103 + #104 + #120). The app is local-first, so the realtime link is a simulated connection shim β demo-toggleable from Settings ("Simulate offline"), which makes the whole surface testable. Offline: an amber banner leads every screen ("you can keep logging"), submitted sets land in a queue (a badge counts them on the central LOG button), and the queue survives reloads. Back online: a visible reconnecting beat, then the queue replays through the real engine and a toast reports the outcome.
Sync conflict (#105) + duplicate warning (#119). Duplicate detection runs on every submit β same exercise + same reps (post-conversion) inside 60 seconds by the same player. Live, that's the "did that set count?" sheet: log it anyway (confirm) or undo back to the confirm step. On replay, a queued set that raced an already-landed log becomes a sync conflict: keep both sets or drop mine β resolved one by one, with the outcome toast tallying kept vs dropped.
Rest-day home (#29 + #101). When the next battle is more than three hours out, Battle Home becomes the rest-day state: "REST DAY", streak-safe messaging (the returning player's π₯ streak named and kept safe), the next battle day + live countdown, the season's progress, and a season-hub jump. Rest days never touch streaks β stated, and true in the engine.
Battle complete but season live (#102). Two halves of one transition. Winner-known while the battle rolls on: a purple card names the Daily Win taker, pushes bank-your-own-day, and frames tomorrow (next battle, season points on the line). Battle ended while the season runs: the completed battle stays framed on the next battle's home β winner, banked/missed counts, tomorrow's angle, and the recap one tap away.

What. First paint: wordmark, tagline, the gold/lime theme toggle β the entry to onboarding.
How it works. Hash router (#/auth-008 style routes matching Ben's Figma frame names). The theme toggle flips data-theme="gold" β see Design System for what that means.



What. Three screens: pick a display name (avatar initials derive live), pick a fitness tier (couch / casual / fit / athlete β the handicap decision), done.
How it works. Draft state accumulates then persists the player object to rwf.figma.v1. The tier chosen here is the multiplier applied to every rep this player ever logs (see Game Rules).



What. Your battle cards: name, target, days, live standings snapshot, temporal state (which play day, when it closes). Empty state β create your first battle.
How it works. Renders from the matches array in state; each card recomputes its countdown chip via the daily layer, so the home screen is always temporal-state aware. The 6-player shot is the deliberate overflow/edge-case test from the design audit.

What. Name the battle, pick play days (week chips), pick a target preset.
How it works. Creates a match through the real engine: createMatch(config, players) with you + 3 demo mates (the demo roster), status open, and generates a CREW-XXXX code β the bridge token the bots use (link CREW-β¦).
createMatch
What. The pre-match lobby: who's in, the crew code, how mates join from WhatsApp/Slack, and a START EARLY button.
How it works. The share card shows the exact bot grammar (link CREW-XXXX) β the appβbot bridge is a shared code, not a shared login (state unification is tracked in Status β T5). START EARLY flips the match to live immediately.



What. The main screen: your progress ring (raw / target), the full leaderboard (adjusted score + verified %), the dual-clock countdown, comeback banner, danger-zone chrome, the big LOG button and the power-up button.
How it works. Leaderboard rows come from engine.standings(state) β the same function the bots use for their standings card. The ring tracks your raw reps against target; the board sorts by adjusted. Countdown + DZ chrome from the daily layer ticker (see Game Rules β danger zone).
standings Β· daily.js applyDzChrome

What. The core loop surface: tap LOG β tap a rep count chip β tap the CTA. Done, mid-workout, with sweaty hands.
How it works. The sheet shows your live conversion ("Γ1.5" for couch β what those reps are worth) and the CTA text mirrors the selection ("LOG 20 PUSH-UPS"). Confirming chains the engine's tag functions β applyComeback then applyLightning β appends the entry, and if the raw total crosses the target the match closes right there. Camera verify is offered inline for supported exercises.
logRepsAt






What. The full power-up journey: discover the button β open the arsenal β inspect a card β activate β feel it in toasts and on the live board.
How it works. All mechanics are specified in Game Rules β power-ups (Γ3/10min, 10% steal, shield-block, +30min freeze). The UI layer adds the feedback: steal shows a preview against the current leader before committing; a blocked steal explains that the shield was consumed and the card kept; lightning leaves a persistent countdown on the battle screen while the window is open.
activatePowerUp / stealPreview



What. The finale: final standings with medals, the closure bonus applied, the charity pot total, the winner's designation flow, and the one-tap REMATCH.
How it works. Result = finalStandings() (bonus applied, re-ranked) with confetti + count-up finale (motion budget: 1200ms β see Design). The pot panel shows the ledger total and, for the winner, the designation picker. Rematch creates a new match with the same roster and rules β "run it back" also exists as a bot command (rematch).
finalStandings / rematchState

What. Profile: identity, tier (changeable between matches), match record. Season ladder: the 4-week points table with MVP counts and division movement.
How it works. The ladder is seasonLadder() over recorded match results (3/2/1 + MVP β see Game Rules β seasons). The profile doubles as the settings surface for HR straps (resting HR / age β Karvonen) in the first-party app build.
Beyond the E2E journey, a 67-screenshot walk covers every frame in Ben's file β including screens the flow doesn't reach: wagers, corporate, social, edge cases, offline.





How it works. Every Figma frame was extracted with exact fills and bounding boxes from figma/assets/file.json and rebuilt as HTML/CSS (lane F4). The offline shot proves the service worker: with the network cut, the app still boots from cache β it's installable as a PWA (manifest.webmanifest + sw.js).
The full walk lives in apps/screenshots/figma-app/ (67 PNGs: auth-*, battle-*, create-*, corp-*, edge-*, home-*, integ-*, join-*, log-*, profile-*, pwr-*, result-*, set-*, social-*, wager-*, _offline-*) β the wiki ships the highlights.
A second app exists β ours, not Ben's β shipped at rwf.qalarc.com/app. It carries the verification lane (camera + HR) and the synced state demo.




How it works. Built from apps/web/src (bundled with Bun, deployed to /app), it shares the same engine port and adds the verifier surfaces: the camera sheet (MoveNet) and BLE HR pairing that feed verified:true + avgHrrPct entries β the wiki's Verification chapter documents those mechanics. The figma-app remains the design reference; this is the shipping surface.