Scenet#

A semantic DSL for comic panels, compiled to SVG.

This project is deliberately AI-generated

This project is, by design, almost entirely generated by AI. It exists as a personal training ground for learning to work with AI coding tools. The architecture, code, tests and documentation are overwhelmingly AI-authored, under human direction and review.

Treat it accordingly: an experiment first, a usable tool second.

What this is#

Music has notation. A score describes the semantics of a piece — pitch, duration, dynamics — without describing the waveform that eventually reaches your ear. Rendering is left to an interpreter, human or machine.

Images have no such thing. SVG describes how to draw, not what is depicted: it is closer to a WAV file than to a score. Scenet is an attempt at the missing layer, narrowed to one tractable domain — the comic panel.

You write what is in the panel:

panel:
  size: [1000, 800]
camera:
  shot: medium_shot
cast:
  alice: {reference: alice, pose: pointing,     at: left_third}
  bob:   {reference: bob,   pose: arms_crossed, at: right_third, facing: left}
staging:
  - alice left_of bob
  - alice looking_at bob
script:
  - say: {by: alice, text: "You forgot your umbrella!", prefer: top_left}
  - say: {by: bob,   text: "I know."}

From that, the compiler works out the rest: how large each figure must be for a medium shot, where they stand, which way they face, how big each balloon needs to be for its text, where a balloon can sit without covering a face, and how its tail reaches the speaker’s mouth — all while preserving reading order.

No generative image model is involved. This is a deterministic compiler: constraint solving and computational geometry. The same input always produces byte-identical output.

Thirty seconds#

from scenet import compile_source, render

result = compile_source("""
panel:
  size: [800, 600]
cast:
  alice: {reference: alice}
script:
  - say: {by: alice, text: "Hello."}
""")

svg = render(result.core)
assert svg.lstrip().startswith("<?xml")
assert len(result.core.balloons) == 1

Every Python example in this documentation is executed by the test suite. If one of them were missing an import, or had drifted out of step with the code, the build would fail.

Where to go#

Tutorial

Start here. Build one panel from nothing, understand each piece as it appears.

Tutorial
How-to guides

Recipes for specific jobs: a sequence, a comic script, your own characters, embedding the compiler in your own tool.

How-to guides
Reference

The complete API, the language specification, the command line, and the normative tables.

Reference
Explanation

Why the design is the way it is, what prior work it draws on, and what was deliberately rejected.

Explanation

Try it without installing anything#

The playground runs this compiler — the same Python, unmodified — in your browser under WebAssembly via Pyodide. It is not a reimplementation: the page installs the exact wheel uv build produces, so there is no second copy of the geometry to drift out of step.

License#

0BSD — deliberately one step more permissive than MIT. You may use, copy, modify and distribute this software for any purpose, with no obligation to preserve a copyright notice or reproduce the license. No attribution is required, though it is always welcome.

The language specification is free to implement. Anyone may build their own compiler, editor, renderer or tooling for this language, in any project, commercial or otherwise, without restriction. A notation is only worth having if it is not owned.