JDS.

Search docs

Find a page or component

Motion

Presets in lib/motion.ts, built on Motion for React. Every animation in the system uses them.

Principles

  • Feedback under 250ms. Anything answering a click or keypress finishes fast.
  • Springs for things that move, tweens for things that fade. Springs keep momentum when interrupted, which happens constantly with streaming content.
  • Motion shows state change. A send button turning into stop, a step completing, the orb following your voice. Nothing moves just to move.
  • Respect reduced motion. Looping animations stop under prefers-reduced-motion.

Springs

spring.snappyButtons, toggles, icon swaps
spring.gentleMessages, panels, layout
spring.softVoice orb, ambient elements
lib/motion.ts
export const spring = {
  snappy: { type: "spring", stiffness: 520, damping: 34, mass: 0.6 },
  gentle: { type: "spring", stiffness: 260, damping: 30 },
  soft: { type: "spring", stiffness: 120, damping: 18 },
}

Durations and easing

For tweens: instant 100ms, fast 160ms, base 240ms, slow 400ms. ease.out (quint) for entrances. The same curves exist in CSS as ease-out-quint and ease-in-out-quart for Tailwind transitions.

Variants

rise is the entrance for streamed content: 6px up, a short blur, fade in. stagger() cascades children, as in Suggestions.

import { rise, stagger } from "@/lib/motion"

<motion.div variants={stagger(0.05)} initial="hidden" animate="visible">
  {items.map((item) => (
    <motion.div key={item.id} variants={rise}>{item.label}</motion.div>
  ))}
</motion.div>