Product UI

Show a product through its real interface, and move each surface the way the real one moves.

A film about a product shows the product working, in its real interface: a capture, or a faithful copy built as a page component. A grey window with a word in a box is not a beat.

Why it exists

The rule show-real-thing says that each beat shows a real artifact working. A hand-written mock has a grey window, small type and a sparse grid. In a measured comparison, reference films filled 0.71 of the frame with picture, and a first mock filled 0.17.

The viewer also knows how ChatGPT, GitHub or a terminal behaves. A copy that moves differently reads as fake.

Choose the source of the screen

Take the first option that fits.

  1. Capture the real product. A capture of the real UI beats any mock. bin/vawe shot <target> --tour <steps.json> drives a drawn cursor through a route or URL with real mouse events and writes an mp4. Add --scale 3 for a sharp close-up.
  2. Copy a real interface as a component. The Product moments group of the moves library has faithful copies: terminal-run, approval-gate, model-picker, diff-card, ai-stream-response, agent-progress, command-palette-summon and more. Each copies one real surface with its real type, colours and behaviour.
  3. Design an interface for an invented product. Build it as a real interface: real-looking data, and controls that do something. Do not make functionless chrome.
Go down the list only when the option above does not fit.

Build an invented interface

The design kitThe design kit is films/<name>/DESIGN.md and the kit/ folder: the palette, the type, the ground and the parts of one film. has a skill ladder with five rungs: builder, type, colour, depth and frame. The builder rung builds product UI as a real interface. The frame rung then removes web-page patterns such as a nav, a CTA button, a pill or an eyebrow. Use both: build the parts at the builder rung, and clean the frame at the frame rung. See Design kit.

Rules for the screen (taste/craft/show-dont-tell.md):

  • One focal element for each screen: the prompt in an editor, the hero tile in a grid.
  • Fill most of the frame. Use display-size type, never web-size type.
  • Show real images whole. Set each cell to the aspect of its source, so object-fit: cover does not crop.
  • Take colour from theme tokens, with one accent.
  • Make every claim in the copy true.
  • Check the laid-out page, not the source. Read the real box of each element against the frame and the safe margin.

A screen that is the subject of the film goes in an element with data-ui. Its text floor is 3 percent of the frame height as cap height, not 6 percent, because it is sized like a real screen. No text on a built screen is under 28 px at 1920 wide.

<div data-ui class="app"> ... </div>

Move a surface the way the real one moves

A copy must move as the real surface moves. A product that animates nothing must not animate in the copy.

surfacehow it movesmove that shows it
terminalEvery character, row and swap lands in whole steps on one frame. No ease, no fade, no scale.terminal-run, approval-gate
web page already loadedThe page is whole. State changes swap on one frame, such as a checks chip or a badge.diff-card
chatThe prompt types at a steady rate. The answer streams in chunks of 1 to 3 words.ai-stream-response
menu or dialogA short fade and a small scale. The selection mark moves on one frame.model-picker, command-palette-summon
window or panelFades in with at most a few pixels of rise. No scale.any move that uses arrive

Only the window arrives with an ease in a terminal clip, and that is clip framing, not the product. The text inside the window never eases.

No invented overshoot

Overshoot is a snap on a small, fast arrival of 3 to 20 px. A large panel does not overshoot. Do not add a spring or a bounce where the real interface has none. The overshoot-share check compares a whole film with reference films, so use overshoot for the arrival that matters and not for the interface. See Motion.

The measured numbers

core/motion/ui.js holds the timing of real product screens, in milliseconds, read from reference clips. core/motion/presets.js re-exports it as UI.

import { UI, EASE } from '../../core/motion/presets.js';
namevaluewhat it measured
UI.typing30 ms a character, 70 ms more after a space, 25 percent jitter20 to 27 characters a second with pauses at word gaps
UI.stream55 to 110 ms between chunks, 200 ms fade15 to 25 words a second
UI.sendspring k 500, d 25a sent bubble overshoots 11 to 14 percent
UI.panel220 ms fade, 0.8vh risea window fades in with no scale
UI.row300 ms fade, 70 ms staggerrows 70 to 100 ms apart
UI.roll150 ms out, 260 ms ina digit rolls in its own clipped slot
UI.exit300 ms, a 100 ms empty endthe window fades to the empty ground; frame 0 is the same ground
UI.snapovershoot 0.09 to 0.2a snap on small, fast arrivals

The presets are for surfaces that animate. A terminal steps, and only UI.typing and UI.panel apply to it. Seed the typing jitter with rng.

Build a product beat

Pick the source from the list above. For a real product, capture it with bin/vawe shot.

bin/vawe shot https://example.com/app --tour tour.json --w 1600 --scale 2 --out out/app-tour.mp4

Pick a Product moments move that matches the surface. Open prompts/moves/<move>.md and read the paragraph that starts with “Use when”. It says which real surface the move copies.

Copy the snippet. Keep the type, colours and timing of the copy. Change only the content: the prompt text, the file names, the numbers.

Put the screen in one world with data-world, with the UI in a data-ui element. See Worlds.

Draft the beat and look at the frames. Check that the claim in the copy is true and that the click shows its result.

bin/vawe dev films/<name>/page.html --from 4 --to 9

To film the screen as a physical object, with tilt, depth and bloom, give it to the lens. See Lens and effects.

Troubleshooting

what you seewhywhat to do
The screen looks like a web template: grey, small type, sparse.A hand-written mock, with no builder rung.Fill the frame, use display-size type, one focal element. Run the builder rung of the ladder.
The copy looks fake, but the layout is right.It moves differently from the real surface.Compare with the table above. Remove the ease from a terminal and the scale from a panel.
A click shows no result.The next frames do not show what the click did.Add the result state on the frame of the press.
readable-text-size advice on UI labels.The UI is the subject but has no data-ui.Put the screen in a data-ui element, or raise the type.
A copied move has too much overshoot.The move uses a spring for a large panel.Use EASE.land for the panel and keep the overshoot for a small snap.

From the blogProduct launch video generator from a website URL · CSS animation library: 126 copyable video components

On this page