Page Tailwindify
This skill reproduces a live page's exact look in clean, semantic Tailwind. The
original's framework-generated class hashes (css-1a2b3c, sc-bdfBwQ, jsx-1234)
are gone, replaced by real utility classes (flex gap-4 rounded-lg px-6 hover:bg-…).
The design does not change — colors, type, spacing, and layout stay identical. Only
the styling system changes, from opaque generated selectors to readable Tailwind.
The accuracy trick: don't guess Tailwind from a screenshot, and don't rely on
getComputedStyle alone (one state — loses @media, :hover, breakpoints). Drive
the rewrite from the page's real markup and CSS plus a dump of real computed
values, so every Tailwind class comes from an actual number, not an eyeball.
This sits between its two sibling skills: page-cloner keeps the exact look but keeps
the ugly selectors (byte-exact extract); page-redesigner rebuilds and changes the
look. This one keeps the look, cleans the selectors.
The parts
- Capture ground truth — reuse
page-clonerto extract the faithful DOM + real CSS, plus screenshots; dumpscripts/computed.jsvalues if translating. Seereferences/capture-notes.mdfor the capture gotchas. - Detect, then branch into one of two modes:
references/rehost.md— already-Tailwind page: swap the inlined compiled CSS for the Tailwind CDN. Nothing to translate.references/rewrite.md(+references/mapping.md) — hashed / CSS-in-JS page: translate real CSS +computed.jsonvalues into semantic HTML + Tailwind, section by section.
references/validate.md— validate in a loop. Screenshot the result, compare against the original on the single fidelity axis, fix drift, repeat.
Read each reference file when you reach that part; don't load them all upfront.
Workflow
1. Capture ground truth
Requires Claude in Chrome — if unavailable, stop and tell the user; the rewrite needs the real rendered page, and guessing produces a fake with nothing to validate against.
- Extract the faithful clone. Invoke the
page-clonerskill (itsreferences/capture.md) to produce<workspace>/clone/index.html— the real rendered DOM with real CSS inlined. This is the structural + CSS spec the rewrite reads from (it carries@media,:hover, fonts — things a screenshot can't). - Dump computed values — only if step 2's detection finds hashed / CSS-in-JS
styling; an already-Tailwind page skips this. Evaluate
scripts/computed.jsand save the array to<workspace>/original/computed.json— exact per-element values to map onto Tailwind. Capture it at the SAME viewport width you validate at (1280). - Screenshot the original (full page + per section, and one narrow-width shot for
breakpoint checking) to
<workspace>/original/, as the human-eye yardstick.
Real capture has several non-obvious failure modes (tool-output content filter,
resize_window not shrinking the window, Chrome blocking the second download). Read
references/capture-notes.md before capturing — it has the workarounds.
2. Detect the styling system, then branch
Before touching anything, check what the page is built with. Grep the markup in
clone/index.html for hashed selectors:
grep -oE '(css-[a-z0-9]+|sc-[a-zA-Z]+|jsx-[0-9]+|[A-Za-z]+_[A-Za-z0-9]{5,}__?[A-Za-z0-9]+)' clone/index.html
(the last alternative catches CSS-Modules names like Button_button__3xYz1).
- Already Tailwind — utility classes present (
grid,lg:grid-cols-2,bg-[#c1ff72],font-sans) and the grep returns nothing → 2a, rehost mode. The markup already IS clean Tailwind; there's nothing to translate. - Hashed / CSS-in-JS — classes look like
css-1a2b3c,sc-bdfBwQ,jsx-1234, or styling lives in a compiled stylesheet keyed by opaque selectors → 2b, translate mode. This is the case the skill is built for. - Mixed — Tailwind utilities and hashed selectors together (common with component libraries): treat as 2b, but leave the already-Tailwind portions as-is and only translate the hashed ones.
2a. Rehost-on-CDN mode
Follow references/rehost.md. Strip the inlined compiled-Tailwind <style>, keep the
markup, add the Tailwind CDN + the real font link. Produces a much smaller
<workspace>/tailwind/index.html with byte-identical classes. computed.json is not
needed for this mode.
2b. Translate mode
Follow references/rewrite.md, mapping with references/mapping.md. Section by
section, turn the real markup + CSS + computed.json values into semantic markup with
Tailwind classes. Produces one self-contained <workspace>/tailwind/index.html
(Tailwind CDN is fine for a preview): generated hashes stripped, fonts and assets
preserved.
3. Validate in a loop — one axis: fidelity
Follow references/validate.md. Render with scripts/shoot.py, compare against the
original captures section by section (and at a narrow width for breakpoints), and turn
every difference into a specific class fix. Loop until it matches or ~5 rounds pass
without progress, then report honestly what's still off.
There is exactly one axis: does it look like the original? Do not improve anything — no new type scale, no palette cleanup, no spacing tweaks beyond matching. A change that makes the rewrite diverge from the original is a regression, not a win.
What this can and can't do
- Static. Scripts are stripped in the extract, so JS-driven behaviour freezes at capture state. Scroll/expand everything before capturing.
- Arbitrary values are expected. A bespoke design won't sit on Tailwind's default
scale; faithful classes like
text-[17px]andbg-[#0b5fff]are correct here. Accuracy first; normalising onto tokens is a separate later pass if the user wants. - Approximate where the loop can't see. Rare pseudo-states or JS-injected styles
may not survive. Byte-exact isn't the goal — clean-and-identical-looking is. For
byte-exact, use
page-cloner.
Notes
- Real numbers, not screenshots. Every class should trace to a value in
computed.jsonor a rule inclone/index.html. If you're guessing from a PNG, you'll drift. - Don't skip the loop. The first rewrite is a draft; the comparison is what makes it faithful.
- Be specific in fixes. "Spacing off" isn't a fix. "Section padding is
py-10, computed.json says 48px → usepy-12" is.