Composing primitives
One motion system per surface. `Jelly`, `Tilt`, `LiquidSurface`, `Magnetic` and `Parallax` each own the transform on the element they wrap. Nesting two of them on the same surface — or on a parent and its direct child — makes both systems fight over the same `transform`, and the result reads as a bug, not layered depth.
Live example
Try the interaction before reading the recipe.
real component · keyboard-safe
Composing primitives · compare the system relationship
The rule
One motion system per surface. Jelly, Tilt, LiquidSurface, Magnetic and Parallax each own the transform on the element they wrap. Nesting two of them on the same surface — or on a parent and its direct child — makes both systems fight over the same transform, and the result reads as a bug, not layered depth.
What composes safely
- A primitive plus a static effect.
Glow Borderframing aJelly Card, orSpotlightlighting the face of aTiltcard, work because one is a transform and the other is light — they don't share a property. - A primitive plus press feedback.
usePressSpringscale and aJellylean can coexist because the lean is idle/hover behaviour and the press scale only applies on activation. - Nested content that brings its own semantics. A button, image or badge inside
MagneticorJelly— the wrapper only ever transforms the whole child, never reaches into it.
What does not compose
JellyinsideTilt(or the reverse) — two independent rotation/lean systems on one surface.Magneticon both a parent and a child it contains — offsets add up and become unpredictable.CursorGlowandSpotlighton the same region — doubles the ambient light for no added meaning.- A
Parallaxlayer nested inside anotherParallax— depths compound instead of composing.
The test
If you can't describe in one sentence what depth or motion each layer is independently responsible for, don't nest them — flatten to one primitive and let composition happen through layout instead.
Related
[[motion-budget]], [[when-not-to-animate]]
Source: packages/skills/patterns/composing-primitives.md