Skip to main content

reskin

Rebuild an existing site's pages with byte-faithful content on a separately-defined donor design system — another live site, or local static HTML prototypes (Figma donors are contract-defined, not yet implemented). Content fidelity is gated byte-level (text, ordered images, SEO metadata); design application is flexible (content re-laid-out onto donor modules). Use when the user says "reskin my site with this design", "apply this design system to my content", "restyle my site to look like <other site>", "new design, same content", "rebrand my site using these prototypes", or names a content site plus a design donor. NOT for redesigning from intent (that's the stardust core extract/direct/prototype chain) and NOT for keeping the current design while migrating (that's the replica flow).

Source facts

Repository
adobe/skills
Last source activity
October 9, 2026 at 13:05
Detected SKILL.md language
English
Stars
304
Forks
94

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
10 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
reskin
description
Rebuild an existing site's pages with byte-faithful content on a separately-defined donor design system — another live site, or local static HTML prototypes (Figma donors are contract-defined, not yet implemented). Content fidelity is gated byte-level (text, ordered images, SEO metadata); design application is flexible (content re-laid-out onto donor modules). Use when the user says "reskin my site with this design", "apply this design system to my content", "restyle my site to look like <other site>", "new design, same content", "rebrand my site using these prototypes", or names a content site plus a design donor. NOT for redesigning from intent (that's the stardust core extract/direct/prototype chain) and NOT for keeping the current design while migrating (that's the replica flow).
license
Apache-2.0
compatibility
Requires Node 22+, Playwright with Chromium resolvable from the project, playwright-cli on PATH, and the impeccable skill (github.com/pbakaus/impeccable) installed alongside stardust.
# stardust:reskin — same content, donor design The user has a site (the **content source**) and a design that already exists somewhere else (the **donor**: another live site, or a directory of static HTML prototypes; Figma is future scope). Reskin rebuilds the content site's pages so that every visible byte of content survives — text, ordered images, CTAs, SEO metadata — while the surface comes entirely from the donor's tokens and module vocabulary. The two halves have different contracts: - **Content is non-negotiable.** The gate is byte equality of whitespace-normalized visible text, the ordered visible-image set, and full metadata carry-over. Not "close" — equal, after an explicitly declared, executable normalization ledger. - **Design is flexible.** Content is re-laid-out onto donor modules; a carousel may become a static card grid, a sidebar may become a band. Structure (element counts, tag sequences) is informational, never gating — a reskin re-structures markup by design. The decisive rule, validated in the UC2-E1 experiment (a healthcare site × a fintech donor: 2281/2281 text bytes, 7/7 images, 47/47 slots, 13/13 metadata, 17/17 donor-token probe): **the page is generated programmatically from the captured content model — content strings are never retyped.** Byte fidelity then holds by construction and the content gate becomes a regression check instead of a debugging tool. ## Inputs - `<content-url>` — required. The site whose content is preserved. - Donor, exactly one of: - `--donor <url>` — a live site whose design system is adopted. - `--donor-dir <path>` — a directory of local static HTML prototypes (claude-design / Mobirise / Relume / Lovable / v0 / hand-coded). Served on localhost and captured through the same path — recipe in `reference/donor-sources.md` § Local prototypes. - `--donor-figma <url>` — **not yet implemented.** The contract is defined (`reference/donor-sources.md` § Figma) but the adapter is future scope. Tell the user exactly this: *"Figma donors are not implemented yet. Export the frames as static HTML prototypes (or point me at a live staging URL of the design) and re-run with `--donor-dir` / `--donor`. The Figma adapter — variables→palette, text styles→type, frame screenshots→vision references, provenance class `figma-mcp` — is specced in `skills/reskin/reference/donor-sources.md` and will land in a later release."* Do not improvise a partial Figma capture. - `--pages <slug,slug,...>` — optional. Restrict the content capture to specific pages. Default: the archetype set (one page per page family; a spec's `archetypes.json` names them; scale to siblings happens in Phase 6 via `migrate`). - `--scope <selectors>` — optional. Pre-declare the content-root scope for a single-page run (comma-separated, `!` suffix keeps a scope whole; see `reference/content-model.md` § Scope declaration). Without it, run the scope-discovery procedure per page. ## Setup 1. Run the master skill's setup (`../stardust/SKILL.md` § Setup): impeccable dep check, context loader, state read. **Flow.** Stamp `state.json.flow: "reskin"` if unset (`../stardust/reference/state-machine.md` § Flow keys); if another flow is set, print it and the switch command (`$stardust reskin --switch-flow`) instead of running. 2. **Playwright import-resolvability probe** — same contract as `../extract/SKILL.md` § Setup: `node -e "import('playwright').then(()=>process.exit(0))"` from the project root; on failure `npm i -D playwright --no-save --legacy-peer-deps`. Re-run the probe at the start of every phase that renders — a `--no-save` install is pruned by any later real `npm i`. 3. **Copy the scripts into the project.** ESM resolves `import('playwright')` from the *script's* directory and the plugin tree ships no `node_modules`. Copy `skills/reskin/scripts/*` (all five files — `capture-content.mjs` and `dom-equality.mjs` import `source-normalize.mjs` as a sibling) byte-identical to `stardust/scripts/reskin/`, **and** `skills/diff/scripts/ live-session.mjs` to `stardust/scripts/diff/` — every reskin gate script (capture-content, dom-equality, donor-probe, **and** slot-coverage) imports it unconditionally at startup, regardless of target type: without the copy each one exits 2 immediately, even for `--help` or a local-file `--rendered` target. It supplies ALL live-target hardening (real-Chrome UA + standard headers, challenge detection, headed-stealth escalation), resolved from `../diff/` next to `../reskin/`, so keep the two dirs siblings. Run the copies. 4. **Origin collision** — if `stardust/state.json` records a different `site.originUrl`, stop and ask before mixing sites, per `../extract/SKILL.md` § Setup. ## Procedure ### Phase 1 — INGEST DONOR The donor's design system is captured **separately** from the content site, into `stardust/canon-source/`. Full recipes per donor type in `reference/donor-sources.md`; summary: - **Live URL** (`--donor <url>`): invoke `$stardust extract <content-url> --design-source <donor-url>` — the existing skill, unchanged. It lands in `stardust/canon-source/`: the donor's `pages/`, `assets/` (screenshots included), `_brand-extraction.json`, `_crawl-log.json`, and a descriptive `DESIGN.md` + `DESIGN.json`, and stamps `state.json.designSource = { url, capturedAt, path }` — see `../extract/SKILL.md` § Cross-site brand sources. - **Local prototype dir** (`--donor-dir <path>`): serve the directory on localhost (`python3 -m http.server <port> --directory <path>`) and run the **same** `--design-source` capture path against the localhost origin. Record the real provenance (localhost serve of `<path>`) in `canon-source/_crawl-log.json`. Recipe details — page listing, index-less directories, port hygiene — in `reference/donor-sources.md` § Local prototypes. - **Figma** (`--donor-figma`): FUTURE. Surface the exact message from § Inputs and stop. Then author two reskin-owned donor artifacts (contracts in `reference/donor-sources.md`): - `stardust/reskin/donor-tokens.json` — the **curated, probe-able token sheet**: palette roles, type ramp, layout metrics, button specs, radii, shadows, motifs — every value a computed-style string the Phase 5 probe can assert verbatim. Curated from `canon-source/DESIGN.json` + `_brand-extraction.json` + the raw computed styles; cites the donor page each value came from. On a **bounded donor capture** (a single donor page, no full `--design-source` run) there is no `DESIGN.json`, `_brand-extraction.json`, or `designSource` stamp to curate from — the token sheet is authored entirely from raw computed-style sampling of the donor page, a first-class parallel path (`reference/donor-sources.md` § Two first-class token-sourcing paths). - `stardust/reskin/donor-modules.md` — the **enumerated module vocabulary** (M1..Mn): one row per donor module with where-seen screenshot evidence and an anatomy description. This is the closed set the Phase 3 mapping brief maps onto. **The pin-one-reference-page rule (hard).** Real donors run multiple design systems concurrently — the experiment's donor served radius-4px / 1266px on its homepage and pill-radius / 1080px on older product pages. Consolidating across them produces a chimera no live page ever shipped, and the token probe then asserts against nothing. When donor pages disagree on a token, **pin ONE donor reference page per module family**, record it in `donor-tokens.json` (`curatedFrom` + a note naming the reference page), and demote the other pages to corroboration. ### Phase 2 — CONTENT-MODEL CAPTURE The new capability: a **byte-oriented** capture of each content page — distinct from extract's design-oriented capture. Run the ported capture script per page: ```bash node stardust/scripts/reskin/capture-content.mjs \ --url <page-url> \ --scope '<sel1,sel2!,...>' \ --normalize stardust/reskin/normalize/<slug>.mjs \ --out stardust/reskin/content-model/<slug>/ ``` It writes `stardust/reskin/content-model/<slug>/content-model.json` (full contract in `reference/content-model.md`): per section-slot — headings with levels, eyebrows and other leftovers, body paragraphs, list items, CTAs with **absolute** hrefs, ordered **visible** images (`currentSrc` + alt), plus the **ordered stream** (`ordered`) — the same content as kind-tagged nodes in document order with nesting and separator flags, the render surface Phase 4 consumes; page-level — full SEO metadata (title, description, canonical, OG, Twitter, JSON-LD, lang, favicon), the whitespace-normalized visible text of the scope (the content-gate reference string), and a full-page screenshot. Two declarations are mandatory per page, because they are the experiment's top two failure modes: 1. **CONTENT-ROOT SCOPE declaration.** Naive scoping silently dropped 30% of the experiment page's content — the hero and a banner carousel lived inside `<header>`, outside the obvious `#content` root, and byte equality would have "passed" against the incomplete reference. Never trust `main` or `#content` blind. Run the **scope-discovery procedure** (`reference/content-model.md` § Scope discovery): compare the captured scope text against the whole-body text and the page screenshot, verify the h1 is inside the scope, widen with comma-separated multi-scope selectors until everything visible in the screenshot that isn't declared chrome is in the model. Chrome exclusions (nav, footer) are declared deltas (`D1`-style), not silent omissions. The capture script prints a coverage line (`bodyTextLen / scopeTextLen / h1InScope`) to make the check mechanical. 2. **EXECUTABLE NORMALIZATION LEDGER.** Cookie-consent chrome removal, carousel de-duplication (hidden slides are absent from `innerText`; clone slides duplicate it — rotating carousels break byte determinism), and any page-specific cleanup live in a per-page ledger module `stardust/reskin/normalize/<slug>.mjs` that extends the shared default (`scripts/source-normalize.mjs`). The **same ledger file is passed verbatim to the capture and to every gate** (`--normalize`), so the gate measures exactly the normalization the capture declared. The ledger is code, not prose. Format in `reference/content-model.md` § Normalization ledger. ### Phase 3 — MAPPING BRIEF Author `stardust/reskin/mapping.md` — the cross-origin mapping brief. Full contract and entry schema in `reference/mapping-brief.md`. Per **every** content slot in the content model: - assigned donor module id (from `donor-modules.md`'s closed vocabulary) + a one-line rationale grounded in slot anatomy vs module anatomy; - status ∈ `{mapped, new-module, chrome, carried-invisible}` — the last for sr-only/visually-hidden content inside the byte scope (carried verbatim into an equivalent hidden element, no donor module; `reference/mapping-brief.md` § Status semantics). Gates before any rendering: - **≥ 80% of content slots `mapped`** onto named donor modules. Below that, the donor vocabulary doesn't cover this content — stop and surface (see § Stop conditions). - **Every `new-module` entry is explicitly composed from donor tokens** (name the tokens it borrows: input spec + primary button spec, etc.) and listed in the brief's stats block. New modules are never silently improvised mid-render. - **Chrome swaps documented** — nav/footer replaced by donor chrome carrying the source's links is a declared delta, excluded from the content-gate scope. - **Casing / text-transform policy declared.** The donor may render eyebrows uppercase (or the source may — Chrome's `innerText` reflects `text-transform`, so captured text is *rendered-case*). The underlying text stays byte-faithful; casing is applied via CSS `text-transform` only, never by editing the string. Policy details in `reference/mapping-brief.md` § Casing policy. Composite source sections (one wrapper div holding two logical regions) are split into atomic slots in the brief — section ≠ slot. ### Phase 4 — PROGRAMMATIC RENDER The decisive validated rule: **the page is GENERATED from `content-model.json` — never retyped by hand.** Write a renderer script per archetype (`stardust/reskin/renderers/<archetype>.mjs`, modeled on the experiment's `render-reskin.mjs`) that: - reads the page's `content-model.json` and interpolates **every** visible string, href, and image URL from the model (HTML-escaped) — if a string appears in the output HTML but not in the model, the renderer is wrong; - takes each slot's structure from the **ordered stream** (`sections[].ordered`, `reference/content-model.md` § The ordered stream): kind-tagged nodes in document order, nesting preserved (a CTA wrapping its heading and vice versa), `sep` flags marking zero-separator inline joins. The stream is **innerText-consistent by construction** (its text nodes are sliced from the parent's rendered `innerText` — the byte-gate basis), so emitting it verbatim is safe. Emit nodes in stream order; emit `sep: ""` neighbours with no whitespace between them (inline); never reorder, and never reconstruct **order or separators** from `visibleText` — the first field run did exactly that (per-type arrays matched greedily against `visibleText` as an oracle) and burned three debug rounds on duplicate identical strings, both directions of CTA/container nesting, and zero-separator inline `li` runs, all of which the stream now captures structurally; - renders `formControl` nodes as **equivalent controls**, not text: a `<select>` carrying the captured option texts **verbatim, in order**; inputs/textareas carrying value/placeholder — restyled with donor tokens (the new-module composition rules apply), never flattened to prose and never dropped. A select's option text is part of the source's `innerText`, so dropping the control fails the byte gate with nothing structured to render from (`reference/content-model.md` § Slot taxonomy, formControls); - carries the metadata block verbatim into `<head>` (title, description, canonical, OG, Twitter, JSON-LD — including source garbage like broken JSON-LD URLs: fidelity over repair; **flag** such items for the human in the run report, never silently fix or silently keep); - takes its surface exclusively from `donor-tokens.json` (emitted as CSS custom properties) + the donor module patterns assigned in `mapping.md`. Use the rendered-page conventions the Phase 5 probe asserts against: content in `<main>`, `.container` for the measure, `.btn` for the donor primary button (`reference/gates.md` § Rendered-page conventions); - writes `stardust/reskin/pages/<slug>.html`, self-contained. Renderers may parse a single node's text apart (split a list-item row into kicker/date/title) but must **fail loudly** (throw) when a parse doesn't reproduce the node's text — a silent partial parse is a silent content drop. A slot whose `orderedVerified` is `false` is inspected before rendering, never trusted blind; when inspection shows stream text genuinely absent from the slot's `visibleText`, the **sanctioned fallback** is to drop that text before rendering and record the drop in the model's provenance — filtering ghosts against `visibleText` is the documented resolution, distinct from the forbidden order-reconstruction move (`reference/content-model.md` § When `orderedVerified` is false). ### Phase 5 — GATES Three gate families per page; commands, pass bars, tolerances, and failure modes in `reference/gates.md`. Serve or `file://`-address the rendered page and run: **(a) CONTENT GATE** — all three must pass: ```bash node stardust/scripts/reskin/dom-equality.mjs \ --source <page-url> --source-scope '<declared scope>' \ --normalize stardust/reskin/normalize/<slug>.mjs \ --rendered stardust/reskin/pages/<slug>.html --rendered-scope main \ --report stardust/reskin/reports/<slug>-content-gate.md node stardust/scripts/reskin/slot-coverage.mjs \ --model stardust/reskin/content-model/<slug>/content-model.json \ --rendered stardust/reskin/pages/<slug>.html \ --report stardust/reskin/reports/<slug>-slot-coverage.md ``` `dom-equality.mjs` (vendored + adapted from github.com/aemcoder/skills, Apache-2.0) gates on whitespace-normalized visible-text **byte equality** and the **ordered, URL-normalized visible-image set**; element count and tag sequence are reported but informational. `slot-coverage.mjs` additionally proves every model slot present (slot text substring, every CTA as a (text, absolute-href) pair, every image) and asserts metadata carry-over field by field. **(b) DESIGN-ADOPTION GATE:** ```bash node stardust/scripts/reskin/donor-probe.mjs \ --tokens stardust/reskin/donor-tokens.json \ --rendered stardust/reskin/pages/<slug>.html \ --report stardust/reskin/reports/<slug>-donor-probe.md ``` Computed-style assertions of donor token values on the rendered page — bg/fg, font-family token string, display weight, button spec,
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub