โ† Back to skills
extension
Category: Development & EngineeringNo API key required

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.

personAuthor: jakexiaohubgithub

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

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

Inject Annotations onto Page

# 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

# 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:

[
  {
    "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

// 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