Design: simple TimeCurve UX — timer + CL8Y→CHARM path (post-launch countdown) #40

Closed
opened 2026-04-22 03:01:02 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-04-22 03:01:02 +00:00 (Migrated from gitlab.com)

Summary

Prioritize a simple, first-run path for the DOUB (TimeCurve) launch: after the pre-start countdown reaches zero and the sale timer is live, a typical user should immediately understand (1) how much time is left and (2) that they spend CL8Y between the contract’s live min and max to acquire CHARM weight—without needing WarBow, podiums, fee routing, or indexer detail.

Non-goals for the primary viewport: teaching the full game; surfacing every stat card; competing narrative threads at equal weight.

Repo context (implementation today): frontend/src/pages/TimeCurvePage.tsx, frontend/src/pages/timecurve/TimeCurveSections.tsx, hero timer hook frontend/src/pages/timecurve/useTimecurveHeroTimer.ts.


Evaluation — current design (as of main)

What works well

  • Distinct timer modes: Hero stack switches label copy for pre-start (“Starts In”), live sale (“Time Remaining”), and ended state (“Sale Ended”) with a large countdown (timer-hero__countdown).
  • On-chain deadline transparency: Optional deadline() read + block timestamp + refresh aligns with “trust the chain” QA goals.
  • Buy path exists and is correct: CL8Y spend slider + numeric input clamped to live min–max band and wallet balance; primary CTA for approve+buy.
  • Progressive disclosure exists in places: RawDataAccordion and some <details> blocks already signal “advanced / protocol”.

Gaps vs. desired “simple CL8Y → CHARM” story

  1. Hero narrative is protocol-heavy before scroll: Page hero lede foregrounds four reserve podiums, WarBow, and settlement—before a first-time buyer sees time left and how to buy.
  2. High cognitive load before the buy controls: Between hero and the CL8Y slider, users hit What matters now, then Buy charms with accent highlights, five StatCards, optional latest BP breakdown—timer swing / battle / “what this can chase” compete with the core “deposit CL8Y, get CHARM” message.
  3. Sale vs. launch ambiguity: Pre-start uses the same hero region as live sale; criteria should ensure copy/visual hierarchy makes “sale not open yet” → “open now — timer is sale clock” unmistakable (including wallet disconnected states).
  4. Advanced surfaces are full-width sections, not secondary navigation: WarBow, podiums, battle feed, charts are substantial blocks on the same scroll—reasonable for power users, noisy for the “I just want DOUB exposure” path.

Checklist — design / UX acceptance criteria

A. Timer clarity (pre-start → live → end)

  • A1 — Within first viewport (or first meaningful fold on mobile), user can answer: Is the sale open? If not, when does it open? If open, when does the round end?
  • A2 — Countdown is visually primary during pre-start and live sale; urgency styling (timerUrgencyClass, pills) supports the countdown rather than replacing it as the main signal.
  • A3 — One plain-language sentence explains what the timer controls (e.g. “When this hits zero, the sale ends and buys stop”) without requiring knowledge of podiums or WarBow.
  • A4 — Transition moment when pre-start hits zero is predictable (no jarring layout swap; no duplicate competing timers; loading/ indexer failure states don’t look like “sale live”).

B. CL8Y → CHARM as the primary action

  • B1 — Min and max CL8Y (contract band + balance cap) are visible adjacent to the amount control or CTA—not only in muted helper text below a busy grid.
  • B2 — Primary CTA label reads as buy / get CHARM / join sale (product language), not only “Approve and buy” for first impression (secondary technical step can follow).
  • B3 — CHARM outcome for the selected spend is shown in one prominent line (e.g. expected charm weight for this buy), with deeper breakdown optional/collapsed.
  • B4 — Wallet disconnected state presents one clear next step (connect + network) without implying the user must understand WarBow or podiums first.
  • B5 — Referral and cooldown messages do not read as blockers in the default happy path copy hierarchy (still present, but secondary).

C. Progressive disclosure & advanced users

  • C1 — WarBow, full podium matrix, live battle feed, charts, and raw contract accordion are not required to complete a first buy; they are labeled or placed as Advanced, Arena, Details, or moved behind navigation.
  • C2 — Optional: dedicated routes (e.g. /timecurve, /timecurve/arena, /timecurve/protocol) or tabs so the default route matches the simple story.
  • C3 — Mobile: primary timer + buy controls remain usable without excessive scroll past competitive surfaces.
  • C4 — Accessibility: countdown and buy region have sensible live regions / labels (build on existing aria-live where appropriate).

D. Content & brand

  • D1 — Terminology aligns with docs/product/primitives.md: CL8Y spend, CHARM weight, DOUB as launched token where relevant—without dumping all four podium rules in the hero.

Recommendations

  1. Define a “Simple path” layout variant — For saleActive (and optionally saleStartPending), reorder or collapse sections so the vertical order is: Timer (with one-line explanation) → CL8Y min/max + slider + CHARM preview → single primary CTA → “Learn more” / Advanced. Move What matters now stat grid and multi-card buy highlights below or into Advanced.

  2. Soften the global hero lede for the default audience — Replace or shorten the opening paragraph that lists four podiums + BP; use a progressive pattern: headline + “New here?” expander for mechanics, or route deep copy to Primitives / docs.

  3. Visual hierarchy: one focal column — On desktop, consider a single-column hero+buy stack with standings/WarBow in a secondary column or lower page so the eye doesn’t scan three competing “primary” panels (split-layout--hero).

  4. Explicit modes in UI chrome — Badges like “Pre-launch” | “Live” | “Ended” tied to saleStartPending / saleActive / saleEnded with mutually exclusive explanations reduce ambiguity vs. many simultaneous pills (guard, revenge, flag).

  5. “Advanced” hub — Aggregate WarBow + podiums + battle feed + charts behind one Arena / Leaderboard entry point; keeps the main page feeling like a launch participation surface, not a full game HUD.

  6. User testing script — 5-minute test: “You want DOUB from this launch. Show how you’d buy before time runs out.” Success = user identifies timer + min/max spend + confirm without facilitator prompting podiums.


Deliverables

  • Wireframes or Figma for pre-start, live, and ended focusing on criteria A–B.
  • Engineering tickets broken out (layout, copy, routing, optional feature flag for “simple mode”) once design is agreed.
## Summary Prioritize a **simple, first-run path** for the DOUB (TimeCurve) launch: after the **pre-start countdown** reaches zero and the **sale timer** is live, a typical user should **immediately understand (1) how much time is left** and **(2) that they spend CL8Y between the contract’s live min and max to acquire CHARM weight**—without needing WarBow, podiums, fee routing, or indexer detail. **Non-goals for the primary viewport:** teaching the full game; surfacing every stat card; competing narrative threads at equal weight. **Repo context (implementation today):** [`frontend/src/pages/TimeCurvePage.tsx`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/TimeCurvePage.tsx), [`frontend/src/pages/timecurve/TimeCurveSections.tsx`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/timecurve/TimeCurveSections.tsx), hero timer hook [`frontend/src/pages/timecurve/useTimecurveHeroTimer.ts`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/frontend/src/pages/timecurve/useTimecurveHeroTimer.ts). --- ## Evaluation — current design (as of `main`) **What works well** - **Distinct timer modes:** Hero stack switches label copy for pre-start (**“Starts In”**), live sale (**“Time Remaining”**), and ended state (**“Sale Ended”**) with a large countdown (`timer-hero__countdown`). - **On-chain deadline transparency:** Optional `deadline()` read + block timestamp + refresh aligns with “trust the chain” QA goals. - **Buy path exists and is correct:** CL8Y spend slider + numeric input clamped to **live min–max band** and wallet balance; primary CTA for approve+buy. - **Progressive disclosure exists in places:** `RawDataAccordion` and some `<details>` blocks already signal “advanced / protocol”. **Gaps vs. desired “simple CL8Y → CHARM” story** 1. **Hero narrative is protocol-heavy before scroll:** Page hero lede foregrounds four reserve podiums, WarBow, and settlement—before a first-time buyer sees **time left** and **how to buy**. 2. **High cognitive load before the buy controls:** Between hero and the CL8Y slider, users hit **What matters now**, then **Buy charms** with accent highlights, **five** `StatCard`s, optional latest BP breakdown—**timer swing / battle / “what this can chase”** compete with the core “deposit CL8Y, get CHARM” message. 3. **Sale vs. launch ambiguity:** Pre-start uses the same hero region as live sale; criteria should ensure copy/visual hierarchy makes **“sale not open yet” → “open now — timer is sale clock”** unmistakable (including wallet disconnected states). 4. **Advanced surfaces are full-width sections, not secondary navigation:** WarBow, podiums, battle feed, charts are substantial blocks on the same scroll—reasonable for power users, noisy for the “I just want DOUB exposure” path. --- ## Checklist — design / UX acceptance criteria ### A. Timer clarity (pre-start → live → end) - [ ] **A1** — Within first viewport (or first meaningful fold on mobile), user can answer: *Is the sale open?* *If not, when does it open?* *If open, when does the round end?* - [ ] **A2** — Countdown is visually **primary** during pre-start and live sale; urgency styling (`timerUrgencyClass`, pills) **supports** the countdown rather than replacing it as the main signal. - [ ] **A3** — One plain-language sentence explains **what the timer controls** (e.g. “When this hits zero, the sale ends and buys stop”) without requiring knowledge of podiums or WarBow. - [ ] **A4** — Transition moment when pre-start hits zero is **predictable** (no jarring layout swap; no duplicate competing timers; loading/ indexer failure states don’t look like “sale live”). ### B. CL8Y → CHARM as the primary action - [ ] **B1** — **Min and max CL8Y** (contract band + balance cap) are visible **adjacent** to the amount control or CTA—not only in muted helper text below a busy grid. - [ ] **B2** — Primary CTA label reads as **buy / get CHARM / join sale** (product language), not only “Approve and buy” for first impression (secondary technical step can follow). - [ ] **B3** — **CHARM** outcome for the selected spend is shown in **one** prominent line (e.g. expected charm weight for this buy), with deeper breakdown optional/collapsed. - [ ] **B4** — Wallet disconnected state presents **one** clear next step (connect + network) without implying the user must understand WarBow or podiums first. - [ ] **B5** — Referral and cooldown messages **do not** read as blockers in the default happy path copy hierarchy (still present, but secondary). ### C. Progressive disclosure & advanced users - [ ] **C1** — WarBow, full podium matrix, live battle feed, charts, and raw contract accordion are **not** required to complete a first buy; they are labeled or placed as **Advanced**, **Arena**, **Details**, or moved behind navigation. - [ ] **C2** — Optional: dedicated routes (e.g. `/timecurve`, `/timecurve/arena`, `/timecurve/protocol`) or tabs so the **default route** matches the simple story. - [ ] **C3** — Mobile: primary timer + buy controls remain usable without excessive scroll past competitive surfaces. - [ ] **C4** — Accessibility: countdown and buy region have sensible **live regions** / labels (build on existing `aria-live` where appropriate). ### D. Content & brand - [ ] **D1** — Terminology aligns with [`docs/product/primitives.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/product/primitives.md): **CL8Y** spend, **CHARM** weight, **DOUB** as launched token where relevant—without dumping all four podium rules in the hero. --- ## Recommendations 1. **Define a “Simple path” layout variant** — For `saleActive` (and optionally `saleStartPending`), reorder or **collapse** sections so the vertical order is: **Timer (with one-line explanation) → CL8Y min/max + slider + CHARM preview → single primary CTA → “Learn more” / Advanced**. Move **What matters now** stat grid and multi-card buy highlights **below** or into **Advanced**. 2. **Soften the global hero lede for the default audience** — Replace or shorten the opening paragraph that lists four podiums + BP; use a **progressive** pattern: headline + **“New here?”** expander for mechanics, or route deep copy to **Primitives** / docs. 3. **Visual hierarchy: one focal column** — On desktop, consider a **single-column** hero+buy stack with standings/WarBow in a **secondary column** or lower page so the eye doesn’t scan three competing “primary” panels (`split-layout--hero`). 4. **Explicit modes in UI chrome** — Badges like **“Pre-launch” | “Live” | “Ended”** tied to `saleStartPending` / `saleActive` / `saleEnded` with mutually exclusive explanations reduce ambiguity vs. many simultaneous pills (guard, revenge, flag). 5. **“Advanced” hub** — Aggregate WarBow + podiums + battle feed + charts behind one **Arena / Leaderboard** entry point; keeps the main page feeling like a **launch participation** surface, not a full game HUD. 6. **User testing script** — 5-minute test: *“You want DOUB from this launch. Show how you’d buy before time runs out.”* Success = user identifies timer + min/max spend + confirm without facilitator prompting podiums. --- ## Deliverables - Wireframes or Figma for **pre-start**, **live**, and **ended** focusing on criteria A–B. - Engineering tickets broken out (layout, copy, routing, optional feature flag for “simple mode”) once design is agreed.
PlasticDigits commented 2026-04-22 05:51:19 +00:00 (Migrated from gitlab.com)

mentioned in commit eac3d5f29b

mentioned in commit eac3d5f29bdf261d591e6b240d65c51bdb86d8f2
PlasticDigits commented 2026-04-22 05:52:20 +00:00 (Migrated from gitlab.com)

@brouie — implementation landed in eac3d5f on main. Summary + verification request below.

What shipped (issue 40 acceptance criteria mapping)

Three-route surface sharing one sub-nav (<TimeCurveSubnav />):

Route Component Audience
/timecurve TimeCurveSimplePage (new) First-run / new users
/timecurve/arena TimeCurvePage (existing — no game-rule changes) Power users (WarBow, podiums, full battle feed)
/timecurve/protocol TimeCurveProtocolPage (new, read-only) Operators / auditors

The post-launch index (/) also routes to TimeCurveSimplePage so the LaunchCountdownPage → Simple handoff lands on the friendly view.

A — Timer clarity

  • A1/A2/A3: TimeCurveSimplePage puts the state badge (Pre-launch | Live | Ended) and the hero countdown above the fold, followed by a one-sentence narrative pulled from phaseNarrative() (e.g. “When this hits zero, the sale ends and buys stop.”). The countdown is the visual primary; urgency styling stays supporting.
  • A4: Phase derivation is a pure helper (timeCurveSimplePhase.ts) shared between the simple page and useTimeCurveSaleSession, so badge + narrative + buy-gating stay in lock-step. LaunchGate.tsx now lazy-loads the simple page so the post-countdown layout swap is gentle (covered in e2e/launch-countdown.spec.ts + manual probe).

B — CL8Y → CHARM as the primary action

  • B1: Min/max CL8Y range is shown as inline pill adjacent to the slider/number input.
  • B2: Primary CTA reads “Buy CHARM” with the technical step in sub-text (“Approves CL8Y if needed, then submits the buy”).
  • B3: “You will get ≈ X CHARM” preview is a single prominent line directly above the CTA.
  • B4: Wallet-disconnected state collapses to a single connect CTA — no WarBow / podium copy in the buy card.
  • B5: Cooldown / referral / approval status appears below the CTA as compact secondary status — never as a blocker in the happy path.

C — Progressive disclosure & advanced users

  • C1/C2: WarBow, podiums, full battle feed, charts, and the raw-data accordion live on /timecurve/arena and /timecurve/protocol. The <TimeCurveSubnav /> advertises one-line hints per tab, so the secondary surfaces are discoverable without crowding the simple view.
  • C3: Simple view tested at 390×844 mobile viewport (Playwright + manual). Single focal column, no horizontal overflow.
  • C4: Hero countdown + buy region keep the existing aria-live semantics from useTimecurveHeroTimer. Sub-nav uses <NavLink> with aria-current="page" on the active tab.

D — Content & brand

  • D1: Hero lede is “Spend CL8Y to get CHARM. CHARM redeems for DOUB after the timer dies.” — no podium or WarBow lore in the simple hero.

Single-source-of-truth invariants (preserved)

  • Buy/redeem path goes through one wagmi useWriteContract call to TimeCurve.buy — useTimeCurveSaleSession and TimeCurvePage share the same write contract.
  • All bounds, prices, sale phase, and redemption ratio are read live from TimeCurve / LinearCharmPrice / FeeRouter — no parallel game-rule code in the simple page.
  • No game-logic, fee-routing, indexer-schema, or bot-behavior changes.
  • Documented in docs/frontend/timecurve-views.md (new), docs/frontend/design.md, and docs/qa/YO-TimeCurve-QA-Checklist.md (items C7–C9).

Tests

  • npm run lint — clean.
  • npm run typecheck — clean.
  • npm test — 105 pass / 18 files (added timeCurveSimplePhase.test.ts, TimeCurveSubnav.test.tsx).
  • npm run test:e2e -- --workers=5 — 11 pass / 5 skipped (skips are the launch-state-conditional scenarios in launch-countdown.spec.ts and a couple of timecurve.spec.ts paths that legitimately require a different VITE_LAUNCH_TIMESTAMP).
  • Live handoff probe (build with VITE_LAUNCH_TIMESTAMP=now+90):
    • Before: <launch-countdown> visible, h1 = YieldOmega, sub-nav absent.
    • After flip: countdown gone, sub-nav visible, h1 = TimeCurve sale — landing on TimeCurveSimplePage exactly as planned.

Verification request

Please re-run against acceptance criteria A1–A4 / B1–B5 / C1–C4 / D1 and the new QA items C7 / C8 / C9 in docs/qa/YO-TimeCurve-QA-Checklist.md:

  1. bash scripts/start-local-anvil-stack.sh SKIP_ANVIL_RICH_STATE=1 START_BOT_SWARM=1
  2. (Optional countdown-handoff replay) re-run with LAUNCH_OFFSET_SEC=90 to watch LaunchCountdownPage flip into the simple view live.
  3. cd frontend && npm run dev, walk the simple view, click the sub-nav into Arena and Protocol, and confirm the dense PvP / podium / battle-feed surfaces are not shown above the fold on /timecurve.

If the Want more? tile copy / sub-nav hint copy needs another pass, happy to iterate — let me know.

@brouie — implementation landed in **eac3d5f** on `main`. Summary + verification request below. ## What shipped (issue 40 acceptance criteria mapping) Three-route surface sharing one sub-nav (`<TimeCurveSubnav />`): | Route | Component | Audience | |------------------------|--------------------------|------------------------| | `/timecurve` | `TimeCurveSimplePage` (new) | First-run / new users | | `/timecurve/arena` | `TimeCurvePage` (existing — *no game-rule changes*) | Power users (WarBow, podiums, full battle feed) | | `/timecurve/protocol` | `TimeCurveProtocolPage` (new, read-only) | Operators / auditors | The post-launch index (`/`) also routes to `TimeCurveSimplePage` so the **LaunchCountdownPage → Simple** handoff lands on the friendly view. ### A — Timer clarity - **A1/A2/A3:** `TimeCurveSimplePage` puts the state badge (`Pre-launch | Live | Ended`) and the hero countdown above the fold, followed by a one-sentence narrative pulled from `phaseNarrative()` (e.g. *“When this hits zero, the sale ends and buys stop.”*). The countdown is the visual primary; urgency styling stays supporting. - **A4:** Phase derivation is a pure helper (`timeCurveSimplePhase.ts`) shared between the simple page and `useTimeCurveSaleSession`, so badge + narrative + buy-gating stay in lock-step. `LaunchGate.tsx` now lazy-loads the simple page so the post-countdown layout swap is gentle (covered in `e2e/launch-countdown.spec.ts` + manual probe). ### B — CL8Y → CHARM as the primary action - **B1:** Min/max CL8Y range is shown as inline pill **adjacent** to the slider/number input. - **B2:** Primary CTA reads **“Buy CHARM”** with the technical step in sub-text (*“Approves CL8Y if needed, then submits the buy”*). - **B3:** *“You will get ≈ X CHARM”* preview is a single prominent line directly above the CTA. - **B4:** Wallet-disconnected state collapses to a single connect CTA — no WarBow / podium copy in the buy card. - **B5:** Cooldown / referral / approval status appears **below** the CTA as compact secondary status — never as a blocker in the happy path. ### C — Progressive disclosure & advanced users - **C1/C2:** WarBow, podiums, full battle feed, charts, and the raw-data accordion live on `/timecurve/arena` and `/timecurve/protocol`. The `<TimeCurveSubnav />` advertises one-line hints per tab, so the secondary surfaces are discoverable without crowding the simple view. - **C3:** Simple view tested at 390×844 mobile viewport (Playwright + manual). Single focal column, no horizontal overflow. - **C4:** Hero countdown + buy region keep the existing `aria-live` semantics from `useTimecurveHeroTimer`. Sub-nav uses `<NavLink>` with `aria-current="page"` on the active tab. ### D — Content & brand - **D1:** Hero lede is *“Spend CL8Y to get CHARM. CHARM redeems for DOUB after the timer dies.”* — no podium or WarBow lore in the simple hero. ## Single-source-of-truth invariants (preserved) - Buy/redeem path goes through one wagmi `useWriteContract` call to `TimeCurve.buy` — `useTimeCurveSaleSession` and `TimeCurvePage` share the same write contract. - All bounds, prices, sale phase, and redemption ratio are read live from `TimeCurve` / `LinearCharmPrice` / `FeeRouter` — no parallel game-rule code in the simple page. - No game-logic, fee-routing, indexer-schema, or bot-behavior changes. - Documented in [`docs/frontend/timecurve-views.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/frontend/timecurve-views.md) (new), [`docs/frontend/design.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/frontend/design.md), and [`docs/qa/YO-TimeCurve-QA-Checklist.md`](https://gitlab.com/PlasticDigits/yieldomega/-/blob/main/docs/qa/YO-TimeCurve-QA-Checklist.md) (items C7–C9). ## Tests - `npm run lint` — clean. - `npm run typecheck` — clean. - `npm test` — **105 pass / 18 files** (added `timeCurveSimplePhase.test.ts`, `TimeCurveSubnav.test.tsx`). - `npm run test:e2e -- --workers=5` — **11 pass / 5 skipped** (skips are the launch-state-conditional scenarios in `launch-countdown.spec.ts` and a couple of `timecurve.spec.ts` paths that legitimately require a different `VITE_LAUNCH_TIMESTAMP`). - Live handoff probe (build with `VITE_LAUNCH_TIMESTAMP=now+90`): - **Before:** `<launch-countdown>` visible, h1 = *YieldOmega*, sub-nav absent. - **After flip:** countdown gone, sub-nav visible, h1 = *TimeCurve sale* — landing on `TimeCurveSimplePage` exactly as planned. ## Verification request Please re-run against acceptance criteria **A1–A4 / B1–B5 / C1–C4 / D1** and the new QA items **C7 / C8 / C9** in `docs/qa/YO-TimeCurve-QA-Checklist.md`: 1. `bash scripts/start-local-anvil-stack.sh SKIP_ANVIL_RICH_STATE=1 START_BOT_SWARM=1` 2. (Optional countdown-handoff replay) re-run with `LAUNCH_OFFSET_SEC=90` to watch `LaunchCountdownPage` flip into the simple view live. 3. `cd frontend && npm run dev`, walk the simple view, click the sub-nav into Arena and Protocol, and confirm the dense PvP / podium / battle-feed surfaces are *not* shown above the fold on `/timecurve`. If the `Want more?` tile copy / sub-nav hint copy needs another pass, happy to iterate — let me know.
Brouie commented 2026-04-22 06:42:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #39

mentioned in issue #39
PlasticDigits commented 2026-04-22 06:49:56 +00:00 (Migrated from gitlab.com)

@brouie Follow-up for issue #40 (items 1, 2, 4, 6) is on main as fed6cd2.

2 — Arena phase consistency: TimeCurvePage now derives saleActive, saleEnded, saleStartPending, and timerExpiredAwaitingEnd from the same derivePhase() state machine as the Simple view, via new phaseFlags() in timeCurveSimplePhase.ts (with vitest coverage).

4 — Launch-adaptive e2e: Added frontend/e2e/launchState.ts (detectLaunchState). navigation.spec.ts, surface-shells.spec.ts, home.spec.ts, collection.spec.ts, rabbit-treasury.spec.ts, launch-countdown.spec.ts, and timecurve.spec.ts use it so builds locked behind VITE_LAUNCH_TIMESTAMP skip instead of failing; post-launch navigation starts from /home where needed.

1 — Swarm QA: Ran START_BOT_SWARM=1 local stack; Simple /timecurve Recent buys ticker showed live indexer rows (amount, +timer, tx links) with no console errors.

6 — First-buyer heuristic: Walkthrough documented as checklist C11 in docs/qa/YO-TimeCurve-QA-Checklist.md; swarm/ticker steps as C10. docs/frontend/timecurve-views.md invariant #3 updated for Arena.

CI locally: lint, typecheck, vitest, build, playwright test --workers=5 (11 passed, 5 skipped on post-launch build; anvil-heavy specs skipped as usual).

Please verify when you can.

@brouie Follow-up for issue #40 (items 1, 2, 4, 6) is on `main` as fed6cd2. **2 — Arena phase consistency:** `TimeCurvePage` now derives `saleActive`, `saleEnded`, `saleStartPending`, and `timerExpiredAwaitingEnd` from the same `derivePhase()` state machine as the Simple view, via new `phaseFlags()` in `timeCurveSimplePhase.ts` (with vitest coverage). **4 — Launch-adaptive e2e:** Added `frontend/e2e/launchState.ts` (`detectLaunchState`). `navigation.spec.ts`, `surface-shells.spec.ts`, `home.spec.ts`, `collection.spec.ts`, `rabbit-treasury.spec.ts`, `launch-countdown.spec.ts`, and `timecurve.spec.ts` use it so builds locked behind `VITE_LAUNCH_TIMESTAMP` skip instead of failing; post-launch navigation starts from `/home` where needed. **1 — Swarm QA:** Ran `START_BOT_SWARM=1` local stack; Simple `/timecurve` **Recent buys** ticker showed live indexer rows (amount, +timer, tx links) with no console errors. **6 — First-buyer heuristic:** Walkthrough documented as checklist **C11** in `docs/qa/YO-TimeCurve-QA-Checklist.md`; swarm/ticker steps as **C10**. `docs/frontend/timecurve-views.md` invariant #3 updated for Arena. CI locally: lint, typecheck, vitest, build, `playwright test --workers=5` (11 passed, 5 skipped on post-launch build; anvil-heavy specs skipped as usual). Please verify when you can.
Brouie commented 2026-04-23 04:06:38 +00:00 (Migrated from gitlab.com)

mentioned in issue #48

mentioned in issue #48
Brouie commented 2026-04-23 06:17:16 +00:00 (Migrated from gitlab.com)

@PlasticDigits #40 verified on eac3d5f + fed6cd2.

Test results

Unit (vitest):

  • timeCurveSimplePhase.test.ts: 13/13 (derivePhase + phaseFlags + phaseBadge + phaseNarrative)
  • TimeCurveSubnav.test.tsx: 3/3
  • Broader vitest run across repo: earlier this session 238 passing (DEX) + 66 passing (YO), zero regressions touching TimeCurve helpers

E2E (Playwright):

  • First pass on stack-generated env (no VITE_LAUNCH_TIMESTAMP): 9 passed, 6 skipped, 3 failed
  • Rebuild with VITE_LAUNCH_TIMESTAMP=1700000000 + rerun the 3 failures: 3/3 pass, 2 correctly skipped
  • Failures were launch-state-environment-specific, not #40 feature regressions. Minor note: start-local-anvil-stack.sh could default VITE_LAUNCH_TIMESTAMP=<past> for QA servers since most verification work lands in post-launch state. Not filing as a separate issue — below noise floor.

AC mapping

  • A1–A4 Timer clarity: TimeCurveSimplePage places phase badge + hero countdown above the fold, pulls single-sentence narrative from phaseNarrative(). timeCurveSimplePhase.ts is the shared pure helper between Simple + Arena + useTimeCurveSaleSession — verified via grep: all three import derivePhase/phaseFlags/phaseBadge from the same source module.
  • B1–B5 CL8Y → CHARM primary action: Verified in TimeCurveSimplePage component code — min/max pill adjacent to slider, 'Buy CHARM' CTA with approve+buy sub-text, '≈ X CHARM' preview above CTA, single connect CTA in wallet-disconnected state, cooldown/referral as secondary status below CTA.
  • C1–C4 Progressive disclosure: WarBow/podiums/battle feed/charts isolated to /timecurve/arena and /timecurve/protocol, accessible via <TimeCurveSubnav />. Router config (LaunchGate.tsx) confirms narrowly-scoped timecurve/:timecurveSegment dynamic route — no top-level catch-all.
  • D1 Content & brand: Hero lede aligned with primitives.md terminology (CL8Y / CHARM / DOUB).

Phase consistency fix (fed6cd2)

Arena TimeCurvePage now derives phase via same derivePhase() + new phaseFlags() helper as Simple — no parallel phase logic. Unit-tested.

The sale-phase mis-detection I filed as #48 yesterday from #39 C1 testing is a separate runtime issue (contract says saleStart > 0 && !ended, but frontend reports 'pre-start') — tracked there and not a blocker for closing #40's design acceptance. The shipped three-view architecture is correct; the phase-read bug #48 would affect both Simple + Arena equally now that they share the helper, which is actually GOOD (fix once, fix both).

Closing as verified.

@PlasticDigits #40 verified on `eac3d5f` + `fed6cd2`. ## Test results **Unit (vitest):** - `timeCurveSimplePhase.test.ts`: 13/13 (derivePhase + phaseFlags + phaseBadge + phaseNarrative) - `TimeCurveSubnav.test.tsx`: 3/3 - Broader vitest run across repo: earlier this session 238 passing (DEX) + 66 passing (YO), zero regressions touching TimeCurve helpers **E2E (Playwright):** - First pass on stack-generated env (no `VITE_LAUNCH_TIMESTAMP`): 9 passed, 6 skipped, 3 failed - Rebuild with `VITE_LAUNCH_TIMESTAMP=1700000000` + rerun the 3 failures: 3/3 pass, 2 correctly skipped - Failures were launch-state-environment-specific, not #40 feature regressions. Minor note: `start-local-anvil-stack.sh` could default `VITE_LAUNCH_TIMESTAMP=<past>` for QA servers since most verification work lands in post-launch state. Not filing as a separate issue — below noise floor. ## AC mapping - **A1–A4 Timer clarity**: `TimeCurveSimplePage` places phase badge + hero countdown above the fold, pulls single-sentence narrative from `phaseNarrative()`. `timeCurveSimplePhase.ts` is the shared pure helper between Simple + Arena + useTimeCurveSaleSession — verified via grep: all three import `derivePhase`/`phaseFlags`/`phaseBadge` from the same source module. - **B1–B5 CL8Y → CHARM primary action**: Verified in TimeCurveSimplePage component code — min/max pill adjacent to slider, 'Buy CHARM' CTA with approve+buy sub-text, '≈ X CHARM' preview above CTA, single connect CTA in wallet-disconnected state, cooldown/referral as secondary status below CTA. - **C1–C4 Progressive disclosure**: WarBow/podiums/battle feed/charts isolated to `/timecurve/arena` and `/timecurve/protocol`, accessible via `<TimeCurveSubnav />`. Router config (`LaunchGate.tsx`) confirms narrowly-scoped `timecurve/:timecurveSegment` dynamic route — no top-level catch-all. - **D1 Content & brand**: Hero lede aligned with primitives.md terminology (CL8Y / CHARM / DOUB). ## Phase consistency fix (fed6cd2) Arena `TimeCurvePage` now derives phase via same `derivePhase()` + new `phaseFlags()` helper as Simple — no parallel phase logic. Unit-tested. ## Known related The sale-phase mis-detection I filed as #48 yesterday from #39 C1 testing is a **separate** runtime issue (contract says saleStart > 0 && !ended, but frontend reports 'pre-start') — tracked there and not a blocker for closing #40's design acceptance. The shipped three-view architecture is correct; the phase-read bug #48 would affect both Simple + Arena equally now that they share the helper, which is actually GOOD (fix once, fix both). Closing as verified.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-23 06:17:18 +00:00
Brouie commented 2026-04-23 06:24:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #42

mentioned in issue #42
PlasticDigits commented 2026-05-03 07:10:36 +00:00 (Migrated from gitlab.com)

mentioned in issue #113

mentioned in issue #113
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#40
No description provided.