haux.studio

Section 09

Motion

Five behaviours cover everything that moves, each with a curve, a duration band and the properties it may touch. One rule sits above all five: nothing bounces.

09 · Motion

One prohibition governs the whole system, and it has no exception band. Read it before the five behaviours, because it constrains all of them.

Nothing bounces

Nothing bounces. No elastic, no overshoot, no back-easing.

An overshoot reads as a visual second guess: the element arrives, changes its mind, and corrects. The claim this studio makes is that the thinking happened before the work shipped, and a bounce contradicts it every time it plays.

There is no exception band on this rule. If a transition feels flat, it gets a shorter duration or a sharper curve, never a wobble.

That constraint is also why the five curves below are all monotonic. Every one of them arrives and stops.

Arrives fast. Lands soft. Holds still.

Settle, which is the shape of the whole system

The five behaviours

Anything that moves is one of these five. A transition that fits none of them is a transition that has not been decided yet.

Settle, Strike, Hold, Track, Trim

Behaviour · Settle

Every entrance.

Specification

Curve: cubic-bezier(0.16, 1, 0.3, 1)

Duration: 620ms for a hero, 420ms for a section, 280ms for a card

May touch: transform and opacity only, 24px maximum travel, 45ms converging stagger

How it behaves

Arrives fast, lands soft, holds still. Most of the distance is covered in the first third of the duration, and the remainder is the part that reads as considered.

Travel is capped at 24px. Beyond that the element stops arriving and starts flying in, which is a different and much cheaper effect.

The stagger converges: 45ms between the first items, tightening across the sequence so a list of twenty does not take four times longer to resolve than a list of five.

The tell: If it is still moving when the eye reaches it, the duration is wrong.

Curves are written as CSS values so they can be pasted rather than retyped. Retyping a bezier is how a system ends up with four curves that are almost the same.

Reduced motion

A reduced-motion setting that quietly disables an interface is worse than one that keeps every control responding. This is what each behaviour becomes when the preference is set.

The contract, published rather than implied

What each behaviour becomes

Settle becomes a 120ms opacity fade. No travel, no stagger, no transform.

Strike keeps its full timing. It is feedback rather than decoration, and removing it removes the confirmation that a control was pressed.

Hold stops. An ambient loop has no function beyond atmosphere, so it is the first thing to go.

Track goes static. Elements sit at their resting position and nothing follows the pointer.

Trim becomes instant. There is no value in animating a removal that the person has already decided on.

WebGL renders one frame and freezes. The scene still appears, and it stops being a scene.

Publishing the contract is the point of this module. Most systems implement a reduced-motion branch and never write down what it does, so nobody can check it and nobody can rely on it.

Keeping Strike at full timing is the decision most often got wrong. Stripping feedback along with decoration leaves an interface that appears not to respond, which is a worse outcome than the motion it removed.

Do and don’t

Each pair below is a default that arrives with a library rather than a choice anyone made. Defaults are where a motion system leaks.

The four ways this system gets broken

  1. Nothing bounces, including at small amplitudes.

    Do

    Settle at 420ms on cubic-bezier(0.16, 1, 0.3, 1). It arrives, lands and holds.

    Don't

    A spring with 8% overshoot on the same element. Small enough to argue about, large enough to read as a correction.

  2. Exits are shorter than entrances.

    Do

    Trim at 160ms against a 280ms card entrance. Attention returns to the page immediately.

    Don't

    A 280ms fade out mirroring the entrance. The interface reads as reluctant to close.

  3. Strike starts on frame one.

    Do

    Press state at 120ms, with the change already visible on the first frame.

    Don't

    A 60ms wind up before the state changes. It is imperceptible as animation and perceptible as lag.

  4. Track lags on purpose.

    Do

    A critically damped lerp, capped at 40px of parallax across the full scroll range.

    Don't

    An element pinned 1:1 to the pointer. It feels attached to the mouse rather than to the page.

Open

Five things are undecided, and three of them will be decided by whoever builds the next project unless they are settled first.

What is not specified yet

The curves are not in the token file. They are retyped per project, which is how a system ends up with four beziers that are nearly identical and none of them canonical.

Route transitions are unspecified. Nothing here says what happens between two pages, and that is the most visible motion decision on any site.

Loading and skeleton behaviour is undecided. It is the one case where an ambient loop has a job, which makes it a genuine exception to Hold rather than an oversight.

Video and WebGL carry no rules beyond the reduced-motion freeze. Autoplay, looping and first-frame posters all need a position.

Sound has never been discussed. That is a decision, not an omission, and it should be written down as one.