Skip to main content

comark-annotate

Writes annotated screenshots and before/after comparisons in Markdown with the comark-annotate Comark plugin, measures each mark from the page, and checks the rendered result. Use when the user wants PR evidence, a visual bug report, a design review, or any screenshot with marks, numbered notes, or arrows in a Markdown document.

Source facts

Repository
onmax/comark-plugins
Last source activity
October 21, 2026 at 22:15
Detected SKILL.md language
English
Stars
3
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
comark-annotate
description
Writes annotated screenshots and before/after comparisons in Markdown with the comark-annotate Comark plugin, measures each mark from the page, and checks the rendered result. Use when the user wants PR evidence, a visual bug report, a design review, or any screenshot with marks, numbered notes, or arrows in a Markdown document.
# Annotated screenshots You write Markdown; comark-annotate renders hand-drawn marks, numbered notes, side notes with arrows, and before/after pairs as static HTML. The reader only sees what you measured, so measure from the page and check the render before you hand it over. ## Choose the layout Pick what explains the change best, and mix freely with ordinary Markdown such as tables and lists: - One `::screenshot` with marks, when a single state shows the point. - A `::compare` of two screenshots, when the change is the point. Capture both at the same viewport, zoom, scroll, and page state, and set the same `viewport` on both. Each image gets under half the page width, where the text of a full-page capture is too small to read, so clip both captures to the same region around the change, such as Playwright's `screenshot({ clip })`. - `::compare{mode="slider"}` instead, when both screenshots show the same spot and the change is small, such as a number or a label at the same place. The reader drags a divider across one full-width image instead of reading two half-width ones. Side notes become numbered notes there, so skip `side`. - A side note (`side="left"`, `"right"`, or `"top"`) for the two or three points that matter most. With `mark="none"` the arrow alone points at the spot, which reads cleanest. Other notes stay numbered in the list under the image. In a side-by-side compare only `side="top"` keeps its arrow; left and right notes join the list. Mark the change at its own size: the bar, field, or label that changed. What stayed the same goes unmarked, or in one sentence above the screenshots. Keep it to about six marks per screenshot, fewer in a compare. Each note says what changed or what is wrong in the words the screen shows, so the reader can check it against the image; a value the screenshot doesn't show stays out of the note. ## Syntax ```md ::compare :::screenshot{src="before.png" alt="Filter toolbar wrapping onto a second row" viewport="1440x900" href="https://pr12.preview.example.com/correlations"} ::::annotation{x=3.6 y=20.6 w=92.9 h=31.4 color="red"} Moon phase and vibes don't fit, so the toolbar wraps and pushes the table down. :::: ::: :::screenshot{src="after.png" alt="Filter toolbar on one row" viewport="1440x900"} ::::annotation{x=87.6 y=24.2 w=7.4 h=9.9 mark="check" color="green"} **Apply** lines up with the chips. :::: ::: :: ``` - `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. Its two screenshots are titled Before and After unless they set their own. - `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), and `viewport` (like `1440x900`) are optional. Other content becomes the caption. - `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `highlight`, `cross`, `check`, or `none`, which needs a `side`. `color` is `blue` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `gray` for neutral, or a 3- or 6-digit hex color. `side` is `left`, `right`, or `top`; keep top notes at least a quarter of the image apart and left or right notes an eighth apart. - Annotations must be direct children of a screenshot. ## Measure every mark Never estimate coordinates from the image. In the browser you captured, measure the element and divide by the viewport: ```js const r = document.querySelector("SELECTOR").getBoundingClientRect(); [(r.x / innerWidth) * 100, (r.y / innerHeight) * 100, (r.width / innerWidth) * 100, (r.height / innerHeight) * 100].map((v) => +v.toFixed(1)); ``` For a full-page screenshot, add `scrollX`/`scrollY` and divide by `document.documentElement.scrollWidth` and `scrollHeight` instead. For a clipped capture, `getBoundingClientRect()` and Playwright's main-frame `clip` use viewport-relative coordinates, so do not add `scrollX`/`scrollY` to this formula. Make sure the clip fully contains every marked element. Subtract the clip's `x` and `y` and divide by its `width` and `height`; if an element crosses the clip edge, intersect its measured rectangle with the clip before normalizing so every value stays between 0 and 100. If the clip is in document coordinates, convert it to viewport coordinates before subtracting. ## Check and preview ```sh npx comark-annotate check report.md npx comark-annotate render report.md -o report.html ``` `check` prints one line per problem and exits with 1 if there are any. Each line names the block, such as `screenshot "after.png", annotation 2`, counting annotations within their screenshot, and says how to fix it. Fix every one. Pass several files to check them all. `render` writes a standalone page; open it in a browser, take a screenshot, and confirm each mark sits on its target and each number matches its note. If a mark can't be verified, say so in the report instead of guessing. Relative `src` paths resolve next to the output file. ## In a Comark host ```ts import { createHtmlRenderer } from "@comark/html"; import annotate, { components } from "comark-annotate/html"; const render = createHtmlRenderer({ plugins: [annotate()], components }); ``` Hosts can reject a document while `meta.issues` is non-empty. For untrusted input, add Comark's `security` plugin with `blockedTags` such as `script`, `style`, and `iframe`; it cleans notes too.
View on GitHub