What moves, how far, how fast, and who opts out.
Part of the Konjo design language. The laws in the spine apply here unless this chapter contradicts them.
Konjo is an app people open sweaty, one-handed, with forty seconds before class. Motion earns its place by making a change legible — where something came from, what replaced what. It never earns its place by being pleasant.
The durations, and what each is for
Read the numbers from the token tables; this is what they mean.
| Token | Use |
|---|---|
instant |
A press state. Colour and opacity only — this is below the threshold where anyone perceives a transition. |
quick |
A chip selecting, a checkbox, a small in-place change. |
base |
The default. A sheet's backdrop, a row expanding, a tab's content cross-fading. |
enter |
Something arriving: a sheet rising, a toast dropping in. |
exit |
Something leaving. Deliberately faster than enter — waiting for a thing you already dismissed is the most irritating motion in any app. |
slow |
Reserved. A deliberate reveal where the delay carries meaning. |
Nothing exceeds 400ms except one celebration. The promotion certificate is the single place the app is allowed to take its time, because the moment is the point.
What is allowed to move
- Things entering and leaving the screen. Sheets, toasts, banners, list items on first load.
- Things changing size in place. An accordion, a "show more".
- State on a control. Press, selection, focus.
- Determinate progress. A bar that fills as something completes.
What is not
- Content that is already on screen and did not change. No entrance animation on scroll, no stagger down a list the user is halfway through.
- Anything decorative. Pulsing, floating, breathing, drifting. A dojo app is not a screensaver.
- Anything that delays an action. If a tap has a result, the result is not gated behind an animation finishing.
- Parallax and auto-playing carousels. Both are vestibular triggers and neither has ever helped anyone find a class.
- Loading spinners under one second. See states — the flash is worse than the wait.
How it should feel
- Enter with easing out, exit with easing in. Things arriving decelerate into place; things leaving accelerate away. The reverse reads as broken.
- One thing moves at a time. If a sheet is rising, the content behind it holds still.
- Motion has a direction and it means something. A sheet comes from the bottom because that is where it goes back to. A push comes from the trailing edge because back returns there. Arbitrary directions teach nothing.
- Distance is small. 8–24pt of travel reads as motion; 200pt reads as a journey. The exception is a surface genuinely entering from off-screen.
- Interruptible. A person who taps again mid-animation gets the new thing, not a queue.
Reduced motion
This is not optional and it is currently mostly missing — 14 of the 19 files that animate
ignore the setting. Use useReducedMotion() from react-native-reanimated; ListFadeIn,
ReflectPill, WizardProgressBar and WizardScaffold already do it correctly.
Reduced motion replaces movement, it does not delete it:
| Normally | Reduced |
|---|---|
| Slide in from the edge | Cross-fade in place |
| Spring / scale | Instant state change |
| Progress counting up | Jump to the value |
| Scrolling to the first invalid field | Jump to it — focus still moves, nothing is lost |
| Certificate reveal | The same certificate, presented statically |
Full rationale in accessibility.
The test
Watch the screen once at normal speed. If you noticed the animation, it is too long, too far, or should not be there. Then turn reduce motion on and watch again: everything you needed to understand should still be there.