EngineeringAugust 5, 2026· 13 min read

How automatic zoom actually works (and why most implementations feel wrong)

A technical walkthrough of framing a zoom on intent rather than on coordinates, and the easing decisions that separate a camera operator from a slideshow.

TATom AldridgeEngineering, DemoRiff

Automatic zoom is the feature people notice first and the one that most often feels subtly wrong. This post is about why.

The naive implementation

The obvious approach: detect clicks, and for each click, scale the frame around the cursor position for some fixed duration.

This produces output that is technically correct and viscerally unpleasant. Three reasons.

  1. 1The cursor is not the subject. When you click a button, the interesting region is the button and what it affects — not the twelve pixels under the pointer.
  2. 2Fixed duration ignores what happens next. A click that opens a modal needs the zoom to hold; a click that navigates needs it to release immediately.
  3. 3Linear scaling reads as mechanical. Real camera movement has acceleration and settle.

Framing on intent

Our recorder captures the DOM element that was interacted with, along with its bounding box, role and accessible name. That changes the framing problem from “zoom toward a point” to “compose a shot containing this element and its consequences.”

Concretely, for each interaction we compute a target rectangle from the union of: the interacted element's bounds, any element that changed within 400ms of the interaction, and a padding margin proportional to the element's size. Then we fit that rectangle into the output frame with a maximum scale cap.

typescript
function targetRect(event: InteractionEvent, mutations: Mutation[]): Rect {
  const consequences = mutations
    .filter((m) => m.at - event.at < 400 && m.at >= event.at)
    .map((m) => m.bounds);

  const union = consequences.reduce(unionRect, event.element.bounds);

  // Padding scales with the element so a small button does not get a
  // claustrophobic frame and a large panel does not float in dead space.
  const pad = clamp(Math.sqrt(area(event.element.bounds)) * 0.85, 24, 160);

  return inflate(union, pad);
}

The mutation window is the part that matters most. It is what makes the zoom frame a dropdown that opens below the button, rather than framing the button and leaving the dropdown off-screen — which is the single most common failure in naive implementations.

Hold duration from consequence, not from a constant

How long a zoom holds should be a function of how long the thing it is framing remains interesting. We derive it from three signals: how long until the next interaction, whether the framed region is still mutating, and whether the narration is still talking about it.

That last signal is available because we have an aligned transcript. If the narration says “and here the rate appears” at 0:34 and continues describing it until 0:41, the zoom holds until 0:41 regardless of whether the user clicked something else at 0:36.

Why this matters more than it sounds

Zoom timing driven by clicks alone produces video that fights the narration. Zoom timing driven by narration produces video that illustrates it. The difference is the whole thing.

Easing, and why most tools get it wrong

A camera operator pushing in does not move at constant velocity. There is acceleration at the start, a longer coast, and a settle at the end that overshoots very slightly and returns.

Most implementations use ease-in-out, which is symmetric and reads as mechanical. We use an asymmetric curve with a fast start, a long tail and a tiny overshoot — closer to a critically damped spring than to a cubic bezier.

typescript
// Asymmetric push: quick departure, long settle, 1.5% overshoot.
const push = (t: number) => {
  const e = 1 - Math.pow(1 - t, 3.2);          // fast out
  const overshoot = Math.sin(t * Math.PI) * 0.015;
  return e + overshoot * (1 - t);              // decays to zero at t=1
};

The overshoot is 1.5%. It is invisible frame by frame and unmistakable in motion. Remove it and viewers describe the result as “fine”; include it and they describe it as “professional,” without being able to say why.

Knowing when not to zoom

The hardest part is restraint. A demo that zooms on every click is exhausting. We suppress zooms when: the previous zoom ended less than 1.2 seconds ago, the target rectangle is more than 70% of the frame, the interaction is part of a rapid sequence the viewer does not need to follow individually, or the narration is describing something general rather than something specific.

In practice this cuts the number of zooms by about 60% from the naive count, and every user study we have run prefers the reduced version.