Skip to main content

Crate makeover_timing

Crate makeover_timing 

Source
Expand description

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.

The move is the one the family makes everywhere. A duration is named by what it is waiting for, and the number follows:

MomentWhat it waits forResolves to
Moment::Reverta control returning to its resting label after confirming1500ms
Moment::Cleara status line emptying itself2000ms
Moment::Dismissa transient notice’s lifetime3000ms
Moment::Debouncetyping settling before the work starts150ms

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 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.

A per-renderer table, resolving the way Density resolves gaps, is the wrong shape. 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.

So a divergence here is a bug report.

§What is deliberately not a moment

Three classes are out of scope, and leaving them out is most of what makes the four above coherent.

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 and give every future one a token to hide behind. They get fixed per screen.

Severity is not a moment either, and it is not a fifth number. A longer lifetime for an error toast is one statement in disguise: a message the user must not miss does not go away on its own. makeover-layout already has the word for it: such a message is not Notice::transient. It is a banner, and a banner has no lifetime. See notice_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, and nothing here has an opinion about them.

§Motion is a separate axis

Moment says how long a state lasts. Motion says how long a change takes. CSS itself draws that line, a setTimeout against a transition-duration, and folding the two together makes a “timing scale” unusable: 300ms of fade and 3000ms of toast answer different questions.

Motion is an enum rather than a constant so a second measured transition has somewhere to go. It grows when something is measured.

§Cadence is a third question

Moment is how long a state lasts and Motion is how long a change takes. Both are one-shot: something starts, it ends. Cadence is how often a repeating mark repeats, which neither of the other two can answer without lying about its own shape.

The crate header’s exclusion of poll intervals does not cover it, and the difference is the same one that exclusion rests on. A backoff or a health check is answerable from what it talks to. How fast a mark may blink before it reads as an alarm is answerable from the reader, which is what every rung in this crate is answerable from.

§Reduced motion

Anything whose whole existence is movement has a motion-off path, and Cadence is that. A duration that is not animating anything is unaffected: Moment::Debounce is a wait, and reducing motion does not make input settle faster.

Two halves, because a browser and an egui window learn about the preference differently. A web surface gets a prefers-reduced-motion block in the generated stylesheet and needs no code. Every other renderer asks activity_blink, or blink for the phase, with the MotionPreference its platform reported, as it asks notice_lifetime with the Persistence the description gave.

§The numbers

Each value is pinned by a test. Changing one is a design decision about every consumer at once, so the test failing is that argument happening out loud. What each is answerable to is stated on the member.

§Consumers

Web surfaces bake timing_css in at build time. Nothing here changes at runtime, so there is no load-time JS step, exactly as with geometry. egui and ratatui surfaces read Moment::duration instead, which is why this is a crate rather than a stylesheet.

Enums§

Cadence
How often a repeating mark repeats.
Moment
A duration named by what it is waiting for.
Motion
How long a change takes, as opposed to how long a state lasts.
MotionPreference
Whether the reader has asked for less motion, as their platform reported it.
Persistence
Whether a notice goes away on its own.

Functions§

activity_blink
How fast the activity mark blinks, given whether the reader has asked for less motion.
blink
Which state the activity mark is in, elapsed into a wait, and how long it holds that state.
notice_lifetime
How long a notice lives, given whether it goes away on its own.
reduced_motion_css
The motion-off block, for a reader who has asked for less of it.
timing_css
The time axis as a stylesheet, inside the family’s cascade layer.
timing_css_declarations
Emit the time axis as CSS declarations, no selector.
timing_css_vars
Emit the whole time axis: a :root { ... } block, then the motion-off block.