Motion — spatial & perceived depth
themes specs/themes/motion/spatial.kmd
Pseudo-3D motion on flat surfaces: pointer/gyroscope parallax, depth-on-scroll, and 3D transitions (flip, cube, perspective shared- element). These imply depth without real geometry — they are a PERCEPTUAL projection of the depth axis (`themes/depth.kmd § R4`). Strictly gated by the reduced-motion contract. Material parity: extends M3 motion with the spatial/expressive depth cues M3 leaves implicit.
Quando esta spec se aplica
Triggers primários
- Add perceived-depth motion to any flat Koder surface
Todos os triggers
- Add parallax (pointer or gyroscope) to a hero or card
- Make layers shift by depth as the user scrolls
- Use a 3D flip / cube / perspective transition between states
Corpo da especificação
Spec — Motion: spatial & perceived depth
Facet Visual do Koder Design. Sub-spec of
motion.kmd. Material parity: https://m3.material.io/styles/motion + the expressive spatial cues M3 leaves to the implementer.
On a flat screen, depth (depth.kmd) can be implied
by motion. This is perceptual, never a real layer — it must not
reorder the stacking bands (depth.kmd § R3) and it is always the
first thing to switch off under reduced-motion.
Reduced-motion is mandatory — see
physics.kmd. Every effect here MUST degrade to a static, non-parallaxed layout.
R1 — Parallax (pointer & gyroscope)
Layers translate at a rate inverse to their depth — near layers move more, far layers move less (distant scenery).
| Token | Meaning | Default |
|---|---|---|
--kds-parallax-max | Max layer translation (px) at depth 1 | 12 |
--kds-parallax-falloff | Multiplier per depth level deeper | 0.6 |
- A layer at depth
dmoves--kds-parallax-max × falloff^(d-1). - Pointer: track cursor offset from element centre (desktop).
- Gyroscope:
deviceorientationβ/γ on mobile (opt-in; needs user permission on iOS — fall back to no parallax if denied). - Clamp total travel so text never clips its container.
R2 — Depth-on-scroll
As the viewport scrolls, layers parallax vertically by depth — a hero image recedes slower than its foreground caption.
- Driven by
scroll-timeline/IntersectionObserver, never a scroll-jankrequestAnimationFramestorm. - Magnitude scales with depth (R1 falloff).
- MUST NOT trigger layout (transform only — no top/height animation).
R3 — 3D transitions
Perspective transitions between two states of the same surface:
| Pattern | Use | Notes |
|---|---|---|
| Flip | Reveal back of a card (front ↔ details) | rotateY(180deg); both faces backface-visibility: hidden |
| Cube | Step through a small sequence (≤ 4 faces) | rotateY on a transform-style: preserve-3d parent |
| Perspective shared-element | Hand off an element between screens with depth | Extends the 2D shared-axis pattern in transitions.kmd |
perspectivebetween600–1000px(closer = more dramatic; default800px).- Lighting is consistent: a face rotating away dims toward the shadow
side of the rig (
lighting.kmd § R1). - Duration from
easing-duration.kmd; spring option fromphysics.kmd.
R4 — Performance
- Animate
transform+opacityonly (compositor-friendly). - Budget: 60 fps; parallax handlers throttled to one update per frame
(
requestAnimationFrame), never per pointer event. will-change: transformonly while active; removed at rest.- Disable all effects when the tab is backgrounded.
R5 — Forbidden patterns
- ❌ Any effect that ignores
prefers-reduced-motion(R1 intro). - ❌ Parallax that reorders real stacking bands (
depth.kmd § R3). - ❌ Animating layout properties (top/left/width/height) for depth.
- ❌ Parallax >
--kds-parallax-maxthat clips or detaches content. - ❌ Gyroscope parallax without a no-permission fallback (R1).
- ❌ Flip/cube on surfaces carrying critical text that becomes unreadable mid-rotation (keep faces legible or fade).
R6 — Accessibility
prefers-reduced-motion: reduce→ static layout, no parallax, no 3D rotation (cross-fade or instant swap instead).- Parallax is decorative: it MUST NOT move focusable targets out from under the pointer/keyboard focus.
- Motion sickness ceiling: no rotation faster than 30°/s in the user's
gaze area (mirrors
xr-preview.kmd § R8).
T1-T3 — Tests
T1 — Reduced-motion: with prefers-reduced-motion, parallax travel is
0 px and 3D transitions resolve as a static state change.
T2 — Transform-only: scroll/parallax effects animate only transform/
opacity (no layout-triggering property in the animation).
T3 — Falloff: a layer at depth 2 moves --kds-parallax-falloff× the
travel of a depth-1 layer (within 1 px).
Live demo
Cross-link
themes/motion/physics.kmd— reduced-motion contract (mandatory)themes/motion/transitions.kmd— 2D pattern catalog (R3 extends it)themes/depth.kmd— the axis these effects project (§ R4)themes/lighting.kmd— face shading during 3D rotation (R3)
Referências
specs/themes/motion/physics.kmdspecs/themes/motion/transitions.kmdspecs/themes/depth.kmdspecs/themes/lighting.kmd