Agent skill

canvas-edit

Live Annotation Feedback Toolbar that overlays design review findings directly on web pages. Displays numbered badges on elements with issues, severity indicators, filtering, and screenshot capture. Integrates with design-review for real-time issue display. Triggers on "show annotations", "display issues", "annotate page", "overlay findings", or after running design-review.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/canvas-edit

SKILL.md

Canvas Edit - Live Annotation Toolbar

Floating toolbar that overlays design review findings directly on web pages in real-time. Displays numbered badges on problematic elements with severity-colored borders, hover popovers for issue details, and one-click screenshot capture.

Key features:

  • Live annotations - Numbered badges appear on elements as issues are found
  • Severity indicators - Color-coded badges (red/orange/blue) with counts
  • Issue popovers - Click badges to see full issue details and recommendations
  • Screenshot capture - Capture annotated page (toolbar hidden, annotations visible)
  • Shadow DOM - Toolbar is invisible to agent-eyes screenshots
  • Filtering - Filter by severity or pillar category

Breaking Changes from v1

This is a complete redesign. Canvas-edit is now a viewing tool, not an editing tool.

Old Functionality New Behavior
Text editing via textarea REMOVED
Style sliders (fontSize, etc.) REMOVED
"Save All to Code" button REPLACED with screenshot capture
contentEditable toggle REMOVED
edit command REPLACED with inject command

For live editing, use agent-canvas --with-edit instead.

Prerequisites

  • Python 3.10+
  • uv package manager
  • Playwright browsers: playwright install chromium

Commands

bash
SKILL_DIR=".claude/skills/canvas-edit/scripts"

Inject Annotations onto Page

bash
# Inject toolbar with issues from JSON file
uv run $SKILL_DIR/canvas_edit.py inject http://localhost:3000 --issues issues.json

# Inject with issues from stdin
echo '[{"id": 1, "selector": "h1", "severity": "major", "title": "Contrast issue"}]' | \
  uv run $SKILL_DIR/canvas_edit.py inject http://localhost:3000 --issues -

# Auto-screenshot on load
uv run $SKILL_DIR/canvas_edit.py inject http://localhost:3000 --issues issues.json --screenshot

Typical Workflow: Design Review + Annotations

bash
# 1. Run design review to find issues
uv run .claude/skills/design-review/scripts/design_review.py review http://localhost:3000 \
  --output-json issues.json

# 2. Inject annotations onto the page
uv run $SKILL_DIR/canvas_edit.py inject http://localhost:3000 --issues issues.json

# 3. User interacts with annotations, takes screenshots, closes browser

Toolbar Controls

The floating toolbar (top-right by default) provides:

Status Display

  • Issue count ("5 Issues" or "All looks good!")
  • Severity badges: 🔴 blocking, 🟡 major, 🔵 minor

Actions

  • 👁 Visibility: Show/hide all annotations
  • ⚙ Filter: Filter by severity or pillar category
  • 📸 Screenshot: Capture page with annotations (toolbar hidden)
  • ↕/↔ Orientation: Toggle vertical/horizontal toolbar
  • ✕ Dismiss: Remove toolbar and all annotations

Dragging

  • Grab the ☰ handle to drag toolbar anywhere on screen
  • Position persists during session

Annotation Badges

Each issue appears as a numbered badge on its target element:

  • Position: Top-right of target element (auto-adjusts at screen edges)
  • Color: Border matches severity (red/orange/blue)
  • Click: Opens popover with full issue details
  • Hover: Highlights the target element

Badge Popover Contents

┌─────────────────────────────────────┐
│ #3  Contrast issue         [major] │
├─────────────────────────────────────┤
│ Color contrast ratio 3.2:1 fails   │
│ WCAG AA requirement of 4.5:1       │
│                                     │
│ Pillar: Quality Craft               │
│ Check: color-contrast               │
├─────────────────────────────────────┤
│ Recommendation:                     │
│ Change text color to #1a1a1a or    │
│ background to #ffffff              │
└─────────────────────────────────────┘

Issue JSON Format

Issues can come from design-review output or be manually constructed:

json
[
  {
    "id": 1,
    "selector": ".hero-title",
    "severity": "major",
    "title": "Contrast ratio insufficient",
    "description": "Text contrast 3.2:1 fails WCAG AA (4.5:1 required)",
    "pillar": "Quality Craft",
    "checkId": "color-contrast",
    "recommendation": "Use darker text (#1a1a1a) or lighter background"
  },
  {
    "id": 2,
    "selector": "button.submit",
    "severity": "minor",
    "title": "Touch target too small",
    "description": "Button is 36x28px, minimum is 44x44px",
    "pillar": "Quality Craft",
    "checkId": "touch-target-size"
  }
]

Required Fields

Field Type Description
id number Unique identifier
selector string CSS selector for target element
severity string "blocking", "major", or "minor"
title string Short issue title

Optional Fields

Field Type Description
description string Detailed explanation
pillar string Design pillar category
checkId string Identifier for the check that found this
recommendation string Suggested fix

Event API (Canvas Bus)

Canvas-edit integrates with other skills via the canvas bus event system.

Events Emitted

Event Payload When
annotation.clicked {issueId, selector, severity} User clicks a badge
screenshot.requested {directory, filename, issueCount} Screenshot button clicked
screenshot.captured {path, issueCount} Screenshot saved (Python-side)
annotations.cleared {} Dismiss button clicked
filter.changed {severity, pillars} Filter settings changed

Events Subscribed

Event Action
review.started Show "Scanning..." state
review.issue_found Add badge for new issue
review.completed Show final count or success message
capture_mode.changed Hide/show toolbar for agent-eyes

Integration Example

javascript
// In another skill's JavaScript
const bus = window.__canvasBus;

// Listen for annotation clicks
bus.subscribe('annotation.clicked', (payload) => {
  console.log(`Issue ${payload.issueId} clicked: ${payload.selector}`);
});

// Add an issue programmatically
window.__annotationLayer.addIssue({
  id: 99,
  selector: '.problematic-element',
  severity: 'major',
  title: 'New issue found'
});

Screenshot Output

Screenshots are saved to .canvas/screenshots/ with timestamp filenames:

.canvas/screenshots/
├── 2026-01-23T15-30-45_5-issues.png
└── 2026-01-23T15-45-12_0-issues.png

Filename format: YYYY-MM-DDTHH-MM-SS_N-issues.png

Screenshots capture:

  • Full page content
  • All visible annotation badges
  • Element highlights (if active)
  • NOT the toolbar (hidden during capture)

Toolbar States

State Display Trigger
Issues Found "N Issues" + severity badges Default when issues > 0
All Clear "✓ All looks good!" (randomized) Zero issues after review completes
Scanning "⟳ Analyzing..." with spinner During review.started

Success messages rotate randomly:

  • "All looks good!"
  • "Ship it!"
  • "Pixel perfect"
  • "Zero issues found"
  • "Looking sharp!"

Keyboard Navigation

Key Action
Tab Navigate toolbar controls
1-9 Jump to badge by number
Arrow keys Navigate between visible badges
Enter/Space Activate focused button/badge
Escape Close open popover

Shadow DOM Isolation

The toolbar is rendered inside a closed Shadow DOM:

  • Invisible to document.querySelector()
  • Excluded from agent-eyes DOM snapshots
  • Hidden from screenshots (annotations remain visible)
  • Page styles cannot affect toolbar appearance

Notes

  • Toolbar auto-repositions to stay on screen when dragged or resized
  • Badges reposition when window resizes or scrolls
  • Multiple badges on the same element stack with offset
  • Orphaned badges (element removed) are automatically cleaned up
  • Filter state persists during session but resets on page reload

Didn't find tool you were looking for?

Be as detailed as possible for better results