Guizang Product Video Skill
op7418/guizang-product-video-skill
制作代码驱动的软件产品宣传片和版本更新片(product promo、release notes video、changelog promo)。从真实功能和产品设计出发定方向,用真实组件、GSAP/Three.js 动效、原创配乐和动作音效完成影片,每支片子的视觉手法都从产品本身推导,不套模板。
Design GPU-accelerated animations with Web Animations API (WAAPI), Scroll-Driven Animations (ScrollTimeline/ViewTimeline), FLIP technique, easing systems, and accessibility (prefers-reduced-motion).
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install EliasOulkadi/shokunin motion-craft --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.pack/skills/motion-craft .claude/skills/motion-craft && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .claude/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craftType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install EliasOulkadi/shokunin motion-craft --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.pack/skills/motion-craft .agents/skills/motion-craft && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .agents/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install EliasOulkadi/shokunin motion-craft --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.pack/skills/motion-craft .cursor/skills/motion-craft && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .cursor/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/EliasOulkadi/shokunin.git --path .pack/skills/motion-craft--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install EliasOulkadi/shokunin motion-craft --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.pack/skills/motion-craft .gemini/skills/motion-craft && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .gemini/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install EliasOulkadi/shokunin motion-craftInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .github/skills && cp -r skills-src/.pack/skills/motion-craft .github/skills/motion-craft && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .github/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EliasOulkadi/shokunin --skill motion-craft -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install EliasOulkadi/shokunin motion-craft --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/EliasOulkadi/shokunin.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.pack/skills/motion-craft .opencode/skills/motion-craft && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "motion-craft" agent skill from https://github.com/EliasOulkadi/shokunin/tree/master/.pack/skills/motion-craft into .opencode/skills/motion-craft/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "motion-craft", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
motion-craftDesign GPU-accelerated animations with Web Animations API (WAAPI), Scroll-Driven Animations (ScrollTimeline/ViewTimeline), FLIP technique, easing systems, and accessibility (prefers-reduced-motion).
Motion Craft is an agent skill from EliasOulkadi/shokunin. Design GPU-accelerated animations with Web Animations API (WAAPI), Scroll-Driven Animations (ScrollTimeline/ViewTimeline), FLIP technique, easing systems, and accessibility (prefers-reduced-motion). Use when user asks to create animations, transitions, scroll effects, page transitions, or interactive motion for web UIs. Do NOT use for canvas-based animations (Three.js, PixiJS), video editing, or non-web (native mobile) motion design.
Its SKILL.md is about 6.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 7 other files, including scripts, reference files and assets (for example `references/animation-frameworks.md`, `references/motion-design-tokens.md` and `scripts/generate-easing.sh`). Compatibility notes: opencode
It sits in Frontend & Design, covering Web animation and motion, Video production and Motion graphics. It works with Three.js. The repository describes itself as: 職人 Shokunin 62 AI agent skills for OpenCode, Claude Code, Cursor, Windsurf. ChromaDB memory, MCP servers, declarative self-updates. Multi-model, open source, zero cost. The licence is MIT.
4 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 4c68e5b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
easing.deveasings.coFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
opencode
From compatibility in the SKILL.md frontmatter.
Motion Craft loads about 6.4k tokens when it runs, and up to ~9.4k if it reads all its reference files. Until then it costs about 113 tokens; SKILL.md has 2,236 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from EliasOulkadi/shokunin at commit 4c68e5b, republished under its MIT licence (© EliasOulkadi). 2,236 words, ~6,405 tokens.
.claude/skills/motion-craft/SKILL.md (or your agent's skills folder). This skill also uses 4 other files; get the full folder from GitHub.Animations that communicate, not decorate. Every frame must earn its place.
Inspired by Emil Kowalski (Linear, Sonner, Vaul), Paul Lewis (Google Chrome), and the CSS Animation Working Group.
Before writing any animation code, answer these four questions in order.
| Frequency | Decision | Reason |
|---|---|---|
| 100+ times/day (keyboard shortcuts, command palette, search toggle) | No animation. Ever. | Animation makes frequent actions feel delayed. Raycast has no open/close animation. Optimal. |
| Tens of times/day (hover effects, list navigation) | Remove or drastically reduce | Users notice animation latency on repeated interactions |
| Occasional (modals, drawers, toasts) | Standard animation | The right place for motion |
| Rare / first-time (onboarding, confirmation, celebration) | Add delight | These moments earn longer, richer animations |
Never animate keyboard-initiated actions. These repeat hundreds of times daily.
Every animation must have a clear answer to "why does this animate?"
| Purpose | Example | Valid? |
|---|---|---|
| Spatial consistency | Toast enters and exits from the same direction | ? |
| State indication | Button morphs to show "sent" | ? |
| Feedback | Button scales down on press, confirming the interface heard the user | ? |
| Preventing jarring changes | Elements fading in instead of appearing abruptly | ? |
| Explanation | Marketing animation showing how a feature works | ? |
| "It looks cool" AND the user sees it often | Gratuitous motion | ? |
| Scenario | Easing | CSS |
|---|---|---|
| Element entering | ease-out (starts fast, feels responsive) | cubic-bezier(0, 0, 0.2, 1) |
| Element exiting | ease-in (starts slow, grabs attention briefly then accelerates away) | cubic-bezier(0.4, 0, 1, 1) |
| On-screen movement / morphing | ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) |
| Hover / color change | ease | cubic-bezier(0.25, 0.1, 0.25, 1) |
| Constant motion (marquee, progress bar) | linear | cubic-bezier(0, 0, 1, 1) |
| UI interactions (buttons, tooltips, dropdowns) | strong ease-out | cubic-bezier(0.23, 1, 0.32, 1) |
Critical: never use ease-in for UI entering animations. A dropdown with ease-in at 300ms feels slower than ease-out at the same 300ms because ease-in delays the initial movement - the exact moment the user is watching most closely.
| Element | Duration | Easing |
|---|---|---|
| Button press feedback (scale) | 100-160ms | cubic-bezier(0.23, 1, 0.32, 1) |
| Tooltip enter / exit | 125-200ms | cubic-bezier(0.23, 1, 0.32, 1) |
| Dropdown / select / popover | 150-250ms | cubic-bezier(0.23, 1, 0.32, 1) |
| Hover transform (scale, lift) | 200ms | cubic-bezier(0.23, 1, 0.32, 1) |
| Modal / dialog enter | 200-300ms | cubic-bezier(0, 0, 0.2, 1) |
| Modal / dialog exit | 150-200ms | cubic-bezier(0.4, 0, 1, 1) |
| Drawer / sheet enter | 200-400ms | cubic-bezier(0.32, 0.72, 0, 1) (iOS-like) |
| Toast enter | 300-400ms | cubic-bezier(0.23, 1, 0.32, 1) |
| Toast exit | 200-300ms | cubic-bezier(0.4, 0, 1, 1) |
| Page transition | 300-400ms | cubic-bezier(0.4, 0, 0.2, 1) |
| Scroll reveal (fade + slide up) | 400-800ms | cubic-bezier(0.16, 1, 0.3, 1) |
| Loading shimmer | 1000-1500ms (infinite) | linear |
| Hold-to-delete (press) | 2000ms | linear (deliberate) |
| Hold-to-delete (release) | 200ms | cubic-bezier(0.23, 1, 0.32, 1) (snappy) |
| Marketing / explanatory | 800-3000ms | variable, depends on narrative |
Rule: UI animations should stay under 300ms. A 180ms dropdown feels noticeably more responsive than a 400ms one.
The built-in CSS ease / ease-in / ease-out are too weak. Use these stronger custom variants:
:root {
--ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1); /* UI interactions, Emil's signature */
--ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1); /* On-screen movement */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); /* iOS-like drawer */
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Slow reveals, dramatic */
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Alternative strong ease-out */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Slight overshoot, sparingly */
}Sources: easing.dev, easings.co
16.67ms per frame. Verify with Chrome DevTools Performance tab. Only animate transform and opacity.
| Property | GPU composite? | Triggers |
|---|---|---|
transform (translate, scale, rotate) | ? Yes | Composite only |
opacity | ? Yes | Composite only |
filter | ?? Sometimes | Paint + Composite |
clip-path | ?? Sometimes | Paint + Composite |
width, height, top, left, margin, padding, border-width | ? No | Layout + Paint + Composite |
box-shadow | ? No | Paint + Composite |
color, background-color | ? No | Paint only |
When reviewing UI animation code, you MUST use a markdown table with Before | After | Why columns. Do NOT use a list with "Before:" and "After:" on separate lines.
| Before | After | Why |
|---|---|---|
transition: all 300ms | transition: transform 200ms ease-out | Specify exact properties; avoid all which triggers layout recalculation |
transform: scale(0) | transform: scale(0.95); opacity: 0 | Nothing in the real world appears from nothing |
ease-in on dropdown | cubic-bezier(0.23, 1, 0.32, 1) | ease-in starts slow - feels sluggish. Strong ease-out gives instant feedback |
No :active state on button | transform: scale(0.97) on :active | Buttons must feel responsive to press |
transform-origin: center on popover | transform-origin: var(--radix-popover-content-transform-origin) | Popovers should scale from their trigger. Modals stay centered. |
transition: 300ms without prefers-reduced-motion | @media (prefers-reduced-motion: reduce) { transition-duration: 0.01ms } | WCAG 2.1 requires reduced-motion support |
animate={{ x: 100 }} in Framer Motion | animate={{ transform: "translateX(100px)" }} | Framer Motion x/y are NOT hardware-accelerated. Use transform string for GPU. |
Wrong format (never do this):
Before: transition: all 300ms
After: transition: transform 200ms ease-outCSS transitions are interruptible - they can be retargeted mid-animation. Keyframes restart from zero. For any interaction that can be triggered rapidly (toasts, toggles, dropdowns), transitions produce smoother results.
.button {
transition: transform 160ms ease-out;
}
.button:active {
transform: scale(0.97);
}
.tooltip {
transition: transform 125ms ease-out, opacity 125ms ease-out;
transform-origin: var(--transform-origin);
}Enter can be slower (user is deciding), exit must be fast (system responding):
.overlay {
transition: clip-path 200ms ease-out; /* release: fast */
}
.button:active .overlay {
transition: clip-path 2s linear; /* press: slow and deliberate */
}.tooltip {
transition: transform 125ms ease-out, opacity 125ms ease-out;
transform-origin: var(--transform-origin);
}
.tooltip[data-instant] {
transition-duration: 0ms;
}.toast {
opacity: 1;
transform: translateY(0);
transition: opacity 400ms ease-out, transform 400ms ease-out;
@starting-style {
opacity: 0;
transform: translateY(100%);
}
}Note:
@starting-styleand scroll-driven animations (animation-timeline: view(),animation-timeline: scroll()) are Chrome-only as of 2026. Use JavaScript fallbacks for cross-browser support.
.overlay {
clip-path: inset(0 100% 0 0);
transition: clip-path 200ms ease-out; /* release: fast */
}
.button:active .overlay {
clip-path: inset(0 0 0 0);
transition: clip-path 2s linear; /* press: slow and deliberate */
}Every pressable element needs physical response.
.button {
transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}
.button:active {
transform: scale(0.97);
}The scale must be subtle (0.95-0.98). Applied to all pressable elements - buttons, cards, list items, tabs.
Popovers scale from their trigger, not center. Modals stay centered.
/* Radix UI */
.popover {
transform-origin: var(--radix-popover-content-transform-origin);
}
/* Base UI */
.popover {
transform-origin: var(--transform-origin);
}
/* Modals (always centered) */
.modal {
transform-origin: center;
}Whether the user notices individually does not matter. In the aggregate, unseen details compound.
When multiple elements enter together, stagger their appearance.
.item {
opacity: 0;
transform: translateY(8px);
animation: fadeIn 300ms ease-out forwards;
}
.item:nth-child(1) { animation-delay: 0ms; }
.item:nth-child(2) { animation-delay: 50ms; }
.item:nth-child(3) { animation-delay: 100ms; }
.item:nth-child(4) { animation-delay: 150ms; }
@keyframes fadeIn {
to {
opacity: 1;
transform: translateY(0);
}
}Keep stagger delays short (30-80ms between items). Never block interaction while stagger plays.
Use for predetermined, non-dynamic animations. Keyframes restart from zero on interruption - avoid for UI.
@keyframes enter-right {
from { opacity: 0; transform: translateX(16px); }
to { opacity: 1; transform: translateX(0); }
}
.enter {
animation: enter-right 300ms ease-out forwards;
}Springs feel more natural than duration-based animations because they simulate real physics. They maintain velocity when interrupted.
{ type: "spring", duration: 0.5, bounce: 0.2 }{ type: "spring", stiffness: 100, damping: 10, mass: 1 }Keep bounce subtle (0.1-0.3). Avoid bounce in most UI. Use for drag-to-dismiss and playful interactions only.
import { useSpring } from 'framer-motion'
const springX = useSpring(mouseX * 0.1, { stiffness: 100, damping: 10 })Without spring: feels artificial, instant. With spring: feels natural, has momentum.
Programmatic CSS animations. Hardware-accelerated, interruptible, no library needed.
const element = document.querySelector('.card')
const animation = element.animate([
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(0.95)', opacity: 0.7 },
], {
duration: 200,
easing: 'cubic-bezier(0.23, 1, 0.32, 1)',
fill: 'both',
})
animation.pause()
animation.play()
animation.reverse()
animation.finish()
animation.finished.then(() => console.log('done'))WAAPI beats Framer Motion under heavy load - it runs off the main thread. Use for dynamic, interruptible animations where CSS keyframes fall short.
Browser support note: Scroll-driven animations (animation-timeline: view() and scroll()) are Chrome/Edge-only as of 2026, not yet Baseline. Provide JS fallbacks via IntersectionObserver for Firefox/Safari.
@keyframes fade-up {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-up 600ms linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}@keyframes shrink {
from { height: 80px; }
to { height: 50px; }
}
.site-header {
animation: shrink 300ms linear both;
animation-timeline: scroll();
animation-range: 0 200px;
}const layers = document.querySelectorAll('[data-parallax]')
window.addEventListener('scroll', () => {
const scrollY = window.scrollY
layers.forEach(layer => {
const speed = parseFloat(layer.dataset.parallax) || 0.3
layer.style.transform = `translateY(${scrollY * speed}px)`
})
})For layout animations - animating elements that change position/size.
function animateLayout(element, callback) {
const first = element.getBoundingClientRect()
callback()
const last = element.getBoundingClientRect()
const dx = first.left - last.left
const dy = first.top - last.top
const dw = first.width / last.width
const dh = first.height / last.height
element.animate([
{ transform: `translate(${dx}px, ${dy}px) scale(${dw}, ${dh})` },
{ transform: 'translate(0, 0) scale(1, 1)' },
], {
duration: 300,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
})
}One of the most powerful animation tools in CSS. Hardware-accelerated.
.overlay {
clip-path: inset(0 100% 0 0);
transition: clip-path 200ms ease-out;
}
.visible {
clip-path: inset(0 0 0 0);
}Use for: hold-to-delete, image reveals on scroll, comparison sliders, seamless color transitions on tabs.
Speed in animation directly affects how users perceive your app:
| Effect | Mechanism |
|---|---|
| Fast-spinning spinner | Makes loading feel faster (same load time, different perception) |
| 180ms select vs 400ms select | Shorter animation = perceived responsiveness jump |
| Instant tooltips after first one | Skip delay + animation on subsequent tooltips |
| Fast exit animations | Exit must be faster than enter (200ms enter, 150ms exit) |
ease-out vs ease-in at same 200ms | ease-out feels faster because user sees immediate movement |
These skip layout and paint, running on GPU.
// Bad: triggers recalculation on all children
element.style.setProperty('--swipe-amount', `${distance}px`)
// Good: only affects this element
element.style.transform = `translateY(${distance}px)`When the browser is busy loading a new page, Framer Motion animations (using requestAnimationFrame) drop frames. CSS animations remain smooth - they run off the main thread.
transform string, not shorthand// NOT hardware accelerated (requestAnimationFrame on main thread)
<motion.div animate={{ x: 100 }} />
// Hardware accelerated (GPU, stays smooth even under load)
<motion.div animate={{ transform: "translateX(100px)" }} />.will-animate {
will-change: transform, opacity;
}Each will-change creates a new compositor layer, consuming GPU memory. Apply before animation, remove after.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}WCAG 2.1 Success Criterion 2.3.3 - Animation from Interactions.
For fine-grained control:
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches
const userPrefersReduced = localStorage.getItem('reduced-motion') === 'true'
const shouldReduce = prefersReduced || userPrefersReduced@media (hover: hover) and (pointer: fine) {
.element:hover { transform: scale(1.05); }
}Touch devices trigger hover on tap. Gate hover animations behind this media query.
Play animations at reduced speed to spot issues invisible at full speed. Temporarily increase duration to 2-5x normal, or use browser DevTools animation inspector.
Things to look for:
Chrome DevTools Animations panel. Step frame by frame. Reveals timing issues between coordinated properties invisible at full speed.
For touch interactions (drawers, swipe gestures), test on physical devices. Connect phone via USB, visit local dev server by IP address, use Safari remote devtools.
| Issue | Fix |
|---|---|
transition: all | Specify exact properties: transition: transform 200ms ease-out |
scale(0) entry animation | Start from scale(0.95) with opacity: 0 |
ease-in on UI element | Switch to strong ease-out or custom curve |
transform-origin: center on popover | Set to trigger location (modals exempt) |
| Animation on keyboard action | Remove entirely |
| Duration > 300ms on UI element | Reduce to 150-250ms |
| Hover animation without media query | Add @media (hover: hover) and (pointer: fine) |
| Keyframes on rapidly-triggered element | Use CSS transitions for interruptibility |
Framer Motion x/y props under load | Use transform: "translateX()" |
| Same enter/exit transition speed | Exit must be faster (e.g. enter 2s, exit 200ms) |
| Elements all appear at once | Stagger with 30-80ms between items |
No prefers-reduced-motion fallback | Required by WCAG 2.1 |
will-change left on after animation | Remove or set to auto when done |
| JS scroll listeners for scroll effects | Use ViewTimeline / IntersectionObserver |
CSS ease default | Replace with custom cubic-bezier |
Before delivering animated UI code:
transform and opacity animated (GPU composite)prefers-reduced-motion respected@media (hover: hover)scale(0) entries - start from scale(0.95)transform-origin anchors to triggertransition: all - exact properties onlytransform string over x/y shorthandwill-change removed after animation completesscale(0.97) on :active| Banned | Because |
|---|---|
transition: all | Triggers layout recalculation on every frame |
ease-in on entering UI | Delays initial movement - feels sluggish |
scale(0) entry | Nothing disappears and reappears completely in the real world |
Animating width, height, top, left | Layout thrashing - use transform |
requestAnimationFrame for scroll effects | Blocking - use ScrollTimeline or IntersectionObserver |
| Bounce / elastic easing on functional UI | Unprofessional - reserve for playful interactions only |
| Duration > 500ms on functional UI | Feels slow - users notice and get frustrated |
| Auto-playing carousels without pause | WCAG accessibility violation |
Framer Motion x/y props under load | Not hardware-accelerated - frames drop during page loads |
No prefers-reduced-motion | WCAG 2.1 failure |
will-change on everything | GPU memory waste - creates compositor layers |
translateZ(0) on every element | Too many GPU layers - memory overhead |
| Keyframes for dynamic UI | Not interruptible - use CSS transitions |
transform-origin: center on popovers | Breaks spatial consistency with trigger |
| Same speed enter and exit | Exit should always be faster |
| Error | Cause | Fix |
|---|---|---|
transition: all causes jank on unrelated property changes | Browser recalculates layout for every animated frame; all triggers layout on properties that don't need it | Specify exact properties: transition: transform 200ms ease-out, opacity 200ms ease-out |
Framer Motion x/y props drop frames during page loads | x/y use requestAnimationFrame on the main thread, competing with React renders | Use animate={{ transform: "translateX(100px)" }} string — hardware-accelerated, GPU composite |
| Animation stutters on mobile Safari | iOS Safari throttles requestAnimationFrame in low-power mode; non-composited properties force layout | Only animate transform and opacity. Test on physical iOS devices via USB remote debugging. |
| Popover scales from wrong origin | Default transform-origin: center breaks spatial consistency with the trigger element | Set transform-origin: var(--radix-popover-content-transform-origin) for Radix; var(--transform-origin) for Base UI |
| Staggered list items flash all at once then disappear | animation-delay applied but items are visible by default before animation starts | Set initial state: opacity: 0; transform: translateY(8px). Animation resolves to visible. |
| CSS keyframes restart on re-trigger instead of continuing | Keyframes run from frame 0 every time animation-name is applied | Use CSS transitions for interruptible UI (toasts, toggles, dropdowns). Keyframes only for predetermined, fire-once animations. |
@starting-style doesn't work in Firefox/Safari | @starting-style is Chrome-only as of 2026, not yet Baseline | Provide JS fallback: set initial inline styles, then remove them on next frame to trigger transition. |
| Scroll-driven animation has no effect in Firefox | animation-timeline: view() and scroll() are not supported outside Chrome/Edge | Provide IntersectionObserver fallback that toggles a CSS class for animation. |
will-change: transform never removed | Browser allocates GPU memory for the compositor layer indefinitely | Remove will-change or set to auto after animation completes. Use sparingly — each layer costs GPU memory. |
| Magnetic button causes continuous React re-renders | useState for cursor position triggers re-render at 60fps | Use Framer Motion useMotionValue + useTransform — updates outside React render cycle. |
Scroll parallax jank from scroll event listener | window.addEventListener('scroll') fires on main thread, competing with rendering | Use ScrollTimeline (Chrome) or throttled IntersectionObserver with requestAnimationFrame debounce. |
| Touch device fires hover state on tap, then hover state persists | Mobile browsers synthesize hover on first tap and keep it until another tap elsewhere | Gate hover animations behind @media (hover: hover) and (pointer: fine). |
| Auto-playing carousel without pause button | WCAG 2.2.2 violation: moving content must be pausable | Add pause/play button. Respect prefers-reduced-motion. Allow keyboard control. |
prefers-reduced-motion respected — fallback to static or reduced variant© EliasOulkadi, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 4 other files (scripts, references, assets) in .pack/skills/motion-craft of EliasOulkadi/shokunin.
Open the folder on GitHubat commit 4c68e5b
Motion Craft next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Motion Craft this skillEliasOulkadi/shokunin | 114 | — | ~6.4k | Automated safety check: Pass | MIT | |
| Guizang Product Video Skillop7418/guizang-product-video-skill | 753 | — | ~1.1k | Automated safety check: Pass | AGPL-3.0 | |
| Oma Designfirst-fluke/oh-my-agent | 1.3k | — | ~2.9k | Automated safety check: Pass | MIT | |
| Motion DesignWrongStack/WrongStack | 371 | — | ~852 | Automated safety check: Pass | MIT | |
| HyperFrames Animationheygen-com/hyperframes | 60k | 3 repos | ~2.1k | Automated safety check: Pass | Apache-2.0 | |
| Phantom Motionpixelxzen/phantom-motion | 185 | — | ~1k | Automated safety check: Pass | Apache-2.0 |
op7418/guizang-product-video-skill
制作代码驱动的软件产品宣传片和版本更新片(product promo、release notes video、changelog promo)。从真实功能和产品设计出发定方向,用真实组件、GSAP/Three.js 动效、原创配乐和动作音效完成影片,每支片子的视觉手法都从产品本身推导,不套模板。
first-fluke/oh-my-agent
AI design specialist skill with DESIGN.md management, anti-pattern enforcement, optional Stitch MCP integration, and component library guidance.
WrongStack/WrongStack
Implement web and React animation, gesture feedback, layout transitions and scroll sequences.
heygen-com/hyperframes
Collects motion rules, scene blueprints, transitions and runtime adapters for HyperFrames video compositions, with GSAP as the default animation runtime.
pixelxzen/phantom-motion
交互式动态视觉叙事生成器 v11.0 (Hybrid Drive Edition)。基于用户输入的任意主题关键词, 通过多轮交互式对话收集需求,利用 React 19 + Tailwind 4 驱动的 Minimal Mono 极简编辑器, 实时操纵隔离在 Iframe 中的硬核 GSAP/WebGL 影视级叙事引擎。
secondsky/claude-skills
120+ Vue/Nuxt animated components with TailwindCSS v4, motion-v, GSAP, Three.js.
EliasOulkadi/shokunin
Design CI/CD pipelines for GitHub Actions, GitLab CI, and CircleCI with matrix builds, test sharding, caching, Docker layer caching, OIDC auth, deployment strategies (rolling, blue-green, canary)…
EliasOulkadi/shokunin
Build production-grade components for React, Vue 3, and Svelte 5 with all states (loading, empty, error, success, idle), TypeScript strict, WCAG 2.2 accessibility, server components (RSC), and…
EliasOulkadi/shokunin
PostgreSQL database administration — backup/restore (pgdump, PITR, WAL archiving), health monitoring (connections, bloat, cache hit ratio, dead tuples), connection pooling (PgBouncer), replication…
EliasOulkadi/shokunin
Design database schemas with Prisma/Drizzle, PostgreSQL index strategy (B-tree, GIN, GiST, BRIN, Hash), query optimization (EXPLAIN ANALYZE), migration safety (expand/contract, zero-downtime), and…
EliasOulkadi/shokunin
Optimize Docker images with multi-stage builds, distroless bases, BuildKit cache mounts, multi-arch builds, compose watch, security hardening (non-root, seccomp, capabilities drop), and…
EliasOulkadi/shokunin
Design error handling, structured logging, and observability with OpenTelemetry (traces, metrics, logs), error classification, recovery patterns (retry with jitter, circuit breaker, bulkhead…
Works with
Design GPU-accelerated animations with Web Animations API (WAAPI), Scroll-Driven Animations (ScrollTimeline/ViewTimeline), FLIP technique, easing systems, and accessibility (prefers-reduced-motion). Motion Craft is an agent skill from EliasOulkadi/shokunin. Design GPU-accelerated animations with Web Animations API (WAAPI), Scroll-Driven Animations (ScrollTimeline/ViewTimeline), FLIP technique, easing systems, and accessibility (prefers-reduced-motion).
Motion Craft fits situations like: user asks to create animations; page transitions; interactive motion for web UIs; canvas-based animations (Three.js.
Run `npx skills add EliasOulkadi/shokunin --skill motion-craft -a claude-code`. Or copy the skill folder (.pack/skills/motion-craft in EliasOulkadi/shokunin) into .claude/skills/motion-craft in your project. Claude Code loads it when a task matches its description.
Run `npx skills add EliasOulkadi/shokunin --skill motion-craft -a codex`. Or copy the skill folder (.pack/skills/motion-craft in EliasOulkadi/shokunin) into .agents/skills/motion-craft in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add EliasOulkadi/shokunin --skill motion-craft -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/motion-craft, .gemini/skills/motion-craft, .github/skills/motion-craft and .opencode/skills/motion-craft in your project.
Going by SKILL.md and its folder, Motion Craft needs a shell for the scripts in its folder. Our summary lists: A Bash shell. Compatibility (from SKILL.md): opencode.
SKILL.md names 2 domains. As links in the text: easing.dev and easings.co. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Motion Craft is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.4k tokens (SKILL.md is roughly 26k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 3k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Motion Craft: Guizang Product Video Skill (op7418/guizang-product-video-skill, 753 stars), Oma Design (first-fluke/oh-my-agent, 1.3k stars), Motion Design (WrongStack/WrongStack, 371 stars) and HyperFrames Animation (heygen-com/hyperframes, 60k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
EliasOulkadi (a GitHub user) maintains it in EliasOulkadi/shokunin, which has 114 GitHub stars. The repository holds 49 skills in this directory. The repository was last updated on October 5, 2026.
Source: EliasOulkadi/shokunin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.