@junco/motion
Motion
Effects with no animation library. One data-motion switch tones them all down, and prefers-reduced-motion always wins.
npm i @junco/motion@import "tailwindcss";
@import "@junco/tailwind"; /* includes motion.css */
@source "../node_modules/@junco/motion/dist";Reveal
Fades and rises in when it scrolls into view. stagger reveals children one after another by the --stagger token.
Text reveal
Words (or characters) rise in one after another. Screen readers get the whole sentence at once.
Number ticker
Counts up when visible, with tabular numbers. The final value is what assistive tech reads, from the start.
Typewriter
Types, pauses, erases and cycles through words. With motion off it shows the first word.
Build your
Marquee
An endless scroll that pauses on hover and focus. Copies are hidden from screen readers; with motion off it wraps into one still row.
Shimmer text
A light sweep across text, for things like “Thinking…”. Plain text with motion off.
Animated beam
A light that travels an SVG path between two elements. Recomputes on resize.
Spotlight card
A soft light follows the pointer across the card and its border.
Realtime sync
Move your pointer over this card.
Magnetic button
A Junco Button that leans toward the pointer. Still with motion off, and for touch.
Border beam and gradient border
A light running around a rounded border, and a slowly turning gradient border in the chart palette.
Confetti
A tiny canvas burst in your theme colors. Does nothing with motion off. No dependencies.
View transitions
Wraps a state change in the View Transitions API, so layouts morph instead of snapping. Falls back to an instant change.
- Inbox
- Drafts
- Sent
CSS-only classes
The same effects as plain classes from @junco/tailwind, for semantic-class users, server components and plain HTML. They follow the motion switch too.
| Class | What it does |
|---|---|
reveal | Fades and rises in as it scrolls into view (CSS scroll-driven where supported; React <Reveal> elsewhere) |
reveal-item | A child that reveals in turn inside a staggered reveal |
text-reveal | Word-by-word reveal container (use <TextReveal> to split the text) |
marquee | Endless horizontal scroll; add marquee-reverse or marquee-vertical. Pauses on hover and focus |
shimmer | A light sweep across text |
spotlight | Pointer-following light; set --spotlight-x and --spotlight-y |
border-beam | A light running around the parent's rounded border |
gradient-border | A slowly turning multi-color border |
animate-rise / animate-fade | Entrance animations from @junco/tailwind |
duration-fast / -base / -slow | Transition durations scaled by --motion-scale |
<div class="reveal">Rises in as you scroll</div>
<div class="marquee">
<div class="marquee-track">…logos…</div>
<div class="marquee-track" aria-hidden="true">…same logos…</div>
</div>
<span class="shimmer">Thinking…</span>The motion switch
| Setting | --motion-scale | Effects |
|---|---|---|
data-motion="full" | 1 | Everything plays |
data-motion="subtle" | 0.6 | Shorter, smaller movement |
data-motion="off" | 0 | Final states, nothing moves (spinners turn slower) |
prefers-reduced-motion | 0 | Always wins over data-motion |
Set it with useTheme().setMotion() or on <html> directly. More in Dark mode and motion.