skills / Development
clone-site
Clone any website from a URL into a pixel-faithful Next.js codebase — recon, asset/CSS extraction, parallel section builders, animation porting, and automated fidelity verification. Use whenever the user pastes a URL and asks to clone, copy, replicate, rebuild, reverse-engineer, or "make me a version of" a website or landing page — even if they don't say the word "clone". Also triggers on "/clone-site <url>". For multi-page sites it discovers and clones every page via the sitemap.
<url> [<url2> ...] [notes like 'landing page only' or 'always animate']
Clone Site
Reverse-engineer the site(s) at $ARGUMENTS into a Next.js codebase. This skill encodes a refined version of the ai-website-cloner-template pipeline: the big lesson is that most marketing sites are static (Astro, plain HTML, SSR), and for those the served source IS the ground truth — downloading it beats hand-measuring computed styles every time. Only fall back to browser-side style extraction for true SPAs.
Default scope: every page in the site's sitemap, pixel-perfect, with real assets and working interactions. If the user scopes it down ("just the landing page"), honor that.
Phase 0 — Project setup
- Create the project OUTSIDE any repo you're currently in:
If the folder exists, ask before overwriting.git clone --depth 1 https://github.com/JCodesMore/ai-website-cloner-template.git ~/Desktop/<hostname>-clone cd ~/Desktop/<hostname>-clone && rm -rf .git && git init -q && npm install - Make research dirs:
docs/research/<hostname>/,docs/research/components/,docs/design-references/. - Check
~/Desktop/inspo/sites.json(the inspo hub — the permanent home of all finished clones, private repocaezium/inspo): if this site was already cloned, ask whether to redo it or extend the existing one. The Desktop folder is a workspace; the clone isn't done until Phase 6 registers it in the hub.
Phase 1 — Stack detection (decides everything)
curl -sS <url> and inspect:
- Content-complete HTML (real headings/copy in the response;
_astro/assets, or no root<div id="root|__next">shell) → source-first path (rest of this skill). - SPA shell (empty root div, content materializes from JS) → the template's browser-extraction pipeline is the right tool; follow
.claude/skills/clone-website/SKILL.mdinside the scaffold (screenshots +getComputedStyle()extraction per section). The verification and parallel-builder phases below still apply.
Record: framework, stylesheet links, inline <style>/<script> blocks, font links, animation libraries (grep for gsap, ScrollTrigger, lenis, framer).
Phase 2 — Download the ground truth (source-first path)
All into docs/research/<hostname>/:
- Every page: fetch
sitemap.xml(orsitemap-index.xml) for the definitive URL list. No sitemap → crawl nav/footer links one level. Save each page's HTML. - Every stylesheet — including page-specific ones (Astro emits per-page CSS files; different pages reference different ones).
- Every behavior script — inline AND external
<script type="module">. These minified files are the exact spec for animations; you will port them, not guess. - Every asset to
public/: write a small Node download script. Sources of asset URLs:<img src>AND everysrcsetvariant,<video src/poster>, CSSurl()refs, favicons, webmanifest, OG images. Missing asrcsetvariant means broken images at other viewport widths — grep the HTML for all of them. - Take reference screenshots with Chrome MCP at 1440px (scroll through, screenshot each viewport-full) and note per-section behavior: what pins, what fades, what's tabbed vs scroll-driven. Two traps:
- Lazy images look blank during fast programmatic scrolling — a blank card usually means
loading="lazy"hadn't fired, not a real gap. Confirm via DOM (naturalWidth > 0) before "fixing" anything. prefers-reduced-motion: if macOS Reduce Motion is on, both the original and your screenshots may show the static branches. CheckmatchMedia('(prefers-reduced-motion: reduce)')and read the source scripts forreducegates so you know which animations exist even if you can't see them.
- Lazy images look blank during fast programmatic scrolling — a blank card usually means
Phase 3 — Foundation (do this yourself, not via agents)
- CSS verbatim: concatenate all downloaded CSS + inline
<style>blocks intosrc/app/globals.css, stripping framework scoping attrs (e.g.[data-astro-cid-*]). Keep the original class names. Do NOT translate to Tailwind — every translation step is drift risk, and fidelity beats idiom. Identical duplicate rules across per-page CSS files are harmless. - Fonts: replicate the original's Google Fonts
<link>(or download self-hosted fonts). The CSS references literal family names, sonext/font's renamed families would break it — plain<link>inlayout.tsxis correct here. - layout.tsx metadata: title, description, favicon, OG image from the original head.
trailingSlash: trueinnext.config.tsif the original uses trailing-slash URLs.- Install animation libs the site uses (
npm i gsapetc.) — port to the npm package, never vendor the minified bundle. - Write
docs/research/PAGE_TOPOLOGY.md(section map, interaction model per section) andBEHAVIORS.md(exact mechanisms from the de-minified scripts: trigger points, easings, durations, media-query gates). These are the builders' bible.
Phase 4 — Parallel build
Split the page into sections (hero, nav, feature blocks, footer, modals...). For each, write a brief spec in docs/research/components/<name>.spec.md: target file, ground-truth fragment path, interaction model, behavior notes, gotchas.
Dispatch parallel builder agents (Agent tool, general-purpose), ~4–7 at once. Worktrees are unnecessary if each agent owns disjoint files — pre-write shared files yourself and forbid agents from touching them. Every builder prompt includes:
- Ground-truth fragment path + spec path + BEHAVIORS.md reference
- Conversion rules: strip scoping attrs;
class→className,srcset→srcSet, camelCase SVG attrs, self-closing tags; text verbatim — including apostrophe/quote style (don't "fix" straight quotes to curly or vice versa; it shows up in the fidelity diff) - "All CSS already exists in globals.css under the original class names — write NO new CSS, NO Tailwind"
- Port behaviors from the actual source scripts (de-minify), as hooks with cleanup; respect the original's media-query/motion gates unless the user asked otherwise
- "Only create/modify your own target files"; verify
npx tsc --noEmit - Ask builders to REPORT deviations and shared-component mismatches they notice — they catch real fidelity bugs (per-page CTA text variants, footer blocks present only on some pages)
Cross-component dependencies: use composition (<Hero>{<HeroCard/>}</Hero> via children) so agents never import each other's unfinished files.
Multi-page sites: extract shared chrome (Nav/Footer/Modals) into components with variant props FIRST — then per-page builders reuse them. Grep every page for the differences before assuming they're identical: nav light/dark variant, CTA label, aria-current, footer link blocks. Pages sharing one template (blog posts, comparison pages) batch 5 per agent.
Assemble src/app/page.tsx (and routes) yourself; run npm run build after merging.
Phase 5 — Verify (don't skip; this catches what eyeballs miss)
npx tsc --noEmitandnpm run build— must be clean.npx next start -p 3210and run the bundled text-fidelity diff:
(Copypython3 scripts/fidelity-diff.py --research docs/research/<hostname> --base http://localhost:3210scripts/fidelity-diff.pyfrom this skill's directory into the project.) It strips tags/scripts, decodes entities, and reports missing words per page. Target ≥99%; chase every gap to root cause — real omissions vs entity-encoding artifacts vs apostrophe-style drift all look different in the output.- Live QA with Chrome MCP: side-by-side against the original at the same scroll positions; click every interactive element (tabs, accordions, toggles, modals); check the console for errors. Verify scroll-pinned sections actually pin (
.pin-spacerexists, body height grew). - Capture a real homepage screenshot of the CLONE for the hub card — the template's stock
docs/design-references/comparison.pngis a demo image, not your site; delete it:"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu \ --screenshot=docs/design-references/clone-home-1440.png --window-size=1440,900 \ --hide-scrollbars --virtual-time-budget=12000 http://localhost:3210/ - Commit with a summary of sections/components/assets. No AI attribution in the message.
Phase 6 — Register in the inspo hub
Every finished clone gets consolidated into ~/Desktop/inspo (gallery of all clones; sites.json is the single source of truth — index.html renders purely from it, no other wiring).
- Snapshot the code:
rsync -a --delete --exclude node_modules --exclude .next --exclude .git \ ~/Desktop/<hostname>-clone/ ~/Desktop/inspo/sites/<id>/ git -C ~/Desktop/<hostname>-clone bundle create ~/Desktop/inspo/histories/<id>.bundle --all<id>= short lowercase name (see existing ids in sites.json). - Add a
sites.jsonentry:kind: "nextjs",port= next free 31xx,thumbnail= the real clone screenshot from Phase 5 (never a stock/template image), 3–5 design-vibetags(reuse existing tag vocabulary where it fits),description= one line on the design language,original_url, andrun: "./serve.sh <id>". - Verify:
cd ~/Desktop/inspo && ./serve.sh→ the new card renders with its thumbnail at localhost:4600. Then commit + push (origin= privatecaezium/inspo). - Ask the user whether to delete the Desktop working folder. Before any deletion: check no other session is actively developing it (uncommitted work, recent commits you didn't make, running dev servers) — the hub snapshot captures files, not in-flight work. The history bundle preserves the git log either way.
Judgment calls to surface to the user (don't silently decide)
- Reduced motion: if the original gates animations on
prefers-reduced-motionand the user's OS has it on, the clone will look "broken but faithful". Default to matching the original's code; if the user reports missing animations, offer the always-animate override (drop the gates, comment the deviation). - Backend endpoints (
/api/download, form posts): a static clone can't replicate them. Keep the original URLs/actions and say so in the completion report. - Analytics (PostHog, GA): strip them; note it.
Completion report
Sections built, components created, assets downloaded, routes generated, build status, fidelity-diff scores, interactions tested, known gaps (backend routes, uncloned linked pages), and hub registration (sites.json id + port, pushed to caezium/inspo).