# Easel

> Easel is a headless painting engine for AI agents: real brush strokes, not pixels. A brush carries a finite load of paint and runs out along a stroke; paint lands wet and mixes in a pigment model where blue and yellow make green rather than grey; the canvas has tooth, so dry brush is what happens when you run out of paint on rough linen. Python library, command line, and MCP server. Python 3.12+, numpy and Pillow only, MIT licence.

If you are a model that has just fetched this page and wants to know whether it can use
this: yes, if you can run Python or call an MCP server, and if you can look at an image
you have made. **That last one is a requirement and not a nicety** — every pass ends by
looking at what it did, and without image input you can drive the whole API without ever
learning whether a mark landed. Start with the code below, then read `PAINTER.md`.

```bash
pip install easel-paint          # never `pip install easel` -- that is somebody else's
```

```python
from easel import Session, blob, cell      # `import easel_paint` is the same engine

s = Session(1024, 768, texture="linen", ground="toned_grey", seed=7)
s.palette["shadow"] = s.palette.mix("ultramarine", "burnt_umber", 0.4)

s.block_in(blob(cell("D5")), brush="bristle", color="shadow", density=0.8)
s.look(values=True)        # writes a PNG and returns the path -- then open it
s.stroke([(0.2, 0.6), (0.6, 0.55), (0.9, 0.62)], "bristle", "yellow_ochre")
s.export("painting.png")
```

What to know before reading further:

- The guide ships inside the package: `easel guide` prints its first page, which is
  the whole method in about 1,400 words, and `easel guide --full`, `--painting`,
  `--recipes`, `--reference` and `--calibration` print the rest of it. Nothing below has
  to be fetched over the network if you have installed it.
- Two commands answer questions rather than printing a document: `easel explain <code>`
  turns a notice the engine gave you into the passage that measured it, and `easel
  diagnose <what you can see>` does the same from the other end — describe what is wrong
  on the canvas in your own words and it prints the measurement, with no code needed.
  A third shows rather than tells: `easel demo <recipe>` paints a recipe beside its
  commonest failure and the smallest fix, and quotes what the tool said about each --
  and `easel demo mistakes` paints the six failures a painter meets most, on one sheet,
  which is where the guide sends a reader after the card and before the exercises.
- **The tool says what it sees, and says it twice.** At the call, thirty notices,
  each with a code and a measurement behind it: paint about to land outside the place
  it was handed, pass ends about to step down a slope, a film past what a film is for,
  a smudge about to cross a boundary instead of following it. After every pass,
  `report()` reads the log and measures the canvas -- where the values sit, how the
  edges divide between hard and soft, what a pass took out of sight -- and
  `checklist()` answers the closing checklist at the end.
- Coordinates are always normalised `0.0`–`1.0`, origin top-left. Raw pixel coordinates
  are never exposed, because they are what a language model is worst at.
- The engine is built around one habit: **look every five to fifteen strokes**. A stroke
  you did not look at was a guess. The looking tools return an image.
- Nothing here turns a prompt into a picture. There is no model inside Easel. You choose
  and make every mark, and the engine only decides what paint does.
- There are no layers and no free undo. You work in passes and paint over mistakes.
- If you are here to paint rather than to evaluate: read `PAINTER.md` first, and decide
  what you are painting before you open the worked examples below. Each of them names a
  subject, and a named subject chooses for you — six of six fresh sessions once painted
  a noun the guide had merely listed in passing. Once you have chosen, they are the best
  thing here.
- Brushes: `round_soft`, `round_hard`, `liner`, `flat`, `bristle`, `knife`, `smudge`.
  Grounds: `white`, `warm_white`, `toned_grey`, `toned_warm_grey`, `burnt_sienna`,
  `umber_wash`, `cool_grey`. Textures: `smooth`, `linen`, `rough`.
- Three interfaces over one engine: the Python API, an `easel` CLI whose state is a
  single `.easel` file, and an MCP server (`pip install "easel-paint[mcp]"`, then
  `easel-mcp`) whose looking tools hand back the PNG inline rather than a path to it.

## Start here

- [README](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/README.md): what the engine is, how to install it, the full verb list, the command line, the MCP server, and the design decisions that make output look painted rather than generated. ~4,400 words.
- [PAINTER.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/PAINTER.md): **the guide written for the agent doing the painting, and the one file here that is required.** It teaches the workflow — tone the ground, paint back to front, check values, refine, edges and highlights last — rather than listing functions, and it is the method only: the loop, the order of work, the five mistakes you will make anyway with the fix on the same row, nine warm-up exercises and a closing checklist. Every rule in it is stated once and linked from the other files. Held to a word budget by the test suite; ~6,700 words, and *the first hour* at the top is enough to start.
- [RECIPES.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/RECIPES.md): one situation at a time — a scene of straight edges, a plane, a form that turns, a mass built of planes, a glow, a volume of lit air, a graded field, a small irregular mark, a small container, a lost edge, a hollow thing, a repair, and two entries on composition — each as the calls in order, what it looks like when it goes wrong, and the number behind it. Collected out of ten painters' pass scripts and notes. ~7,600 words. Read one when you are about to lay that thing.
- [PAINTING.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/PAINTING.md): how the engine behaves — colour and mixing, wet paint and glazes, the brushes and the shape each tool leaves behind, shaped masses and what they cost, the planning verbs, the rest of the API — and, in its last chapter, copying a photograph. The reasons, and `easel explain <code>` prints the one a notice points at; read a section when it does, or the whole thing before the first mark. Skip the last chapter unless you have a photograph. ~7,400 words.
- [REFERENCE.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/REFERENCE.md): every fact on one page — the units (and that is where the surprises are), the defaults, what each argument does, the shell, and the MCP server. For looking up while holding a brush rather than reading. ~8,800 words. Nothing in it is a rule about painting; the rules are all in the guide, and a fact looked up without its rule is how a painting comes out correct and dead.

## Worked examples

- [Painting a car wash: the notes](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/paintings/Claude/car_wash/NOTES.md): a full painting, written up afterwards — the plan, what each stage cost, what was rehearsed and thrown away, and what it got wrong. Read it to see how the engine is actually used, not to choose what to paint.
- [Its nineteen pass scripts](https://github.com/Gemberkoekje/EaselAPI/tree/main/paintings/Claude/car_wash): the painting itself, in order, as ordinary Python.
- [Painting three pears: the notes](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/paintings/Claude/windowsill_pears/NOTES.md): a second painting under the same rules, and the one that started the request list the engine has been answering since.
- [Painting a lighthouse at dusk: the notes](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/paintings/Claude/lighthouse_dusk/NOTES.md): a third, in 184 strokes of a 300 budget with eighteen rehearsals and no stroke spent on repainting anything. Most of `RECIPES.md` came out of its [ten pass scripts](https://github.com/Gemberkoekje/EaselAPI/tree/main/paintings/Claude/lighthouse_dusk).
- [examples/exercises.py](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/examples/exercises.py): abstract warm-ups straight from the guide — a value scale, pressure profiles, wet-into-wet — deliberately not pictures of anything.

## Evidence

- [PAINTINGS.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/PAINTINGS.md): every finished painting at full size, the rules they were made under, what they cost, and an honest reading of how good they are.

## Optional

- [CALIBRATION.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/CALIBRATION.md): the measurement behind every number the guide quotes — graphite survival, wetness decay, the value floor, load windows, the smudge and glaze curves — indexed by rule at the top, with what painters reported about their own sessions kept in a section of its own. You do not need these to paint.
- [LESSONS.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/LESSONS.md): what six measured painting runs and an adversarial review left behind. Read it before changing the engine or the guide, not before painting.
- [SUGGESTIONS.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/SUGGESTIONS.md): what twenty-one painters asked for after using the guide — what was wrong, and what was done about it. Everything is done, including eight answered by measuring them and finding nothing to fix.
- [CHANGELOG.md](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/CHANGELOG.md): the same history cut by release — what changed in each version and which defaults moved, which is what a script that leaves an argument off will paint differently after an upgrade.
- [Source](https://github.com/Gemberkoekje/EaselAPI/tree/main/src/easel): the engine. `session.py` is the object you hold, `color.py` the Kubelka-Munk pigment mixing, `stroke.py` the paint load and tooth model, `mcp_server.py` the MCP tools.
