Skip to content

dev → main: journal 'A Strange Dream' + features page, knob settings, MIDI edition - #434

Merged
engmung merged 8 commits into
mainfrom
dev
Sep 16, 2026
Merged

engmung merged 8 commits into
mainfrom
dev

Conversation

@engmung

@engmung engmung commented Sep 16, 2026

Copy link
Copy Markdown
Owner

What changed

New journal post — a-strange-dream (ko + en), published 2026-09-16: a vivid dream about a snake, the first artist edition going out signed with a certificate Hyunji designed, and a few low days before it.

One image, placed beside the certificate paragraph and used as the cover: the certificate's front (recipient name already blurred in the source photo) and its Patternflow-shaped back, joined side by side (2416×1600 JPEG, 430 KB).

Also on dev and carried by this PR (already committed there, not new work for this post):

  • firmware: MIDI edition — the DevKit's USB port as a MIDI device
  • firmware: knob direction and click size as settings, on a /knobs page
  • firmware: the shelf is Core, Audio and Performance; an edition cuts on its own; CI builds compositions in parallel
  • web: the features page, one row per feature with a reel each, including the note on the failed Bluetooth attempt

Notes

  • Verified the post against the running dev server: both language versions return 200, the image serves, and the index hero points at the new post with the certificate as its thumbnail.
  • No highlight set.
  • Uncommitted working-tree changes on dev (CONTRIBUTING.md, inside page, globe card) are not part of this PR.

🤖 Generated with Claude Code

engmung and others added 7 commits September 15, 2026 19:25
A second transport for the MIDI feature: plug the panel into a computer
with the cable it is flashed over and it is a class-compliant MIDI device
named "Patternflow" - no driver, no session, no Wi-Fi in the path. Same map
as RTP-MIDI (CC 20-23 hold, 24-27 nudge, notes 60-63 press, program change
picks a pattern; encoders out as CC 24-27), both transports up at once.

The transport (features/midi/core_midi_usb.h) is part of the midi feature,
not a feature of its own: the boundary checker's rule is that features do
not know each other, and a transport that needs the map is not a peer of
the map. It compiles in only when the build's USB port is the OTG stack
(ARDUINO_USB_MODE=0); everywhere else it is three empty functions. That
flag is the Arduino core's, decided per env, so the edition needs its own
PlatformIO env - `env`, the third file a bundle may now carry, read by
build.sh and shelf.sh (bundles/midi/env -> firmware_midi). The S3 has one
USB PHY; OTG presents CDC (still Serial: Improv and the log survive) plus
MIDI, and the ROM's download mode is untouched.

No worker and no queue on this transport, unlike RTP: USB has flow
control, so a full FIFO makes the host wait rather than losing data, and
the frame task reads the class FIFO itself, one batch per frame.

Verified on board .119 (Windows 11): enumerates as a composite - CDC on
COM18 and a MEDIA-class "Patternflow" with the in-box driver; CC 20 sweeps
0..127 track params 0..1000; relative CC 24 counted; program change both
ways (host picks a module, the panel echoes the change); Improv answers
over the TinyUSB CDC; `build.sh all` builds all five compositions and the
marker scan holds (the audio image carries no USB marker). Cost: ~28 KB of
internal RAM against the default image (45 KB free after services, largest
32 KB; a 22 KB module still loads), so the edition is for a panel that is
a MIDI port first.

In the tree and built by CI, not on the shelf: the EDITIONS tuples in
release.py/check_versions.py, the cards and the AGENTS.md version line stay
as they are until it is published.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Some encoders count the other way round, some give two edges per detent
instead of four. Both are properties of the part soldered in, and until
now the only answer was INVERT_ENCODER in config.h and a rebuild - which
is also the answer builders keep asking for. Now each knob has a direction
and an edges-per-click setting (4, 2 or 1), stored in NVS ("pf_knobs"),
with INVERT_ENCODER remaining the compile-time default a fresh device
starts from.

- core_encoders.h: getClicks() counts from a per-knob base, so a saved
  change does not move the knob - the click count carries on from where it
  was, in the new direction and at the new size. Settings are applied on
  the frame task (PFLoopSync from the handler) because the frame reads the
  same counters.
- core_knobs_http.h + console/knobs.html: GET/POST /api/knobs and the page,
  with a live position and edge readout to check a knob against. A Setup
  row on the home console.
- console_serve.py mocks /api/knobs so the page can be worked on without a
  panel; console_pages.py knows the page.
- docs: rest-api.md (the endpoint, 1.5), console/README.md, BUILD_GUIDE.md
  (the direction advice points here), CHANGELOG.
- director-midi.md: the one Live setting that made a wired or wireless
  MIDI knob pin itself and tick - Remote on the port's Output row sends
  every mapped value straight back, and the panel reads a position as a
  relative turn. Found on the first USB test; documented for both.

Verified on board .119: GET/POST, invalid input refused, clicks unchanged
across a save, settings survive a reboot; build.sh all compiles every
composition; boundary, source and version checks pass; the page renders
in the console preview and on the panel.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n its own; CI builds compositions in parallel.

The structure was starting to multiply: a feature became an edition
because that was the only way onto a panel, and every edition brought a
card, a release, a build and a board to test. The shelf is now what its
maintainer stands behind and nothing else.

- The Clock edition leaves the shelf. The clock stays a feature and
  bundles/clock stays in the tree as a composition CI keeps compiling;
  its last image, clock-v0.1.5, stays on the v3.10.2 tag. EDITIONS in
  release.py and check_versions.py is ("audio", "performance"); the card
  and the AGENTS.md clause go with it.
- `release.py edition <name> vA.B.C`: one edition on its own - bump its
  PF_VARIANT_VERSION and AGENTS.md clause, shelf.sh, point its card,
  commit - with no core release, no tag, no changelog section. It is how
  an edition's maintainer ships from a pull request; the core's
  maintainer merges and does nothing else (docs/RELEASING.md). cut's
  helpers are split so both commands share them.
- build.sh gains `one <composition>`: build one and scan its image,
  with the marker tables and the scan factored out of `all`. The CI
  workflow runs the five compositions as a matrix, one job each, so the
  wall clock is one build instead of five in a row, and each job pins
  its own static RAM (check_footprint.py --only).
- check_footprint.py pins midi (154,000 / 71,667) and re-pins the rest
  after the knobs page: default +344 B DRAM / +156 B IRAM, audio +864 /
  +156, performance +88 / +0, clock +352 / +156 - the knob settings and
  the /knobs handler, all well inside tolerance.
- Docs say which bundles are published: EDITIONS.md, bundles/README.md,
  RELEASING.md, AGENTS.md, CHANGELOG.

Verified: check_versions agrees with the shelf as it now is; the docs
link checker passes; the web typecheck passes with three cards;
`release.py edition performance v0.2.8 --no-build --no-commit` edits the
three files it should; `build.sh one clock` builds and scans.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
/features is the catalogue the shelf never was. The shelf answers "which
firmware do I install"; this answers the question under it: what can a
panel do, one feature at a time, what does each one need, and which
firmware carries it. Features are the unit somebody develops, proposes and
maintains, so they get a page rather than a bullet list on a card.

Five groups, each with the reel that goes round on Instagram beside its
cards: the panel itself (knobs, console, a pattern arriving from the
community site); sound, one reel for the microphone, the browser extension
and OSC, with a caption that says OSC into a DAW is not in it and works the
same way; MIDI over Wi-Fi in Live, with the USB route named as the midi
composition in the tree; the clock, now a feature with a recipe rather than
a firmware on the shelf; and Simone's performance set - MQTT with its reel,
sequences and the weather without one, and saying so. Features in the tree
but in no firmware are listed at the end so nobody starts them twice.

Reels are Instagram's own embed pages by permalink, in lazy iframes: no
script of theirs on the site, nothing fetched until scrolled to, and the
permalink under each for when an embed is blocked. The page shares the
shelf's document shape and card (its CSS module is imported), and adds the
one thing the shelf lacks: a sticky reel column that goes single-column
with the reel first on a phone.

Also: the sitemap, the shelf's lede, README's editions row, ARCHITECTURE's
route table, AGENTS.md and the changelog name the page.

Verified in the dev server: renders, five embeds load, no console errors,
no horizontal overflow at 375px, typecheck and lint clean on the new files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ys so.

The catalogue's last section described Improv-BLE as something for
whoever finishes it. It was tried, it did not work (the phone never
listed the panel), and it was left in the tree as it was; the copy now
says exactly that.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rest.

The first cut grouped the rows under headings that were the firmwares in
disguise - "Sound", "MIDI", "Performance" - which put the shelf back one
level up and lost the reason features and firmwares are separate things.
It also needed a screen of scrolling per group.

Now: one flat list, one line per feature - name, a one-liner, and a tag
saying where it lives (every firmware, in Audio, in Performance, a recipe
in the tree, did not work) - so the ten rows fit on a screen. A row is a
native <details>: open it for the paragraph, what it needs, which firmware
carries it (a fact on the row, never a category over it), the links and
the reel. Reels stay Instagram embeds and load only when a row is opened;
self-hosting was considered and rejected for the server's sake.

Copy that changed with the shape: the clock's row says it is joining the
Performance firmware and is a recipe until then; the sequences and weather
rows have no reel and say so; the Bluetooth row says the attempt did not
work. The shared sound reel says, on each of its three rows, which of them
it shows.

Verified in the dev server: rows are single-line on a desktop (46 px, the
list 505 px for ten), name + tag over the line on a phone with no
horizontal overflow, typecheck and lint clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
New post (ko+en): a vivid dream about a snake, the first artist
edition going out signed with a certificate Hyunji designed, and a
few low days before that.

The certificate's front (recipient name already blurred) and its
Patternflow-shaped back are joined into one image beside the
paragraph about it, also the cover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pattern-flow_origin Building Building Preview Sep 16, 2026 10:12am UTC
pattern-flow-open Error Error Sep 16, 2026 10:12am UTC

… the panel slims down.

Each Inside entry now has a title and one primary category, with a filter in the store and in the panel heading (with counts); a shared URL or Back that lands on a pin outside the filter widens it to All rather than losing it. The panel loses its second layer: contact links, the filtered list, a note asking for links and photos, journal and map links. The mobile viewer CTA and its styles go. CONTRIBUTING.md says how to add an entry and how to classify it (the subject, not its surroundings); the Inside subtitle now reads 'Builds, projects, and places where Patternflow comes to life.'

Work from another session, committed here to ride the same dev -> main merge.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@engmung
engmung merged commit dc53054 into main Sep 16, 2026
9 of 11 checks passed
engmung added a commit that referenced this pull request Sep 16, 2026
Dev: the Inside filter's files, missing from #434

This branch had an error being deployed

1 failed deployment
Preview – pattern-flow-open — 94cfd2e6 Deployed Sep 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant