Compact nodes and shared interface components

This document answers how Patch nodes are sized, how interface components are placed in Patch and Frame Design from one palette, which control faces and displays exist, and the cap

This document answers how Patch nodes are sized, how interface components are placed in Patch and Frame Design from one palette, which control faces and displays exist, and the capture/media bounds behind Scope and Screen.

Status: implemented in the browser editor and shared renderer with shared source conformance across browser/WASM/native. Browser fixtures qualify local software interactions, not external WebViews, codecs or DAWs. Native UI signal capture is unqualified. Live video Screens and the paint, curve, switcher and readout faces run in the browser; native hosts show their unavailable states (video). Arbitrary rendering scripts and imported 3D models remain planned.

Components may sit anywhere on the Patch. An empty-space palette drop creates a loose Definition.widgets entry at the pointer; dropping inside a Frame creates a Frame.widgets member. Dragging into or out of a Frame transfers ownership with converted coordinates in one Undo step. Both use the same shared renderer and Properties fields. Loose components persist through save/reload, support negative positions and do not appear in public playback until explicitly placed in a Frame.

Node sizing#

Patch defaults to 190px audio nodes, with undoable 140–640px instance widths. Drag the right edge, or focus its resize handle and use arrows (10px; Shift 1px). Visual component cards resize in both axes from their corner. Pointer and held-key gestures preview locally, commit once, and cancel on Escape, blur or source replacement. Parameter rows keep exact numeric editing without embedded sliders; full parameter sliders stay in Properties.

One palette, two surfaces#

Patch → Interface and Frame Design use the same component palette. Components are explicit members of a Frame belonging to the current definition; the first insertion creates that Frame when necessary. Patch positions use namespaced editor metadata keyed by Frame/widget identities. Existing Frame members can be placed from the palette's Existing components group. Frame-only members stay out of Patch until placed; closing a Patch card hides that view while retaining its Frame member. Changing a card's size edits its portable widget bounds. WidgetView projects the same member through the shared Frame board, including instance-relative public bindings, themes and asset receipts. Components do not pretend to be DSP nodes or acquire signal ports. The card's pencil opens its owning Frame for binding and appearance editing. Hidden Frame members stay hidden in Patch.

Controls and displays#

ComponentBindingNotes
KnobOne public numeric controlSee knob feedback
SliderOne public numeric controlRectangular fill/bar; automatic, horizontal or vertical orientation
Button, momentary button, trigger padOne public numeric controlSee playable controls
Checkbox, SwitchOne public numeric controlToggle appearances
SwitchesOne public numeric controlNamed segmented selector; values stay public numeric bindings
XY pad, JoystickTwo distinct public controlsJoystick defaults to spring return at the normalized center, including logarithmic domains; Properties change its face and spring behavior
ScopeOne actual input/output/node sourceModes: oscilloscope, Hann FFT, rolling spectrogram, synchronized XY/phase and tuner, with channel choice and Freeze/Resume. The authored default mode is portable; changing a live mode does not edit the sound
ScreenA verified attached asset or built-in sceneVerified image, verified muted video with play/pause/seek, or a built-in interactive 3D cube/pyramid on canvas (drag/arrows orbit, +/- zoom, Home resets). Media mode, asset, fit and scene are authored in Properties; video decoding depends on host codecs
Live ScreenA video output of the definitionmode: 'live' with source and an optional stream; the host's video engine paints the canvas. Without one: "Video needs a host with a video engine". See video
Paint, Curve, Switcher, ReadoutA video.paint, std.wavetable or video.switch node, or one parameter or control laneNode faces; see Frames, video and MIDI, control and mixing
Piano, filter/ADSR editors, text, icons, panels, nested FramesAs documented elsewhereDistinct vector icons identify each face

Checkbox/Switch are toggle appearances and Joystick is an XY appearance; they reuse existing numeric transactions, ownership, cancellation and MIDI/automation behavior and introduce no event engine. Screen and Scope are portable widget kinds admitted by the generated schema with shared browser/native/WASM semantics. Clipboard and reusable-component closure, asset remapping and node/asset deletion include their references.

Scope has an audio inlet on the Patch, accepting one 1–32-channel bundle. A cable writes the component's source and exact port; it does not add a DSP processor or alter audio routing. Properties offers the same audio-only endpoints. New Scopes start disconnected; Delete, the cut tool or Disconnect audio clears the binding, and Undo restores it. Scope mode fills the component's current width and height; XY retains equal axis scaling. Compact Scopes show no text beneath the plot.

Capture and media bounds#

Engine capture remains one selected source at a time and retains two synchronized 2048-sample lanes: the selected channel and the next channel, wrapping to channel zero (mono pairs with itself). Selection resets both rings, and storage counts toward preparation admission. The additive tt_trace_secondary_value ABI accessor exposes the paired lane. Sampling is allocation-free; the worklet serializes bounded arrays in its observation handler outside process(). Older pinned engines show paired-capture unavailability. Live inspectors share the most recent lease and restore earlier leases on close; this is not an unlimited simultaneous capture engine. See signal inspection.

BoundValue
Spectrogram history1024 × 512 UI canvas; FFT and drawing run on the UI thread
Image16 MiB encoded
Video (MP4/WebM)16 MiB
Decoded dimensions8192 per axis and 16 megapixels
VerificationByte length, SHA-256, declared type and decoded dimensions before display

Freeze retains the actual snapshot. Blob URLs are reference counted and released on replacement/teardown. Videos pause on hidden pages and teardown. No credentials, local URLs or device bindings enter portable source.

The Slider's rectangular fill/bar and aspect-driven orientation were behavior references from the sibling Hotwire ControlFace.svelte. The React implementation and fixtures are original; no source or sibling build dependency was imported.

Verification#

Shared source conformance covers each Scope mode, control appearance, slider orientation and Screen asset admission across browser/WASM/native. Runtime signal fixtures check synchronized ring chronology, resets, isolation and invalid indices against actual WASM. Palette and clipboard tests exercise admitted members, independent identities, assets and atomic Undo (apps/web/test/frame-palette.test.mjs, apps/web/test/interface-components.browser.mjs). Root npm run check remains required.

Implementation#

Edit this page on GitHub

esc

↑ ↓ move↩ open⌘↩ new tabesc close