This is the end-to-end methodology. Read it once so you understand what the scripts are doing, then drive the real work through the four slash-command skills (/start-analysis, /analyze-page, /map-to-eds, /capture-eds).
The kit is a three-phase pipeline that produces four deliverables:
Legacy URL Phase 1: Site inventory Phase 2: Mapping rules Phase 3: EDS authoring
───────── ─────────────────────── ────────────────────── ──────────────────────
https://... → analyze pages → map detected → EDS → author sample blocks
aggregate output fill block + fields capture screenshots
↓ ↓ ↓
component-inventory.html component-mapping.html eds-authoring-guide.md
site-overview.html (with mapping rules) (detailed sections in
component-mapping.html)
/map-to-eds.The output folders mirror Phase 1 and Phase 2+3:
1-site-inventory/ — Phase 1 output (inventory + overview)2-eds-mapping/ — Phase 2 input/output (mapping.json + mapping.html) and Phase 3 output (eds-screenshots/, eds-authoring-guide.md)Before diving in, it’s worth being precise about terminology because this kit does two separate mappings:
hero-section, card, accordion, icon-grid, …). This is code — it lives in scripts/analyze_page.mjs as WIDGET_MAP + inline heuristics + ANATOMY_DEFS. You edit it when detection is wrong or when you’re adapting to a new CMS.hero, cards, accordion, contact-form, …). This is data — it lives in 2-eds-mapping/component-mapping.json and is filled via /map-to-eds. You edit it when deciding how the legacy component should become an EDS block.Between the two sits 1-site-inventory/taxonomy.json — the vocabulary of generic component types the project recognizes, with their classifications (composite/standalone), variants, and atoms.
taxonomy.json is not auto-generated. It’s hand-written at project start (use templates/taxonomy.template.json as the starter) and extended incrementally as the per-page analysis loop discovers new types:
/analyze-page <slug> → see a component flagged as unknown or missed entirely1-site-inventory/taxonomy.json and add the new type: classification (composite / standalone / structural), description, variants (with atoms), any styling notesscripts/analyze_page.mjs (WIDGET_MAP for simple widget→type renames, or the heuristic block for composites)/analyze-page <slug> and check if it picks up the new typeWhy hand-authored: the classifications + variants are design decisions, not things a script can infer. Whether a banner is a variant of hero-section or its own type, whether card [redirect] and card [default] should share a taxonomy entry, etc. — those are conversations between the migration consultant and the design/frontend team. The kit keeps them in a data file so the build scripts can read them without hardcoding.
The starter templates/taxonomy.template.json has 5 generic types (heading, image, button, text-block, hero-section) — enough to bootstrap any project. Everything else gets added as you analyze.
npx playwright install chromiumskills/ installed (copy them into ~/.claude/skills/ or the project’s .claude/skills/)Run /start-analysis. It asks you:
| Question | What it becomes |
|---|---|
| Project folder name | New folder alongside the kit |
| Site URL | domain + first pages[] entry |
| Source CMS | sourceCMS + preset detection.baseSelectors |
| Auth provider | authentication.* skeleton (you fill credentials) |
| Cookie consent | cookieConsent.* |
| Initial page list | pages[] array |
After it finishes you’ll have:
<project>/
├── GOAL.md (filled with your answers)
├── 1-site-inventory/
│ ├── site-config.json (filled)
│ ├── taxonomy.json (starter)
│ └── pages/ (empty)
└── 2-eds-mapping/
└── component-mapping.json (empty mappings array + default matchStyles)
If the site has auth: open site-config.json and fill in authentication.credentials.username/password before Step 2. Don’t commit this file to a public repo.
For each slug in pages[]:
/analyze-page <slug>
or directly:
node scripts/analyze_page.mjs <url> --slug <slug> --template <template> [--auth]
The script:
cookieConsent.acceptSelector)--auth is passed (DocCheck-style form submission using authentication.* selectors)exclusions config01_clean.png (main content only)WIDGET_MAP and running heuristics per component type02_annotated.png (components with colored overlays)components.json with every component’s { type, variant, rect, widgetType, elementId }review.html — an interactive per-page review with both screenshots side by sideThis is where manual work happens. Open review.html in a browser (or let the /analyze-page skill auto-invoke review-spec for you) and check:
02_annotated.png and make sure they cover every visible block on the page.image or a card group tagged as icon-grid means the heuristics misfired.height: 2400px that swallows half the page means a container was wrongly classified as a leaf.The review-spec skill (if installed) automates most of these checks. Otherwise eyeball it.
Detection bugs fall into three buckets — fix in order of least-invasive:
1. Selector misses → edit site-config.json:
detection.baseSelectors: the CMS base classes (section, widget, column, container).technical.componentSelectors: free-form per-widget selectors the analyzer can use as hints.exclusions: add a selector to strip a pesky fixed header or overlay./analyze-page <slug> — this covers 70% of issues.2. Taxonomy gaps → edit taxonomy.json:
testimonial, anchor-nav, download-block).hero-section.with-video, card.clickable)./analyze-page <slug> — build scripts will pick up the new entries automatically.3. Heuristic failures → edit scripts/analyze_page.mjs:
analyze_page.mjs 1,600+ lines.// ─── DETECTION: <type> ─── section headers. Each component type usually has a small function or inline block you can tweak.WIDGET_MAP constant near the top is a direct mapping from CMS widget names (e.g. data-widget_type="heading.default") to the generic taxonomy type (heading).ANATOMY_DEFS constant further down defines how composites are split into sub-components.WIDGET_MAP.After each fix, re-run the analyzer and re-review. Iterate until the review is clean.
Repeat for every slug in pages[]. With 10-15 pages this is usually 1-3 hours total, mostly spent on the first 2-3 pages while you tune the selectors. Once the detection is tight for one page, the rest come fast.
Once all pages are clean:
node scripts/build_inventory.mjs # → 1-site-inventory/component-inventory.html
node scripts/build_site_overview.mjs # → 1-site-inventory/site-overview.html
These are pure rollups — no re-rendering, no Playwright. They take a second to run. Open the HTMLs in a browser to sanity check:
If something looks wrong, check:
components.json → re-run /analyze-page <slug>taxonomy.jsontemplateColors / componentColors in site-config.json/map-to-eds
The skill:
(type, variant) pair from 1-site-inventory/pages/*/components.jsoncomponent-mapping.json, asks you three questions: which EDS block, what match type, and any notescomponent-mapping.json incrementally (so an interrupted session doesn’t lose work)build_mapping.mjs to regenerate component-mapping.html| Type | When to use | Example |
|---|---|---|
direct |
EDS block fits cleanly, no adaptation needed | heading → Default content |
split |
One legacy component needs multiple EDS blocks | hero-section.with-anchors → hero + link-list |
indirect |
Block exists but needs CSS/config tweaks, or is a reuse with a twist | banner → hero (reuse) with overlay CSS |
gap |
No EDS block exists; needs custom dev or content workaround | infographic → document as SVG for launch, custom block Phase 2 |
If you’d rather skip the skill and edit the JSON directly, here’s the shape:
{
"mappings": [
{ "site": "hero-section", "variant": "default", "eds": "hero", "match": "direct", "notes": "..." }
],
"matchStyles": { "direct": {...}, "split": {...}, "indirect": {...}, "gap": {...} }
}
Variant is null for components that don’t have variants. build_mapping.mjs looks up each detected component by exact (site, variant) first, falling back to (site).
component-mapping.json does not contain a per-page section — that view is auto-derived from each page’s detected components at render time.
This phase is optional but strongly recommended: without it, the mapping is still abstract (“hero-section maps to hero”), and you don’t have a concrete deliverable for content editors or a visual comparison showing what the migration actually looks like.
Open the target EDS repo. Create or reuse a sample page (e.g. sample-<project>.html or a Google Doc published to the sample branch). For each mapped component, author the equivalent EDS block once with realistic content — real images, real headings, real copy. This is the creative work: iterating on sizes, deciding what maps to what field, getting the composition right. Have a conversation with the client and/or the frontend dev as needed.
Tip: do hero first, then cards, then accordion — the ones with the clearest field shapes. Save the tricky ones (form with DocCheck auth, infographics, tabs) for last.
For each block you’ve authored, edit 2-eds-mapping/component-mapping.json and add an edsCapture field to the matching mapping entry:
{
"site": "hero-section",
"variant": "default",
"eds": "hero",
"match": "direct",
"notes": "...",
"edsCapture": {
"url": "/sample-desmoid",
"selector": "main .hero:first-of-type",
"filename": "hero-default.png"
}
}
url is relative to edsSample.baseUrl (default http://localhost:3000) or a full URL.selector is a CSS selector that uniquely picks the authored block.filename is where to save it under 2-eds-mapping/eds-screenshots/.Also add edsAuthoring to the entry to describe the field structure — this drives the editor-facing guide and the field table in the detailed comparison section:
"edsAuthoring": {
"blockName": "hero",
"fields": [
{ "name": "Background image", "type": "image", "example": "/assets/hero.jpg", "required": true, "notes": "Min 1920×1080" },
{ "name": "Heading", "type": "heading", "example": "# Welcome", "required": true },
{ "name": "Subtitle", "type": "text", "example": "A short tagline" },
{ "name": "CTA", "type": "link", "example": "[Learn more](/about)" }
],
"notes": "Author as the first block on the page."
}
The /map-to-eds skill can collect both of these interactively if you run it after authoring.
/capture-edsStarts your local EDS dev server if it’s not already running, then runs scripts/capture_eds_blocks.mjs which:
edsCapture field2-eds-mapping/eds-screenshots/Failures are logged inline — a selector that matches 0 elements (the block isn’t authored yet) skips rather than failing the whole run. Use --only <site>[:<variant>] to capture just one block, and --headed to watch it in a visible browser when debugging a selector.
node scripts/build_mapping.mjs # → 2-eds-mapping/component-mapping.html (now with detailed sections)
node scripts/build_authoring_guide.mjs # → 2-eds-mapping/eds-authoring-guide.md (new deliverable)
component-mapping.html now includes a new “Detailed Component Comparisons” section at the bottom: one full-width block per mapping-with-capture, showing the legacy anatomy screenshot on the left, the EDS screenshot on the right, the authoring field table, and migration notes.eds-authoring-guide.md is a markdown deliverable for content editors. It has one section per authored block with: field list, Google Docs table structure example, and per-field notes.Mappings without an edsCapture are listed in the guide as “pending authoring structures” — that’s your todo list.
Authoring is rarely one-shot. As the client reviews the sample page, they’ll ask for tweaks: “make the hero image smaller”, “add a subtitle”, “change the card border color”. Each time you re-author, re-run /capture-eds to refresh the screenshots, then re-run build_mapping.mjs + build_authoring_guide.mjs.
If you’re only producing a pre-sales gap analysis (not a real migration), you can stop after Phase 2. The mapping.html summary is enough to answer “how much EDS block coverage do we have?” and “which components need custom work?”. Phase 3 becomes relevant only when authoring + delivery start.
The kit was originally built for WordPress/Elementor pharma sites. For other CMSes:
site-config.json under detection.baseSelectors. The /start-analysis skill has a cheat sheet for a few common CMSes.scripts/analyze_page.mjs directly:
WIDGET_MAP near the top — add/replace mappings from your CMS’s widget attributes to the taxonomy typesANATOMY_DEFS further down — adjust sub-component selectors per component typeThink of analyze_page.mjs as a CMS adapter. For a new CMS, either:
scripts/analyze_page.gutenberg.mjs) and run different adapters per project, orsite-config.json flagNeither path is clean, but that’s the honest tradeoff: the heuristics took manual tuning and the kit doesn’t try to hide that.
1-site-inventory/site-config.json in .gitignore if auth is configured.cookieConsent.acceptSelector.unknown. Add to WIDGET_MAP.anatomy/<type>/anatomy_annotated.png files exist for that page. Re-run the analyzer.component-mapping.json.| File | Role |
|---|---|
scripts/analyze_page.mjs |
Playwright-driven page analyzer. CMS adapter — heuristics + WIDGET_MAP + ANATOMY_DEFS live here. |
scripts/capture_eds_blocks.mjs |
Playwright-driven EDS sample page screenshotter. Reads edsCapture entries in the mapping JSON. |
scripts/build_inventory.mjs |
Aggregates pages/*/components.json + taxonomy.json → component-inventory.html |
scripts/build_site_overview.mjs |
Aggregates same data → site-overview.html (tree + matrix + distribution) |
scripts/build_mapping.mjs |
Reads component-mapping.json + pages data → component-mapping.html (summary + detailed sections when captures exist) |
scripts/build_authoring_guide.mjs |
Reads edsAuthoring fields → eds-authoring-guide.md (deliverable for content editors) |
scripts/lib/render.mjs |
renderTemplate() + esc() helpers |
scripts/lib/read-pages.mjs |
readAllPages() + readTaxonomy() + readSiteConfig() + readMappingData() |
templates/*.html |
HTML templates with `` placeholders (CSS + shell live here; dynamic content comes from scripts) |
templates/authoring-guide-template.md |
Markdown shell for the authoring guide |
templates/*.template.json |
Blank config shapes for new projects |
templates/site-config.schema.md |
Field-by-field docs for site-config.json |
templates/GOAL.template.md |
Project charter starter |
skills/*/SKILL.md |
The four Claude Code skills: /start-analysis, /analyze-page, /map-to-eds, /capture-eds |