Skip to content

acmedity/no-notes

Repository files navigation

No Notes

No Notes runs a drawing session where an LLM makes an image one step at a time while a blind chorus of absurd critics interrupts between steps. It saves every frame, every command, and every line of text, then bundles the result into a self-contained gallery player HTML file.

It is adapted from Kyle Booten's Lotus Chorus Workshop, ported from creative writing to visual art-making.

What it does

  1. An artist model states an intention for the next drawing step.
  2. A chorus model speaks through one or more critic personas from config/chorus.yaml.
  3. The artist responds and emits drawing commands.
  4. No Notes renders those commands to a canvas and logs the whole exchange.
  5. make_player.py turns the session into a playable web page.

Project layout

path purpose
config/config.yaml Main control panel: models, session length, canvas backend, output settings.
config/chorus.yaml The critic personas. This is the most authorial/editable file.
config/tts.yaml Optional text-to-speech settings. Keep real voice IDs in config/tts.local.yaml.
run_session.py Runs a full drawing session.
make_player.py Builds a self-contained gallery player HTML file from a session.
canvas.py Selects the active canvas backend.
svg_canvas.py SVG vector backend.
excalidraw_canvas.py Excalidraw-style vector backend.
models.py Provider adapters for OpenAI, Anthropic, and OpenRouter.
player_template.html Gallery player template.
renderers/excalidraw/ Optional official Excalidraw PNG renderer.

Requirements

  • Python 3.10+
  • At least one LLM API key:
    • OpenAI
    • Anthropic
    • OpenRouter
  • Optional, only for the official Excalidraw renderer:
    • Node.js
    • Playwright Chromium
  • Optional, only for macOS local TTS:
    • macOS say and afconvert commands

The default config uses OpenAI and the simple paint canvas backend.

Setup

Clone the repo and enter it:

git clone https://github.com/your-username/no-notes.git
cd no-notes

Create and activate a virtual environment:

python3 -m venv .venv
source .venv/bin/activate

On Windows PowerShell, activation is usually:

.venv\Scripts\Activate.ps1

Install Python dependencies:

pip install -r requirements.txt

Create your local environment file:

cp .env.example .env

Edit .env and replace the placeholders with real API keys. .env is ignored by Git and is loaded automatically by the Python scripts.

For the default config, you only need:

OPENAI_API_KEY=your-real-key

If you switch providers in config/config.yaml, set the matching key instead.

Run a session

python run_session.py

When it finishes, it writes output to a new folder under sessions/, for example:

sessions/session_20260604_143022

Useful options:

python run_session.py --steps 20
python run_session.py --name spider_attempt

Build the gallery player

python make_player.py sessions/session_20260604_143022

This creates gallery_player.html inside the session folder. Open it in a browser. Press space to play/pause, arrow keys to step manually, and F for fullscreen.

Model configuration

Edit config/config.yaml to choose providers and models.

The artist model must support image input because it sees the canvas. Chorus models do not need image input because the chorus is deliberately blind.

Example OpenRouter artist config:

artist:
  provider: openrouter
  model: openai/gpt-4o
  temperature: 1.0

Example Anthropic artist config:

artist:
  provider: anthropic
  model: claude-3-5-sonnet-latest
  temperature: 1.0

Supported providers are implemented in models.py:

  • openai
  • anthropic
  • openrouter

To add another provider, add a new adapter in models.py and register it in ADAPTERS.

Canvas backends

Set the backend in config/config.yaml:

canvas:
  backend: paint       # "paint" | "svg" | "excalidraw"

paint

The simplest backend. Uses Pillow to render chunky MS-Paint-style raster marks. This is the default and requires no Node setup.

svg

Renders vector commands to SVG and PNG using CairoSVG. It supports paths, polylines, hatching, scatter, gradients, text, and optional raw SVG fragments.

canvas:
  backend: svg
  svg_mode: limited    # "limited" | "hybrid" | "raw"

excalidraw

Uses an Excalidraw-style scene backend. The preview renderer is Python-only; the official renderer needs Node and Playwright.

canvas:
  backend: excalidraw
  renderer: preview    # "preview" | "official"

For the official renderer:

cd renderers/excalidraw
npm install
npx playwright install chromium
cd ../..

Optional text-to-speech

You can build a player with inlined TTS audio:

python make_player.py sessions/session_20260604_143022 --tts --out gallery_player_tts.html

Supported TTS providers:

# macOS system voices
python make_player.py sessions/session_20260604_143022 --tts-provider macos

# Typecast
python make_player.py sessions/session_20260604_143022 --tts-provider typecast

# Fish Audio
python make_player.py sessions/session_20260604_143022 --tts-provider fish

Keep real Typecast/Fish voice IDs in config/tts.local.yaml, not in config/tts.yaml. config/tts.local.yaml is ignored by Git and overrides the public defaults.

Tuning the piece

The chorus lives in config/chorus.yaml. Each voice is just text. Rewrite, add, or remove voices to change the pressure the artist experiences.

Every voice inherits a shared instruction that critiques the work, not the artist. That boundary is part of the project structure.

Useful settings in config/config.yaml:

session:
  steps: 10

chorus_behavior:
  voices_per_step: 3
  selection: random    # "random" | "all" | "escalating"

Outputs and generated files

Session output goes into sessions/, which is ignored by Git. A session may contain:

  • frames/ — rendered step images
  • action_frames/ — optional command-by-command images
  • final.png
  • final.svg or final.excalidraw, depending on backend
  • transcript.json
  • gallery_player.html
  • .tts_cache/, if TTS is used

Optional player assets

The gallery player checks for optional assets:

  • assets/fonts/PPMondwest-Regular.otf
  • assets/goldframe.png

They are not required. If absent, the player falls back to system fonts and no decorative frame. Only commit replacement assets if you have redistribution rights.

Troubleshooting

  • No module named yaml or No module named PIL: activate your virtualenv and run pip install -r requirements.txt.
  • API/authentication error: check that .env contains the key for the provider selected in config/config.yaml.
  • Artist output is unparseable: try a different model or lower temperature.
  • The run is slow: model calls dominate runtime. Reduce session.steps for quick tests.
  • Official Excalidraw rendering fails: use renderer: preview, or run the Node/Playwright setup in renderers/excalidraw/.

License

MIT. See LICENSE.

About

No Notes runs a drawing session where an LLM makes an image one step at a time while a blind chorus of critics interrupts between steps. It saves every frame, every command, and every line of text, then bundles the result into a file you can play back.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors