--- name: ui-motion description: Apply a named StyleSeed motion to a component — either one of the 5 personality seeds (Spring/Silk/Snap/Float/Pulse × entrance/exit/hover/press/layout) or a distinctive keyword move from the motion library (toggle-flip, toggle-curtain, reveal-blur, pop-in, shimmer, …). Translates vibe... risk: unknown source: https://github.com/bitjaru/styleseed/tree/main/engine/.claude/skills/ss-motion source_repo: bitjaru/styleseed source_type: community date_added: 2026-07-01 license: MIT license_source: https://github.com/bitjaru/styleseed/blob/main/LICENSE --- # Motion Seed Applier ## When to Use Use this skill when you need apply a named StyleSeed motion to a component — either one of the 5 personality seeds (Spring/Silk/Snap/Float/Pulse × entrance/exit/hover/press/layout) or a distinctive keyword move from the motion library (toggle-flip, toggle-curtain, reveal-blur, pop-in, shimmer, …). Translates vibe... ## When NOT to use - For general framer-motion docs or learning → use the framer-motion site - For non-React motion (CSS-only transitions, GSAP) — this skill targets `motion.X` JSX only - For full scroll-linked timelines or parallax — out of scope per DESIGN-LANGUAGE.md Rule 59 - For tweaking the existing FadeIn/FadeUp/Stagger wrappers — edit `engine/components/ui/motion.tsx` directly ## Vibe → Seed mapping Translate the user's prompt to one of the five seeds before applying. Use this lookup table from `engine/motion/index.ts`: | Words the user might say | Seed | |---|---| | bouncy, springy, playful, energetic, alive | **Spring** | | smooth, silky, fluid, elegant, composed, continuous | **Silk** | | snappy, quick, instant, decisive, sharp, precise | **Snap** | | floaty, gentle, weightless, dreamy, ambient, drifting | **Float** | | rhythmic, punchy, pulsing, heartbeat, beat | **Pulse** | | "Toss style", "Arc style" | **Spring** (per brand default) | | "Stripe style", "Notion style" | **Silk** | | "Linear style", "Raycast style", "Vercel style" | **Snap** | If the user says only a *brand* name, use that brand's default seed from `BRAND_DEFAULT_SEED`. If the user is explicit about a seed name (`spring`, `silk`, etc.), respect it verbatim. ## Recommend mode — use-case → motion (when the user describes the *moment*, not the vibe) If the user describes **what the thing is** ("a like button", "a modal", "the loading state", "items in a feed") rather than a feeling, recommend from the use-case map (`MOTION_BY_USECASE` in `engine/motion/library.ts`, exported from `@engine/motion`): | Use case | Reach for | Why | |---|---|---| | Primary button / CTA press | `spring · press` | tactile, confident — the press should "give" | | Modal / dialog / sheet enter | `silk · entrance` | smooth; never bounce serious/destructive content | | Dropdown / popover / menu | `snap · entrance` | instant, precise — frequent UI shouldn't wait | | Toast / inline notification | `spring · entrance` | small friendly arrival, non-blocking | | List / feed items appearing | `stagger-cascade` | choreograph order, gently | | Feature / marketing card hover | `tilt-3d` | depth/flair OK on content-light marketing | | Dashboard / data card hover | `snap · hover` | a subtle lift only — keep dense UI calm | | Like / favorite / reaction | `like-burst` | a celebratory one-shot; reward the tap | | Live / online / recording dot | `pulse-beat` | looping heartbeat = "alive" | | Loading / skeleton | `shimmer` | calm directional progress | | Success / confirmation | `pop-in` | positive little "done" | | Toggle / tab / segment switch | `toggle-flip` | distinctive, recognizable switch | | Page / route transition | `silk · entrance` | smooth, minimal, get out of the way | | Number / balance / KPI / price reveal | **none** | don't animate the payload — it must read instantly | **Two anti-rules override the table** (state them if you deviate): 1. **One seed per product.** If the project already uses a seed, match it — don't introduce a second personality. 2. **Never delay the payload.** Don't animate a balance, price, or search result into view; motion is for affordance, not content. ## Named motion keywords (distinctive moves) Seeds set a *personality* (how a fade/scale feels). The **motion library** in `engine/motion/library.ts` adds *distinctive moves* — a flip, a curtain wipe, a morph — each behind a unique keyword. Prefer a keyword when the user wants a specific, recognizable motion rather than a generic feel. `engine/motion/library.ts` (exported as `MOTION_LIBRARY` / `MOTION_BY_KEY` from `@engine/motion`) is the **single source of truth** — every keyword carries its own runnable `snippet`. Pull the snippet from there; never hand-write the params. | Keyword | Move | Say it when the user wants… | |---|---|---| | `toggle-flip` | 3D Y-axis card flip | a switch/toggle to flip between two faces | | `toggle-slide` | slide-stack swap | a value to slide out and the next to slide in | | `toggle-morph` | pill ⇄ circle morph | a control to change shape on toggle | | `toggle-curtain` | top→bottom clip-path wipe | a panel to reveal like a curtain | | `reveal-blur` | blur(12px)→0 focus-in | content to focus-pull into place | | `reveal-rise` | masked clip-path text rise | a headline/text to climb into view | | `reveal-unfold` | scaleY from top edge | an accordion/panel to unfold | | `pop-in` | spring overshoot from 0 | a badge/checkmark to pop in bouncily | | `press-squish` | scale-down + skew | a button to feel jelly/tactile on tap | | `tap-ripple` | radial ripple from tap | Material-style press feedback | | `pulse-beat` | looping scale pulse | a live/recording/heartbeat indicator | | `wiggle` | quick horizontal shake | error / invalid-input feedback | | `shimmer` | skeleton loading sweep | a loading placeholder | | `stagger-cascade` | children fade-up in sequence | a list to animate in one-by-one | **Applying a keyword:** 1. Read the exact recipe from `engine/motion/library.ts` — find the entry whose `key` matches, copy its `snippet` verbatim (it is calibrated and runnable). 2. Adapt only the element/content to the user's JSX; keep the transition values. 3. If the keyword is stateful (toggles, ripple), wire the `useState` shown in the snippet. If it's a one-shot reveal, a `key` bump replays it. 4. Tell the user the keyword you applied so they can reuse it elsewhere for consistency, and point them at `/motion` to preview/Copy others. If the user describes a move but no exact keyword fits, fall back to a seed + context. If they say a keyword that doesn't exist, suggest the closest real one from the table — never invent a keyword. ## Context detection Infer one of the five contexts from the prompt: - "on hover" / "when hovered" → `hover` - "on press" / "on tap" / "on click" → `press` - "when it appears" / "on mount" / "entering" → `entrance` - "when it leaves" / "on close" / "exiting" → `exit` (requires ``) - "when layout changes" / "FLIP" / "rearranging" → `layout` If ambiguous, default to `entrance`. If multiple contexts are reasonable (e.g., a button needs both `hover` and `press`), apply both. ## Application steps Apply seed: **$0** · Context: **$1** · Target: **$ARGUMENTS** 1. **Read the target file** at the path given (or, if no path was given, ask the user which file). Locate the JSX element the user is talking about — usually a `