From e587e7e106afd534aa2e87d7b94d58a1233f3398 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Tue, 18 Aug 2026 22:11:29 +0200 Subject: [PATCH] docs: say that the board has two shapes now F1 described "one lane per game" as a fact about the timeline, which is now false half the time, and the prefs key space did not list the pref that decides it. Both say why the merged board sorts with endingSoonestFirst rather than a bare end date, since that is the part a later change is most likely to "simplify". Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 3 ++- docs/ARCHITECTURE.md | 1 + docs/DATA-MODEL.md | 7 +++++-- docs/PRD.md | 18 ++++++++++++++++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f57e6a1..23e4c42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -113,9 +113,10 @@ src/client/ React app, service worker, manifest useCustom.ts — the reader's own games and events (PRD F13) lens.ts — who sees which rows (focus, outstanding, next-to-expire); pure zoom.ts — the timeline's scale ladder; pure + lanes.ts — how the timeline stacks: a lane per game, or one deadline queue; pure scripts/ build-feed.ts, build-static.ts, parse-fixture.ts (offline), refresh-sources.ts (fetches) serve.ts static server + /api/health -test/ 599 tests +test/ 606 tests fixtures// raw HTML + .expected.json per source — pinned, kept forever snapshots/ current page per source, rewritten by refresh — see its README ``` diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4cf40b4..395cfe0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -126,6 +126,7 @@ src/ sort.ts deadline order, or what you're partway through lens.ts who sees which rows — focus, outstanding, next-to-expire zoom.ts the timeline's scale ladder; pure + lanes.ts how the timeline stacks — lanes, or one deadline queue; pure useAppUpdate.ts is a newer build waiting, and taking it (F14) serve.ts static server + /api/health ✓ built scripts/ diff --git a/docs/DATA-MODEL.md b/docs/DATA-MODEL.md index bb91ff1..07e7e95 100644 --- a/docs/DATA-MODEL.md +++ b/docs/DATA-MODEL.md @@ -218,12 +218,15 @@ Namespaced, versioned, and small. Nothing here ever goes to the server. "gacha-tracker:v1:daily" // { [id]: { days: ["2026-08-15", ...], at } } "gacha-tracker:v1:ignored" // { [eventId]: { at } } — "stop showing me this" "gacha-tracker:v1:prefs" // { region, hiddenGames[], knownGames[]?, focusGame, sort, view, - // timelineDayWidth, detectDaily, showCompleted, showIgnored, - // regionConfirmed, onboarded } + // timelineDayWidth, timelineGroup, detectDaily, showCompleted, + // showIgnored, regionConfirmed, onboarded } // timelineDayWidth is px per day on the board, stored as the // measurement rather than a step number and read through // snapDayWidth — so a value from an older ladder still opens // on something renderable. + // timelineGroup is "game" (a lane each) or "ending" (every game + // in one deadline queue). Defaults to "game", so shipping it + // moved nobody's board; see PRD F1. // knownGames is every lane the reader has been offered. Absent // means unrecorded, not "offered nothing" — see PRD F8; a lane // missing from it is new to them and arrives switched off. diff --git a/docs/PRD.md b/docs/PRD.md index d6bbe42..920cc2f 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -66,8 +66,8 @@ no stored key. A game may have several sources; see `docs/INGESTION.md` § Three ### Features **F1 — Timeline view.** -A horizontal timeline, one lane per game, spanning a scrollable date range with "today" pinned as a -vertical marker. Each event is a bar from `startsAt` to `endsAt`. Bars are colored by game, and +A horizontal timeline, by default one lane per game, spanning a scrollable date range with "today" +pinned as a vertical marker. Each event is a bar from `startsAt` to `endsAt`. Bars are colored by game, and completed events render at reduced opacity with a check. Clicking a bar opens a detail panel with title, type, exact start/end in the user's local timezone, source link, and a completion toggle. @@ -81,6 +81,20 @@ calendar on screen, and nothing left saying which day, whose game, or which even six-week bar starts weeks off-screen, so a name that rides off with its own start date leaves a coloured rectangle behind. +**The reader chooses how it stacks.** Lanes keep a game's events adjacent and comparable, which is +what makes the board readable for someone playing four of them — but that reader also has one queue +of deadlines, and lanes scatter it: what ends tonight sits three lanes below what ends next month, +and no scroll position puts them side by side. So a pair of pills in the board's header switches +between **By game** and **Ending soonest**, and the choice is remembered (`prefs.timelineGroup`, +default `"game"` — the board every existing reader already has). Merged, the order is +`endingSoonestFirst`, the same comparator behind the list's "Ending soonest" (F2), so the two views +cannot mean different things by the same words and an unannounced end still sorts behind every dated +one rather than claiming a place in the queue. Merged there is also no lane heading to say whose +event a bar is, and hue alone cannot answer that once thirteen games share a stack — so each bar +carries its game's short name, with the full name in its tooltip. A bar too narrow for a tag and a +title both keeps the title: a chopped game name reads as a broken word, and the hue and the tooltip +still answer it. + **The reader sets the scale.** A patch cycle is six weeks and a login campaign can run for months, so no single density answers both "what am I in the middle of this week?" and "how do the next three months line up?". A pair of controls steps through a ladder of day widths, and the choice is