Skip to content

Latest commit

 

History

History
1027 lines (820 loc) · 28.7 KB

File metadata and controls

1027 lines (820 loc) · 28.7 KB

JS Animation — Library Reference

Supplementary reference for the js-animation skill. Every library with CDN URLs, sizes, licenses, API quick-reference, and technique tables.


1. Core Animation Engines

GSAP (GreenSock) v3.14

Status: 100% FREE (including all plugins) since v3.13 (March 2025). Acquired by Webflow. License: Standard GreenSock License (free for all use including commercial) Core Size: ~28kb min+gzip

CDN URLs

<!-- Core (required) -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/gsap.min.js"></script>

<!-- Scroll Plugins -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/ScrollSmoother.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/Observer.min.js"></script>

<!-- Text Plugins -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/SplitText.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/TextPlugin.min.js"></script>

<!-- SVG Plugins -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/DrawSVGPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/MorphSVGPlugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/MotionPathPlugin.min.js"></script>

<!-- Layout & Interaction Plugins -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/Flip.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/Draggable.min.js"></script>

<!-- Easing & Physics -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/CustomEase.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14/dist/EasePack.min.js"></script>

Plugin Sizes

Plugin Size (gzip) Purpose
gsap core ~28kb Timeline, tweens, easing
ScrollTrigger ~10kb Scroll-based triggering, pinning, scrubbing
ScrollSmoother ~6kb Smooth scroll + parallax (requires ScrollTrigger)
SplitText ~5kb Split text into chars/words/lines
Flip ~8kb FLIP layout animations
DrawSVGPlugin ~3kb Animate SVG stroke drawing
MorphSVGPlugin ~8kb SVG shape morphing
MotionPathPlugin ~6kb Animate along SVG paths
TextPlugin ~2kb Character-by-character text replacement
Draggable ~7kb Drag and throw with momentum
Observer ~4kb Unified scroll/touch/pointer events
CustomEase ~3kb Design custom easing curves
EasePack ~2kb ExpoScaleEase, RoughEase, SlowMo

API Quick-Reference

// Always register plugins first
gsap.registerPlugin(ScrollTrigger, SplitText, Flip, DrawSVGPlugin);

// --- Basic Tween ---
gsap.to('.el', { x: 100, opacity: 1, duration: 0.6, ease: 'power2.out' });
gsap.from('.el', { y: 50, opacity: 0, duration: 0.6 });
gsap.fromTo('.el', { opacity: 0 }, { opacity: 1, duration: 0.6 });
gsap.set('.el', { x: 0, opacity: 1 }); // instant set, no animation

// --- Timeline ---
const tl = gsap.timeline({ defaults: { duration: 0.6, ease: 'power2.out' } });
tl.from('.a', { y: 30, opacity: 0 })
  .from('.b', { y: 30, opacity: 0 }, '-=0.3')   // overlap 0.3s
  .from('.c', { y: 30, opacity: 0 }, '+=0.1');   // gap 0.1s

// --- Stagger ---
gsap.from('.cards', { y: 40, opacity: 0, stagger: 0.1, duration: 0.5 });
gsap.from('.cards', { y: 40, opacity: 0, stagger: { each: 0.1, from: 'center' } });

// --- ScrollTrigger ---
gsap.from('.section', {
    opacity: 0, y: 50,
    scrollTrigger: {
        trigger: '.section',
        start: 'top 80%',          // trigger-top hits 80% of viewport
        end: 'top 30%',            // trigger-top hits 30% of viewport
        toggleActions: 'play none none none',  // onEnter onLeave onEnterBack onLeaveBack
        scrub: true,               // tie to scroll position (true or number for smoothing)
        pin: true,                 // pin the trigger element
        snap: 0.5,                 // snap to halfway point
        markers: true,             // debug (remove for production)
    }
});

// --- ScrollSmoother ---
// Requires: #smooth-wrapper > #smooth-content wrapping all page content
ScrollSmoother.create({
    wrapper: '#smooth-wrapper',
    content: '#smooth-content',
    smooth: 1.2,       // smoothing amount
    effects: true,     // enable data-speed parallax
});
// HTML: <div data-speed="0.8">slower</div>  <div data-speed="1.3">faster</div>

// --- SplitText ---
const split = new SplitText('.heading', { type: 'chars,words,lines' });
gsap.from(split.chars, {
    opacity: 0, y: 60, rotateX: -40,
    stagger: 0.03, duration: 0.8, ease: 'back.out(1.7)'
});
// Revert (restore original HTML): split.revert();

// --- DrawSVGPlugin ---
gsap.from('.svg-path', { drawSVG: '0%', duration: 2, ease: 'power2.inOut' });
gsap.to('.svg-path', { drawSVG: '50% 100%', duration: 1 }); // partial draw

// --- MorphSVGPlugin ---
gsap.to('#shape1', { morphSVG: '#shape2', duration: 1.5, ease: 'power2.inOut' });
gsap.to('#shape1', { morphSVG: { shape: '#shape2', shapeIndex: 'auto' } });

// --- Flip ---
const state = Flip.getState('.items');   // record current positions
container.classList.toggle('reordered'); // change layout
Flip.from(state, { duration: 0.6, ease: 'power2.inOut', stagger: 0.05, absolute: true });

// --- MotionPathPlugin ---
gsap.to('.dot', {
    motionPath: { path: '#myPath', align: '#myPath', autoRotate: true },
    duration: 3, ease: 'power1.inOut'
});

// --- Draggable ---
Draggable.create('.draggable', {
    type: 'x,y',
    bounds: '.container',
    inertia: true,  // throw with momentum
    onDrag: function() { console.log(this.x, this.y); }
});

// --- Observer ---
Observer.create({
    target: window,
    type: 'wheel,touch,pointer',
    onUp: () => goToPrevSlide(),
    onDown: () => goToNextSlide(),
    tolerance: 50,
    preventDefault: true,
});

// --- Easing ---
// power1-4.in / .out / .inOut
// expo.in / .out / .inOut
// back.out(1.7)
// elastic.out(1, 0.3)
// bounce.out
// sine.inOut
// circ.out
// steps(5)
// "none" (linear)

Anime.js v4.3

License: MIT Size: ~10kb gzipped (full bundle)

CDN URLs

<!-- UMD Bundle (script tag) -->
<script src="https://cdn.jsdelivr.net/npm/animejs@4.3/dist/bundles/anime.umd.min.js"></script>

<!-- ES Module -->
<script type="module">
  import { animate, stagger, timeline, utils } from 'https://cdn.jsdelivr.net/npm/animejs@4.3/+esm';
</script>

API Quick-Reference

// --- Basic Animation ---
anime.animate('.el', {
    translateX: 250,
    opacity: [0, 1],       // from 0 to 1
    duration: 800,
    ease: 'outExpo',
});

// --- Stagger ---
anime.animate('.items', {
    translateY: [-40, 0],
    opacity: [0, 1],
    delay: anime.stagger(100),           // 100ms between each
    delay: anime.stagger(100, { start: 500 }),    // start after 500ms
    delay: anime.stagger(100, { from: 'center' }), // ripple from center
});

// --- Timeline ---
const tl = anime.timeline({ defaults: { duration: 600, ease: 'outQuad' } });
tl.add('.a', { translateY: [30, 0], opacity: [0, 1] })
  .add('.b', { translateY: [30, 0], opacity: [0, 1] }, '-=300');

// --- Text Split (v4.1+) ---
const split = anime.text.split('.heading');
anime.animate(split.chars, {
    opacity: [0, 1],
    translateY: [20, 0],
    delay: anime.stagger(30),
});

// --- Scroll-Linked (v4+) ---
anime.animate('.el', {
    translateX: [0, 300],
    composition: 'blend',
}, {
    autoplay: anime.onScroll({
        target: '.scroll-container',
        axis: 'y',
        enter: 'top bottom',
        leave: 'bottom top',
    })
});

// --- Spring Physics (v4.2+) ---
anime.animate('.el', {
    translateX: 200,
    ease: 'spring',
    bounce: 0.4,       // 0-1
    duration: 800,
});

// --- SVG Path Drawing ---
anime.animate('.path', {
    strokeDashoffset: [anime.setDashoffset, 0],
    duration: 2000,
    ease: 'inOutQuad',
});

// --- Easing ---
// in / out / inOut variants: Quad, Cubic, Quart, Quint, Sine, Expo, Circ, Back, Bounce, Elastic
// Examples: 'outExpo', 'inOutQuad', 'outElastic(1, 0.5)', 'outBack(1.7)'
// Spring: 'spring' with bounce param

Motion.dev v12.x (formerly Framer Motion)

License: Free for vanilla JS Size: Mini = 2.3kb; Full = ~18kb

CDN URLs

<!-- Full library (global) -->
<script src="https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js"></script>

<!-- Mini (2.3kb, ES Module) -->
<script type="module">
  import { animate } from 'https://cdn.jsdelivr.net/npm/motion@latest/mini/+esm';
</script>

<!-- Full (ES Module) -->
<script type="module">
  import { animate, scroll, inView, spring } from 'https://cdn.jsdelivr.net/npm/motion@latest/+esm';
</script>

API Quick-Reference

// --- Basic Animation (WAAPI-powered) ---
animate('.el', { opacity: [0, 1], y: [30, 0] }, { duration: 0.6, easing: 'ease-out' });

// --- Spring ---
animate('.el', { x: 200 }, { type: 'spring', stiffness: 300, damping: 20 });

// --- Stagger ---
animate('.items', { opacity: [0, 1], y: [20, 0] }, { delay: stagger(0.1) });

// --- Scroll-Linked ---
scroll(
    animate('.el', { opacity: [0, 1], y: [50, 0] }),
    { target: document.querySelector('.section'), offset: ['start end', 'end start'] }
);

// --- In-View Detection ---
inView('.el', (info) => {
    animate(info.target, { opacity: 1, y: 0 }, { duration: 0.6 });
    return () => { /* cleanup on leave */ };
});

// --- Keyframes ---
animate('.el', {
    x: [0, 100, 50, 100],
    opacity: [0, 1, 1, 0],
}, { duration: 2 });

// --- Controls ---
const controls = animate('.el', { x: 200 }, { duration: 2 });
controls.pause();
controls.play();
controls.reverse();
controls.cancel();
await controls.finished; // promise-based

2. Scroll Libraries

Lenis

License: MIT | Size: ~2.1kb gzipped

<script src="https://cdn.jsdelivr.net/npm/lenis@latest/dist/lenis.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lenis@latest/dist/lenis.css">
const lenis = new Lenis({
    duration: 1.2,         // scroll smoothness
    easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
    orientation: 'vertical',
    smoothWheel: true,
});

function raf(time) {
    lenis.raf(time);
    requestAnimationFrame(raf);
}
requestAnimationFrame(raf);

// GSAP integration
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);

AOS (Animate On Scroll)

License: MIT | Size: ~5kb gzipped

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css">
<script src="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js"></script>
AOS.init({ duration: 800, once: true, offset: 100 });
<div data-aos="fade-up" data-aos-delay="200">Content</div>
<!-- Types: fade-up, fade-down, fade-left, fade-right, zoom-in, flip-left, slide-up -->

CSS Scroll-Driven Animations (Native)

Support: Chrome 115+, Safari 26+, Firefox (behind flag) Size: 0kb (native CSS)

/* Progress bar tied to page scroll */
.progress-bar {
    animation: grow-width linear;
    animation-timeline: scroll();
}
@keyframes grow-width {
    from { width: 0%; }
    to { width: 100%; }
}

/* Element fades in as it enters viewport */
.reveal {
    animation: fade-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
}
@keyframes fade-in {
    from { opacity: 0; transform: translateY(40px); }
    to { opacity: 1; transform: translateY(0); }
}

3. Text Animation Libraries

TypeIt

License: Free personal / Paid commercial | Size: ~4kb gzipped

<script src="https://cdn.jsdelivr.net/npm/typeit@8/dist/index.umd.js"></script>
new TypeIt('#terminal', {
    speed: 50,
    waitUntilVisible: true,
    cursor: true,
    cursorChar: '|',
    cursorSpeed: 1000,
})
.type('npm install my-app')
.pause(500)
.break()
.type('npm start', { speed: 30 })
.pause(300)
.delete(9)
.type('run dev')
.go();

Typed.js

License: MIT | Size: ~4kb gzipped

<script src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js"></script>
new Typed('#typed-output', {
    strings: ['Developer', 'Designer', 'Creator'],
    typeSpeed: 50,
    backSpeed: 30,
    backDelay: 2000,
    loop: true,
    showCursor: true,
    cursorChar: '|',
});

CountUp.js

License: MIT | Size: ~3kb gzipped

<script src="https://cdn.jsdelivr.net/npm/countup.js@2/dist/countUp.umd.js"></script>
const counter = new countUp.CountUp('stat-element', 1250, {
    duration: 2.5,
    separator: ',',
    prefix: '$',
    suffix: 'M',
    decimal: '.',
    decimals: 1,
    enableScrollSpy: true,
    scrollSpyOnce: true,
});
counter.start();

4. SVG Animation Libraries

Vivus.js

License: MIT | Size: ~5kb gzipped

<script src="https://cdn.jsdelivr.net/npm/vivus@0.4.6/dist/vivus.min.js"></script>
// Animate all SVG paths drawing in sequence
new Vivus('my-svg', {
    type: 'delayed',        // 'delayed' | 'sync' | 'oneByOne'
    duration: 200,          // in frames (~3.3s at 60fps)
    start: 'inViewport',
    animTimingFunction: Vivus.EASE,
});

// Manual control
const anim = new Vivus('my-svg', { type: 'scenario-sync' });
anim.play();
anim.reset();
anim.finish();

Lottie Web

License: MIT | Size: ~50kb (full), ~35kb (light)

<!-- Full (SVG + Canvas + HTML renderers) -->
<script src="https://cdn.jsdelivr.net/npm/lottie-web@5.13/build/player/lottie.min.js"></script>

<!-- Light (SVG renderer only) -->
<script src="https://cdn.jsdelivr.net/npm/lottie-web@5.13/build/player/lottie_light.min.js"></script>
const anim = lottie.loadAnimation({
    container: document.getElementById('lottie-container'),
    renderer: 'svg',
    loop: true,
    autoplay: true,
    path: 'animation.json',      // Lottie JSON file URL
    // OR: animationData: jsonObj  // inline JSON object
});

// Controls
anim.play();
anim.pause();
anim.stop();
anim.setSpeed(1.5);
anim.goToAndStop(30, true);     // go to frame 30
anim.setDirection(-1);          // reverse

// Events
anim.addEventListener('complete', () => console.log('done'));
anim.addEventListener('loopComplete', () => console.log('loop'));

5. 3D / WebGL Libraries

Three.js r183

License: MIT | Size: ~160kb gzipped

CDN URLs

<!-- Classic script tag (UMD) -->
<script src="https://cdn.jsdelivr.net/npm/three@0.183/build/three.min.js"></script>

<!-- ES Modules (recommended) -->
<script type="importmap">
{
    "imports": {
        "three": "https://cdn.jsdelivr.net/npm/three@0.183/build/three.module.min.js",
        "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183/examples/jsm/"
    }
}
</script>
<script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
    import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
    import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
</script>

<!-- Older UMD (for non-module contexts) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

API Quick-Reference

// --- Minimal Scene Setup ---
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);

// --- Geometry + Material ---
const mesh = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshStandardMaterial({ color: 0x00ffcc })
);
scene.add(mesh);

// --- Lighting ---
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);

// --- Particle System (BufferGeometry) ---
const COUNT = 500;
const positions = new Float32Array(COUNT * 3);
for (let i = 0; i < COUNT * 3; i++) positions[i] = (Math.random() - 0.5) * 20;
const particleGeo = new THREE.BufferGeometry();
particleGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const particles = new THREE.Points(
    particleGeo,
    new THREE.PointsMaterial({ color: 0xffffff, size: 0.05, transparent: true, opacity: 0.6 })
);
scene.add(particles);

// --- InstancedMesh (efficient thousands of identical objects) ---
const instanceMesh = new THREE.InstancedMesh(
    new THREE.SphereGeometry(0.1, 16, 16),
    new THREE.MeshStandardMaterial({ color: 0xff6600 }),
    1000  // count
);
const dummy = new THREE.Object3D();
for (let i = 0; i < 1000; i++) {
    dummy.position.set(Math.random()*10-5, Math.random()*10-5, Math.random()*10-5);
    dummy.updateMatrix();
    instanceMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instanceMesh);

// --- Animation Loop ---
function animate() {
    requestAnimationFrame(animate);
    mesh.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();

// --- Resize Handler ---
window.addEventListener('resize', () => {
    camera.aspect = innerWidth / innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(innerWidth, innerHeight);
});

// --- Post-Processing (Bloom) ---
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new UnrealBloomPass(
    new THREE.Vector2(innerWidth, innerHeight),
    1.5,   // strength
    0.4,   // radius
    0.85   // threshold
));
// In animation loop: composer.render() instead of renderer.render()

// --- GLTF Model Loading ---
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
    scene.add(gltf.scene);
    // Access animations: gltf.animations
});

PixiJS v8

License: MIT | Size: ~100kb gzipped

<script src="https://cdn.jsdelivr.net/npm/pixi.js@8/dist/pixi.min.js"></script>
const app = new PIXI.Application();
await app.init({ width: 800, height: 600, backgroundAlpha: 0 });
document.body.appendChild(app.canvas);

const sprite = new PIXI.Sprite(PIXI.Texture.from('image.png'));
sprite.anchor.set(0.5);
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
app.stage.addChild(sprite);

app.ticker.add((delta) => {
    sprite.rotation += 0.01 * delta.deltaTime;
});

p5.js

License: LGPL | Size: ~100kb gzipped

<script src="https://cdn.jsdelivr.net/npm/p5@1/lib/p5.min.js"></script>
// Instance mode (doesn't pollute global scope)
new p5((p) => {
    p.setup = () => {
        const canvas = p.createCanvas(800, 600);
        canvas.parent('canvas-container');
    };
    p.draw = () => {
        p.background(0, 10);
        p.fill(255, 100);
        p.noStroke();
        for (let i = 0; i < 50; i++) {
            const x = p.noise(i * 0.1, p.frameCount * 0.01) * p.width;
            const y = p.noise(i * 0.1 + 100, p.frameCount * 0.01) * p.height;
            p.circle(x, y, 8);
        }
    };
});

6. Canvas 2D / Particle Libraries

canvas-confetti

License: ISC | Size: ~6kb gzipped

<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9/dist/confetti.browser.min.js"></script>
// Basic burst
confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } });

// Fireworks
confetti({ particleCount: 50, angle: 60, spread: 55, origin: { x: 0 } });
confetti({ particleCount: 50, angle: 120, spread: 55, origin: { x: 1 } });

// Custom colors
confetti({ particleCount: 80, spread: 100, colors: ['#ff0000', '#00ff00', '#0000ff'] });

// Confetti cannon (sustained)
const end = Date.now() + 3000;
(function frame() {
    confetti({ particleCount: 3, angle: 60, spread: 55, origin: { x: 0 }, colors: ['#ff6b6b'] });
    confetti({ particleCount: 3, angle: 120, spread: 55, origin: { x: 1 }, colors: ['#4ecdc4'] });
    if (Date.now() < end) requestAnimationFrame(frame);
})();

tsParticles

License: MIT | Size: ~40kb gzipped (confetti bundle)

<script src="https://cdn.jsdelivr.net/npm/@tsparticles/confetti@3/tsparticles.confetti.bundle.min.js"></script>
// Confetti
tsParticles.confetti({ count: 100, spread: 160, ticks: 200 });

// Snow
tsParticles.confetti({
    count: 50, spread: 360, ticks: 500,
    gravity: 0.5, drift: 1,
    shapes: ['circle'], colors: ['#ffffff'],
    origin: { x: 0.5, y: 0 },
});

Matter.js

License: MIT | Size: ~30kb gzipped

<script src="https://cdn.jsdelivr.net/npm/matter-js@0.20/build/matter.min.js"></script>
const { Engine, Render, World, Bodies, Runner } = Matter;

const engine = Engine.create();
const render = Render.create({
    element: document.getElementById('physics-container'),
    engine: engine,
    options: { width: 800, height: 600, wireframes: false, background: 'transparent' }
});

// Ground
World.add(engine.world, Bodies.rectangle(400, 580, 800, 40, { isStatic: true }));

// Falling boxes
for (let i = 0; i < 10; i++) {
    World.add(engine.world, Bodies.rectangle(
        200 + Math.random() * 400, -50 - i * 60, 40, 40,
        { render: { fillStyle: '#E07A5F' } }
    ));
}

Render.run(render);
Runner.run(Runner.create(), engine);

7. Annotation / Emphasis Libraries

Rough Notation

License: MIT | Size: ~3.8kb gzipped

<script src="https://cdn.jsdelivr.net/npm/rough-notation@0.5/lib/rough-notation.iife.js"></script>
// Available types: underline, box, circle, highlight, strike-through, crossed-off, bracket

// Single annotation
const annotation = RoughNotation.annotate(document.getElementById('target'), {
    type: 'highlight',            // animation type
    color: 'rgba(245,158,11,0.3)', // annotation color
    animationDuration: 1200,       // ms
    strokeWidth: 2,                // for underline/box/circle
    padding: 5,                    // space around element
    iterations: 2,                 // roughness (1 = neat, 3+ = very rough)
    multiline: true,               // support multi-line text
    brackets: ['left', 'right'],   // for type: 'bracket'
});
annotation.show();
annotation.hide();
annotation.remove();

// Annotation Group — sequential reveal
const group = RoughNotation.annotationGroup([
    RoughNotation.annotate(el1, { type: 'underline', color: '#E07A5F' }),
    RoughNotation.annotate(el2, { type: 'circle', color: '#3B82F6' }),
    RoughNotation.annotate(el3, { type: 'highlight', color: 'rgba(34,197,94,0.3)' }),
]);
group.show(); // plays all annotations one after another

8. Page Transition Libraries

View Transitions API (Native)

Support: Baseline available Oct 2025 (Chrome 111+, Safari 18+, Firefox 133+) Size: 0kb (native browser API)

// Same-document transition
document.startViewTransition(() => {
    // Update the DOM here
    container.innerHTML = newContent;
});

// Shared element transition
// HTML: <img style="view-transition-name: hero-image" src="...">
// The browser automatically morphs elements with matching view-transition-name

// Customizing the transition
document.startViewTransition({
    update: () => { /* DOM update */ },
    types: ['slide-left'],  // named transition type
});
/* Customize the transition animation */
::view-transition-old(root) {
    animation: fade-out 0.3s ease-in;
}
::view-transition-new(root) {
    animation: fade-in 0.3s ease-out;
}

/* Target specific named transitions */
::view-transition-group(hero-image) {
    animation-duration: 0.5s;
}

Barba.js

License: MIT | Size: ~7kb gzipped

<script src="https://cdn.jsdelivr.net/npm/@barba/core@2/dist/barba.umd.js"></script>
barba.init({
    transitions: [{
        name: 'fade',
        leave(data) {
            return gsap.to(data.current.container, { opacity: 0, duration: 0.3 });
        },
        enter(data) {
            return gsap.from(data.next.container, { opacity: 0, duration: 0.3 });
        }
    }]
});

9. Layout Animation Libraries

AutoAnimate

License: MIT | Size: ~1.9kb gzipped

<script src="https://cdn.jsdelivr.net/npm/@formkit/auto-animate@0.9/dist/index.js"></script>
// One function call — all children get animated on add/remove/reorder
autoAnimate(document.getElementById('list'));

// With options
autoAnimate(document.getElementById('list'), {
    duration: 250,
    easing: 'ease-in-out',
    disrespectUserMotionPreference: false,
});

vanilla-tilt.js

License: MIT | Size: ~3kb gzipped

<script src="https://cdn.jsdelivr.net/npm/vanilla-tilt@1.8/dist/vanilla-tilt.min.js"></script>
VanillaTilt.init(document.querySelectorAll('.tilt-card'), {
    max: 15,            // max tilt degrees
    speed: 400,         // transition speed
    glare: true,        // enable glare effect
    'max-glare': 0.3,   // glare opacity
    perspective: 1000,
    scale: 1.05,        // scale on hover
});

10. Technique Tables by Animation Category

Text Animations

Technique Library Lines of Code Impact
Character stagger reveal GSAP SplitText ~10 High
Word-by-word scroll reveal GSAP ScrollTrigger ~15 High
Typewriter effect TypeIt / Custom ~5 / ~60 Medium
Text scramble/decode GSAP ScrambleText / Custom ~5 / ~30 Medium
Number counter CountUp.js / GSAP ~5 Medium
Gradient text animation CSS only ~8 Low

Scroll-Driven Animations

Technique Library Lines of Code Impact
Pinned section + scrub GSAP ScrollTrigger ~15 Very High
Smooth scroll + parallax ScrollSmoother / Lenis ~8 High
Simple fade-in on scroll Intersection Observer ~10 Medium
Horizontal scroll section GSAP ScrollTrigger ~20 High
Progress indicator CSS scroll-timeline ~8 Low
Parallax headings GSAP ScrollTrigger ~10 Medium

3D / WebGL

Technique Library Lines of Code Impact
Particle mesh background Three.js ~80 Very High
Floating 3D object Three.js ~40 High
Post-processing bloom Three.js EffectComposer ~20 High
Instanced particles Three.js InstancedMesh ~30 High
GLTF model display Three.js GLTFLoader ~20 High
Shader effects Three.js ShaderMaterial ~50+ Very High

SVG Animations

Technique Library Lines of Code Impact
Path stroke drawing GSAP DrawSVG ~8 High
Shape morphing GSAP MorphSVG ~5 High
Line art sequence Vivus.js ~8 Medium
Lottie animation Lottie Web ~10 High
Animated icons Lottie / CSS ~10 Medium

Micro-Interactions

Technique Library Lines of Code Impact
Magnetic button GSAP / Custom ~12 Medium
3D card tilt vanilla-tilt.js / Custom ~3 / ~15 Medium
Ripple click effect CSS + JS ~15 Low
Custom cursor trail Canvas + RAF ~40 Medium
Hover color shift CSS transitions ~5 Low

Layout Animations

Technique Library Lines of Code Impact
FLIP reorder/filter GSAP Flip ~8 High
Auto-animate children AutoAnimate ~1 Medium
Stagger grid reveal GSAP / anime.js ~5 Medium
Accordion expand CSS / GSAP ~10 Low

Annotation & Emphasis

Technique Library Lines of Code Impact
Hand-drawn highlight Rough Notation ~5 High
Hand-drawn underline Rough Notation ~5 Medium
Hand-drawn circle Rough Notation ~5 High
Sequential annotation group Rough Notation ~10 Very High
Bracket emphasis Rough Notation ~5 Medium

11. Audience → Recommended Stack

Audience Primary Stack Add-Ons Total Size
Corporate GSAP + ScrollTrigger + Rough Notation CountUp.js ~45kb
Developer GSAP + ScrollTrigger + SplitText + DrawSVG TypeIt ~50kb
Creative GSAP + ScrollTrigger + SplitText + Three.js Lenis, vanilla-tilt ~210kb
Marketing GSAP + ScrollTrigger + SplitText + Rough Notation CountUp.js, confetti ~50kb
Educational GSAP + ScrollTrigger + SplitText + DrawSVG + Rough Notation TypeIt ~55kb