Getting Started
This guide walks you from zero to a rendered canvas, a first edit, and an exported image in under five minutes. You will need:
- Node.js β₯ 20.19
- A Chromium-based browser (Chrome, Edge, Brave, Arc) β for the studio. The CLI itself runs anywhere Node runs.
1. Scaffold a project
npm create lerret@latest my-canvasThe scaffolder downloads from npm and writes a new project at ./my-canvas/. Total install β including Vite and React, downloaded once and cached β typically runs in under a minute on a warm broadband connection. No global install is required.
If my-canvas already exists, the scaffolder refuses to overwrite a non-empty directory but is happy to populate an empty one.
What you got
my-canvas/
βββ .lerret/
βββ README.md
βββ config.json
βββ _fonts/
β βββ LerretFixtureMono.woff2
βββ intro/
β βββ config.json
β βββ welcome.md
βββ landing/
β βββ about-vars.md
β βββ landing-hero.jsx
βββ social/
β βββ about-data-files.md
β βββ og-card.jsx
β βββ og-card.data.json
β βββ tw-banner.jsx
β βββ tw-banner.data.json
βββ brand/
β βββ about-validation.md
β βββ business-card.jsx
β βββ business-card.data.json
βββ live/
βββ about-live-refresh.md
βββ config.json
βββ clock.jsx
βββ clock.config.json
βββ counter.jsx
βββ counter.config.jsonThis is the five-page teaching preset: each page demonstrates one Lerret concept β intro (a welcome note), landing (cascading vars), social (data files + variants), brand (props schemas + validation), and live (auto-refreshing artboards). Each page ships a short about-*.md note that renders on the canvas and explains what that page teaches.
The .lerret/ folder is the only thing Lerret cares about. Everything else in the project is yours β Lerret never touches files outside it (the separation invariant).
| Path | What it is |
|---|---|
.lerret/config.json | Project-root config. The vars block flows down the cascade as CSS-like variables. |
.lerret/_fonts/ | Reserved folder. Any .woff2 / .woff / .ttf / .otf here is auto-registered as a CSS @font-face rule. Available to every asset by its file name. |
.lerret/social/ | A page β top-level non-underscore folders become pages on the canvas. |
*.jsx | Each component file becomes an artboard. The default export is the primary variant; named exports become extra variants. |
*.data.json | Co-located data file for an asset (here, og-card.data.json). Overrides component props at runtime. |
*.config.json (next to an asset) | Co-located per-asset config β e.g. clock.config.json sets an autoRefresh interval. |
Want a minimal start?
For an empty project β just .lerret/config.json with { "vars": {} }, no sample assets:
npm create lerret@latest my-canvas --no-samplesWant a themed starting point?
Instead of the teaching preset, scaffold one of seven ready-made kits with --preset:
npm create lerret@latest my-canvas --preset producthuntValid names: acme (brand starter kit), appstore (App Store screenshots), producthunt (launch assets), social-media (six social formats), talks (conference slides), personal (personal-site assets), and live (auto-refresh demos). An unknown name errors with the valid list. There is also --demo, which scaffolds the default teaching preset and immediately starts the dev server with the first-run walkthrough (--demo is mutually exclusive with --preset and --no-samples).
2. Start the studio
cd my-canvas
npx @lerret/cli@latest devThe Vite dev server boots and your default browser opens to the studio. You should see the five teaching pages on the canvas β a welcome note, a landing hero, social cards (an OG card plus an X banner in three variants), a business card, and two live auto-refreshing demos β each artboard rendered at its real pixel dimensions.
Common flags
npx @lerret/cli@latest dev --port 4000 # custom port (default: Vite's default, usually 5173)
npx @lerret/cli@latest dev --no-open # don't auto-open the browser
npx @lerret/cli@latest dev --folder ./ # explicit project folder (bypasses walk-up)If you do not pass --folder, the CLI walks up from the current working directory looking for the nearest .lerret/ β like git walks up looking for .git/.
3. Edit a component
Open .lerret/landing/landing-hero.jsx in your editor. Find the headline and change it:
// Before
<div style={{ fontSize: 76, lineHeight: 1.04, ... }}>
Designs are just files.
</div>
// After
<div style={{ fontSize: 76, lineHeight: 1.04, ... }}>
Hello from my first Lerret canvas
</div>Save the file. The landing-hero artboard re-renders in under a second. No page reload, no manual rebuild. The watcher detects the change, Viteβs React Fast Refresh swaps the module, and the canvas updates in place.
The social and brand assets keep their text in co-located
.data.jsonfiles instead of the JSX β open.lerret/social/og-card.data.json, change theheadline, and save for the same sub-second loop. Step 6 covers how that works.
4. Add a second asset
Create a new file .lerret/social/release-card.jsx:
export const meta = {
dimensions: { width: 1200, height: 630 },
label: 'Release card',
tags: ['release', 'og'],
};
export default function ReleaseCard() {
return (
<div style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'var(--brandColor, #B85B33)',
color: 'white',
fontSize: 72,
fontWeight: 800,
fontFamily: 'system-ui',
}}>
v1.0 β Shipping today
</div>
);
}Save it. A new artboard appears on the canvas β at exactly 1200Γ630 β alongside the others. The watcher reports an add event, the loader incorporates the new asset into the project model, and the canvas adds the artboard.
Notice the var(--brandColor, #B85B33). The project-root config.json declares vars.brandColor = "#B85B33", which the studio exposes as a CSS custom property on the artboard. Change the value in config.json β say to "#3D5A80" β save, and every artboard re-renders with the new color.
5. Add a variant
Variants are extra components in the same file, exported by name. Add this to release-card.jsx:
export const Dark = () => (
<div style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: '#0A0A0A',
color: '#E0FBFC',
fontSize: 72,
fontWeight: 800,
fontFamily: 'system-ui',
}}>
v1.0 β Shipping today
</div>
);Save. A second artboard appears next to the original β labelled Dark β also at 1200Γ630. The meta export is shared across all variants in the file; the default export is the primary variant; each named function export is an extra variant.
Component-valued exports = variants. Non-function exports (constants, the
metaobject) are ignored.
6. Add data
Lerret can supply props to your component from a co-located data file β no code change required.
Create .lerret/social/release-card.data.json:
{
"default": {
"label": "v1.0 β Shipping today"
},
"Dark": {
"label": "v1.0 β Shipping today (dark mode)"
}
}Then accept label as a prop in your component:
export default function ReleaseCard({ label = 'Untitled' }) {
return (
<div style={{ /* ... */ }}>
{label}
</div>
);
}The top-level keys match your variant export names (default, Dark), so each variant gets its own data. This is per-variant data keying. If the top-level keys do not match any export name, the entire data object is applied as shared data to every variant.
There is also a .data.js form when you need computed or conditional data β see Authoring Assets for the full mechanics.
7. Export to image files
When you are happy with the canvas, render every artboard to image files from the command line:
npx @lerret/cli@latest exportBy default, output goes to ./lerret-export/ (relative to your CWD, never inside .lerret/). Each artboard becomes a PNG β including one per variant and one per Markdown note β nested under folders that mirror the projectβs page/group structure. The social page from the walkthrough comes out as:
lerret-export/
βββ brand/ β¦
βββ landing/ β¦
βββ live/ β¦
βββ social/
βββ about-data-files.png
βββ og-card.png
βββ release-card.png
βββ release-card-Dark.png
βββ tw-banner.png
βββ tw-banner-Maker.png
βββ tw-banner-Talk.pngThe intro page is absent by design: its config.json sets "excludeFromExport": true, a page-level flag that keeps canvas-only notes out of your export.
Useful flags:
npx @lerret/cli@latest export --format jpg # JPG instead of PNG (jpeg also accepted)
npx @lerret/cli@latest export --out ./assets # custom output directory
npx @lerret/cli@latest export --flat # all images at one level, no nested folders
npx @lerret/cli@latest export .lerret/social # scope: only this pageThe CLI boots a headless Chromium through Playwright and uses the same rendering path the in-studio export buttons use, so a @lerret/cli export run produces a pixel-faithful match to what the studio captures.
See CLI Reference for the full flag list, including the --data and --config override flags that let you re-render an entire project with different data or theming without modifying any files.
Whatβs next
- Concepts β the mental model: pages, groups, variants, the four-tier prop cascade.
- Authoring Assets β the full guide to writing components, schemas, data files, and fonts.
- Examples β sixteen runnable patterns to copy and adapt: OG cards, YouTube thumbnails, repo cards, release graphics, more.
- CLI Reference β every flag and exit code for
devandexport. - Deployment β local CLI, hosted browser, or self-hosted static studio.
Welcome to Lerret.