# How ai-website-cloner-template Handles Scroll-Driven Animations: A Complete Implementation Guide

> Discover how ai-website-cloner-template implements scroll-driven animations. Learn about trigger mechanisms, computed styles, and various approaches for dynamic web experiences.

- Repository: [JCodesMore/ai-website-cloner-template](https://github.com/JCodesMore/ai-website-cloner-template)
- Tags: how-to-guide
- Published: 2026-07-07

---

**The template treats scroll-driven interactions as first-class "interaction models" that require detecting the trigger mechanism, capturing computed styles at both initial and scrolled states, then implementing the specific trigger—whether IntersectionObserver, CSS scroll-snap, position:sticky, animation-timeline, or a library like Lenis—in the cloned React components.**

The `ai-website-cloner-template` by JCodesMore provides a systematic workflow for reproducing scroll-driven animations when cloning websites. Unlike static layouts, scroll-triggered effects require capturing both the trigger mechanism and the visual transition states to ensure behavioral fidelity. According to the inspection guide in [`docs/research/INSPECTION_GUIDE.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/docs/research/INSPECTION_GUIDE.md), the template encodes scroll-driven interactions as a core "interaction model" that developers must identify before writing any clone code.

## Detecting the Scroll Interaction Model

Before implementing any animation, you must identify which mechanism drives the scroll behavior. The workflow documented in [`.opencode/commands/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.opencode/commands/clone-website.md) and [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md) requires manually scrolling through the target page and categorizing the interaction into one of five trigger types.

### IntersectionObserver Patterns

Look for elements that appear, fade in, or transform when entering the viewport. These typically rely on the **IntersectionObserver API** rather than scroll event listeners. Check for libraries like **GSAP ScrollTrigger** or native observers that toggle visibility classes.

### CSS Scroll-Snap and Sticky Positioning

Identify containers with `scroll-snap-type` properties or headers that become fixed after scrolling past a certain point. **Scroll-snap** creates a carousel-like experience where the viewport locks to specific sections, while **position:sticky** elements transition from relative to fixed positioning based on scroll position.

### CSS Animation-Timeline

Modern browsers support **scroll-driven animations** using `animation-timeline: scroll()` in CSS. These animations progress based on scroll position without JavaScript.

### JavaScript Scroll Libraries

Heavy smooth-scrolling effects often use **Lenis** or **Locomotive Scroll**. These libraries replace native scrolling with inertia-based smooth scrolling and require specific initialization in the React root.

## Capturing Computed Styles at Scroll Positions 0 and Threshold

Once you identify the trigger, record the element's computed styles at two critical points. According to [`INSPECTION_GUIDE.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/INSPECTION_GUIDE.md) lines 103-108, use `getComputedStyle` to capture:

1. **Scroll position 0**: The initial state before any scroll interaction
2. **Scroll past threshold**: The final state after the trigger activates (e.g., 120px scroll)

Store these values in the component specification as a JSON block under `states: {initial: …, scrolled: …}`. This data feeds directly into the builder agent that generates the clone components.

## Implementing Scroll Triggers in Next.js 18/React 19

The template targets **Next.js 18/React 19** for implementations. Place your code in the appropriate file based on the trigger type:

| Trigger type | Implementation approach | File location |
|--------------|------------------------|---------------|
| **IntersectionObserver** | Create a `useEffect` hook that observes the target element and toggles state (`isVisible`). Apply scrolled CSS via `className` or `style`. | `src/components/<YourComponent>.tsx` |
| **scroll-snap** | Add `scroll-snap-type: y mandatory` on the container and `scroll-snap-align: start` on children. No JavaScript required. | [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css) |
| **position:sticky** | Apply `position: sticky; top: 0` and optionally change background/shadow when `scrollY > threshold`. | Component CSS or [`globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/globals.css) |
| **CSS animation-timeline** | Use `@keyframes` with `animation-timeline: scroll()` for modern browsers. | [`globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/globals.css) |
| **JS scroll library** | Initialize Lenis/Locomotive in a `useEffect` and add a CSS class (e.g., `.lenis`) to the root element. | [`src/app/layout.tsx`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/layout.tsx) for initialization, [`globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/globals.css) for class styling |

### IntersectionObserver Hook Example

```tsx
import { useEffect, useState } from "react";

export default function ScrollFade() {
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    const target = document.querySelector("#fade-target");
    if (!target) return;
    const observer = new IntersectionObserver(
      ([entry]) => setVisible(entry.isIntersecting),
      { rootMargin: "0px", threshold: 0.1 }
    );
    observer.observe(target);
    return () => observer.disconnect();
  }, []);

  return (
    <div
      id="fade-target"
      className={visible ? "opacity-100" : "opacity-0"}
      style={{ transition: "opacity 0.5s ease" }}
    >
      {/* content that appears on scroll */}
    </div>
  );
}

```

*Source:* Pattern described in [`docs/research/INSPECTION_GUIDE.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/docs/research/INSPECTION_GUIDE.md) lines 86-89.

### Lenis Smooth Scroll Initialization

```tsx
// src/app/layout.tsx
"use client";
import { useEffect } from "react";
import Lenis from "@studio-freight/lenis";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    const lenis = new Lenis({
      smooth: true,
      lerp: 0.1,
    });
    function raf(time: number) {
      lenis.raf(time);
      requestAnimationFrame(raf);
    }
    requestAnimationFrame(raf);
    return () => lenis.destroy();
  }, []);

  return <html>{children}</html>;
}

```

```css
/* src/app/globals.css */
html.lenis {
  scroll-behavior: auto; /* Lenis handles smoothing */
}

```

*Source:* Library recommendation in [`.opencode/commands/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.opencode/commands/clone-website.md) lines 78-83.

### Scroll-Snap CSS Implementation

```css
/* src/app/globals.css */
.scroll-snap-container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 100vh;
}
.scroll-snap-item {
  scroll-snap-align: start;
  height: 100vh;
}

```

```tsx
// src/components/ui/ScrollSnap.tsx
export default function ScrollSnap() {
  return (
    <div className="scroll-snap-container">
      <section className="scroll-snap-item bg-red-200">Page 1</section>
      <section className="scroll-snap-item bg-blue-200">Page 2</section>
    </div>
  );
}

```

*Source:* Scroll-snap guidance in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md) lines 65-68.

## Configuring Global Styles and Dependencies

Add all scroll-related keyframes, utility classes, and global behaviors to [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css). If the original site uses **Lenis** or **Locomotive Scroll**, install the dependency via `npm i lenis` and update [`package.json`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/package.json). The [`README.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/README.md) (lines 90-98) specifically reminds developers to note any libraries that require installation.

## Verifying the Cloned Scroll Experience

Run the development server with `npm run dev` and manually scroll through the entire page. Verify that headers, sticky sidebars, scroll-snap sections, and parallax layers match the original both **visually and behaviorally**. Check that thresholds trigger at the same scroll positions and that smooth-scroll libraries maintain the same inertia and damping as the source.

## Summary

- **Identify** the interaction model first using [`docs/research/INSPECTION_GUIDE.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/docs/research/INSPECTION_GUIDE.md) before writing implementation code
- **Record** both pre- and post-trigger CSS values using `getComputedStyle` at scroll positions 0 and threshold
- **Implement** the exact trigger mechanism—IntersectionObserver, scroll-snap, sticky, animation-timeline, or JS library—in the appropriate file (`src/components/*.tsx`, [`src/app/layout.tsx`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/layout.tsx), or [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css))
- **Install** required dependencies like Lenis and add global CSS classes to [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css)
- **Test** the scrolling experience end-to-end to ensure behavioral fidelity with the original site

## Frequently Asked Questions

### How does ai-website-cloner-template identify scroll-driven animations?

The template uses a systematic inspection process documented in [`docs/research/INSPECTION_GUIDE.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/docs/research/INSPECTION_GUIDE.md) that requires manually scrolling the target page and categorizing the behavior into one of five trigger types: IntersectionObserver, scroll-snap, position:sticky, CSS animation-timeline, or JavaScript scroll libraries like Lenis. This classification determines where the implementation code belongs and which dependencies are required.

### Where should I initialize smooth scroll libraries like Lenis?

Initialize Lenis and similar libraries in [`src/app/layout.tsx`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/layout.tsx) using a `useEffect` hook that creates a new instance and sets up a `requestAnimationFrame` loop. Apply the library's CSS class (e.g., `.lenis`) to the root `html` element in the same file, and add corresponding styles to [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css).

### What is the difference between handling scroll-snap and IntersectionObserver?

**Scroll-snap** is a pure CSS solution that requires adding `scroll-snap-type` to a container and `scroll-snap-align` to children in [`src/app/globals.css`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/app/globals.css), with no JavaScript needed. **IntersectionObserver** requires a React `useEffect` hook in `src/components/<YourComponent>.tsx` that observes elements and toggles state to apply CSS classes when elements enter the viewport.

### How do I store scroll states for the builder agent?

Capture `getComputedStyle` values at scroll position 0 and at the trigger threshold (e.g., 120px), then store them in the component specification as a JSON object with the structure `states: {initial: {…}, scrolled: {…}}`. This allows the builder agent to generate components with the correct initial and animated styles.