Creates native CSS animations using keyframes, transitions, and modern animation properties. Use when building animations without JavaScript libraries, optimizing performance, or implementing micro-interactions.
Creates native CSS animations using keyframes, transitions, and modern properties. Use when building animations without JavaScript libraries, optimizing performance, or implementing micro-interactions.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/keyframe-patterns.mdNative browser animations - GPU-accelerated, no dependencies, excellent performance.
/* Define keyframes */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Apply animation */
.element {
animation: fadeIn 0.5s ease-out forwards;
}
| Transitions | Animations |
|---|---|
| Two states only | Multiple keyframes |
| Triggered by state change | Can auto-play |
| Simpler syntax | More control |
:hover, :focus, class change | Loops, delays, direction |
For simple two-state animations.
.button {
background: blue;
transform: scale(1);
transition: all 0.3s ease-out;
/* Or be specific (better performance) */
transition:
background 0.3s ease-out,
transform 0.2s ease-out;
}
.button:hover {
background: darkblue;
transform: scale(1.05);
}
.element {
transition-property: transform, opacity;
transition-duration: 0.3s;
transition-timing-function: ease-out;
transition-delay: 0.1s;
/* Shorthand: property duration timing-function delay */
transition: transform 0.3s ease-out 0.1s;
}
/* Using from/to */
@keyframes slide {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
/* Using percentages */
@keyframes bounce {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-30px);
}
100% {
transform: translateY(0);
}
}
/* Multiple properties at same point */
@keyframes complex {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.8;
}
}
.element {
/* Required */
animation-name: fadeIn;
animation-duration: 0.5s;
/* Optional */
animation-timing-function: ease-out;
animation-delay: 0.2s;
animation-iteration-count: 1; /* or infinite */
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
/* Shorthand */
animation: fadeIn 0.5s ease-out 0.2s 1 normal forwards running;
/* Multiple animations */
animation:
fadeIn 0.5s ease-out,
slideUp 0.5s ease-out 0.1s;
}
| Property | Values |
|---|---|
animation-timing-function | linear, ease, ease-in, ease-out, ease-in-out, cubic-bezier(), steps() |
animation-iteration-count | 1, 2, 3, infinite |
animation-direction | normal, reverse, alternate, alternate-reverse |
animation-fill-mode | none, forwards, backwards, both |
animation-play-state | running, paused |
/* none - Returns to original state after animation */
animation-fill-mode: none;
/* forwards - Keeps final keyframe state */
animation-fill-mode: forwards;
/* backwards - Applies first keyframe during delay */
animation-fill-mode: backwards;
/* both - forwards + backwards */
animation-fill-mode: both;
/* Built-in */
animation-timing-function: linear;
animation-timing-function: ease; /* default */
animation-timing-function: ease-in;
animation-timing-function: ease-out;
animation-timing-function: ease-in-out;
/* Custom cubic bezier */
animation-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
/* Steps (for sprite animations) */
animation-timing-function: steps(6);
animation-timing-function: steps(6, start);
animation-timing-function: steps(6, end);
/* Smooth deceleration */
cubic-bezier(0, 0, 0.2, 1)
/* Smooth acceleration */
cubic-bezier(0.4, 0, 1, 1)
/* Standard ease */
cubic-bezier(0.4, 0, 0.2, 1)
/* Overshoot (bouncy) */
cubic-bezier(0.68, -0.55, 0.265, 1.55)
/* Elastic */
cubic-bezier(0.68, -0.6, 0.32, 1.6)
/* GOOD - GPU accelerated, no layout/paint */
transform: translateX(100px);
transform: scale(1.5);
transform: rotate(45deg);
opacity: 0.5;
/* Hint for GPU acceleration */
will-change: transform, opacity;
/* BAD - triggers layout recalculation */
width, height, top, left, right, bottom,
margin, padding, border-width,
font-size, line-height
/* Instead of: left: 100px */
transform: translateX(100px);
/* Instead of: width: 200px */
transform: scaleX(2);
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-up {
animation: slideUp 0.5s ease-out forwards;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
.pulse {
animation: pulse 2s ease-in-out infinite;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake {
animation: shake 0.5s ease-in-out;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
@keyframes bounce {
0%, 100% {
transform: translateY(0);
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
50% {
transform: translateY(-25%);
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
}
}
.bounce {
animation: bounce 1s infinite;
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.skeleton {
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
/* Define full animation */
.element {
animation: fadeIn 0.5s ease-out forwards;
}
/* Reduce or remove for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
.element {
animation: none;
opacity: 1;
}
/* Or use simpler animation */
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
.element {
animation: spin 2s linear infinite;
}
.element:hover {
animation-play-state: paused;
}
// Add animation class
element.classList.add('animate-in');
// Remove after animation ends
element.addEventListener('animationend', () => {
element.classList.remove('animate-in');
});
// Restart animation
function restartAnimation(element) {
element.style.animation = 'none';
element.offsetHeight; // Trigger reflow
element.style.animation = null;
}
// Pause/resume
element.style.animationPlayState = 'paused';
element.style.animationPlayState = 'running';
element.addEventListener('animationstart', (e) => {
console.log('Started:', e.animationName);
});
element.addEventListener('animationiteration', (e) => {
console.log('Iteration:', e.elapsedTime);
});
element.addEventListener('animationend', (e) => {
console.log('Ended:', e.animationName);
});
element.addEventListener('animationcancel', (e) => {
console.log('Cancelled');
});
.item { animation: fadeIn 0.5s ease-out forwards; opacity: 0; }
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }
.item:nth-child(4) { animation-delay: 0.4s; }
.item:nth-child(5) { animation-delay: 0.5s; }
/* With CSS custom properties */
.item {
animation: fadeIn 0.5s ease-out forwards;
animation-delay: calc(var(--index) * 0.1s);
opacity: 0;
}
<div class="item" style="--index: 0">Item 1</div>
<div class="item" style="--index: 1">Item 2</div>
<div class="item" style="--index: 2">Item 3</div>
:root {
--animation-duration: 0.3s;
--animation-easing: cubic-bezier(0.4, 0, 0.2, 1);
}
.element {
transition: transform var(--animation-duration) var(--animation-easing);
}
/* Override per component */
.modal {
--animation-duration: 0.5s;
}
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.