An API for an LLM to create images via brush strokes
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
git clone https://github.com/Gemberkoekje/EaselAPI && cp EaselAPI/*.md ~/.claude/agents/Subagents overview
# Easel
**Can an LLM paint with real brush strokes, rather than draw with pixels? Yes — this is
the API for it.**
Easel is a headless painting engine for AI agents: brushes, paint load, wet blending
and canvas texture, driven from Python, from a shell, or over MCP. A brush carries a
finite load of paint and runs out along a stroke. Paint lands wet and mixes with what
is already there, in a pigment model where blue and yellow make green rather than grey.
The canvas has tooth, and a brush low on paint catches only the high points — so dry
brush is not a special effect, it is what happens when you run out of paint on rough
canvas. Between strokes you look at your own work, which is the whole point: the engine
is built for an agent that can see what it just did.
It is not a drawing library, not a rasteriser, and not an image generator — nothing
here turns a prompt into a picture. You choose and make every mark. There are no
layers, and no undo that costs nothing: you work in passes, and when something is wrong
you paint over it.
**Read the guide before you paint.** The engine is only the brush;
[`PAINTER.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTER.md) is the method, and six measured runs say the method
is the half that matters. It ships inside the package, so there is nothing to go and
find: **`easel guide`** prints its first page — the whole workflow, under a thousand
words — and `easel guide --full` prints the rest.
```python
from easel import Session, blob, cell
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) # check the value structure
s.stroke([(0.2, 0.6), (0.6, 0.55), (0.9, 0.62)], "bristle", "yellow_ochre")
s.export("painting.png")
```
## Three paintings, made this way

*[**Inside a car wash, from the driver's seat**](https://github.com/Gemberkoekje/EaselAPI/blob/main/paintings/car_wash/NOTES.md) — 206
strokes of a 300 budget, 1152×720 linen, no reference photograph. The nineteen pass
scripts beside it reproduce that PNG byte for byte.*

*[**Three pears on a kitchen windowsill**](https://github.com/Gemberkoekje/EaselAPI/blob/main/paintings/windowsill_pears/NOTES.md) — 224
strokes, 1024×768 linen, no reference photograph.*

*[**A lighthouse on a rocky headland at dusk**](https://github.com/Gemberkoekje/EaselAPI/blob/main/paintings/lighthouse_dusk/NOTES.md) — 184
strokes of a 300 budget, 1024×768 linen, no reference photograph. Eighteen rehearsals,
none of them charged; the ten pass scripts beside it reproduce that PNG byte for byte.*
All three were painted by a language model working from [`PAINTER.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTER.md),
one call to this API at a time, with no human hand on the canvas and nothing traced.
Every stroke is in the log, every time-lapse was rebuilt from it, and the notes beside
each painting say what went wrong as well as what went right.
[`PAINTINGS.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTINGS.md) gathers the record, and *The worked examples* below
says what each one is made of.
**If you are about to paint from the guide yourself: have you decided what to paint?**
If you have, these are yours to study and the scripts beside them are the best thing
here. If you have not, do not look — a worked example names a subject and a named
subject chooses for you, as six of six fresh sessions once demonstrated by painting a
noun the guide had merely listed in passing. Decide first, then look.
## The brushes themselves

*Every brush, size and pressure profile, on each canvas texture. Regenerate with
`python scripts/make_brush_sampler.py` — this sheet is the project's primary test
artefact, and looking at it catches what the test suite cannot.*

*A mass does not have to be a rectangle. Each row is one way of building a shape,
each column a way of sweeping it; the last column is the box that mass would have
been. Regenerate with `python scripts/make_shape_sampler.py`.*
## Install
Requires Python 3.12 or newer. Only numpy and Pillow — nothing that is painful to
build on Windows.
```bash
pip install easel-paint # the engine, the CLI and the Python API
pip install "easel-paint[mcp]" # and the MCP server
```
From a checkout, `pip install -e .` and `pip install -e ".[mcp]"` do the same two
things.
Either installs an `easel` command. Pip puts it in the interpreter's scripts
directory, which is often not on `PATH` (it warns when it is not), so
`python -m easel ...` is always available as the same command by another name.
The MCP server is an opt-in extra because nothing else in the engine imports it.
See *MCP server* below.
## If you are an LLM agent, read PAINTER.md
[`PAINTER.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTER.md) is the guide written for you. It teaches the *workflow* —
tone the ground, paint back to front, check values, refine, edges, highlights
last — rather than listing functions, and it opens with *the first hour*: the whole
method on one page, so the eight warm-up exercises come before anything else.
It is one file of five, split by what you do with each rather than by subject, because
three painters each said the same two things — the guide is long, and the essay in it is
what made the rules stick. Nothing was cut to shorten it; it was moved, and `PAINTER.md`
is now held to a word budget by the test suite.
| | |
|---|---|
| [`PAINTER.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTER.md) | the method: the order of work, the mistakes, the exercises, the checklist. Held in your head |
| [`PAINTING.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/PAINTING.md) | the reasons: colour, wet paint, the brushes, working from a reference. Read once |
| [`RECIPES.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/RECIPES.md) | the procedures: the calls in order for a kind of thing, and what it looks like when it goes wrong |
| [`REFERENCE.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/REFERENCE.md) | the facts: units, defaults, what each argument does |
| [`CALIBRATION.md`](https://github.com/Gemberkoekje/EaselAPI/blob/main/CALIBRATION.md) | the numbers behind the rules, each with what it was measured on |
The engine is designed around one habit:
> Look every five to fifteen strokes. A stroke you did not look at was a guess.
[`llms.txt`](https://raw.githubusercontent.com/Gemberkoekje/EaselAPI/main/llms.txt) is
the same signpost in the format a model fetching this repository is increasingly told
to look for: the summary, what to know before reading further, and where each document
is, in about 850 words.
## What is in the box
| Piece | What it does |
|---|---|
| `Session` | The one object you hold. Canvas, palette, seed, history, `look()`. |
| `Canvas` | Linear-light RGB plus `wetness`, `thickness`, `sketch` (graphite) and canvas `height` (tooth). |
| Brushes | `round_soft`, `round_hard`, `liner`, `flat`, `bristle`, `knife`, `smudge`. Procedural tips, and `tip_wobble` gives a round one a silhouette of its own, redrawn per mark. |
| `Palette` | A limited pigment set with no black. Mix, tint, shade, and name your mixes. |
| Regions | `region("top-left")`, `cell("D6")`, `horizon(0.4)`, `below(...)`, `between(...)`. |
| Shapes | A mass that is not a box: `blob`, `ellipse`, `hull`, `union`, `ribbon`, `polygon`, and `s.circle()` for one that is round in pixels on any canvas. `smooth()` cuts the corners off an outline. Any of them goes where a region goes. |
| Masses | `block_in(place, ...)` fills a rectangle *or a shape* with overlapping passes, stopping at the silhouette, or drawing its contour with `edge="clean"`; `solid=True` when it has to be solid paint, because density spaces the passes rather than filling them. `sweep(edge, ...)` lays a mass as passes along its own boundary, stepped inward. Both emit ordinary strokes. |
| Passages and repairs | `scumble(band, a, b, n)` lays a soft passage as `n` overlapping passes stepping between two values — the thing a gradient tool would be for, as paint — and `direction="inward"` runs them round a patch instead of across it, for a value falling off from a centre. `cover(place, color)` buries a mistake with every clause of the correction recipe already set. `smudge(edge, ...)` loses an edge along its own shape: points, or a mass whose outline it walks. |
| `look()` | Grid overlay, greyscale values, region crop, side-by-side, diff, landmarks, and a fine grid of labelled tenths inside a crop. |
| DrawWhat people ask about EaselAPI
What is Gemberkoekje/EaselAPI?
+
Gemberkoekje/EaselAPI is subagents for the Claude AI ecosystem. An API for an LLM to create images via brush strokes It has 0 GitHub stars and its last recorded update is dated 2026-09-12.
How do I install EaselAPI?
+
You can install EaselAPI by cloning the repository (https://github.com/Gemberkoekje/EaselAPI) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is Gemberkoekje/EaselAPI safe to use?
+
Our security agent has analyzed Gemberkoekje/EaselAPI and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains Gemberkoekje/EaselAPI?
+
Gemberkoekje/EaselAPI is maintained by Gemberkoekje. The last recorded GitHub activity is dated 2026-09-12, with 1 open issues.
Are there alternatives to EaselAPI?
+
Yes. On ClaudeWave you can browse similar subagents at /categories/agents, sorted by popularity or recent activity.
Deploy EaselAPI to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/gemberkoekje-easelapi)<a href="https://claudewave.com/repo/gemberkoekje-easelapi"><img src="https://claudewave.com/api/badge/gemberkoekje-easelapi" alt="Featured on ClaudeWave: Gemberkoekje/EaselAPI" width="320" height="64" /></a>More Subagents
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
The agent that grows with you
Java 面试 & 后端通用面试指南,覆盖计算机基础、数据库、分布式、高并发、系统设计与 AI 应用开发
Build Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.
The agent engineering platform.
Makes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote.