comark-ui 0.7.4 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/html.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as criticCss, n as Preset, r as PresetOptions } from "./index-BUDHsvnm.mjs";
1
+ import { a as criticCss, n as Preset, r as PresetOptions } from "./index-Dbqxt4Qg.mjs";
2
2
  import { NodeHandler } from "comark";
3
3
  //#region src/html.d.ts
4
4
  /**
@@ -8,6 +8,7 @@ import { ReadingTimeOptions } from "comark-reading-time";
8
8
  import { XrefOptions } from "comark-xref";
9
9
  import { ComarkPlugin } from "comark";
10
10
  import { BadgeOptions } from "comark-badge";
11
+ import { AnnotateOptions } from "comark-annotate";
11
12
  import { CastOptions } from "comark-cast";
12
13
  import { ChartsOptions } from "comark-charts";
13
14
  import { ChipsOptions } from "comark-chips";
@@ -43,7 +44,7 @@ type PresetOptions = {
43
44
  /** Pastes files into the Markdown before the other plugins read it. Off, since it reads from disk by default. */
44
45
  include?: IncludeOptions | boolean;
45
46
  /** HTML only: Vue, React, and Svelte have no annotate components. */
46
- annotate?: boolean;
47
+ annotate?: AnnotateOptions | boolean;
47
48
  carousel?: boolean;
48
49
  /** Reads no cast files unless you pass `{ root }` or `{ read }`; inline casts render either way. */
49
50
  cast?: CastOptions | boolean;
@@ -122,7 +123,7 @@ type Part<C, O = void> = {
122
123
  };
123
124
  /** One renderer's entry of each package with components, by the option that turns it on. */
124
125
  type Renderer<C> = {
125
- annotate?: Part<C>;
126
+ annotate?: Part<C, AnnotateOptions>;
126
127
  carousel: Part<C>;
127
128
  cast: Part<C, CastOptions>;
128
129
  charts: Part<C, ChartsOptions>;
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { t as typesetCss } from "./typeset-css-DdOGL7WF.mjs";
2
- import { a as criticCss, c as typeset, i as Renderer, n as Preset, o as preset, r as PresetOptions, s as TYPESET_TAG, t as AnyPlugin } from "./index-BUDHsvnm.mjs";
2
+ import { a as criticCss, c as typeset, i as Renderer, n as Preset, o as preset, r as PresetOptions, s as TYPESET_TAG, t as AnyPlugin } from "./index-Dbqxt4Qg.mjs";
3
3
  export { AnyPlugin, Preset, PresetOptions, Renderer, TYPESET_TAG, criticCss, preset, typeset, typesetCss };
package/dist/react.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as criticCss, n as Preset, r as PresetOptions } from "./index-BUDHsvnm.mjs";
1
+ import { a as criticCss, n as Preset, r as PresetOptions } from "./index-Dbqxt4Qg.mjs";
2
2
  import { ComponentType } from "react";
3
3
  //#region src/react.d.ts
4
4
  type AnyComponent = ComponentType<any>;
@@ -51,7 +51,7 @@ Image `src` must be a URL the renderer can reach: a path next to the document, o
51
51
  1. Lint it, and fix until it reports no problems:
52
52
 
53
53
  ```sh
54
- vp dlx --package comark-linter --package comark-ui lint-comark evidence.md
54
+ vp dlx --package comark-linter --package comark-ui comark-lint evidence.md
55
55
  ```
56
56
 
57
57
  These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
@@ -141,5 +141,5 @@ Mark only what your text talks about. Each note says what changed or what is wro
141
141
 
142
142
  ## Check the result
143
143
 
144
- 1. Lint the file: `vp exec lint-comark report.md`, in a project with `comark-linter` and the plugins installed, where `comark-ui` counts as every plugin. It prints one line per problem with its line, its rule, and how to fix it, and exits with 1 while any remain. Fix every one, and run it again until it exits with 0. The [lint reference](references/lint.md) covers its flags, its config file, the library, ESLint, and Vite Doctor.
144
+ 1. Lint the file: `vp exec comark-lint report.md`, in a project with `comark-linter` and the plugins installed, where `comark-ui` counts as every plugin. It prints one line per problem with its line, its rule, and how to fix it, and exits with 1 while any remain. Fix every one, and run it again until it exits with 0. The [lint reference](references/lint.md) covers its flags, its config file, the library, ESLint, and Vite Doctor.
145
145
  2. Look at the render, made as the block's reference says. Open it in a browser and take a screenshot: each mark sits on its target, each number matches its note, and each chart says what your text says. If you can't verify something, say so when you hand the document over instead of guessing.
@@ -64,4 +64,4 @@ vp exec comark-annotate render report.md -o report.html
64
64
  ## Register
65
65
 
66
66
  - In `comark-ui`: on, in `comark-ui/html` only.
67
- - Alone: `pnpm add comark @comark/html comark-annotate`, then `createHtmlRenderer({ plugins: [annotate()], components })` with both from `comark-annotate/html`. It renders only to HTML and takes no options. Each document inlines the styles once, with style attributes for positions, so a strict Content Security Policy needs `style-src 'unsafe-inline'`.
67
+ - Alone: `pnpm add comark @comark/html comark-annotate`, then `createHtmlRenderer({ plugins: [annotate()], components })` with both from `comark-annotate/html`. It renders only to HTML. Screenshots reserve their `viewport`, or dimensions from a data URI. `annotate({ size: true })` also fetches remote screenshots at render time; enable it only for trusted documents, since requests follow redirects and can reach private networks. `annotate({ size: false })` disables measurement while retaining authored viewports. In `comark-ui`, put these options under `annotate`. Each document inlines the styles once, with style attributes for positions, so a strict Content Security Policy needs `style-src 'unsafe-inline'`.
@@ -5,14 +5,14 @@ comark-linter reports what Comark forgives, such as a `::` block never closed, a
5
5
  ## Run the command
6
6
 
7
7
  ```sh
8
- vp exec lint-comark "docs/**/*.md" --format json --check-urls
8
+ vp exec comark-lint "docs/**/*.md" --format json --check-urls
9
9
  ```
10
10
 
11
- - Pass files or globs. Quote a glob so the shell passes it as written; lint-comark expands it and skips `node_modules` and `dist`.
11
+ - Pass files or globs. Quote a glob so the shell passes it as written; comark-lint expands it and skips `node_modules` and `dist`.
12
12
  - It prints `file:line:column rule message fix` for each problem, or `No problems.` when there are none. It exits with 0 when clean, 1 on any problem, and 2 when a file can't be read, a glob matches nothing, or the config fails to load.
13
13
  - `--format json` prints an array of `{ file, rule, line, column, message, fix }` instead.
14
14
  - `--check-urls` also requests every external URL, and reports one that answers 404 or 410, has no DNS record, or fails its TLS check. It caches answers for a day in `node_modules/.cache/comark-linter/urls.json`, except a 404, 410, 429, or 5xx, which it requests again on the next run.
15
- - `--config lint-comark.config.ts` loads a config. The command finds none on its own.
15
+ - It loads `comark-lint.config.ts` (or `.mts`, `.mjs`, `.js`) from the working directory, or a `lint-comark.config` file there. `--config path/to/config.ts` loads another one instead.
16
16
 
17
17
  Run it from the project root. A relative link or image resolves from the document's folder, and a `/` path from the working directory. Each must point at a file that exists, so save the screenshots before you lint.
18
18
 
@@ -21,7 +21,7 @@ It lints with every comark-ui package installed, `comark-ui` first; the [comark-
21
21
  ## Config file
22
22
 
23
23
  ```ts
24
- // lint-comark.config.ts
24
+ // comark-lint.config.ts
25
25
  import { defineConfig } from "comark-linter";
26
26
  import include from "comark-include";
27
27
 
@@ -68,12 +68,12 @@ const results = await lintFiles(["docs/index.md", "docs/setup.md"], await resolv
68
68
  // eslint.config.js
69
69
  import comark from "comark-linter/eslint";
70
70
 
71
- export default [comark.configs.recommended, { settings: { comark: { config: "lint-comark.config.mjs" } } }];
71
+ export default [comark.configs.recommended, { settings: { comark: { config: "comark-lint.config.mjs" } } }];
72
72
  ```
73
73
 
74
74
  Use a JavaScript ES module (`export default { ... }`) for the linter config across supported Node versions. A `.ts` config requires Node 22.18+ or `--experimental-strip-types` on Node 22.12–22.17, including in the editor. Restart ESLint after editing the config or its imports; they are cached for the process lifetime.
75
75
 
76
- Install `eslint` (9.15 or later) and `@eslint/markdown` (8 or later). The recommended config lints `**/*.md` and `**/*.mdc` with `@eslint/markdown`'s `markdown/commonmark` language and YAML frontmatter, and turns on every rule but `comark/dead-url`, which requests every URL; turn that one on in `rules` to check them. Each rule has the name the command prints and is configured like any ESLint rule, `<!-- eslint-disable-next-line comark/unknown-component -->` included. ESLint prints the fix after the message. `settings.comark.config`, from the working directory, loads the same config file as `--config`. oxlint can't run it: its JS plugins don't lint `.md` files, so run `lint-comark` beside `oxlint`.
76
+ Install `eslint` (9.15 or later) and `@eslint/markdown` (8 or later). The recommended config lints `**/*.md` and `**/*.mdc` with `@eslint/markdown`'s `markdown/commonmark` language and YAML frontmatter, and turns on every rule but `comark/dead-url`, which requests every URL; turn that one on in `rules` to check them. Each rule has the name the command prints and is configured like any ESLint rule, `<!-- eslint-disable-next-line comark/unknown-component -->` included. ESLint prints the fix after the message. `settings.comark.config`, from the working directory, loads the same config file as `--config`. oxlint can't run it: its JS plugins don't lint `.md` files, so run `comark-lint` beside `oxlint`.
77
77
 
78
78
  ## Vite Doctor
79
79
 
@@ -93,4 +93,4 @@ Run `vite-doctor . --config doctor.config.ts --max-warnings 0`. The extension ta
93
93
  ## Register
94
94
 
95
95
  - In `comark-ui`: not included. Install it beside the preset, which it finds on its own.
96
- - Alone: `pnpm add -D comark-linter`. The command is `lint-comark`, the library `comark-linter`, the ESLint plugin `comark-linter/eslint`, and the extension `comark-linter/doctor`. npm refused `comark-lint` as too close to `remark-lint`, hence the name.
96
+ - Alone: `pnpm add -D comark-linter`. The command is `comark-lint`, also installed as `lint-comark`, the library `comark-linter`, the ESLint plugin `comark-linter/eslint`, and the extension `comark-linter/doctor`. npm refused `comark-lint` as too close to `remark-lint`, hence the name.
@@ -12,7 +12,7 @@ The spinner now stops once the build finishes:
12
12
 
13
13
  - A `src` that ends in `.mp4`, `.webm`, `.mov`, or `.m4v`, before any `?` or `#`, plays as a video, and one in `.mp3`, `.wav`, `.ogg`, or `.m4a` as audio. Every other image stays an image.
14
14
  - The alt text is required. It names the player for screen readers, and it's the text of a link to the file where the browser can't play it.
15
- - `autoplay`, `loop`, and `muted` are off by default. Browsers start a file by itself only when it's muted, so `autoplay` needs `muted`. `poster="frame.png"` shows an image before a video plays; audio takes none. `{loop=false}` turns a prop off. Other props, such as `width` or a class, are dropped and reported.
15
+ - `autoplay`, `loop`, and `muted` are off by default. Browsers start a file by itself only when it's muted, so `autoplay` needs `muted`. `poster="frame.png"` shows an image before a video plays; audio takes none. `{loop=false}` turns a prop off. A video's `width` and `height` must be paired whole pixel dimensions, like `{width=1280 height=720}`, to reserve its room before loading. Audio takes neither. Other props, such as a class, are dropped and reported.
16
16
  - A GitHub attachment link, `https://github.com/user-attachments/assets/<id>`, plays as a video when the bare URL sits alone in its paragraph, as on GitHub. With text of its own, or inside a sentence, it stays a link.
17
17
 
18
18
  ## Record the evidence
@@ -25,5 +25,5 @@ The spinner now stops once the build finishes:
25
25
 
26
26
  ## Register
27
27
 
28
- - In `comark-ui`: on. `media: { controls: "native" }` keeps the browser's own controls and leaves the script out.
28
+ - In `comark-ui`: on. `media: { controls: "native" }` keeps the browser's own controls and leaves the script out. Measurement reads only data URIs by default. `media: { size: true }` also measures remote videos while parsing; use it only for trusted documents, since requests follow redirects and can reach private networks. `media: { size: false }` disables measurement. Authored dimensions work with any setting. Alone, pass the same options to `media()`.
29
29
  - Alone: `pnpm add comark @comark/html comark-media`, then `createHtmlRenderer({ plugins: [media()], components })` with both from `comark-media/html`. `comark-media/vue`, `/react`, and `/svelte` render it too. Its place in `plugins` doesn't matter. It reads the tokens before any plugin sees the tree, so comark-zoom never zooms a video and comark-chips never turns an attachment link into a chip. The HTML renderer inlines the players' script once per document, and the browser's own controls show until it runs and whenever a file can't play.
@@ -22,7 +22,8 @@ comarkUi({
22
22
 
23
23
  - Every plugin except `include`, which reads files from disk. `include: { root, base }` turns it on, or `{ read }` in a browser or an edge runtime. `include: true` reads under the working directory.
24
24
  - `cast`, `table`, and `tests` get a reader that finds no file. Inline casts, CSV fences, and pasted JUnit reports render, and a `src` file doesn't load until you pass `{ root }` or `{ read }`. Any other options object replaces that reader too, so the plugin reads under the working directory.
25
- - Three plugins use the network while parsing: `chips` downloads favicons and avatars, `icon` fetches icon sets from the Iconify API, and `diagrams` sends each diagram's source to `https://kroki.io`. In a browser, pass `chips: { download: false }`, since a browser may not download another site's images. To parse offline, also pass `icon: { fetch: false }` with your icon sets in `collections`, and `diagrams: { draw: false }`. To keep diagram sources private, pass your own Kroki `server`.
25
+ - By default, three plugins use the network while parsing: `chips` downloads favicons and avatars, `icon` fetches icon sets from the Iconify API, and `diagrams` sends each diagram's source to `https://kroki.io`. In a browser, pass `chips: { download: false }`, since a browser may not download another site's images. To parse offline, also pass `icon: { fetch: false }` with your icon sets in `collections`, and `diagrams: { draw: false }`. To keep diagram sources private, pass your own Kroki `server`.
26
+ - Media sizing reads only data URIs by default. `zoom: { size: true }` and `media: { size: true }` also fetch remote files while parsing; `annotate: { size: true }` does so at HTML render time. Enable these only for trusted documents, since requests follow redirects and can reach private networks. `{ size: false }` disables measurement for each plugin; authored dimensions and screenshot viewports still work.
26
27
  - `icon`'s options apply to every icon the preset draws, in cards, details, file trees, tabs, and code actions too.
27
28
  - comark-critic has no component to add its styles, so put `criticCss`, which every entry exports, in the page.
28
29
  - The text around the blocks is styled by default, scoped to the element the document renders into, on the same `--comark-*` tokens. Pass `typeset: false` when the site already styles Markdown, such as with Tailwind Typography's `prose`.
@@ -31,5 +31,5 @@ The zoomed view fires `comark-zoom:open`, `comark-zoom:change`, and `comark-zoom
31
31
 
32
32
  ## Register
33
33
 
34
- - In `comark-ui`: on, as `zoom`. `zoom: { images: false }` leaves images alone, so only `::zoom` blocks and elements marked `{data-zoom}` zoom.
34
+ - In `comark-ui`: on, as `zoom`. `zoom: { images: false }` leaves images alone, so only `::zoom` blocks and elements marked `{data-zoom}` zoom. Data URI images get dimensions by default; one authored pixel side gets the other at the file's ratio. Images with both sides or a side such as `50%` keep them. `zoom: { size: true }` also measures remote images while parsing; use it only for trusted documents, since requests follow redirects and can reach private networks. `zoom: { size: false }` disables measurement. Alone, pass the same options to `zoom()`.
35
35
  - Alone: `pnpm add comark @comark/html comark-zoom`, then `createHtmlRenderer({ plugins: [zoom()], components })` with both from `comark-zoom/html`. `comark-zoom/vue`, `/react`, and `/svelte` export the same pair for those renderers. The plugin adds a node that starts the script, so pass the components even when only images zoom. A page with no renderer calls `start()` from `comark-zoom/client` once. comark-annotate and comark-carousel zoom their own blocks without it, so register `zoom()` for images and `::zoom`.
@@ -54,7 +54,7 @@ Follow [references/example.md](references/example.md):
54
54
  1. Lint it, and fix until it reports no problems:
55
55
 
56
56
  ```sh
57
- vp dlx --package comark-linter --package comark-ui lint-comark review.md
57
+ vp dlx --package comark-linter --package comark-ui comark-lint review.md
58
58
  ```
59
59
 
60
60
  These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
@@ -68,7 +68,7 @@ Done when the question tests the stated outcome with one changed input, every op
68
68
  1. Lint it, and fix until it reports no problems:
69
69
 
70
70
  ```sh
71
- vp dlx --package comark-linter --package comark-ui lint-comark lesson.md
71
+ vp dlx --package comark-linter --package comark-ui comark-lint lesson.md
72
72
  ```
73
73
 
74
74
  These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
@@ -57,7 +57,7 @@ Done when the explanation reads top to bottom in under a minute and every visual
57
57
  1. Lint it, and fix until it reports no problems:
58
58
 
59
59
  ```sh
60
- vp dlx --package comark-linter --package comark-ui lint-comark explanation.md
60
+ vp dlx --package comark-linter --package comark-ui comark-lint explanation.md
61
61
  ```
62
62
 
63
63
  These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
package/dist/skills.mjs CHANGED
@@ -12,7 +12,7 @@ const skills = [
12
12
  "files": [
13
13
  {
14
14
  "path": "SKILL.md",
15
- "text": "---\nname: before-after-evidence\ndescription: Shows a visible change as two comparable screenshots, before and after, with marks measured from the source and checked in the rendered page. Use when a pull request, bug fix, or design change alters what people see, or when someone asks for before/after screenshots or visual evidence.\nlicense: MIT\n---\n\n# Before/after evidence\n\nA before/after is evidence when a reviewer can check every claim against the two images and nothing else. Three things make it so, and the reader can't repair any of them: two captures of the same view, marks that sit on what changed, and notes in the words the screen shows.\n\nThis skill writes the document. Where it's published, and who can open it, is up to your host.\n\n## 1. Capture a comparable pair\n\nTake **after** from the branch or its preview, and **before** from a deployment or commit that still behaves the old way. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.\n\n- Set up the state that shows the change before you capture: the long name that wrapped, the error that stayed hidden, the empty list.\n- Clip both captures to one region around the change, the same rectangle on each side. A `::compare` gives each image under half the page width, where a full-page capture's text is too small to read.\n- Pin anything that moves the layout between the two states, such as a dialog centered vertically that grows by one line, so the same element sits at the same place in both.\n\nIf one side can't be captured comparably, stop and say what blocked you. A description in place of a screenshot, or one side alone, isn't before/after evidence.\n\nDone when both images exist, have the same size, and differ only where the change is.\n\n## 2. Measure every mark\n\nMarks take `x`, `y`, `w`, and `h` as percentages of the image. Measure them: an estimate drifts a few percent, and on a half-width image that's the neighbouring button.\n\n- **A page you captured:** read the element's box in the same browser, viewport, and state, minus the clip's offset. [references/measuring.md](references/measuring.md) has the snippet.\n- **A still you didn't capture**, such as a frame from a screen recording, a design export, or an image attached to a bug report: there is no DOM to ask. Measure in image pixels and divide by the image's natural width and height. Confirm each box by cropping the image to it and looking at the crop, as the same reference shows.\n\nMark the change at its own size: the field, the label, the button. Use `red` on the before side for the problem and `green` on the after side for the fix, and leave what stayed the same unmarked. Two or three marks a side usually tell the whole story.\n\nDone when every mark has numbers you measured, and you can name the element or the pixel rectangle each came from.\n\n## 3. Write the document\n\nStart from [references/example.md](references/example.md) and keep its shape:\n\n1. One sentence: what changed, and for whom.\n2. One line of steps to reach the screen, so a reviewer can reproduce it.\n3. The `::compare`, each note a few words in the screen's own words. A value the screenshot doesn't show stays out of its note.\n4. A `::diff` of the line that caused it, only when the reader would otherwise ask.\n\nThe images carry the evidence, so the text only points into them. How the work went (the checks you ran, retries, CI) goes in your report to the user, not in the document. [references/blocks.md](references/blocks.md) has the syntax of each block.\n\nImage `src` must be a URL the renderer can reach: a path next to the document, or an https URL your host gives you for the upload.\n\n## 4. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui lint-comark evidence.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the page where it will be read and take a screenshot of it. For a local screenshot-only check, copy the complete `::compare` block, including its nested screenshots and annotations, into `evidence-screenshots.md` beside `evidence.md`.\n\n Ensure comark-annotate is a direct dependency of this workspace package. If it is only transitive, read the installed Comark UI version and add that exact version with the project's package manager: for pnpm, `pnpm add -D comark-annotate@<version>`, substituting that version. Add `-w` when installing at the workspace root. With no Comark UI packages installed, omit `@<version>`. This links the executable without fetching a different renderer release via `@latest`. Then run:\n\n ```sh\n vp exec comark-annotate render evidence-screenshots.md -o evidence-screenshots.html\n ```\n\n Without Vite+, use `pnpm exec` with the same arguments.\n\n Open `evidence-screenshots.html` and take a screenshot of it. This CLI renders annotate, carousel, and zoom only; check any `::diff` or other blocks in the host's full Comark UI preview.\n3. Check that each mark sits on its target and each note matches what its side shows. Measure a mark that misses again, from the source, since a box moved by eye stays a guess.\n\nDone when you've looked at the rendered page and every mark lands. Name any mark or block you couldn't check in your report.\n"
15
+ "text": "---\nname: before-after-evidence\ndescription: Shows a visible change as two comparable screenshots, before and after, with marks measured from the source and checked in the rendered page. Use when a pull request, bug fix, or design change alters what people see, or when someone asks for before/after screenshots or visual evidence.\nlicense: MIT\n---\n\n# Before/after evidence\n\nA before/after is evidence when a reviewer can check every claim against the two images and nothing else. Three things make it so, and the reader can't repair any of them: two captures of the same view, marks that sit on what changed, and notes in the words the screen shows.\n\nThis skill writes the document. Where it's published, and who can open it, is up to your host.\n\n## 1. Capture a comparable pair\n\nTake **after** from the branch or its preview, and **before** from a deployment or commit that still behaves the old way. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.\n\n- Set up the state that shows the change before you capture: the long name that wrapped, the error that stayed hidden, the empty list.\n- Clip both captures to one region around the change, the same rectangle on each side. A `::compare` gives each image under half the page width, where a full-page capture's text is too small to read.\n- Pin anything that moves the layout between the two states, such as a dialog centered vertically that grows by one line, so the same element sits at the same place in both.\n\nIf one side can't be captured comparably, stop and say what blocked you. A description in place of a screenshot, or one side alone, isn't before/after evidence.\n\nDone when both images exist, have the same size, and differ only where the change is.\n\n## 2. Measure every mark\n\nMarks take `x`, `y`, `w`, and `h` as percentages of the image. Measure them: an estimate drifts a few percent, and on a half-width image that's the neighbouring button.\n\n- **A page you captured:** read the element's box in the same browser, viewport, and state, minus the clip's offset. [references/measuring.md](references/measuring.md) has the snippet.\n- **A still you didn't capture**, such as a frame from a screen recording, a design export, or an image attached to a bug report: there is no DOM to ask. Measure in image pixels and divide by the image's natural width and height. Confirm each box by cropping the image to it and looking at the crop, as the same reference shows.\n\nMark the change at its own size: the field, the label, the button. Use `red` on the before side for the problem and `green` on the after side for the fix, and leave what stayed the same unmarked. Two or three marks a side usually tell the whole story.\n\nDone when every mark has numbers you measured, and you can name the element or the pixel rectangle each came from.\n\n## 3. Write the document\n\nStart from [references/example.md](references/example.md) and keep its shape:\n\n1. One sentence: what changed, and for whom.\n2. One line of steps to reach the screen, so a reviewer can reproduce it.\n3. The `::compare`, each note a few words in the screen's own words. A value the screenshot doesn't show stays out of its note.\n4. A `::diff` of the line that caused it, only when the reader would otherwise ask.\n\nThe images carry the evidence, so the text only points into them. How the work went (the checks you ran, retries, CI) goes in your report to the user, not in the document. [references/blocks.md](references/blocks.md) has the syntax of each block.\n\nImage `src` must be a URL the renderer can reach: a path next to the document, or an https URL your host gives you for the upload.\n\n## 4. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint evidence.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the page where it will be read and take a screenshot of it. For a local screenshot-only check, copy the complete `::compare` block, including its nested screenshots and annotations, into `evidence-screenshots.md` beside `evidence.md`.\n\n Ensure comark-annotate is a direct dependency of this workspace package. If it is only transitive, read the installed Comark UI version and add that exact version with the project's package manager: for pnpm, `pnpm add -D comark-annotate@<version>`, substituting that version. Add `-w` when installing at the workspace root. With no Comark UI packages installed, omit `@<version>`. This links the executable without fetching a different renderer release via `@latest`. Then run:\n\n ```sh\n vp exec comark-annotate render evidence-screenshots.md -o evidence-screenshots.html\n ```\n\n Without Vite+, use `pnpm exec` with the same arguments.\n\n Open `evidence-screenshots.html` and take a screenshot of it. This CLI renders annotate, carousel, and zoom only; check any `::diff` or other blocks in the host's full Comark UI preview.\n3. Check that each mark sits on its target and each note matches what its side shows. Measure a mark that misses again, from the source, since a box moved by eye stays a guess.\n\nDone when you've looked at the rendered page and every mark lands. Name any mark or block you couldn't check in your report.\n"
16
16
  },
17
17
  {
18
18
  "path": "agents/openai.yaml",
@@ -42,7 +42,7 @@ const skills = [
42
42
  "files": [
43
43
  {
44
44
  "path": "SKILL.md",
45
- "text": "---\nname: comark-ui\ndescription: Writes PR evidence, explanations of how something works, and docs pages in Markdown with comark-ui. Use when a document needs an annotated screenshot, a before/after, a chart, a diagram, a code change, or another comark block, or when setting up comark-ui or a comark-* package.\n---\n\n# comark-ui\n\nYou write Markdown; the comark plugins render it as static HTML, from marks on screenshots and charts drawn from tables to code changes, diagrams, and steps. The reader sees only what you measured and wrote down, so measure every mark from the page, take every number from the data, and check the render before you hand it over.\n\n## Install\n\nPrefer `comark-ui`, every plugin in one install, registered in the order they need:\n\n```sh\npnpm add comark @comark/html comark-ui\n```\n\nRun the comark CLIs with the [global Vite+ CLI](https://viteplus.dev/guide/global-cli): `vp dlx` for a package the project doesn't install, `vp exec` for one it does. Without Vite+, `pnpm dlx` and `pnpm exec` take the same arguments.\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport comarkUi from \"comark-ui/html\";\n\nconst render = createHtmlRenderer(comarkUi());\n```\n\nEvery plugin is on except `include`. The [comark-ui reference](references/ui.md) covers its options, the plugins that read files or use the network, and its Vue, React, and Svelte entries.\n\nWhen a project wants only some plugins, install those packages and register each plugin with its components:\n\n```sh\npnpm add comark @comark/html comark-annotate\n```\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst render = createHtmlRenderer({ plugins: [annotate()], components });\n```\n\nEach reference ends with a Register section that says how its package registers alone and which options it needs.\n\nEither way, the HTML renderer inlines the styles once per document, and the Vue, React, and Svelte components add them on mount. On a server-rendered page, import each package's `style.css`, such as `comark-cards/style.css`, so the page doesn't shift. The `--comark-*` tokens in https://comark-ui.onmax.me/guide/theming/ theme every plugin at once. In a Nuxt UI app the plugins follow its `--ui-*` variables with no setup; for a page rendered outside the app, such as review evidence, put the CSS from `nuxtUiTheme({ colors: appConfig.ui?.colors, css: mainCss })` in `comark-ui/nuxt-ui` in a `<style>`, so the page matches the app.\n\nProblems land in `meta.issues` after `parseMarkdown`, one sentence each, and a host can refuse a document while any remain. For untrusted input, add Comark's `security` plugin with `blockedTags` such as `script`, `style`, and `iframe`; it cleans the Markdown inside blocks too.\n\n## Shape the document\n\nThis skill teaches the blocks. Four sibling skills teach a whole document, what goes in it and in what order: `before-after-evidence`, `review-document`, `visual-explanation`, and `teach-lesson`. When the user asks for one of those and the skill isn't installed, suggest `vp dlx skills add onmax/comark-ui` and picking it from the list.\n\n## Pick the blocks\n\nRead the reference for each block you use before you write it. Mix the blocks freely with ordinary Markdown, such as headings, tables, and lists.\n\n### Review blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| One state of a screen, with marks, numbered notes, or arrows | `::screenshot` | [annotate](references/annotate.md) |\n| A change on screen, before and after | `::compare` | [annotate](references/annotate.md) |\n| A command's output, such as a test run or a build, as colored text | `::cast` | [cast](references/cast.md) |\n| Numbers, such as sizes, timings, before/after metrics, a trend, or a timeline | `::chart` | [charts](references/charts.md) |\n| A flow, a sequence, an architecture, or a schema as a diagram | a `mermaid`, `d2`, `dot`, `plantuml`, `dbml`, `goat`, or `svgbob` fence | [diagrams](references/diagrams.md) |\n| Links and `@mentions` with the site's favicon or the person's avatar | links, `@user`, `:chip` | [chips](references/chips.md) |\n| Colors, such as design tokens before and after, or a palette | a color in inline code, `::palette` | [colors](references/colors.md) |\n| A suggested change to one file, before and after | `::diff` | [diff](references/diff.md) |\n| Suggested edits and comment threads on prose, such as a copy review, each note in a card in the margin | `:suggestion`, `:comment` | [comments](references/comments.md) |\n| A video, a design file, or a live reproduction from its link | `::embed` | [embed](references/embed.md) |\n| A screen recording or a sound that a screenshot can't show | `![alt](clip.mp4)` | [media](references/media.md) |\n| A number before and after, a table of befores and afters, or progress | `:delta`, `::stats`, `:progress` | [metrics](references/metrics.md) |\n| Data from a CSV, TSV, or JSON fence or file, as a table that copies and sorts | `::table`, a `csv` fence | [table](references/table.md) |\n| A test run's passed, failed, and skipped counts and its failures, from a JUnit report | `::tests` | [tests](references/tests.md) |\n| A note, tip, or warning box, or long output folded away, as on GitHub | `> [!NOTE]`, `<details>` | [github](references/github.md) |\n| The review's status, pull request, author, date, and tags in a box | frontmatter, `::properties` | [properties](references/properties.md) |\n| Claims backed by links, with numbered citations | `:cite`, `::sources` | [sources](references/sources.md) |\n| An icon in a sentence or a table cell, such as a logo or a status | `:icon` | [icon](references/icon.md) |\n| A preview link a reviewer can scan with a phone | `:qr` | [qr](references/qr.md) |\n| Why a line of code is there, as numbered notes under it | `// <1>` and a numbered list | [code-notes](references/code-notes.md) |\n\n### Page behavior\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A stable link to a section, or a link that opens a new tab | `{#id}`, `{target=\"_blank\"}` | [links](references/links.md) |\n| A table, code block, or diagram too small to read in place | `::zoom` | [zoom](references/zoom.md) |\n| A sequence to page through in one place, such as the screens of a flow | `::carousel` | [carousel](references/carousel.md) |\n| Versions of one thing where each reader needs only one, such as an OS or a package manager | `::tabs`, `::code-group`, `pm` | [tabs](references/tabs.md) |\n| Code with lines marked added, removed, or highlighted, or a pasted `git diff` | `ins={4}` after a fence's language, `diff lang=\"ts\"` | [code](references/code.md) |\n\n### Docs blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Content a reader may skip, such as a long log, behind a summary | `::details`, `::accordion`, `::collapsible` | [details](references/details.md) |\n| Folders and files, with what a change added, removed, or changed | `::file-tree` | [file-tree](references/file-tree.md) |\n| A component's props or a function's options, with types and defaults | `::field` | [fields](references/fields.md) |\n| A version, status, or deprecation tag in a heading or a sentence | `:badge` | [badge](references/badge.md) |\n| Links to the next pages as cards, or blocks side by side | `::card-group`, `::columns` | [cards](references/cards.md) |\n| Instructions the reader follows in order, such as repro or setup steps | `::steps` | [steps](references/steps.md) |\n| Code that changes over several steps, such as a refactor told one move at a time | `::magic-move` | [magic-move](references/magic-move.md) |\n| An interactive lesson question, poll, or recall card | `::question`, `::poll`, `::recall` | [quiz](references/quiz.md) |\n\n### Markdown syntax\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Bold or italics in Chinese, Japanese, or Korean text | `**…**`, `*…*` | [cjk](references/cjk.md) |\n| An image with a caption under it | `![alt](src \"Caption\")` | [figure](references/figure.md) |\n| A highlighted phrase or a superscript | `==text==`, `^2^` | [mark](references/mark.md) |\n| A suggested edit or a comment inside the text | `{++ ++}`, `{-- --}`, `{~~ ~> ~~}`, `{== ==}`, `{>> <<}` | [critic](references/critic.md) |\n| Terms and their definitions, such as a glossary | `Term`, then `: definition` | [deflist](references/deflist.md) |\n| A numbered note at the end of the page, such as a source or a caveat | `[^label]`, `^[note]` | [footnotes](references/footnotes.md) |\n| A formula, such as a complexity bound or how a number was computed | `$…$`, `$$…$$` | [math](references/math.md) |\n| A keyboard shortcut | `++ctrl+k++` | [keys](references/keys.md) |\n\n### Authoring tools\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A shared section, or real source lines, pasted from a file | `:include{src}` | [include](references/include.md) |\n| A table of contents of the page's headings | `::toc` | [outline](references/outline.md) |\n| Figures and tables numbered and referred to by number | `{#fig-name}`, `:ref{#fig-name}` | [xref](references/xref.md) |\n| Word count and reading time, for the page's layout | nothing; it writes `meta.readingTime` | [reading-time](references/reading-time.md) |\n\n### Chat\n\n| To show | Use | Reference |\n| --- | --- | --- |\n| An AI SDK chat message, with its reasoning, tool calls, sources, and files | `MessageParts` from `comark-chat` | [chat](references/chat.md) |\n\n## Marks\n\nScreenshots and charts draw the same marks. Each `::annotation` is one mark and its note, written in Markdown.\n\n- `mark` is `box` (default), `circle`, `underline`, `highlight`, `bracket`, `cross`, `check`, or `none`, which draws nothing, so its note needs a `side` and the arrow alone points.\n- `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color.\n- `side` is `top`, `bottom`, `left`, or `right`, and puts the note in that margin with an arrow to its mark. Notes without one are numbered in a list under the figure.\n\nMark only what your text talks about. Each note says what changed or what is wrong in the words the screen or the table shows, so the reader can check it against the figure; a value the figure doesn't show stays out of the note.\n\n## Check the result\n\n1. Lint the file: `vp exec lint-comark report.md`, in a project with `comark-linter` and the plugins installed, where `comark-ui` counts as every plugin. It prints one line per problem with its line, its rule, and how to fix it, and exits with 1 while any remain. Fix every one, and run it again until it exits with 0. The [lint reference](references/lint.md) covers its flags, its config file, the library, ESLint, and Vite Doctor.\n2. Look at the render, made as the block's reference says. Open it in a browser and take a screenshot: each mark sits on its target, each number matches its note, and each chart says what your text says. If you can't verify something, say so when you hand the document over instead of guessing.\n"
45
+ "text": "---\nname: comark-ui\ndescription: Writes PR evidence, explanations of how something works, and docs pages in Markdown with comark-ui. Use when a document needs an annotated screenshot, a before/after, a chart, a diagram, a code change, or another comark block, or when setting up comark-ui or a comark-* package.\n---\n\n# comark-ui\n\nYou write Markdown; the comark plugins render it as static HTML, from marks on screenshots and charts drawn from tables to code changes, diagrams, and steps. The reader sees only what you measured and wrote down, so measure every mark from the page, take every number from the data, and check the render before you hand it over.\n\n## Install\n\nPrefer `comark-ui`, every plugin in one install, registered in the order they need:\n\n```sh\npnpm add comark @comark/html comark-ui\n```\n\nRun the comark CLIs with the [global Vite+ CLI](https://viteplus.dev/guide/global-cli): `vp dlx` for a package the project doesn't install, `vp exec` for one it does. Without Vite+, `pnpm dlx` and `pnpm exec` take the same arguments.\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport comarkUi from \"comark-ui/html\";\n\nconst render = createHtmlRenderer(comarkUi());\n```\n\nEvery plugin is on except `include`. The [comark-ui reference](references/ui.md) covers its options, the plugins that read files or use the network, and its Vue, React, and Svelte entries.\n\nWhen a project wants only some plugins, install those packages and register each plugin with its components:\n\n```sh\npnpm add comark @comark/html comark-annotate\n```\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst render = createHtmlRenderer({ plugins: [annotate()], components });\n```\n\nEach reference ends with a Register section that says how its package registers alone and which options it needs.\n\nEither way, the HTML renderer inlines the styles once per document, and the Vue, React, and Svelte components add them on mount. On a server-rendered page, import each package's `style.css`, such as `comark-cards/style.css`, so the page doesn't shift. The `--comark-*` tokens in https://comark-ui.onmax.me/guide/theming/ theme every plugin at once. In a Nuxt UI app the plugins follow its `--ui-*` variables with no setup; for a page rendered outside the app, such as review evidence, put the CSS from `nuxtUiTheme({ colors: appConfig.ui?.colors, css: mainCss })` in `comark-ui/nuxt-ui` in a `<style>`, so the page matches the app.\n\nProblems land in `meta.issues` after `parseMarkdown`, one sentence each, and a host can refuse a document while any remain. For untrusted input, add Comark's `security` plugin with `blockedTags` such as `script`, `style`, and `iframe`; it cleans the Markdown inside blocks too.\n\n## Shape the document\n\nThis skill teaches the blocks. Four sibling skills teach a whole document, what goes in it and in what order: `before-after-evidence`, `review-document`, `visual-explanation`, and `teach-lesson`. When the user asks for one of those and the skill isn't installed, suggest `vp dlx skills add onmax/comark-ui` and picking it from the list.\n\n## Pick the blocks\n\nRead the reference for each block you use before you write it. Mix the blocks freely with ordinary Markdown, such as headings, tables, and lists.\n\n### Review blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| One state of a screen, with marks, numbered notes, or arrows | `::screenshot` | [annotate](references/annotate.md) |\n| A change on screen, before and after | `::compare` | [annotate](references/annotate.md) |\n| A command's output, such as a test run or a build, as colored text | `::cast` | [cast](references/cast.md) |\n| Numbers, such as sizes, timings, before/after metrics, a trend, or a timeline | `::chart` | [charts](references/charts.md) |\n| A flow, a sequence, an architecture, or a schema as a diagram | a `mermaid`, `d2`, `dot`, `plantuml`, `dbml`, `goat`, or `svgbob` fence | [diagrams](references/diagrams.md) |\n| Links and `@mentions` with the site's favicon or the person's avatar | links, `@user`, `:chip` | [chips](references/chips.md) |\n| Colors, such as design tokens before and after, or a palette | a color in inline code, `::palette` | [colors](references/colors.md) |\n| A suggested change to one file, before and after | `::diff` | [diff](references/diff.md) |\n| Suggested edits and comment threads on prose, such as a copy review, each note in a card in the margin | `:suggestion`, `:comment` | [comments](references/comments.md) |\n| A video, a design file, or a live reproduction from its link | `::embed` | [embed](references/embed.md) |\n| A screen recording or a sound that a screenshot can't show | `![alt](clip.mp4)` | [media](references/media.md) |\n| A number before and after, a table of befores and afters, or progress | `:delta`, `::stats`, `:progress` | [metrics](references/metrics.md) |\n| Data from a CSV, TSV, or JSON fence or file, as a table that copies and sorts | `::table`, a `csv` fence | [table](references/table.md) |\n| A test run's passed, failed, and skipped counts and its failures, from a JUnit report | `::tests` | [tests](references/tests.md) |\n| A note, tip, or warning box, or long output folded away, as on GitHub | `> [!NOTE]`, `<details>` | [github](references/github.md) |\n| The review's status, pull request, author, date, and tags in a box | frontmatter, `::properties` | [properties](references/properties.md) |\n| Claims backed by links, with numbered citations | `:cite`, `::sources` | [sources](references/sources.md) |\n| An icon in a sentence or a table cell, such as a logo or a status | `:icon` | [icon](references/icon.md) |\n| A preview link a reviewer can scan with a phone | `:qr` | [qr](references/qr.md) |\n| Why a line of code is there, as numbered notes under it | `// <1>` and a numbered list | [code-notes](references/code-notes.md) |\n\n### Page behavior\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A stable link to a section, or a link that opens a new tab | `{#id}`, `{target=\"_blank\"}` | [links](references/links.md) |\n| A table, code block, or diagram too small to read in place | `::zoom` | [zoom](references/zoom.md) |\n| A sequence to page through in one place, such as the screens of a flow | `::carousel` | [carousel](references/carousel.md) |\n| Versions of one thing where each reader needs only one, such as an OS or a package manager | `::tabs`, `::code-group`, `pm` | [tabs](references/tabs.md) |\n| Code with lines marked added, removed, or highlighted, or a pasted `git diff` | `ins={4}` after a fence's language, `diff lang=\"ts\"` | [code](references/code.md) |\n\n### Docs blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Content a reader may skip, such as a long log, behind a summary | `::details`, `::accordion`, `::collapsible` | [details](references/details.md) |\n| Folders and files, with what a change added, removed, or changed | `::file-tree` | [file-tree](references/file-tree.md) |\n| A component's props or a function's options, with types and defaults | `::field` | [fields](references/fields.md) |\n| A version, status, or deprecation tag in a heading or a sentence | `:badge` | [badge](references/badge.md) |\n| Links to the next pages as cards, or blocks side by side | `::card-group`, `::columns` | [cards](references/cards.md) |\n| Instructions the reader follows in order, such as repro or setup steps | `::steps` | [steps](references/steps.md) |\n| Code that changes over several steps, such as a refactor told one move at a time | `::magic-move` | [magic-move](references/magic-move.md) |\n| An interactive lesson question, poll, or recall card | `::question`, `::poll`, `::recall` | [quiz](references/quiz.md) |\n\n### Markdown syntax\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Bold or italics in Chinese, Japanese, or Korean text | `**…**`, `*…*` | [cjk](references/cjk.md) |\n| An image with a caption under it | `![alt](src \"Caption\")` | [figure](references/figure.md) |\n| A highlighted phrase or a superscript | `==text==`, `^2^` | [mark](references/mark.md) |\n| A suggested edit or a comment inside the text | `{++ ++}`, `{-- --}`, `{~~ ~> ~~}`, `{== ==}`, `{>> <<}` | [critic](references/critic.md) |\n| Terms and their definitions, such as a glossary | `Term`, then `: definition` | [deflist](references/deflist.md) |\n| A numbered note at the end of the page, such as a source or a caveat | `[^label]`, `^[note]` | [footnotes](references/footnotes.md) |\n| A formula, such as a complexity bound or how a number was computed | `$…$`, `$$…$$` | [math](references/math.md) |\n| A keyboard shortcut | `++ctrl+k++` | [keys](references/keys.md) |\n\n### Authoring tools\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A shared section, or real source lines, pasted from a file | `:include{src}` | [include](references/include.md) |\n| A table of contents of the page's headings | `::toc` | [outline](references/outline.md) |\n| Figures and tables numbered and referred to by number | `{#fig-name}`, `:ref{#fig-name}` | [xref](references/xref.md) |\n| Word count and reading time, for the page's layout | nothing; it writes `meta.readingTime` | [reading-time](references/reading-time.md) |\n\n### Chat\n\n| To show | Use | Reference |\n| --- | --- | --- |\n| An AI SDK chat message, with its reasoning, tool calls, sources, and files | `MessageParts` from `comark-chat` | [chat](references/chat.md) |\n\n## Marks\n\nScreenshots and charts draw the same marks. Each `::annotation` is one mark and its note, written in Markdown.\n\n- `mark` is `box` (default), `circle`, `underline`, `highlight`, `bracket`, `cross`, `check`, or `none`, which draws nothing, so its note needs a `side` and the arrow alone points.\n- `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color.\n- `side` is `top`, `bottom`, `left`, or `right`, and puts the note in that margin with an arrow to its mark. Notes without one are numbered in a list under the figure.\n\nMark only what your text talks about. Each note says what changed or what is wrong in the words the screen or the table shows, so the reader can check it against the figure; a value the figure doesn't show stays out of the note.\n\n## Check the result\n\n1. Lint the file: `vp exec comark-lint report.md`, in a project with `comark-linter` and the plugins installed, where `comark-ui` counts as every plugin. It prints one line per problem with its line, its rule, and how to fix it, and exits with 1 while any remain. Fix every one, and run it again until it exits with 0. The [lint reference](references/lint.md) covers its flags, its config file, the library, ESLint, and Vite Doctor.\n2. Look at the render, made as the block's reference says. Open it in a browser and take a screenshot: each mark sits on its target, each number matches its note, and each chart says what your text says. If you can't verify something, say so when you hand the document over instead of guessing.\n"
46
46
  },
47
47
  {
48
48
  "path": "agents/openai.yaml",
@@ -50,7 +50,7 @@ const skills = [
50
50
  },
51
51
  {
52
52
  "path": "references/annotate.md",
53
- "text": "# Screenshots and compares\n\ncomark-annotate draws `::screenshot` and `::compare`. Their marks take the values under Marks in SKILL.md.\n\n## Choose the layout\n\nPick what explains the change best:\n\n- One `::screenshot` with marks, when a single state shows the point.\n- 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 })`.\n- `::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`.\n- A side note for the two or three points that matter most. With `mark=\"none\"` and `to` on the exact spot, the arrow alone points and nothing covers the screen, which reads cleanest. Other notes stay numbered in the list under the image. In a side-by-side compare only `top` and `bottom` keep their arrows; left and right notes join the list.\n\nFor a review the reader should follow without a key, write it the way a designer marks up a board: the default ink with no `color`, every note a side note in the margin nearest its point, set off with `at` so its arrow sweeps in, and a `bracket` where a note covers a run of rows. Write the notes of a compare as a pair that argue the change: \"The type gets the headline…\" on the before, \"The message becomes the starting point.\" on the after.\n\nMark 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.\n\n## Syntax\n\n```md\n::compare\n:::screenshot{src=\"before.png\" alt=\"Filter toolbar wrapping onto a second row\" viewport=\"1440x900\" href=\"https://pr12.preview.example.com/correlations\"}\n::::annotation{x=3.6 y=20.6 w=92.9 h=31.4 color=\"red\"}\nMoon phase and vibes don't fit, so the toolbar wraps and pushes the table down.\n::::\n:::\n\n:::screenshot{src=\"after.png\" alt=\"Filter toolbar on one row\" viewport=\"1440x900\"}\n::::annotation{x=87.6 y=24.2 w=7.4 h=9.9 mark=\"check\" color=\"green\"}\n**Apply** lines up with the chips.\n::::\n:::\n::\n```\n\n- `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. `ink` colors every annotation in both screenshots that doesn't set its own `color`. Its two screenshots are titled Before and After unless they set their own.\n- `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), `viewport` (like `1440x900`), and `ink` are optional. Other content becomes the caption.\n- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket`, `cross`, `check`, or `none`, which needs a `side`. `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color. `side` is `top`, `bottom`, `left`, or `right`; keep top or bottom notes at least a quarter of the image apart and left or right notes an eighth apart.\n- `at` moves a side note along its margin, as a percentage of the image (across for top and bottom, down for left and right). A note set off from its point reads away from it, so put it on the side with room: a top note at `at=40` pointing left of 40 reads to the right. `to=\"x,y\"` is the point the arrow lands on, measured like the box; without it the arrow meets the middle of the mark's facing edge. Both need a `side`.\n- Annotations must be direct children of a screenshot.\n\n## Measure every mark\n\nTake each mark's coordinates from the page, in the browser you captured. Measure the element and divide by the viewport:\n\n```js\nconst r = document.querySelector(\"SELECTOR\").getBoundingClientRect();\n[(r.x / innerWidth) * 100, (r.y / innerHeight) * 100, (r.width / innerWidth) * 100, (r.height / innerHeight) * 100].map((v) => +v.toFixed(1));\n```\n\nFor a full-page screenshot, add `scrollX`/`scrollY` and divide by `document.documentElement.scrollWidth` and `scrollHeight` instead.\nFor a clipped capture, `getBoundingClientRect()` and Playwright's main-frame `clip` both use viewport-relative coordinates, so the formula takes no scroll offsets. 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.\n\n## Preview\n\nEnsure comark-annotate is a direct dependency of the workspace package where you run the CLI. If it is only transitive, read the installed Comark UI version and add that exact version with the project's package manager: for pnpm, `pnpm add -D comark-annotate@<version>`, substituting that version. Add `-w` when installing at the workspace root. With no Comark UI packages installed, omit `@<version>`. This links the executable without fetching a different renderer release via `@latest`.\n\n```sh\nvp exec comark-annotate render report.md -o report.html\n```\n\n`render` writes a standalone page of the screenshots and compares, and relative `src` paths resolve next to it. Without comark-linter, `vp exec comark-annotate check report.md` lists these blocks' problems on its own. It names each one like `screenshot \"after.png\", annotation 2`, counting annotations within their screenshot, and exits with 1 while any remain.\n\n## Register\n\n- In `comark-ui`: on, in `comark-ui/html` only.\n- Alone: `pnpm add comark @comark/html comark-annotate`, then `createHtmlRenderer({ plugins: [annotate()], components })` with both from `comark-annotate/html`. It renders only to HTML and takes no options. Each document inlines the styles once, with style attributes for positions, so a strict Content Security Policy needs `style-src 'unsafe-inline'`.\n"
53
+ "text": "# Screenshots and compares\n\ncomark-annotate draws `::screenshot` and `::compare`. Their marks take the values under Marks in SKILL.md.\n\n## Choose the layout\n\nPick what explains the change best:\n\n- One `::screenshot` with marks, when a single state shows the point.\n- 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 })`.\n- `::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`.\n- A side note for the two or three points that matter most. With `mark=\"none\"` and `to` on the exact spot, the arrow alone points and nothing covers the screen, which reads cleanest. Other notes stay numbered in the list under the image. In a side-by-side compare only `top` and `bottom` keep their arrows; left and right notes join the list.\n\nFor a review the reader should follow without a key, write it the way a designer marks up a board: the default ink with no `color`, every note a side note in the margin nearest its point, set off with `at` so its arrow sweeps in, and a `bracket` where a note covers a run of rows. Write the notes of a compare as a pair that argue the change: \"The type gets the headline…\" on the before, \"The message becomes the starting point.\" on the after.\n\nMark 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.\n\n## Syntax\n\n```md\n::compare\n:::screenshot{src=\"before.png\" alt=\"Filter toolbar wrapping onto a second row\" viewport=\"1440x900\" href=\"https://pr12.preview.example.com/correlations\"}\n::::annotation{x=3.6 y=20.6 w=92.9 h=31.4 color=\"red\"}\nMoon phase and vibes don't fit, so the toolbar wraps and pushes the table down.\n::::\n:::\n\n:::screenshot{src=\"after.png\" alt=\"Filter toolbar on one row\" viewport=\"1440x900\"}\n::::annotation{x=87.6 y=24.2 w=7.4 h=9.9 mark=\"check\" color=\"green\"}\n**Apply** lines up with the chips.\n::::\n:::\n::\n```\n\n- `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. `ink` colors every annotation in both screenshots that doesn't set its own `color`. Its two screenshots are titled Before and After unless they set their own.\n- `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), `viewport` (like `1440x900`), and `ink` are optional. Other content becomes the caption.\n- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket`, `cross`, `check`, or `none`, which needs a `side`. `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color. `side` is `top`, `bottom`, `left`, or `right`; keep top or bottom notes at least a quarter of the image apart and left or right notes an eighth apart.\n- `at` moves a side note along its margin, as a percentage of the image (across for top and bottom, down for left and right). A note set off from its point reads away from it, so put it on the side with room: a top note at `at=40` pointing left of 40 reads to the right. `to=\"x,y\"` is the point the arrow lands on, measured like the box; without it the arrow meets the middle of the mark's facing edge. Both need a `side`.\n- Annotations must be direct children of a screenshot.\n\n## Measure every mark\n\nTake each mark's coordinates from the page, in the browser you captured. Measure the element and divide by the viewport:\n\n```js\nconst r = document.querySelector(\"SELECTOR\").getBoundingClientRect();\n[(r.x / innerWidth) * 100, (r.y / innerHeight) * 100, (r.width / innerWidth) * 100, (r.height / innerHeight) * 100].map((v) => +v.toFixed(1));\n```\n\nFor a full-page screenshot, add `scrollX`/`scrollY` and divide by `document.documentElement.scrollWidth` and `scrollHeight` instead.\nFor a clipped capture, `getBoundingClientRect()` and Playwright's main-frame `clip` both use viewport-relative coordinates, so the formula takes no scroll offsets. 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.\n\n## Preview\n\nEnsure comark-annotate is a direct dependency of the workspace package where you run the CLI. If it is only transitive, read the installed Comark UI version and add that exact version with the project's package manager: for pnpm, `pnpm add -D comark-annotate@<version>`, substituting that version. Add `-w` when installing at the workspace root. With no Comark UI packages installed, omit `@<version>`. This links the executable without fetching a different renderer release via `@latest`.\n\n```sh\nvp exec comark-annotate render report.md -o report.html\n```\n\n`render` writes a standalone page of the screenshots and compares, and relative `src` paths resolve next to it. Without comark-linter, `vp exec comark-annotate check report.md` lists these blocks' problems on its own. It names each one like `screenshot \"after.png\", annotation 2`, counting annotations within their screenshot, and exits with 1 while any remain.\n\n## Register\n\n- In `comark-ui`: on, in `comark-ui/html` only.\n- Alone: `pnpm add comark @comark/html comark-annotate`, then `createHtmlRenderer({ plugins: [annotate()], components })` with both from `comark-annotate/html`. It renders only to HTML. Screenshots reserve their `viewport`, or dimensions from a data URI. `annotate({ size: true })` also fetches remote screenshots at render time; enable it only for trusted documents, since requests follow redirects and can reach private networks. `annotate({ size: false })` disables measurement while retaining authored viewports. In `comark-ui`, put these options under `annotate`. Each document inlines the styles once, with style attributes for positions, so a strict Content Security Policy needs `style-src 'unsafe-inline'`.\n"
54
54
  },
55
55
  {
56
56
  "path": "references/badge.md",
@@ -162,7 +162,7 @@ const skills = [
162
162
  },
163
163
  {
164
164
  "path": "references/lint.md",
165
- "text": "# Checking documents\n\ncomark-linter reports what Comark forgives, such as a `::` block never closed, a misspelled component, or a link to a missing file. It also reports every problem a plugin puts in `meta.issues`, each under its own rule. Check the result in SKILL.md runs it on one file; this page covers its flags, its config file, the library, ESLint, and Vite Doctor.\n\n## Run the command\n\n```sh\nvp exec lint-comark \"docs/**/*.md\" --format json --check-urls\n```\n\n- Pass files or globs. Quote a glob so the shell passes it as written; lint-comark expands it and skips `node_modules` and `dist`.\n- It prints `file:line:column rule message fix` for each problem, or `No problems.` when there are none. It exits with 0 when clean, 1 on any problem, and 2 when a file can't be read, a glob matches nothing, or the config fails to load.\n- `--format json` prints an array of `{ file, rule, line, column, message, fix }` instead.\n- `--check-urls` also requests every external URL, and reports one that answers 404 or 410, has no DNS record, or fails its TLS check. It caches answers for a day in `node_modules/.cache/comark-linter/urls.json`, except a 404, 410, 429, or 5xx, which it requests again on the next run.\n- `--config lint-comark.config.ts` loads a config. The command finds none on its own.\n\nRun it from the project root. A relative link or image resolves from the document's folder, and a `/` path from the working directory. Each must point at a file that exists, so save the screenshots before you lint.\n\nIt lints with every comark-ui package installed, `comark-ui` first; the [comark-ui reference](ui.md) says what it turns on there. Besides each plugin's own rules, named `comark/<package>/<kind>`, it reports unclosed blocks, unknown components, an unclosed `{` or a key set twice, broken links and anchors, frontmatter that isn't valid YAML, `javascript:` and other unsafe URLs, duplicate ids, images without alt text unless `{alt=\"\"}` marks them as decoration, and empty links. It also reports links that stop working for other readers: localhost, private network, and `file:` URLs, tunnels such as ngrok, and Vercel or Netlify deploy previews. In PR evidence, link the production page or the pull request, and write a local address as code, such as `` `localhost:3000` ``, since Comark links a bare URL.\n\n## Config file\n\n```ts\n// lint-comark.config.ts\nimport { defineConfig } from \"comark-linter\";\nimport include from \"comark-include\";\n\nexport default defineConfig({\n plugins: [include({ root: \"content\" })],\n components: [\"duck-count\"],\n links: { routes: { \"/\": \"content\" }, skip: [\"staging.example.com\"] },\n});\n```\n\n- `plugins` and `components` add to those of the installed packages. `components` takes names, or the components map you render with. Comark keeps the first plugin of each name and drops the rest, so a config can add plugins, such as your own or [include](include.md), and can't change the options of one an installed package registers.\n- It takes every library option below except `file`. Node reads a `.ts` config from 22.18 on; on older versions, write it as `.mjs`.\n\n`links` sets how the linter checks links. It applies `skip`, `block`, and `allow` in that order, then checks the file or the URL:\n\n| Option | What it does |\n| --- | --- |\n| `skip` | Links that skip every check, the built-in block list included. |\n| `block` | Patterns added to the built-in list of local, private, tunnel, and preview URLs. `false` turns that list off. |\n| `allow` | When set, the linter blocks a link to any external host it doesn't match. |\n| `routes` | Where a `/` link finds its file. A record maps URL prefixes to folders from `root`, and the longest prefix wins. A function gets the path and returns the file's path from `root`, `true` for a page with no Markdown to check, or `undefined` when nothing serves it. By default, a `/` link resolves from `root`, as on GitHub. |\n| `urls` | `true`, or these options, does what `--check-urls` does: `timeout` (10000 ms), `concurrency` (8, at most 2 to one host), `retries` (1), `cache` (the file above, or `false`), and `maxAge` (one day, in ms). |\n\nA pattern is a host (`example.com`), its subdomains (`*.example.com`), a host with a port or a path (`example.com:8080`, `example.com/docs`), a RegExp tested against the link as written, or a function that gets the resolved `URL`.\n\n## Library\n\n```ts\nimport { lint, lintFiles, resolveConfig } from \"comark-linter\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst diagnostics = await lint(markdown, { plugins: [annotate()], components, file: \"docs/review.md\" });\nconst results = await lintFiles([\"docs/index.md\", \"docs/setup.md\"], await resolveConfig());\n```\n\n- `lint(markdown, options)` returns `{ rule, line, column?, message, fix }[]` in source order and never throws. A rule that crashes reports one diagnostic saying so, and the others still run.\n- Pass `plugins` and `components`, the ones you render with; without `components`, it skips the unknown-component check. Pass `file`, the document's path, to check its links to files. `root` defaults to the working directory, and `read`, `exists`, and `list` replace node:fs, by absolute path. Pass `headingIds` if you render with it, so anchors match, and `links` as above.\n- `lintFiles(paths, options)` parses each file once, checks links between them against each other's headings, and requests each URL once. It returns `{ file, text, diagnostics }` for each path, with no `text` when the file can't be read.\n- `resolveConfig(config)` returns the installed packages' plugins and components plus the config's, as the command uses them. `rules` maps every rule to its title.\n\n## ESLint\n\n```js\n// eslint.config.js\nimport comark from \"comark-linter/eslint\";\n\nexport default [comark.configs.recommended, { settings: { comark: { config: \"lint-comark.config.mjs\" } } }];\n```\n\nUse a JavaScript ES module (`export default { ... }`) for the linter config across supported Node versions. A `.ts` config requires Node 22.18+ or `--experimental-strip-types` on Node 22.12–22.17, including in the editor. Restart ESLint after editing the config or its imports; they are cached for the process lifetime.\n\nInstall `eslint` (9.15 or later) and `@eslint/markdown` (8 or later). The recommended config lints `**/*.md` and `**/*.mdc` with `@eslint/markdown`'s `markdown/commonmark` language and YAML frontmatter, and turns on every rule but `comark/dead-url`, which requests every URL; turn that one on in `rules` to check them. Each rule has the name the command prints and is configured like any ESLint rule, `<!-- eslint-disable-next-line comark/unknown-component -->` included. ESLint prints the fix after the message. `settings.comark.config`, from the working directory, loads the same config file as `--config`. oxlint can't run it: its JS plugins don't lint `.md` files, so run `lint-comark` beside `oxlint`.\n\n## Vite Doctor\n\n```ts\n// doctor.config.ts\nimport comark from \"comark-linter/doctor\";\nimport { defineDoctorConfig } from \"vite-doctor/config\";\n\nexport default defineDoctorConfig({\n extends: [\"comark/recommended\"],\n extensions: [comark({ include: \"content/**/*.md\" })],\n});\n```\n\nRun `vite-doctor . --config doctor.config.ts --max-warnings 0`. The extension takes the config file's options plus `include` (default `**/*.{md,mdc}`) and `exclude` (default `node_modules` and `dist`), and needs vite-doctor 0.1 or later. Each rule reports under its own code, from `COMARK0001` for the core rules and a hundred per package. Unsafe URLs, invalid frontmatter, and paths that leave a plugin's `root` are errors; the rest are warnings, which Vite Doctor passes unless you add `--max-warnings 0`.\n\n## Register\n\n- In `comark-ui`: not included. Install it beside the preset, which it finds on its own.\n- Alone: `pnpm add -D comark-linter`. The command is `lint-comark`, the library `comark-linter`, the ESLint plugin `comark-linter/eslint`, and the extension `comark-linter/doctor`. npm refused `comark-lint` as too close to `remark-lint`, hence the name.\n"
165
+ "text": "# Checking documents\n\ncomark-linter reports what Comark forgives, such as a `::` block never closed, a misspelled component, or a link to a missing file. It also reports every problem a plugin puts in `meta.issues`, each under its own rule. Check the result in SKILL.md runs it on one file; this page covers its flags, its config file, the library, ESLint, and Vite Doctor.\n\n## Run the command\n\n```sh\nvp exec comark-lint \"docs/**/*.md\" --format json --check-urls\n```\n\n- Pass files or globs. Quote a glob so the shell passes it as written; comark-lint expands it and skips `node_modules` and `dist`.\n- It prints `file:line:column rule message fix` for each problem, or `No problems.` when there are none. It exits with 0 when clean, 1 on any problem, and 2 when a file can't be read, a glob matches nothing, or the config fails to load.\n- `--format json` prints an array of `{ file, rule, line, column, message, fix }` instead.\n- `--check-urls` also requests every external URL, and reports one that answers 404 or 410, has no DNS record, or fails its TLS check. It caches answers for a day in `node_modules/.cache/comark-linter/urls.json`, except a 404, 410, 429, or 5xx, which it requests again on the next run.\n- It loads `comark-lint.config.ts` (or `.mts`, `.mjs`, `.js`) from the working directory, or a `lint-comark.config` file there. `--config path/to/config.ts` loads another one instead.\n\nRun it from the project root. A relative link or image resolves from the document's folder, and a `/` path from the working directory. Each must point at a file that exists, so save the screenshots before you lint.\n\nIt lints with every comark-ui package installed, `comark-ui` first; the [comark-ui reference](ui.md) says what it turns on there. Besides each plugin's own rules, named `comark/<package>/<kind>`, it reports unclosed blocks, unknown components, an unclosed `{` or a key set twice, broken links and anchors, frontmatter that isn't valid YAML, `javascript:` and other unsafe URLs, duplicate ids, images without alt text unless `{alt=\"\"}` marks them as decoration, and empty links. It also reports links that stop working for other readers: localhost, private network, and `file:` URLs, tunnels such as ngrok, and Vercel or Netlify deploy previews. In PR evidence, link the production page or the pull request, and write a local address as code, such as `` `localhost:3000` ``, since Comark links a bare URL.\n\n## Config file\n\n```ts\n// comark-lint.config.ts\nimport { defineConfig } from \"comark-linter\";\nimport include from \"comark-include\";\n\nexport default defineConfig({\n plugins: [include({ root: \"content\" })],\n components: [\"duck-count\"],\n links: { routes: { \"/\": \"content\" }, skip: [\"staging.example.com\"] },\n});\n```\n\n- `plugins` and `components` add to those of the installed packages. `components` takes names, or the components map you render with. Comark keeps the first plugin of each name and drops the rest, so a config can add plugins, such as your own or [include](include.md), and can't change the options of one an installed package registers.\n- It takes every library option below except `file`. Node reads a `.ts` config from 22.18 on; on older versions, write it as `.mjs`.\n\n`links` sets how the linter checks links. It applies `skip`, `block`, and `allow` in that order, then checks the file or the URL:\n\n| Option | What it does |\n| --- | --- |\n| `skip` | Links that skip every check, the built-in block list included. |\n| `block` | Patterns added to the built-in list of local, private, tunnel, and preview URLs. `false` turns that list off. |\n| `allow` | When set, the linter blocks a link to any external host it doesn't match. |\n| `routes` | Where a `/` link finds its file. A record maps URL prefixes to folders from `root`, and the longest prefix wins. A function gets the path and returns the file's path from `root`, `true` for a page with no Markdown to check, or `undefined` when nothing serves it. By default, a `/` link resolves from `root`, as on GitHub. |\n| `urls` | `true`, or these options, does what `--check-urls` does: `timeout` (10000 ms), `concurrency` (8, at most 2 to one host), `retries` (1), `cache` (the file above, or `false`), and `maxAge` (one day, in ms). |\n\nA pattern is a host (`example.com`), its subdomains (`*.example.com`), a host with a port or a path (`example.com:8080`, `example.com/docs`), a RegExp tested against the link as written, or a function that gets the resolved `URL`.\n\n## Library\n\n```ts\nimport { lint, lintFiles, resolveConfig } from \"comark-linter\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst diagnostics = await lint(markdown, { plugins: [annotate()], components, file: \"docs/review.md\" });\nconst results = await lintFiles([\"docs/index.md\", \"docs/setup.md\"], await resolveConfig());\n```\n\n- `lint(markdown, options)` returns `{ rule, line, column?, message, fix }[]` in source order and never throws. A rule that crashes reports one diagnostic saying so, and the others still run.\n- Pass `plugins` and `components`, the ones you render with; without `components`, it skips the unknown-component check. Pass `file`, the document's path, to check its links to files. `root` defaults to the working directory, and `read`, `exists`, and `list` replace node:fs, by absolute path. Pass `headingIds` if you render with it, so anchors match, and `links` as above.\n- `lintFiles(paths, options)` parses each file once, checks links between them against each other's headings, and requests each URL once. It returns `{ file, text, diagnostics }` for each path, with no `text` when the file can't be read.\n- `resolveConfig(config)` returns the installed packages' plugins and components plus the config's, as the command uses them. `rules` maps every rule to its title.\n\n## ESLint\n\n```js\n// eslint.config.js\nimport comark from \"comark-linter/eslint\";\n\nexport default [comark.configs.recommended, { settings: { comark: { config: \"comark-lint.config.mjs\" } } }];\n```\n\nUse a JavaScript ES module (`export default { ... }`) for the linter config across supported Node versions. A `.ts` config requires Node 22.18+ or `--experimental-strip-types` on Node 22.12–22.17, including in the editor. Restart ESLint after editing the config or its imports; they are cached for the process lifetime.\n\nInstall `eslint` (9.15 or later) and `@eslint/markdown` (8 or later). The recommended config lints `**/*.md` and `**/*.mdc` with `@eslint/markdown`'s `markdown/commonmark` language and YAML frontmatter, and turns on every rule but `comark/dead-url`, which requests every URL; turn that one on in `rules` to check them. Each rule has the name the command prints and is configured like any ESLint rule, `<!-- eslint-disable-next-line comark/unknown-component -->` included. ESLint prints the fix after the message. `settings.comark.config`, from the working directory, loads the same config file as `--config`. oxlint can't run it: its JS plugins don't lint `.md` files, so run `comark-lint` beside `oxlint`.\n\n## Vite Doctor\n\n```ts\n// doctor.config.ts\nimport comark from \"comark-linter/doctor\";\nimport { defineDoctorConfig } from \"vite-doctor/config\";\n\nexport default defineDoctorConfig({\n extends: [\"comark/recommended\"],\n extensions: [comark({ include: \"content/**/*.md\" })],\n});\n```\n\nRun `vite-doctor . --config doctor.config.ts --max-warnings 0`. The extension takes the config file's options plus `include` (default `**/*.{md,mdc}`) and `exclude` (default `node_modules` and `dist`), and needs vite-doctor 0.1 or later. Each rule reports under its own code, from `COMARK0001` for the core rules and a hundred per package. Unsafe URLs, invalid frontmatter, and paths that leave a plugin's `root` are errors; the rest are warnings, which Vite Doctor passes unless you add `--max-warnings 0`.\n\n## Register\n\n- In `comark-ui`: not included. Install it beside the preset, which it finds on its own.\n- Alone: `pnpm add -D comark-linter`. The command is `comark-lint`, also installed as `lint-comark`, the library `comark-linter`, the ESLint plugin `comark-linter/eslint`, and the extension `comark-linter/doctor`. npm refused `comark-lint` as too close to `remark-lint`, hence the name.\n"
166
166
  },
167
167
  {
168
168
  "path": "references/magic-move.md",
@@ -178,7 +178,7 @@ const skills = [
178
178
  },
179
179
  {
180
180
  "path": "references/media.md",
181
- "text": "# Videos and audio\n\ncomark-media plays an image that points at a video or a sound file, and a GitHub attachment link alone on its line, with the alt text as the player's label. Use it for a screen recording in PR evidence: a transition, a loading state, or a sound, which a screenshot can't show.\n\n## Syntax\n\n```md\nThe spinner now stops once the build finishes:\n\n![The build spinner stops and the Deploy button turns green](./recordings/build.mp4){loop muted}\n```\n\n- A `src` that ends in `.mp4`, `.webm`, `.mov`, or `.m4v`, before any `?` or `#`, plays as a video, and one in `.mp3`, `.wav`, `.ogg`, or `.m4a` as audio. Every other image stays an image.\n- The alt text is required. It names the player for screen readers, and it's the text of a link to the file where the browser can't play it.\n- `autoplay`, `loop`, and `muted` are off by default. Browsers start a file by itself only when it's muted, so `autoplay` needs `muted`. `poster=\"frame.png\"` shows an image before a video plays; audio takes none. `{loop=false}` turns a prop off. Other props, such as `width` or a class, are dropped and reported.\n- A GitHub attachment link, `https://github.com/user-attachments/assets/<id>`, plays as a video when the bare URL sits alone in its paragraph, as on GitHub. With text of its own, or inside a sentence, it stays a link.\n\n## Record the evidence\n\n- Record only the part of the screen that changes, for a few seconds.\n- Encode it as H.264 `.mp4` for every browser, or `.webm` for a smaller file. A `.mov` from macOS doesn't always play in Firefox.\n- Say what happens in the alt text, so a reader who can't play the file still learns what it shows.\n- Add `loop muted` to a clip of one motion, so it reads like an animated screenshot once played.\n- A GitHub attachment from a private repository plays only for readers signed in with access to it. For a page that others read, download the file and serve it with the page.\n\n## Register\n\n- In `comark-ui`: on. `media: { controls: \"native\" }` keeps the browser's own controls and leaves the script out.\n- Alone: `pnpm add comark @comark/html comark-media`, then `createHtmlRenderer({ plugins: [media()], components })` with both from `comark-media/html`. `comark-media/vue`, `/react`, and `/svelte` render it too. Its place in `plugins` doesn't matter. It reads the tokens before any plugin sees the tree, so comark-zoom never zooms a video and comark-chips never turns an attachment link into a chip. The HTML renderer inlines the players' script once per document, and the browser's own controls show until it runs and whenever a file can't play.\n"
181
+ "text": "# Videos and audio\n\ncomark-media plays an image that points at a video or a sound file, and a GitHub attachment link alone on its line, with the alt text as the player's label. Use it for a screen recording in PR evidence: a transition, a loading state, or a sound, which a screenshot can't show.\n\n## Syntax\n\n```md\nThe spinner now stops once the build finishes:\n\n![The build spinner stops and the Deploy button turns green](./recordings/build.mp4){loop muted}\n```\n\n- A `src` that ends in `.mp4`, `.webm`, `.mov`, or `.m4v`, before any `?` or `#`, plays as a video, and one in `.mp3`, `.wav`, `.ogg`, or `.m4a` as audio. Every other image stays an image.\n- The alt text is required. It names the player for screen readers, and it's the text of a link to the file where the browser can't play it.\n- `autoplay`, `loop`, and `muted` are off by default. Browsers start a file by itself only when it's muted, so `autoplay` needs `muted`. `poster=\"frame.png\"` shows an image before a video plays; audio takes none. `{loop=false}` turns a prop off. A video's `width` and `height` must be paired whole pixel dimensions, like `{width=1280 height=720}`, to reserve its room before loading. Audio takes neither. Other props, such as a class, are dropped and reported.\n- A GitHub attachment link, `https://github.com/user-attachments/assets/<id>`, plays as a video when the bare URL sits alone in its paragraph, as on GitHub. With text of its own, or inside a sentence, it stays a link.\n\n## Record the evidence\n\n- Record only the part of the screen that changes, for a few seconds.\n- Encode it as H.264 `.mp4` for every browser, or `.webm` for a smaller file. A `.mov` from macOS doesn't always play in Firefox.\n- Say what happens in the alt text, so a reader who can't play the file still learns what it shows.\n- Add `loop muted` to a clip of one motion, so it reads like an animated screenshot once played.\n- A GitHub attachment from a private repository plays only for readers signed in with access to it. For a page that others read, download the file and serve it with the page.\n\n## Register\n\n- In `comark-ui`: on. `media: { controls: \"native\" }` keeps the browser's own controls and leaves the script out. Measurement reads only data URIs by default. `media: { size: true }` also measures remote videos while parsing; use it only for trusted documents, since requests follow redirects and can reach private networks. `media: { size: false }` disables measurement. Authored dimensions work with any setting. Alone, pass the same options to `media()`.\n- Alone: `pnpm add comark @comark/html comark-media`, then `createHtmlRenderer({ plugins: [media()], components })` with both from `comark-media/html`. `comark-media/vue`, `/react`, and `/svelte` render it too. Its place in `plugins` doesn't matter. It reads the tokens before any plugin sees the tree, so comark-zoom never zooms a video and comark-chips never turns an attachment link into a chip. The HTML renderer inlines the players' script once per document, and the browser's own controls show until it runs and whenever a file can't play.\n"
182
182
  },
183
183
  {
184
184
  "path": "references/metrics.md",
@@ -226,7 +226,7 @@ const skills = [
226
226
  },
227
227
  {
228
228
  "path": "references/ui.md",
229
- "text": "# Every plugin in one install\n\ncomark-ui registers every comark-ui package for one renderer, in the order they need, with one icon resolver shared by `:icon`, cards, details, file trees, tabs, and code actions. Install in SKILL.md shows its basic use. This page covers its options, what it turns on, its other renderers, and how the linter uses it.\n\n## Options\n\n`comarkUi(options)` returns `{ plugins, components }`. Each key is a package's name without `comark-`, in camelCase, such as `fileTree`, `codeNotes`, or `readingTime`. `false` turns a plugin off along with its components, and an object turns it on with those options. `true` turns on `include` and leaves the others as they are:\n\n```ts\ncomarkUi({\n zoom: false,\n code: { actions: [{ id: \"run\", label: \"Run\" }] },\n github: { callouts: false, references: { repo: \"owner/name\" } },\n table: { root: \"data\" },\n include: { root: \"content\", base: \"guide\" },\n});\n```\n\n`github` takes its three plugins by name, `callouts`, `references`, and `html`, and `links` takes `external` and `anchors`. Each package's reference lists its own options. The order stays fixed whatever you pass. `include` runs first, so the others read what it pastes, and `code` and `codeNotes` run last, after every plugin that writes code blocks.\n\n## What it turns on\n\n- Every plugin except `include`, which reads files from disk. `include: { root, base }` turns it on, or `{ read }` in a browser or an edge runtime. `include: true` reads under the working directory.\n- `cast`, `table`, and `tests` get a reader that finds no file. Inline casts, CSV fences, and pasted JUnit reports render, and a `src` file doesn't load until you pass `{ root }` or `{ read }`. Any other options object replaces that reader too, so the plugin reads under the working directory.\n- Three plugins use the network while parsing: `chips` downloads favicons and avatars, `icon` fetches icon sets from the Iconify API, and `diagrams` sends each diagram's source to `https://kroki.io`. In a browser, pass `chips: { download: false }`, since a browser may not download another site's images. To parse offline, also pass `icon: { fetch: false }` with your icon sets in `collections`, and `diagrams: { draw: false }`. To keep diagram sources private, pass your own Kroki `server`.\n- `icon`'s options apply to every icon the preset draws, in cards, details, file trees, tabs, and code actions too.\n- comark-critic has no component to add its styles, so put `criticCss`, which every entry exports, in the page.\n- The text around the blocks is styled by default, scoped to the element the document renders into, on the same `--comark-*` tokens. Pass `typeset: false` when the site already styles Markdown, such as with Tailwind Typography's `prose`.\n\n## Renderers\n\n| Renderer | Entry |\n| --- | --- |\n| `@comark/html` | `comark-ui/html` |\n| `@comark/vue` | `comark-ui/vue` |\n| `@comark/react` | `comark-ui/react` |\n| `@comark/svelte` | `comark-ui/svelte` |\n\nThe Vue, React, and Svelte entries leave out annotate, comments, diff, and quiz, which render only to HTML. Screenshots, compares, diffs, suggestions and comments, and the marks on charts need `comark-ui/html`.\n\nTo use another renderer, install it in place of `@comark/html`, such as `pnpm add comark @comark/vue comark-ui`, and pass it `plugins` and `components` as you would one package's. The preset needs Vue 3.5, React 18, or Svelte 5.20 or later. Every entry exports the `PresetOptions` type, and `comark-ui` itself exports `preset(renderer, options)`, which builds the same pair from renderer entries you pass.\n\n## In the linter\n\ncomark-linter imports `comark-ui/html` when the project has it, and lints with all its plugins and components, ahead of any comark package installed on its own, so none runs twice. It calls `comarkUi()` with options of its own, so the app's options don't reach it:\n\n- It draws no chart or diagram, and downloads no chip image.\n- `::cast`, `::table`, and `::tests` read their `src` files from the working directory.\n- `include` stays off until a lint config adds it, as [include](include.md) says.\n\n## Register\n\n- In `comark-ui`: this is the preset itself, registered as Install in SKILL.md shows.\n- Alone: each plugin is its own package, registered as its reference says. The preset ships in lockstep with them, so `comark-ui@X` holds every plugin at version `X`.\n"
229
+ "text": "# Every plugin in one install\n\ncomark-ui registers every comark-ui package for one renderer, in the order they need, with one icon resolver shared by `:icon`, cards, details, file trees, tabs, and code actions. Install in SKILL.md shows its basic use. This page covers its options, what it turns on, its other renderers, and how the linter uses it.\n\n## Options\n\n`comarkUi(options)` returns `{ plugins, components }`. Each key is a package's name without `comark-`, in camelCase, such as `fileTree`, `codeNotes`, or `readingTime`. `false` turns a plugin off along with its components, and an object turns it on with those options. `true` turns on `include` and leaves the others as they are:\n\n```ts\ncomarkUi({\n zoom: false,\n code: { actions: [{ id: \"run\", label: \"Run\" }] },\n github: { callouts: false, references: { repo: \"owner/name\" } },\n table: { root: \"data\" },\n include: { root: \"content\", base: \"guide\" },\n});\n```\n\n`github` takes its three plugins by name, `callouts`, `references`, and `html`, and `links` takes `external` and `anchors`. Each package's reference lists its own options. The order stays fixed whatever you pass. `include` runs first, so the others read what it pastes, and `code` and `codeNotes` run last, after every plugin that writes code blocks.\n\n## What it turns on\n\n- Every plugin except `include`, which reads files from disk. `include: { root, base }` turns it on, or `{ read }` in a browser or an edge runtime. `include: true` reads under the working directory.\n- `cast`, `table`, and `tests` get a reader that finds no file. Inline casts, CSV fences, and pasted JUnit reports render, and a `src` file doesn't load until you pass `{ root }` or `{ read }`. Any other options object replaces that reader too, so the plugin reads under the working directory.\n- By default, three plugins use the network while parsing: `chips` downloads favicons and avatars, `icon` fetches icon sets from the Iconify API, and `diagrams` sends each diagram's source to `https://kroki.io`. In a browser, pass `chips: { download: false }`, since a browser may not download another site's images. To parse offline, also pass `icon: { fetch: false }` with your icon sets in `collections`, and `diagrams: { draw: false }`. To keep diagram sources private, pass your own Kroki `server`.\n- Media sizing reads only data URIs by default. `zoom: { size: true }` and `media: { size: true }` also fetch remote files while parsing; `annotate: { size: true }` does so at HTML render time. Enable these only for trusted documents, since requests follow redirects and can reach private networks. `{ size: false }` disables measurement for each plugin; authored dimensions and screenshot viewports still work.\n- `icon`'s options apply to every icon the preset draws, in cards, details, file trees, tabs, and code actions too.\n- comark-critic has no component to add its styles, so put `criticCss`, which every entry exports, in the page.\n- The text around the blocks is styled by default, scoped to the element the document renders into, on the same `--comark-*` tokens. Pass `typeset: false` when the site already styles Markdown, such as with Tailwind Typography's `prose`.\n\n## Renderers\n\n| Renderer | Entry |\n| --- | --- |\n| `@comark/html` | `comark-ui/html` |\n| `@comark/vue` | `comark-ui/vue` |\n| `@comark/react` | `comark-ui/react` |\n| `@comark/svelte` | `comark-ui/svelte` |\n\nThe Vue, React, and Svelte entries leave out annotate, comments, diff, and quiz, which render only to HTML. Screenshots, compares, diffs, suggestions and comments, and the marks on charts need `comark-ui/html`.\n\nTo use another renderer, install it in place of `@comark/html`, such as `pnpm add comark @comark/vue comark-ui`, and pass it `plugins` and `components` as you would one package's. The preset needs Vue 3.5, React 18, or Svelte 5.20 or later. Every entry exports the `PresetOptions` type, and `comark-ui` itself exports `preset(renderer, options)`, which builds the same pair from renderer entries you pass.\n\n## In the linter\n\ncomark-linter imports `comark-ui/html` when the project has it, and lints with all its plugins and components, ahead of any comark package installed on its own, so none runs twice. It calls `comarkUi()` with options of its own, so the app's options don't reach it:\n\n- It draws no chart or diagram, and downloads no chip image.\n- `::cast`, `::table`, and `::tests` read their `src` files from the working directory.\n- `include` stays off until a lint config adds it, as [include](include.md) says.\n\n## Register\n\n- In `comark-ui`: this is the preset itself, registered as Install in SKILL.md shows.\n- Alone: each plugin is its own package, registered as its reference says. The preset ships in lockstep with them, so `comark-ui@X` holds every plugin at version `X`.\n"
230
230
  },
231
231
  {
232
232
  "path": "references/xref.md",
@@ -234,7 +234,7 @@ const skills = [
234
234
  },
235
235
  {
236
236
  "path": "references/zoom.md",
237
- "text": "# Zoom\n\ncomark-zoom lets the reader click an image or a `::zoom` block to see it large, and closes it with Escape, Back, or a click around it. Images zoom with no markup. Wrap a table, code block, or diagram in `::zoom` when it's too small to read in place.\n\n## Syntax\n\n```md\n::zoom{title=\"Deploy retry policy\"}\n| Attempt | Wait before it |\n| --- | --- |\n| 1 | 1 s |\n| 2 | 4 s |\n| 3 | 16 s |\n::\n```\n\n- `::zoom` zooms everything inside it as one item. `title` heads the zoomed view. Items with the same `group` page through one zoomed view, with a strip of them below. `#id` and `.class` go on the block.\n- Every content image zooms on its own, with its alt text as the zoomed view's heading. It grows no larger than its file, so give a small image a larger file to open with `{data-zoom-src=\"dashboard@2x.png\"}`.\n- An image inside a link keeps its link and doesn't zoom. Images inside `::zoom`, `::carousel`, `::screenshot`, or `::compare` zoom with their block.\n- `{zoom=false}` keeps an image from zooming, and `{data-zoom}` makes any element zoom on its own.\n\ncomark-zoom reports no problems, so a misspelled prop such as `titel` is dropped silently and passes the linter. Spell `title` and `group` as written here.\n\n## Group or carousel\n\nA `group` leaves each item in its place in the text and pages through them only once one is zoomed. Use it for screenshots that sit apart, each next to the paragraph about it. A `::carousel` puts the items in one place with arrows instead. An item hidden when the view opens, such as one in a closed tab, stays out of its group.\n\n## In the page\n\nThe zoomed view fires `comark-zoom:open`, `comark-zoom:change`, and `comark-zoom:close` on the item, and they bubble. The `detail` of `open` and `change` holds the dialog's `header` and `footer`, a `layer` over the zoomed content where a host draws its own pins, and `copyOf(element)` and `originalOf(element)` to map between the page and the zoomed copy. `data-zoom-aside`, a selector, shows a caption beside the zoomed item at its own size, as annotate does with a screenshot's notes.\n\n## Register\n\n- In `comark-ui`: on, as `zoom`. `zoom: { images: false }` leaves images alone, so only `::zoom` blocks and elements marked `{data-zoom}` zoom.\n- Alone: `pnpm add comark @comark/html comark-zoom`, then `createHtmlRenderer({ plugins: [zoom()], components })` with both from `comark-zoom/html`. `comark-zoom/vue`, `/react`, and `/svelte` export the same pair for those renderers. The plugin adds a node that starts the script, so pass the components even when only images zoom. A page with no renderer calls `start()` from `comark-zoom/client` once. comark-annotate and comark-carousel zoom their own blocks without it, so register `zoom()` for images and `::zoom`.\n"
237
+ "text": "# Zoom\n\ncomark-zoom lets the reader click an image or a `::zoom` block to see it large, and closes it with Escape, Back, or a click around it. Images zoom with no markup. Wrap a table, code block, or diagram in `::zoom` when it's too small to read in place.\n\n## Syntax\n\n```md\n::zoom{title=\"Deploy retry policy\"}\n| Attempt | Wait before it |\n| --- | --- |\n| 1 | 1 s |\n| 2 | 4 s |\n| 3 | 16 s |\n::\n```\n\n- `::zoom` zooms everything inside it as one item. `title` heads the zoomed view. Items with the same `group` page through one zoomed view, with a strip of them below. `#id` and `.class` go on the block.\n- Every content image zooms on its own, with its alt text as the zoomed view's heading. It grows no larger than its file, so give a small image a larger file to open with `{data-zoom-src=\"dashboard@2x.png\"}`.\n- An image inside a link keeps its link and doesn't zoom. Images inside `::zoom`, `::carousel`, `::screenshot`, or `::compare` zoom with their block.\n- `{zoom=false}` keeps an image from zooming, and `{data-zoom}` makes any element zoom on its own.\n\ncomark-zoom reports no problems, so a misspelled prop such as `titel` is dropped silently and passes the linter. Spell `title` and `group` as written here.\n\n## Group or carousel\n\nA `group` leaves each item in its place in the text and pages through them only once one is zoomed. Use it for screenshots that sit apart, each next to the paragraph about it. A `::carousel` puts the items in one place with arrows instead. An item hidden when the view opens, such as one in a closed tab, stays out of its group.\n\n## In the page\n\nThe zoomed view fires `comark-zoom:open`, `comark-zoom:change`, and `comark-zoom:close` on the item, and they bubble. The `detail` of `open` and `change` holds the dialog's `header` and `footer`, a `layer` over the zoomed content where a host draws its own pins, and `copyOf(element)` and `originalOf(element)` to map between the page and the zoomed copy. `data-zoom-aside`, a selector, shows a caption beside the zoomed item at its own size, as annotate does with a screenshot's notes.\n\n## Register\n\n- In `comark-ui`: on, as `zoom`. `zoom: { images: false }` leaves images alone, so only `::zoom` blocks and elements marked `{data-zoom}` zoom. Data URI images get dimensions by default; one authored pixel side gets the other at the file's ratio. Images with both sides or a side such as `50%` keep them. `zoom: { size: true }` also measures remote images while parsing; use it only for trusted documents, since requests follow redirects and can reach private networks. `zoom: { size: false }` disables measurement. Alone, pass the same options to `zoom()`.\n- Alone: `pnpm add comark @comark/html comark-zoom`, then `createHtmlRenderer({ plugins: [zoom()], components })` with both from `comark-zoom/html`. `comark-zoom/vue`, `/react`, and `/svelte` export the same pair for those renderers. The plugin adds a node that starts the script, so pass the components even when only images zoom. A page with no renderer calls `start()` from `comark-zoom/client` once. comark-annotate and comark-carousel zoom their own blocks without it, so register `zoom()` for images and `::zoom`.\n"
238
238
  }
239
239
  ]
240
240
  },
@@ -249,7 +249,7 @@ const skills = [
249
249
  "files": [
250
250
  {
251
251
  "path": "SKILL.md",
252
- "text": "---\nname: review-document\ndescription: Turns a review's findings into one short Markdown document a reader can act on, with the verdict first and each finding ranked, located, backed by evidence, and paired with its fix. Use when writing up a code review, a design or QA review, an audit, or any report whose reader must decide what to do next.\nlicense: MIT\n---\n\n# Review document\n\nA review's reader has one question: what do I do now? Answer it in the first two lines, then give each finding just enough evidence that the reader trusts it without redoing your work. This skill organizes findings you already have; finding them is the review itself.\n\nLength is the usual failure. A reader who has to dig through praise, process, and restated findings misses the one that blocks the merge. Every line below the verdict either supports a finding or says what you didn't check.\n\n## 1. Decide the verdict\n\nPick one: **approve**, **approve with changes**, **request changes**, or **blocked** on a named thing. Under it, write the reason in one sentence that names the finding behind it.\n\nDone when someone who reads only the verdict knows what to do.\n\n## 2. Keep the findings that change the decision\n\n- Keep a finding when fixing it, or not, changes what the reader should do.\n- Merge findings with one root cause into one, and list every place it appears.\n- Rank each one: **blocking** (wrong results, lost data, a security hole, broken for users), **should fix** (a real cost that can wait), or **nit**, only when the reader asked for them.\n\nOrder them blocking first. Done when every finding has a rank and no two share a cause.\n\n## 3. Back each finding\n\nEach finding is four parts, in this order:\n\n1. **A title that states the consequence**, for whom: \"Small avatars load the 512px image\", not \"Cache key issue\".\n2. **Where**: the file and line, linked when there's a URL.\n3. **Evidence**, the strongest you have: a failing test or command you ran (`::tests`, a fenced block of output), a screenshot of the wrong state (measured as the before-after-evidence skill describes), the lines that cause it (a fence with the line highlighted), then reasoning. Say which it is: a finding you reproduced reads differently from one you read in the code.\n4. **The fix**: a `::diff` of the smallest change, or one sentence when the fix is a decision for the reader.\n\nDone when every blocking finding has evidence you ran or captured, or says plainly that it comes from reading the code.\n\n## 4. Say what you checked\n\nEnd with two short lists: what you checked and how, and what you didn't check. A review that implies more coverage than it had loses the reader's trust in the parts that were real.\n\n## 5. Write it\n\nFollow [references/example.md](references/example.md):\n\n- The verdict in a callout: `> [!CAUTION]` for request changes or blocked, `> [!WARNING]` for approve with changes, `> [!TIP]` for approve.\n- One `##` heading per finding, numbered, with its rank in the heading. About a dozen lines each, evidence included.\n- No summary that repeats the findings, no section for an empty rank, no list of what's good unless the reader asked.\n\n[references/blocks.md](references/blocks.md) has the syntax for the callout, `::tests`, `::diff`, and highlighted lines.\n\n## 6. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui lint-comark review.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read and read it top to bottom as the reader would. Each finding's evidence should be visible without expanding anything except a long log, and each `::diff` should start at the line its finding names.\n\nDone when the page renders without problems and you've read it once as the reader.\n"
252
+ "text": "---\nname: review-document\ndescription: Turns a review's findings into one short Markdown document a reader can act on, with the verdict first and each finding ranked, located, backed by evidence, and paired with its fix. Use when writing up a code review, a design or QA review, an audit, or any report whose reader must decide what to do next.\nlicense: MIT\n---\n\n# Review document\n\nA review's reader has one question: what do I do now? Answer it in the first two lines, then give each finding just enough evidence that the reader trusts it without redoing your work. This skill organizes findings you already have; finding them is the review itself.\n\nLength is the usual failure. A reader who has to dig through praise, process, and restated findings misses the one that blocks the merge. Every line below the verdict either supports a finding or says what you didn't check.\n\n## 1. Decide the verdict\n\nPick one: **approve**, **approve with changes**, **request changes**, or **blocked** on a named thing. Under it, write the reason in one sentence that names the finding behind it.\n\nDone when someone who reads only the verdict knows what to do.\n\n## 2. Keep the findings that change the decision\n\n- Keep a finding when fixing it, or not, changes what the reader should do.\n- Merge findings with one root cause into one, and list every place it appears.\n- Rank each one: **blocking** (wrong results, lost data, a security hole, broken for users), **should fix** (a real cost that can wait), or **nit**, only when the reader asked for them.\n\nOrder them blocking first. Done when every finding has a rank and no two share a cause.\n\n## 3. Back each finding\n\nEach finding is four parts, in this order:\n\n1. **A title that states the consequence**, for whom: \"Small avatars load the 512px image\", not \"Cache key issue\".\n2. **Where**: the file and line, linked when there's a URL.\n3. **Evidence**, the strongest you have: a failing test or command you ran (`::tests`, a fenced block of output), a screenshot of the wrong state (measured as the before-after-evidence skill describes), the lines that cause it (a fence with the line highlighted), then reasoning. Say which it is: a finding you reproduced reads differently from one you read in the code.\n4. **The fix**: a `::diff` of the smallest change, or one sentence when the fix is a decision for the reader.\n\nDone when every blocking finding has evidence you ran or captured, or says plainly that it comes from reading the code.\n\n## 4. Say what you checked\n\nEnd with two short lists: what you checked and how, and what you didn't check. A review that implies more coverage than it had loses the reader's trust in the parts that were real.\n\n## 5. Write it\n\nFollow [references/example.md](references/example.md):\n\n- The verdict in a callout: `> [!CAUTION]` for request changes or blocked, `> [!WARNING]` for approve with changes, `> [!TIP]` for approve.\n- One `##` heading per finding, numbered, with its rank in the heading. About a dozen lines each, evidence included.\n- No summary that repeats the findings, no section for an empty rank, no list of what's good unless the reader asked.\n\n[references/blocks.md](references/blocks.md) has the syntax for the callout, `::tests`, `::diff`, and highlighted lines.\n\n## 6. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint review.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read and read it top to bottom as the reader would. Each finding's evidence should be visible without expanding anything except a long log, and each `::diff` should start at the line its finding names.\n\nDone when the page renders without problems and you've read it once as the reader.\n"
253
253
  },
254
254
  {
255
255
  "path": "agents/openai.yaml",
@@ -276,7 +276,7 @@ const skills = [
276
276
  "files": [
277
277
  {
278
278
  "path": "SKILL.md",
279
- "text": "---\nname: teach-lesson\ndescription: Write a short lesson on one concept, with simplified English, a worked example, and an application question. Use for a lesson, a self-check, or onboarding on one idea.\nlicense: MIT\n---\n\n# Teach lesson\n\nA lesson teaches one concept through a worked example and an application question. Keep it short enough to finish in five minutes.\n\n## 1. Pin the concept and the outcome\n\nInfer the reader's purpose and existing knowledge from the conversation. Focus on the gap their question reveals.\n\nName one concept and write a testable outcome, such as \"Predict what happens when two people save the same record.\" Use a verb such as predict, explain, choose, or spot.\n\nIf the outcome depends on another concept, link to its prerequisite lesson or teach that prerequisite first.\n\nDone when one sentence names the action the reader will perform and the situation they will apply it to.\n\n## 2. Find a worked example\n\nPick a case from the reader's world where the concept prevents a visible failure. Trace it in three or four moves with concrete names, status codes, or numbers. Label invented values as illustrative.\n\nVerify behavior against a primary source, such as code or a specification. For an existing design, find recorded reasons when available. Distinguish verified behavior, recorded reasons, and inferred reasons. Preserve uncertainty such as \"likely\", and say when a reason is unknown.\n\nDone when each move has a concrete value, its behavior matches the source, and each design reason is sourced or qualified.\n\n## 3. Write the lesson\n\nRead [references/example.md](references/example.md) as a model for the complete lesson. Write these parts in order:\n\n1. **The outcome**, one sentence under the title.\n2. **Why it matters**: the failure the concept prevents, told as the worked example's problem. Three or four sentences.\n3. **The idea**: give the smallest complete explanation in at most four sentences. Start with a plain definition, connect it to the reader's case, and explain how it solves the problem.\n4. **The worked example**: add the supporting detail, one move per step, showing the value that changed. For text and code, use [`::steps`](references/blocks.md#the-worked-example-steps). When diagrams help explain interacting parts, use the [diagram series guidance](references/blocks.md#build-a-diagram-across-steps).\n5. **The check**, below.\n6. **Read next**: one primary source, linked to the exact section, and the lesson that naturally follows.\n\n### Use STE 100 writing rules\n\nApply [ASD-STE100 Simplified Technical English](https://asd-ste100.org/) writing rules to the whole lesson, including the example, question, hints, and answer explanations.\n\n- Give each sentence one idea. Give each instruction one action.\n- Keep instructions within 20 words and descriptive sentences within 25 words. Use short paragraphs.\n- Use common words and active voice. Write instructions as direct commands.\n- Define each technical term in bold at first use. Use one term for each concept and keep its meaning consistent.\n- Keep technical names, code, units, and UI labels exact.\n- Put a condition before the action it controls. Make each pronoun refer to one clear subject.\n- Use literal wording and explain abbreviations. Split long noun groups into phrases.\n- State the mechanism directly, with the detail needed to follow it.\n\nDone when the outcome, problem, idea, worked example, and source link are present. Each term must have a definition before use, and each sentence must meet the applicable word limit. Preserve the example's behavior and evidence confidence.\n\n## 4. Write the check\n\nUse [`::question`](references/blocks.md#the-check-question) to test the outcome. Change one input of the worked example and ask the reader to predict, explain, choose, or spot the result.\n\n- Make each wrong option a real misconception, and give it a `>` rationale that says why it's tempting and why it's wrong.\n- Keep the options parallel, one idea each and close in length, so their shape gives no clue to the answer.\n- Add `#explain` for the one thing the reader should take away whatever they picked.\n- For a fact worth remembering a week later, optionally add a [`::recall` card](references/blocks.md#the-fact-to-keep-recall).\n\nDone when the question tests the stated outcome with one changed input, every option has a rationale, and the shared explanation resolves each misconception.\n\n## 5. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui lint-comark lesson.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read. Select each option and check its rationale and the shared explanation.\n\nDone when lint reports no problems, every worked step and diagram is visible, and each option reveals the expected result and rationale. Confirm that the correct answer follows from the example and that the lesson fits a five-minute read.\n"
279
+ "text": "---\nname: teach-lesson\ndescription: Write a short lesson on one concept, with simplified English, a worked example, and an application question. Use for a lesson, a self-check, or onboarding on one idea.\nlicense: MIT\n---\n\n# Teach lesson\n\nA lesson teaches one concept through a worked example and an application question. Keep it short enough to finish in five minutes.\n\n## 1. Pin the concept and the outcome\n\nInfer the reader's purpose and existing knowledge from the conversation. Focus on the gap their question reveals.\n\nName one concept and write a testable outcome, such as \"Predict what happens when two people save the same record.\" Use a verb such as predict, explain, choose, or spot.\n\nIf the outcome depends on another concept, link to its prerequisite lesson or teach that prerequisite first.\n\nDone when one sentence names the action the reader will perform and the situation they will apply it to.\n\n## 2. Find a worked example\n\nPick a case from the reader's world where the concept prevents a visible failure. Trace it in three or four moves with concrete names, status codes, or numbers. Label invented values as illustrative.\n\nVerify behavior against a primary source, such as code or a specification. For an existing design, find recorded reasons when available. Distinguish verified behavior, recorded reasons, and inferred reasons. Preserve uncertainty such as \"likely\", and say when a reason is unknown.\n\nDone when each move has a concrete value, its behavior matches the source, and each design reason is sourced or qualified.\n\n## 3. Write the lesson\n\nRead [references/example.md](references/example.md) as a model for the complete lesson. Write these parts in order:\n\n1. **The outcome**, one sentence under the title.\n2. **Why it matters**: the failure the concept prevents, told as the worked example's problem. Three or four sentences.\n3. **The idea**: give the smallest complete explanation in at most four sentences. Start with a plain definition, connect it to the reader's case, and explain how it solves the problem.\n4. **The worked example**: add the supporting detail, one move per step, showing the value that changed. For text and code, use [`::steps`](references/blocks.md#the-worked-example-steps). When diagrams help explain interacting parts, use the [diagram series guidance](references/blocks.md#build-a-diagram-across-steps).\n5. **The check**, below.\n6. **Read next**: one primary source, linked to the exact section, and the lesson that naturally follows.\n\n### Use STE 100 writing rules\n\nApply [ASD-STE100 Simplified Technical English](https://asd-ste100.org/) writing rules to the whole lesson, including the example, question, hints, and answer explanations.\n\n- Give each sentence one idea. Give each instruction one action.\n- Keep instructions within 20 words and descriptive sentences within 25 words. Use short paragraphs.\n- Use common words and active voice. Write instructions as direct commands.\n- Define each technical term in bold at first use. Use one term for each concept and keep its meaning consistent.\n- Keep technical names, code, units, and UI labels exact.\n- Put a condition before the action it controls. Make each pronoun refer to one clear subject.\n- Use literal wording and explain abbreviations. Split long noun groups into phrases.\n- State the mechanism directly, with the detail needed to follow it.\n\nDone when the outcome, problem, idea, worked example, and source link are present. Each term must have a definition before use, and each sentence must meet the applicable word limit. Preserve the example's behavior and evidence confidence.\n\n## 4. Write the check\n\nUse [`::question`](references/blocks.md#the-check-question) to test the outcome. Change one input of the worked example and ask the reader to predict, explain, choose, or spot the result.\n\n- Make each wrong option a real misconception, and give it a `>` rationale that says why it's tempting and why it's wrong.\n- Keep the options parallel, one idea each and close in length, so their shape gives no clue to the answer.\n- Add `#explain` for the one thing the reader should take away whatever they picked.\n- For a fact worth remembering a week later, optionally add a [`::recall` card](references/blocks.md#the-fact-to-keep-recall).\n\nDone when the question tests the stated outcome with one changed input, every option has a rationale, and the shared explanation resolves each misconception.\n\n## 5. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint lesson.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read. Select each option and check its rationale and the shared explanation.\n\nDone when lint reports no problems, every worked step and diagram is visible, and each option reveals the expected result and rationale. Confirm that the correct answer follows from the example and that the lesson fits a five-minute read.\n"
280
280
  },
281
281
  {
282
282
  "path": "agents/openai.yaml",
@@ -303,7 +303,7 @@ const skills = [
303
303
  "files": [
304
304
  {
305
305
  "path": "SKILL.md",
306
- "text": "---\nname: visual-explanation\ndescription: Explains how something works with the smallest visual that answers the question, such as a sequence diagram, a call tree, a file tree, or a marked-up screenshot, placed beside the sentence it supports. Use when someone asks to be shown how a system, a flow, or a change works, or when the answer would otherwise take paragraphs of prose.\nlicense: MIT\n---\n\n# Visual explanation\n\nA good explanation answers one question with one picture the reader can check against the code. Prose carries the reasoning, and the visual carries the shape: what happens in what order, what calls what, what lives where. Each visual stands next to the sentence that tells the reader what to look for.\n\n## 1. Name the question\n\nWrite the question in one sentence, in the reader's words: \"What happens between `parseMarkdown` and the HTML?\" If it's two questions, answer the one they asked and offer the other.\n\nDone when the question fits on one line.\n\n## 2. Pick the view\n\nChoose by the shape of the answer:\n\n| The answer is… | Draw |\n| --- | --- |\n| The order of events between parts | A `mermaid` sequence diagram or flowchart |\n| Who calls whom | A call tree in a `text` fence, indented by call depth |\n| Where code lives, or which files a change touches | `::file-tree`, with `+`, `-`, and `~` marks |\n| The states something moves between | A `mermaid` `stateDiagram-v2` |\n| Something on screen | `::screenshot` with measured marks |\n| What a few lines do, line by line | A code fence with `// <1>` notes |\n| How a number changed | `::chart` or a two-row table |\n\nUse one primary view. Add a second only when it answers the question the first one raises, such as \"where is that in my code?\" after a flow diagram. [references/blocks.md](references/blocks.md) has the syntax of each.\n\nDone when you can say, in one sentence, what the reader will see in the view.\n\n## 3. Draw it from the source\n\nRead the code, the product, or the data before you draw. Every box, arrow, file, and label in the view is something the reader can find: a real function name, a real file path, a state the code really has. Leave out the parts that don't bear on the question; a diagram of everything answers nothing.\n\nKeep a diagram to about eight nodes or participants. Past that, split it by stage or zoom into the part the question is about.\n\nDone when every label in the view exists in the source, and nothing in it is there only for completeness.\n\n## 4. Write around it\n\n[references/example.md](references/example.md) shows the shape:\n\n1. A title that is the question, or its answer.\n2. Two or three sentences with the answer in plain words, ending on what to look at in the view.\n3. The view.\n4. One or two sentences for what the view can't show, such as a rule that applies at every step.\n5. A second view only if step 2 allowed one, with a sentence before it saying why it's there.\n\nDone when the explanation reads top to bottom in under a minute and every visual has a sentence beside it.\n\n## 5. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui lint-comark explanation.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read and look at each view at the width the reader has. A diagram whose labels are too small to read needs fewer nodes, not a wider page.\n\nDone when you've looked at the render and every label reads at its size.\n"
306
+ "text": "---\nname: visual-explanation\ndescription: Explains how something works with the smallest visual that answers the question, such as a sequence diagram, a call tree, a file tree, or a marked-up screenshot, placed beside the sentence it supports. Use when someone asks to be shown how a system, a flow, or a change works, or when the answer would otherwise take paragraphs of prose.\nlicense: MIT\n---\n\n# Visual explanation\n\nA good explanation answers one question with one picture the reader can check against the code. Prose carries the reasoning, and the visual carries the shape: what happens in what order, what calls what, what lives where. Each visual stands next to the sentence that tells the reader what to look for.\n\n## 1. Name the question\n\nWrite the question in one sentence, in the reader's words: \"What happens between `parseMarkdown` and the HTML?\" If it's two questions, answer the one they asked and offer the other.\n\nDone when the question fits on one line.\n\n## 2. Pick the view\n\nChoose by the shape of the answer:\n\n| The answer is… | Draw |\n| --- | --- |\n| The order of events between parts | A `mermaid` sequence diagram or flowchart |\n| Who calls whom | A call tree in a `text` fence, indented by call depth |\n| Where code lives, or which files a change touches | `::file-tree`, with `+`, `-`, and `~` marks |\n| The states something moves between | A `mermaid` `stateDiagram-v2` |\n| Something on screen | `::screenshot` with measured marks |\n| What a few lines do, line by line | A code fence with `// <1>` notes |\n| How a number changed | `::chart` or a two-row table |\n\nUse one primary view. Add a second only when it answers the question the first one raises, such as \"where is that in my code?\" after a flow diagram. [references/blocks.md](references/blocks.md) has the syntax of each.\n\nDone when you can say, in one sentence, what the reader will see in the view.\n\n## 3. Draw it from the source\n\nRead the code, the product, or the data before you draw. Every box, arrow, file, and label in the view is something the reader can find: a real function name, a real file path, a state the code really has. Leave out the parts that don't bear on the question; a diagram of everything answers nothing.\n\nKeep a diagram to about eight nodes or participants. Past that, split it by stage or zoom into the part the question is about.\n\nDone when every label in the view exists in the source, and nothing in it is there only for completeness.\n\n## 4. Write around it\n\n[references/example.md](references/example.md) shows the shape:\n\n1. A title that is the question, or its answer.\n2. Two or three sentences with the answer in plain words, ending on what to look at in the view.\n3. The view.\n4. One or two sentences for what the view can't show, such as a rule that applies at every step.\n5. A second view only if step 2 allowed one, with a sentence before it saying why it's there.\n\nDone when the explanation reads top to bottom in under a minute and every visual has a sentence beside it.\n\n## 5. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint explanation.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the rendered page where it will be read and look at each view at the width the reader has. A diagram whose labels are too small to read needs fewer nodes, not a wider page.\n\nDone when you've looked at the render and every label reads at its size.\n"
307
307
  },
308
308
  {
309
309
  "path": "agents/openai.yaml",
@@ -321,6 +321,6 @@ const skills = [
321
321
  }
322
322
  ];
323
323
  /** The comark-ui version the skills come from, for a host's cache key or a digest. */
324
- const version = "0.7.4";
324
+ const version = "0.7.6";
325
325
  //#endregion
326
326
  export { skills, version };
package/dist/vue.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as criticCss, n as Preset, r as PresetOptions } from "./index-BUDHsvnm.mjs";
1
+ import { a as criticCss, n as Preset, r as PresetOptions } from "./index-Dbqxt4Qg.mjs";
2
2
  import { Component } from "vue";
3
3
  //#region src/vue.d.ts
4
4
  /** Every plugin with components for `@comark/vue`, which leaves out annotate, comments, diff, and quiz. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comark-ui",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "Every comark-ui block in one install: annotated screenshots, charts, diffs, tabs, zoom, and more, registered in the order they need with shared icons. Turn any of them off or pass its options.",
5
5
  "keywords": [
6
6
  "comark",
@@ -48,50 +48,50 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "comark-pele": "^1.1.0",
51
- "comark-annotate": "^0.7.4",
52
- "comark-cards": "^0.7.4",
53
- "comark-carousel": "^0.7.4",
54
- "comark-badge": "^0.7.4",
55
- "comark-cast": "^0.7.4",
56
- "comark-charts": "^0.7.4",
57
- "comark-chips": "^0.7.4",
58
- "comark-cjk": "^0.7.4",
59
- "comark-code": "^0.7.4",
60
- "comark-colors": "^0.7.4",
61
- "comark-code-notes": "^0.7.4",
62
- "comark-deflist": "^0.7.4",
63
- "comark-critic": "^0.7.4",
64
- "comark-details": "^0.7.4",
65
- "comark-comments": "^0.7.4",
66
- "comark-diagrams": "^0.7.4",
67
- "comark-embed": "^0.7.4",
68
- "comark-fields": "^0.7.4",
69
- "comark-figure": "^0.7.4",
70
- "comark-diff": "^0.7.4",
71
- "comark-file-tree": "^0.7.4",
72
- "comark-footnotes": "^0.7.4",
73
- "comark-github": "^0.7.4",
74
- "comark-keys": "^0.7.4",
75
- "comark-include": "^0.7.4",
76
- "comark-icon": "^0.7.4",
77
- "comark-mathml": "^0.7.4",
78
- "comark-mark": "^0.7.4",
79
- "comark-magic-move": "^0.7.4",
80
- "comark-links": "^0.7.4",
81
- "comark-media": "^0.7.4",
82
- "comark-metrics": "^0.7.4",
83
- "comark-outline": "^0.7.4",
84
- "comark-properties": "^0.7.4",
85
- "comark-sources": "^0.7.4",
86
- "comark-quiz": "^0.7.4",
87
- "comark-qr": "^0.7.4",
88
- "comark-table": "^0.7.4",
89
- "comark-steps": "^0.7.4",
90
- "comark-reading-time": "^0.7.4",
91
- "comark-tabs": "^0.7.4",
92
- "comark-xref": "^0.7.4",
93
- "comark-tests": "^0.7.4",
94
- "comark-zoom": "^0.7.4"
51
+ "comark-annotate": "^0.7.6",
52
+ "comark-badge": "^0.7.6",
53
+ "comark-carousel": "^0.7.6",
54
+ "comark-cast": "^0.7.6",
55
+ "comark-charts": "^0.7.6",
56
+ "comark-cards": "^0.7.6",
57
+ "comark-code": "^0.7.6",
58
+ "comark-code-notes": "^0.7.6",
59
+ "comark-colors": "^0.7.6",
60
+ "comark-comments": "^0.7.6",
61
+ "comark-critic": "^0.7.6",
62
+ "comark-chips": "^0.7.6",
63
+ "comark-deflist": "^0.7.6",
64
+ "comark-cjk": "^0.7.6",
65
+ "comark-details": "^0.7.6",
66
+ "comark-diagrams": "^0.7.6",
67
+ "comark-diff": "^0.7.6",
68
+ "comark-embed": "^0.7.6",
69
+ "comark-fields": "^0.7.6",
70
+ "comark-figure": "^0.7.6",
71
+ "comark-github": "^0.7.6",
72
+ "comark-icon": "^0.7.6",
73
+ "comark-file-tree": "^0.7.6",
74
+ "comark-footnotes": "^0.7.6",
75
+ "comark-links": "^0.7.6",
76
+ "comark-magic-move": "^0.7.6",
77
+ "comark-keys": "^0.7.6",
78
+ "comark-mathml": "^0.7.6",
79
+ "comark-mark": "^0.7.6",
80
+ "comark-media": "^0.7.6",
81
+ "comark-metrics": "^0.7.6",
82
+ "comark-outline": "^0.7.6",
83
+ "comark-include": "^0.7.6",
84
+ "comark-qr": "^0.7.6",
85
+ "comark-properties": "^0.7.6",
86
+ "comark-quiz": "^0.7.6",
87
+ "comark-reading-time": "^0.7.6",
88
+ "comark-sources": "^0.7.6",
89
+ "comark-steps": "^0.7.6",
90
+ "comark-table": "^0.7.6",
91
+ "comark-tests": "^0.7.6",
92
+ "comark-tabs": "^0.7.6",
93
+ "comark-xref": "^0.7.6",
94
+ "comark-zoom": "^0.7.6"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@comark/html": "^0.8.1",