Create designs that scale.
Freshcoat is an open-source design and rendering stack for creating cards, badges, certificates, labels and watermarked photos from reusable templates. A portable format describes each design, a Skia renderer turns it into pixels, and print and workspace utilities help produce the output in batches.
Use the packages in your own application, render from a terminal with the
freshcoat command, create templates in Figma, or design and export in
Freshcoat Studio. The format and renderer also power
Davi's card production system.
Freshcoat grew out of our own production needs as a small team. We struggled to find a design and rendering solution that fit our workflow, so we built one. We're sharing it so others can build on it and adapt it to their own needs. We want design files to be portable and the code that interprets them to be understandable and open to change, without depending on proprietary formats.
We're not experts in graphics engines or compiler design, and most of the work on Freshcoat has been AI-assisted. Our design decisions draw on working knowledge of compilers, experience with Canvas2D rendering and the practical demands of producing designs at scale. There is still plenty for us to learn.
We'd welcome help from people with deeper experience in these areas: finding mistakes, questioning assumptions and improving the template format, renderer and print workflows. If that sounds like your kind of work, see the contribution guide.
| If you want to | Start with |
|---|---|
| Fill a template with data and render it | @freshcoat-js/coatfile |
| Render your own 2D scene graph with CanvasKit | @freshcoat-js/engine |
| Analyze images and plan corrections for card printers | @freshcoat-js/for-print |
| Bind datasets to templates and batch-export them to ZIPs or PDFs | @freshcoat-js/workspace |
| Render, validate and batch-export from a terminal or CI | @freshcoat-js/cli |
| Design, preview and batch-export in a browser | Freshcoat Studio |
| Turn Figma frames and field markers into templates | Freshcoat for Figma (Figma Community) |
From a terminal, install the command line and render a template:
npm install --global @freshcoat-js/cli
freshcoat render card.coat --set displayName="Alex" --out out
freshcoat render card.coat --data people.csv --out cards.zipThe first command writes one image per side into out. The second renders the
template once per row of a spreadsheet and zips the results. See the
CLI README for every option.
From code, install the template package and the renderer:
npm install @freshcoat-js/coatfile @freshcoat-js/engineimport { readFile, writeFile } from "node:fs/promises";
import { loadTemplate } from "@freshcoat-js/coatfile";
import { renderTemplate } from "@freshcoat-js/coatfile/render";
import { createRenderer } from "@freshcoat-js/engine";
import { loadCanvasKit } from "@freshcoat-js/engine/node";
const loaded = await loadTemplate(await readFile("card.coat"));
if (!loaded.ok) throw new Error("Could not read card.coat");
const renderer = await createRenderer({ ck: await loadCanvasKit() });
const [front] = await renderTemplate(renderer, loaded.template, { displayName: "Alex" });
await writeFile("front.png", front.bytes);Create the renderer once and reuse it. See the coatfile README for variants, export sizes and batch rendering.
- Templates: layers, fields, fonts, sides and variants define a reusable
design. Templates are described in JSON; a
.coatarchive can bundle their assets. - Scenes and rendering: coatfile compiles a template and values into a
scene. The engine lays out and paints that scene through CanvasKit, which
brings Skia to WebAssembly. The host creates one renderer with
createRenderer, giving it a CanvasKit instance and fonts, and keeps it for the life of the process or worker. The renderer owns text shaping, the paint cache and image decoding. - Production utilities: print analysis and correction are separate from authoring. The workspace package adds datasets, bindings, export plans, PDF assembly and sheet imposition for applications that need batch output.
- Command line: the CLI puts coatfile, the engine and workspace behind one
freshcoatcommand, so a script or CI job can render without any code.
The UI and test-utils packages are internal packages and are not currently included in npm releases. The workspace model is independent of React; the UI kit supplies Studio's React controls and themes.
The command line renders a template to images, once per
spreadsheet row, or runs a workspace's export preset to a zip or PDF. It also
validates and inspects templates and workspaces, and packs a template with its
images into one .coat file. A template can be JSON, a .coat file, or a
TypeScript or JavaScript module that builds one. See the
CLI README for commands and options.
Studio combines template editing, typed datasets and worker-based exports in a browser. Imported files and autosaved work stay in browser storage; URL-referenced fonts and images can still be fetched from their hosts. See the Studio README for features, screenshots, limitations and development instructions.
Freshcoat for Figma exports frames as .coat templates
with optional field bindings and can send them to Studio. Install it from the
Figma Community listing.
See the plugin README for layer naming, supported Figma
features and installation.
Requires Bun 1.3.13 or later. From the repository root:
bun install
bun run test
bun run typecheckEach app and package has its own README with development commands.
For example, bun run --cwd apps/editor dev starts Studio, while
bun run --cwd apps/figma-plugin build builds the plugin.
The root dev and build aliases target Studio for convenience.
To run the CLI from source, call its entry with Bun:
bun packages/cli/src/bin.ts render card.coat --out outRelease builds for the SDK packages and the command line include compiled ESM, TypeScript declarations and assets. Their source manifests are private and intended for workspace development; use the generated tarballs for publication. See the release guide for npm setup, release checks and Figma plugin bundles.
- Architecture: package responsibilities and host boundaries.
- Contributing: repository setup, checks and review conventions.
- Upgrading from 0.3: what changed in 0.4 and how to move over.
- Releases: npm publication and Figma release bundles.
- CLI, Studio and Figma plugin: commands, behavior and guides for each tool.
- Each package README documents its API, runtime requirements and examples.
Freshcoat is licensed under the Apache License 2.0. Copyright 2026 Dotside Studios; see NOTICE and third-party notices. The name and marks are not licensed; see NAMES-AND-LOGOS.md.