AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Css Inspector

skill-aviranrevach-css-inspector-skill-css-inspector-skill · by aviranrevach

Launch a visual CSS inspector panel on any HTML project. Triggers on: "inspect my page", "visual CSS editor", "let me tweak the styles", "open the CSS inspector", "I want to edit styles visually

No reviews yet
0 installs
5 views
0.0% view→install

Install

$ agentstack add skill-aviranrevach-css-inspector-skill-css-inspector-skill

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-aviranrevach-css-inspector-skill-css-inspector-skill)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Css Inspector? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

CSS Inspector Skill

When this skill is triggered, follow these steps exactly.

Step 1 — Clean up any previous session

Search the project for leftover injection markers and remove them:

grep -rl "css-inspector:start" . --include="*.html" 2>/dev/null

For each file found, remove the block between ` and ` (inclusive).

Step 2 — Gitignore setup

Check if .gitignore exists. If so, add .inspector/ if not already present. If not, create it with .inspector/.

Step 3 — Detect project type

Live mode: Check if a dev server is running on common ports:

lsof -i :3000 -i :5173 -i :4200 -i :8080 | grep LISTEN

If found → live mode with that port.

Static mode: If no dev server found and index.html exists in the project → static mode.

Ambiguous: Ask the user: "Is there a dev server running, or should I serve the HTML files directly?"

Step 3.5 — Design system detection (always run)

Detect which design system (if any) the project uses. The result is written to .inspector/settings.json and consumed by the inspector to power the "Component" section of the Design tab.

  1. Read package.json (if present) and check dependencies + devDependencies for these fingerprints:

| System | Signal in deps | |---|---| | shadcn | any @radix-ui/* package and class-variance-authority | | mui | @mui/material or @mui/joy | | chakra | @chakra-ui/react | | mantine | @mantine/core | | antd | antd | | nextui | @nextui-org/react | | tailwind | tailwindcss (devDependencies counts) |

  1. Look for corroborating project files to upgrade confidence:
  • components.json at the project root → strong shadcn signal
  • src/components/ui/*.tsx files that import from class-variance-authority → strong shadcn signal
  • tailwind.config.{js,ts,mjs} → tailwind confirmed
  1. Classname-only fallback (when there's no package.json, e.g. static HTML): grep the rendered HTML for class prefixes:
  • ant-* → antd
  • chakra-* → chakra
  • MuiButton-* or emotion css-* patterns → mui
  • lots of bg-*, text-*, rounded-* utilities → tailwind
  1. Pick a winner by confidence:
  • High: deps signal + at least one corroborating file or matching classnames
  • Medium: deps signal alone
  • Low: only classnames
  • If multiple match (e.g. tailwind + shadcn), prefer the higher layer (shadcn over tailwind).
  1. Build settings.json. If the winner has a preset shipped under ~/.claude/skills/css-inspector/presets/.json, read it and inline its manifest:

``json { "detection": { "detected": [ { "system": "shadcn", "confidence": "high", "signals": ["@radix-ui/react-slot in deps", "components.json at root", "src/components/ui/button.tsx uses cva"] } ], "recommended": "shadcn" }, "preset": "shadcn", "manifest": { /* contents of presets/shadcn.json, inlined */ } } ``

If no system matched: recommended: null, preset: "claude" (Claude design — Claude identifies components on the fly), manifest: { "components": [] }.

Valid preset values: "claude", "shadcn", "mui", "chakra", "mantine", "antd", "nextui", "tailwind", "custom", "none". Picking "none" disables the Component section entirely. Picking "claude" skips the manifest and surfaces an "Ask Claude" action for every pick.

  1. Write the file: .inspector/settings.json. Create .inspector/ if it doesn't exist (it normally will by the time step 4a/4b runs, but this step can come first).

Step 3.6 — Custom design-system manifest (run when no preset matched)

Trigger: Step 3.5 wrote "recommended": null (no known design system detected) and the project has source files that look hand-authored (custom React/JSX/Vue/Svelte/etc.). Skip this step if the recommended preset is one of the shipped ones — that preset's manifest already covers detection.

The goal: build a design-system.json describing the project's components so the inspector's Component section can identify them by classname instead of always falling back to "Ask Claude."

  1. Scan the source files for component definitions. Prioritize, in order:
  • *.jsx / *.tsx files in src/, app/, components/, or the project root
  • *.vue / *.svelte files if present
  • *.html files with non-trivial markup (for static prototypes)

For each file, find:

  • Component declarations (function ComponentName(...), const ComponentName = (...) =>, export function, export default function)
  • The root JSX element's className — note all classname fragments, especially those that look like component identifiers (card, chip, pill, btn, *-card, etc.)
  • Conditional classnames driven by props (className={\base ${variant === 'foo' ? 'class-a' : 'class-b'}\}, clsx(...), template strings) — these are variant signals.
  1. Pick component-worthy entries. Keep only components that:
  • Have at least one distinctive classname on the root element (a class that wouldn't match unrelated components)
  • Are reusable enough to appear more than once, or are visually meaningful even as a one-off (cards, headers, large layout regions are fine even as singletons)

Skip pure layout wrappers and one-line passthroughs with no classnames.

  1. Verify against the live DOM (recommended). A pure source scan often produces incorrect class fragments (e.g. filter-bar vs filterbar, src-chip vs src-pill). If you have a way to render the prototype briefly:
  • Open the static HTML / dev server and let it hydrate
  • Enumerate the actually-rendered classnames on element samples
  • Cross-check the source-derived names against the rendered classes; fix any mismatches before writing the manifest

If you can't render the page, write the manifest from source alone but mark uncertain entries with a "$confidence": "low" field — the user can refine later.

  1. Write .inspector/design-system.json with this shape (matches presets/shadcn.json):

``json { "system": "custom", "label": " (custom)", "description": "Generated by scanning .", "components": [ { "name": "Button", "tag": "button", "anyClass": ["btn"], "source": "src/components/Button.tsx", "props": { "variant": { "values": ["default","primary","secondary","ghost"], "default": "default", "detect": [ { "hasClass": "primary", "value": "primary" }, { "hasClass": "secondary", "value": "secondary" }, { "hasClass": "ghost", "value": "ghost" } ] } } } ] } ``

Match rule reference (use the strictest rule that fits — exact match preferred):

  • "anyClass": ["foo"] — matches if the element has the exact class foo (any of the list)
  • "allClass": ["foo","bar"] — matches only if both classes are present
  • "anyClassContains": ["foo"] — matches if any class contains the substring (looser; use only when class names follow a prefix-value convention like tier-pro)
  • "allClassContains": ["foo"] — same but requires all
  • "tag": "button" — combine with class rules to scope

Detect rule reference (for props..detect):

  • { "hasClass": "primary", "value": "primary" } — exact-class match (preferred — required for live class swapping to work cleanly)
  • { "if": "tier-pro", "value": "pro" } — substring match (loose; fine for unique prefix conventions)
  1. Set preset: "custom" in settings.json and inline the new design-system.json into the manifest field. Add a customLabel field with a short project name (e.g. "Pulse for Product"); the Settings panel will display it on the Import card.
  1. Tell the user what was found. After writing the manifest, surface a one-liner like: "Generated a custom design-system manifest with N components for . Edit .inspector/design-system.json to refine matches; reload the inspector to apply."

Step 4a — Static mode setup

  1. Read index.html and all linked CSS/SCSS files.
  2. Build a cssMap object mapping each selector → property → { file, line }. Example:

``json { ".hero-title": { "font-size": { "file": "styles.css", "line": 24 } } } ``

  1. Create .inspector/ directory in project root.
  2. Copy overlay.js and server.py from the skill folder (~/.claude/skills/css-inspector/) into .inspector/.
  3. Write .inspector/inspector.html:

```html

Inspector

window.__inspectorCssMap = CSSMAPJSONHERE; window._inspectorSettings = SETTINGSJSONHERE;

`` Replace CSSMAPJSONHERE with the JSON-stringified cssMap, and SETTINGSJSON_HERE with the contents of .inspector/settings.json` written in step 3.5.

The overlay is iframe-aware: it detects the iframe, waits for it to finish loading, and binds picker listeners to the iframe's contentDocument. The script tag and iframe can appear in either order.

  1. Kill any process on port 8787: lsof -ti:8787 | xargs kill -9 2>/dev/null || true
  2. Start server: python3 .inspector/server.py 8787 . &
  3. Output: Open http://localhost:8787/.inspector/inspector.html to start inspecting.

Step 4b — Live mode setup

  1. Detect framework web root:
  • Check for vite.config.* → root is project root
  • Check for public/index.html (CRA / Next.js) → root is public/
  • Default: project root
  1. Always re-copy overlay.js from ~/.claude/skills/css-inspector/ into /.inspector/overlay.js — overwrite any existing copy. This ensures every "open the inspector" run gets the latest skill code; otherwise users hit stale-snapshot bugs when the skill is updated but their projects still hold the old overlay.
  2. Always re-copy any presets/ files referenced by .inspector/settings.json so design-system data is fresh too.
  3. Find the HTML entry point (index.html in project root, or public/index.html)
  4. Inject before ``:

```html

window.__inspectorSettings = SETTINGSJSONHERE;

`` Replace SETTINGSJSONHERE with the inline JSON contents of .inspector/settings.json written in step 3.5. If the markers already exist (re-trigger of a project that's been inspected before), leave the injection in place and just refresh the overlay.js and settings.json` content.

  1. Output: Inspector injected. Open your dev server (http://localhost:PORT) to start inspecting. The panel will appear in the top-right corner.

Step 5 — Wait for user to finish

Tell the user:

  • The panel docks to the top-right. Drag the header to move it; the bottom-left handle resizes it; the button minimizes it to the header bar.
  • Click the Select button (top-left of the header), then click any element on the page. The selector pill at the top shows what's currently selected. Right-click a picked element to open the element-tree popup for navigating parents and siblings.
  • Talk to Claude about the selection. After picking, click the selector pill in the header — the element-tree popup opens with a 📋 Copy chat-ready intro link at the top. Clicking it puts a chat-ready intro on your clipboard (Let's talk about this element \.hero-title\ (h1): for leaf elements, Let's talk about this area \.hero\ (section): for containers). Paste it into your next Claude message, then type the ask. Claude now has the selector unambiguously. (The next to the selector pill clears the current selection.)
  • Edit in the Design tab — collapsible sections for Position (X/Y/Z, rotation, flip), Layout (flow, dimensions, padding/margin diagram, clip/border-box), Appearance (opacity, radius, fill, stroke, shadow), and Typography (font family, size, weight, line height, color). All edits preview live. The color picker supports solid and linear-gradient with eyedropper.
  • Use the CSS Raw tab to edit matched stylesheet rules as plain text and click Apply to tracker.
  • The bottom Changes bar shows undo/redo and a "Changes to execute" pill. Click the pill to expand the list of tracked edits, then click Copy Prompt.
  • Paste the copied prompt back into this chat.

When the user pastes a prompt containing either a ` block or a ` block, proceed to Step 6. A pasted prompt may contain one or both blocks.

Step 6 — Apply changes to source

The Copy Prompt can carry three payloads:

  • `` — raw CSS edits the user made in the Design / CSS Raw tabs.
  • `` — design-system intents (variant swaps, component conversions) the user picked from the Component section.
  • `` — sibling reorders (arrow-key nudges or drag-drops) the user made on the live DOM.

Handle whichever blocks are present. Apply order: CSS changes first → component intents → reorders. CSS first so classname swaps operate on the latest source; reorders last because they may move elements out from under earlier edits.

6a · Apply `` (CSS edits)

Parse the ` JSON block. Each entry is { selector, property, from, to, file, line }`.

  • If file is set: Open that file. Find the CSS rule for selector. Update the property value to to. If line is provided, start searching near that line.
  • If file is null: Search the codebase for where selector is defined. Check CSS/SCSS files first. If found in a component file (CSS-in-JS, CSS Module, Vue/Svelte scoped styles), find the declaration and update it. If the style comes from an external/CDN stylesheet, add an override rule to the project's main CSS file.

6b · Apply `` (design-system intents)

Parse the ` JSON block. Each entry has an action field; handle the two actions below. Look up the active manifest from .inspector/settings.json` so you know how the component's variants are signaled (classname vs. prop).

Action: swap-variant

Shape:

{ "action": "swap-variant", "selector": ".my-btn", "component": "Button",
  "prop": "variant", "from": "primary", "to": "destructive",
  "text": "Promote to backlog", "domIndex": 1, "source": "src/page.tsx:34" }

text and domIndex are pinpointing hints emitted by the inspector — they let you choose the right element when the bare selector matches several source locations.

Source disambiguation (before either strategy below): grep the candidate file for the element's signal. Filter the matches in this order, stopping when you have exactly one:

  1. text match (preferred when present): keep candidates whose surrounding JSX contains the text value (or a normalized version — strip leading punctuation/icons, collapse whitespace). For text: "+ Promote to backlog", match against the JSX literal "Promote to backlog".
  2. domIndex fallback (preferred for icon-only / textless elements): if text is absent or didn't narrow to one, pick the Nth match in source-document order where N = domIndex (e.g., the second `` in the file).
  3. Still ambiguous → surface a TODO instead of guessing: "Found 3 candidates for .my-btn; please confirm which one."

Two strategies depending on how the manifest signals the variant — inspect the matching component entry in the manifest:

  • If the manifest's props..detect rules use hasClass or if (classname-driven) — typical for hand-authored design systems like Pulse:
  1. Find the JSX element matching selector in source. Use the source hint (file path + line) to narrow the search.
  2. In the element's className (string, template literal, or clsx call), remove the class fragment that signaled from and add the class fragment for to. Find both fragments in the manifest's detect rules (hasClass: "primary" → the literal class primary; if: "tier-pro" → that exact class).
  3. If the className is built from a prop or variable (e.g.,

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.