diff --git a/docs/REPOSITORY.md b/docs/REPOSITORY.md index fa6dfd3e8..48a6ff1ba 100644 --- a/docs/REPOSITORY.md +++ b/docs/REPOSITORY.md @@ -9,6 +9,7 @@ A map for people. (AI coding agents get the same map with more rules in [`../AGE | `firmware/` | The ESP32-S3 firmware. `patternflow/` is the sketch: `patternflow.ino`, `config.h` (pins, brightness, limits, calibration), `net_config.h` (Wi-Fi, OTA, update defaults), `src/` (the engine: HUB75 driver, encoders, canvas, colour, noise, Wi-Fi, web console — the **core**, compiled unchanged into every published firmware), `features/` (everything optional: OSC, audio, the microphone, MQTT, MIDI, shows, weather, clock, BLE — attached through hooks the core exposes), `presets/` (the curated patterns), `abi/` (the frozen contract a `.pfm` module is compiled against), `console/` (the device's web pages as plain HTML). `bundles/` names the compositions — the shelf editions `audio` and `performance`, plus `clock` and `midi`, which CI keeps compiling but the shelf does not carry — and holds `build.sh` and `shelf.sh`. `toolchain/` is the repo-level scripts: build a module, make the Basics pack, and the `check_*.py` that CI runs. `modules/` is the module toolchain's working folder, not a place patterns are contributed to. `encoder_test/` is a standalone sketch for checking the four encoders, and `CUSTOM_PATTERNS.md` the hands-on pattern route | [`firmware/README.md`](../firmware/README.md) for building; [`EDITIONS.md`](EDITIONS.md) before touching anything | | `hardware/` | `pcb/` (KiCad source, Gerbers per revision, schematic PDF), `case/` (STLs by printer bed size, knob plates, the Blender source, legacy v2 cases, the old v1/v2 laser-cut drawings in `legacy_lasercut/`, and `remixes/` — enclosures other people designed and built, one folder each), `bom/` (the CSV that is the BOM source of truth) | [`hardware/README.md`](../hardware/README.md) | | `web/` | The Next.js site at patternflow.work: landing page, the interactive guide (`/guide`, with `/guide/build`, `/guide/play`, `/guide/make` and `/guide/audio`), Live Editor, Pattern Lab, the community (only on the community host), the browser flasher (the **Flash Patternflow** button on the Pattern tab and in the Play guide; the images it installs are `public/flash/`), edition shelf, feature catalogue, device update handoff, journal, roadmap. The JS presets in `src/lib/presets/` are the source of truth for the firmware's preset headers. The breadboard build guide is a React page here, `src/app/build/breadboard/` | [`web/README.md`](../web/README.md), then [`web/ARCHITECTURE.md`](../web/ARCHITECTURE.md) | +| `shared/` | `constants.json`, the values the firmware and the site both carry: the panel geometries, the knob count, the encoder's 24 detents a turn, the bus maximum and the button timings. `npm run gen:shared` in `web/` writes `firmware/patternflow/src/core_shared.h` and `web/src/lib/shared/constants.ts` from it. Neither is edited by hand, and `check:shared` fails while either is stale. The folder exists because the lab counted 20 detents a turn, against the encoder's 24, until 31 July 2026 | [`constants.json`](../shared/constants.json) | | `docs/` | Contracts other software is built against, how the firmware is put together, walk-throughs, the audio guide (`AUDIO_GUIDE.md`), the assembly map, the legacy v2.x build guide (`legacy/`), the writing voice (`voice.md` and `voice-banned.txt`), project records (`releases/`, one file per release) and media | [`README.md`](README.md) | | `tools/` | Clients Patternflow ships that run on their own: the audio-react browser extension (also the authoring source of the device's `/audio-in` page), the Android capture app, an RTP-MIDI probe. Also `case-models/`, the scripts that make the /build page's 3D model of each case, the official one and every remix on its case switch | [`tools/README.md`](../tools/README.md) | | `integrations/` | Bridges that run inside or beside someone else's software (Ableton / Max for Live today) and talk to the panel only through the contracts in `docs/` | [`integrations/README.md`](../integrations/README.md) | diff --git a/firmware/README.md b/firmware/README.md index 5f99ca1fd..6f5e310fe 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -156,10 +156,13 @@ Library Manager: > not the plain device. > The HUB75 library is also **vendored** under `patternflow/src/hub75/`, and that -> copy is the one that compiles — it carries Patternflow's additions -> (`resumeDMAoutput()` for sleep, the brightness hook the power clamp uses). The -> installed/cloned copy only needs to satisfy headers, so its exact version does -> not matter. See `src/hub75/VENDORED.md`. +> copy is the one that compiles. [`UPSTREAM.md`](patternflow/src/hub75/UPSTREAM.md) +> there names the upstream tag and commit it was copied from, and each upstream +> commit taken since. Every line Patternflow changed is in `patternflow.patch` +> beside it, and [`VENDORED.md`](patternflow/src/hub75/VENDORED.md) says why. +> After an edit under `src/hub75/`, rebuild the patch with the command in +> `UPSTREAM.md` instead of editing it. The installed/cloned copy only needs to +> satisfy headers, so its exact version does not matter. OSC uses the ESP32 Arduino core's built-in `WiFi` and `WiFiUdp` libraries, so it does not require an extra OSC library. The MQTT client (`pubsubclient`) and the HUB75 driver are vendored under `patternflow/src/`. diff --git a/web/ARCHITECTURE.md b/web/ARCHITECTURE.md index abd5a30e8..abf538bf1 100644 --- a/web/ARCHITECTURE.md +++ b/web/ARCHITECTURE.md @@ -56,7 +56,7 @@ Cross-component landing state (active tab, virtual knob values, bloom toggle, th Mirrors the firmware; the same JS runs in the browser, in the community's sandbox iframe and in the lab's worker. - **`src/lib/presets/`** — JS pattern sources, one file per pattern. **Source of truth** for the firmware preset `.h` files (`firmware/patternflow/presets/`; the web has more presets than the firmware — the cut list is in `firmware/patternflow/README.md`). `_TEMPLATE.ts` is the skeleton; `index.ts` the registry. -- **`src/lib/pattern/harness.ts`** — runs pattern JS on a 128×64 virtual matrix with 4 virtual encoders (24 detents/turn), matching device semantics (`knobDeltas`, `btnPressed`/`btnHeld`); also the OKLab/OKLCH colour ramp math and the LUT builders. `public/pattern-sandbox.html` is **built from it** — `scripts/build-sandbox.ts` bundles `src/sandbox/sandbox.ts` (the canvas, the live loop, the postMessage protocol) with the runtime it imports, and `check:sandbox-sync` fails when the committed page is not that build. It was a hand-kept ES5 port until 3.9.4, and it drifted (`next.config.ts` records one such bug; another was 20 detents a turn against the lab's 24). +- **`src/lib/pattern/harness.ts`** — runs pattern JS on a 128×64 virtual matrix with 4 virtual encoders (24 detents/turn), matching device semantics (`knobDeltas`, `btnPressed`/`btnHeld`); also the OKLab/OKLCH colour ramp math and the LUT builders. `public/pattern-sandbox.html` is **built from it** — `scripts/build-sandbox.ts` bundles `src/sandbox/sandbox.ts` (the canvas, the live loop, the postMessage protocol) with the runtime it imports, and `check:sandbox-sync` fails when the committed page is not that build. It was a hand-kept ES5 port until 3.9.4, and it drifted (`next.config.ts` records one such bug; another was 20 detents a turn against the lab's 24). The 24 now comes from `src/lib/shared/constants.ts`, and so do the panel size and the knob count. `npm run gen:shared` writes that file from `shared/constants.json` at the repository root, the same source as the firmware's `core_shared.h`. - **Annotations** — a pattern's frame, ramp, knob ranges and layer stack travel *inside its code* as one-line comments so they survive every copy: `@matrix` (`src/lib/pattern/matrix.ts`), `@ramp` (`src/lib/pattern/ramp.ts`), `@knobs` (`src/lib/pattern/knobs.ts` — the lab's knob state in `src/lib/lab/annotations.ts` and the community's card reader in `src/lib/community/knobs.ts` both build on it), `@stack` (`src/lib/lab/stackShare.ts`). - **`src/lib/pattern/controls.ts`** — knob-scale constants shared with the firmware. - **`src/lib/pattern/share.ts`** — licence header + attribution footer, injected at export time only. @@ -77,7 +77,7 @@ A layered, dockable workspace: nine panels over a layer-stack project. A panel i Each panel owns its stylesheet (`panels/.module.css`); `PatternLab.module.css` keeps only what two or more files draw with, and `LabPanels.module.css` the dock chrome. The lab reaches the community through exactly one file, `community.ts` (the publish and send modals, the configured switches, the handoff, the `.pfs` reader) — ESLint refuses any other import of `@/components/community` or `@/lib/community` from under the lab. -Exports flatten the visible stack to one standalone pattern (`flatten.ts`); `hExport.ts` writes the C++ header; `HardwareModal.tsx` sends it to the build service or the panel. Persistence is `localStorage`: the project (`serialize.ts`, `patternflow_lab_project_v2`), the dock layout, a ring of parked sessions (`sessions.ts`), capture settings and shaders under their own keys, and the legacy v1 draft/gallery keys read by `src/lib/lab/legacyDraft.ts`. +Exports flatten the visible stack to one standalone pattern (`flatten.ts`); `hExport.ts` writes the C++ header; `HardwareModal.tsx` sends it to the build service or the panel. Persistence is `localStorage`: the project (`serialize.ts`, `patternflow_lab_project_v2`), the dock layout, a ring of parked sessions (`sessions.ts`), capture settings and shaders under their own keys, the generated gallery (`patternflow_lab_gallery_v1`, still the live key, read and written by `src/lib/lab/legacyDraft.ts`), and the draft and ramp keys the lab stopped writing at Pattern Lab v2 on 27 July 2026, which `migrateLegacyDraft` in `serialize.ts` lifts into a project when none restores. ## Community (`src/lib/community/` + `src/components/community/`)