agentleFS
calebnewtonusccalebnewtonusc/Chewbacca/skills/clone-site/SKILL.md

clone-site

Skill8 starsChanged 3 months agoMITView on GitHub

Rebuild an existing website faithfully: a replica, a design study, or a page that has to match a reference. Use when asked to clone, replicate, copy, match or rebuild a site, when a reference URL is given as the target to hit, when the user says make it look like <site>, and when a build is being judged against a live page. Also fires on: clone, replica, reverse engineer, match this site, like their site, fidelity, pixel perfect, same as theirs, why is theirs better.

3 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

5 rules. 0 are common, 5 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 3 edited versions we read keep these.

  • 5

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before any instrument. Scroll the entire page and capture every section.

    line 52
  2. Distinctive:

    Read to learn the technique and the parameters, then write your own.

    line 82
  3. Distinctive:

    An instrument that samples is an instrument that lies: Check its coverage before believing a negative result.

    line 120
  4. Distinctive:

    No measurement of the effective value can find this, because the effective value is correct.

    line 177
  5. Distinctive:

    Every section from step 0 is built.

    line 224

“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Clone site

Rebuilding a page faithfully fails in two different ways, and doing one of them well does not protect you from the other.

Method A, inspect the surface. Screenshot it, read getComputedStyle, list the components, build from that. It is what most cloning guides teach and it is thorough about states, tokens and breakpoints.

Method B, read what was shipped. Fetch the payload, parse the chunk manifest, read the source that generates the thing. It is exact where A is approximate, and it says nothing at all about hover states or breakpoints.

Doing only A means inventing a mechanism that happens to match the output. Doing only B means shipping a component whose default state is perfect and whose hover state does not exist.

Process discipline here is adapted from JCodesMore/ai-website-cloner-template (MIT), which is the best-organised version of A I have read. The bundle work and the instruments are this kit's. Both halves below are load-bearing.

The evidence this is written from

A replica of one page, 2026-09-26 to 27, two full days.

Its densest figure was rebuilt as a fitted probability field: p(d) = -1.0125 d² + 1.4126 d + 0.0556. That matched the real density to a few percent. The figure is Wolfram Rule 30, 40 cells, 50 generations, one seed, wrapping boundaries, and their component is named CellularAutomataFigure in a lazy chunk that shipped the whole time. With the real generator: 842 live cells and 1158 dead, matching exactly, with no tuned parameter.

Fitting a distribution to a generative figure's output is not recovering it.

The same two days also produced: a claim of "no parallax on the reference" from an instrument that sampled 26 of 9,133 elements, a component declared dead code that turned out to be the richest thing on the page, and six plates shipped at the wrong size because the layout was read off a screenshot. The user's summary was that four of his screenshots taught more in thirty seconds than six hours of measurement, because they showed what exists. Measurement only ever refines what you already know is there.

Order of operations

0. Look at the whole thing first, with a human

Before any instrument. Scroll the entire page and capture every section. If the user is present, ask them to scroll it and send frames; they will catch sections you did not know existed. An inventory of what is there precedes every measurement of how it behaves, and no amount of the second substitutes for the first.

Output: a numbered section list with scroll offsets. Nothing else starts until this exists.

1. Take the assets and the payload

brand-grab <out> --site <url>      # their fonts, palette, images, photos
curl -sL <url> -o page.html        # the served HTML, which carries a lot

Parse the chunk manifest, not just what the HTML references. On the page above, the HTML referenced 37 chunks and the webpack manifest listed 79; the generators were in the half nobody had fetched.

curl -sL <origin>/_next/static/chunks/webpack-*.js      # or the equivalent
# check for source maps: a 200 on <chunk>.js.map ends the guessing entirely

Then grep the bundle for magic constants, never for an API you guessed. setAttribute("cx" returns nothing because React does not emit that string. A literal radius like .5888 lands in exactly the file that generates it.

Do not vendor their code, CSS, fonts or third-party logos into the repo. Read to learn the technique and the parameters, then write your own. Company marks in a logo wall belong to those companies, not to the site being copied.

2. Sweep the states, not just the default

The step most often skipped, and the one that produces "it looks almost right but feels cheap". For every component capture: default, hover, active, focus, disabled, loading, empty, error, and open where it opens. Then desktop, tablet and phone, and note where the layout actually shifts.

A missed state is invisible in a screenshot and obvious in use.

3. Write a spec before building

One file per component: exact computed values, DOM structure, every state, verbatim text, assets, responsive behaviour. The spec is the source of truth and the build reads from it.

This is also what makes parallel builders work. Seven agents dispatched at a page with no spec contract produced nothing usable, because each was measuring rather than building. Agents given a spec build; agents given a URL wander.

4. Build, then diff

ux-scan <url> --out lenses/<name>     # every element, every scroll position
ux-rate lenses/<name>                 # what moves against scroll, and at what rate
ux-recover lenses/<name>              # recover generators from served geometry
ux-diff lenses/<ref> lenses/<mine>    # rank the gap by axis
design-gate <url> --shots 8           # refuses a page that is broken

design-gate catches broken, never bad. It passed the replica above on a turn the user called the result unusable, and its own docstring says so. Fidelity is ux-diff's job; treat a green gate as "not broken" and nothing more.

The traps, each paid for

An instrument that samples is an instrument that lies. Check its coverage before believing a negative result. "No parallax on this page" came from 26 elements out of 9,133; the real figure was 38% of elements moving at a rate between pinned and normal flow.

Measure the observable, not the implementation. That instrument read each element's own transform. The reference animated containers, so a parallaxing child reported transform: none. An element's rect against scroll offset cannot be fooled by which ancestor or which property carried the motion.

Counts are per element, not per page. A path total attributed to one figure sent a 714-path construction into a frame that holds 48.

Fixed pixels or percentages is a measurable question. Measure at three viewport widths. If sizes hold and only offsets move by half the delta, it is a capped centred container, and percentage positioning will pull the composition apart on a wide screen.

Delays that are not round numbers are usually chained. A draw starting at 0.42s running 1.1s, with the next stage at 1.52s, is 0.42 + 1.1. Each stage begins as the previous ends. An index * 100ms stagger cannot express that, because it never knows how long anything takes.

Normalise path lengths for a draw-on. pathLength="100" with strokeDasharray="100" makes twelve edges of different screen lengths finish together. Without it the short ones land first and the object assembles raggedly.

A declared transition is not a running one. 842 circles carried transition: cx 220ms and none of them ever moved on load or on pointer move. It fires on click, after an entrance completes. Probing found nothing twice; the source said it outright.

The traps from the second pass, 2026-09-27

Added after a morning where the page still looked wrong and three DOM measurements in a row said it did not.

THE PIXELS OUTRANK THE DOM. Three probes were wrong in one morning: "the ring renders 0 paths" (the selector did not count polygon), "the ring is missing its 0.6 opacity" (it was on the <svg> and the probe read the <g>), "every plate is 6px too low" (they were 6px too SHORT and top-anchored, so the bottoms already matched). Each would have become a commit that fixed nothing. Crop the same region from both screenshots and look. That found in one image what three probes missed.

When two things measure identical and render differently, ask WHERE the value is applied, not what it is. Sixty rotated pentagons: identical geometry, identical stroke width, identical effective opacity (0.6 on both sides, walking the parent chain and multiplying). Theirs crosshatched, ours a smooth airbrushed donut.

per element   two crossing strokes at 0.6 give 1-(1-0.6)^2 = 0.84, so
              crossings are darker and the moire survives
on the group  all 60 composite into one layer at full alpha FIRST, every
              crossing saturates, THEN the finished layer fades

No measurement of the effective value can find this, because the effective value is correct. Filters, transforms, blend modes and masks all compose differently on a group than on its children.

Measure the element's inset inside its container. Their figures sat in a well: l19 t24 r19 b19 on some plates, l1 t6 r1 b1 on others. Ours all filled the frame. Missing 19px each side of a 202px box draws the contents 19% too large while every internal measurement stays correct, which is the most confusing possible combination. It is also not one rule: check every container, because a page will have two or three classes of them.

Neither uniform nor random. Go and read the palette. A wall of 42 bricks was first a rigid lattice with i % 4 failures, then, correcting that, a seeded random masonry with widths drawn from 96..208. Both wrong. Theirs: seven rows of six, four widths only (154, 182, 197, 221) in a fixed sequence per row, and row centres alternating between two values 38px apart. The ragged look came from the alternating centre, not from random widths. Overcorrecting from uniform to random is still not measuring.

Stage ORDER carries the meaning, so measure the sequence, not just the states. Our failure highlight fired while the wall was still solid and was gone before the outlines arrived. Theirs: solid wall, wall goes quiet, then the nine that failed light up against the quiet. Same states, same colours, and ours read as a wall that flickered rather than a wall with faults in it.

Pair sections by position, never by heading text. A clone has its own copy, so headings match on maybe 5 of 11 sections and an automatic text match silently pairs the other 6 wrong. Write the pairing by hand, assert it increases on both sides, interpolate between anchors. Where a paired gap is wildly unequal (928px on theirs against 3425px on ours) that is not a matching failure, that is the finding.

Compare at 90 chunks, not 20. At one screen per frame a section's internals never appear next to their counterpart. At 90 the same scene shows up in several frames at different offsets, which makes a spacing difference visible rather than inferrable.

Check brand and third-party marks before anything visual, in the RENDERED innerText. A clone will quietly keep the original's real customer names, real email addresses, real investor badges and real repo paths. Ours shipped twelve real people's real quotes, a real employee's email and a real investor logo, all still rendering after a rebrand pass that only touched the source. Grep the DOM text, case-insensitively, for the original's name.

Done means

Every section from step 0 is built. Every component has a spec and every state in that spec renders. ux-diff has been run against the reference and its ranked gaps are either closed or written down, design-gate exits 0, and nothing of theirs has been vendored into the repo.

Credit

Phase structure, the spec-file discipline, the mandatory interaction sweep and the visual QA diff are adapted from JCodesMore/ai-website-cloner-template, MIT, © 2025 JCodesMore. Its method is Method A done properly and it is worth reading directly. It does not cover bundle reading, which is the half that makes generative figures recoverable rather than approximable.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.