AgentStack
SKILL verified MIT Self-run

Excalidraw Diagram

skill-aeonbook-aeon-excalidraw-diagram-excalidraw-diagram · by aeonbook

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.

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-aeonbook-aeon-excalidraw-diagram-excalidraw-diagram

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Excalidraw Diagram? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

> ${var} — REQUIRED. A drawfile slug. Must match an existing drawfiles/.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)

| File | When | |---|---| | references/design-system.md | Every run, first. | | references/drawfile-spec.md | Step 1, to parse the drawfile. | | references/catalog.md | Step 2, to confirm diagram type + see element-cost range. | | references/patterns.md | Step 2 (budget math) + Step 3 (composition). | | references/schema.md | Step 3 only if you need to look up a field. | | references/render-helpers.mjs | Step 3 — imports for the generate script. | | examples/aeon-self-heal.generate.mjs | Step 3 — canonical reference for what a good generate script looks like. Read this before writing your own. | | examples/aeon-self-heal.excalidraw | The 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-.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[] 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-.mjs > diagrams/-${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/-${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}-/ for post-mortem.
  2. Append the violation list to the failure dir as violations.json.
  3. Delete diagrams/-${today}.excalidraw.
  4. ./notify "excalidraw-diagram FAILED for ${var}: . Failure artifacts at memory/excalidraw-failures/${today}-/"
  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/-${today}.md:

# 

**

## What this shows

## Reading guide
- ****: 
- : 
- : 
- : 

## Built with
- Diagram type:  ()
- Palette:  (accent ``)
- Canvas: ×
- Audience: 
- Drawfile: `drawfiles/.drawfile`
- Generate script: `scripts/generate-.mjs`
- Element count:  (budget: )
- 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: 
- Drawfile: drawfiles/.drawfile
- Diagram type: 
- Palette:  (accent )
- Canvas: ×
- Element count:  / 
- Validator: PASS (1st try) | PASS (after 1 fix) | FAILED (twice)
- Generate script: scripts/generate-.mjs
- Scene file: diagrams/-${today}.excalidraw
- Article: articles/-${today}.md
- Status: EXCALIDRAW_OK

7. Notify

*excalidraw-diagram — *

Type:  · Palette:  ·  elements (validated)

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

Under 4000 chars. Don't paste the JSON.

Exit taxonomy

| Code | When | Action | |---|---|---| | EXCALIDRAW_OK | Scene + article written, validator PASS | Notify with links | | EXCALIDRAW_NO_VAR | ${var} empty | Notify abort reason; stop | | EXCALIDRAW_NO_DRAWFILE | drawfiles/${var}.drawfile doesn't exist | Notify with scaffold command; stop | | EXCALIDRAW_DRAWFILE_INVALID | Frontmatter unparseable, invalid palette, malformed constraints | Notify with parse error; stop | | EXCALIDRAW_DRAWFILE_SOURCE_MISSING | A sources: file doesn't exist | Notify with missing path; stop | | EXCALIDRAW_BUDGET_EXCEEDED | Composition estimate exceeds max_elements, no clean drop | Notify with N vs M; stop | | EXCALIDRAW_VALIDATION_FAILED | Validator 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/.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-.mjs — runs JS in the sandbox; allowed and required.
  5. Execute node skills/excalidraw-diagram/scripts/validate.mjs — same.
  6. Write diagrams/-${today}.excalidraw, articles/-${today}.md, scripts/generate-.mjs
  7. Append to memory/logs/${today}.md
  8. On failure: write memory/excalidraw-failures/${today}-/{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-.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 (maxelements, maxtitlechars, requiredfocal, …) are hard fails, not suggestions. If the operator's budget is impossible, EXCALIDRAW_BUDGET_EXCEEDED and let them fix the drawfile.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.