Apply modern, semantic visual themes to existing draw.io / diagrams.net
.drawio files — from the command line, without touching geometry,
topology, or shape semantics.
| Before | After — dark-neon-mode theme |
|---|---|
![]() |
![]() |
Manually restyling every shape in a .drawio file — fills, strokes,
fonts, corner radius, edge arrows — is tedious and error-prone, and
generic "convert to X" tools tend to mangle geometry, connections, or
shape semantics (a database cylinder becoming a plain rectangle, for
example). drawio-themer rewrites only presentational style
properties via a small YAML theme, leaving everything else — layout,
connections, embedded images/icons, shape types — untouched.
- Safe by construction — a style-property allow-list (see
docs/PRD.md) guarantees geometry, topology, and shape type are never rewritten. - Semantic classification — nodes, edges, containers, and database shapes are classified automatically and themed with distinct rules.
- Multi-page & compressed diagrams — supports both inline and
raw-deflate+ base64 compressed page content. - Idempotent — re-applying a theme to an already-themed file is a no-op.
- Bundled themes — ships with 10 built-in themes covering light
and dark, muted and vibrant, professional and accessibility-first
styles (
shadcn-modern,dark-neon-mode,nord,dracula,solarized-light,gruvbox,catppuccin-mocha,monokai,github-light,high-contrast); write your own in a few lines of YAML.
Run the published CLI without installing it:
npx --yes drawio-themer@latest --helpFor a persistent global installation:
npm install --global drawio-themerAfter global installation, the drawio-themer command is available directly.
For local development from a checkout:
npm install
npm run buildTo use the locally built command directly, install this checkout globally:
make install-globaldrawio-themer apply input.drawio -t shadcn-modern -o output.drawioOr run the published CLI with npx, without a global install:
npx --yes drawio-themer@latest apply input.drawio -t shadcn-modern -o output.drawioOr without an npm install, run the built CLI directly from a checkout:
node dist/cli.js apply input.drawio -t shadcn-modern -o output.drawioOr during development, without a build step:
npx tsx src/cli.ts apply input.drawio -t shadcn-modern -o output.drawiodrawio-themer apply <input>
Options:
-t, --theme <theme> Built-in theme name or theme file
-o, --output <file> Output .drawio file
--dry-run Analyze without writing
--format <format> preserve | compressed | uncompressed
--verbose Show matching/transformation details
--no-theme-metadata Do not annotate generated file
--png-original <file> Render the input (pre-theme) file as an
approximate PNG render
--png-themed, --png <file>
Render the themed output as an approximate
PNG render
--svg-original <file> Render the input (pre-theme) file as an
approximate SVG render
--svg-themed, --svg <file>
Render the themed output as an approximate
SVG render
--renderer <backend> resvg (default) | chromium
-h, --help
PNG/SVG renders are an offline, approximate rasterization of the diagram (rects, database cylinders, edges clipped to node borders, labels) meant for a quick visual check — not a substitute for opening the file in real draw.io (no waypoints, groups, rotation, or HTML labels support):
node dist/cli.js apply input.drawio -t dark-neon-mode -o output.drawio \
--png-original before.png \
--png-themed after.png \
--svg-original before.svg \
--svg-themed after.svg--png-* rasterization uses one of two backends, selected with
--renderer <backend>:
-
resvg(default) — a native, offline, zero-setup static SVG rasterizer (@resvg/resvg-js). Fast and dependency-light, but structurally limited: no<foreignObject>/HTML label support, no real web font loading, and only partial CSS filter support. -
chromium(opt-in) — drives a real headless Chromium viaplaywright-corefor higher-fidelity output closer to real draw.io's own Electron-based PNG export. Requires a one-timenpx playwright install chromium(not downloaded by defaultnpm install/make install):npx playwright install chromium node dist/cli.js apply input.drawio -t dark-neon-mode -o output.drawio \ --png-themed after.png --renderer chromium
Known limitation: with glow-enabled themes (e.g.
dark-neon-mode),--renderer chromiumcan drop perfectly axis-aligned (horizontal or vertical) edges due to a degenerate SVG filter region on zero-width/ height bounding boxes (see issue #71).--renderer resvgis unaffected.
A theme is a YAML file of design tokens plus a small set of rules
matched against classified cells (node, edge, container,
database) or explicit tags. Ten themes are bundled:
shadcn-modern— light, shadcn/ui-inspired defaultdark-neon-mode— dark zinc base with a violet/cyan glow accent (shown in the demo above)nord— cool arctic blues, muted, professional-darkdracula— vibrant purple/pink/green darksolarized-light— warm cream, low-contrast, eye-friendlygruvbox— warm retro browns/oranges, darkcatppuccin-mocha— soft pastel darkmonokai— classic yellow/green/pink code-editor darkgithub-light— clean corporate/professional lighthigh-contrast— WCAG-AA-oriented black/white/yellow, accessibility-first
Each render below shows the same fixture
(docs/assets/fixtures/layered-architecture.drawio) via
apply --png-themed (see Usage above). Only the
vibrant/neon-leaning dark themes (dark-neon-mode, dracula,
monokai) opt into the render's glow filter (glow: true in
their YAML) — muted, light, retro, or accessibility-focused themes
render flat/crisp on purpose.
| Theme | Render |
|---|---|
shadcn-modern |
![]() |
dark-neon-mode |
![]() |
nord |
![]() |
dracula |
![]() |
solarized-light |
![]() |
gruvbox |
![]() |
catppuccin-mocha |
![]() |
monokai |
![]() |
github-light |
![]() |
high-contrast |
![]() |
See docs/PRD.md for the full theme format and style
allow-list.
Common tasks are wrapped in a Makefile with a dependency chain
(format-check -> lint -> build/test -> run -> release-*), so
each target re-verifies the gates before it:
make format # prettier --write (mutates files)
make format-check # prettier --check (CI-safe, no mutation)
make lint # format-check + eslint
make test # lint + build + vitest
make run # test + `node dist/cli.js --version`
make install-global # build + `npm install -g .` (adds `drawio-themer` to PATH)
make release-patch # run + npm version patch + git push --follow-tags
make release-minor # run + npm version minor + git push --follow-tags
make release-major # run + npm version major + git push --follow-tagsPlain npm scripts are also available (npm run build|lint|test|format|format:check).
CI runs make format-check, make lint, and make test as separate
required checks (Checks / Format, Checks / Lint, Checks / Tests)
on every pull request.
The offline PNG/SVG preview renderer (--png-*/--svg-* flags) bundles
src/render/assets/NotoSans-Regular.ttf (Noto Sans, SIL Open Font
License 1.1 — see src/render/assets/NotoSans-LICENSE.txt) so labels
render in a proportional sans-serif font even on hosts without it
installed, instead of silently falling back to resvg's default
monospace font.











