agentsclimarketplace

Excalidraw diagram

Skill aeonbook/aeon-excalidraw-diagram/skills/excalidraw-diagram

Aeon skill: beautiful two-color Excalidraw diagrams from drawfiles, machine-validated

Install
npx -y skills add aeonbook/aeon-excalidraw-diagram --skill excalidraw-diagram

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Generate a beautiful two-color .excalidraw v2 scene from a drawfile. Strict design system (black + one accent + neutrals), machine-validated. Renderable in any React app, exportable to SVG/PNG, no live canvas required.

SKILL.md

15.0 KB, as published. Nobody here has run it

${var} — REQUIRED. A drawfile slug. Must match an existing drawfiles/<slug>.drawfile at the repo root. If no drawfile exists, the skill aborts with EXCALIDRAW_NO_DRAWFILE and prints the scaffold command.

Today is ${today}. Your task: read a drawfile, generate a .excalidraw v2 scene file via a script-driven path that uses only the pattern helpers, then pass the result through a machine validator. If the validator fails after one fix pass, abort cleanly. The output is portable JSON renderable anywhere (excalidraw.com, the @excalidraw/excalidraw React component, server-side SVG/PNG exporters).

Mental model

You are NOT drawing on a live canvas. You are writing a JavaScript generate script that imports references/render-helpers.mjs and emits a v2 .excalidraw file. The script becomes a reproducible artifact — re-running it must produce the same scene. Authoring raw JSON is off the table; the helpers handle defaults, the design system, and grid snapping for you. The validator catches anything the helpers don't.

drawfile  →  Step 1 parse  →  Step 2 plan + budget check  →  Step 3 generate-script.mjs  →
                                                                       │
                                                                       ▼
                                                                  .excalidraw JSON file
                                                                       │
                                                                       ▼
                              Step 4 machine validator (PASS) ─── Step 5 article + log + notify
                                       │
                                       ▼  FAIL ─→ fix → re-validate → FAIL again → EXCALIDRAW_VALIDATION_FAILED

HARDCODED design system (read every run)

Before doing anything else, read references/design-system.md. Rules there override every other consideration:

  • Strict two-color rule: black #1e1e1e for ALL strokes + text; ONE accent from six palettes; neutrals (#ffffff, #f8fafc, #64748b, transparent) for everything else. No other hex codes anywhere.
  • 60-30-10: 60% whitespace + neutrals, 30% accent, 10% black.
  • Universal defaults: roughness: 1, roundness: { type: 3 }, strokeWidth: 2-3.
  • Grid: shape x, y, width, height snap to multiples of 20 (prefer 40 / 60).
  • Typography: title 32-40, headers 24-28, body 18-20, notes 14-16. fontFamily 1 (Virgil) default.
  • Hierarchy via size + position FIRST, color SECOND.

If you feel tempted to reach for a second accent, shrink margins, or fudge a coordinate — STOP. The helpers and validator are the authority, not your judgment.

Reference files (read in this order)

FileWhen
references/design-system.mdEvery run, first.
references/drawfile-spec.mdStep 1, to parse the drawfile.
references/catalog.mdStep 2, to confirm diagram type + see element-cost range.
references/patterns.mdStep 2 (budget math) + Step 3 (composition).
references/schema.mdStep 3 only if you need to look up a field.
references/render-helpers.mjsStep 3 — imports for the generate script.
examples/aeon-self-heal.generate.mjsStep 3 — canonical reference for what a good generate script looks like. Read this before writing your own.
examples/aeon-self-heal.excalidrawThe known-good output paired with the script above.

Steps

1. Parse the drawfile

DRAWFILE="drawfiles/${var}.drawfile"

If ${var} is empty:

./notify "excalidraw-diagram aborted: var empty — pass a drawfile slug"

Exit with EXCALIDRAW_NO_VAR.

If the file does not exist at drawfiles/${var}.drawfile:

./notify "excalidraw-diagram aborted: drawfiles/${var}.drawfile not found. Bootstrap one with: ./skills/excalidraw-diagram/scaffold-drawfile ${var}"

Exit with EXCALIDRAW_NO_DRAWFILE. Do not attempt to interpret ${var} as a catalog slug or free-form spec — drawfile is the only input mode.

Read the drawfile per references/drawfile-spec.md. Extract:

  • Frontmatter: slug, diagram_type, palette, canvas, audience, font, style_ref, constraints (structured), sources.
  • Body sections: Subject, What to show, Context, Emphasis, Notes.
  • For each path in sources, read the file (fail with EXCALIDRAW_DRAWFILE_SOURCE_MISSING if any is absent — never silently proceed without context).
  • Validate palette is one of the six valid names. Validate constraints keys are recognized. Invalid → EXCALIDRAW_DRAWFILE_INVALID.
  • If style_ref is set and the referenced article exists, read it.

If diagram_type is absent, pick one via the picker table at the bottom of catalog.md based on Subject + What to show.

If palette is absent, pick one via design-system.md §2 keyword rules (default modernTeal).

2. Plan + budget check (do BEFORE generating)

Read context: memory/MEMORY.md, any sources listed in the drawfile, soul/STYLE.md if present (for article voice; the diagram itself stays design-system-locked).

Compose your patterns on paper. Sketch tier-by-tier (y bands) and column-by-column (x bands) inside a scratch comment block. All coordinates multiples of 40 (or 60 on larger canvases). Whitespace margins ≥ min_whitespace_margin on every side.

Then do the element-count math using the pattern costs from patterns.md. Example:

A1 architecture composition:
  1 P11 title                          1
  3 P1 lanes (2 each)                  6
  6 P2 sub-cards w/ bound label        6
  2 P4 action buttons                  4
  5 P10 numbered steps + 4 arrows     14
  1 P11 section header                 1
                                    ─────
                                       32

If your total > constraints.max_elements, you have a choice:

  • Drop a section (lose the file row, the function lists, etc.)
  • Raise max_elements in the drawfile (if the operator's budget was unrealistic — but flag this; usually the drawfile is right)

Do not start generation until the math works. If you cannot get the composition under budget without dropping the diagram's intent:

./notify "excalidraw-diagram aborted: composition for ${var} requires N elements but max_elements=M. Drop sections or raise max_elements in drawfile."

Exit with EXCALIDRAW_BUDGET_EXCEEDED.

3. Write the generate script (NOT raw JSON)

Create scripts/generate-<slug>.mjs at the repo root (NOT in skills/). This is the canonical artifact — committed alongside the .excalidraw file, re-runnable, diffable.

Read examples/aeon-self-heal.generate.mjs before writing your own to see the exact shape. Hard requirements:

  1. Imports from skills/excalidraw-diagram/references/render-helpers.mjs — primitives, pattern helpers, PALETTES, buildSceneFile. No direct hex codes; always reference PAL.accent, PAL.lightTint, neutrals.*.
  2. Resets ids at start (ex.resetIds()).
  3. Picks the palette via PALETTES[<name>] matching the drawfile.
  4. Uses pattern helpers (lane, subCard, flowStep, pill, actionButton, fileCard, sectionHeader, boundArrow, curveArrow, msgArrows, fanOutArrow) — NOT raw primitives, unless a primitive is the natural choice (e.g. a single decorative line).
  5. All coordinate inputs are multiples of 40 (preferred) or 60 (multiples of 20 minimum). The helpers _assertGrid() throws if you pass anything else.
  6. For step-and-arrow flows: override the auto-generated rect id with a stable one (e.g. stepRect.id = 'step_3') so subsequent boundArrow calls can reference it. Also set stepText.containerId = stepRect.id so the validator can associate labels with shapes.
  7. Builds the scene with buildSceneFile(els, { backgroundColor: '#ffffff' }).
  8. Emits the JSON on stdout: console.log(JSON.stringify(scene, null, 2));

Then run it:

node scripts/generate-<slug>.mjs > diagrams/<slug>-${today}.excalidraw

If the script throws (likely from _assertGrid catching a non-snapped coord), fix the offending input in the script and re-run. Never silence the assertion — the assertion is the design system enforcing itself.

4. Machine quality gate (MANDATORY — run, don't think)

Run the validator. Do NOT skip this and claim the diagram looks fine. Do NOT mental-walkthrough the rules. The validator is the source of truth.

node skills/excalidraw-diagram/scripts/validate.mjs \
  diagrams/<slug>-${today}.excalidraw \
  drawfiles/${var}.drawfile

The validator prints structured JSON to stdout and exits non-zero on any violation. Read the JSON, look at violations[] — each violation has element_id, rule, expected, actual, fix_hint. Fix each one element-by-element in the generate script (not by hand-editing the .excalidraw file), then re-run the generate script + validator.

The retry loop is exactly one pass. After the first re-run:

  • If validator exits 0 → continue to Step 5.
  • If validator exits 1 again → abort.

Abort sequence on second failure:

  1. Move the failed scene and the generate script to memory/excalidraw-failures/${today}-<slug>/ for post-mortem.
  2. Append the violation list to the failure dir as violations.json.
  3. Delete diagrams/<slug>-${today}.excalidraw.
  4. ./notify "excalidraw-diagram FAILED for ${var}: <violation summary>. Failure artifacts at memory/excalidraw-failures/${today}-<slug>/"
  5. Exit EXCALIDRAW_VALIDATION_FAILED.

Do not ship a non-compliant diagram. Aborting cleanly is always better than committing broken output.

5. Write the companion article

Only after step 4 passes. Write articles/<slug>-${today}.md:

# <Diagram title>

*<one-sentence subtitle>*

![<title>](../diagrams/<slug>-${today}.excalidraw)

## What this shows
<2-3 sentences. The thesis, not a caption.>

## Reading guide
- **<focal element>**: <what it does, why focal>
- <secondary element 1>: <role>
- <secondary element 2>: <role>
- <key arrow / flow>: <what it represents>

## Built with
- Diagram type: <catalog slug> (<diagram type name>)
- Palette: <palette name> (accent `<hex>`)
- Canvas: <W>×<H>
- Audience: <audience>
- Drawfile: `drawfiles/<slug>.drawfile`
- Generate script: `scripts/generate-<slug>.mjs`
- Element count: <N> (budget: <max_elements>)
- Validator: PASS

If soul/ is populated, match its voice in the prose sections. The diagram itself stays design-system-locked regardless of voice.

6. Log

Append to memory/logs/${today}.md:

### excalidraw-diagram
- Slug: <slug>
- Drawfile: drawfiles/<slug>.drawfile
- Diagram type: <catalog slug>
- Palette: <name> (accent <hex>)
- Canvas: <W>×<H>
- Element count: <N> / <max_elements>
- Validator: PASS (1st try) | PASS (after 1 fix) | FAILED (twice)
- Generate script: scripts/generate-<slug>.mjs
- Scene file: diagrams/<slug>-${today}.excalidraw
- Article: articles/<slug>-${today}.md
- Status: EXCALIDRAW_OK

7. Notify

*excalidraw-diagram — <title>*
<one-sentence subtitle>
Type: <catalog slug> · Palette: <name> · <N> elements (validated)

Scene: <repo-url>/blob/main/diagrams/<slug>-${today}.excalidraw
Article: <repo-url>/blob/main/articles/<slug>-${today}.md
Script: <repo-url>/blob/main/scripts/generate-<slug>.mjs

Under 4000 chars. Don't paste the JSON.

Exit taxonomy

CodeWhenAction
EXCALIDRAW_OKScene + article written, validator PASSNotify with links
EXCALIDRAW_NO_VAR${var} emptyNotify abort reason; stop
EXCALIDRAW_NO_DRAWFILEdrawfiles/${var}.drawfile doesn't existNotify with scaffold command; stop
EXCALIDRAW_DRAWFILE_INVALIDFrontmatter unparseable, invalid palette, malformed constraintsNotify with parse error; stop
EXCALIDRAW_DRAWFILE_SOURCE_MISSINGA sources: file doesn't existNotify with missing path; stop
EXCALIDRAW_BUDGET_EXCEEDEDComposition estimate exceeds max_elements, no clean dropNotify with N vs M; stop
EXCALIDRAW_VALIDATION_FAILEDValidator fails twice (one fix pass attempted)Persist failure artifacts; delete partial scene; notify; stop

Inline invocation contract (for other skills calling this one)

When another skill needs to embed a diagram, it can inline-invoke this skill rather than dispatching a separate workflow.

Caller writes:

  • .outputs/excalidraw-brief.md — a drawfile-format file. Same schema as drawfiles/<slug>.drawfile.

Caller invokes:

  • Reads skills/excalidraw-diagram/SKILL.md
  • Executes steps 2-7 with .outputs/excalidraw-brief.md as input (skip step 1's var parsing — the brief replaces it).

Caller reads back:

  • .outputs/excalidraw-result.json{ diagramPath, articlePath, scriptPath, elementCount, palette, exitCode }

The caller embeds diagramPath in its own output (e.g. the article it's writing).

Sandbox note

This skill is fully offline. No curl, no WebFetch, no MCP, no canvas server. The only I/O:

  1. Read references/*.md, references/render-helpers.mjs, examples/* (skill files)
  2. Read drawfiles/${var}.drawfile and any sources: files
  3. Read memory/MEMORY.md, optionally memory/topics/*.md, soul/*.md
  4. Execute node scripts/generate-<slug>.mjs — runs JS in the sandbox; allowed and required.
  5. Execute node skills/excalidraw-diagram/scripts/validate.mjs — same.
  6. Write diagrams/<slug>-${today}.excalidraw, articles/<slug>-${today}.md, scripts/generate-<slug>.mjs
  7. Append to memory/logs/${today}.md
  8. On failure: write memory/excalidraw-failures/${today}-<slug>/{generate.mjs, scene.failed.excalidraw, violations.json}
  9. Call ./notify

The two node invocations replace what used to be mental walkthroughs. They are mandatory, not optional.

Constraints (don't break)

  • One diagram per run. If the spec implies multiple, pick the most important and mention the others as candidates in the article footer.
  • Never bypass the validator. Claiming "the diagram looks fine" without validate.mjs exit 0 is a process violation. The skill ships only what the machine says is correct.
  • Never author raw JSON. Always go through scripts/generate-<slug>.mjs using the helpers. Raw JSON authoring is how mental-math grid errors get past the helpers' guards.
  • Never call a canvas server. This skill never talks to localhost:3000 or localhost:8080. The output is a file, not a side effect.
  • Never invent color hexes. The seven valid hexes per diagram are: #1e1e1e, #ffffff, #f8fafc, #64748b, transparent, plus the chosen palette's accent and lightTint. Validator enforces.
  • Drawfile is contract. Constraints in the drawfile (max_elements, max_title_chars, required_focal, …) are hard fails, not suggestions. If the operator's budget is impossible, EXCALIDRAW_BUDGET_EXCEEDED and let them fix the drawfile.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.