Skip to content

Help / example patch generation (phase 0: tool + plumbing)#126

Open
jcelerier wants to merge 6 commits into
mainfrom
feature/help-patch-generation
Open

Help / example patch generation (phase 0: tool + plumbing)#126
jcelerier wants to merge 6 commits into
mainfrom
feature/help-patch-generation

Conversation

@jcelerier

Copy link
Copy Markdown
Member

What

Infrastructure for shipping a help / example patch with every object, per backend. Two sources, in priority order:

  1. Per-object override — when registering an object, the author points to an explicit hand-authored help/example file per backend; it is copied verbatim to that backend's expected package location.
  2. Auto-generated — otherwise a generator produces a patch from the object's introspection dump (dump/<c_name>.json).

This first PR lands the plumbing and the generator tool (phase 0). The rich per-backend emitters land in follow-up phases — see HELP_PATCH_GENERATION_PLAN.md for the full design.

Contents

  • examples/Demos/GeneratePatches.cpp — new JSON-driven tool (generate_patches <backend> <dump.json> <output>). Parses the dump schema into a normalized model once, then dispatches to per-backend emitters (pd, max/.maxhelp, godot/.tscn, td, python). Phase-0 emitters are minimal but valid (instantiate the object + carry title/description).
  • cmake/avendish.help.cmake — reusable avnd_generate_help(): override-if-present else auto-generate, stores the result path as a target property, best-effort, AVND_DISABLE_AUTOHELP escape hatch. Mirrors the existing maxref wiring.
  • cmake/avendish.tools.cmake — builds the generate_patches target.
  • cmake/avendish.pd.cmakeavnd_make_pd gains a HELP_PATCH override arg and emits pd/<c_name>-help.pd.
  • cmake/avendish.cmake — includes avendish.help.
  • HELP_PATCH_GENERATION_PLAN.md — architecture, per-backend design, override mechanism, packaging integration, phasing, and the validated TouchDesigner .tox text-synthesis path (via the bundled toeexpand/toecollapse).

Verification

  • generate_patches builds on MSVC and emits valid output for all five backends from a real AllPortsTypes dump (.maxhelp is valid JSON, .tscn valid scene text).
  • avnd_generate_help exercised in both override (verbatim copy) and auto-gen modes.

Next

Phase 1: the full Pure Data emitter (header + badge, live interactive demo with a widget wired per control, inlets/outlets/arguments sections, enum/string/color/xy completion).

🤖 Generated with Claude Code

jcelerier and others added 5 commits June 30, 2026 19:28
Introduces the infrastructure for shipping a help/example patch with every
object, per backend. Two sources: an explicit per-object override file (copied
verbatim) or an auto-generated patch produced from the object's introspection
dump.

- examples/Demos/GeneratePatches.cpp: a new JSON-driven tool
  (generate_patches <backend> <dump.json> <output>) that parses the dump schema
  into a normalized model once and dispatches to per-backend emitters
  (pd, max/.maxhelp, godot/.tscn, td, python). Phase 0 emitters are minimal but
  valid (instantiate the object + carry title/description); later phases flesh
  out the rich layout.
- cmake/avendish.tools.cmake: build the generate_patches target (same deps as
  json_to_maxref).
- cmake/avendish.help.cmake: reusable avnd_generate_help() — override-if-present
  else auto-generate, stores the result path as a target property, best-effort,
  with an AVND_DISABLE_AUTOHELP escape hatch. Mirrors the maxref wiring.
- cmake/avendish.pd.cmake: avnd_make_pd gains a HELP_PATCH override arg and
  emits pd/<c_name>-help.pd.
- cmake/avendish.cmake: include avendish.help after avendish.dump.
- HELP_PATCH_GENERATION_PLAN.md: full plan (architecture, per-backend design,
  override mechanism, packaging, phasing, validated TD .tox text-synthesis path).

Verified: tool builds on MSVC and emits valid output for all five backends from
a real dump; avnd_generate_help exercised in both override and auto-gen modes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
Flesh out the pd emitter from the phase-0 stub into a rich, ELSE-style help
patch generated from the dump JSON:

- Header: title bar (object name) + an avendish library badge.
- Description text from the object metadata.
- Live interactive demo:
  * one driver widget per control, wired to the object's left inlet via a
    [<selector> $1( message — float→hsl (with range) or floatatom, int→floatatom,
    bool→tgl, enum(with choices)→hradio, string→symbolatom; bang/impulse and
    complex/multi-component controls fall back to an editable message box;
  * the message selector replicates the binding's name normalization
    ([^a-zA-Z0-9.~] -> '_'), so messages actually route to the control;
  * osc~ sources into the signal inlets for audio inputs;
  * clip~ -> dac~ for audio outputs, number/print sinks for value/message
    outputs, wired in dump (= outlet) order.
- Labelled inlets / outlets sections (cnv dividers) with per-port type/range and
  description text.

Object indices are tracked in creation order and connections emitted afterward,
matching the Pd netlist format. Verified against real dumps (a value-port object
and an audio effect with a ranged slider): correct widget→message→inlet and
audio osc~→object→clip~→dac~ wiring, and all connect indices in range.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
- GeneratePatches.cpp: full Max emitter producing an interactive .maxhelp JSON
  patcher: title/description comments; one widget per control (flonum/number/
  toggle/button) wired through a [selector $1( message into the object's left
  inlet (Max registers an "anything" A_GIMME method, same name normalization as
  Pd); cycle~ sources for audio in; *~ -> ezdac~ and print sinks for outputs.
  Complements the existing .maxref.xml reference. Also create the output's parent
  directory before writing (fixes generation into max/help/, pd/, etc.).
- avendish.max.cmake: avnd_make_max gains a HELP_PATCH override arg and emits
  max/help/<c_name>.maxhelp via avnd_generate_help (property AVND_MAX_HELP).
- avendish.packaging.cmake: the Max addon packager copies the .maxhelp into the
  package's help/ folder (best-effort, same rationale as the maxref copy).

Verified: 112 *_max_help targets created; building one produces a valid .maxhelp
(comment header, flonum->[Gain $1]->inlet 0, cycle~->object->*~->ezdac~).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
…lish

Godot (.tscn, fully text-emittable):
- emit a scene instantiating the registered class (avnd_<c_name><suffix>, passed
  from CMake via the new EXTRA_ARG hint since the suffix depends on processor
  type) with exported properties set to their init values.
- avnd_make_godot gains an EXAMPLE_GODOT override; godot/examples/<...>.tscn,
  copied into the package's examples/ folder.

TouchDesigner (.tox is binary + an avendish operator is a compiled Custom OP, so
a network can only reference it once installed):
- ship a Python network-builder script (td/examples/<c_name>.example.py) that
  documents the parameters and scaffolds the network; a hand-authored .tox can be
  shipped via the EXAMPLE_TD override. (The validated toeexpand/toecollapse
  text-synthesis path remains documented for a future iteration.)

Python: a runnable usage example (import, construct, set controls) next to the
module, with an EXAMPLE_PY override.

Polish / infra:
- Pd: wrap long control lists into columns (a 190-port object went from 620x6286
  to 2084x3946) and move per-control descriptions to the inlets section.
- avnd_generate_help: EXTRA_ARG passthrough; guard against a not-yet-created
  source target (direct avnd_make_* calls).
- generate_patches: create the output's parent directory; optional hint arg.

Per-control descriptions need no code change: emit_port already dumps each port's
metadata (incl. description), and every emitter surfaces it — authors only need to
declare them.

Verified: 189 godot / 194 td / 94 python example targets configure; building one
of each produces a valid .tscn (type=avnd_avnd_addition, properties set), a TD
builder script, and a Python example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
Pd auto-wraps long #X text comments, but the emitter advanced the Y cursor by a
fixed amount per line, so a comment that wrapped to two lines (e.g. the "left
inlet: any [name value( ..." explanation) collided with the next comment.

Give each comment an explicit character width (Pd's `, f <n>` flag) so wrapping
is deterministic, and have text() return the vertical space it occupies
(ceil(len/width) * line-height). Section emission now advances Y by that returned
height, so multi-line comments reserve the room they need. Verified in Pd 0.56.5:
the inlets/outlets sections no longer overlap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
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