paint-cost-lab
by kajetanmazur
README.md
# Paint Cost Lab
One Paint application. One reference photo. Claude Code draws it twice: with
its usual setup and with a cost-control framework. Compare drawing quality,
completion time and the full cost of each drawing session.
**Status:** working prototype. A local paired portrait pilot has been recorded;
experiment images, transcripts and its report are maintained separately. Building the
editor is a separate development cost, not one of the two drawing runs.
Live editor: https://kajetanmazur.github.io/paint-cost-lab/
## Try the editor
Serve the `web` directory with any static server:
```sh
python3 -m http.server 8080 --directory web --bind 127.0.0.1
```
Open http://127.0.0.1:8080. Upload a portrait or use the included original demo
illustration. Draw, erase, undo/redo, export a PNG or save the stroke log.
The editor has no auto-tracer, image generator, API key field or fake AI chat.
The run selector only labels exports; it does not enable the framework.
All assets use relative URLs. The `web` folder is suitable for GitHub Pages,
including deployment at a repository subpath. Photos stay in browser memory;
reloading clears the session. Export your work before closing it.
## Connect your own Claude Code locally
The public editor does not provide a hosted Claude. Use your own Claude Code
installation/account, Python 3.11+ and the local MCP server in this repository.
It launches a **separate visible browser window** with the same editor. An
existing GitHub Pages tab is not automatically connected.
From this project's directory:
```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m playwright install chromium
claude mcp add --scope local paint-cost-lab -- "$PWD/.venv/bin/python" "$PWD/server.py"
```
On Windows use the corresponding `.venv\\Scripts\\python.exe` path. If using an
installed Google Chrome instead of downloading Chromium, register with:
```sh
claude mcp add --scope local paint-cost-lab -e PAINT_BROWSER_CHANNEL=chrome -- "$PWD/.venv/bin/python" "$PWD/server.py"
```
Choose **one** registration command. Start a new Claude Code session in the
same project directory. Ask it to call `studio_view` and wait for you to upload
the reference in the opened window. Then ask it to draw the portrait.
The server exposes four tools: view, one brush stroke, undo/redo and export.
Strokes use the real color/size controls and mouse input; there is no arbitrary
JavaScript, direct pixel replacement, source-image copying or auto-tracing tool.
A view sends a screenshot containing your reference and drawing to your Claude.
You decide which photos to use. Server action logs and outputs are local under
`artifacts/` and excluded from Git. CLI usage/cost logs must be collected separately.
For independent sessions, exit the previous CLI so its MCP process closes,
then start a new CLI with a fresh MCP process and upload the same photo. Each
process gets an isolated browser and artifact directory. Do not use the label
selector as a session reset.
## Drawing experiment
1. Freeze the editor/server revision, photo, model version, effort, prompt,
screenshot size, limits and evaluation rubric before running.
2. Use the same four painting tools in both arms. Both can see the reference,
choose colors, draw, inspect, correct and export. No source reading or image
processing scripts as alternate drawing channels in the controlled test.
3. Standard arm: record the actual CLI configuration. Framework arm: record
all policy/tool/context differences. Integrate this MCP server explicitly:
the existing cost-lab controller disables MCP by default and cannot run
this experiment unchanged. Do not silently drop the painting tools.
4. Start from a blank canvas for each run. The app itself applies no artistic
improvements. The model chooses every stroke.
5. Include screenshot calls, reasoning, retries, repairs and helper calls in
cost. Report input/cache-read/cache-write/output separately; don't add
thinking to output twice. CLI USD is an estimate, not a subscription bill.
6. Compare anonymous drawings against the same reference: likeness, facial
proportions, colors, completeness. A cheap unfinished drawing is not a win.
7. Pilot one pair, then repeat at least three pairs if the budget permits.
Alternate order and retain failures. Fresh sessions can still share cache.
Default test should not assume a reset every three final replies saves money.
Prior coding experiments found it increased cost. Painting is a new workload;
measure the selected framework policy without assuming it transfers.
### Common drawing prompt
> Use only the Paint Cost Lab tools to draw the uploaded reference portrait on
> the blank canvas. Aim for a recognizable, stylized likeness: face shape,
> proportions, hair, main colors and distinctive features. Choose your own
> brush strokes. Inspect your progress and correct mistakes when useful.
> Do not trace/copy the image with code, access files, or use other image tools.
> Finish by exporting the drawing with studio_save. Follow the shared limits
> supplied with this experiment.
Exact cost/time/tool-call limits must be supplied by the runner before starting,
not invented by the model. Freeze them equally for both arms.
## GitHub Pages
Publish only the contents of `web/`. Keep `server.py`, README and tests in the
source repository for people who want to connect their own Claude. Do not
publish `artifacts`, portraits, credentials or CLI transcripts. This repository publishes `web/` to the `gh-pages` branch. GitHub Pages is
configured to serve the root of that branch. After committing changes to
`main`, update the deployed branch with:
```sh
git subtree push --prefix web origin gh-pages
```
## Local checks
```sh
.venv/bin/pip install pytest
PAINT_HEADLESS=1 PAINT_BROWSER_CHANNEL=chrome .venv/bin/python -m pytest -q
```
Tests exercise the editor in Chrome and the MCP connection without paid model
calls. If you installed Playwright Chromium, omit PAINT_BROWSER_CHANNEL.
### Recording a controlled experiment
The MCP server accepts optional environment settings for an experiment runner:
`PAINT_REFERENCE` (local image path), `PAINT_OUT` (new output directory),
`PAINT_LABEL` (`standard` or `framework`), `PAINT_RECORD=1`,
`PAINT_MAX_STROKES` and `PAINT_MAX_VIEWS`. These configure the shared environment;
they do not change the model's painting logic. With recording enabled the server
uses a fixed studio layout and writes a native browser `capture.webm` on shutdown.
Action logs include canvas bounds and a recording timestamp so a video editor
can crop the drawing and align it with CLI events. In recording mode,
`studio_save` finishes the run and finalizes the video before replying; subsequent
drawing calls require a new MCP process.
Cost and token usage still come from the Claude CLI transcript. A recording alone
cannot measure model cost. The local pilot is separate from this public editor; no portraits or raw CLI
transcripts are uploaded by the app.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues