# Pads — the composable controller surface

The Pads panel is an on-screen MIDI controller you can **compose yourself**: a list of widgets — pads, knobs, faders, buttons — each with its own MIDI mapping. It is a **sender, nothing else**: it produces exactly the bytes a hardware controller would, and everything it "does" is decided by whatever you route it to in the Patchbay. Master the virtual device and you have mastered the real one: when hardware arrives, re-route the same Patchbay edges from the `pads-default` source to the hardware input and nothing downstream changes.

Add it to the left rail via the **+** in the MIDI-sources area (same picker as Sequencer and Keyboard).

## The widget types

- **Pad** — sends a **note**: press = note-on (velocity 110), release = note-off. For drums, triggers, and controller bindings.
- **Knob** — sends a **CC** as you turn it (a rotary knob in byte form: "controller *N* is now at *value*"). Rendered as the same audio knob every FaustWave parameter uses — drag vertically to turn it.
- **Fader** — same as a knob, rendered as a slider.
- **Button** — a momentary **CC** switch: press sends its `max`, release sends its `min`. For sustain-style switches and CC-triggered bindings.

Each widget carries its own mapping: note/CC **number**, a **channel** (0 = follow the device channel set in the header chip; 1–16 = per-widget override, the way multi-engine controllers send per-section channels), a **min..max** range for CC widgets (limit a sweep to e.g. 20..100), and an optional **label**.

## The default surface

A fresh Pads panel is pre-composed as a BeatStep-class device: **16 pads on notes 36–51** — the GM drum anchor (kick 36, snare 38, closed hat 42, open hat 46) that the bundled Drum Kit Electro and the C64 Drum Machine gate on — plus **8 knobs on CC 71–78** (the classic sound-controller block; CC 74 is the conventional filter cutoff/brightness). Route `Pads → <drum instrument>:midi-in` and the grid plays drums with zero configuration.

## EDIT mode — composing your surface

The **EDIT** button in the panel **footer** opens the authoring layer:

- **Add** widgets with the per-type footer buttons (max 64).
- **Click a widget** to select it (amber outline) — its configuration opens as a **popover right at the click point**: number, channel, min/max for CC widgets, label.
- For CC widgets the popover has a **MAP** button — the project's **CC map**: which CC numbers already have a listener (a `midi_cc` node in a Builder DSP, a `[midi:ctrl]`-tagged slider in a .dsp source, a controller binding), what the standard name is (CC 1 Mod Wheel, 64 Sustain, 74 Brightness…), and the last value the bus saw on that CC. Click a row to assign it — no more guessing numbers.
- **Reorder** with the popover's arrow buttons, **remove** with its trash button.
- Leave EDIT mode (or press Esc to dismiss the popover) and the surface is playable again.

The whole configuration persists with the **project** — your live-set surface travels in the project file, and a saved surface is the future device template (share a "my BeatStep layout" via the Hub — planned).

## What a widget does NOT do

A widget only *sends*. It does nothing audible until a receiver listens:

1. **Notes** → an instrument's `:midi-in` (drums, synths) or the **Controller Actions** sink (`controller.bind.add` maps notes to IDE commands — scenes, transport).
2. **CCs** → a **`midi_cc` node** in a Builder DSP or a **`[midi:ctrl N]`-tagged slider** in a .dsp source — see **FaustWave — Patchbay & Routing** § *External clock sync & controller actions*.

Silence from a knob means "no receiver has that CC number", not "broken" — the MIDI Devices panel's **MONITOR** shows every byte the surface sends (`[Pads] ch1 CC CC 74 = 96`) and settles the question in seconds.

## Scripting (palette.run)

`pads.state` (read FIRST — widget ids) · `pads.widget.add { type, number?, channel?, label?, min?, max? }` · `pads.widget.set { widget_id, … }` · `pads.widget.remove` / `pads.widget.move` · `pads.widget.value.set { widget_id, value }` (turn a knob = send its CC) · `pads.press { widget_id, velocity? }` (press gesture with timed release) · `pads.channel.set { channel }` (releases held pads on the old channel first — no stuck notes) · `midi.cc.map` (the project CC map as text — who listens to which CC; read it before choosing a CC number).
