Inspiration
Every front-end developer knows this ritual: you see a beautifully built component on a live site, open DevTools, and start the archaeology — digging through nested divs, copying CSS rules one by one, chasing down image URLs. DevTools shows you one element at a time, but it never shows the page the way a designer sees it: a hero, a nav, a card grid, a footer. We wanted a tool that reads any live page as a tree of components, and lets you pick up any one of them — fully packaged — with a single click.
What it does
Click the toolbar icon and the extension scans the page and builds a structure tree in a sidebar: sections and components, each with a bilingual type label (Hero, Nav, Card, …), media badges, and interactivity badges.
- Hover anything on the page → a blue outline + label tells you what it is (
tag.class · size · type). - Alt+click locks it (red outline) — normal clicks still pass through to the page, so the site keeps working while you inspect it.
- ↑ / ↓ arrow keys walk up and down the DOM to adjust granularity; clicking a tree node scrolls to it and locks it.
- The overlay repositions every frame, so it stays glued to its target even on smooth-scroll (Lenis) sites.
Two one-click exports:
- Component export — a tiny self-contained zip (~24 KB for a typical card):
component.jsonwith a stable CSS selector, classification, matched CSS classes and asset URLs;component.html, an isolated render you can open directly; plus DOM snapshots of interaction states (default / hover / scrolled / clicked). Structured for both humans and AI coding agents to consume. - Mirror export — a browser-side snapshot of the whole page as you currently see it: post-hydration DOM, every loaded asset (cross-origin ones fetched through the extension's background worker), framework payloads like
__NEXT_DATA__/__NUXT__, with all links rewritten to local paths. Serve the folder with any static server and the page runs offline. Because it runs inside your logged-in browser, it captures authenticated and purely runtime pages that no crawler can reach.
How we built it
Vanilla JavaScript, zero dependencies — the entire tool is a self-contained IIFE injected as a Manifest V3 content script (isolated world, so strict page CSP can't break it). Cross-origin asset fetches go through the background service worker.
The real problem isn't drawing outlines — it's deciding where they go:
- Sections come from landmarks (
header/nav/main/footer/ ARIA roles) plus heading hierarchy. - Components come from repeated-sibling detection: siblings sharing the same tag+class signature (≥2) are cards or list items, and each repeat becomes one selectable unit — a card's image, title, and button count as one box, not three.
- Type classification is a heuristic rule set distilled from a corpus of 7 real production sites, with a built-in bilingual (EN/中文) dictionary. No LLM in the loop — labeling is instant, free, and deterministic.
Determinism was a hard requirement: one synchronous full-DOM scan, no scrolling, no timers, sizes measured with offsetWidth/Height so they don't change with scroll position. Scanning the same page at top, middle, and bottom scroll produces item-for-item identical trees.
Even the zip writer is handwritten (store-only ZIP format) to keep the dependency count at zero.
Challenges we ran into
- Granularity. Too fine and every
<span>gets a box; too coarse and the whole page is one box. Repeated-sibling grouping plus minimum-area thresholds got us to "one card = one unit". - Our first UI was wrong. v1 drew outlines on everything at once — on scroll-heavy marketing sites it was visual chaos. We threw it away and rebuilt around a "tree + spotlight" model: the full inventory lives in the sidebar; the page only highlights what you hover or lock.
- Smooth-scroll sites. Libraries like Lenis move content with transforms, so absolutely-positioned overlays drift. Per-frame repositioning fixed it.
- CSP and CORS. Our bookmarklet prototype died on strict-CSP sites → moved to an extension content script in an isolated world. Cross-origin assets are unfetchable from the page → routed through the background worker's host permissions.
- Export design. Early exports duplicated everything and ballooned. The final component zip references the page snapshot instead of re-bundling it, which is how it stays ~24 KB.
Accomplishments that we're proud of
- Reproducible scans: identical component trees regardless of scroll position, run after run.
- Snapshotted a real production site into a 61 MB, 375-file offline mirror that serves and browses locally with zero fixups.
- The whole thing is plain JavaScript with no dependencies — no build step, no framework, loads instantly.
What we learned
- In "outline every component", drawing is 5% of the work; deciding what counts as a component is the other 95%.
- A small heuristic rule set distilled from real sites beats an LLM call for this job: instant, free, and deterministic.
- The browser is a privileged vantage point: post-hydration DOM and logged-in sessions are things no server-side crawler will ever see.
What's next
- Shadow DOM piercing (deep
elementFromPoint) and iframe support. - Auto-scroll sweep to inventory lazily-mounted components that only appear after interaction.
- Richer dynamics annotation — detecting GSAP / Swiper / Lottie usage per component, not just page-wide.
- A Firefox port.
Built With
- browser-extension
- chrome
- html5
- javascript
- manifest-v3
- web-apis
Log in or sign up for Devpost to join the conversation.