Capture a real website, rebuild it, and prove the rebuild is correct — one pixel at a time.
clone
is a design-cloning workshop. A Chrome extension captures a live site's screenshot, DOM, and computed styles; a Claude Code plugin turns that capture into a clone that is verified pixel-by-pixel against the original screenshot by a measuring oracle. No "looks close enough" — every region is scored, and the clone isn't done until the diff is under threshold.
A real oracle, not eyeballing. The clone is rendered in headless Chromium at the capture's exact DPR, cropped to the reference's exact size, and diffed per-pixel. Every DOM box gets a match score against a calibrated floor.Two targets, one engine./clone:html
emits a staticpage.html
;/clone:react
emits shadcn/ui components with the site's captured states (hover, focus, dialogs) as real props. Same measurement code underneath.Systematic-cause-first reports. A 3px sidebar offset that breaks 200 boxes reports asoneupstream cause, not 200 failures.Behavior, not just looks. The React target gets command palettes, focus traps, and keyboard nav from Radix — the things a screenshot can't capture.Honest by construction. Fonts are self-hosted and gated (a fallback font fails the run). Icons ship as verified files. Photos become neutral placeholders and are never asserted.
Cloning a UI by hand always drifts — spacing creeps, a color is one shade off, a font silently falls back. This project makes drift measurable. The capture is ground truth (a real PNG bitmap plus the computed styles that produced it), and the clone is graded against it on every cycle until it passes.
The example header above is Doppler's Team settings page:
| Original | Clone | Pixel diff |
|---|
The pixel diff is mostly dark — matching pixels — with color only where the clone and original disagree (chiefly the deliberately-omitted brand marks). The oracle also annotates every measured region ( boxes.png) with the color and geometry it checks. The live clone itself is
. (Brand marks are deliberately dropped from the clone; see the disclaimer below.)
example/render.html
graph LR
A[Chrome extension] -->|ref.png · DOM · computed styles| B[capture folder]
B --> C[prep · extract · resolve · cluster]
C --> D[author page.html / .tsx]
D --> E[check: render → diff → score]
E -->|failing boxes| D
E -->|0 failing| F[verified clone]
Capture— the extension takes a full-page screenshot (one shot, via CDP device-metrics override, not stitched) plus a recursive tree of every node's rect, text, ~50 computed style properties, and its:hover
/:focus
states.Prep / extract / resolve / cluster— validate the capture, derive a shared design system (base.css
, tokens, self-hosted fonts, open-source icon glyphs), and cluster repeated subtrees into components.Author— build one route by hand from the extractedlayout.md
.Check— render, diff against the reference, and score every box. Fix, repeat, until zero boxes fall below their floor.
Full architecture: docs/CODEBASE_MAP.md · pipeline design rationale: docs/PIPELINE_GRAPH.md.
clone
is a Claude Code plugin. Install it from this repo's marketplace:
/plugin marketplace add HarKro753/claude-copy
/plugin install clone@clone-marketplace
Enabling the plugin puts the clone
CLI on your Bash PATH and loads the
/clone:html
and /clone:react
skills. See Requirements for the Python (PIL + Playwright), Node, and Chrome pieces the pipeline needs.
The capture side is a Chrome MV3 extension in capture-extension/, loaded unpacked (no Web Store, no account):
- Open
chrome://extensions
. - Toggle
Developer mode(top right). Load unpacked→ select thecapture-extension/
folder.
The copy-website capture action then appears in your toolbar. It writes a
capture folder that clone prep
consumes.
The plugin puts one CLI on PATH while enabled:
clone prep <session> --target html|react # target recorded in routes.json
clone extract # layout.md, tree.json, shared/*
clone resolve # fetch/recolor open-source icon glyphs
clone cluster # detect repeated components
clone init | map | build # react target only
clone check [route] # render → diff → score, loop until 0 failing
Static HTML in one line per phase; React adds init
(scaffold + theme), map
(shadcn component per node), and build
(vite → self-contained page.html
).
- Python 3 with
PIL andPlaywright(Chromium) on the system
python3
— the oracle. - Node + a package manager for the React target (React + Vite + Tailwind v4 + shadcn/ui).
- Chrome — load
capture-extension/
as an unpacked Manifest V3 extension. Claude Codewith theclone
plugin enabled (auto-loads from this repo).
assets/ example capture, clone render, pixel diff, annotated boxes, README banner
example/ the live static clone (render.html + its fonts/css/svg)
capture-extension/ Chrome MV3 capture tool
skills/clone/ the pipeline plugin (engine/ + html & react targets)
docs/ CODEBASE_MAP.md · PIPELINE_GRAPH.md
The engine is skills/clone/engine/
— one module per concern, with the two artifacts behind a shared Target
interface, so adding a third is one file in targets/
, not a fork. After touching the engine, run all four test files:
cd skills/clone/tests
python3 -m pytest test_engine.py test_react.py test_hook.py test_e2e.py
Doppler is used purely as a technical fixture to demonstrate the pipeline. This project is not affiliated with, endorsed by, or sponsored by Doppler; all trademarks and brand marks belong to their respective owners. Clones are rendered locally for measurement only and are never deployed as live sites.
MIT © Harro Krog. See CONTRIBUTING, Code of Conduct, and Security Policy.