spring / stagger / observeEntry
Primitivas de movimiento que dejan el dibujo en tus manos: un muelle resuelto de forma exacta (también como easing CSS linear()), retrasos escalonados, una entrada en pantalla de un solo disparo y la preferencia de movimiento reducido del lector. Ninguna tiene su propio bucle de animación, así que sirven igual con Web Animations, transiciones CSS o tu propio requestAnimationFrame.
API
spring(options?)
Devuelve { at, duration, easing }. at(seconds) es el progreso de 0 a 1 (un muelle subamortiguado pasa de 1 antes de asentarse); duration es el tiempo hasta quedar a menos del 0,1 % del objetivo; easing es la misma curva como cadena CSS linear() para esa duración.
| Opción | Descripción | Valor por defecto |
|---|---|---|
stiffness |
Fuerza hacia el objetivo; más alta, más rápida | 170 |
damping |
Resistencia; por debajo de 2 * sqrt(stiffness * mass) rebota |
26 |
mass |
Inercia | 1 |
velocity |
Velocidad inicial, en progreso por segundo | 0 |
stagger(index, count, options?)
Retraso en segundos del elemento index de count, empezando por el primero, el último o el centro (from).
observeEntry(element, options)
Llama a onEnter una sola vez, cuando el borde superior del elemento cruza line (fracción de la altura de la ventana desde arriba), y deja de observar. Recibe { reduced }: si es true, muestra el estado final sin animar. Devuelve una función para dejar de observar antes.
prefersReducedMotion()
true cuando el lector pidió movimiento reducido; false donde no hay window (SSR, Node).
Ejemplo
import { observeEntry, prefersReducedMotion, spring, stagger } from 'ranuts';
const { duration, easing } = spring({ stiffness: 260, damping: 20 });
const cards = [...document.querySelectorAll('.card')];
cards.forEach((card, index) => {
observeEntry(card, {
line: 0.85,
onEnter: ({ reduced }) => {
if (reduced) return; // already in its final place
card.animate(
[
{ opacity: 0, transform: 'translateY(24px)' },
{ opacity: 1, transform: 'none' },
],
{
duration: duration * 1000,
delay: stagger(index, cards.length, { each: 0.06 }) * 1000,
easing,
fill: 'backwards',
},
);
},
});
});Notas
- El contenido se ve sin script. Anima desde un desplazamiento con
fill: 'backwards'en lugar de ocultar elementos con CSS, así un script fallido o el movimiento reducido lo dejan todo en su sitio. - Sin IntersectionObserver,
observeEntryentra de inmediato en vez de dejar el elemento esperando. - El muelle es exacto, no por pasos, así que las mismas opciones dan la misma curva a cualquier frecuencia de fotogramas.