开发编程
#react
motion-ui
Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.
DeepseekModel
官方收录技能
质量 优秀 · 90
v1.0.0
获取
https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-skills-motion-ui-skill-md&format=skill
下载 .skill
标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
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
Agent 识别该技能的关键词,点击任意一个即可复制。
该技能未提供触发词。
下载的 .skill 包内含以下字段。
| 字段 | 说明 |
|---|---|
| format | 格式标识(skill/v1) |
| skill_id | 技能唯一 ID |
| name | 技能名称 |
| version | 版本号 |
| description | 技能描述 |
| category | 所属分类(数组) |
| trigger_words | 触发词列表 |
| tags | 标签列表 |
| source | 来源标识 |
| source_url | 来源链接(本页地址) |
| exported_at | 导出时间(每次下载生成) |
| system_prompt | 系统提示词正文 |
| model_config | 模型参数:provider / model / temperature / max_tokens / top_p |
| examples | 示例 |
| install_guide | 各平台导入说明(Coze / Dify / Claude / 自定义框架) |