Skip to content

sahajamoth/scrawl

Repository files navigation

scrawl

npm license

Hand-drawn diagrams from plain text. 57% fewer tokens than Mermaid.

Scrawl is a compact, line-oriented diagram format that renders to hand-drawn SVGs. Designed for LLM generation, documentation, and anywhere you want diagrams that feel human.

Version 0.5.0 adds chart mode, explicit sequence branching with fork / join, note callout leaders, and richer structured-workflow examples.

Why scrawl?

lr                                          flowchart LR
push(Git Push)~blue->ci(Run Tests)            push[Git Push]:::blue --> ci[Run Tests]
ci->build(Build)|pass                         ci -->|pass| build[Build Image]
ci=>fail(Notify)~red|fail                     ci -.->|fail| fail[Notify]:::red
build->gate{Approve?}                         build --> gate{Approve?}
gate->prod(Deploy)~green|yes                  gate -->|yes| prod[Deploy]:::green
gate=>fail|no                                 gate -.->|no| fail
                                              classDef blue fill:#3182ce33,stroke:#3182ce
~57 tokens                                    classDef green fill:#38a16933,stroke:#38a169
                                              classDef red fill:#e53e3e33,stroke:#e53e3e
                                              ~129 tokens

Same diagram. 56% fewer tokens. Colors are inline (~blue), not separate classDef blocks. Edge labels are inline (|pass), not -->|pass|. Dashed edges are =>, not -.->.

CI/CD Pipeline (sketch preset)

CI/CD Pipeline diagram

source
lr
push(Git Push)~blue->ci(Run Tests)
ci->build(Build Image)|pass
ci=>fail(Notify Team)~red|fail
build->staging(Deploy Staging)~orange->gate{Approve?}
gate->prod(Deploy Prod)~green|yes
gate=>fail|no

Microservices (architect preset)

Microservices diagram

source
td
gw(API Gateway)~purple->{auth(Auth Service),users(User Service),orders(Order Service)}
users->db_u[(Users DB)]~orange
orders->db_o[(Orders DB)]~orange
orders->queue:Event Bus~blue|emit
queue=>notify(Notify Service)|subscribe

Auth Flow (rough preset)

Auth flow diagram

source
td
user((User))->login(Login Form)~blue->check{Valid?}
check->mfa(MFA Challenge)~orange|yes
check=>lock(Lock Account)~red|no
mfa->token(Issue JWT)~green|valid
mfa=>lock|invalid

API Request Lifecycle (clean preset)

API lifecycle diagram

source
lr
client((Client))->lb(Load Balancer)~blue->mw(Middleware)~purple->router{Router}
router->ctrl(Controller)~blue|matched
router=>error(Error Handler)~red|unmatched
ctrl->svc(Service Layer)->repo(Repository)->db[(Database)]~orange

Wireframe Dashboard (wireframe mode, rough preset)

Wireframe dashboard sketch

Wireframe Minimal

Minimal wireframe example

Wireframe Style Gallery

sketch rough clean
architect blueprint
source
wireframe
style rough
screen app:Dashboard 1360x940
  header top:Product Header
    text top_nav_overview:Overview
    text top_nav_customers:Customers
    text top_nav_billing:Billing
    button invite:Invite
  sidebar side_nav:Main Nav
    list menu:Navigation
  column content:Dashboard
    row stats:Stats
      card revenue:Revenue
      card mrr:MRR
      card churn:Churn
    row body:Body
      panel signup:Signup Flow
        input name:Full Name
        input email:Email
        textarea notes:Notes
        button create:Create User
      panel preview:Preview
        image hero:Wireframe Preview
        text copy:Marketing Copy

Quick start

npm install -g scrawl-cli
echo 'lr\na(Start)~blue->b(End)~green' | scrawl > diagram.svg

Or use as a library:

npm install scrawl-core

Syntax in 60 seconds

td                          # direction: td, lr, rl, dt
a:Label->b:Label            # edge with labels
a(Rounded)                  # shape: () rounded
a((Circle))                 # shape: (()) circle
a{Diamond}                  # shape: {} diamond
a[(Cylinder)]               # shape: [()] cylinder
a->b|edge label             # edge label after pipe
a=>b                        # dashed edge
a..>b                       # dotted edge
a<->b                       # bidirectional
a->{b,c,d}                  # fan-out
a~blue                      # color: red blue green yellow purple orange pink gray teal cyan
[Group Name: a b c]         # group nodes
# this is a comment

Wireframe mode

Use wireframe as the first line to switch from graph layout to UI sketch layout.

wireframe
screen landing:Landing Page 1440x960
  header top:Header
    text brand:Acme
    button cta:Get Started
  column hero:Hero
    text headline:Big Promise
    row actions:Actions
      button primary:Start Trial
      button secondary:Talk to Sales

Supported first-pass wireframe components:

  • screen
  • header
  • sidebar
  • row
  • column
  • panel
  • card
  • button
  • input
  • textarea
  • image
  • text
  • list

Wireframe flows can also take explicit route turns when auto-routing is not enough:

wireframe
screen desk:Desk 1280x900
  card start:Start
  modal confirm:Confirm
flow start -> confirm route=right,down,left | guided
flow confirm -> start turns=up left left
flow review -> publish route=left*2,down:140,right | long detour

Route actions are absolute orthogonal directions: up, down, left, right.

  • left*2 repeats the default step twice
  • down:140 uses an explicit pixel distance
  • plain left / down still use the default step

Sequence mode

Use sequence to render long ordered step lists as chained blocks. Add wrap=N to bend the sequence into serpentine rows instead of one long strip.

sequence wrap=4 snake=horizontal rowgap=90 colgap=28
style architect
brief:Brief->draft:Draft->review:Review->revise:Revise->approve:Approve->package:Package->publish:Publish->measure:Measure

You can still declare one step per line, but graph-style chains like A->B->C->D work directly. With wrap=4, the first four steps flow left-to-right, the next four flow right-to-left, and row transitions connect vertically at the edge.

Header options:

  • wrap=N limits how many steps go on one row before the serpentine turn
  • snake=horizontal|vertical chooses whether the snake advances by rows or by columns
  • rowgap=N increases or tightens spacing between rows
  • colgap=N increases or tightens spacing between columns

Transition labels also work inline on chained sequence edges:

sequence wrap=3
triage->debug|investigate->fix|patch->ship

Use phase and lane to mark semantic sections. They render as labeled group regions behind the relevant steps:

sequence wrap=3 snake=vertical
phase setup:Setup
A->B->C
lane review:Review Lane
C->D->E

Use notes for annotations that should stay attached to a step without becoming part of the main chain:

sequence wrap=3
A->B->C
note right of B:Wait for reviewer
note over C:Deploy window

Sequence notes now avoid overlapping nearby step boxes, which matters most in wrapped fork/join flows.

Use fork and join when the process fans out into parallel review lanes and later reconverges:

sequence wrap=3 snake=horizontal rowgap=100 colgap=26
phase intake:Intake and triage
intake:Intake->draft:Draft
fork draft -> legal:Legal Review, security:Security Review
lane release:Release lane
join legal, security -> approve:Approve
approve->ship:Ship
note right of approve:Final sign-off\nand release window
note over security:Parallel checks stay visible

Sequence branching example

Use break when you want to force a new row before the next step:

sequence wrap=4
triage:Triage->debug:Debug->fix:Fix
break
verify:Verify->ship:Ship

Chart mode

Use chart as the first line to render lightweight hand-drawn charts without dropping to coordinates.

Supported chart kinds:

  • bar
  • line
  • area
  • scatter
  • pie

Bar, line, and area charts use numeric series values:

chart
style blueprint
kind bar
title Revenue by Quarter
xlabel Quarter
ylabel Revenue
categories Q1, Q2, Q3, Q4
series Revenue: 12, 18, 15, 22
series Plan: 10, 14, 16, 20

Supported chart kinds:

  • Axis and combo: bar, line, area, scatter, combo, waterfall, dot, box, tornado, likert
  • Slice and radial: pie, donut, radar, radial-bar, gauge
  • Matrix and hierarchy: heatmap, treemap, sunburst
  • Flow and stage: sankey, funnel

Common chart controls:

  • legend right|top|bottom|none
  • grid none|x|y|both
  • points show|hide|auto
  • labels show|hide|auto
  • curve linear|smooth|step
  • stack grouped|stacked|percent
  • xticks N, yticks N, y2ticks N
  • xmin, xmax, ymin, ymax, y2min, y2max
  • ref x|y|y2 ...
  • annotate x,y: Label

Series lines can carry per-series options:

series Revenue [type=bar color=#2563eb]: 12, 18, 24
series Conversion [type=line axis=right color=#16a34a curve=smooth labels=show]: 2.1, 2.8, 3.4

Example combo chart with a secondary axis, target line, and annotation:

chart
style blueprint
kind combo
title Revenue vs Conversion
xlabel Month
ylabel Revenue
legend top
grid both
labels auto
y2ticks 4
categories Jan, Feb, Mar, Apr
ref y 20 label=Target color=#ef4444
annotate Mar,24:Peak color=#0f172a
series Revenue [type=bar color=#2563eb]: 12, 18, 24, 28
series Conversion [type=line axis=right color=#16a34a curve=smooth labels=show]: 2.1, 2.8, 3.4, 3.9

Stacked and percent-stacked bars/areas use stack stacked or stack percent:

chart
style architect
kind bar
stack percent
title Revenue Mix by Quarter
ylabel Revenue Share
legend top
grid y
categories Q1, Q2, Q3, Q4
series Product: 12, 16, 18, 22
series Services: 8, 9, 11, 14
series Support: 4, 5, 6, 7

Scatter charts use x,y point pairs separated by semicolons:

chart
kind scatter
title Activation vs Retention
xlabel Activation
ylabel Retention
series Cohort A: 12,34; 18,29; 24,41; 30,48
series Cohort B: 10,22; 16,26; 20,24; 28,33

Pie and donut charts use categories plus one series of slice values, or multiple one-value series:

chart
style rough
kind donut
title Revenue Mix
legend right
categories Product, Services, Support, Training
series Mix: 40, 30, 20, 10

Special data forms:

  • Heatmap cells: cell Row,Column: 91
  • Sankey flows: flow leads -> demo: 48
  • Treemap / sunburst hierarchy: item Product/API: 32
  • Gauge thresholds: threshold 85 #f59e0b Watch

Gauge charts render on a centered upper arc so threshold bands and the needle stay aligned inside the frame.

Bar chart example

Area chart example

Stacked bar chart example

Scatter chart example

Pie chart example

Donut chart example

Combo chart example

Heatmap chart example

Sankey chart example

Gauge chart example

Treemap chart example

Style presets

One input, five visual styles — same diagram (a(Start)~blue->b{Check}->c(Done)~green / b=>d(Error)~red):

sketch (default) rough clean
wabi-sabi art brut geometric
architect blueprint
drafting engineering
import { renderDiagram } from 'scrawl-core'

const svg = renderDiagram('lr\na->b->c', { style: 'architect' })
scrawl render diagram.scrawl --style architect > diagram.svg

Each preset controls roughness, bowing, stroke width variation, arrowhead style, text wobble, edge curvature, double-line mode, and corner overshoot. Per-element seed derivation ensures every shape has unique character while remaining deterministic.

Packages

Package Description
Package Install
--------- ---------
scrawl-core npm i scrawl-core
scrawl-cli npm i -g scrawl-cli
remark-scrawl npm i remark-scrawl
scrawl-web
scrawl-vscode

Use it everywhere

Markdown docs — remark-scrawl plugin renders code blocks as inline SVGs:

```scrawl
td
a(Start)->b{Check}->c(Done)~green
b=>d(Error)~red
```

LLM prompts — 57% fewer tokens means cheaper, faster, and fits more context.

CI pipelines — deterministic output: same input always produces the same SVG. Diffable in version control.

VS Code — live preview as you type.

Token comparison

Diagram scrawl Mermaid Savings
CI/CD Pipeline ~57t ~129t 56%
Microservices ~77t ~153t 50%
User Auth Flow ~51t ~133t 62%
Git Branching ~55t ~162t 66%
React Component Tree ~50t ~146t 66%
Database Schema ~64t ~167t 62%
Network Topology ~66t ~152t 57%
Bug Triage ~70t ~134t 48%
API Lifecycle ~82t ~139t 41%
How Scrawl Works ~60t ~164t 63%
Average 57%

How it works

How scrawl works

  1. Parse — zero-dependency recursive descent parser converts text to a typed IR
  2. Layout — dagre computes node positions and edge routing
  3. Render — rough.js draws hand-drawn shapes, edges with Bezier smoothing, and text with per-character wobble
  4. Seed — djb2 hash of source content ensures deterministic output

Contributing

Contributions welcome. This is a pnpm monorepo with Turborepo:

pnpm install
pnpm turbo build
pnpm turbo test

License

MIT

Packages

 
 
 

Contributors