Starting a project¶
ComicForge is a content-free engine: it ships no art and imports nothing
from your project. A project is just data — YAML specs plus SVG and pixel
art — that the cmf CLI points at.
So in the simplest and most common setup, your comic project is not a Python project at all.
The simple path: a data-only project¶
Install the engine once, globally:
…or straight from the repository:
Then scaffold and render:
cmf init lays out everything you need:
my-comic/
characters/ one dir per character (base.svg + overlays + character.yaml)
scenes/ one dir per scene background
pixel/ pixel-art sprites (grid + palette) — heart.yaml seeded
pages/hello.yaml a renderable starter page
output/ renders land here when you omit -o (gitignored)
README.md .gitignore
.claude/skills/comicforge/ the authoring skill — lets Claude write specs for you
That is the whole project. No pyproject.toml, no virtualenv, no Python files.
Add your own characters under characters/, reference them as actors in a
page spec, and render.
cmf init is idempotent — re-running it over an existing project leaves your
files untouched. Pass --force to overwrite the scaffolded ones, which is how
you refresh the bundled skill after upgrading the engine.
Your first comic walks through this with a character you draw yourself.
Version control¶
Commit everything except output/, which the scaffolded .gitignore already
excludes. The art is small, hand-authored SVG and YAML — it diffs, reviews and
merges like source code, which is much of the point.
When you need more¶
| You want… | Setup |
|---|---|
| Just to author and render comics | The data-only project above. The default, and what most projects should stay as. |
A pinned engine version, or the inspire extra |
uv tool install "comicforge[inspire]", or a tiny pyproject.toml with comicforge==<version> as its only dependency, run via uv run cmf …. Use this when two projects need different engine versions — uv tool installs are global and single-version. |
| Your own render scripts or a generator | A full Python project with comicforge as a library dependency: from comicforge import render_spec. Rare — see the Python API. |
A minimal pinned project:
[project]
name = "my-comic"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = ["comicforge==0.2.0"]
How paths resolve¶
This is worth getting straight once:
- Relative
library:/scenes_dir:/pixel_dir:keys in a spec resolve against the spec file's directory. That is why a spec inpages/writeslibrary: "../characters"and works from any working directory. - A CLI flag (
--library,--scenes,--pixel-dir) overrides the spec key and resolves against your current working directory. - A page spec always needs a
library:, even one pointing at an emptycharacters/directory.scenes_dir:andpixel_dir:are needed only when a spec actually uses a scene or a library sprite; inline pixel art needs neither.
Structuring a bigger project¶
The four asset directories are a convention, not a rule — the engine only knows what the spec keys point at. What tends to hold up as a project grows:
- One directory per character, named for the character, matching the
name:in itscharacter.yaml. - Pages under
pages/, one file per page or strip, named for the story beat rather than numbered. - A contact-sheet spec per character — a page with one panel per variant, captioned with the variant name. It costs nothing to render and it is documentation that cannot go stale. See the gallery.
references/for generated inspiration art, kept well away fromcharacters/. It documents intent; it is never an asset.
Authoring with Claude¶
The scaffolded .claude/skills/comicforge/ is the authoring contract: open the
project in Claude Code and it can write and validate specs for you. See
With Claude.