Skip to content

feat(design): Notte — the schedule as a night instrument - #296

Closed
JanWelker wants to merge 2 commits into
mainfrom
design/notte-timeline
Closed

feat(design): Notte — the schedule as a night instrument#296
JanWelker wants to merge 2 commits into
mainfrom
design/notte-timeline

Conversation

@JanWelker

Copy link
Copy Markdown
Owner

Knead Time is about elapsed time in the dark — a fridge at 4 °C for a day and a half while you sleep — so this redesign draws it as an instrument for that night instead of a form with a table beside it.

The page in dark mode after the redesign

What a user sees differently

Above everything: a now band. A full-width panel sits directly under the header, above the two-column grid, in every layout. It says what you should be doing (Now / Next / Done plus the step name), how long is left in one large figure, and draws the whole bake to scale — warm phases in ember, fridge phases in cold blue, the 22:00–08:00 hours washed over, and a playhead at now. Previously the app's single most valuable fact was a 12 px pulsing dot inside a list that sat two screens below the fold on a phone.

The band is a night face in both themes: on a page of warm daylight paper it stays a lit dark panel, because the thing you need to read across a kitchen should not be the same colour as the form.

Before After
Before, daylight After, daylight

Phone. The answer is now above the fold; the form starts below it.

Before After
Before, phone After, phone

Schedule. The rail turns blue leaving a fridge step and a fridge phase gets a blue hollow node, so the cold stretch is findable in the list the same way it is on the bar. Times are set in the display face with lining tabular figures, so a column of them scans straight down. Durations became .gauge readings rather than grey badges. The current step's node is the one glowing thing in the list.

Form. Recedes into a control surface: inset fields that sink into the panel, one .field-label shape, hairline rules instead of another round of cards.

Window slider. The two tolerance bands were two shades of one green that said nothing about which leg was which. They are now the same two colours as the overview bar.zone-room warm, .zone-cold blue — so "what this flour tolerates in the fridge" is legible as a colour.

Ingredients, My recipes, Community, 50 Top Pizza. The three collapsed collections became .card-quiet: an outline on the page rather than three more panels of equal weight. The ingredient amounts are tabular figures.

Mode. ModeBadge became ModeGauge and moved into the band, where it is also the legend for the blue on the bar.

The band on a biga + poolish cold plan

The system

Three ramps, and the third is reserved. notte is the warm neutral (espresso, never slate) and carries every surface and every piece of text in both themes. ember is heat: room temperature, the active step, every filled control. frost is cold and nothing else — a blue thing on this page is in the fridge. That reservation is what makes temperature legible as colour, and it is written into app.css and CLAUDE.md as a rule, not a convention.

Surfaces and ink are named once and flipped as a set. --kt-ground / -panel / -raised / -inset / -line / -line-strong / -ink / -ink-soft / -ink-faint / -accent / -accent-solid / -on-accent / -cold / -warm-band / -cold-band / -night-wash / -glow are declared on :root and redeclared on .dark. Component classes read those names and carry no dark: pairs of their own — which is also what lets .now-band re-theme its whole subtree with one block.

New component classes (@layer components in app.css): .card-quiet, .panel-heading, .now-band, .night-bar, .night-seg{,-warm,-cold}, .night-wash, .night-wash-swatch, .playhead, .zone-room, .zone-cold, .window-card, .state-chip{,-live,-idle}, .gauge, .num, .ink{,-soft,-faint}, .text-cold, .field-label, .popover-panel. .btn-tomato{,-sm}.btn-ember{,-sm}. .card, .input, .pill*, .notice*, .menu-item, .dialog-panel, .row-divider, .text-accent, .link-* kept their names and changed their look.

Typography. --font-display is now a condensed grotesque (Avenir Next Condensed / Bahnschrift / Roboto Condensed) rather than a serif — a station board and an oven timer use one for the same reason: it holds a long time in a narrow column and its figures line up. Every platform in the support matrix ships one, so nothing is downloaded and the app still works with no network. .num adds tabular figures and a little tracking; times, durations, weights and temperatures wear it and prose does not.

Glow is spent on two things only — the current step's node and the playhead. No page-load animation, no hover transitions on cards.

New code

src/lib/timeline.ts is the pure geometry behind the overview bar: the axis span, a segment per step, the night bands, where "now" falls. It is deliberately not in src/lib/dough/ — it computes no dough, so it stays outside the "Get nerdy" contract — and it is at 100 % coverage with 19 unit tests. computeSchedule and everything in src/lib/dough/ is untouched; every share URL reproduces the same recipe.

Browser-only faults this found, each with a test

e2e/now-band.spec.ts (5 tests) exists because building this surfaced four things no unit test could see:

  • The playhead was invisible. Drawn in the same ember as the phase under it, and inside the bar, which clips its contents so the segments keep its corners. It is now a sibling of the bar and ink-coloured. Pinned by geometry (it overhangs the bar) and by colour (it differs from both segment colours).
  • The night key painted as a hole — a transparency on a transparent background, so the legend said "Night" beside an empty square.
  • The band and the list could disagree about "now." They decide it by different rules (nowState() partitions the axis; the table compares each step against its own duration), so a boundary could split them. Pinned as an equality.
  • A fixed focus ring failed contrast in daylight — one ember sat at about 2:1 against the paper panel, under the 3:1 a focus indicator needs. It reads a theme-flipping token now; axe checks text contrast but not focus indicators, so this needed its own test.

Two more fixes came out of running axe: --kt-accent-solid is a deeper ember in daylight under warm white and a brighter one at night under near-black (the ramp's mid-ember carried small white text at 4.09:1), and .pill lost its colour transition, which was also animating the theme flip and left axe measuring a pill halfway between two palettes.

Notes

  • Version bumped to 6.11.0. No URL schema key changed, so CURRENT_VERSION stays 6. This will conflict with the three sibling redesign PRs, which all bump to the same number — expected, and trivial to resolve on merge.
  • playwright.config.ts now reads E2E_PORT (const PORT = Number(process.env.E2E_PORT ?? 4173)), so four agents can run the suite on one machine. All four PRs make this identical one-line change.
  • The dark theme is the one that was designed first, but the theme resolution is unchanged: a fresh visit still follows the system preference. Making dark the unconditional default would be a contract break for returning users and a major bump.
  • The print route and the TRMNL payload are untouched. Print still fits one A4 page in B&W for the 9-step biga + poolish cold plan — verified by hand. It picks up the new display face for its headings, which it has always inherited from app.css's base h1, h2, h3 rule.
  • New i18n keys (schedule.now_*, schedule.bar_*) added to all five locales.

Checks

Check Result
npm run lint pass
npm run check pass, 0 errors
npm run test:coverage pass — 959 tests, 100 % statements/branches/functions/lines
npm run test:baseline pass — raised to 959 unit / 95 browser
E2E_PORT=4182 npm run test:e2e pass — 95/95, including axe in both themes and both view modes

Verified by eye at 390 px and 1440 px, light and dark, on a cold plan, a room plan, a biga + poolish cold plan, beginner and expert, plus the print sheet.

One honest note: e2e/recipe-output.spec.ts › "the print sheet weighs exactly what the screen weighs" failed once under parallel load early in this work and has passed every run since, alone and in the full suite. I could not reproduce it and it touches nothing this branch changes, so I have left it rather than paper over it — worth knowing about if it reappears in CI.

The app is about elapsed time in the dark, so it is drawn as an instrument
for that night rather than a form with a table beside it.

- NowBand: a full-width hero above the grid answering what to do and how
  long is left, with the whole bake on one proportional bar — warm phases,
  fridge phases in cold blue, the 22:00-08:00 hours washed over, a playhead
  at now. It is a night face in both themes.
- src/lib/timeline.ts: the pure geometry behind the bar, outside
  src/lib/dough/ because it computes no dough. 100 % covered.
- One palette in three ramps (notte / ember / frost) with frost reserved
  for the fridge, and every surface and ink named once as --kt-* tokens
  flipped as a set on .dark. Component classes carry no dark: pairs.
- Condensed display face plus tabular figures for every time, duration and
  weight; glow spent only on the current step's node and the playhead.
- e2e/now-band.spec.ts covers the four browser-only faults this found: the
  playhead painted in the phase's own colour and clipped by the bar, the
  night key painting as a hole, the band and the list disagreeing about
  now, and a fixed focus ring that failed contrast in daylight.

Version 6.11.0 (minor: user-facing, no URL schema change).
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://JanWelker.github.io/knead-time/pr-preview/pr-296/

Built to branch gh-pages at 2026-09-07 10:53 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@JanWelker

Copy link
Copy Markdown
Owner Author

Closing: design variant not chosen. #300 (Servizio × Bottega) merged as v7.0.0.

Notte had the best single product idea of the seven: the now-band — what to do, how long is left, and the whole bake as a proportional bar with the night hours shaded and a playhead at now. Nothing in v7 replaces that, and it would sit naturally at the top of the merged plan view. The rule that colour means temperature (blue reserved for the fridge, spent nowhere else) is also worth carrying forward.

Kept for reference rather than deleted.

@JanWelker JanWelker closed this Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant