CLI Reference
The Lerret CLI ships as the npm package @lerret/cli. It installs one binary, named lerret, with two subcommands: dev and export. There is no init subcommand β use create-lerret to scaffold projects.
Running the CLI
| Context | Command |
|---|---|
Zero-install (npx) | npx @lerret/cli dev |
| Installed as a project dep | lerret dev (via package.json scripts, pnpm exec, npx, etc.) |
| Installed globally | lerret dev |
Donβt run
npx lerret β¦β the barelerretname belongs to a different (unrelated, deprecated) npm package. Always include the@lerret/cliscope when invoking vianpx.
The command syntax shown below uses the post-install form (lerret β¦). Prefix with npx @lerret/cli if you havenβt installed it.
Exit codes
Every subcommand uses the same convention:
| Code | Meaning |
|---|---|
0 | Success β work completed, --help printed, or graceful shutdown. |
1 | Failure β unknown subcommand, malformed flags, missing project, fatal runtime error. |
lerret <command> --help (or -h) prints command-specific help and exits with code 0.
lerret dev
Runs the studio against a .lerret/ project folder. Starts a local Vite dev server, bundles the studio, and opens it in your browser. The server is long-running β it stays up until you Ctrl+C (SIGINT) or send SIGTERM.
lerret dev [options]Options
| Flag | Type | Default | Description |
|---|---|---|---|
--port <n> | integer (1β65535) | Viteβs default (usually 5173) | Dev-server port. |
--folder <path> | path | (walk up from CWD) | Project folder. Bypasses the walk-up auto-detection. |
--open | boolean | true | Open the studio in the default browser on start. |
--no-open | boolean | (sets open=false) | Do not open the browser. |
-h, --help | β | β | Print this help and exit 0. |
Unknown flags are a usage error (exit 1).
Project resolution
lerret dev resolves the project in this order:
--folder <path>if supplied. The path is used directly; the CLI checks that it (or a parent) contains a.lerret/directory.- Otherwise the CLI walks up from the current working directory looking for the nearest
.lerret/β the waygitwalks up looking for.git/.
If neither path finds a project, the command exits with code 1 and a clear message.
Examples
lerret dev # walk up from cwd, default port, auto-open
lerret dev --port 4000 # custom port
lerret dev --no-open # headless: useful in CI / SSH
lerret dev --folder ./design-tokens # explicit folder, skip walk-uplerret export
Headlessly renders every artboard in scope to image files. The CLI boots a Vite server, launches a headless Chromium through Playwright, navigates the studio against your project, and captures each artboard. Uses the same rendering path as the studioβs per-artboard PNG button, so the output is pixel-faithful to the studio.
lerret export [path] [options]Argument
| Argument | Description |
|---|---|
path (optional) | A project root, or a page / group folder inside .lerret/. Omitted β walks up from CWD to find the nearest project, then exports the whole project. |
When path points at a page or group folder, only artboards within that scope are captured.
Options
| Flag | Type | Default | Description |
|---|---|---|---|
--format <fmt> | png | jpg | png | Output image format. jpeg is accepted as an alias for jpg. |
--out <dir> | path | ./lerret-export | Output directory, resolved relative to CWD. Created if absent. |
--flat | boolean | false | Write all images directly under --out with collision-disambiguated names. Default: nested folders mirroring page/group hierarchy. |
--data <path> | path | β | JSON or .js file whose contents override the data tier (tier 1 of prop resolution) for every artboard in this run. Missing / invalid β exit 1. |
--config <path> | path | β | JSON or .js file deep-merged into the cascaded config for this run. Missing / invalid β exit 1. |
-h, --help | β | β | Print this help and exit 0. |
Output structure
Default (nested):
<out>/
βββ <page>/
βββ <group>/
βββ ...
βββ <asset.name>.<ext>
βββ <asset.name>-<variant>.<ext>--flat:
<out>/
βββ <asset.name>.<ext>
βββ <asset.name>-<variant>.<ext>In flat mode, file-name collisions (assets with the same name in different folders) are disambiguated by joining the path location segments with -.
Override flags: --data and --config
The override flags let you re-render an entire project with different data or theming without modifying any files:
--data <path>β a JSON or.jsfile. Its contents override tier 1 (DATA) of prop resolution for every artboard. The file is loaded once before Vite starts; a missing or unparseable file aborts the run immediately (exit1) so you get feedback before spending time booting Chromium.--config <path>β a JSON or.jsfile. Its contents are deep-merged into the cascaded config (using the same merge semantics as the on-disk cascade) for every folder in this run.
Neither override is ever written back to your .lerret/ (the separation invariant). The values flow through the project plugin as in-memory constructor options and are discarded on exit.
A common pattern: keep a theme-dark.json and a theme-light.json alongside your project, then export both themes with one command each.
Failure isolation
A failure to capture an individual artboard is reported but does not abort the run β the remaining artboards still write to disk. The final summary lists per-artboard failures and any custom fonts that could not be embedded across the run.
The run exits 1 (fatal) only for these conditions:
- No project resolved.
- No artboards in scope.
- Output directory could not be created.
- Vite failed to start.
- No Chromium could be launched (neither a system
chrome/msedgechannel nor a bundled Playwright browser). --dataor--configfile missing or unparseable.
Chromium resolution
lerret export tries a system Chromium channel first (chrome, then msedge) so a zero-install npx @lerret/cli export stays light. It falls back to a bundled Playwright browser if one has been installed (npx playwright install chromium). If neither is available, the command exits with code 1 and a clear, actionable message about how to install one.
Examples
# Whole project, default output
lerret export
# JPG output to a custom directory
lerret export --format jpg --out ./assets
# Only the `social` page, flat output
lerret export .lerret/social --flat
# Re-render with a dark-theme override
lerret export --config ./theme-dark.json --out ./dark
# Re-render with both data and config overrides (no source edit)
lerret export \
--data ./fixtures/release-1.0.json \
--config ./theme-corporate.json \
--out ./marketing/release-1.0create-lerret
Scaffolder for new Lerret projects. Always invoke via npx (or your runnerβs dlx) β create-* is the npm convention for scaffolders.
npx create-lerret <project-name> # full scaffold with sample assets (default)
npx create-lerret <project-name> --no-samples # minimal empty project| Runner | Command |
|---|---|
| npm | npx create-lerret my-canvas |
| pnpm | pnpm dlx create-lerret my-canvas |
| Yarn | yarn dlx create-lerret my-canvas |
| Bun | bunx create-lerret my-canvas |
Arguments
| Argument | Required | Description |
|---|---|---|
<project-name> | yes | Directory name for the new project. Letters, digits, and . - _ only β no path separators, no path traversal. |
Flags
| Flag | Description |
|---|---|
--no-samples | Scaffold only .lerret/config.json (with { "vars": {} }). No _fonts/, no social/ page, no sample artboards. The studio opens with a calm empty-but-correct canvas. |
Default output
<project-name>/
βββ .lerret/
βββ config.json
βββ _fonts/
β βββ LerretFixtureMono.woff2
βββ social/
βββ instagram-square.jsx
βββ twitter-banner.jsx
βββ twitter-banner.data.json
βββ youtube-thumbnail.jsxBehavior on conflicts
| Condition | Behavior | Exit code |
|---|---|---|
| Target dir does not exist | Create it, populate it. | 0 |
| Target dir is empty | Populate it. | 0 |
| Target dir is non-empty | Refuse with clear message. No writes. | 1 |
| Target path is a file | Refuse. No writes. | 1 |
| Parent dir missing or unwritable | Refuse with clear message. | 1 |
| Mid-copy filesystem failure | Clean up any partial output, then exit. | 1 |
Network and offline
create-lerret itself has zero runtime dependencies β the package contains the template and a single Node script. The npm runner (npx / pnpm dlx / etc.) needs to fetch the package the first time; once cached, scaffolding is offline-capable.
The follow-up npx @lerret/cli dev does need network to fetch Vite, React, and @lerret/cli the first time, but never makes outbound requests at runtime. After the first run, dev startup is offline-capable.