napkin-sketchdocs 1.0.0 GitHub

The AI helpers#

On this page

API hub · Reference · Quickstart · Cheatsheet

Experimental. The AI helpers run an agentic AI command-line tool that napkin-sketch does not ship, on your account and at its cost. They are new, and their commands, forms and files may change in a minor release.

The graphic-designer helper reads a graphic you already have into a written design language, and generates a skill that draws new work in it through the graphic design API; the scripting helper writes a napkin script from a sentence. This page is the reference for plugging them in, capturing a language, using the skill it hands you, giving it your brand and drawing from a request - and for how an agent should read these pages and write the napkin scripts they describe.

Contents

What this is#

The helper is two skills and a command. design-language measures an asset and writes what it found as a DESIGN_LANGUAGE.md, then generates a skill named after the asset that carries the language, your brand's resources.md, and a script that composes new work in it; graphic-design-api carries the visual judgment that makes such work good. Everything the helper reports is measured from the file, and what a format cannot say, it says so.

The other half of this category is the reader. These pages are written for people and for agents alike: docs/api/INDEX.json maps every page with its size, each category has a cheatsheet and a quickstart that are shorter than its reference, and the command line hands the whole language over as JSON.

The scripting helper closes the loop from a sentence. Its napkin-script skill teaches an AI tool the language from the verb table, so napkin-sketch draw --prompt "a three-box flowchart with arrows" gets back a script the parser accepts; napkin-sketch checks it, sends it back once with its errors if it has any, keeps it beside the files, and draws it.

The mental model#

 a graphic you have --design-language--> DESIGN_LANGUAGE.md + a skill named after the graphic
                                                 |
 references/resources.md: your brand ------------+--> make-<stem>.mjs --> card.svg, card.png, ...
                                                 |
 references/graphic-design-api.json -------------+--> "/graphic-design-api <request>" picks a mode and draws

The helper measures and generates; the generated script draws with the composition API; the two files in references/ say what your brand is and which script a bare request runs.

 "a three-box flowchart with arrows" --draw --prompt--> _temp/script-form.txt
                                                               |
                         an AI tool, with the napkin-script skill
                                                               |
 checked as check checks it <----------------- _temp/script-out.napkin
     | errors: sent back once, with the script and its diagnostics
     v
 flowchart.napkin, kept, and drawn: flowchart.svg, flowchart.png, ...

Reference#

Plug in the helper#

The graphic-designer helper is what makes /graphic-designer:design-language a command you can type. There are two ways to get it, and they differ in more than convenience.

As a plugin (Claude Code)#

/plugin marketplace add .                              # from a clone
/plugin marketplace add isocialPractice/napkin-sketch  # without one
/plugin install graphic-designer@napkin-sketch

This is the delivery the plugin was designed for: the command, both skills, and the contract arrive as one addressable unit, and the skills answer to graphic-designer:design-language and graphic-designer:graphic-design-api. An npm install carries the helpers too, with the vectors helper's reference sheets and data named by address in each skill's assets/uri.md.

As files in your AI tool's folder#

npm run ai-helper -- --helper graphic-designer          # -> .claude
npm run ai-helper -- --helper graphic-designer --to github   # -> .github
npm run ai-helper -- --list                             # every target and helper

This copies the skills, the contract, and the command into that folder:

.claude/
├── commands/graphic-designer/design-language.md   ->  /graphic-designer:design-language
├── instructions/design-language.instructions.md
└── skills/
    ├── design-language/
    └── graphic-design-api/

The command lands in a folder named for the helper, so it answers to the same /graphic-designer:design-language either way. Paths inside it are rewritten on copy from the plugin-only ${CLAUDE_PLUGIN_ROOT} to the repository-relative folder, so the command's own instructions can be followed as written.

Which to choose. The plugin if your tool loads plugins; the files install for a tool that only reads a dot-folder, or when you want the skills visible in the working tree. Running both is fine but pointless - you get two copies of the same four files.

Capture a design language#

Point it at a graphic you already have. Anything the helper reports is measured from the file; what a format cannot say, it says so rather than guessing.

/graphic-designer:design-language test/graphic-design-api/reference-graphics/created-svg_graphic-api.svg

Add a destination when the file should land somewhere specific:

/graphic-designer:design-language path/to/asset.svg docs/design/

or in plain words - "write DESIGN_LANGUAGE.md to docs/design/" means the same thing.

That run does five things:

  1. Measures the asset. Palette, and for a vector also type, stroke widths, corner radii, and an element census.
  2. Finds where the brand sits. A vector whose layers are named logo, linkedMedia, tagline or brandName has marked its own slots; failing a name, the media is scanned a quarter of the page at a time, top first. The report says which of the two it was, because a name is exact and a scan is a guess.
  3. Writes a DESIGN_LANGUAGE.md into the destination - or DESIGN_LANGUAGE-<stem>.md when that directory already holds one, so a second asset never overwrites the first.
  4. Generates a skill named after the asset in your AI tool's skills folder, carrying that language, a references/resources.md for your brand, and a script that composes new work in it.
  5. Checks itself by analyzing what the generated script drew and comparing the palette against the source's.

Steps 1 to 4 are arithmetic, so they are also a plain CLI:

node ai-helper/graphic-designer/skills/design-language/scripts/generate-skill.mjs asset.svg --to .claude/skills

It asks before overwriting a skill that already exists, and it never overwrites a design language file - a reader's corrections are the most valuable thing in one.

Without an AI tool#

The measuring half is a plain CLI. Nothing about it needs a model:

node ai-helper/graphic-designer/skills/design-language/scripts/analyze-media.mjs asset.svg --colors 12
node ai-helper/graphic-designer/skills/design-language/scripts/analyze-media.mjs asset.svg --markdown

--markdown prints the body of a DESIGN_LANGUAGE.md: page size, palette with shares and guessed roles, type, strokes, corners, and the element census.

What each format can tell you#

FormatPaletteTypeStrokes, radii, structure
SVGyes, weighted by how often each class is referencedyesyes
PNGyes, decoded and quantized from the pixelsnono
JPEG, GIF, WebPno decodernono

Two things follow that are worth knowing before you read a report:

An empty palette always means "not measured", never "no colours" - and the report's notes say which.

Use the skill you were handed#

The helper generated a skill named after your asset. It is not documentation - it is a tool with a script in it. Here is the whole loop, using the asset this repository ships.

See what you got. .claude/skills/<stem>/ holds four things:

.claude/skills/<stem>/
├── SKILL.md                  when to reach for it, and the language in brief
├── DESIGN_LANGUAGE.md        every measurement, and every reading
├── references/
│   └── resources.md          your brand - see step 5
└── scripts/
    ├── make-<stem>.mjs       draws new work in that language
    └── brand-resources.mjs   resolves resources.md into placeable assets

Read DESIGN_LANGUAGE.md first, and specifically the parts that say which values were measured and which were read. The readings are the ones you may disagree with, and disagreeing with them is the point - in the shipped example the analyzer's guess about which colour was the ground was wrong, and the file says so and corrects it.

Draw the default.

node .claude/skills/<stem>/scripts/make-<stem>.mjs --out ./out

Look at out/card.png. It is deliberately plain. The point is not that it is interesting; the point is that it is in the language.

Change the content, not the language.

node .claude/skills/<stem>/scripts/make-<stem>.mjs \
  --title "Acme Corp" --heading "Quarterly Summary" --out ./out

The constants at the top of the script are the language - palette, type scale, page, spacing. Everything below them is layout. Changing a colour means editing one constant, and if you find yourself editing a colour further down, the script has drifted.

Draw something structurally different. A design language is not a template, and the way to prove that to yourself is to make it carry something the source never carried:

node .claude/skills/<stem>/scripts/make-<stem>.mjs --cheatsheet --out ./out

The worked example is test/graphic-design-api/generated-graphics/cheatsheet.png: an HTML reference in the language of a card that had no code in it at all.

Check yourself. This is the habit worth keeping:

node ai-helper/graphic-designer/skills/design-language/scripts/analyze-media.mjs out/card.png --colors 6

Compare the shares against the source's. Agreement on ground, paper and accent means you are still in the language. A right palette with a wrong ratio is the most common way a generated graphic goes subtly wrong, and the shares say so immediately where the eye does not.

Give it your brand#

The skill knows where a logo goes, because it measured that off the source asset's own layer names. It cannot know which logo, because that is not a property of the file it measured. One file closes the gap:

references/resources.md            the project's, and the one a request uses
.claude/skills/<stem>/references/resources.md   the skill's own snapshot

The project's is the one to edit. The skill carries a copy made when it was generated so it runs anywhere on its own, but a registered request always reads the project's.

- logo: assets/logo.svg
- GLOBAL_ASSETS: assets/brand/
- brand name: Acme Corp.
- domain: example.com
- tag line: This or That

A value with a folder separator or a media extension is a path; anything else is text to draw. That single rule is why example.com prints as a domain and assets/logo.svg is drawn as a file.

In a GLOBAL_ASSETS folder the file name is the slot it fills. logo.svg fills the logo, footer.png fills the footer, logo-mark.svg fills logoMark. There is no manifest, so adding an asset to the folder is the whole of adding it to the brand.

Check what resolved before wondering why a graphic looks wrong:

node .claude/skills/<stem>/scripts/brand-resources.mjs --print
resources: .claude/skills/<stem>/references/resources.md
  logo           assets/logo.svg -> /abs/path/assets/logo.svg
  footer         assets/footer.png -> /abs/path/assets/footer.png
  brandName      "Acme Corp."
configured: true

Being wired up#

generate-skill.mjs writes one more file as its last act:

references/
├── resources.md              what your brand is
└── graphic-design-api.json   which skill draws it, and what to draw by default

The second is the difference between a skill that exists and a skill that is usable without a manual. It records the script, the project's resources.md, the output folder, the modes the script can draw, and a defaultRequest - so a request can become a command with nothing else supplied:

node ai-helper/graphic-designer/skills/design-language/scripts/brand-resources.mjs --registration
registration: references/graphic-design-api.json
  skill:     created-svg_graphic-api
  script:    .claude/skills/created-svg_graphic-api/scripts/make-created-svg_graphic-api.mjs
  resources: references/resources.md
  output:    test/graphic-design-api/generated-graphics
  default:   "make a html cheatsheet. ensure to include linked assets"
  mode cheatsheet   --cheatsheet
  mode card
  run:       node .claude/skills/.../make-created-svg_graphic-api.mjs --cheatsheet --resources ... --out ...

Matching a request to a mode is deliberately dumb string matching - the request is read for a mode's own keywords, and the default wins when none appear. That is why /graphic-design-api generate works: generate contains no mode keyword, so it falls through to whatever defaultRequest says. Anything cleverer would need a model, and the point of this file is to be the part that does not.

Two flags worth knowing:

Four things worth knowing#

Symlinked asset folders#

A brand folder is often a link to somewhere else. That works, and the two fixtures in test/graphic-design-api/test-assets/ are exactly that - git symlinks into reference-graphics/links/. One rule makes them portable: a symlink's target is resolved from the link's own directory, so it reads ../reference-graphics/links/logo.svg and never test/graphic-design-api/reference-graphics/links/logo.svg. A repository-root path resolves on no clone at all, and because a missing asset falls back rather than failing, the graphics come out looking plausible and wrong.

git ls-files -s test/graphic-design-api/test-assets/
# 120000 <sha> 0  test/graphic-design-api/test-assets/logo.svg

Mode 120000 and a forward-slash relative target is what makes a link resolve on a Linux clone and render as a link on GitHub.

Two things about the raster#

Both come from the same root - one set of coordinates, two renderers with different font metrics - and both are worth knowing before you are surprised by them:

Reading these pages as an agent#

Writing napkin scripts that read clean#

Patterns that give scripts the parser accepts the first time:

napkin 1
page 400 300
background #ffffff
layer "Card"
color #1f2328 width 3 fill #ffe08a
rect 20 20 360 260 r 16
text "Acme Corp" at 200 130 size 32 align center

Drawing from a request#

napkin-sketch draw --prompt "<request>" asks an AI tool for the script instead of reading one, and draws it like any other:

napkin-sketch draw --prompt "a three-box flowchart with arrows" --to svg,png

It needs an agentic AI command-line tool on the PATH, and works best with the scripting helper plugged in, which is how the tool learns the language: /plugin install scripting@napkin-sketch, or npm run ai-helper -- --helper scripting for the files.

Inside an AI tool, /scripting:draw a three-box flowchart with arrows writes the script as flowchart.napkin in the working folder, and the same command with no request answers a form napkin-sketch left.

Asking well. The tool reads the request and nothing else, so a request that says what matters draws it the first time:

Troubleshooting#

SymptomCauseFix
Unknown command: /graphic-designer:design-languageThe helper is not plugged inStep 2
PNG palette empty, note mentions the APIThe build output was not foundnpm run build in the clone
graphic-design API not found from a generated scriptSame cause, from the other directionnpm run build, or install @isocialpractice/napkin-sketch
The command runs but writes the file somewhere unexpectedNo destination was givenPass one, or name it in words
A second run overwrote nothing and made DESIGN_LANGUAGE-<stem>.mdWorking as intendedThat directory already had one
Generated graphic does not look like the sourceThe script drifted from the languageAnalyze the output, compare the shares, fix the script - not the design language file
The graphic is mostly backgroundA paper element is missingThe shares say so at once; compare them against the source's
The last line of a listing is missingIt rendered under the footerLook at the PNG, not the SVG - the vector will not show you
Text runs overlap in the SVG but look fine in the PNGRuns were advanced by measureTextAdvance by the named font's metric: 0.6 em per character for monospace
Small text in the PNG is grey mushThe stroke is under a device pixelRaster at --scale 2 or 3
Colours are right, the graphic still looks wrongThe palette is right and the ratio is notCheck the shares against the 60-30-10 the language declares
Editing a colour changed nothingIt was edited in the composition, not in the constantsThe constants at the top of the script are the language
A monogram is drawn where the logo should beThe declared asset did not resolvenode scripts/brand-resources.mjs --print names the path that failed
The logo is in the SVG and missing from the PNGIt was placed as an image rather than inlinedPlace it through brand.place, and read the warnings
A copied resources.md stopped finding anythingIts relative paths were not rewritten for the new locationRewrite them, or copy with generate-skill.mjs --resources
/graphic-design-api generate says nothing is wired upNo registration above the working directoryRun generate-skill.mjs, or npm run test:graphic-design-api for the shipped example
A request draws the wrong thingIt matched a different mode's keyword--registration prints the modes and what each one answers to
The registration names a script that is goneThe skill was deleted or regenerated elsewhereRe-run generate-skill.mjs; usable: false is what the reader reports
A symlinked asset resolves for you and nobody elseThe link stores a repository-root pathRetarget it relative to the link's own directory
The ground and the paper look swappedRoles were read off the reference-weighted paletteUse the Palette by area table; area is what "the ground" means
draw --prompt exits 4, missing-toolThe AI tool is not on the PATHInstall it, or name another with --helper or NAPKIN_SCRIPT_HELPER
draw --prompt exits 4, authThe tool is installed and not signed inRun the tool once in a terminal and sign in
draw --prompt exits 4, no-scriptThe tool finished without saving or printing a scriptPlug in the scripting helper; its skill says where to save
The drawing is not what was meantThe request left it openSay what it holds, its size and its colors; or edit the kept .napkin

Worked examples#

A design language, measured and read. test/graphic-design-api/design-language/DESIGN_LANGUAGE.md is a real run of this against test/graphic-design-api/reference-graphics/created-svg_graphic-api.svg. It is worth reading for one reason: the analyzer's mechanical guess about the colour roles was wrong, and the file says so and corrects it from the raster cross-check. That is the intended division of labour - the tool measures, you read - and a design language that hides which half is which is not worth keeping.

That particular correction is now made for you. The analyzer renders the vector and counts how much page each colour covers, reports it as a second table, and decides the roles from that rather than from how often each colour is referenced - because "which colour is the ground" is an area question. Both measurements stay in the file. The reading still belongs to you; there is just one fewer wrong default to catch.

test/graphic-design-api/generated-graphics/ holds what npm run test:graphic-design-api draws: the same language as a card and as an HTML cheatsheet, both carrying the logo and footer that resources.md names.

A request, drawn and kept. With the scripting helper plugged in:

napkin-sketch draw --prompt "a three-box flowchart - Plan, Build, Ship - with arrows, call it flowchart" --to svg,png

prints flowchart.napkin, flowchart.svg and flowchart.png, and the script is one like the first of the napkin-script skill's three examples - boxes, labels and arrows each on a layer of their own. What a tool writes varies from run to run; what it saved does not, so napkin-sketch draw flowchart.napkin draws the same picture again with no AI at all.

A script an agent wrote, checked, then drawn. An agent hands a script over on standard input, reads the diagnostics as JSON, and draws once it checks clean:

napkin-sketch check - --json < card.napkin      # {"ok":true,...} or the diagnostics to fix
napkin-sketch draw - --json --to svg,png < card.napkin

Limits#

For agents#

See also#