Site Clone
You are about to reverse-engineer and rebuild $ARGUMENTS as pixel-perfect replicas inside this Next.js codebase.
When given multiple URLs, isolate each site's extraction artifacts in docs/research/<hostname>/ and process them in parallel where possible.
You are not working in two discrete phases. You are a construction foreman — as you inspect each section, you draft a detailed blueprint, then hand it to a specialist builder with everything they need. Extraction and construction overlap, but extraction is meticulous and produces auditable artifacts.
Scope Defaults
Clone exactly what is visible at the given URL. Unless the user says otherwise:
- Fidelity: Pixel-perfect — exact colors, spacing, typography, animations
- Included: Visual layout, component structure, interactions, responsive behavior, mock data
- Excluded: Real backend, authentication, real-time features, SEO audit, accessibility audit
- Customization: None — pure emulation first
Honor any additional user instructions over these defaults.
Pre-Flight
- Browser automation is mandatory. Check for Chrome MCP, Playwright MCP, Browserbase MCP, Puppeteer MCP, or similar. If none are available, ask the user. This skill cannot run without browser control.
- Parse
$ARGUMENTSas one or more URLs. Validate each — if invalid, ask the user. Navigate to each and confirm it loads. - Verify the base scaffold builds:
npm run build. The Next.js + shadcn/ui + Tailwind v4 foundation must be in place. - Create output directories if missing:
docs/research/,docs/research/components/,docs/design-references/,scripts/.
Core Principles
These principles govern every decision. Internalize them.
1. Exhaustive Extraction Over Fast Shipping
Every builder agent must receive everything it needs. If a builder has to guess a color, a padding value, or an animation timing — you have failed at extraction. Spend the extra minute extracting one more property rather than shipping an incomplete brief.
2. Granular Tasks Produce Precision
A builder given "build the entire features section" will approximate spacing, guess font sizes, and produce something close but clearly wrong. A builder given a single focused component with exact CSS values nails it every time. If a section has 3+ distinct sub-components, break it up.
Complexity budget: If a builder prompt exceeds ~150 lines of spec content, the section is too complex for one agent. Split it.
3. Authentic Content Only
Extract actual text, images, videos, and SVGs from the live site. This is a clone, not a mockup. Use element.textContent, download every <img> and <video>, extract inline <svg> as React components. The only exception: content that is clearly server-generated and unique per session.
Layered assets matter. A section that looks like one image is often multiple layers — a background gradient, a foreground mockup PNG, an overlay icon. Inspect each container's full DOM tree and enumerate ALL images within it, including absolutely-positioned overlays.
4. Global Foundation Before Any Component
Nothing can be built until the foundation exists: global CSS with design tokens, TypeScript types, global assets (fonts, favicons). This is sequential and non-negotiable. Everything after this can be parallel.
5. Capture Motion, Not Just Appearance
A website is not a screenshot. Elements move, change, appear, and disappear in response to scrolling, hovering, clicking, resizing, and time. For every element, extract its appearance (exact computed CSS) AND its behavior (what changes, what triggers the change, how the transition happens).
Not "it looks like 16px" — extract the actual computed value. Not "the nav changes on scroll" — document the trigger, the before/after CSS values, and the transition.
6. Determine Interaction Driver First
This is the single most expensive mistake in cloning: building click-driven tabs when the original is scroll-driven, or vice versa. Before writing any builder prompt for an interactive section, definitively answer: Is this section driven by clicks, scrolls, hovers, time, or some combination?
How to determine this:
- Don't click first. Scroll through the section slowly and observe if things change on their own.
- If they do — it's scroll-driven. Extract the mechanism.
- If nothing changes on scroll — click and hover to test.
- Document the interaction model explicitly in the blueprint.
7. Every State Matters — Extract All Of Them
Many components have multiple visual states. A tab bar shows different content per tab. A header looks different at scroll 0 vs scroll 100. A card has hover effects. You must extract ALL states.
For tabbed/stateful content:
- Click each tab/button via browser MCP
- Extract the content, images, and data for EACH state
- Record which content belongs to which state
- Note the transition animation between states
For scroll-dependent elements:
- Capture computed styles at scroll 0 and after the trigger
- Diff the two to identify which properties change
- Record the transition CSS and trigger threshold
8. Blueprints Are Contracts
Every component gets a blueprint file in docs/research/components/ BEFORE any builder is dispatched. The blueprint is the contract between extraction and building. The builder receives it inline — never "go read the file."
9. Continuous Compilation
Every builder must verify npx tsc --noEmit passes. After merging worktrees, run npm run build. A broken build is never acceptable.
Stage 1: Survey
Navigate to the target URL with browser MCP.
Screenshots
- Full-page screenshots at 1440px (desktop) and 390px (mobile)
- Save to
docs/design-references/with descriptive names
Global Token Extraction
Extract these from the page before anything else:
Fonts — Inspect <link> tags for Google Fonts or self-hosted fonts. Check computed font-family on headings, body, code, labels. Document every family, weight, and style. Configure in layout.tsx using next/font/google or next/font/local.
Colors — Extract the site's color palette from computed styles. Update globals.css with the target's actual colors. Map to shadcn token names where they fit. Add custom properties for extras.
Favicons & Meta — Download favicons, apple-touch-icons, OG images, webmanifest to public/seo/. Update layout.tsx metadata.
Global UI patterns — Identify site-wide CSS/JS: custom scrollbar hiding, scroll-snap, global keyframe animations, backdrop filters, smooth scroll libraries (Lenis, Locomotive Scroll — check for .lenis, .locomotive-scroll classes). Add to globals.css.
Mandatory Interaction Sweep
This is a dedicated pass AFTER screenshots and BEFORE component work. Its purpose is to discover every behavior on the page.
Scroll Sweep
Scroll the page slowly from top to bottom via browser MCP. At each section, pause and observe:
- Does the header change appearance? Record the scroll position threshold.
- Do elements animate into view? Record which ones and the animation type.
- Does a sidebar or tab indicator auto-switch as you scroll?
- Are there scroll-snap points?
- Is there a smooth scroll library active?
Interactive Element Deep Extraction
This is critical. Systematically discover and document every interactive element on the page:
Button Audit:
- Find every
<button>,<a>,[role="button"], and clickable element - For each: record its text, href/target, visual style at rest
- Click it via browser MCP and record what happens: navigation? modal? state change? animation?
- Record hover effect: color change, scale, shadow, underline, opacity shift
- Record the transition CSS (duration, easing)
Tab/Pill/Segmented Control Audit:
- Find every tab group, pill selector, or segmented control
- Click EACH tab/pill one by one
- For each state: screenshot the visible content, extract all text and images
- Record the active indicator style (underline, background fill, font weight change)
- Record the content transition animation (fade, slide, instant swap)
- Map: { tabLabel → contentHTML, images[], cardData[] }
Carousel/Slider Audit:
- Find every carousel, slider, or horizontally scrollable container
- Scroll/swipe through ALL slides
- For each slide: screenshot, extract content, images, text
- Record: total slide count, auto-play behavior, transition type (slide, fade, scale)
- Record navigation controls: dots, arrows, swipe gestures
- Map: { slideIndex → content }
Dropdown/Menu Audit:
- Find every dropdown trigger (nav items, select-like elements, "more" buttons)
- Click each one to open
- Screenshot the expanded state
- Extract all menu items: text, icons, href, sub-menus
- Record open/close animation
Accordion/Expandable Audit:
- Find every accordion, FAQ section, or collapsible element
- Click each to expand
- Extract the revealed content (text, images, code blocks)
- Record expand/collapse animation (height transition, rotation of chevron icon)
- Check: can multiple be open simultaneously, or is it exclusive?
Modal/Dialog Audit:
- Find elements that trigger modals (buttons with "Sign up", "Learn more", "Watch demo", etc.)
- Click each trigger via browser MCP
- Screenshot the modal content
- Extract all content inside the modal
- Record: overlay style, entrance animation, close mechanism
- IMPORTANT: close each modal before proceeding to the next
Hover Effect Audit:
- Hover over every element that might have hover states: buttons, cards, links, images, nav items
- Record what changes: color, scale, shadow, underline, opacity, transform
- Record the transition CSS (property, duration, easing)
Scroll-Triggered Animation Audit:
- Scroll slowly and watch for elements that animate into view
- Record: which elements, animation type (fade-up, slide-in, scale-in, stagger), trigger point (viewport intersection ratio), duration
- Check if animations replay on re-scroll or fire only once
Responsive Sweep
Test at 3 widths via browser MCP:
- 1440px (desktop), 768px (tablet), 390px (mobile)
- At each width, note layout changes (column → stack, sidebar disappears, hamburger menu appears)
- Note approximately which breakpoint triggers each change
Save ALL interaction findings to docs/research/BEHAVIORS.md.
Page Topology
Map every distinct section top to bottom. Give each a working name. Document:
- Visual order
- Fixed/sticky vs. flow positioning
- Page layout (scroll container, columns, z-layers)
- Section dependencies
- Interaction model of each section (static, click-driven, scroll-driven, time-driven, swipe-driven)
Save as docs/research/TOPOLOGY.md.
Stage 2: Foundation
Sequential. Do this yourself — not delegated.
- Update fonts in
layout.tsxto match the target site - Update globals.css with extracted color tokens, spacing, keyframes, global scroll behaviors
- Create TypeScript interfaces in
src/types/for observed content structures - Extract SVG icons — find all inline
<svg>elements, deduplicate, save as named React components insrc/components/icons.tsx(e.g.,SearchIcon,ArrowRightIcon,LogoIcon) - Trigger all lazy-loaded content — scroll the entire page slowly via browser MCP to force-load lazy images and scroll-triggered content:
// Run via browser MCP to trigger all lazy content
(async function() {
const totalHeight = document.body.scrollHeight;
const step = window.innerHeight / 2;
for (let y = 0; y < totalHeight; y += step) {
window.scrollTo(0, y);
await new Promise(r => setTimeout(r, 400));
}
window.scrollTo(0, 0);
await new Promise(r => setTimeout(r, 500));
// Report lazy-loaded elements found
const lazySrcs = [...document.querySelectorAll('[data-src],[data-lazy-src],[data-original],[data-srcset],[loading="lazy"]')].map(el => ({
tag: el.tagName,
dataSrc: el.dataset?.src || el.dataset?.lazySrc || el.dataset?.original,
dataSrcset: el.dataset?.srcset,
currentSrc: el.src || el.currentSrc,
loaded: el.tagName === 'IMG' ? el.complete : true
}));
return JSON.stringify({ lazyElements: lazySrcs.length, lazySrcs });
})();
- Discover all assets — run the comprehensive asset discovery script:
JSON.stringify({
images: [...document.querySelectorAll('img')].map(img => ({
src: img.currentSrc || img.src,
srcset: img.srcset || null,
sizes: img.sizes || null,
alt: img.alt,
width: img.naturalWidth,
height: img.naturalHeight,
loading: img.loading,
parentTag: img.parentElement?.tagName,
position: getComputedStyle(img).position,
zIndex: getComputedStyle(img).zIndex
})),
videos: [...document.querySelectorAll('video')].map(v => ({
src: v.src || v.querySelector('source')?.src,
type: v.querySelector('source')?.type,
poster: v.poster,
autoplay: v.autoplay, loop: v.loop, muted: v.muted, playsInline: v.playsInline
})),
backgroundImages: [...document.querySelectorAll('*')].filter(el => {
const bg = getComputedStyle(el).backgroundImage;
return bg && bg !== 'none';
}).map(el => ({
url: getComputedStyle(el).backgroundImage,
element: el.tagName + (el.id ? '#' + el.id : '') + (el.className ? '.' + el.className.toString().split(' ')[0] : '')
})),
pseudoBackgrounds: (() => {
const results = [];
document.querySelectorAll('*').forEach(el => {
for (const pseudo of ['::before', '::after']) {
const bg = getComputedStyle(el, pseudo).backgroundImage;
if (bg && bg !== 'none') {
results.push({ element: el.tagName + '.' + (el.className?.toString().split(' ')[0] || ''), pseudo, url: bg });
}
}
});
return results;
})(),
svgs: [...document.querySelectorAll('svg')].map((svg, i) => ({
index: i,
viewBox: svg.getAttribute('viewBox'),
width: svg.getAttribute('width'),
height: svg.getAttribute('height'),
pathCount: svg.querySelectorAll('path').length,
label: svg.getAttribute('aria-label') || svg.querySelector('title')?.textContent
})),
fonts: (() => {
const fontFaces = [...document.styleSheets].flatMap(sheet => {
try { return [...sheet.cssRules].filter(r => r instanceof CSSFontFaceRule).map(r => ({ family: r.style.fontFamily, src: r.style.src, weight: r.style.fontWeight, style: r.style.fontStyle })); }
catch { return []; }
});
const googleFonts = [...document.querySelectorAll('link[href*="fonts.googleapis"]')].map(l => l.href);
const computed = [...new Set([...document.querySelectorAll('h1,h2,h3,h4,h5,h6,p,a,span,button,input,label,code')].map(el => getComputedStyle(el).fontFamily))];
return { fontFaces, googleFonts, computed };
})(),
favicons: [...document.querySelectorAll('link[rel*="icon"],link[rel="apple-touch-icon"],link[rel="manifest"]')].map(l => ({ rel: l.rel, href: l.href, sizes: l.sizes?.toString(), type: l.type })),
meta: {
title: document.title,
description: document.querySelector('meta[name="description"]')?.content,
ogImage: document.querySelector('meta[property="og:image"]')?.content,
themeColor: document.querySelector('meta[name="theme-color"]')?.content
}
}, null, 2);
- Write asset manifest — create
docs/research/asset-manifest.jsonfrom the discovery results, then run:node scripts/fetch-assets.mjs - Verify asset completeness — after downloading, check that every
<img>src andbackground-imageURL has a corresponding local file. Re-download any missing items. - Verify:
npm run buildpasses
Stage 3: Blueprint & Build
The core loop. For each section in your topology (top to bottom): extract → blueprint → dispatch.
Step 1: Extract
For each section, use browser MCP to extract everything:
Screenshot the section in isolation. Save to
docs/design-references/.Extract CSS for every element using the deep extraction script:
(function(selector) {
const el = document.querySelector(selector);
if (!el) return JSON.stringify({ error: 'Not found: ' + selector });
const PROPS = [
'fontSize','fontWeight','fontFamily','lineHeight','letterSpacing','color',
'textTransform','textDecoration','textAlign','wordSpacing',
'backgroundColor','background','backgroundImage','backgroundSize','backgroundPosition',
'padding','paddingTop','paddingRight','paddingBottom','paddingLeft',
'margin','marginTop','marginRight','marginBottom','marginLeft',
'width','height','maxWidth','minWidth','maxHeight','minHeight',
'display','flexDirection','justifyContent','alignItems','alignSelf','flexWrap','flexGrow','flexShrink','gap','rowGap','columnGap',
'gridTemplateColumns','gridTemplateRows','gridColumn','gridRow','gridAutoFlow',
'borderRadius','borderTopLeftRadius','borderTopRightRadius','borderBottomLeftRadius','borderBottomRightRadius',
'border','borderTop','borderBottom','borderLeft','borderRight','borderColor','borderWidth','borderStyle',
'boxShadow','textShadow',
'overflow','overflowX','overflowY','overscrollBehavior',
'position','top','right','bottom','left','zIndex','float',
'opacity','visibility','transform','transformOrigin',
'transition','transitionProperty','transitionDuration','transitionTimingFunction','transitionDelay',
'animation','animationName','animationDuration','animationTimingFunction','animationDelay','animationIterationCount',
'cursor','pointerEvents','userSelect',
'objectFit','objectPosition','aspectRatio',
'mixBlendMode','filter','backdropFilter',
'whiteSpace','textOverflow','WebkitLineClamp','WebkitBoxOrient',
'scrollSnapType','scrollSnapAlign','scrollBehavior',
'clipPath','maskImage','contain','willChange'
];
function grab(element, pseudo) {
const cs = pseudo ? getComputedStyle(element, pseudo) : getComputedStyle(element);
const result = {};
PROPS.forEach(p => {
const v = cs[p];
if (v && v !== 'none' && v !== 'normal' && v !== 'auto' && v !== '0px' && v !== 'rgba(0, 0, 0, 0)' && v !== 'start') result[p] = v;
});
return result;
}
function walk(element, depth) {
if (depth > 5) return null;
const kids = [...element.children];
const node = {
tag: element.tagName.toLowerCase(),
id: element.id || null,
classes: element.className?.toString?.().split(' ').filter(Boolean).slice(0, 8) || [],
text: element.childNodes.length === 1 && element.childNodes[0].nodeType === 3 ? element.textContent.trim().slice(0, 300) : null,
styles: grab(element),
href: element.tagName === 'A' ? element.href : null,
img: element.tagName === 'IMG' ? { src: element.src, srcset: element.srcset, alt: element.alt, naturalWidth: element.naturalWidth, naturalHeight: element.naturalHeight } : null,
video: element.tagName === 'VIDEO' ? { src: element.src || element.querySelector('source')?.src, poster: element.poster, autoplay: element.autoplay, loop: element.loop, muted: element.muted } : null,
svg: element.tagName === 'svg' || element.tagName === 'SVG' ? { viewBox: element.getAttribute('viewBox'), innerHTML: element.innerHTML.slice(0, 500) } : null,
childCount: kids.length,
children: kids.slice(0, 30).map(c => walk(c, depth + 1)).filter(Boolean)
};
// Pseudo-elements
const beforeBg = getComputedStyle(element, '::before').backgroundImage;
const afterBg = getComputedStyle(element, '::after').backgroundImage;
if (beforeBg && beforeBg !== 'none') node['::before'] = grab(element, '::before');
if (afterBg && afterBg !== 'none') node['::after'] = grab(element, '::after');
return node;
}
return JSON.stringify(walk(el, 0), null, 2);
})('SELECTOR');
- Extract interactive element states — for components with tabs, sliders, or state changes:
// For a tab group: click each tab and extract its content
(async function(tabSelector, contentSelector) {
const tabs = [...document.querySelectorAll(tabSelector)];
const results = [];
for (const tab of tabs) {
tab.click();
await new Promise(r => setTimeout(r, 500)); // wait for transition
const content = document.querySelector(contentSelector);
results.push({
tabText: tab.textContent.trim(),
tabActive: tab.classList.toString(),
contentHTML: content?.innerHTML?.slice(0, 2000),
images: [...(content?.querySelectorAll('img') || [])].map(img => ({ src: img.src, alt: img.alt })),
text: content?.textContent?.trim().slice(0, 1000)
});
}
return JSON.stringify(results, null, 2);
})('TAB_SELECTOR', 'CONTENT_SELECTOR');
- Extract hover states — capture before/after CSS for interactive elements:
// Compare resting vs. hover CSS for an element
(function(selector) {
const el = document.querySelector(selector);
if (!el) return '{}';
const before = {};
const cs = getComputedStyle(el);
['color','backgroundColor','boxShadow','transform','opacity','borderColor','textDecoration','scale'].forEach(p => before[p] = cs[p]);
return JSON.stringify({ selector, restingStyles: before, transition: cs.transition });
})(SELECTOR);
Then hover via browser MCP and re-extract to get the diff.
Extract real content — all text, alt attributes, aria labels. For tabbed content, click each tab and extract per state.
Identify assets — which downloaded images/videos map to this section. Check for layered images.
Step 2: Write the Blueprint
For each section (or sub-component), create a blueprint file.
Path: docs/research/components/<component-name>.blueprint.md
Template:
# <ComponentName> Blueprint
## Overview
- **Target file:** `src/components/<ComponentName>.tsx`
- **Screenshot:** `docs/design-references/<name>.png`
- **Interaction model:** <static | click-driven | scroll-driven | time-driven | swipe-driven>
## DOM Structure
<Element hierarchy — what contains what>
## Computed Styles (from getComputedStyle)
### Container
- display: ...
- padding: ...
- (every relevant property with exact values)
### <Child element 1>
- fontSize: ...
- color: ...
## Interactive Elements
### Buttons
| Text | Type | Href | Hover Effect | Click Action |
|------|------|------|-------------|-------------|
| "Learn More →" | link | /docs | opacity 0.8, underline | navigate |
### Tabs / State Switches
| Tab Label | Active Style | Content Summary |
|-----------|-------------|-----------------|
| "Video Generation API" | font-weight: 700, border-bottom: 2px solid white | Video cards with... |
| "Image Generation API" | ... | Image cards with... |
### Carousel / Slider
- Slide count: N
- Auto-play: yes/no, interval: Nms
- Transition: slide/fade, duration: Nms
- Navigation: arrows/dots/swipe
- Slides: [{ content description, images }]
## State Transitions
### <Behavior name>
- **Trigger:** <exact mechanism>
- **State A:** <CSS values>
- **State B:** <CSS values>
- **Transition:** <duration, easing, properties>
### Hover States
- **<Element>:** <property>: <before> → <after>, transition: <value>
## Per-State Content (for tabbed/stateful components)
### State: "<Tab 1 Label>"
- Title: "..."
- Description: "..."
- Cards/Items: [{ title, description, image, link }]
### State: "<Tab 2 Label>"
- ...
## Assets
- Background: `public/images/<file>`
- Images: `public/images/<file1>`, `public/images/<file2>`
- Icons: <ArrowIcon>, <SearchIcon> from icons.tsx
## Text Content (verbatim)
<All text, copy-pasted from live site>
## Responsive Behavior
- **Desktop (1440px):** <layout>
- **Tablet (768px):** <changes>
- **Mobile (390px):** <changes>
- **Breakpoint:** ~<N>px
Fill every section. If N/A, write "N/A" — but think twice. Even a footer has hover states on links.
Step 3: Dispatch Builders
Based on complexity, dispatch builder agents in worktrees:
Simple section (1-2 sub-components): One builder. Complex section (3+ sub-components): One agent per sub-component + one for the wrapper.
Every builder receives:
- Full blueprint contents inline (not a file reference)
- Path to section screenshot
- Shared imports:
icons.tsx,cn(), shadcn primitives - Target file path
- Instruction to verify
npx tsc --noEmit - Responsive breakpoints and changes
Don't wait. Dispatch builders for section N while extracting section N+1. Builders work in parallel via worktrees.
Step 4: Merge
As builders complete:
- Merge worktree branches into main
- Resolve conflicts intelligently (you have full context)
- After each merge:
npm run build - Fix type errors immediately
Stage 4: Assembly
After all sections are built and merged, wire everything in src/app/page.tsx:
- Import all section components
- Implement page-level layout from your topology (scroll containers, columns, sticky positioning, z-layers)
- Connect content to component props
- Implement page-level behaviors: scroll snap, scroll-driven animations, theme transitions, intersection observers, smooth scroll
- Wire interactive element logic: tab state management, carousel auto-play, modal triggers
- Verify:
npm run buildpasses
Stage 5: Fidelity Check
Do NOT declare completion without this.
- Open the original and your clone at the same viewport widths
- Compare section by section at 1440px desktop
- Compare again at 390px mobile
- For each discrepancy: check the blueprint — was extraction correct? Fix at the source.
- Test every interactive element:
- Click every button — does it do the right thing?
- Click every tab — does the correct content appear with the right transition?
- Scroll through carousels — are all slides present?
- Open every dropdown/accordion
- Hover over all interactive elements — do effects match?
- Scroll the page — do scroll-triggered animations fire correctly?
- Test responsive — does the layout adapt at the right breakpoints?
- Asset completeness check — compare every visible image in the original with your clone. Any missing images are bugs.
Pre-Dispatch Checklist
Before dispatching ANY builder, verify:
- Blueprint file written with ALL sections filled
- Every CSS value from
getComputedStyle(), not estimated - Interaction model identified (static / click / scroll / time / swipe)
- For stateful components: every state's content and styles captured
- For scroll-driven: trigger, before/after styles, transition recorded
- For hover: before/after values and timing recorded
- For tabs: every tab clicked, content per tab extracted
- For carousels: every slide captured with content and images
- All images in the section identified (including overlays and layers)
- Responsive behavior documented for desktop, tablet, and mobile
- Text content verbatim from site
- Builder prompt under ~150 lines; if over, split the section
- All interactive elements documented: buttons (text, href, effect), links, form elements
- Layout verified via DOM inspection (grid vs flex vs block), not assumed from screenshot
- Footer section included in topology
- Language/region version confirmed with user
- Asset URLs preserved with full query strings for CDN auth tokens
Anti-Patterns
Lessons from failed clones — each one costs hours of rework:
Building click-tabs when the original is scroll-driven. Determine the interaction model FIRST by scrolling before clicking. This requires a complete rewrite, not a CSS tweak.
Extracting only the default state. If tabs show "Video Generation API" on load, you must also click "Image Generation API" and "Virtual Try-On API" to extract each state's content and cards.
Missing layered/overlay images. A background gradient + foreground photo + floating badge = 3 separate assets. Check every container's DOM tree for multiple images.
Building HTML mockups for content that's actually video. Check if a section uses
<video>, Lottie, or<canvas>before building elaborate HTML replicas.Approximating CSS. "It looks like
text-lg" is wrong if the computed value shows18pxwith24pxline-height buttext-lgmaps to28px. Extract exact values.Skipping interactive element logic. A "Learn More →" button that goes nowhere breaks the clone's credibility. Extract every button's href, click handler, and destination.
Forgetting carousel content. A slider with 8 slides but you only captured the 3 visible clone. Scroll/click through ALL slides.
Not triggering lazy-loaded images. Scroll the entire page FIRST to force all lazy images to load, THEN run asset discovery.
Missing hover/focus effects on navigation. Navigation links almost always have hover effects. Extract them.
Ignoring dropdown menu contents. A nav item that opens a mega-menu contains valuable structure and links. Click every nav item.
Giving a builder too much scope. If the prompt is getting long, the section is too complex for one agent. Break it up.
Referencing docs from builder prompts. Each builder gets the CSS spec inline — never "see DESIGN_TOKENS.md." Zero external doc reads.
Skipping responsive extraction. Desktop-only inspection means broken tablet and mobile layouts. Test at 1440, 768, and 390.
Forgetting smooth scroll libraries. Check for Lenis (
.lenisclass), Locomotive Scroll, or similar. Default browser scrolling feels noticeably different.Guessing layout from screenshots instead of verifying DOM. A section that looks like "3 small cards in a row" might actually be "3 full-width stacked cards" or "3 columns with image-on-top." Always extract the DOM hierarchy with
getBoundingClientRect()andgridTemplateColumns/flexDirectionto confirm the actual layout before building.Tab extraction with insufficient wait time. Frameworks like Vue/React use fade transitions (300-500ms). Clicking a tab and extracting after 500ms may capture the old content mid-transition. Wait at least 1200ms after tab click, and verify the content title changed before extracting. If you see transition classes like
fade-leave-active, poll until they disappear.Assuming carousel slides contain images when they contain videos. Always check for both
<video>and<img>in each slide. A carousel that displays video previews looks like images in a screenshot but requires<video>elements with autoplay/loop/muted.Stripping CDN query params from asset URLs. Many CDNs (Akamai, CloudFront, custom) embed auth tokens in query strings. Downloading with stripped URLs returns 404. Keep the full URL for downloads; only clean the filename for local storage.
Forgetting the footer. Always include Footer in the page topology. It typically has multi-column link groups, copyright text, and social icons. Add "Footer extracted" as a mandatory checklist item.
Not confirming language/region version. International sites often have different layouts per locale (e.g.,
klingai.com/devin Chinese vskling.ai/devin English). Check<html lang="">and confirm with the user which version to clone before starting.
Completion Report
When done, report:
- Total sections built
- Total components created
- Total blueprint files written (should match components)
- Total assets downloaded (images, videos, SVGs, fonts)
- Interactive elements captured (buttons, tabs, carousels, dropdowns, accordions, modals)
- Build status (
npm run buildresult) - Fidelity check results (any remaining discrepancies)
- Known gaps or limitations
Source: CloveSVG/One-Click-Clone — distributed by TomeVault.