# Euclid — Code Review & Architecture Docs

> Audience: the next LLM agent (Claude or otherwise) or human picking this
> codebase up cold. These docs are written to be read top-to-bottom or jumped
> into by section. Every claim is grounded in a named file; line references use
> the `file.js:NN` form so you can open them directly.

## TL;DR (read this first)

**Euclid is a browser-based synthesiser that turns on-chain generative artworks
("Cyphers") into sound.** Each Cypher is a deterministic circular drawing of 16
concentric rings made of arcs and segments, originally generated by an Ethereum
smart contract (`CypherDrawing.sol`) in 2021. Euclid reads a Cypher's geometry
as **Euclidean sequencer data**: rings are tracks, segments are evenly-spaced
trigger events, and each segment's visual attributes (colour, fill, edge, span
type, radius, thickness, rotation phase) become **modulation sources**. A
declarative **binding engine** maps those sources onto **synth parameters** of a
fixed FM → wavefold → filter voice, one voice per ring (16 voices). Audio is
synthesised in a WebAssembly DSP (`dsp.c` → `dsp.wasm`) running in an
AudioWorklet.

```
Cypher artwork (JSON)  ──►  binding engine  ──►  16-voice WASM synth  ──►  sound
   rings/arcs/segments      sources→targets      FM/fold/filter/delay
   = sequencer data         via patches
```

There is **no build step for the JS** — it is plain ES modules loaded directly
by a single-file app (`index.html`).
Only `dsp.c` is compiled (to `dsp.wasm`, via the WASI SDK).

## Reading order

| # | Doc | What it covers |
|---|-----|----------------|
| 1 | [01-overview.md](01-overview.md) | What the project is; the Cypher concept; the "art as sequencer" idea |
| 2 | [02-architecture.md](02-architecture.md) | The runtime pipeline, the per-frame tick loop, module dependency map |
| 3 | [03-cypher-format.md](03-cypher-format.md) | `CypherDrawing.sol` generator + the Cypher JSON schema |
| 4 | [04-binding-engine.md](04-binding-engine.md) | `sources.js` / `targets.js` / `shapes.js` / `bindings.js` + patch format |
| 5 | [05-audio-dsp.md](05-audio-dsp.md) | `audio.js` / `synth.js` / `dsp.c`; the 44-register voice frame |
| 6 | [06-ui-and-views.md](06-ui-and-views.md) | the `index.html` app + the SVG view renderers |
| 7 | [07-build-test-data.md](07-build-test-data.md) | Build scripts, `verify.mjs`, the data-manifest pipeline |
| 8 | [08-file-map.md](08-file-map.md) | Per-file reference table; what's active vs legacy |
| 9 | [09-glossary-gotchas.md](09-glossary-gotchas.md) | Terms, invariants, known caveats & TODOs |

## The single most important mental model

Everything flows through one data shape: the **segment instance**. Per animation
frame, `cypher.js:buildTickFromCypher()` walks the Cypher tree and emits a flat
list of segment records, each carrying every attribute a binding could read
(projected down from its ring and arc). `bindings.js:runBindings()` consumes that
list and produces **voice frames** (one per ring). `audio.js:writeVoiceFrames()`
ships them to the WASM DSP. If you understand the segment instance, you
understand the data plane of the whole app.

## Status notes (don't trip on these)

- `legacy/presets.js` is **legacy** — superseded by `cypher.js` +
  `transport.js`. The live apps do **not** import it. See doc 08 and
  `legacy/README.md`.
- `legacy/euclid-source.md` is a **historical handover bundle**
  describing an earlier architecture (`editor.js`, `definitions.js`,
  `labels.js`, `compiler.js`). Those files no longer exist. Trust the live
  source over that document.
- MIDI targets are defined (`targets.js`) and the engine emits MIDI events, but
  MIDI output is **only partially wired**; the shipped audio path is the WASM
  synth. See doc 04 / 05.
- App version markers in the HTML read **v0.7 / v0.8 / v0.9** — this is
  pre-release, actively-evolving code.
