feat(udg): instrument parameter blocks; o1nk's UI under fux-capacity #210

Merged
peterswimm merged 2 commits from feat/udg-param-blocks into main 2026-10-14 00:49:55 +00:00
Owner

Adds a parameter-UI vocabulary to UDG so a plugin's UI can be defined once here and rendered by whichever client hosts it. The first user is o1nk (FUX CAPACITY), which ships as an AUv3 and as a CLAP for the sndstation handhelds.

Scope

One family: instrument parameter UI.

  • Vocabulary (forgeblock.yml): a new "Instrument · programmatic" group with page_strip, param_page (a composite of param_knob / param_enum / param_toggle), and an on_adjust event. The event covers stepped value changes per the APG slider and spinbutton patterns, and also maps to the gamepad. A control binds to a parameter by OPSL identifier only. Range, default and value names stay in each client's own parameter table, which each plugin build already checks against its OPSL device. UDG never restates a number the DSP owns.
  • Surfaces (surface_profiles.yml):
    • auv3.instrument (swift): the Audio Unit's own view inside a host.
    • handheld.display (new clap destination): the plugin draws its own screen through the CLAP display extension. The d-pad moves focus and steps values; the shoulder buttons change page.
  • fux-capacity: changed from the CLI placeholder (whose intent was TBD) into the FUX CAPACITY instrument label. ux.yml places the parameter panel on both surfaces, and the client chooses which one it renders. o1nk.forgeblock.json is o1nk's UI: one param_page per page of o1nk's OPSL movemap layout.
  • Tooling:
    • forgeblock_validate now walks the controls of a param_page.
    • The grammar test checks parameter bindings and refuses min/max/default/values on a control.
    • Artifact mockups and all five channel reductions are included for the new blocks.

Split out, not in this PR:

  • An artifact board tab for the clap destination. Today the board draws only flutter, swift, cli and wordpress, and adding a tab changes all 13 boards.
  • The renderers themselves, which live in the o1nk repo.

Testing

  • just check: all gates pass, including WCAG channel reductions for the 5 new blocks, forgeblock validation (38 blocks, 28 fixtures), and artifact/docs drift.
  • pytest generator/tests/: 344 passed.
  • Failing controls:
    • The validator rejects a header inside a param_page, and a style: dial.
    • The grammar test rejects max on a control, a bare param: cutoff, and a non-control block inside a page.
  • Determinism: two builds are byte-identical, and a clean origin/main rebuilds with 0 changes. So all 86 regenerated dist/ files come from this change: every product's block catalog gains the new group.
  • Cross-repo: o1nk's scripts/udg_parity.py (branch feat/clap-handheld on peterswimm/01nk) checks o1nk.forgeblock.json against the vendored OPSL device and movemap, and against the CLAP's remote-controls pages.
    • Passes: 8 pages, 26 OPSL params placed.
    • It catches injected faults: a dropped param, a wrong control kind, an unknown param, page order, the page strip, and a CLAP page mismatch.
    • The CLAP built with these pages scores 100 at clapcheck's conformant level.

Impact Statement

  • Existing features: Every product's block catalog (artifact, docx, pdf, pptx, block-catalog.svg) lists one more group. Nothing is removed.
  • Public APIs / contracts:
    • The ForgeBlock vocabulary gains 5 blocks and 1 event.
    • The on_adjust event carries a gamepad field, which no other event has.
    • param_page is a new composite with controls children.
  • Schemas: No change to the shape of forgeblock.yml or surface_profiles.yml. handheld.display adds an input: map, which is descriptive and not read by the generators.
  • Data / artifacts: 86 regenerated dist/ files (see Testing).
  • Integrations: A new clap destination value. No generator emits code for it yet.
  • Mappings: No design_mapping change.
  • Backward compatibility:
    • fux-capacity drops its cli.80col surface. It was a placeholder with no consumer.
    • Older clients treat the new blocks as unknown, which is non-required, so they show a placeholder rather than failing.

Docs

Each new block carries fields: descriptions in forgeblock.yml. The fux-capacity meta.yml and ux.yml comments explain the model. The o1nk side is documented in its clap/README.md.

Adds a parameter-UI vocabulary to UDG so a plugin's UI can be defined once here and rendered by whichever client hosts it. The first user is o1nk (FUX CAPACITY), which ships as an AUv3 and as a CLAP for the sndstation handhelds. ## Scope One family: instrument parameter UI. - **Vocabulary** (`forgeblock.yml`): a new "Instrument · programmatic" group with `page_strip`, `param_page` (a composite of `param_knob` / `param_enum` / `param_toggle`), and an `on_adjust` event. The event covers stepped value changes per the APG slider and spinbutton patterns, and also maps to the gamepad. A control binds to a parameter **by OPSL identifier only**. Range, default and value names stay in each client's own parameter table, which each plugin build already checks against its OPSL device. UDG never restates a number the DSP owns. - **Surfaces** (`surface_profiles.yml`): - `auv3.instrument` (swift): the Audio Unit's own view inside a host. - `handheld.display` (new `clap` destination): the plugin draws its own screen through the CLAP display extension. The d-pad moves focus and steps values; the shoulder buttons change page. - **fux-capacity**: changed from the CLI placeholder (whose intent was TBD) into the FUX CAPACITY instrument label. `ux.yml` places the parameter panel on both surfaces, and the client chooses which one it renders. `o1nk.forgeblock.json` is o1nk's UI: one `param_page` per page of o1nk's OPSL movemap layout. - **Tooling**: - `forgeblock_validate` now walks the controls of a `param_page`. - The grammar test checks parameter bindings and refuses `min`/`max`/`default`/`values` on a control. - Artifact mockups and all five channel reductions are included for the new blocks. Split out, not in this PR: - An artifact board tab for the `clap` destination. Today the board draws only flutter, swift, cli and wordpress, and adding a tab changes all 13 boards. - The renderers themselves, which live in the o1nk repo. ## Testing - `just check`: all gates pass, including WCAG channel reductions for the 5 new blocks, forgeblock validation (38 blocks, 28 fixtures), and artifact/docs drift. - `pytest generator/tests/`: 344 passed. - **Failing controls:** - The validator rejects a `header` inside a `param_page`, and a `style: dial`. - The grammar test rejects `max` on a control, a bare `param: cutoff`, and a non-control block inside a page. - **Determinism:** two builds are byte-identical, and a clean `origin/main` rebuilds with 0 changes. So all 86 regenerated `dist/` files come from this change: every product's block catalog gains the new group. - **Cross-repo:** o1nk's `scripts/udg_parity.py` (branch `feat/clap-handheld` on peterswimm/01nk) checks `o1nk.forgeblock.json` against the vendored OPSL device and movemap, and against the CLAP's remote-controls pages. - Passes: 8 pages, 26 OPSL params placed. - It catches injected faults: a dropped param, a wrong control kind, an unknown param, page order, the page strip, and a CLAP page mismatch. - The CLAP built with these pages scores 100 at clapcheck's conformant level. ## Impact Statement - **Existing features:** Every product's block catalog (artifact, docx, pdf, pptx, block-catalog.svg) lists one more group. Nothing is removed. - **Public APIs / contracts:** - The ForgeBlock vocabulary gains 5 blocks and 1 event. - The `on_adjust` event carries a `gamepad` field, which no other event has. - `param_page` is a new composite with `controls` children. - **Schemas:** No change to the shape of `forgeblock.yml` or `surface_profiles.yml`. `handheld.display` adds an `input:` map, which is descriptive and not read by the generators. - **Data / artifacts:** 86 regenerated `dist/` files (see Testing). - **Integrations:** A new `clap` destination value. No generator emits code for it yet. - **Mappings:** No `design_mapping` change. - **Backward compatibility:** - fux-capacity drops its `cli.80col` surface. It was a placeholder with no consumer. - Older clients treat the new blocks as `unknown`, which is non-required, so they show a placeholder rather than failing. ## Docs Each new block carries `fields:` descriptions in `forgeblock.yml`. The fux-capacity `meta.yml` and `ux.yml` comments explain the model. The o1nk side is documented in its `clap/README.md`.
feat(udg): instrument parameter blocks; o1nk's UI under fux-capacity
Some checks failed
PR policy check / policy-gate (pull_request) Successful in 0s
Security Scans / Trivy filesystem scan (pull_request) Successful in 1m4s
Security Scans / Gitleaks secret scan (pull_request) Successful in 47s
Block Validation / validate (pull_request) Successful in 2m8s
Test Generator / lint-workflows (pull_request) Successful in 33s
Test Generator / lint-prose (pull_request) Successful in 30s
Test Generator / test (pull_request) Failing after 1m41s
UDG dist drift gate / dist/ matches dtcg + udg sources (pull_request) Successful in 26s
Copy coverage / Design copy reaching rendered HTML (pull_request) Successful in 1m0s
e0dd7d5c27
Adds a parameter-UI vocabulary so a plugin's UI can be defined once in UDG and
rendered by whichever client hosts it.

- forgeblock.yml: "Instrument · programmatic" group with page_strip,
  param_page (composite of param_knob / param_enum / param_toggle), and an
  on_adjust event (APG slider/spinbutton stepping, with a gamepad mapping).
  Controls bind by OPSL identifier only; range, default and value names stay
  in each client's parameter table.
- surface_profiles.yml: auv3.instrument (swift) and handheld.display (clap,
  the sndstation display extension; d-pad focus, shoulder paging).
- fux-capacity: from a CLI placeholder to the FUX CAPACITY instrument label.
  ux.yml places the parameter panel on both surfaces; o1nk.forgeblock.json
  is o1nk's UI, one param_page per OPSL movemap page.
- forgeblock_validate walks param_page controls; the grammar test checks
  param bindings and refuses min/max/default/values on a control.
- Artifact mockups and all five channel reductions for the new blocks.

o1nk's scripts/udg_parity.py checks the definition against its OPSL device
and movemap. The handheld.display surface has no artifact board tab yet: the
board draws only flutter/swift/cli/wordpress.
udg: handheld large steps are A held with up/down, the LittleGPTracker idiom
Some checks failed
PR policy check / policy-gate (pull_request) Successful in 0s
Security Scans / Trivy filesystem scan (pull_request) Successful in 1m9s
Block Validation / validate (pull_request) Successful in 1m40s
Security Scans / Gitleaks secret scan (pull_request) Successful in 1m36s
Test Generator / lint-workflows (pull_request) Successful in 45s
Test Generator / test (pull_request) Failing after 2m14s
Test Generator / lint-prose (pull_request) Successful in 1m1s
UDG dist drift gate / dist/ matches dtcg + udg sources (pull_request) Successful in 21s
Copy coverage / Design copy reaching rendered HTML (pull_request) Successful in 1m10s
ee73ffe2f4
The o1nk handheld screen keeps the shoulder buttons for paging, so on_adjust's
gamepad mapping and the handheld.display summary now name A + up/down for large
steps rather than a held shoulder button.
peterswimm deleted branch feat/udg-param-blocks 2026-10-14 00:49:55 +00:00
Sign in to join this conversation.
No description provided.