# CDN Setup (No Bundler)

For plain HTML/CSS/JS projects without npm/webpack/vite.

---

## Script tags

Add before closing `</body>`:

```html
<!-- Lenis Smooth Scroll -->
<script src="https://cdn.jsdelivr.net/npm/lenis@1.3.0/dist/lenis.min.js"></script>

<!-- GSAP + ScrollTrigger -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.0/dist/ScrollTrigger.min.js"></script>

<!-- Sebanim8 init (your custom file) -->
<script src="js/sebanim8.js"></script>
```

## CSS

Add to `<head>`:

```html
<!-- Lenis base styles (required for smooth scroll) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lenis@1.3.0/dist/lenis.css">

<!-- Sebanim8 animation CSS -->
<link rel="stylesheet" href="css/sebanim8.css">
```

## Combined JS file

Since there's no module system, combine all layers into a single IIFE:

**File: `js/sebanim8.js`**

```javascript
(function () {
  'use strict';

  // Respect reduced motion
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    console.info('[sebanim8] Reduced motion — animations disabled.');
    return;
  }

  gsap.registerPlugin(ScrollTrigger);

  // --- Layer 1: Smooth Scroll ---
  const lenis = new Lenis({
    duration: 1.2,
    easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
    smoothWheel: true,
    touchMultiplier: 1.5,
  });

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

  // Expose for modal integration
  window.sebanim8 = {
    lenis,
    pause: () => lenis.stop(),
    resume: () => lenis.start(),
  };

  // --- Layer 2: Section Reveals ---
  document.querySelectorAll('section').forEach((section) => {
    gsap.set(section, {
      clipPath: 'inset(100% 0% 0% 0%)',
      scale: 0.96,
      opacity: 0.3,
    });

    gsap.to(section, {
      clipPath: 'inset(0% 0% 0% 0%)',
      scale: 1,
      opacity: 1,
      ease: 'power2.out',
      duration: 1,
      scrollTrigger: {
        trigger: section,
        start: 'top 95%',
        end: 'top 30%',
        scrub: 0.8,
      },
    });
  });

  // --- Layer 3: Entry Animations ---
  var PRESETS = {
    up:    { y: 60, opacity: 0 },
    down:  { y: -50, opacity: 0 },
    left:  { x: 70, opacity: 0 },
    right: { x: -70, opacity: 0 },
    scale: { scale: 0.8, opacity: 0 },
    pop:   { scale: 0.75, rotation: -2, y: 40, opacity: 0 },
    blur:  { filter: 'blur(18px)', y: -30, scale: 0.95, opacity: 0 },
    clip:  { clipPath: 'inset(100% 0% 0% 0%)', opacity: 0 },
    wipe:  { clipPath: 'inset(0% 100% 0% 0%)', opacity: 0 },
  };

  var TO_OVERRIDES = {
    clip: { clipPath: 'inset(0% 0% 0% 0%)', opacity: 1 },
    wipe: { clipPath: 'inset(0% 0% 0% 0%)', opacity: 1 },
    blur: { filter: 'blur(0px)', y: 0, scale: 1, opacity: 1 },
  };

  document.querySelectorAll('[data-anim]').forEach(function (el) {
    var animType = el.dataset.anim;
    var delay = parseFloat(el.dataset.delay) || 0;
    var from = PRESETS[animType];
    if (!from) return;

    gsap.set(el, from);

    var to = Object.assign(
      { y: 0, x: 0, scale: 1, rotation: 0, opacity: 1 },
      TO_OVERRIDES[animType] || {},
      {
        duration: 1.1,
        delay: delay,
        ease: 'power3.out',
        scrollTrigger: {
          trigger: el,
          start: 'top 88%',
          toggleActions: 'play none none none',
        },
      }
    );

    gsap.to(el, to);
  });

  // --- Layer 4: Parallax ---
  document.querySelectorAll('[data-parallax]').forEach(function (el) {
    var speed = parseFloat(el.dataset.parallax) || 0;
    speed = Math.max(-0.12, Math.min(0.1, speed));

    gsap.to(el, {
      y: speed * 350,
      ease: 'none',
      scrollTrigger: {
        trigger: el,
        start: 'top bottom',
        end: 'bottom top',
        scrub: true,
      },
    });
  });

  // --- Layer 5: Particles ---
  document.querySelectorAll('.seba-particles').forEach(function (container) {
    var count = parseInt(container.dataset.particleCount) || 20;
    var frag = document.createDocumentFragment();

    for (var i = 0; i < count; i++) {
      var p = document.createElement('span');
      p.className = 'seba-particle';
      var size = Math.random() * 3 + 1;
      p.style.cssText =
        'width:' + size + 'px;height:' + size + 'px;' +
        'left:' + (Math.random() * 100) + '%;' +
        'bottom:' + (Math.random() * 20 - 10) + '%;' +
        'animation-duration:' + (Math.random() * 10 + 6) + 's;' +
        'animation-delay:' + (Math.random() * 8) + 's;';
      frag.appendChild(p);
    }

    container.appendChild(frag);
  });
})();
```

## Combined CSS file

Merge the ambient and interaction CSS into a single `css/sebanim8.css`:

Copy the contents of:
1. `sebanim8-ambient.css` (Layer 5)
2. `sebanim8-interactions.css` (Layer 6)
3. Accessibility block (`@media (prefers-reduced-motion: reduce)`)

All into one file. The contents are in `references/implementation.md`.
