Gum is a JSX language for vector graphics: plots, diagrams, mathematical figures, and slides. Compose shapes, text, and TeX with measured layouts, then export SVG, PNG, PDF, or PPTX, or display the result directly in an image-capable terminal.
Use Gum as a command-line tool, a TypeScript library, or through its browser editor and React bindings. JSX figures use ordinary JavaScript functions and data; they do not require React.
Start with the CLI · Documentation and gallery
Use Node.js 24 or newer and install the bundled CLI:
npm install -g @gum-jsx/cliThe CLI includes the core renderer, math, maps, and PNG/PDF/PPTX exporters. It
provides the gum command. Bun 1.4.2 or newer works equally well as an alternative
runtime and is required for CLI plugins.
Save this as figure.jsx:
<Plot
width={px(640)}
aspect={2}
font-size={px(18)}
title="Sine wave"
xlabel="x"
ylabel="sin(x)"
xlim={[0, tau]}
ylim={[-1.5, 1.5]}
background="white"
>
<SymLine
fy={sin}
xlim={[0, tau]}
samples={161}
stroke={blue}
stroke-width={px(2)}
/>
</Plot>Render it:
gum figure.jsx -o figure.svg
gum figure.jsx -o figure.png --ratio 2
gum figure.jsx -o figure.pdfElements, units, and helpers such as Plot, px, sin, and tau are already in
scope. Use px(24) for pixels, em(1.5) for font-relative lengths, and fractions
such as 0.5 for relative sizes. Gum measures text and composes layouts with
boxes, stacks, and positioned canvases. Start with the
units and
sizing guides.
Command line. Omit -o to display a figure in a terminal supporting the kitty
graphics protocol. Use -f svg for SVG on stdout, or -f tree --stats to inspect
layout. The CLI includes math bindings:
gum figure.jsx
gum figure.jsx -f tree --stats
gum slides/ -o talk.pdfPNG and terminal rendering use tiny-skia WebAssembly without native addons or install scripts. Raster output uses outlined text; emoji without outlines and external SVG images are unsupported. PDF output preserves vector paths and embedded PNG images; text is outlined and is not searchable or selectable. See the CLI, PDF, and PPTX references for format support and limits.
Browser editor. From a development checkout, run bun --filter @gum-jsx/edit dev
and open the printed URL to edit JSX with a live SVG preview. The /docs page
provides searchable, editable examples.
Library. Evaluate JSX and render it to SVG from a Bun script:
import { evaluate, render_element } from '@gum-jsx/core'
const source = await Bun.file('figure.jsx').text()
const result = render_element(evaluate(source))
if (result.kind === 'svg') {
await Bun.write('figure.svg', result.svg)
}You can also construct elements directly in TypeScript. The core and math renderers support browser hosts with preloaded font resources. Use @gum-jsx/math for TeX or @gum-jsx/react to compose figures as React components. Evaluated JSX executes JavaScript in the host environment; use trusted source or an application-provided isolation boundary.
Coding agents. From the workspace root, bun run plugin:build generates the
plugin's authoring skill from the maintained
documentation. bun run plugin:pack rebuilds it and packages the plugin ZIP.
To install the plugin from GitHub:
codex plugin marketplace add CompendiumLabs/gum-jsx
codex plugin add gum-jsx@gum-jsxStart a new task after installation. Rendering uses the Gum CLI described above.
Each package is a separate repository, developed together through Git submodules.
| Package | Purpose |
|---|---|
| @gum-jsx/core | JSX evaluation, layout, shapes, text, plots, networks, and SVG output. |
| @gum-jsx/math | TeX parsing, math layout, and standalone formula exports. |
| @gum-jsx/png | Fragment rasterization to PNG or RGBA through WebAssembly. |
| @gum-jsx/pdf | Vector PDF export from laid-out fragments. |
| @gum-jsx/pptx | Native PowerPoint shapes and images from laid-out fragments. |
| @gum-jsx/react | React bindings, headless rendering, and the gum-react command. |
| @gum-jsx/mark | Markdown terminal rendering with figures and math. |
| @gum-jsx/cli | The gum command. |
| @gum-jsx/edit | Browser editor and interactive documentation viewer. |
| @gum-jsx/docs | Guides, element references, gallery sources, and skill generation. |
Clone the workspace and its package submodules:
git clone https://github.com/CompendiumLabs/gum-jsx.git
cd gum-jsx
git -c url."https://github.com/".insteadOf=git@github.com: submodule update --init --recursive
bun install
bun --filter @gum-jsx/png buildThe submodule command uses HTTPS for the repository's SSH remotes, so a public checkout does not require a GitHub SSH key.
Run shared commands from the workspace root:
bun run test # Every package's suite, sequentially
bun run typecheck # TypeScript checks across all packages
bun run build # Build PNG assets, then the bundled CLI
bun run perf # Core, math, maps, and demos benchmarks, sequentially
bun --filter @gum-jsx/edit build # Production browser editor and docs viewer
bun run visual-test # Searchable HTML report of rendered examples
bun run rehearse # Publish to a temporary local registry and check fresh installs
bun run --cwd gum-jsx-cli test # Includes isolated npm CLI installation checksTo work on one package, use its scripts, for example
bun --filter @gum-jsx/core test. Package READMEs cover additional checks and
dependencies. The design, roadmap, and
feature map describe implementation decisions and planned work.
The release checklist covers packaging and publication checks.
bun run perf # All suites, measured sequentially
bun run perf:core # Core only
bun run perf:math # Math only
bun run perf:maps # Maps only
bun run perf:demos # Full JSX demos, split by rendering stage
bun run perf --list # List case names without preparing fixtures
bun run perf --smoke # Exercise every case twice without timing
bun run perf --filter '^core/layout/'
bun run perf --json > /tmp/gum-perf.jsonEach of these packages also exposes bun run perf from its own directory, with
the same options. The suites use Mitata for warmup, sampling, and latency
statistics. Inputs are deterministic and maps use bundled atlases. Construction,
fresh-pass layout, SVG serialization, full renders, and cache hits have separate
cases so their costs can be compared. Fonts are warmed except in explicitly named
fresh-provider cases.
See the core, math, maps, and demos workload notes for exact timing boundaries. Run on an idle machine, save JSON reports before and after a change, and compare the same case names on the same hardware and Bun version. JSON timings are in nanoseconds. Record Git revisions with reports and repeat runs to check noise; performance results are separate from correctness tests.
Compare freezing modes with the regular benchmark commands:
GUM_FREEZE=1 bun run perf --json > /tmp/gum-freeze.json
GUM_FREEZE=0 bun run perf --json > /tmp/gum-no-freeze.json
GUM_FREEZE=0 bun run perf:demosRun modes sequentially and alternate their order across repeats.
For production rendering, NODE_ENV=production disables runtime freezing while
retaining input snapshots and validation. GUM_FREEZE=1 or 0 overrides the
default before Gum loads. Browser builds use __GUM_FREEZE__; Studio and the
MCP viewer configure this automatically. See the
immutability policy.
bun run test:immutability runs the workspace tests with freezing both enabled
and disabled.
For a CPU profile of selected cases:
bun --cpu-prof --cpu-prof-dir=/tmp test/perf.ts --filter '^core/layout/'