Agent Skills: Web Animations (WAAPI + CSS Transitions + CSS Animations)

|

UncategorizedID: testacode/llm-toolkit/web-animations

Install this agent skill to your local

pnpm dlx add-skill https://github.com/testacode/llm-toolkit/tree/HEAD/skills/web-animations

Skill Files

Browse the full folder contents for web-animations.

Download Skill

Loading file tree…

skills/web-animations/SKILL.md

Skill Metadata

Name
web-animations
Description
|

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

  1. WAAPI default easing es linear, no ease como CSS — siempre especificar
  2. WAAPI duration en milisegundos, CSS en segundos — duration: 300 = 300ms
  3. fill: 'forwards' tiene side-effects — preferir commitStyles() + cancel()
  4. Transitions no se activan sin estado previo — usar @starting-style o rAF delay
  5. transitionend no se dispara si se interrumpe — no depender como unico cleanup
  6. Compositor vs main thread — animar solo transform, opacity, filter, clip-path
  7. will-change no es gratis — cada capa consume GPU memory
  8. animation-duration: auto requerido 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
Web Animations (WAAPI + CSS Transitions + CSS Animations) Skill | Agent Skills