Skills Plugins MCP Prompt Model 博客 我的中心

motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-skills-motion-ui-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name motion-ui description Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns. metadata {"origin":"ECC"} Motion System v4.2 Production-ready UI motion system for React / Next.js. Focused on performance, accessibility, and usability — not decoration. When to Use Use this motion system when motion: Guides attention (e.g., onboarding, key actions) Communicates state (loading, success, error, transitions) Preserves spatial continuity (layout changes, navigation) Appropriate Scenarios Interactive components (buttons, modals, menus) State transitions (loading → loaded, open → closed) Navigation and layout continuity (shared elements, crossfade) Considerations Accessibility : Always support reduced motion Device adaptation : Adjust for low-end devices Performance trade-offs : Prefer responsiveness over visual smoothness Avoid Using Motion When It is purely decorative It reduces usability or clarity It impacts performance negatively How It Works Core Principle Motion must: Guide attention Communicate state Preserve spatial continuity If it does none → remove it. Installation npm install motion Version motion/react - default for current Motion for React projects (package: motion ) framer-motion - legacy import path for projects that still depend on Framer Motion Do not mix. Mixing causes conflicting internal schedulers and broken AnimatePresence contexts — components from one package will not coordinate exit animations with components from the other. To check which version your project uses: cat package.json | grep -E '"motion"|"framer-motion"' Always import from one source consistently: // Correct (modern) import { motion, AnimatePresence } from "motion/react" // Correct (legacy) import { motion, AnimatePresence } from "framer-motion" // Never mix both in the same project Motion Tokens // motionTokens.ts export const motionTokens = { duration : { fast : 0.18 , normal : 0.35 , slow : 0.6 }, // Use these as the `ease` value inside a `transition` object: // transition={{ duration: motionTokens.duration.normal, ease: motionTokens.easing.smooth }} easing : { smooth : [ 0.22 , 1 , 0.36 , 1 ] as [ number , number , number , number ], sharp : [ 0.4 , 0 , 0.2 , 1 ] as [ number , number , number , number ] }, distance : { sm : 8 , md : 16 , lg : 24 } } Usage example: import { motionTokens } from "@/lib/motionTokens" <motion. div initial={{ opacity : 0 , y : motionTokens. distance . md }} animate={{ opacity : 1 , y : 0 }} transition={{ duration : motionTokens. duration . normal , ease : motionTokens. easing . smooth }} /> Performance Rules Safe transform opacity Avoid width / height top / left Rule: responsiveness > smoothness Device Adaptation The heuristic combines CPU core count and available memory for a more reliable signal. deviceMemory is available on Chrome/Android; the fallback covers Safari and Firefox. const isLowEnd = typeof navigator !== "undefined" && ( // Low memory (Chrome/Android only; undefined elsewhere → treat as capable) (navigator. deviceMemory !== undefined && navigator. deviceMemory <= 2 ) || // Few cores AND no memory API (covers Safari/Firefox on weak hardware) (navigator. deviceMemory === undefined && navigator. hardwareConcurrency <= 4 ) ) const duration = isLowEnd ? 0.2 : 0.4 Accessibility JS (useReducedMotion) import { motion, useReducedMotion } from "motion/react" export function FadeIn ( ) { const reduce = useReducedMotion () return ( < motion.div initial = {{ opacity: 0 , y: reduce ? 0 : 24 }} animate = {{ opacity: 1 , y: 0 }} /> ) } CSS @media ( prefers-reduced-motion : reduce) { .motion-safe-transition { transition : opacity 0.2s ; } .motion-reduce-transform { transform : none !important ; } } Tailwind < div class = "motion-safe:animate-fade motion-reduce:opacity-100" > </ div > Architecture & Patterns Core Patterns Scenario Pattern Hover feedback whileHover Tap / press feedback whileTap Reveal on scroll whileInView Scroll-linked value useScroll + useTransform Conditional mount/unmount AnimatePresence Small layout shifts (single element, < ~300px change) layout prop Large layout shifts or full-page reflows Avoid layout ; use CSS transitions or page-level routing instead Complex, imperative sequences useAnimate Why avoid layout on large containers? Framer's layout animation uses transform to reconcile positions, but on elements that span the full viewport or trigger deep reflow, the measurement cost causes visible jank and CLS. Prefer CSS Grid/Flexbox transitions or coordinate with layoutId on specific child elements only. Layout & Transitions Shared element transitions → layoutId (must be unique per mounted instance) Enter / exit transitions → AnimatePresence (see mode guidance below) AnimatePresence mode Always specify mode explicitly — the default ( "sync" ) runs enter and exit simultaneously, which causes visual overlap in most UI patterns. mode When to use "wait" Exit completes before enter starts. Use for modals, toasts, page transitions . "sync" (default) Enter and exit overlap. Use only when overlap is intentional (e.g., crossfade carousels). "popLayout" Exiting element is popped out of flow immediately; remaining items animate to fill. Use for lists, tabs, dismissible cards . // Modal — always use "wait" < AnimatePresence mode= "wait" > {open && < Modal key = "modal" /> } </ AnimatePresence > // Dismissible list item — use "popLayout" < AnimatePresence mode = "popLayout" > {items.map(item => < Card key = {item.id} /> )} </ AnimatePresence > Advanced Patterns (Concepts) Parallax (scroll-linked transforms) Scroll storytelling (sticky sections) 3D tilt (pointer-based transforms) Crossfade (shared layoutId ) Progressive reveal (clip-path) Skeleton loading (looped opacity) Micro-interactions (hover/tap feedback) Spring system (physics-based motion) Modal Essentials Focus trap Escape close Scroll lock ARIA roles Use AnimatePresence mode="wait" so exit animation completes before the next modal enters Full Example import React , { useEffect, useRef, useState } from "react" import { motion, AnimatePresence } from "motion/react" function useFocusTrap ( ref : React . RefObject < HTMLDivElement | null >, active : boolean ) { useEffect ( () => { if (!active || !ref. current ) return const el = ref. current const focusable = el. querySelectorAll < HTMLElement >( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ) const first = focusable[ 0 ] const last = focusable[focusable. length - 1 ] function handleKey ( e : KeyboardEvent ) { if (e. key !== "Tab" ) return if (e. shiftKey && document . activeElement === first) { e. preventDefault () last?. focus () } else if (!e. shiftKey && document . activeElement === last) { e. preventDefault () first?. focus () } } el. addEventListener ( "keydown" , handleKey) first?. focus () return () => el. removeEventListener ( "keydown" , handleKey) }, [active, ref]) } function useScrollLock ( active : boolean ) { useEffect ( () => { if (!active) return const prev = document . body . style . overflow document . body . style . overflow = "hidden" return () => { document . body . style . overflow = prev } }, [active]) } function Modal ( { open, closeModal }: { open: boolean ; closeModal: () => void } ) { const ref = useRef< HTMLDivElement >( null ) useFocusTrap (ref, open) useScrollLock (open) useEffect ( () => { function onKey ( e : KeyboardEvent ) { if (e. key === "Escape" ) closeModal () } if (open) window . addEventListener ( "keydown" , onKey) return () => window . removeEventListener ( "keydown" , onKey) }, [open, closeModal]) return ( // mode="wait" ensures exit animation finishes before any new modal enters < AnimatePresence mode = "wait" > {open && ( < motion.div role = "dialog" aria-modal = "true" aria-labelledby = "modal-title" initial = {{ opacity: 0 }} animate = {{ opacity: 1 }} exit = {{ opacity: 0 }} transition = {{ duration: 0.2 }} className = "fixed inset-0 flex items-center justify-center bg-black/40" > < motion.div ref = {ref} initial = {{ scale: 0.95 , opacity: 0 }} animate = {{ scale: 1 , opacity: 1 }} exit = {{ scale: 0.95 , opacity: 0 }} transition = {{ duration: 0.2 , ease: [ 0.22 , 1 , 0.36 , 1 ] }} className = "bg-white p-6 rounded" > < h2 id = "modal-title" > Dialog Title </ h2 > < button onClick = {closeModal} > Close </ button > </ motion.div > </ motion.div > )} </ AnimatePresence > ) } export function Example ( ) { const [open, setOpen] = useState ( false ) return ( <> < button onClick = {() => setOpen(true)}>Open </ button > < Modal open = {open} closeModal = {() => setOpen(false)} /> </> ) } SSR Safety Match initial states between server and client renders Avoid implicit animation origins (always set initial explicitly) Wrap motion components in "use client" in Next.js App Router Debugging Check: Wrong import (mixing motion/react and framer-motion ) Missing "use client" directive in Next.js App Router Missing key prop on AnimatePresence children Hydration mismatch (initial state differs between SSR and client) layout prop misuse on large containers causing reflow jank State-driven animation not triggering (check dependency arrays) QA No CLS Keyboard works Focus trapped in modals ARIA roles correct ( role="dialog" , aria-modal="true" ) Reduced motion respected ( useReducedMotion + CSS media query) No hydration warnings in Next.js Animations stop cleanly on unmount (no memory leaks) AnimatePresence mode set explicitly on all usage sites Anti-Patterns Animating layout properties ( width , height , top , left ) Infinite animations without purpose (always ask: what state does this communicate?) Over-staggering lists (keep staggerChildren ≤ 0.1s; beyond that it feels slow) Ignoring reduced motion preferences Using layout on large or full-viewport containers Omitting mode on AnimatePresence (default "sync" causes visual overlap) Using motion purely for decoration Philosophy Motion is interaction design. Final Rule If motion does not improve UX → remove it. Examples Button Interaction import { motion } from "motion/react" export function Button ( ) { return ( < motion.button whileHover = {{ scale: 1.02 }} whileTap = {{ scale: 0.97 }} transition = {{ duration: 0.15 , ease: [ 0.4 , 0 , 0.2 , 1 ] }} > Click me </ motion.button > ) } Reduced Motion Example import { motion, useReducedMotion } from "motion/react" export function FadeIn ( ) { const reduce = useReducedMotion () return ( < motion.div
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。