# Use theme motion in your own code

Make your own CSS and JavaScript animations follow the theme's speed, bounce, travel, hover and stagger, and share a motion setup as a link.

## Follow the theme in CSS

Use the `--bm-*` variables the theme defines:

```css title="Your CSS"
.card {
  transition: transform var(--bm-duration-base) var(--bm-ease-out);
}
.card:hover {
  transform: translateY(var(--bm-lift)); /* -2px at hover 1, 0 at hover 0 */
}
.card:active {
  transform: scale(var(--bm-press)); /* 0.97 at hover 1 */
}
.toast {
  transform: translateY(var(--bm-distance)); /* enter distance, 10px at travel 1 */
  transition: transform var(--bm-duration-slow) var(--bm-ease-spring);
}
.list > * {
  transition-delay: calc(var(--i) * var(--bm-stagger-step));
}
.glow {
  animation: pulse 2s infinite;
  animation-play-state: var(--bm-ambient-state); /* running or paused */
}
```

Tailwind's own classes follow too, with no edits: `duration-*`, `delay-*`, `ease-out`, `ease-in`, `ease-in-out` and `ease-spring`.

## Follow the theme in JavaScript

`@ballmac/motion-presets` reads the same variables. Import the constants for one-off values, or call `useMotion()` when a component should follow the theme live.

```tsx title="components/toast.tsx"
import { motion } from "motion/react"
import { useLoopsPaused, useMotion } from "@/lib/ballmac/motion"

export function Toast({ children }: { children: React.ReactNode }) {
  const m = useMotion()
  return (
    <motion.div
      initial={{ opacity: 0, y: m.distance }}
      animate={{ opacity: 1, y: 0 }}
      transition={m.spring.snappy}
    >
      {children}
    </motion.div>
  )
}
```

## Hold decorative loops still

Decorative loops hold still when the theme turns them off, or under reduced motion. Use `useLoopsPaused` for those only:

```tsx
function Glow() {
  const still = useLoopsPaused()
  return <motion.span animate={still ? undefined : { opacity: [0.4, 1, 0.4] }} transition={{ duration: 2, repeat: Infinity }} />
}
```

> **Note:** Spinners and "thinking" indicators carry meaning, so they should keep running. Don't pause them with `useLoopsPaused`.

## Share a motion setup as a link

A feel has a short address, and any combination is a link. Nothing is stored, and every value is clamped to its range, so a link can never produce an unsafe theme.

```bash
# a ready-made feel
https://ui.ballmac.com/themes?mo=playful

# or any values: speed, bounce, travel, hover, stagger, ambient (1 or 0), reduce (system or always)
https://ui.ballmac.com/themes?sp=1.3&bn=0.6&tv=0.8&hv=1.2&st=0.5&am=0
```

Install a custom design, color and motion together:

```bash
npx shadcn@latest add "https://ui.ballmac.com/themes/custom.json?h=262&mo=calm"
```
