# Frames and interface composition

> This document answers what a Frame is, how its controls bind to a running instance, which widget kinds exist, and what every host must do when it mounts one. A Frame is a declarati

Source: https://docs.tune.toys/contributors/frames/

This document answers what a Frame is, how its controls bind to a running instance, which widget kinds exist, and what every host must do when it mounts one. A Frame is a declarative presentation of a definition in a running-instance context. It is the authored app interface, not a screenshot of the graph. The editor shows each Frame on the Patch as a card holding its components, which move and resize in place, where most Toys are designed, with a derived binding link from each control to the node parameter it drives ([patch editor](https://docs.tune.toys/contributors/patch-editor/)); runtime presentation reads an explicit widget list.

**Status:** the shared React renderer, every widget kind below, nested and inline Frames, themes/styles, responsive projection and the host interface are implemented in [`packages/frame-runtime`](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/README.md) and used by the browser editor, published playback and the native Player WebView. Node faces (`face`, `paint`, `curve`, `switcher`, `readout`) and live video Screens bind through optional host hooks; the browser implements them, and hosts without a video engine or authoring (the native Player WebView, exports) show honest unavailable states ([video](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/video.md#status-and-unavailable-states), [MIDI, control and mixing](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/midi-and-control.md#wavetable-and-the-curve-editor)). General event actions remain planned. Physical touch, screen-reader, embedded WebView and DAW qualification remain open.

## One renderer, every host

The renderer is a React package with no dependency on the graph editor or account shell. Browser pages, a JUCE WebView and later Electron embed that same implementation. Framework-neutral binding/interaction contracts let another shell mount it without a second renderer. Legacy Svelte/React faces supply behavior and fixtures to port deliberately; **do not ship two independent implementations of the same production widget.**

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#FAFAF7', 'primaryTextColor': '#1C1C1B', 'primaryBorderColor': '#1C1C1B', 'lineColor': '#64645F', 'fontFamily': 'DM Sans, Inter, system-ui, sans-serif'}}}%%
flowchart LR
  subgraph TOY["Toy source"]
    DEF["Definition<br/>public parameters · nodes"]
    FRAME["Frame<br/>widgets · bounds · theme"]
    FRAME -- "binds parameter IDs of" --> DEF
  end
  subgraph HOST["Host (browser · Player · export)"]
    FH["FrameHost<br/>instance path · live values · gestures"]
    INST["Running instance<br/>root / stage-1 / voice-2"]
    FH <--> INST
  end
  RENDER["Shared renderer<br/>FrameView"]
  FRAME --> RENDER
  DEF --> RENDER
  RENDER <--> FH

  classDef source fill:#F0442E,stroke:#1C1C1B,color:#FAFAF7
  classDef shared fill:#DCEBDD,stroke:#1C1C1B,color:#1C1C1B
  classDef host fill:#DED8F0,stroke:#1C1C1B,color:#1C1C1B
  class DEF,FRAME source
  class RENDER shared
  class FH,INST host
  style TOY fill:#FAFAF7,stroke:#1C1C1B,color:#1C1C1B
  style HOST fill:#FAFAF7,stroke:#1C1C1B,color:#1C1C1B
```

## Bindings and nesting

Controls bind to stable public parameter IDs relative to the owning definition. At runtime the host supplies an instance path such as `root / first-stage / voice-2`, and a reused Frame resolves its relative bindings in that context. A child `frame` widget names a group node instance and a Frame belonging to that node's definition; an inline `frame` widget omits the node and references a Frame of the same definition (see [performance and reuse](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/performance-reuse.md#patch-lock-and-reuse)). **Reusing one definition twice yields two controls and independent state.**

Frames have stable IDs, dimensions, explicit member/widget IDs, labels, bounds and an entry point. Loose interface components may also live in `Definition.widgets` at absolute Patch coordinates; explicit `Frame.widgets` membership selects the published interface. Graph-node canvas coordinates are editor metadata; moving an unrelated graph node cannot add it to a published Frame. Publishing includes the complete processing dependency closure even when most nodes are not visible. Frames use bounded reference geometry with optional portable anchors and limits; see [responsive Frames](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/responsive-frames.md).

## Widget kinds

The schema admits these widget kinds. Numeric controls and graphical roles bind public IDs; observations use the shared host interface.

| Kind                             | Binds                                                                                                                                      | Notes                                                                             | Detail                                                                     |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `knob`, `slider`                 | One public numeric control                                                                                                                 | Rectangular slider with automatic/horizontal/vertical orientation                 | [appearance](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/appearance.md), [components](https://docs.tune.toys/contributors/interface-components/)         |
| `toggle`, `momentary`, `trigger` | One public numeric control                                                                                                                 | Button, checkbox and switch faces; trigger pulses 10–2000 ms                      | [playable controls](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/playable-inspection.md#playable-controls)              |
| `xy`                             | Two distinct public controls                                                                                                               | XY pad or spring-return joystick face                                             | [playable controls](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/playable-inspection.md#playable-controls)              |
| `segmented`                      | One public numeric control, 2–16 named values                                                                                              | Values must fit the effective domain and discrete step                            | [performance and reuse](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/performance-reuse.md#frame-widgets-and-tuning)     |
| `piano`                          | A `midi.keyboard` node path                                                                                                                | Pointer/touch/keyboard notes become MIDI in the graph                             | [performance and reuse](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/performance-reuse.md#owned-polyphonic-performance) |
| `filter`, `envelope`             | Role-bound public controls of one processor                                                                                                | Analytic response/ADSR editors verified against PCM                               | [graphical editing](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/playable-inspection.md#graphical-editing)              |
| `face`                           | A face key, every role bound to a distinct public control of one node of its type; `node` for data faces                                   | Any node face (dynamics, delay, oscillators, EQ, wavetable, tuner, curve, …)      | [face kit](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/face/README.md)                |
| `meter`                          | Engine observation                                                                                                                         | Per-lane signal meters, expandable beyond stereo                                  | [multichannel audio](https://docs.tune.toys/contributors/multichannel-audio/)                                |
| `scope`                          | Engine capture of one selected source                                                                                                      | Oscilloscope, FFT, spectrogram, XY/phase and tuner modes                          | [components](https://docs.tune.toys/contributors/interface-components/)                                      |
| `screen`                         | A verified attached image or muted video, a built-in 3D scene, or a live video output (`source`, optional `stream` and preview `tracking`) | Codec availability is host-dependent                                              | [components](https://docs.tune.toys/contributors/interface-components/)                                      |
| `paint`                          | A `video.paint` node's `video` output                                                                                                      | Live strokes (colour, width, opacity, eraser, Clear); runtime state, never source | [frame-runtime](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/README.md#node-faces)     |
| `curve`                          | A `std.wavetable` node's table frame                                                                                                       | Pencil, line, smooth and preset shapes; one source commit per gesture             | [frame-runtime](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/README.md#node-faces)     |
| `switcher`                       | A `video.switch` node and its public program/preview/transition                                                                            | Multiview tally, cue, Take; public controls stay the authority                    | [frame-runtime](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/README.md#node-faces)     |
| `readout`                        | One public parameter or one control-output lane                                                                                            | Number, percent, integer or on/off text with a unit                               | [frame-runtime](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/README.md#node-faces)     |
| `image`                          | A declared PNG/JPEG/WebP/GIF asset                                                                                                         | Verified by length and SHA-256 before display                                     | [performance and reuse](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/performance-reuse.md#frame-widgets-and-tuning)     |
| `text`, `icon`                   | Nothing                                                                                                                                    | Static text; bundled icon vocabulary, no SVG markup                               | [icons](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/icons.md)                                                          |
| `frame`                          | A group instance's Frame, or an inline Frame                                                                                               | Nested presentation, max sixteen levels                                           | this page                                                                  |

Arbitrary HTML, CSS injection, JavaScript, remote iframes and executable widget bundles are not admitted by the draft schema. General event actions remain planned.

## Shared node faces

Node cards, inspectors and Frame `face` widgets use the same [face kit](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/src/face/README.md). Pure scene models produce SVG geometry and accessible handles; the shared gesture grammar freezes axes during a drag, commits once per gesture and supports keyboard edits, reset and cancellation. `FACE_BINDINGS` defines each face's roles and compatible processor, with generated Rust admission matching TypeScript. Data faces additionally name a node; a host with authoring can persist a data edit through `commitNodeData` as one Undo step.

The Wavetable face includes waveform selection, **+ Add** (a copy of the selected waveform), **Remove** (keeping one) and the shared pencil/line/smooth/preset editor. Editing selection is local to each surface and independent of playback Position. Changes carry the whole 1–8-frame `data.table` through the existing live preview and atomic authoring bridge; rejected edits restore the previous table, and Undo/Redo supersedes an unfinished stroke. Fixed-frame `curve` widgets use the same sample editor.

The portable theme tokens `screen`, `screenTrace` and `screenGlow` override the shared glass, trace and glow defaults. A single scheduler updates visible live layers outside React. Dense spectrum pixels use Canvas below the SVG; zoom and reduced motion limit refresh rates. The engine exposes one signal trace, so the active inspection or face claims it by priority. Polyphonic playheads read each engine voice’s stage, elapsed time and gain; Chorus dots read its actual modulation phase. These optional host observations never enter portable source or DAW state. Unsupported engines omit the moving marks.

The Bitcrusher (`std.crush`, face `crush`) draws a quiet 1 kHz sine and its quantized, held output over 4 ms, including Mix. Two right-hand rails edit Bits and Rate through the shared gesture lifecycle. It is a nominal-clock example without jitter or dither, not a live signal trace. Its portable roles are `bits`, `rate_hz` and `mix`; the signed grid and sample holds are checked against shared-engine PCM.

## Interaction contract

A control sends begin-gesture, parameter changes and end-gesture through the host interface. It displays authored default, live value, automation/modulation ownership and unavailable/read-only state distinctly. Repaint is suspended when hidden; input receipt and note release never depend on animation frames. Outbound observations are coalesced. **DSP never waits for rendering.**

Pointer cancellation, lost focus, editor close, disposal and disconnected sources release held notes and momentary gates according to source ownership. A widget never releases another input source's notes. Keyboard navigation, accessible names, visible focus, value readouts, reduced-motion behavior, touch sizing and resize behavior belong in widget acceptance fixtures.

A plugin embeds its UI resources for offline use. A hosted page gets only the Frame, the runtime adapter, the verified release and required assets. Host-level start, input-selection and error controls may surround it; creator branding and free-host branding are separate from the Frame's authored processing.

## Non-audio applications

Camera, display, media and sensing nodes run as host and video domains beside the audio engine and reach Frames through live Screens, paint surfaces and lane readouts; their requirements are derived, and control production stays outside audio rendering ([signal types and domains](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/signal-types-and-domains.md), [video](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/video.md), [sensing](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/sensing.md)). The browser runs them; the native Player WebView and exports show the faces as unavailable, and a native host does not yet report unavailable domains before activation. General widgets and service actions, remote-system control with remote mode and connection status, and IoT services remain planned.

## Implementation

- [`packages/frame-runtime`](https://github.com/joshstovall/TuneToys/blob/main/packages/frame-runtime/README.md) — `FrameView`, `ParameterControl`, theme resolution, responsive projection, icons
- [`packages/runtime-protocol`](https://github.com/joshstovall/TuneToys/blob/main/packages/runtime-protocol/README.md) — the host interface Frames talk to
- [`apps/web`](https://github.com/joshstovall/TuneToys/blob/main/apps/web/README.md) — Frame Design editor and published playback host
- [`native/plugin-shell`](https://github.com/joshstovall/TuneToys/blob/main/native/plugin-shell/README.md) — embedded WebView host

## Related

- [Appearance and Frame design](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/appearance.md), [responsive Frames](https://github.com/joshstovall/TuneToys/blob/main/docs/architecture/responsive-frames.md), [interface components](https://docs.tune.toys/contributors/interface-components/)
- [Toy source format](https://docs.tune.toys/contributors/toy-format/) and [running-instance protocol](https://github.com/joshstovall/TuneToys/blob/main/docs/specs/runtime-protocol.md)
- [Decision 0003: Frames and authoring](https://github.com/joshstovall/TuneToys/blob/main/docs/decisions/0003-frames-and-authoring.md)
