ExklusivBeta
Agent Vision <mv-agent-vision>
Sieh deine Seite so, wie ein KI-Agent (oder ein Screenreader) sie sieht: umschließt einen beliebigen Bereich und teilt ihn mit einer verschiebbaren Scanlinie. Links ist die menschliche Ansicht, rechts die "agent view", in der jeder Knoten des Accessibility-Baums zu einem pixelgenauen Wireframe-Kasten wird, beschriftet wie eine Baumzeile (button "Add to cart", heading 2 "Shipping", text field "Promo code"), während alles andere in einem ruhigen Raster verblasst. Die Mängel, die eine Website für Agenten unlesbar machen (Icon-Buttons ohne Namen, klickbare divs, Bilder ohne alt, Felder nur mit Placeholder, übersprungene Überschriftenebenen, nicht unterscheidbare "Learn more"-Links, stumme Farbpunkte), werden markiert, mit bis zu 100 Punkten bewertet und mit ihrer Lösung aufgelistet; ein Klick auf ein Problem schiebt es in die Agentenansicht und lässt es pulsieren. Scannt bei Mutationen, Größenänderung und Scrollen automatisch neu.
| Kategorie | Utilities |
|---|---|
| Typ | Web Component (<mv-agent-vision>) |
| Status | Beta |
| Kit | KI, die du überprüfen kannst |
| Keywords | exclusive, accessibility, a11y, ai-agent, agent, screen-reader, accessibility-tree, audit, lint, geo, seo, wipe, splitter, before-after, devtools, semantic-html |
When to use
- A team wants to show how AI agents and screen readers perceive a page during review or a demo
- Developers audit a region for unnamed buttons, missing alt text and heading skips with a score
- A before and after view helps explain accessibility or agent-readiness fixes to stakeholders
Avoid when
- It would ship on a public production page for end users; keep it in dev, docs or review builds
- A full compliance audit is required; it flags common issues but does not replace a real audit
Installation
node scripts/add.mjs agent-vision --out ./src/marvelousKI-Agent mit dem MCP-Server von Marvelous UI: install_components({ slugs: ["agent-vision"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Kopierte Dateien (inklusive Abhängigkeiten): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, core/pointer.js, components/agent-vision/agent-vision.js, components/agent-vision/agent-vision.css.
Verwendung
Schnellstart mit dem kleinsten funktionierenden Markup:
<mv-agent-vision>
<form>
<h2>Newsletter</h2>
<input type="email" placeholder="Email"> <button>Subscribe</button>
<button type="button"><svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 6l12 12M18 6 6 18" stroke="currentColor" stroke-width="2"/></svg></button>
</form>
</mv-agent-vision>Referenz-Markup zum Starten und Anpassen mit Attributen, data-* und CSS-Variablen:
<div id="av-demo" style="width:min(100%,76rem);margin-inline:auto">
<style>
#av-demo .av-bar { display:flex; align-items:center; justify-content:space-between; gap:.75rem 1rem; flex-wrap:wrap; margin:0 0 1rem }
#av-demo .av-bar p { margin:0; color:var(--mv-fg-muted); font-size:.8125rem; max-width:46rem }
#av-demo .av-bar strong { color:var(--mv-fg) }
#av-demo .av-page { container-type:inline-size; padding:1rem 1.25rem 1.25rem; border:1px solid var(--mv-border); border-radius:var(--mv-radius-xl); background:var(--mv-surface) }
#av-demo .av-grid { display:grid; gap:1.25rem; margin-top:.875rem }
@container (min-width:36rem) { #av-demo .av-grid { grid-template-columns:minmax(0,1fr) minmax(0,1.05fr); gap:1.75rem } }
#av-demo .av-media { display:grid; gap:.625rem; align-content:start }
#av-demo .av-hero-wrap { position:relative }
#av-demo .av-hero { width:100%; aspect-ratio:4/3; object-fit:cover; border-radius:var(--mv-radius-lg) }
#av-demo .av-tools { position:absolute; top:.625rem; right:.625rem; display:flex; gap:.375rem }
#av-demo .av-tools .mv-button { background:var(--mv-surface-raised) }
#av-demo .av-tools svg { width:1rem; height:1rem }
#av-demo .av-thumbs { display:grid; grid-template-columns:repeat(3,1fr); gap:.5rem }
#av-demo .av-thumbs img { width:100%; aspect-ratio:1; object-fit:cover; border-radius:var(--mv-radius-md) }
#av-demo .av-thumbs img:nth-child(2) { object-position:20% 80%; transform:scaleX(-1) }
#av-demo .av-thumbs img:nth-child(3) { object-position:85% 30% }
#av-demo .av-info { display:grid; gap:.75rem; align-content:start }
#av-demo .av-brand { margin:0; color:var(--mv-fg-muted); font-size:.75rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase }
#av-demo .av-info h2 { margin:-.375rem 0 0; font-size:1.5rem; line-height:1.15; letter-spacing:-.02em }
#av-demo .av-reviews { color:var(--mv-fg-muted); font-size:.8125rem; text-decoration:none; justify-self:start }
#av-demo .av-reviews:hover { color:var(--mv-fg); text-decoration:underline }
#av-demo .av-reviews span { color:var(--mv-warning); letter-spacing:.08em; margin-right:.25rem }
#av-demo .av-price { display:flex; align-items:center; gap:.625rem; margin:0; font-size:1.375rem; font-weight:700; font-variant-numeric:tabular-nums }
#av-demo .av-dot { width:.625rem; height:.625rem; border-radius:50%; background:var(--mv-success); box-shadow:0 0 0 3px color-mix(in oklab,var(--mv-success) 22%,transparent) }
#av-demo .av-stock { color:var(--mv-fg-muted); font-size:.8125rem; font-weight:500 }
#av-demo .av-buy { display:grid; grid-template-columns:7rem 1fr; gap:.625rem; align-items:end }
#av-demo .av-buy > .mv-button { width:100% }
#av-demo .av-h { margin:.25rem 0 -.25rem; font-size:.9375rem }
#av-demo .av-perks { display:grid; gap:.375rem; margin:0; padding:0; list-style:none; font-size:.8125rem; color:var(--mv-fg-muted) }
#av-demo .av-perks li { display:flex; justify-content:space-between; gap:.75rem; padding:.5rem .75rem; border-radius:var(--mv-radius-md); background:var(--mv-bg-muted) }
#av-demo .av-perks a { color:var(--mv-fg); font-weight:500; white-space:nowrap }
#av-demo .av-promo { display:grid; gap:.375rem }
#av-demo .av-promo-row { display:flex; gap:.5rem }
#av-demo .av-hint { margin:.75rem 0 0; color:var(--mv-fg-muted); font-size:.75rem; text-align:center }
</style>
<div class="av-bar">
<p><strong>Agent view</strong>. Drag the scan line: on the right, the page as an AI agent or a screen reader perceives it. Click an issue to jump to it.</p>
<button class="mv-button" data-variant="outline" type="button" id="av-fix">Fix the page</button>
</div>
<mv-agent-vision id="av-vision" split="48">
<article class="av-page" aria-labelledby="av-title">
<nav class="mv-breadcrumb" aria-label="Breadcrumb">
<ol>
<li><a href="#home">Home</a></li>
<li><a href="#trail">Trail</a></li>
<li><span aria-current="page">Aster 3</span></li>
</ol>
</nav>
<div class="av-grid">
<div class="av-media">
<div class="av-hero-wrap">
<img class="av-hero" src="data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 480 360%27%3E%3Cdefs%3E%3ClinearGradient id=%27bg%27 x1=%270%27 y1=%270%27 x2=%270%27 y2=%271%27%3E%3Cstop offset=%270%27 stop-color=%27oklch(0.95 0.015 150)%27/%3E%3Cstop offset=%271%27 stop-color=%27oklch(0.88 0.03 150)%27/%3E%3C/linearGradient%3E%3CradialGradient id=%27fl%27%3E%3Cstop offset=%270%27 stop-color=%27black%27 stop-opacity=%27.25%27/%3E%3Cstop offset=%271%27 stop-color=%27black%27 stop-opacity=%270%27/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width=%27480%27 height=%27360%27 fill=%27url(%23bg)%27/%3E%3Cellipse cx=%27246%27 cy=%27286%27 rx=%27186%27 ry=%2716%27 fill=%27url(%23fl)%27/%3E%3Cpath d=%27M70 246 Q70 276 104 280 L386 280 Q424 278 428 246 Z%27 fill=%27oklch(0.3 0.03 160)%27/%3E%3Cpath d=%27M104 280v9M140 280v9M176 280v9M212 280v9M248 280v9M284 280v9M320 280v9M356 280v9M392 280v8%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-width=%2712%27/%3E%3Cpath d=%27M74 236 L426 236 Q430 254 416 262 L98 262 Q76 258 74 236Z%27 fill=%27oklch(0.96 0.01 90)%27/%3E%3Cpath d=%27M82 238 Q76 196 118 174 L192 136 Q212 98 252 94 L290 96 Q302 138 340 158 L392 182 Q428 200 426 238 Z%27 fill=%27oklch(0.66 0.16 40)%27/%3E%3Cpath d=%27M290 96 Q302 138 340 158 L392 182 Q428 200 426 238 L360 238 Q350 180 300 150 Z%27 fill=%27black%27 fill-opacity=%27.1%27/%3E%3Cpath d=%27M212 126 L262 148 M204 142 L254 164 M196 158 L246 180%27 stroke=%27oklch(0.96 0.01 90)%27 stroke-width=%277%27 stroke-linecap=%27round%27/%3E%3Cpath d=%27M104 218 Q230 200 416 220%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-opacity=%27.45%27 stroke-width=%276%27 fill=%27none%27/%3E%3Cpath d=%27M120 200 Q160 186 176 150%27 stroke=%27white%27 stroke-opacity=%27.35%27 stroke-width=%275%27 fill=%27none%27 stroke-linecap=%27round%27/%3E%3Ccircle cx=%27378%27 cy=%27206%27 r=%279%27 fill=%27oklch(0.96 0.01 90)%27 fill-opacity=%27.8%27/%3E%3C/svg%3E" alt="Aster 3 trail running shoe, side view" width="480" height="360">
<div class="av-tools">
<button class="mv-button" data-variant="outline" data-size="icon" data-shape="round" type="button" id="av-fav">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.5-1.5 3-3.2 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.8 0-3 .5-4.5 2-1.5-1.5-2.7-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4 3 5.5l7 7z"/></svg>
</button>
<button class="mv-button" data-variant="outline" data-size="icon" data-shape="round" type="button" id="av-share">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="m8.6 13.5 6.8 4M15.4 6.5l-6.8 4"/></svg>
</button>
</div>
</div>
<div class="av-thumbs">
<img src="data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 480 360%27%3E%3Cdefs%3E%3ClinearGradient id=%27bg%27 x1=%270%27 y1=%270%27 x2=%270%27 y2=%271%27%3E%3Cstop offset=%270%27 stop-color=%27oklch(0.95 0.015 150)%27/%3E%3Cstop offset=%271%27 stop-color=%27oklch(0.88 0.03 150)%27/%3E%3C/linearGradient%3E%3CradialGradient id=%27fl%27%3E%3Cstop offset=%270%27 stop-color=%27black%27 stop-opacity=%27.25%27/%3E%3Cstop offset=%271%27 stop-color=%27black%27 stop-opacity=%270%27/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width=%27480%27 height=%27360%27 fill=%27url(%23bg)%27/%3E%3Cellipse cx=%27246%27 cy=%27286%27 rx=%27186%27 ry=%2716%27 fill=%27url(%23fl)%27/%3E%3Cpath d=%27M70 246 Q70 276 104 280 L386 280 Q424 278 428 246 Z%27 fill=%27oklch(0.3 0.03 160)%27/%3E%3Cpath d=%27M104 280v9M140 280v9M176 280v9M212 280v9M248 280v9M284 280v9M320 280v9M356 280v9M392 280v8%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-width=%2712%27/%3E%3Cpath d=%27M74 236 L426 236 Q430 254 416 262 L98 262 Q76 258 74 236Z%27 fill=%27oklch(0.96 0.01 90)%27/%3E%3Cpath d=%27M82 238 Q76 196 118 174 L192 136 Q212 98 252 94 L290 96 Q302 138 340 158 L392 182 Q428 200 426 238 Z%27 fill=%27oklch(0.66 0.16 40)%27/%3E%3Cpath d=%27M290 96 Q302 138 340 158 L392 182 Q428 200 426 238 L360 238 Q350 180 300 150 Z%27 fill=%27black%27 fill-opacity=%27.1%27/%3E%3Cpath d=%27M212 126 L262 148 M204 142 L254 164 M196 158 L246 180%27 stroke=%27oklch(0.96 0.01 90)%27 stroke-width=%277%27 stroke-linecap=%27round%27/%3E%3Cpath d=%27M104 218 Q230 200 416 220%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-opacity=%27.45%27 stroke-width=%276%27 fill=%27none%27/%3E%3Cpath d=%27M120 200 Q160 186 176 150%27 stroke=%27white%27 stroke-opacity=%27.35%27 stroke-width=%275%27 fill=%27none%27 stroke-linecap=%27round%27/%3E%3Ccircle cx=%27378%27 cy=%27206%27 r=%279%27 fill=%27oklch(0.96 0.01 90)%27 fill-opacity=%27.8%27/%3E%3C/svg%3E" alt="Aster 3, full profile" width="160" height="160">
<img src="data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 480 360%27%3E%3Cdefs%3E%3ClinearGradient id=%27bg%27 x1=%270%27 y1=%270%27 x2=%270%27 y2=%271%27%3E%3Cstop offset=%270%27 stop-color=%27oklch(0.95 0.015 150)%27/%3E%3Cstop offset=%271%27 stop-color=%27oklch(0.88 0.03 150)%27/%3E%3C/linearGradient%3E%3CradialGradient id=%27fl%27%3E%3Cstop offset=%270%27 stop-color=%27black%27 stop-opacity=%27.25%27/%3E%3Cstop offset=%271%27 stop-color=%27black%27 stop-opacity=%270%27/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width=%27480%27 height=%27360%27 fill=%27url(%23bg)%27/%3E%3Cellipse cx=%27246%27 cy=%27286%27 rx=%27186%27 ry=%2716%27 fill=%27url(%23fl)%27/%3E%3Cpath d=%27M70 246 Q70 276 104 280 L386 280 Q424 278 428 246 Z%27 fill=%27oklch(0.3 0.03 160)%27/%3E%3Cpath d=%27M104 280v9M140 280v9M176 280v9M212 280v9M248 280v9M284 280v9M320 280v9M356 280v9M392 280v8%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-width=%2712%27/%3E%3Cpath d=%27M74 236 L426 236 Q430 254 416 262 L98 262 Q76 258 74 236Z%27 fill=%27oklch(0.96 0.01 90)%27/%3E%3Cpath d=%27M82 238 Q76 196 118 174 L192 136 Q212 98 252 94 L290 96 Q302 138 340 158 L392 182 Q428 200 426 238 Z%27 fill=%27oklch(0.66 0.16 40)%27/%3E%3Cpath d=%27M290 96 Q302 138 340 158 L392 182 Q428 200 426 238 L360 238 Q350 180 300 150 Z%27 fill=%27black%27 fill-opacity=%27.1%27/%3E%3Cpath d=%27M212 126 L262 148 M204 142 L254 164 M196 158 L246 180%27 stroke=%27oklch(0.96 0.01 90)%27 stroke-width=%277%27 stroke-linecap=%27round%27/%3E%3Cpath d=%27M104 218 Q230 200 416 220%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-opacity=%27.45%27 stroke-width=%276%27 fill=%27none%27/%3E%3Cpath d=%27M120 200 Q160 186 176 150%27 stroke=%27white%27 stroke-opacity=%27.35%27 stroke-width=%275%27 fill=%27none%27 stroke-linecap=%27round%27/%3E%3Ccircle cx=%27378%27 cy=%27206%27 r=%279%27 fill=%27oklch(0.96 0.01 90)%27 fill-opacity=%27.8%27/%3E%3C/svg%3E" width="160" height="160" id="av-thumb">
<img src="data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 480 360%27%3E%3Cdefs%3E%3ClinearGradient id=%27bg%27 x1=%270%27 y1=%270%27 x2=%270%27 y2=%271%27%3E%3Cstop offset=%270%27 stop-color=%27oklch(0.95 0.015 150)%27/%3E%3Cstop offset=%271%27 stop-color=%27oklch(0.88 0.03 150)%27/%3E%3C/linearGradient%3E%3CradialGradient id=%27fl%27%3E%3Cstop offset=%270%27 stop-color=%27black%27 stop-opacity=%27.25%27/%3E%3Cstop offset=%271%27 stop-color=%27black%27 stop-opacity=%270%27/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width=%27480%27 height=%27360%27 fill=%27url(%23bg)%27/%3E%3Cellipse cx=%27246%27 cy=%27286%27 rx=%27186%27 ry=%2716%27 fill=%27url(%23fl)%27/%3E%3Cpath d=%27M70 246 Q70 276 104 280 L386 280 Q424 278 428 246 Z%27 fill=%27oklch(0.3 0.03 160)%27/%3E%3Cpath d=%27M104 280v9M140 280v9M176 280v9M212 280v9M248 280v9M284 280v9M320 280v9M356 280v9M392 280v8%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-width=%2712%27/%3E%3Cpath d=%27M74 236 L426 236 Q430 254 416 262 L98 262 Q76 258 74 236Z%27 fill=%27oklch(0.96 0.01 90)%27/%3E%3Cpath d=%27M82 238 Q76 196 118 174 L192 136 Q212 98 252 94 L290 96 Q302 138 340 158 L392 182 Q428 200 426 238 Z%27 fill=%27oklch(0.66 0.16 40)%27/%3E%3Cpath d=%27M290 96 Q302 138 340 158 L392 182 Q428 200 426 238 L360 238 Q350 180 300 150 Z%27 fill=%27black%27 fill-opacity=%27.1%27/%3E%3Cpath d=%27M212 126 L262 148 M204 142 L254 164 M196 158 L246 180%27 stroke=%27oklch(0.96 0.01 90)%27 stroke-width=%277%27 stroke-linecap=%27round%27/%3E%3Cpath d=%27M104 218 Q230 200 416 220%27 stroke=%27oklch(0.3 0.03 160)%27 stroke-opacity=%27.45%27 stroke-width=%276%27 fill=%27none%27/%3E%3Cpath d=%27M120 200 Q160 186 176 150%27 stroke=%27white%27 stroke-opacity=%27.35%27 stroke-width=%275%27 fill=%27none%27 stroke-linecap=%27round%27/%3E%3Ccircle cx=%27378%27 cy=%27206%27 r=%279%27 fill=%27oklch(0.96 0.01 90)%27 fill-opacity=%27.8%27/%3E%3C/svg%3E" alt="Quick-lace detail" width="160" height="160">
</div>
</div>
<div class="av-info">
<p class="av-brand">Nomad Supply Co. · Trail</p>
<h2 id="av-title">Aster 3 Trail Running Shoe</h2>
<a class="av-reviews" href="#avis"><span aria-hidden="true">★★★★☆</span>Read reviews (128)</a>
<p class="av-price">$139.00 <span class="av-dot" title="In stock" id="av-dot"></span></p>
<div class="av-buy">
<div class="mv-field">
<label class="mv-label" for="av-size">Size (US)</label>
<select class="mv-select" id="av-size">
<option>8</option><option>9</option><option selected>10</option><option>10.5</option><option>11</option>
</select>
</div>
<div class="mv-button" data-size="lg" id="av-cart" onclick="this.textContent = 'Added ✓'">Add to cart</div>
</div>
<h4 class="av-h" id="av-heading">Shipping & returns</h4>
<ul class="av-perks">
<li><span>Free shipping on orders over $75</span><a href="#shipping">Learn more</a></li>
<li><span>Free returns within 30 days</span><a href="#returns">Learn more</a></li>
<li><span>2-year workshop warranty</span><a href="#warranty">Learn more</a></li>
</ul>
<form class="av-promo" aria-label="Promo code" onsubmit="event.preventDefault()">
<div class="av-promo-row">
<input class="mv-input" id="av-code" placeholder="Promo code" autocomplete="off">
<button class="mv-button" data-variant="secondary" type="submit">Apply</button>
</div>
</form>
</div>
</div>
</article>
</mv-agent-vision>
<p class="av-hint">Arrow keys or <kbd class="mv-kbd">Home</kbd> / <kbd class="mv-kbd">End</kbd> on the handle · “Fix the page” applies the fixes live and re-runs the scan</p>
<script type="module">
const vision = document.getElementById("av-vision");
const fix = document.getElementById("av-fix");
const $ = (id) => document.getElementById(id);
await customElements.whenDefined("mv-agent-vision");
// Semantic twins of the broken elements, swapped in and out.
const fakeCart = $("av-cart");
const realCart = Object.assign(document.createElement("button"), { type: "button", className: "mv-button", textContent: "Add to cart" });
realCart.dataset.size = "lg";
const badHeading = $("av-heading");
const goodHeading = Object.assign(document.createElement("h3"), { className: "av-h", textContent: badHeading.textContent });
const label = Object.assign(document.createElement("label"), { className: "mv-label", htmlFor: "av-code", textContent: "Promo code" });
const stock = Object.assign(document.createElement("span"), { className: "av-stock", textContent: "In stock" });
const links = [...document.querySelectorAll("#av-demo .av-perks a")];
const precise = ["Learn more about shipping", "Learn more about returns", "Learn more about the warranty"];
const apply = (fixed) => {
const toggle = (el, name, value) => (fixed ? el.setAttribute(name, value) : el.removeAttribute(name));
toggle($("av-fav"), "aria-label", "Add to wishlist");
toggle($("av-share"), "aria-label", "Share");
toggle($("av-thumb"), "alt", "Lugged outsole, bottom view");
(fixed ? fakeCart : realCart).replaceWith(fixed ? realCart : fakeCart);
(fixed ? badHeading : goodHeading).replaceWith(fixed ? goodHeading : badHeading);
const dot = $("av-dot");
if (fixed) { dot.removeAttribute("title"); dot.setAttribute("aria-hidden", "true"); dot.after(stock); }
else { dot.title = "In stock"; dot.removeAttribute("aria-hidden"); stock.remove(); }
links.forEach((a, i) => toggle(a, "aria-label", precise[i]));
if (fixed) document.querySelector("#av-demo .av-promo").prepend(label); else label.remove();
fix.dataset.fixed = String(fixed);
fix.textContent = fixed ? "Bring the flaws back" : "Fix the page";
};
fix.addEventListener("click", () => apply(fix.dataset.fixed !== "true"));
vision.addEventListener("mv-agent-scan", (e) => console.info("mv-agent-scan", e.detail.score, e.detail.issues.length));
</script>
</div>API
Attributes
| Name | Typ | Default | Description |
|---|---|---|---|
split | number (0-100) | 55 | Scan line position, as the % of the region shown in human view (the rest is agent view). |
scope | CSS selector | Restricts the analysis to matching elements inside the region (default: all wrapped content). | |
show | all | issues | all | Full agent view, or only the boxes with an issue. Also driven by the toggle in the panel. |
Properties
| Name | Typ | Description |
|---|---|---|
split | number | Current line position (read/write; dragging does not rewrite the attribute). |
score | number | Agent readability, 0-100: 100 − 7 per blocking issue − 3 per minor issue (a group of duplicate names counts once). |
issues | { type, severity, severityLabel, title, what, note, fix, role, name, count }[] | Detected issues, blockers first. severity: "blocker" | "minor". A non-enumerable elements property holds the affected nodes. |
tree | { role, label, name, level, states, rect, issue }[] | Perceived tree, JSON-serialisable: ARIA role, readable label, accessible name, states, rect relative to the region, issue if any. |
Methods
| Name | Description |
|---|---|
scan() | Re-runs the analysis now, announces the result and returns { score, issues } (the analysis also runs on its own, batched per frame). |
focusIssue(index) | Moves the line so the element is in agent view, scrolls it on screen if needed, selects and pulses its box, and announces the issue and its fix. |
Events
| Name | Description |
|---|---|
mv-agent-scan | Analysis finished with a new result (or an explicit scan()). detail: { score, issues }. |
Content structure
| Name | Description |
|---|---|
(content) | One child element: the region to analyse (card, section, form, whole page…). It stays fully interactive on both sides of the line. |
CSS classes
| Name | Description |
|---|---|
mv-agent-vision-layer / -box / -tag | Agent view layer (aria-hidden), wireframe boxes (data-kind control | heading | media | container, data-issue blocker | minor, data-selected) and their tree line. |
mv-agent-vision-rail / -handle / -scan | Splitter: role=slider handle and glowing scan line. |
mv-agent-vision-summary / -list / -issue | Panel: readability gauge, counts, display toggle, issue list (buttons). |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-agent-vision-accent | var(--mv-accent) | Scan line and interactive box color. |
--mv-agent-vision-blocker | var(--mv-danger) | Blocking issue color (always paired with an icon and a label). |
--mv-agent-vision-minor | var(--mv-warning) | Minor issue color. |
--mv-agent-vision-radius | var(--mv-radius-xl) | Agent view layer radius (match it to the region's). |
--mv-agent-vision-grid | 16px | Pitch of the grid that replaces the visual rendering. |
Accessibility
The tool is accessible itself. The handle is a role="slider" (arrows ±2, Shift ±10, Page Up/Down ±10, Home = all agent view, End = all human view) with aria-valuetext "48% human view, 52% agent view". The agent view layer is aria-hidden and pointer-events: none: the region keeps its keyboard, clicks and accessibility tree intact on both sides. The issue list is a real list of buttons (Tab, or Up/Down arrows, Home/End); the active issue carries aria-current. A polite live region announces the score when the analysis changes and, when an issue is selected, its description and fix. Severity is always an icon + label ("Blocker", "Minor") on top of color. Reduced motion: no typed-in labels or pulse, instant scrolling. No loop: everything is driven by MutationObserver, ResizeObserver and events, batched into one read-then-write pass per frame.