comark-ui 0.7.2 → 0.7.5

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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/{editor-BAdok66p.mjs → editor-DmxNPK7K.mjs} +522 -68
  3. package/dist/{editor-CNivEuMH.d.mts → editor-KD97dL_1.d.mts} +21 -3
  4. package/dist/editor-vue.d.mts +1 -1
  5. package/dist/editor-vue.mjs +1 -1
  6. package/dist/editor.d.mts +2 -2
  7. package/dist/editor.mjs +1 -1
  8. package/dist/html.d.mts +1 -1
  9. package/dist/html.mjs +3 -1
  10. package/dist/{index-jkwx6SyG.d.mts → index-Dbqxt4Qg.d.mts} +10 -2
  11. package/dist/index.d.mts +1 -1
  12. package/dist/index.mjs +1 -1
  13. package/dist/react.d.mts +2 -2
  14. package/dist/react.mjs +2 -2
  15. package/dist/skills/before-after-evidence/SKILL.md +72 -0
  16. package/dist/skills/before-after-evidence/agents/openai.yaml +3 -0
  17. package/dist/skills/before-after-evidence/references/blocks.md +54 -0
  18. package/dist/skills/before-after-evidence/references/example.md +37 -0
  19. package/dist/skills/before-after-evidence/references/measuring.md +50 -0
  20. package/dist/skills/comark-ui/SKILL.md +8 -1
  21. package/dist/skills/comark-ui/references/annotate.md +5 -3
  22. package/dist/skills/comark-ui/references/comments.md +43 -0
  23. package/dist/skills/comark-ui/references/lint.md +1 -1
  24. package/dist/skills/comark-ui/references/media.md +2 -2
  25. package/dist/skills/comark-ui/references/quiz.md +1 -1
  26. package/dist/skills/comark-ui/references/ui.md +3 -2
  27. package/dist/skills/comark-ui/references/zoom.md +1 -1
  28. package/dist/skills/review-document/SKILL.md +64 -0
  29. package/dist/skills/review-document/agents/openai.yaml +3 -0
  30. package/dist/skills/review-document/references/blocks.md +69 -0
  31. package/dist/skills/review-document/references/example.md +51 -0
  32. package/dist/skills/teach-lesson/SKILL.md +78 -0
  33. package/dist/skills/teach-lesson/agents/openai.yaml +3 -0
  34. package/dist/skills/teach-lesson/references/blocks.md +91 -0
  35. package/dist/skills/teach-lesson/references/example.md +70 -0
  36. package/dist/skills/visual-explanation/SKILL.md +67 -0
  37. package/dist/skills/visual-explanation/agents/openai.yaml +3 -0
  38. package/dist/skills/visual-explanation/references/blocks.md +89 -0
  39. package/dist/skills/visual-explanation/references/example.md +25 -0
  40. package/dist/skills.d.mts +18 -0
  41. package/dist/skills.mjs +326 -0
  42. package/dist/{src-DROB05U6.mjs → src-PkmYCSNu.mjs} +1 -0
  43. package/dist/svelte/index.d.ts +1 -1
  44. package/dist/svelte/index.js +1 -1
  45. package/dist/vue.d.mts +2 -2
  46. package/dist/vue.mjs +2 -2
  47. package/package.json +46 -44
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: review-document
3
+ description: 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.
4
+ license: MIT
5
+ ---
6
+
7
+ # Review document
8
+
9
+ A 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.
10
+
11
+ Length 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.
12
+
13
+ ## 1. Decide the verdict
14
+
15
+ Pick 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.
16
+
17
+ Done when someone who reads only the verdict knows what to do.
18
+
19
+ ## 2. Keep the findings that change the decision
20
+
21
+ - Keep a finding when fixing it, or not, changes what the reader should do.
22
+ - Merge findings with one root cause into one, and list every place it appears.
23
+ - 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.
24
+
25
+ Order them blocking first. Done when every finding has a rank and no two share a cause.
26
+
27
+ ## 3. Back each finding
28
+
29
+ Each finding is four parts, in this order:
30
+
31
+ 1. **A title that states the consequence**, for whom: "Small avatars load the 512px image", not "Cache key issue".
32
+ 2. **Where**: the file and line, linked when there's a URL.
33
+ 3. **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.
34
+ 4. **The fix**: a `::diff` of the smallest change, or one sentence when the fix is a decision for the reader.
35
+
36
+ Done when every blocking finding has evidence you ran or captured, or says plainly that it comes from reading the code.
37
+
38
+ ## 4. Say what you checked
39
+
40
+ End 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.
41
+
42
+ ## 5. Write it
43
+
44
+ Follow [references/example.md](references/example.md):
45
+
46
+ - The verdict in a callout: `> [!CAUTION]` for request changes or blocked, `> [!WARNING]` for approve with changes, `> [!TIP]` for approve.
47
+ - One `##` heading per finding, numbered, with its rank in the heading. About a dozen lines each, evidence included.
48
+ - No summary that repeats the findings, no section for an empty rank, no list of what's good unless the reader asked.
49
+
50
+ [references/blocks.md](references/blocks.md) has the syntax for the callout, `::tests`, `::diff`, and highlighted lines.
51
+
52
+ ## 6. Check the render
53
+
54
+ 1. Lint it, and fix until it reports no problems:
55
+
56
+ ```sh
57
+ vp dlx --package comark-linter --package comark-ui lint-comark review.md
58
+ ```
59
+
60
+ These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
61
+
62
+ 2. 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.
63
+
64
+ Done when the page renders without problems and you've read it once as the reader.
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "Review document"
3
+ short_description: "Write findings as a verdict, evidence, and fixes"
@@ -0,0 +1,69 @@
1
+ # Blocks for a review document
2
+
3
+ These blocks come with `comark-ui`, or alone with `comark-github`, `comark-tests`, `comark-diff`, and `comark-code`. The comark-ui skill (`vp dlx skills add onmax/comark-ui`) documents every block in full.
4
+
5
+ ## The verdict: a callout
6
+
7
+ ```md
8
+ > [!CAUTION] Request changes
9
+ > One blocking finding: after a large avatar loads, every smaller one shows the large image.
10
+ ```
11
+
12
+ The text after the marker is the title. `[!CAUTION]` fits request changes or blocked, `[!WARNING]` approve with changes, `[!TIP]` approve, and `[!NOTE]` context the reader needs before the findings. Any other marker stays a plain quote and is reported.
13
+
14
+ ## A test run: `::tests`
15
+
16
+ Paste the JUnit XML the runner wrote, unedited, so the counts are the run's own:
17
+
18
+ ````md
19
+ ::tests{title="pnpm test src/avatars"}
20
+ ```xml
21
+ <testsuite name="cache.test.ts" time="0.18">
22
+ <testcase classname="cache.test.ts" name="returns a cached avatar"/>
23
+ <testcase classname="cache.test.ts" name="returns a 32px avatar after a 512px one">
24
+ <failure message="expected 512 to be 32">AssertionError: expected 512 to be 32</failure>
25
+ </testcase>
26
+ </testsuite>
27
+ ```
28
+ ::
29
+ ````
30
+
31
+ It shows the passed, failed, and skipped counts and each failure's message and stack. Most runners write the report with a flag: `vitest run --reporter=junit --outputFile=junit.xml`, `pytest --junitxml=junit.xml`, `jest --reporters=jest-junit`. For a command that isn't a test run, paste its output in a `txt` or `sh` fence instead.
32
+
33
+ ## The lines that cause it: a fence with `mark`
34
+
35
+ ````md
36
+ ```ts [src/avatars/cache.ts] mark={1}
37
+ const cache = new Map<string, Blob>();
38
+ ```
39
+ ````
40
+
41
+ `mark={1}` highlights the block's first line; ranges look like `{3-4}` or `{1, 3-4}`. Copy a few lines from the file, the ones your text names.
42
+
43
+ ## The fix: `::diff`
44
+
45
+ ````md
46
+ ::diff{line=18 label="Fix"}
47
+ ```ts [src/avatars/cache.ts]
48
+ const key = user.id;
49
+ ```
50
+ ```ts
51
+ const key = `${user.id}:${size}`;
52
+ ```
53
+ ::
54
+ ````
55
+
56
+ Two fenced blocks, before then after, starting at the file's line `line`. One file per diff, a few lines each.
57
+
58
+ ## A long log: `<details>`
59
+
60
+ ```md
61
+ <details>
62
+ <summary>Full test output</summary>
63
+
64
+ …
65
+
66
+ </details>
67
+ ```
68
+
69
+ Fold away anything the reader may skip, such as a full log under the failure that matters.
@@ -0,0 +1,51 @@
1
+ # Review: avatar cache
2
+
3
+ > [!CAUTION] Request changes
4
+ > One blocking finding: after a large avatar loads, every smaller one on the page shows the large image. The fix is one line.
5
+
6
+ Reviewed [acme/web#418](https://github.com/acme/web/pull/418) at `9f3c2e1`.
7
+
8
+ ## 1. Small avatars load the 512px image (blocking)
9
+
10
+ `src/avatars/cache.ts:18`. The cache key is the user's id alone, so once the profile header loads someone's 512px avatar, the 32px avatars in comments get the same file. Reproduced with a test:
11
+
12
+ ::tests{title="pnpm test src/avatars"}
13
+ ```xml
14
+ <testsuite name="cache.test.ts" time="0.18">
15
+ <testcase classname="cache.test.ts" name="returns a cached avatar" time="0.01"/>
16
+ <testcase classname="cache.test.ts" name="returns a 32px avatar after a 512px one" time="0.02">
17
+ <failure message="expected 512 to be 32">AssertionError: expected 512 to be 32
18
+ at cache.test.ts:27:31</failure>
19
+ </testcase>
20
+ </testsuite>
21
+ ```
22
+ ::
23
+
24
+ ::diff{line=18 label="Fix"}
25
+ ```ts [src/avatars/cache.ts]
26
+ const key = user.id;
27
+ ```
28
+ ```ts
29
+ const key = `${user.id}:${size}`;
30
+ ```
31
+ ::
32
+
33
+ ## 2. The cache never evicts (should fix)
34
+
35
+ `src/avatars/cache.ts:9`. Read in the code, not measured: the map grows by one entry per user and size for as long as the tab stays open, which on the team directory is thousands of images.
36
+
37
+ ```ts [src/avatars/cache.ts] mark={1}
38
+ const cache = new Map<string, Blob>();
39
+ ```
40
+
41
+ Cap it, such as an LRU of 500 entries, or decide the tab's lifetime is short enough not to.
42
+
43
+ ## Checked
44
+
45
+ - Ran `pnpm test src/avatars`: one failure, above.
46
+ - Opened a profile on the preview at 1440px and watched the comment avatars after the header loaded.
47
+
48
+ ## Not checked
49
+
50
+ - Server rendering: the cache only runs in the browser, and I didn't confirm the server skips it.
51
+ - Safari's memory use.
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: teach-lesson
3
+ description: 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.
4
+ license: MIT
5
+ ---
6
+
7
+ # Teach lesson
8
+
9
+ A lesson teaches one concept through a worked example and an application question. Keep it short enough to finish in five minutes.
10
+
11
+ ## 1. Pin the concept and the outcome
12
+
13
+ Infer the reader's purpose and existing knowledge from the conversation. Focus on the gap their question reveals.
14
+
15
+ Name 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.
16
+
17
+ If the outcome depends on another concept, link to its prerequisite lesson or teach that prerequisite first.
18
+
19
+ Done when one sentence names the action the reader will perform and the situation they will apply it to.
20
+
21
+ ## 2. Find a worked example
22
+
23
+ Pick 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.
24
+
25
+ Verify 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.
26
+
27
+ Done when each move has a concrete value, its behavior matches the source, and each design reason is sourced or qualified.
28
+
29
+ ## 3. Write the lesson
30
+
31
+ Read [references/example.md](references/example.md) as a model for the complete lesson. Write these parts in order:
32
+
33
+ 1. **The outcome**, one sentence under the title.
34
+ 2. **Why it matters**: the failure the concept prevents, told as the worked example's problem. Three or four sentences.
35
+ 3. **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.
36
+ 4. **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).
37
+ 5. **The check**, below.
38
+ 6. **Read next**: one primary source, linked to the exact section, and the lesson that naturally follows.
39
+
40
+ ### Use STE 100 writing rules
41
+
42
+ Apply [ASD-STE100 Simplified Technical English](https://asd-ste100.org/) writing rules to the whole lesson, including the example, question, hints, and answer explanations.
43
+
44
+ - Give each sentence one idea. Give each instruction one action.
45
+ - Keep instructions within 20 words and descriptive sentences within 25 words. Use short paragraphs.
46
+ - Use common words and active voice. Write instructions as direct commands.
47
+ - Define each technical term in bold at first use. Use one term for each concept and keep its meaning consistent.
48
+ - Keep technical names, code, units, and UI labels exact.
49
+ - Put a condition before the action it controls. Make each pronoun refer to one clear subject.
50
+ - Use literal wording and explain abbreviations. Split long noun groups into phrases.
51
+ - State the mechanism directly, with the detail needed to follow it.
52
+
53
+ Done 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.
54
+
55
+ ## 4. Write the check
56
+
57
+ Use [`::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.
58
+
59
+ - Make each wrong option a real misconception, and give it a `>` rationale that says why it's tempting and why it's wrong.
60
+ - Keep the options parallel, one idea each and close in length, so their shape gives no clue to the answer.
61
+ - Add `#explain` for the one thing the reader should take away whatever they picked.
62
+ - For a fact worth remembering a week later, optionally add a [`::recall` card](references/blocks.md#the-fact-to-keep-recall).
63
+
64
+ Done when the question tests the stated outcome with one changed input, every option has a rationale, and the shared explanation resolves each misconception.
65
+
66
+ ## 5. Check the render
67
+
68
+ 1. Lint it, and fix until it reports no problems:
69
+
70
+ ```sh
71
+ vp dlx --package comark-linter --package comark-ui lint-comark lesson.md
72
+ ```
73
+
74
+ These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
75
+
76
+ 2. Open the rendered page where it will be read. Select each option and check its rationale and the shared explanation.
77
+
78
+ Done 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.
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "Teach lesson"
3
+ short_description: "Teach one concept with a worked example and a check"
@@ -0,0 +1,91 @@
1
+ # Blocks for a lesson
2
+
3
+ These blocks come with `comark-ui`. The steps and questions also come separately with `comark-steps` and `comark-quiz`.
4
+
5
+ ## The worked example: `::steps`
6
+
7
+ ````md
8
+ ::steps
9
+ ### Both load version 7
10
+
11
+ Ana and Ben each `GET /articles/42`, and both get `ETag: "v7"`.
12
+
13
+ ### Ana saves first
14
+
15
+ ```http
16
+ PUT /articles/42
17
+ If-Match: "v7"
18
+ ```
19
+ ::
20
+ ````
21
+
22
+ Each `###` heading starts a step that holds everything up to the next one, code blocks included. Put any introduction above the block, since a paragraph before the first heading is reported. For steps of one line each, a numbered list inside `::steps` works too.
23
+
24
+ ## Build a diagram across steps
25
+
26
+ Use a `mermaid` fence when a diagram helps explain interacting parts. Redraw the previous diagram and add one part or relationship at each move. Keep existing labels and participant order consistent.
27
+
28
+ Use numbered Markdown headings for the worked example. Mermaid fences currently disappear inside `::steps`, so place them directly under these headings:
29
+
30
+ ````md
31
+ ### 1. The client requests the article
32
+
33
+ ```mermaid
34
+ sequenceDiagram
35
+ participant Client
36
+ participant Server
37
+ Client->>Server: GET /articles/42
38
+ ```
39
+
40
+ ### 2. The server returns a version label
41
+
42
+ ```mermaid
43
+ sequenceDiagram
44
+ participant Client
45
+ participant Server
46
+ Client->>Server: GET /articles/42
47
+ Server-->>Client: ETag v7
48
+ ```
49
+ ````
50
+
51
+ These paths and version labels are illustrative. Use `sequenceDiagram` for messages or `flowchart LR` for a flow. comark-ui renders Mermaid as SVG, so the reader needs no diagram script.
52
+
53
+ ## The check: `::question`
54
+
55
+ ```md
56
+ ::question{#etag-no-if-match}
57
+ Ben's editor sends his `PUT` with no `If-Match` header. What happens?
58
+
59
+ - [x] The server saves Ben's version and Ana's fix is lost
60
+ > Without `If-Match` there's no condition to fail.
61
+ - [ ] The server refuses the save with a 412 status code
62
+ > A 412 needs a condition that failed.
63
+
64
+ #hint
65
+ What does the server compare the label against?
66
+
67
+ #explain
68
+ `If-Match` is opt-in.
69
+ ::
70
+ ```
71
+
72
+ - Mark the right option `[x]`. One `[x]` makes radio buttons; add `multiple` to the block for checkboxes with several right options.
73
+ - The `>` quote under an option is its rationale, shown once the reader answers.
74
+ - `#hint` is optional, shown on request; `#explain` shows after any answer.
75
+ - Options are shuffled the same way on every render; write `shuffle="false"` only when their order means something, such as numbers in order.
76
+ - Give the block an `#id` so a host can store the answer. Without one, the id comes from the question's text and changes when you edit it.
77
+
78
+ Without its script, the question and an answer disclosure still render as plain HTML.
79
+
80
+ ## The fact to keep: `::recall`
81
+
82
+ ```md
83
+ ::recall{#etag-412}
84
+ What does a server answer when `If-Match` names an old version?
85
+
86
+ #answer
87
+ `412 Precondition Failed`, and it leaves the resource unchanged.
88
+ ::
89
+ ```
90
+
91
+ The reader answers in their head, then reveals `#answer`.
@@ -0,0 +1,70 @@
1
+ # Keep both writers' changes
2
+
3
+ After this lesson, you can predict how a server handles two changes to the same record, with or without a version check.
4
+
5
+ ## Why it matters
6
+
7
+ In this example, Ana and Ben open the same help article. Ana corrects a spelling error and saves the article. Ben adds a paragraph to his older copy and saves it. His save removes Ana's correction without a warning. This is a **lost update**.
8
+
9
+ ## The idea
10
+
11
+ An **ETag** is a version label, such as `"v7"`, that the server sends with a resource. The **If-Match** header carries that label back to require the same version before saving a change. If the labels match, the server saves the change. If the labels differ, the server returns `412 Precondition Failed` and keeps the resource unchanged.
12
+
13
+ ## Worked example
14
+
15
+ ::steps
16
+ ### Both load version 7
17
+
18
+ Ana and Ben each `GET /articles/42`, and both get `ETag: "v7"`.
19
+
20
+ ### Ana saves first
21
+
22
+ ```http
23
+ PUT /articles/42
24
+ If-Match: "v7"
25
+ ```
26
+
27
+ The article is still at `"v7"`. The server saves Ana's change and returns `200 OK` with `ETag: "v8"`.
28
+
29
+ ### Ben saves second
30
+
31
+ ```http
32
+ PUT /articles/42
33
+ If-Match: "v7"
34
+ ```
35
+
36
+ The article is now at `"v8"`. The labels differ, so the server returns `412 Precondition Failed`. Ana's correction stays.
37
+
38
+ ### Ben reloads and merges
39
+
40
+ Ben's editor fetches `"v8"` and shows Ana's correction. Ben adds his paragraph to that version. He saves again with `If-Match: "v8"`.
41
+ ::
42
+
43
+ ## Check yourself
44
+
45
+ ::question{#etag-no-if-match}
46
+ This API accepts requests without `If-Match`. Ben's editor sends his `PUT` without that header. The article is at `"v8"`. What happens?
47
+
48
+ - [x] The server saves Ben's version and removes Ana's correction
49
+ > Without `If-Match`, the server has no version condition to check. The server saves Ben's version. This removes Ana's correction.
50
+ - [ ] The server refuses the save with a 412 status code
51
+ > A 412 response requires a condition that failed. Ben sent no condition, so the server has no labels to compare.
52
+ - [ ] The server merges Ben's paragraph into version 8
53
+ > The server does not combine the two versions. After a 412 response, the client must get the current version and combine the changes.
54
+
55
+ #explain
56
+ The client must send its original version label for `If-Match` to protect the change. An API can require that header. If the header is absent, that API can return `428 Precondition Required`.
57
+ ::
58
+
59
+ ::recall{#etag-412}
60
+ What does a server answer when `If-Match` names an old version?
61
+
62
+ #answer
63
+ `412 Precondition Failed`, and it leaves the resource unchanged.
64
+ ::
65
+
66
+ ## Read next
67
+
68
+ [RFC 9110, section 13.1.1](https://www.rfc-editor.org/rfc/rfc9110#name-if-match) defines `If-Match`.
69
+
70
+ The next lesson explains weak ETags and why `W/"v7"` never matches `If-Match`.
@@ -0,0 +1,67 @@
1
+ ---
2
+ name: visual-explanation
3
+ description: 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.
4
+ license: MIT
5
+ ---
6
+
7
+ # Visual explanation
8
+
9
+ A 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.
10
+
11
+ ## 1. Name the question
12
+
13
+ Write 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.
14
+
15
+ Done when the question fits on one line.
16
+
17
+ ## 2. Pick the view
18
+
19
+ Choose by the shape of the answer:
20
+
21
+ | The answer is… | Draw |
22
+ | --- | --- |
23
+ | The order of events between parts | A `mermaid` sequence diagram or flowchart |
24
+ | Who calls whom | A call tree in a `text` fence, indented by call depth |
25
+ | Where code lives, or which files a change touches | `::file-tree`, with `+`, `-`, and `~` marks |
26
+ | The states something moves between | A `mermaid` `stateDiagram-v2` |
27
+ | Something on screen | `::screenshot` with measured marks |
28
+ | What a few lines do, line by line | A code fence with `// <1>` notes |
29
+ | How a number changed | `::chart` or a two-row table |
30
+
31
+ Use 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.
32
+
33
+ Done when you can say, in one sentence, what the reader will see in the view.
34
+
35
+ ## 3. Draw it from the source
36
+
37
+ Read 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.
38
+
39
+ Keep a diagram to about eight nodes or participants. Past that, split it by stage or zoom into the part the question is about.
40
+
41
+ Done when every label in the view exists in the source, and nothing in it is there only for completeness.
42
+
43
+ ## 4. Write around it
44
+
45
+ [references/example.md](references/example.md) shows the shape:
46
+
47
+ 1. A title that is the question, or its answer.
48
+ 2. Two or three sentences with the answer in plain words, ending on what to look at in the view.
49
+ 3. The view.
50
+ 4. One or two sentences for what the view can't show, such as a rule that applies at every step.
51
+ 5. A second view only if step 2 allowed one, with a sentence before it saying why it's there.
52
+
53
+ Done when the explanation reads top to bottom in under a minute and every visual has a sentence beside it.
54
+
55
+ ## 5. Check the render
56
+
57
+ 1. Lint it, and fix until it reports no problems:
58
+
59
+ ```sh
60
+ vp dlx --package comark-linter --package comark-ui lint-comark explanation.md
61
+ ```
62
+
63
+ These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.
64
+
65
+ 2. 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.
66
+
67
+ Done when you've looked at the render and every label reads at its size.
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "Visual explanation"
3
+ short_description: "Explain how something works with one checkable visual"
@@ -0,0 +1,89 @@
1
+ # Blocks for a visual explanation
2
+
3
+ These blocks come with `comark-ui`. The comark-ui skill (`vp dlx skills add onmax/comark-ui`) documents every block in full.
4
+
5
+ ## Diagrams: a `mermaid` fence
6
+
7
+ ````md
8
+ ```mermaid
9
+ sequenceDiagram
10
+ participant Browser
11
+ participant Worker
12
+ participant Assets
13
+ Browser->>Worker: GET /zoom/
14
+ Worker->>Assets: zoom/index.html
15
+ Assets-->>Browser: prerendered page
16
+ ```
17
+ ````
18
+
19
+ comark-ui draws Mermaid as SVG while parsing, so the page needs no script to show it. Use `flowchart LR` for a pipeline, `sequenceDiagram` for messages between parts, and `stateDiagram-v2` for states. Write labels as the code names them. For a diagram in another language, `d2`, `dot`, `plantuml`, `dbml`, `goat`, and `svgbob` fences draw through comark-diagrams.
20
+
21
+ ## A call tree: a `text` fence
22
+
23
+ ````md
24
+ ```text
25
+ renderPage
26
+ parseMarkdown
27
+ plugins' post
28
+ renderHtmlFromDocument
29
+ components
30
+ ```
31
+ ````
32
+
33
+ Indent by call depth, two spaces a level. Name functions as the code does.
34
+
35
+ ## Files: `::file-tree`
36
+
37
+ ````md
38
+ ::file-tree
39
+ ```
40
+ docs/
41
+ build.ts # renders every page
42
+ ~ style.css
43
+ + pages/
44
+ + skills/
45
+ ...
46
+ ```
47
+ ::
48
+ ````
49
+
50
+ Two spaces nest an entry, a trailing `/` makes a folder, `+`, `-`, and `~` mark added, removed, and changed, and ` # ` starts a note. `...` stands for entries left out. Write the tree in a fence; a Markdown list renders names like `__init__.py` as bold.
51
+
52
+ ## Line notes: `// <1>` and a list
53
+
54
+ ````md
55
+ ```ts
56
+ const document = await parseMarkdown(source, { plugins }); // <1>
57
+ const html = await renderHtmlFromDocument(document, { components }); // <2>
58
+ ```
59
+
60
+ 1. Every plugin runs here.
61
+ 2. Components only draw.
62
+ ````
63
+
64
+ A numbered list right after the fence becomes the notes. The marker goes in a line-end comment in the block's language, such as `# <1>` in Python.
65
+
66
+ ## On screen: `::screenshot`
67
+
68
+ ```md
69
+ ::screenshot{src="https://example.com/settings.png" alt="Settings page with the Save button" viewport="1280x800"}
70
+ :::annotation{x=71.2 y=84.1 w=12.4 h=6.3}
71
+ **Save** writes all three tabs at once.
72
+ :::
73
+ ::
74
+ ```
75
+
76
+ Measure `x y w h` from the page as percentages of the image. The before-after-evidence skill explains how.
77
+
78
+ ## Numbers: `::chart`
79
+
80
+ ```md
81
+ ::chart{type="bar" title="Build time, seconds"}
82
+ | Step | Before | After |
83
+ | --- | --: | --: |
84
+ | Parse | 4.1 | 1.2 |
85
+ | Render | 2.3 | 2.2 |
86
+ ::
87
+ ```
88
+
89
+ The chart draws from the table, so the numbers in your text and the chart can't disagree.
@@ -0,0 +1,25 @@
1
+ # How a Comark document becomes HTML
2
+
3
+ Parsing and rendering are two separate calls, and the plugins do their work in the first. That's why a block's problems are known before any HTML exists.
4
+
5
+ ```mermaid
6
+ flowchart LR
7
+ md[Markdown] --> tokens[Tokens]
8
+ tokens --> tree[Node tree]
9
+ tree --> doc[Nodes and issues]
10
+ doc --> html[HTML]
11
+ ```
12
+
13
+ A plugin can join at three points: its Markdown rules while the text becomes tokens, `markdownItPost` on the tokens, and `post` on the tree. The last arrow is the renderer, which only maps each node to a component.
14
+
15
+ In code, the diagram is three lines:
16
+
17
+ ```ts
18
+ const document = await parseMarkdown(source, { plugins }); // <1>
19
+ if (document.meta.issues.length) refuse(document.meta.issues); // <2>
20
+ const html = await renderHtmlFromDocument(document, { components }); // <3>
21
+ ```
22
+
23
+ 1. Every plugin runs here, in the order of `plugins`.
24
+ 2. Each issue is one sentence naming the block and the fix, so a host can refuse a document before it renders.
25
+ 3. Components only draw: `screenshot` maps to the figure's HTML, and nothing is parsed again.
@@ -0,0 +1,18 @@
1
+ //#region src/skills.d.ts
2
+ /** One file of a skill, at its path from the skill's folder, such as `SKILL.md` or `references/example.md`. */
3
+ export interface SkillFile {
4
+ path: string;
5
+ text: string;
6
+ }
7
+ /** An Agent Skill: its folder's name, its frontmatter, and every file in it, `SKILL.md` first. */
8
+ export interface Skill {
9
+ name: string;
10
+ description: string;
11
+ frontmatter: Record<string, unknown>;
12
+ files: SkillFile[];
13
+ }
14
+ /** Every agent skill this version of comark-ui ships, in the order of their names. */
15
+ export declare const skills: Skill[];
16
+ /** The comark-ui version the skills come from, for a host's cache key or a digest. */
17
+ export declare const version: string;
18
+ //#endregion