Motion
The morph is the product, so it gets the budget a modal normally does not. Surface, shadow, radius and mask all run on one clock, and every spring is dialled by eye on the tuner, never typed.The morph is the product. Surface, shadow, radius and mask run on one clock, and every spring is dialled by eye, never typed.


00Rest


01≈20%


02≈50%


03≈80%


04Settled
One open on the default preset, about 600ms to settle.
Springs
Three springs are props on Root: transition.open, .close and .shared. Shared is direction-aware. Snap is internal.stiffness / damping / mass
| Spring | Stiffness | Damping | Mass | What it moves |
|---|---|---|---|---|
| open | 375 | 42.5 | 1.75 | The surface, trigger to sheet. |
| close | 375 | 32 | 1 | The surface home. Stiffer than open. |
| shared.open | 500 | 45 | — | The shared element, clearing the growing sheet. |
| shared.close | 340 | 30 | 1 | The shared element, arriving with the trigger. |
| snap | 700 | 52 | 1 | Drag release to the nearest anchor. Internal. |
open375 / 42.5 / 1.75
Surface, trigger to sheet.
close375 / 32 / 1
Surface home. Stiffer than open.
shared.open500 / 45
Shared element clears the sheet.
shared.close340 / 30 / 1
Shared element arrives home.
snap700 / 52 / 1
Drag release. Internal.
<Iris.Root
transition={{
close: { stiffness: 375, damping: 32, mass: 1 },
shared: {
open: { stiffness: 500, damping: 45 },
close: { stiffness: 340, damping: 30, mass: 1 },
},
}}
>Timings
Everything else is internal. These are fixes for specific artifacts, not knobs.
35ms
Surface close leadSurface close lead
0.2s
Content reveal after openContent reveal
90ms
Item staggerItem stagger
80ms
Content fade-outContent fade-out
200ms
Reduced-motion crossfadeReduced-motion crossfade
Presets
Three named feels, so you can change how it feels without typing spring numbers. default is exactly what ships with no preset.preset={presets.snappy}
Each stage is the live component on its preset. Tap one, or open all three on the same frame.
presets.default
- open
- 375 / 42.5 / 1.75
- close
- 375 / 32 / 1
- shared.open
- 500 / 45
- shared.close
- 340 / 30 / 1
- lead delay
- 35ms
presets.snappy
- open
- 495.94 / 48.88 / 1.75
- close
- 495.94 / 36.8 / 1
- shared.open
- 661.25 / 51.75
- shared.close
- 449.65 / 34.5 / 1
- lead delay
- 30ms
presets.gentle
- open
- 270.94 / 36.13 / 1.75
- close
- 270.94 / 27.2 / 1
- shared.open
- 361.25 / 38.25
- shared.close
- 245.65 / 25.5 / 1
- lead delay
- 41ms
snappy and gentle are frequency-scaled from default and not yet judged by eye. Expect their values to change on the tuner; the API won’t.
Principles
- 01
One surface, one clock.
Box, shadow, radius and mask all derive from collapseProgress. Nothing has its own spring.
- 02
Nothing appears from nothing.
The sheet never paints at a size the trigger did not grow into.
- 03
Transform and opacity only.
No filter, blur, shadow, width or height animates while the clock runs.
- 04
Springs, dialled, never typed.
Every change goes through the tuner with a measured before and after.
- 05
Reveal after settle.
The close control waits until the surface is within 1% of rest. Content starts 0.2s in and staggers at 90ms.
- 06
Exit faster than enter.
Content fades out in 80ms; the close spring is stiffer than the open.
- 07
Reduced motion is a crossfade, not nothing.
Opacity only, 200ms. The close control stays reachable.
- 08
Judge with the instrument.
Smoothness is a number: distinct rendered frames per open and close.