makeover-timing 0.3.0

The time axis of the make-family design system: a duration is named by what it is waiting for, never by a number, and resolves the same on every renderer.
Documentation

makeover-timing

The time axis of the make-family design system. makeover resolves colour, makeover-geometry resolves distance, and makeover-layout names what a thing is without resolving anything. This crate answers the remaining question of the same shape: how long.

A duration is named by what it is waiting for

Moment What it waits for Resolves to
revert a control returning to its resting label after confirming 1500ms
clear a status line emptying itself 2000ms
dismiss a transient notice's lifetime 3000ms
debounce typing settling before the work starts 150ms

Whether a toast should live 3000ms or 3500ms is unanswerable on its own. Whether a message is a toast or a banner is not. That is the whole argument for the layer, and it is the same one gap-peer makes about six pixels.

One duration per moment, on every renderer

A moment resolves to exactly one duration everywhere, whatever the renderer and whatever the theme.

Distance has a renderer axis because a fingertip is coarser than a cursor and a terminal cell is coarser than a pixel: the surface differs. Time does not differ that way. A second is a second in a browser, in egui and in a terminal, and the reader waiting it out is the same reader. A divergence between renderers is a bug report.

What is deliberately not a moment

A race is not a moment. Waiting 300ms before navigating because the write "should" have landed, or 150ms before closing a dropdown so a mousedown can beat the blur, is a synchronisation bug wearing a duration's clothes. Naming those would launder them into design decisions. They get fixed per screen.

Severity is not a moment, and it is not a fifth number. A message the user must not miss does not go away on its own. makeover-layout already has the word for that (such a message is not Notice::transient), and a banner has no lifetime.

A poll interval is not a moment. A retry backoff, a health check, an update check: those are answerable from what they talk to, not from what a reader can follow.

Motion and cadence are separate axes

Moment says how long a state lasts. Motion says how long a change takes, and Cadence says how often a repeating mark repeats. CSS draws the first line itself, a setTimeout against a transition-duration: 300ms of fade and 3000ms of toast answer different questions.

Motion and Cadence both resolve to zero for a reader who has asked for less motion. A web surface gets that as a prefers-reduced-motion block in the generated stylesheet; every other renderer asks activity_blink with the preference its platform reported.

Using it

Web surfaces bake the stylesheet in at build time. Nothing here changes at runtime, so there is no load-time JS step:

use makeover_timing::timing_css;

std::fs::write("static/timing.css", timing_css())?;

egui and ratatui surfaces resolve through Duration instead, which is the reason this is a crate rather than a stylesheet:

use makeover_timing::{Moment, Motion, Persistence, notice_lifetime};

let settle = Moment::Debounce.duration();
let gone = notice_lifetime(Persistence::Transient).map(|life| life + Motion::Fade.duration());

notice_lifetime takes the description's answer to "does this go away on its own" rather than makeover-layout's Notice, so this crate stays off that dependency graph.

Licence

MIT.