@erclx/canon 5.24.0 → 5.25.0
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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
- package/claude/skills/backlog-triage/SKILL.md +19 -6
- package/claude/skills/canvas/REQUIREMENT.md +49 -0
- package/claude/skills/canvas/SKILL.md +106 -0
- package/claude/skills/design-extract/REQUIREMENT.md +1 -1
- package/claude/skills/draft-doc/REQUIREMENT.md +1 -1
- package/claude/skills/draft-figure/REQUIREMENT.md +14 -3
- package/claude/skills/draft-figure/SKILL.md +24 -51
- package/claude/skills/draft-figure/references/architecture-set.md +35 -0
- package/claude/skills/draft-figure/references/hand-drawn.md +31 -0
- package/claude/skills/draft-figure/references/mermaid.md +55 -0
- package/claude/skills/git-followup/SKILL.md +17 -6
- package/claude/skills/git-pr/references/evidence.md +4 -2
- package/claude/skills/git-split/SKILL.md +1 -1
- package/claude/skills/index-lookup/SKILL.md +2 -2
- package/claude/skills/review-address/SKILL.md +6 -13
- package/claude/skills/review-address/references/rest-reads.md +43 -0
- package/claude/skills/review-craft/references/ui.md +7 -1
- package/claude/skills/review-pr/REQUIREMENT.md +1 -0
- package/claude/skills/review-pr/SKILL.md +9 -3
- package/claude/skills/review-pr/references/close-out.md +2 -2
- package/claude/skills/review-pr/references/post.md +17 -5
- package/claude/skills/review-pr/references/scope.md +10 -8
- package/claude/skills/review-ui/SKILL.md +12 -4
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +30 -1
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +4 -0
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +4 -4
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +6 -0
- package/claude/skills/role-orchestrator/scripts/poll.ts +90 -27
- package/claude/skills/role-orchestrator/scripts/repo.ts +3 -5
- package/claude/skills/role-orchestrator/scripts/watch.ts +4 -7
- package/docs/agents/canvas.md +1 -1
- package/docs/agents/commands.md +45 -45
- package/docs/agents/context-audit-checks.md +2 -2
- package/docs/agents/index.md +0 -1
- package/docs/agents/key-changes.md +3 -3
- package/docs/agents/pr-evidence.md +11 -2
- package/docs/agents/pr-reads.md +5 -4
- package/docs/target/projects.md +4 -4
- package/docs/workflow/ai-workflow.md +0 -1
- package/docs/workflow/skill-map.md +3 -3
- package/docs/workflow/visual-design-workflow.md +1 -0
- package/governance/renames.toml +0 -4
- package/governance/rules/standards/markdown.md +1 -0
- package/package.json +1 -2
- package/scripts/core/install-check.sh +1 -1
- package/src/audits/catalog.ts +2 -2
- package/src/canvas/client/inspector/field.tsx +200 -0
- package/src/canvas/client/inspector/fields.css +151 -0
- package/src/canvas/client/inspector/section.tsx +27 -0
- package/src/canvas/client/inspector/values.ts +60 -0
- package/src/canvas/client/inspector.tsx +154 -115
- package/src/canvas/client/shell.css +0 -101
- package/src/claude/cases/misc.ts +5 -0
- package/src/claude/cases/workflow.ts +1 -1
- package/src/claude/seeds.ts +0 -1
- package/src/commands/design.ts +2 -64
- package/src/commands/pr.ts +219 -202
- package/src/context/audit.ts +7 -6
- package/src/help.ts +2 -2
- package/src/migrate/skill-names.ts +7 -1
- package/src/pr/evidence.ts +25 -5
- package/src/pr/rest.ts +137 -0
- package/standards/canvas.md +112 -0
- package/standards/context.md +2 -1
- package/standards/figures.md +0 -1
- package/standards/index.md +1 -1
- package/standards/markdown.md +1 -0
- package/standards/mermaid.md +1 -7
- package/tooling/claude/reference.md +0 -5
- package/claude/skills/draft-diagram/REQUIREMENT.md +0 -45
- package/claude/skills/draft-diagram/SKILL.md +0 -177
- package/docs/agents/design-board.md +0 -33
- package/governance/rules/standards/diagrams.md +0 -14
- package/governance/rules/standards/mermaid.md +0 -15
- package/scripts/core/check-gallery-exclusion.sh +0 -50
- package/src/design/board.ts +0 -576
- package/standards/diagrams.md +0 -132
- package/tooling/claude/seeds/.claude/diagrams/index.md +0 -8
|
@@ -9,12 +9,12 @@ description: Why the backlog gets a measured verdict per row with a lean toward
|
|
|
9
9
|
|
|
10
10
|
Without this skill, the backlog only grows. `task-board` declines or archives one named task, and nothing reads the backlog as a whole, so a row stays until somebody happens to remember it and decides by hand. The orchestrator's backlog re-test only clears a row upward onto the board, so no sweep ever takes one off. A backlog past fifty rows had no surface that could say which of them still mattered.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Four failure modes cost more than the rest. A pass that judges a row by what its task file says rather than by the tree keeps every row, since a task file reads as live the day it was written and every day after. A pass that applies its own verdicts decides rows on silence, which ships a decline nobody approved on a board with no history to restore it from. A keep that carries no measurement is the default nobody argues with, so a triage without a lean toward decline ends with the same backlog it started with. And a keep that measures only that the defect still exists keeps nearly everything, since a row filed against the tree almost always still reproduces. One pass suggested keeping 24 of 27 rows that way, where the operator kept 6 and promoted 1.
|
|
13
13
|
|
|
14
14
|
## Must
|
|
15
15
|
|
|
16
16
|
- Measure every row against the tree and the log during the pass, carrying a count, a path, or a commit rather than the task file's own claim
|
|
17
|
-
- Suggest
|
|
17
|
+
- Suggest keep or promote only for a row that names a cost, being a wrong result the pass observed or a case someone hit, including a user asking for a feature or working around its absence, or a reach, being a defect on a path the project ships that changes what its users or targets receive, hit or not, and suggest decline for a row whose defect merely still exists
|
|
18
18
|
- Name the commit or pull request per outcome position before suggesting archive
|
|
19
19
|
- File into an ordinary intake folder, so the intake list and answer verbs read and write it unchanged
|
|
20
20
|
- Carry the verdict in the suggestion line and the task stem in the item heading, rather than in new fields
|
|
@@ -45,18 +45,31 @@ A row whose link resolves to no file gets an item anyway, carrying `decline` and
|
|
|
45
45
|
|
|
46
46
|
Measure every claim the task makes against the tree and `git log` during this pass. Grep for the construct its defect names and count the sites, check whether each open outcome's behavior exists, and search the log for a commit or pull request that shipped it under another task. Never carry a figure from the task file forward as current, since the task states what was true when it was filed.
|
|
47
47
|
|
|
48
|
+
Then gather the evidence Step 5 reads for each row that reproduces. Check whether its origin line or `## Findings` names an issue, a run, or a person it bit. Search the log for a commit or pull request that worked around it rather than fixing it. For a defect in something the project ships, whether a route or a page its users call or a rule, a seed, a scaffold, or a verb other repositories copy or run, name the shipped path it sits on. Record each one that is absent as absent rather than inferring it.
|
|
49
|
+
|
|
48
50
|
Name the commit the pass measured against in the overview body.
|
|
49
51
|
|
|
50
52
|
### Step 5: pick the verdict
|
|
51
53
|
|
|
52
|
-
Keep and promote carry the burden of proof. A row
|
|
54
|
+
Keep and promote carry the burden of proof, and a defect that still exists does not meet it. A row filed against the tree nearly always still reproduces, so a test of reproduction alone keeps almost every row.
|
|
55
|
+
|
|
56
|
+
A row earns keep or promote only by naming one of two things from the evidence Step 4 gathered:
|
|
57
|
+
|
|
58
|
+
- **A cost**: the defect gives a wrong result that this pass observed, by running the verb that carries it or reading the committed output that shows it, or that the row's evidence shows an issue, a run, or a person hit, a workaround commit included. A hit counts only while the pass does not measure it as fixed or as no longer recurring.
|
|
59
|
+
- **A reach**: the defect sits on a path the project ships, and everyone who reaches that path, whether a user calling it or a target copying or running it, receives the defect as a wrong instruction, a broken, failing, or unbounded behavior, or a wrong output. Reach needs no hit, since the path's users meet the defect whether or not anyone reported it.
|
|
60
|
+
|
|
61
|
+
A plausible cost names nothing. A row arguing what could go wrong off a shipped path, with no observed output and no hit, is declined however likely the argument sounds. Three things are not a reach: a missing feature on a shipped surface, a defect that changes nothing a user or a target receives, such as dead code on a shipped path, and a defect that shows only in this repository's own config, workflows, scripts, or fixtures.
|
|
62
|
+
|
|
63
|
+
A missing protection is a defect, not a missing feature. Read a row as a missing protection when the shipped path lacks a bound, a check, or a guard on what it does at run time, such as a limit, a timeout, or input validation, so that the path can fail, run unbounded, or return a wrong output for every user who reaches it. That is a reach. A missing feature leaves the path working as it does today and adds a capability, a document kind, or a sentence of guidance, and it is not a reach.
|
|
64
|
+
|
|
65
|
+
A missing feature can still earn keep or promote through the cost arm. A user asking for it in an issue or a report, or working around its absence on their side, is a case someone hit, so that row is never declined for being a feature. A feature nobody asked for is declined. A passing mention is not a request, and neither is one the project's own planning records filed with no user behind it.
|
|
53
66
|
|
|
54
|
-
- **keep**: the defect
|
|
55
|
-
- **promote**: it
|
|
67
|
+
- **keep**: the defect reproduces this pass, stated with a count or a path, and the row names a cost or a reach, stated with the observation, the hit, or the shipped path.
|
|
68
|
+
- **promote**: it qualifies for keep, and the thing it was waiting on has cleared, naming what cleared it.
|
|
56
69
|
- **archive**: every open outcome is measured shipped, naming the commit or pull request per outcome position.
|
|
57
|
-
- **decline**: anything else, including a defect the tree no longer holds, work superseded by another task, and a row whose argument rests only on its original filing.
|
|
70
|
+
- **decline**: anything else, including a defect that reproduces but names no cost and no reach, a defect the tree no longer holds, work superseded by another task, and a row whose argument rests only on its original filing.
|
|
58
71
|
|
|
59
|
-
Age is evidence in neither direction. A row untouched for months is not more declinable than one filed yesterday, and a row filed yesterday is not more worth keeping.
|
|
72
|
+
Age is evidence in neither direction. A row untouched for months is not more declinable than one filed yesterday, and a row filed yesterday is not more worth keeping. An old hit is read the same way as a new one, by whether the pass measures it as still able to recur.
|
|
60
73
|
|
|
61
74
|
### Step 6: write the items
|
|
62
75
|
|
|
@@ -64,7 +77,7 @@ Write one item per row in the intake item format, one cluster file per domain th
|
|
|
64
77
|
|
|
65
78
|
- `Problem:` states what this pass measured, with the count, path, or commit behind it
|
|
66
79
|
- `Fix:` states what applying the verdict does to the board
|
|
67
|
-
- `Worth it:`
|
|
80
|
+
- `Worth it:` names the cost or the reach the verdict rests on in one clause, or says the row names neither. A `yes` or a `later` carries no verdict on its own, so a decline can follow either word
|
|
68
81
|
- `Open:` reads `decline, archive, keep, or promote?` on every item
|
|
69
82
|
- `Suggested:` opens with exactly one of the four verdict tokens, then the reason. An archive suggestion lists every outcome position it closes, as `archive 1, 3: shipped in #NNN`
|
|
70
83
|
- `Overlaps:` names a live board task that already carries the work, where one does
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canvas
|
|
3
|
+
description: Scope boundary for driving the local design canvas, and the line between a drafted frame and the design it feeds
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canvas requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session asked to draw on the canvas writes frames into a folder nothing is serving, so the operator sees nothing and the session reports the frames as drawn. When the server is running, the session trusts a passing capture as proof the canvas works. Captures go through the frame route, so a shell that answers its address with an empty page passes every capture while the operator looks at a blank tab.
|
|
11
|
+
|
|
12
|
+
It reads "this one" from the conversation rather than from the operator's selection, and when it does read the selection it acts on an element index recorded against an earlier version of the file, which lands the edit on a different element. It restyles through a class while the operator's inspector edit sits on the element as inline style, so the change never shows and the session reports it as made.
|
|
13
|
+
|
|
14
|
+
It writes frames from a linked worktree with the file tools, which refuse the main-root path and offer a worktree copy the canvas never serves. It captures after every edit, filling session scratch with images of drafts nobody picked.
|
|
15
|
+
|
|
16
|
+
When the operator picks a frame, the session leaves the decision on the canvas and cites the frame as the design, so the project's design document never learns it and a gitignored file becomes the only record.
|
|
17
|
+
|
|
18
|
+
## Must
|
|
19
|
+
|
|
20
|
+
- Start the canvas when it is not serving, before writing any frame
|
|
21
|
+
- Confirm the live shell loads at the address the server reported, rather than trusting a capture
|
|
22
|
+
- Read the address off the server's record rather than composing one
|
|
23
|
+
- Make pages and frames through the verbs, so a box and the operator's drags share one locked writer
|
|
24
|
+
- Name the main-root write route for a frame written from a linked worktree
|
|
25
|
+
- Read the operator's selection when they point at something, and treat a stale element pick as unknown
|
|
26
|
+
- Read a frame's inline styles before restyling it, and say which operator edits were kept and which dropped
|
|
27
|
+
- Capture once per finished frame or page rather than after every edit
|
|
28
|
+
- Carry a picked direction into the project's design document or wireframes
|
|
29
|
+
|
|
30
|
+
## Must not
|
|
31
|
+
|
|
32
|
+
- Present the canvas as the project's source of truth for design
|
|
33
|
+
- Promise the canvas survives a lost checkout
|
|
34
|
+
- Name any third-party design tool, or the canvas's predecessor surface
|
|
35
|
+
- Be invoked only by the author typing its name. A request to draw, select, or capture on the canvas should reach it by description, and a run where it never fires on such a request is a defect in the description
|
|
36
|
+
|
|
37
|
+
## Guards
|
|
38
|
+
|
|
39
|
+
- No `canon` on PATH, or an installed CLI with no canvas command, stop rather than writing files nothing serves
|
|
40
|
+
- A server that refuses to start, or a shell that answers blank, stop and report it rather than drawing into it
|
|
41
|
+
|
|
42
|
+
## Out of scope
|
|
43
|
+
|
|
44
|
+
- What the canvas verbs do internally, which is the CLI's own contract
|
|
45
|
+
- The content format a frame and a layout take, which the canvas standard fixes
|
|
46
|
+
- Drafting candidates for a taste decision and taking the pick, which `draft-and-pick` runs on its own render path
|
|
47
|
+
- Tracing reference images into design values, which is `sketch-design`
|
|
48
|
+
- Writing the design document itself, which is `design-extract`
|
|
49
|
+
- Backing up the canvas folder off one disk
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canvas
|
|
3
|
+
description: Drives the local design canvas, where pages hold HTML frames the operator sees, drags, selects, and edits in the browser. Starts the canvas when it is not running, confirms the live shell loads, makes pages and frames, edits a frame through its file, reads what the operator selected or restyled, captures finished frames, and carries a picked direction into the project's design document. Use when asked to "open the canvas", "put this on the canvas", "draw a frame for X", "change the one I selected", "what did I pick", "capture this frame", or "move that frame on the canvas". Do NOT use to trace reference images into design values, which is `sketch-design`, or to write the design document from code, which is `design-extract`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canvas
|
|
7
|
+
|
|
8
|
+
Drive the canvas the operator is looking at. A page is a folder of HTML frames and a frame is one file, so a session draws by writing files and the operator sees each write land in the browser. The content format is fixed by `${CLAUDE_SKILL_DIR}/../../standards/canvas.md`. Read it before writing a frame.
|
|
9
|
+
|
|
10
|
+
Every verb below is `canon canvas`. Run `canon docs canvas` for the full verb reference, its records, and its refusals.
|
|
11
|
+
|
|
12
|
+
## Guards
|
|
13
|
+
|
|
14
|
+
- If `canon` is not on PATH, stop: `❌ canon CLI not found.`
|
|
15
|
+
- If `canon canvas --help` reports no such command, stop: `❌ The installed canon carries no canvas command. Update the CLI and re-run.`
|
|
16
|
+
- Write no frame before the canvas is serving and the shell has loaded. A frame nobody can see is a draft reported as delivered.
|
|
17
|
+
- Never present a frame as the project's design. The canvas is a drafting surface and the project's design document or wireframes hold what was decided.
|
|
18
|
+
- Never promise the canvas survives a lost checkout. Its folder is gitignored and nothing backs it up.
|
|
19
|
+
|
|
20
|
+
## Step 1: start the canvas and confirm the shell
|
|
21
|
+
|
|
22
|
+
Read the pages first, which also proves the verb resolves:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
canon canvas list --json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The record carries `content`, the folder every page lives in. It sits at the main worktree root whichever worktree the session runs in, so write through that path rather than one composed from the current directory.
|
|
29
|
+
|
|
30
|
+
Start the server in the background unless the operator named an address that already answers, since it runs until interrupted. No verb reports a running server, and a second one is harmless, since it walks to the next free port and serves the same folder:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
canon canvas serve --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Read `url` off the record rather than composing one, since the server walks past a port already in use. Report the refusal and its `reason` when `ok` is false, and stop there.
|
|
37
|
+
|
|
38
|
+
Then fetch the printed address and check the shell itself, not a capture:
|
|
39
|
+
|
|
40
|
+
- The body is non-empty and carries a `<script` tag. An empty `200` means the shell failed to build, usually a dependency missing from the canvas tool's install, and every capture still passes because captures go through the frame route alone. Report it as a blank shell and stop.
|
|
41
|
+
- `<url>/api/pages` answers with JSON listing the pages.
|
|
42
|
+
|
|
43
|
+
Hand the operator the address as a markdown link carrying the URL as its text and its target.
|
|
44
|
+
|
|
45
|
+
## Step 2: make pages and frames
|
|
46
|
+
|
|
47
|
+
- Add a page for each decision being drafted: `canon canvas page add <page> --json`.
|
|
48
|
+
- Add each frame through the verb, which writes the starting file and its box in one locked step: `canon canvas frame add <page> <frame> --width <px> --height <px> --json`. Give the width the frame should render at, since a capture and the canvas both render at it.
|
|
49
|
+
- Lay frames out with `canon canvas frame move <page> <frame> --x <px> --y <px> --json` rather than writing `layout.json` by hand, since the operator's drags write the same file under a lock.
|
|
50
|
+
- Name pages and frames for what they hold, such as `pricing` and `pricing-dense`, so the operator can say which one by name.
|
|
51
|
+
|
|
52
|
+
## Step 3: edit a frame through its file
|
|
53
|
+
|
|
54
|
+
Write the frame's whole document to the `path` the add verb reported. The open canvas reloads the frame when its file changes.
|
|
55
|
+
|
|
56
|
+
- From a linked worktree, `Edit` and `Write` refuse a main-root path. Write the whole file through one plain `Bash` heredoc instead, the route `session-worktree` states for a main-root write, and never take the redirect to a worktree copy.
|
|
57
|
+
- Change one property of one element with `canon canvas edit <page>/<frame> --element <index> --set <property>=<value> --json` when the set it accepts covers the change, since it leaves every other byte as it was.
|
|
58
|
+
- Use the project's custom properties for every value the token stylesheet defines. The record from `serve` names the token source under `tokens`, and a `none` source means frames render unstyled, so say so rather than inventing values to cover it.
|
|
59
|
+
|
|
60
|
+
## Step 4: read what the operator pointed at
|
|
61
|
+
|
|
62
|
+
Read the selection when the operator says "this one", "the selected frame", or "that button":
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
canon canvas selection --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- `selection: null` means nothing is selected or the selected frame is gone. Ask which one rather than guessing.
|
|
69
|
+
- An `element` carrying `stale: true` was picked against an earlier version of the file, so its `index` may now land on a different element. Treat the pick as unknown and ask the operator to pick again, rather than acting on the index or matching its `tag` and `text` by eye.
|
|
70
|
+
- A fresh `element` gives the `index` that `canvas edit` takes.
|
|
71
|
+
|
|
72
|
+
## Step 5: respect the operator's inspector edits
|
|
73
|
+
|
|
74
|
+
The operator restyles elements from the inspector, and each edit lands as inline `style` on the element. Inline style beats a class, so a class change made afterwards does not show.
|
|
75
|
+
|
|
76
|
+
- Read the frame's inline `style` attributes before restyling anything in it.
|
|
77
|
+
- Keep an inline property the operator set unless the change replaces it, and drop it, through `canvas edit` with an empty value or by rewriting the file, when it does.
|
|
78
|
+
- Say which operator edits were kept and which were dropped.
|
|
79
|
+
|
|
80
|
+
## Step 6: capture finished work
|
|
81
|
+
|
|
82
|
+
- Capture a frame once it is finished: `canon canvas capture <page>/<frame> --json`. Each PNG is the frame's whole document, so its height follows the content rather than the box.
|
|
83
|
+
- Capture a whole page once its frames are finished: `canon canvas capture <page> --composite --json`. The image shows each frame clipped to its box at its layout position.
|
|
84
|
+
- Capture once per finished frame or page, not after every edit. The live canvas is the working view, and a capture is the record handed on.
|
|
85
|
+
- Read each `path` off the record rather than composing one.
|
|
86
|
+
- A capture refused because a font is not installed names the family it read off the frame's `html` element. Set that element's `font-family` to a family the machine has and capture again, rather than reporting the frame as captured.
|
|
87
|
+
|
|
88
|
+
## Step 7: carry a picked direction back
|
|
89
|
+
|
|
90
|
+
When the operator picks a frame, the decision leaves the canvas.
|
|
91
|
+
|
|
92
|
+
- Carry visual values, being color, type, spacing, and radius, into the project's design document, through the skill that owns it. Carry structure and layout into the project's wireframes.
|
|
93
|
+
- Name the frame the decision came from in the reply, and leave the frame on the canvas until the operator clears it.
|
|
94
|
+
- Never cite a frame path from a tracked file. The folder is gitignored, so the citation resolves on this machine alone.
|
|
95
|
+
|
|
96
|
+
## Output
|
|
97
|
+
|
|
98
|
+
```plaintext
|
|
99
|
+
✅ Canvas: <url the serve verb reported>
|
|
100
|
+
Page: <page>, <n> frames
|
|
101
|
+
Selected: <page>/<frame>, element <index>, or none, or stale
|
|
102
|
+
Capture: <path of each capture written>
|
|
103
|
+
Carried: <the design document or wireframe the pick went to, or not yet>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Write the canvas line's URL as a markdown link. Omit the capture line when nothing was captured and the carried line when no direction was picked. Emit every path from the project root.
|
|
@@ -39,4 +39,4 @@ The greenfield case is the one that fails quietly. A project with no UI code sti
|
|
|
39
39
|
- Mutating an existing design system, which is a direct edit of the file rather than a skill
|
|
40
40
|
- Producing the HTML and CSS preview, which `canon design render` owns
|
|
41
41
|
- Auditing the implemented UI against the tokens, which `ux-audit` owns
|
|
42
|
-
- Architecture and flow diagrams, which `draft-
|
|
42
|
+
- Architecture and flow diagrams, which `draft-figure` owns
|
|
@@ -42,5 +42,5 @@ The same procedure ran as five skills, one per kind, each restating the read, th
|
|
|
42
42
|
- Rewriting or syncing an existing `docs/` page or an authored README against a diff: `docs-sync`
|
|
43
43
|
- Refreshing an existing context entry or wireframe, or stubbing a surface a diff touched: `context-fold`
|
|
44
44
|
- Drafting a standard or a governance rule: `create-standard`, `create-rule`
|
|
45
|
-
- Drawing a figure or a diagram for a document: `draft-figure
|
|
45
|
+
- Drawing a figure or a diagram for a document: `draft-figure`
|
|
46
46
|
- Voice, rhythm, punctuation, and formatting in the drafted document: the `write-human` skill and the markdown standard
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: draft-figure
|
|
3
|
-
description: Why a figure decides between Mermaid and freehand SVG before drawing, and why
|
|
3
|
+
description: Why a figure decides between Mermaid, an architecture view, and freehand SVG before drawing, and why the Mermaid path carries a render-verification loop
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Draft figure requirement
|
|
@@ -11,18 +11,24 @@ Without this skill, a session asked for a figure reaches for whichever path it t
|
|
|
11
11
|
|
|
12
12
|
A teach lesson breaks the Mermaid path outright. The lesson letters its figures in a hand font the renderer cannot load, so the render sizes every label in a narrower fallback face and the lesson clips the text it actually shows. The check then reads the standalone image, rendered in that same fallback, and passes a figure the reader sees clipped. Both happened on one lesson, where every group title clipped mid-word and only a capture taken inside the lesson showed it.
|
|
13
13
|
|
|
14
|
+
An architecture view asked for one at a time fails its own way. A session asked to refresh one view redraws every view beside it, so pictures nobody checked change in the same commit and the reviewer cannot tell which one the pass was about. It reaches for C4, state, or class diagrams that render differently in every viewer. A Mermaid source can satisfy every rule in the standard and still render as a picture asserting something false about the system, so a session that judges the source and calls it verified has spent the only signal a reader has on a picture nobody looked at.
|
|
15
|
+
|
|
14
16
|
The color failure is the quiet one. Mermaid's own theme writes literal hex values, and a figure carrying one stops re-coloring itself the moment the host page switches its palette, which the figure standard's own accessibility bar rules out.
|
|
15
17
|
|
|
16
18
|
## Must
|
|
17
19
|
|
|
18
20
|
- Apply the standard's earn-its-place bar before drawing anything
|
|
19
21
|
- Decide between the Mermaid path and the freehand path by whether the subject reduces to a graph, not by which is faster to produce
|
|
22
|
+
- Draw an architecture view from its named source signal, inside `flowchart` and `sequenceDiagram`, and render it through the Mermaid path
|
|
23
|
+
- Draw only the view the request names, leaving every other figure in the destination untouched
|
|
20
24
|
- Draw a figure bound for a teach lesson freehand whatever its shape, since the lesson's hand font is one the renderer cannot measure
|
|
21
25
|
- Verify a figure bound for a rendered page by capturing it inside that page, and fall back to the standalone render only where the destination has no page to load
|
|
22
26
|
- Keep the scoped overflow style as the documented fallback for a clipped group title wherever the Mermaid path still runs
|
|
23
27
|
- Render the Mermaid path with the hand-drawn look and the figure font stack, never with Mermaid's default look
|
|
24
28
|
- Rewrite every literal color the renderer wrote into the custom property the host stylesheet defines
|
|
25
|
-
- Read the Mermaid render back and judge it against what the figure means to say,
|
|
29
|
+
- Read the Mermaid render back and judge it against what the figure means to say, rather than judging the source
|
|
30
|
+
- Read the node labels by hand, since no hook checks inside a fence
|
|
31
|
+
- Cite only code paths that exist in an architecture view's caption or prose
|
|
26
32
|
- Wrap either path in a `<figure>` and `<figcaption>` and give it an accessible name
|
|
27
33
|
|
|
28
34
|
## Must not
|
|
@@ -33,16 +39,21 @@ The color failure is the quiet one. Mermaid's own theme writes literal hex value
|
|
|
33
39
|
- Report a clean verification when the Mermaid render was skipped or a defect survived
|
|
34
40
|
- Loop past two correction passes on a surviving defect
|
|
35
41
|
- Commit a scratch render. Only the SVG that ships in the destination document survives
|
|
42
|
+
- Redraw a figure the request did not name, or report one as drawn when it was left alone
|
|
43
|
+
- Leave an architecture view as an unrendered fence
|
|
36
44
|
|
|
37
45
|
## Guards
|
|
38
46
|
|
|
39
47
|
- No subject given: stop, since nothing states what the figure has to show
|
|
40
48
|
- No destination document given: stop, since the figure has nowhere to land
|
|
41
49
|
- Subject does not clear the earn-its-place bar: stop rather than drawing decoration
|
|
50
|
+
- An architecture view with no planning file and no folder structure to scan: stop, because nothing anchors it
|
|
51
|
+
- Render fails for any reason: continue to the output and name the skipped check. A missing renderer degrades the loop rather than failing it.
|
|
42
52
|
|
|
43
53
|
## Out of scope
|
|
44
54
|
|
|
45
|
-
- The toolkit's own `.canon/diagrams/` architecture surface, which shares no code, font, or visual language with this convention: `draft-diagram`
|
|
46
55
|
- Mermaid's own layout, budgets, and label rules for the fence itself: the mermaid standard, cited rather than restated here
|
|
47
56
|
- A UI wireframe or screen mockup: `draft-doc`
|
|
57
|
+
- Design tokens and the visual system: `design-extract`
|
|
58
|
+
- Implementation detail behind an architecture view, which belongs in a context entry the caption points at
|
|
48
59
|
- Which lesson needs a figure and where it sits among the lesson's blocks: `teach-workspace`, which calls this skill to draw one
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: draft-figure
|
|
3
|
-
description: Drafts one hand-drawn figure for a document, deciding whether the subject is Mermaid-shaped or needs freehand SVG, then draws it. Renders the Mermaid path through Mermaid's own hand-drawn look, reads the render back, and fixes what it exposes. Wraps
|
|
3
|
+
description: Drafts one hand-drawn figure for a document, deciding whether the subject is Mermaid-shaped, an architecture view, or needs freehand SVG, then draws it. Renders the Mermaid path through Mermaid's own hand-drawn look, reads the render back, and fixes what it exposes. Wraps every path in the figure standard's caption, color, and accessibility rules. Use when asked to "draw a figure", "add a hand-drawn diagram", "draft a figure for this doc", "draw this relationship as a figure", "draw the architecture", "diagram the system", or "show the components". Do NOT use for a UI wireframe, which is `draft-doc`, or for design tokens, which is `design-extract`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Draft figure
|
|
7
7
|
|
|
8
|
-
Decide whether a requested figure reduces to a graph Mermaid can draw, or needs freehand SVG, then draw it and verify what a reader will actually see.
|
|
8
|
+
Decide whether a requested figure reduces to a graph Mermaid can draw, is one of the architecture views, or needs freehand SVG, then draw it and verify what a reader will actually see.
|
|
9
9
|
|
|
10
10
|
## Guards
|
|
11
11
|
|
|
@@ -17,7 +17,6 @@ Decide whether a requested figure reduces to a graph Mermaid can draw, or needs
|
|
|
17
17
|
Read these in parallel:
|
|
18
18
|
|
|
19
19
|
- `${CLAUDE_SKILL_DIR}/../../standards/figures.md`: when a figure earns its place, the render-first policy, wrapping and captioning, and the color and accessibility rules
|
|
20
|
-
- `${CLAUDE_SKILL_DIR}/../../standards/mermaid.md`: direction and layout, node and edge budgets, the accessibility fields, and how a render is verified, for the Mermaid path
|
|
21
20
|
- `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: formatting for the caption prose
|
|
22
21
|
- The `write-human` skill: voice and rhythm for the caption prose
|
|
23
22
|
|
|
@@ -25,74 +24,48 @@ Read these in parallel:
|
|
|
25
24
|
|
|
26
25
|
Apply the standard's bar: a relationship, a boundary, a path, or a before-and-after that prose or a list cannot carry as well. Stop when it does not: `❌ <subject> reads fine as prose. A figure adds nothing here.`
|
|
27
26
|
|
|
28
|
-
## Step 3:
|
|
27
|
+
## Step 3: pick the path
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
- **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: draw it through Step 4.
|
|
32
|
-
- **Not graph-shaped**, meaning the subject is a spatial or physical arrangement no flowchart reduces to: draw it through Step 5.
|
|
29
|
+
Take the first that matches, and state which path was picked and why in one sentence:
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
1. **A teach lesson**, meaning the destination is a lesson page in a learning workspace's `lessons/` folder: the hand-drawn path, whatever the subject's shape, an architecture view included. The lesson letters its figures in a hand font the renderer cannot load, so a Mermaid render measures its labels in a narrower face and the lesson clips them.
|
|
32
|
+
2. **An architecture view**, meaning the request names system context, components, request flow, data pipeline, or deployment: the architecture set, then the Mermaid path.
|
|
33
|
+
3. **Graph-shaped**, meaning the relationship, boundary, or path is already what a flowchart or sequence diagram expresses: the Mermaid path.
|
|
34
|
+
4. **Anything else**, a spatial or physical arrangement no flowchart reduces to: the hand-drawn path.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
The standard states this as a render-first policy rather than a ban on any tool-exported drawing, so outside a teach lesson a graph-shaped subject always routes through Mermaid even though that is itself an external renderer.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
- Render it with the hand-drawn look and the figure font stack, writing scratch files under `.canon/tmp/figures/`:
|
|
38
|
+
## Step 4: draw
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
mkdir -p .canon/tmp/figures
|
|
43
|
-
cat <<'EOF' >.canon/tmp/figures/<slug>.json
|
|
44
|
-
{"look": "handDrawn", "themeVariables": {"fontFamily": "Virgil, Excalifont, cursive"}}
|
|
45
|
-
EOF
|
|
46
|
-
bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.svg -c .canon/tmp/figures/<slug>.json
|
|
47
|
-
bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.png -c .canon/tmp/figures/<slug>.json
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Render both formats in one pass: the SVG is what ships inside the `<figure>`, and the PNG is what Step 6 reads back, since an SVG's markup carries no recoverable spatial meaning the way `draft-diagram` Step 5 already states for the architecture surface.
|
|
51
|
-
|
|
52
|
-
Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cli ...` otherwise.
|
|
53
|
-
|
|
54
|
-
- Rewrite every stroke, fill, and text color the renderer wrote as a literal hex value into the custom property the host stylesheet defines, per the standard's color rule. Mermaid's own theme has no notion of a custom property, so this is a source edit made to the rendered SVG, not a config option.
|
|
55
|
-
- Expect a group title or a long label to clip once the destination shows it in the hand font, since the renderer sized its box in a fallback face.
|
|
56
|
-
- When the in-page check shows a clipped title, add a `<style>` inside the SVG, scoped to that SVG's own id, that sets `overflow: visible` on the clipped label's `foreignObject` and centers the label within it, so the wider text spills past both edges evenly. The style hides the mismatch for a title and does nothing for a node label crowding its box, which takes a shorter label instead.
|
|
57
|
-
- Check whether the project ran `canon design css --figures`. The figure and figcaption styling ships unconditionally either way, but that flag alone embeds the Virgil and Excalifont font files. Without it, the figure falls back to the browser's own generic `cursive` face rather than the intended hand-drawn font, and Step 7's output names that gap when the flag was not passed.
|
|
58
|
-
|
|
59
|
-
## Step 5: the freehand path
|
|
40
|
+
Read the reference for the path Step 3 picked and follow it:
|
|
60
41
|
|
|
61
|
-
-
|
|
62
|
-
-
|
|
42
|
+
- Architecture set: read `${CLAUDE_SKILL_DIR}/references/architecture-set.md` to shape the view, then `${CLAUDE_SKILL_DIR}/references/mermaid.md` to draw and render it. The architecture branch always renders and reads back. An unrendered fence is not a figure.
|
|
43
|
+
- Mermaid path: read `${CLAUDE_SKILL_DIR}/references/mermaid.md`.
|
|
44
|
+
- Hand-drawn path: read `${CLAUDE_SKILL_DIR}/references/hand-drawn.md`.
|
|
63
45
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Step 6: wrap, caption, and verify
|
|
46
|
+
## Step 5: wrap, caption, and verify
|
|
67
47
|
|
|
68
48
|
- Wrap the drawing in a `<figure>` element with a `<figcaption>` naming what to take from the figure, never what it shows. Let it run wider than the surrounding prose column.
|
|
69
|
-
- On the Mermaid path,
|
|
70
|
-
- On
|
|
71
|
-
- When the
|
|
72
|
-
- When the destination is a rendered page, an HTML file a browser loads, the check that counts is the figure inside that page, which Step 7 runs once the figure is written. The standalone PNG is measured in the renderer's own fonts and can read clean while the page clips it. A markdown destination has no page to load, so the standalone check above is the whole check there.
|
|
49
|
+
- On the Mermaid path, run the read-back `mermaid.md` states before confirming.
|
|
50
|
+
- On every path, confirm the figure still reads once every color and font it depends on is stripped to its fallback, per the standard's own working-figure bar.
|
|
51
|
+
- When the destination is a rendered page, an HTML file a browser loads, the check that counts is the figure inside that page, which Step 6 captures once the figure is written, on either path. A markdown destination has no page to load, so the checks above are the whole check there.
|
|
73
52
|
|
|
74
|
-
## Step
|
|
53
|
+
## Step 6: confirm and write
|
|
75
54
|
|
|
76
|
-
Show the destination path, the decided
|
|
55
|
+
Show the destination path, the decided path, and the full `<figure>` markup before writing. Confirm with the user, since the path decision and the render verdict are judgment calls with no diff to preview either against.
|
|
77
56
|
|
|
78
57
|
Write the figure into the destination document at the location the user named.
|
|
79
58
|
|
|
80
|
-
When the destination is a rendered page,
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
canon capture <destination> --selector figure --out .canon/tmp/figures/
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Narrow the selector to this figure, such as by an id on its `<figure>`, when the page carries more than one. Fix a clipped label, a misaligned shape, or an arrow that misses its target in the destination and capture again, within the same two correction passes Step 6 allows. A clipped group title on the Mermaid path takes the scoped overflow style Step 4 states. When the capture fails, keep the figure and name the skipped check in the output, the same way Step 6 treats a failed render.
|
|
59
|
+
When the destination is a rendered page, read the `## Capture in the page` section of `${CLAUDE_SKILL_DIR}/references/hand-drawn.md` and run it, on the Mermaid path as well as the hand-drawn one, within the same two correction passes the read-back allows.
|
|
87
60
|
|
|
88
|
-
Renders and captures under `.canon/tmp/figures/` are verification artifacts, and the scratch PNGs, the stamps the capture writes beside them, and the JSON config are deleted once the checks confirm, since only the SVG ships.
|
|
61
|
+
Renders and captures under `.canon/tmp/figures/` are verification artifacts, and the scratch PNGs, the stamps the capture writes beside them, and the JSON config are deleted once the checks confirm, since only the SVG ships. Keep the `.mmd` source, which is what a later refresh redraws from.
|
|
89
62
|
|
|
90
63
|
## Output
|
|
91
64
|
|
|
92
65
|
### Preview
|
|
93
66
|
|
|
94
67
|
**Destination:** `<path>`
|
|
95
|
-
**Render path:** `<mermaid | freehand>`, `<one-sentence reason>`
|
|
68
|
+
**Render path:** `<mermaid | architecture | freehand>`, `<one-sentence reason>`
|
|
96
69
|
|
|
97
70
|
```html
|
|
98
71
|
<drafted figure markup></drafted>
|
|
@@ -102,7 +75,7 @@ Renders and captures under `.canon/tmp/figures/` are verification artifacts, and
|
|
|
102
75
|
|
|
103
76
|
```plaintext
|
|
104
77
|
✅ Drafted figure in <path>
|
|
105
|
-
Render path: <mermaid | freehand>
|
|
78
|
+
Render path: <mermaid | architecture | freehand>
|
|
106
79
|
Verified <in page | as a standalone render>. <defect or skipped check, one line, omitted when clean>
|
|
107
80
|
<Font not embedded: run `canon design css --figures` to ship Virgil and Excalifont. Omitted when the project already ran it.>
|
|
108
81
|
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Architecture set
|
|
3
|
+
description: The five architecture views with each one's question, source signal, and diagram type, the code-scan fallback, cited paths, and what moves to canon/context/ instead, read by draft-figure when a request names an architecture view
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Architecture set
|
|
7
|
+
|
|
8
|
+
`draft-figure` reads this file when the request names an architecture view. It shapes the subject, then the figure goes through `${CLAUDE_SKILL_DIR}/references/mermaid.md` like any other graph-shaped figure. The destination stays the one the user named.
|
|
9
|
+
|
|
10
|
+
## The five views
|
|
11
|
+
|
|
12
|
+
Draw the view the request names. Each answers one question and is drawn from one source signal:
|
|
13
|
+
|
|
14
|
+
| View | Question it answers | Source signal | Diagram type |
|
|
15
|
+
| -------------- | ------------------------------------------------------- | ------------------------------------------------- | ------------------------------------ |
|
|
16
|
+
| System context | Who uses the system, what it talks to, where it ends | `canon/REQUIREMENTS.md` | `flowchart TB` |
|
|
17
|
+
| Components | The layered structure inside the boundary | `canon/ARCHITECTURE.md` | `flowchart TB` with `subgraph` lanes |
|
|
18
|
+
| Request flow | A request lifecycle, an agent loop, or an actor handoff | the entry point and its handlers | `sequenceDiagram` |
|
|
19
|
+
| Data pipeline | Retrieval, ranking, queues, or ETL | the pipeline's modules | `flowchart TB` |
|
|
20
|
+
| Deployment | Hosts, services, and infrastructure config | deploy config, compose files, infrastructure code | `flowchart TB` |
|
|
21
|
+
|
|
22
|
+
System context is the only view that draws the world outside the boundary, and the one a reader outside the team opens first, so assume no knowledge of the repository there.
|
|
23
|
+
|
|
24
|
+
Stay inside `flowchart` and `sequenceDiagram`. C4, state, ER, and class diagrams render inconsistently across viewers.
|
|
25
|
+
|
|
26
|
+
## Sources
|
|
27
|
+
|
|
28
|
+
- Read `canon/REQUIREMENTS.md`, `canon/ARCHITECTURE.md`, `CLAUDE.md`, and the language manifest (`package.json`, `pyproject.toml`, `Cargo.toml`) when present, plus the top-level folder layout through `ls`. Do not recurse speculatively.
|
|
29
|
+
- When neither planning file exists and no folder structure names a boundary, stop: `❌ No source signal for <view>. Add canon/ARCHITECTURE.md or run inside a project folder.`
|
|
30
|
+
- When the view came from a code scan rather than planning prose, open the caption with `Source: code.` and add `Fidelity is lower than prose-driven figures. Verify against the project's intent.`
|
|
31
|
+
|
|
32
|
+
## Caption and prose
|
|
33
|
+
|
|
34
|
+
- Name one or two code paths a reader can open, in the caption or the prose beside the figure. Cite only paths that exist and spell each one exactly, since a reader deciding whether the figure still holds starts by opening them.
|
|
35
|
+
- Keep implementation detail out of the figure: function names and call signatures, library versions, config keys and environment variable names, retry counts and timeouts, and workarounds needing more than a sentence. That detail belongs in a `canon/context/` entry, which the caption points at by path when a reader needs the mechanism.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hand-drawn path
|
|
3
|
+
description: Authoring a freehand SVG, its color and accessibility audit, and the in-page capture loop a rendered destination takes, read by draft-figure once a figure is drawn by hand
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hand-drawn path
|
|
7
|
+
|
|
8
|
+
`draft-figure` reads this file when Step 3 routes a figure to a freehand drawing: a teach lesson whatever its subject, or a subject no flowchart reduces to.
|
|
9
|
+
|
|
10
|
+
## Draw
|
|
11
|
+
|
|
12
|
+
- Author the SVG by hand: plain shapes and lines authored directly in the markup.
|
|
13
|
+
- Follow the `## Color and accessibility` section of `${CLAUDE_SKILL_DIR}/../../standards/figures.md` for every fill, stroke, and accessible name.
|
|
14
|
+
|
|
15
|
+
There is no external render to verify a freehand drawing against before it is written. The check here is the stroke-and-fill audit above and a read of the markup against what the subject means to show, done once rather than looped. Hand-placed coordinates can drift out of line where a layout engine would not, so a freehand figure bound for a rendered page also takes the in-page capture below.
|
|
16
|
+
|
|
17
|
+
## Capture in the page
|
|
18
|
+
|
|
19
|
+
When the destination is a rendered page, an HTML file a browser loads, capture the figure inside it once it is written and read the capture against what the figure means to say:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
canon capture <destination> --selector figure --out .canon/tmp/figures/
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- Narrow the selector to this figure, such as by an id on its `<figure>`, when the page carries more than one.
|
|
26
|
+
- Fix a clipped label, a misaligned shape, or an arrow that misses its target in the destination and capture again. Stop after two correction passes.
|
|
27
|
+
- When the capture fails, keep the figure and name the skipped check in the output.
|
|
28
|
+
|
|
29
|
+
A Mermaid figure bound for a rendered page takes this same capture, since its standalone PNG is measured in the renderer's own fonts and can read clean while the page clips it. A clipped group title there takes the scoped overflow style `${CLAUDE_SKILL_DIR}/references/mermaid.md` states.
|
|
30
|
+
|
|
31
|
+
A markdown destination has no page to load, so the read of the markup, or of the standalone render on the Mermaid path, is the whole check there.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mermaid path
|
|
3
|
+
description: The hand-drawn render config, the SVG and PNG pair, the hex rewrite, the scoped overflow fallback, the label check, and the PNG read-back with its two-pass stop, read by draft-figure once a figure routes through Mermaid
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mermaid path
|
|
7
|
+
|
|
8
|
+
`draft-figure` reads this file when Step 3 routes a figure through Mermaid, whether the subject is graph-shaped or an architecture view the architecture set already shaped.
|
|
9
|
+
|
|
10
|
+
## Draft the fence
|
|
11
|
+
|
|
12
|
+
- Draft the fence against `${CLAUDE_SKILL_DIR}/../../standards/mermaid.md` for direction, node and edge budgets, `accTitle` and `accDescr`, and quoted labels. Do not work the layout or the budgets from memory.
|
|
13
|
+
- Read every node and subgraph label against the banned characters `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` lists. The audit hook skips every line inside a fence, so a label carrying a banned character passes silently while the same character in the caption is caught. Reading the labels is the only gate they have. A colon works as a replacement inside a label.
|
|
14
|
+
|
|
15
|
+
## Render
|
|
16
|
+
|
|
17
|
+
Render with the hand-drawn look and the figure font stack, writing scratch files under `.canon/tmp/figures/`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
mkdir -p .canon/tmp/figures
|
|
21
|
+
cat <<'EOF' >.canon/tmp/figures/<slug>.json
|
|
22
|
+
{"look": "handDrawn", "themeVariables": {"fontFamily": "Virgil, Excalifont, cursive"}}
|
|
23
|
+
EOF
|
|
24
|
+
bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.svg -c .canon/tmp/figures/<slug>.json
|
|
25
|
+
bunx -y @mermaid-js/mermaid-cli -i .canon/tmp/figures/<slug>.mmd -o .canon/tmp/figures/<slug>.png -c .canon/tmp/figures/<slug>.json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Render both formats in one pass. The SVG is what ships inside the `<figure>`, and the PNG is what the read-back below judges, since an SVG's markup carries no recoverable spatial meaning.
|
|
29
|
+
|
|
30
|
+
Use `bunx` when bun is available, falling back to `npx -y @mermaid-js/mermaid-cli ...` otherwise.
|
|
31
|
+
|
|
32
|
+
Before the first render in a project, say what is about to block:
|
|
33
|
+
|
|
34
|
+
```plaintext
|
|
35
|
+
Rendering to verify layout. The first run downloads the Mermaid CLI and takes about 15 seconds.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Rewrite the colors
|
|
39
|
+
|
|
40
|
+
Rewrite every stroke, fill, and text color the renderer wrote as a literal hex value into the custom property the host stylesheet defines, per the color rule in `${CLAUDE_SKILL_DIR}/../../standards/figures.md`. Mermaid's own theme has no notion of a custom property, so this is a source edit made to the rendered SVG, not a config option.
|
|
41
|
+
|
|
42
|
+
## Clipped titles
|
|
43
|
+
|
|
44
|
+
- Expect a group title or a long label to clip once the destination shows it in the hand font, since the renderer sized its box in a fallback face.
|
|
45
|
+
- When the in-page check shows a clipped title, add a `<style>` inside the SVG, scoped to that SVG's own id, that sets `overflow: visible` on the clipped label's `foreignObject` and centers the label within it, so the wider text spills past both edges evenly. The style hides the mismatch for a title and does nothing for a node label crowding its box, which takes a shorter label instead.
|
|
46
|
+
|
|
47
|
+
## Fonts
|
|
48
|
+
|
|
49
|
+
Check whether the project ran `canon design css --figures`. The figure and figcaption styling ships unconditionally either way, but that flag alone embeds the Virgil and Excalifont font files. Without it, the figure falls back to the browser's own generic `cursive` face rather than the intended hand-drawn font, and the output names that gap when the flag was not passed.
|
|
50
|
+
|
|
51
|
+
## Read the render back
|
|
52
|
+
|
|
53
|
+
- Read the rendered PNG and judge it against what the figure means to say, applying the verification properties in the mermaid standard. A source satisfying every rule there can still render as a picture asserting something false, so the image is what gets judged.
|
|
54
|
+
- Fix the Mermaid source and re-render on a defect. Stop after two correction passes. When a defect survives, keep the figure and name the defect in the output rather than reporting a false verification.
|
|
55
|
+
- When the render fails for any reason, no browser engine, no network, no package manager, continue to the confirm step and name the skipped check. A missing renderer degrades the loop rather than failing it.
|