web-animations
Web Animations (WAAPI + CSS Transitions + CSS Animations)
Guia de referencia para las 3 APIs nativas de animacion del browser. Complementa la skill view-transitions (navegacion entre estados/paginas — ver ../view-transitions/SKILL.md).
Cuando Usar Cada API
| Necesidad | API | Por que |
|---|---|---|
| Hover, focus, estado simple | CSS Transitions | Declarativo, cero JS |
| Secuencia de keyframes pura CSS | CSS Animations | @keyframes + animation |
| Control runtime (pause, reverse, seek) | WAAPI | Element.animate() retorna Animation controlable |
| Scroll-driven reveal/parallax | CSS animation-timeline o WAAPI ScrollTimeline |
Off main thread, sin jank |
Entry desde display:none |
CSS Transitions + @starting-style + allow-discrete |
Nativo, sin JS |
Animacion de height: auto |
CSS + interpolate-size |
Chrome 129+, progressive enhancement |
| Logica per-frame (fisica, canvas) | requestAnimationFrame |
Ultimo recurso, main thread only |
Web Animations API (WAAPI)
Element.animate()
const anim = element.animate(
[{ transform: 'translateX(0)', opacity: 1 }, { transform: 'translateX(300px)', opacity: 0 }],
{
duration: 300, // milisegundos (NO segundos como CSS)
easing: 'ease-out', // default es 'linear' (distinto a CSS!)
iterations: 1, // Infinity para loops
fill: 'forwards', // none | forwards | backwards | both
direction: 'alternate', // normal | reverse | alternate | alternate-reverse
delay: 100,
composite: 'replace', // replace | add | accumulate
}
);
Keyframes: array de objetos (flexible, soporta offset/easing por keyframe) u objeto compacto ({ opacity: [0, 1] }). Implicit from/to: element.animate({ transform: 'translateX(300px)' }, 400) anima desde el valor actual. Siempre camelCase (backgroundColor).
El Objeto Animation
// Playback
anim.play(); anim.pause(); anim.reverse(); anim.finish(); anim.cancel();
// Estado
anim.playState; // 'idle' | 'running' | 'paused' | 'finished'
anim.currentTime; // ms | null
anim.playbackRate; // 1.0 default, negativo = reversa
anim.updatePlaybackRate(0.5); // smooth rate change
// Promises (async/await)
await anim.ready; // animacion arranco
await anim.finished; // animacion termino
// Events: onfinish, oncancel, onremove
Persistir Estilos (Preferir sobre fill:'forwards')
anim.finished.then(() => { anim.commitStyles(); anim.cancel(); });
fill: 'forwards' mantiene memoria y tiene side-effects en la cascada. commitStyles() escribe los valores computados en element.style y libera recursos.
getAnimations()
element.getAnimations(); // del elemento (incluye CSS animations/transitions)
document.getAnimations(); // todas del documento
Para features avanzadas (KeyframeEffect constructor, compositing, pseudo-element targeting), leer references/waapi-advanced.md.
CSS Transitions
transition: opacity 200ms ease-out, transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
@starting-style — Entry Animations
Sin @starting-style, las transitions no se activan en el primer render (no hay estado "antes"):
.card {
opacity: 1; transform: translateY(0);
transition: opacity 300ms, transform 300ms;
@starting-style { opacity: 0; transform: translateY(8px); }
}
Animar display con allow-discrete
.dialog {
display: none; opacity: 0;
transition: opacity 200ms ease, display 200ms allow-discrete;
}
.dialog[open] { display: block; opacity: 1; }
@starting-style { .dialog[open] { opacity: 0; } }
Eventos: transitionend, transitionrun, transitionstart, transitioncancel. Gotcha: transitionend NO se dispara si se interrumpe.
CSS Animations
@keyframes slide-in {
from { transform: translateX(-100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
.element {
animation: slide-in 300ms ease-out forwards;
/* name | duration | easing | fill-mode */
/* Composicion con otras animaciones */
animation-composition: add; /* replace | add | accumulate */
}
Eventos
element.addEventListener('animationend', (e: AnimationEvent) => {
e.animationName; // nombre del @keyframes
});
// Tambien: animationstart, animationcancel, animationiteration
Performance
Propiedades compositor (GPU, preferir siempre): transform, opacity, filter, clip-path
Propiedades main thread (evitar animar): width, height, top, left, background-color, box-shadow
CSS Animations y WAAPI corren en compositor para las propiedades GPU. requestAnimationFrame siempre corre en main thread.
will-change: aplicar solo cuando la animacion es inminente (ej: .card:hover { will-change: transform; }). No aplicar a todo — cada capa promovida consume GPU memory.
Layout thrashing: no intercalar reads (offsetHeight) y writes (style.height) en un loop. Batch reads primero, luego writes.
Scroll-Driven Animations
Para scroll-driven animations (ScrollTimeline, ViewTimeline, animation-timeline, animation-range), leer references/scroll-driven.md.
Patrones Modernos
Para interpolate-size, prefers-reduced-motion, @supports guards y otros patrones modernos, leer references/patterns.md.
Gotchas
- WAAPI default easing es
linear, noeasecomo CSS — siempre especificar - WAAPI duration en milisegundos, CSS en segundos —
duration: 300= 300ms fill: 'forwards'tiene side-effects — preferircommitStyles()+cancel()- Transitions no se activan sin estado previo — usar
@starting-styleo rAF delay transitionendno se dispara si se interrumpe — no depender como unico cleanup- Compositor vs main thread — animar solo
transform,opacity,filter,clip-path will-changeno es gratis — cada capa consume GPU memoryanimation-duration: autorequerido para scroll-driven timelines en CSS
Browser Support (2025)
| Feature | Chrome | Edge | Firefox | Safari |
|---|---|---|---|---|
Element.animate() core |
36+ | 79+ | 48+ | 13.1+ |
commitStyles() / persist() |
84+ | 84+ | 75+ | 13.1+ |
@starting-style |
117+ | 117+ | 129+ | 17.5+ |
transition-behavior: allow-discrete |
117+ | 117+ | 129+ | 17.5+ |
| Scroll-driven (CSS) | 115+ | 115+ | flag | 18+ (parcial) |
ScrollTimeline / ViewTimeline JS |
115+ | 115+ | flag | 18+ (parcial) |
interpolate-size |
129+ | 129+ | No | No |
Checklist Pre-Deploy
[ ] prefers-reduced-motion implementado
[ ] Solo animar propiedades de compositor (transform, opacity, filter)
[ ] will-change aplicado selectivamente y removido post-animacion
[ ] Duraciones razonables (150-400ms transiciones, hasta 1s animaciones complejas)
[ ] @starting-style para entry animations
[ ] commitStyles() + cancel() en vez de fill:'forwards' persistente
[ ] Scroll-driven animations con @supports guard y fallback visible
[ ] Testeado en Chrome, Safari Y Firefox
More from testacode/llm-toolkit
claude-md-writer
Escribe y mejora archivos CLAUDE.md siguiendo best practices de Anthropic. Este skill se activa cuando el usuario dice "crear CLAUDE.md", "mejorar CLAUDE.md", "actualizar CLAUDE.md", "revisar CLAUDE.md", "escribir instrucciones del proyecto", "create CLAUDE.md", "improve CLAUDE.md", "review CLAUDE.md", "write project instructions", "optimize docs for Claude", "auditar CLAUDE.md", "audit CLAUDE.md", "limpiar CLAUDE.md", "dead weight", o configura un nuevo repositorio.
53doc-writer
Este skill se usa para crear documentos tecnicos organizados en /docs (specs, planes de implementacion, ADRs, documentacion de referencia). Se activa cuando el usuario dice "crear documento", "escribir spec", "documentar esto", "creame una spec", "escribime documentacion", "hacer documentacion", "write a spec", "create documentation", "write an ADR", o quiere agregar documentacion tecnica al proyecto.
44llms-txt-generator
This skill generates llms.txt documentation optimized for AI/LLM consumption. It should be used when the user says "crear llms.txt", "generate llms.txt", "documentar para AI", "document for AI", "crear documentacion para LLMs", "generate docs for LLMs", "make repo readable for Claude", or wants to create structured machine-readable documentation following the llms.txt standard.
40doc-organizer
Este skill se usa cuando el usuario pide "organizar docs", "ordenar documentacion", "mover documentos a carpetas", "categorizar archivos md", "reorganizar documentacion", o cuando hay archivos .md sueltos en docs/ que necesitan ser movidos a subcarpetas tematicas. Organiza y categoriza documentos tecnicos en la estructura correcta del proyecto.
28feature-planner
Planifica features con entrevista estructurada y crea tareas. Este skill se activa cuando el usuario dice "quiero agregar", "planificar feature", "nueva funcionalidad", "implementar esto", "crear plan", "planificar antes de codear", "disenar feature", "como deberia implementar esto", "pensar la arquitectura", o quiere alinear antes de escribir codigo.
27nextjs-project-starter
Creates Next.js projects with a configurable stack (Mantine, Supabase, Zustand, Zod). This skill should be used when the user says "create a Next.js project", "new web project", "bootstrap fullstack app", "start new app", "crear proyecto Next.js", "nuevo proyecto web", "empezar app fullstack", or wants to scaffold a new personal project from scratch.
25