How ai-website-cloner-template Handles Scroll-Driven Animations: A Complete Implementation Guide
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, 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 and .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 lines 103-108, use getComputedStyle to capture:
- Scroll position 0: The initial state before any scroll interaction
- 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 |
| position:sticky | Apply position: sticky; top: 0 and optionally change background/shadow when scrollY > threshold. |
Component CSS or globals.css |
| CSS animation-timeline | Use @keyframes with animation-timeline: scroll() for modern browsers. |
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 for initialization, globals.css for class styling |
IntersectionObserver Hook Example
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 lines 86-89.
Lenis Smooth Scroll Initialization
// 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>;
}
/* src/app/globals.css */
html.lenis {
scroll-behavior: auto; /* Lenis handles smoothing */
}
Source: Library recommendation in .opencode/commands/clone-website.md lines 78-83.
Scroll-Snap CSS Implementation
/* 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;
}
// 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 lines 65-68.
Configuring Global Styles and Dependencies
Add all scroll-related keyframes, utility classes, and global behaviors to src/app/globals.css. If the original site uses Lenis or Locomotive Scroll, install the dependency via npm i lenis and update package.json. The 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.mdbefore writing implementation code - Record both pre- and post-trigger CSS values using
getComputedStyleat 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, orsrc/app/globals.css) - Install required dependencies like Lenis and add global CSS classes to
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 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 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.
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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →