$npx -y skills add bluzir/claude-code-design --skill inspectResolve a natural-language element description ("the red button in the hero", "the third card from the top") to a concrete DOM element in the current preview + source-code location. Uses Chrome DevTools MCP take_snapshot UIDs for deterministic targeting. Use when user asks to cha
| 1 | # Inspect |
| 2 | |
| 3 | Replaces Claude Design's `<mentioned-element>` inline-comment protocol with a terminal-native alternative: user describes an element in English, Claude resolves to a specific DOM node + source location for surgical edits. |
| 4 | |
| 5 | ## Prerequisites |
| 6 | |
| 7 | - Chrome DevTools MCP has a page loaded (via `/preview` or `/done`) |
| 8 | - `.claude/last-snapshot.json` exists (produced by `/done`) — or we snapshot fresh |
| 9 | |
| 10 | ## Pipeline |
| 11 | |
| 12 | 1. **Get snapshot:** |
| 13 | - Prefer `Read .claude/last-snapshot.json` if recent (< 5 min, same URL) |
| 14 | - Otherwise `mcp__chrome-devtools__take_snapshot` to get fresh tree |
| 15 | |
| 16 | 2. **Match the description** against snapshot nodes. Use vision + text heuristics: |
| 17 | - Role/tag match ("button" → role=button, tag=button) |
| 18 | - Text content match ("the CTA that says 'Get started'") |
| 19 | - Positional hints ("hero", "top", "third from left", "right sidebar") |
| 20 | - Color hints ("the red button") — if ambiguous, take screenshot and visually match |
| 21 | - Size hints ("the big heading") |
| 22 | - Hierarchy ("inside the first card") |
| 23 | |
| 24 | 3. **Pick the best UID**. If multiple candidates, show the top 3 to the user with a one-line summary each: |
| 25 | ``` |
| 26 | Candidates for "red button in hero": |
| 27 | [uid=3_12] <button> "Get started" — background #d83 |
| 28 | [uid=3_28] <a class="btn"> "Try free" — background #c55 |
| 29 | [uid=3_07] <div role=button> "Sign up" — background #d80 |
| 30 | Which one (or describe differently)? |
| 31 | ``` |
| 32 | |
| 33 | 4. **Resolve to source location.** Once UID is confirmed: |
| 34 | - `mcp__chrome-devtools__evaluate_script` — select by UID and return useful identifiers: |
| 35 | ```js |
| 36 | // (Pass the picked uid as an arg to the evaluate function) |
| 37 | (el) => ({ |
| 38 | tag: el.tagName.toLowerCase(), |
| 39 | id: el.id || null, |
| 40 | classList: Array.from(el.classList), |
| 41 | textContent: el.textContent.trim().slice(0, 80), |
| 42 | dataAttrs: Object.fromEntries( |
| 43 | Array.from(el.attributes) |
| 44 | .filter(a => a.name.startsWith('data-')) |
| 45 | .map(a => [a.name, a.value]) |
| 46 | ), |
| 47 | outerHTML: el.outerHTML.slice(0, 300), |
| 48 | }) |
| 49 | ``` |
| 50 | - With these signals, `Grep` the source HTML (current `artifacts/<name>.html`) for the matching element — preferring `id` > `data-*` > unique class combination > text snippet > outerHTML substring. |
| 51 | - Return: source file path + approximate line number. |
| 52 | |
| 53 | 5. **Report:** |
| 54 | ``` |
| 55 | Element: <button> "Get started" (uid 3_12) |
| 56 | Source: artifacts/landing.html:142-148 |
| 57 | Selector: #cta-primary |
| 58 | ``` |
| 59 | |
| 60 | 6. **Optional next step:** if user requested an edit alongside inspection ("make it bigger") — perform the `Edit` directly with the located line range. Otherwise just report and wait. |
| 61 | |
| 62 | ## Heuristic priorities for "the red button" style references |
| 63 | |
| 64 | When user phrase maps to multiple candidates: |
| 65 | 1. **Explicit labels win** — if `<button aria-label="Subscribe">` and user says "the subscribe button", pick that regardless of visual cues |
| 66 | 2. **Visible-first** — prefer elements currently in viewport over below-fold |
| 67 | 3. **Unique before common** — a unique hero button beats the third of eight grid buttons |
| 68 | 4. **Large before small** — for "the big title" prefer larger font-size |
| 69 | 5. **Top-first for ambiguous position** — "the button" → closest to top-of-page in reading order |
| 70 | |
| 71 | ## When to fall back to asking |
| 72 | |
| 73 | If >3 candidates and vision can't disambiguate — ask the user: "you mean X, Y, or Z?" |
| 74 | |
| 75 | ## Limits |
| 76 | |
| 77 | - Only resolves elements that rendered successfully (not in-error components) |
| 78 | - React components with generated class names (CSS modules): selector might not round-trip — use outerHTML substring for source grep |
| 79 | - Elements inside shadow DOM are visible to `take_snapshot` but Grep on source HTML won't find them — warn the user if this path fails |