Lab Mock content
Four decisions that changed the feel.
The card interaction study went through more than forty iterations. These are the four changes that mattered most. Each one runs the same recorded gesture through the old rule and the new rule, so you can watch where they disagree. Then drag on a phone to feed in your own.mock The four preset gestures are synthesised from typical values, not captured from a person.
01v1 → v12 → now
Close on where the pull is going, not where it is
- The problem
- The first versions looked at distance only. A short fast flick was cancelled, and a long pull that you were already taking back was closed. The case study counted 31% missed closes. mock
- The change
- At release the sheet projects the pull forward: distance + release velocity × τ. If that lands past 35% of the sheet height, it closes. A pull shorter than 16 px never counts.
- Why
- People judge intent by speed first and distance second. The projection is one multiplication, cheap enough to show and tune.
- mock 38% as the old line (v12)
Showing Short fast flick: About 150 px in 125 ms, still accelerating at lift-off. With JavaScript this replays and you can record your own.
Stayed open
139 px < 243 px
Old rule: only the distance counts. You let go 139 px down; the line is 243 px (38% of the sheet). Short of it, so it stayed open, however fast you were going.
Closed
139 px + 1.59 × 80 ms = 267 px > 224 px
New rule: where was it going? 139 px so far, moving 1.59 px/ms down, so 80 ms later it would be 267 px. The line is 224 px (35%). Past it, so it closed.
One tunable: the look-ahead
The new rule closes when distance + velocity × τ passes 35% of the sheet. τ is how far ahead it looks. The table re-runs both rules on all recordings as you move it (τ = 0 is the old distance-only idea, at 35% instead of 38%).
Shipped: 80 ms. The slider needs JavaScript.
| Recording | Old rule | New rule |
|---|---|---|
| Short fast flick | Stayed open | Closed |
| Pull far, then swing back up | Closed | Stayed open |
| Ordinary pull | Closed | Closed |
| Accidental twitch | Stayed open | Stayed open |
Why 80 ms. On these four recordings the right answer holds for roughly 55 to 125 ms. Below that, the flick is missed again; above it, the twitch starts to close the sheet. 80 ms is about five frames at 60 Hz, inside the window and a little on the cautious side. It is still to be tuned by hand on a phone. mock
02v18.0.4 → v18.0.5
Close the picture first, let the text go
- The problem
- Closing shrank the whole sheet as one piece. The text was squashed on the way down and the picture reached its card late.
- The change
- The picture flies straight to the card on its own spring. The text is already gone by the 40% mark, so nothing readable is ever distorted.
- Why
- The picture is the thing that must be recognised on arrival; the text only has to get out of the way.
- mock old spring stiffness 170 (slower than today’s 300)
Showing Ordinary pull: Steady pull, release, close. With JavaScript this replays and you can record your own.
Closed
picture lands 480 ms, text squashed ×0.21
v18.0.4 and earlier: the whole sheet shrinks as one piece. The text is squashed on the way down (to 21% of its height) and the picture only reaches the card at 480 ms.
Closed
picture lands 360 ms, text gone by 80 ms
v18.0.5+: the text fades out first (gone by 80 ms) while the picture flies straight to the card, landing at 360 ms. Nothing is squashed.
03v20.0.5 → v20.0.7
A drag is not a tap, and an echo is not a tap
- The problem
- Pulling the sheet down from a link lifted the finger over that link and the browser fired a click. And the echo of the tap that opened the sheet could land on the backdrop and close it right away.
- The change
- A press that moves past a slop (8 px mouse, 10 px touch) is a drag, and the click that follows it is swallowed once. A backdrop tap in the first 260 ms after opening is ignored.
- Why
- Taps must still work with a shaky finger, so the slop is small. The grace window is long enough for a ghost click and short enough that nobody notices it.
- mock “ghost click arrives 120 ms after opening” (typical, not measured)
Showing Pull that starts on a link: The finger lands on "Read more", drags the sheet down 78 px and lets go. With JavaScript this replays and you can record your own.
Link fired
click leaked after the pull
v20.0.5 and earlier: the finger started on the link, dragged the sheet and lifted off still on the link (the sheet moves with the finger), so the browser fired a click. A pull navigated away.
Click swallowed
moved 78 px (> 10 px slop) = a drag
v20.0.6+: the press moved past the 10 px slop, so it stopped being a tap and became a drag. The click that follows a drag is swallowed once. The link stays quiet.
04v20.0.x → this site
Snap back with the speed your hand had
- The problem
- When a pull was not enough to close, the sheet returned with a fixed ease-out that started from rest. A hand that was moving still saw the sheet lurch.
- The change
- The return is a spring that starts at the release position with the release velocity. A new press can grab it mid-flight with no jump.
- Why
- Continuing the motion you just made reads as the sheet being physical; restarting it reads as an animation playing.
- mock old duration 220 ms (170–220 ms were used for reveals)
Showing Slow pull, gentle release: Pull 145 px, ease off, let go. Below the close line. With JavaScript this replays and you can record your own.
Stayed open
hand 17 px/s, next frame -2574 px/s, at rest 156 ms
Legacy prototypes: a fixed 220 ms ease-out from where you let go. It ignores how fast the hand was moving: the hand was at 17 px/s, one frame later the sheet is at -2574 px/s. That sudden change is the hitch.
Stayed open
hand 17 px/s, next frame -498 px/s, at rest 364 ms
This site: a spring that starts from your release position and your release speed (17 px/s) and then pulls toward home, so the speed builds from what the hand was doing instead of lurching (-498 px/s one frame later). It overshoots by 3 px and is at rest in 364 ms.