← All docs
Ideas

Pad launcher (Sequences panel)

> Track B. Read after 04-sequence-engine.md.

The pad surface is separate from the node graph. A node on the canvas does not represent "play sequence X." Pads live in their own panel; they appear in the input bus so any source can fire them and any sink can react to their state changes.

Where it lives

A new top-level view alongside the canvas. Two options for the shell:

Option A (recommended). A Pads button in the topbar that swaps the main view between Graph and Pads. The inspector stays on the right and adapts (pad-aware when a pad is selected, node-aware when a node is selected).

Option B. A drawer that slides up from the bottom (like the debug log). Cramped — pads need real estate.

Go with A. Implementation: src/features/sequences/PadView.tsx is the new top-level component; App.tsx toggles between <GraphCanvas /> and <PadView /> based on ui.activeView.

The grid

Default 8 pads (TagTable ships 8). Display as a 4×2 or 2×4 grid; let the user pick. Each pad shows:

  • The sequence's pad color as the swatch.
  • Sequence name.
  • A row of cue swatches (clipped to ~32) so the user can preview the pattern at a glance.
  • Hot-key indicator (Q W E R T Y U I by default — TagTable's defaults; rebindable).
  • Live playhead progress as an arc/bar around the pad when active.
  • A small "live" highlight on the pad whose layer is currently the top in the mixer for its slot.
Reuse the existing nodes' visual language (border-top accent, surface-2 background, accent glow on active). Theme variables only.

Pad interactions

| Action | Trigger |
|---|---|
| Start sequence | Click pad / press hotkey |
| Stop sequence | Re-click pad / re-press hotkey (toggle) |
| Stop ALL active | Spacebar (matches TagTable) |
| Restart sequence | Shift-click |
| Open editor | Edit (✎) button on hover |
| Set color | Right-click → palette |

Hotkey routing: pads register with the existing keyboard input system (src/features/inputs/keyboard.ts) under the signature pad:<padId>:hotkey. This means a pad can also be triggered via:

  • USB MIDI (a button is rebound to fire that signature)
  • A Resolume parameter going above a threshold (via transform threshold)
  • An OSC inbound packet
  • Any other XOSC source

Pad editor modal

Reuse the existing Modal component. Fields:

  • Identity. Name, pad color, hotkey assignment.
  • Target fixture. Universe + fixture profile + start channel. Same picker as dmx-out (extract a shared <FixtureTargetPicker> component).
  • Cue list. Editable table: t, role values, fade, emit?. Add / remove / drag-reorder. Cues sorted by t on save.
  • Playback. Duration (s), loop toggle.
  • Mixer hints. Slot (free-text + recent suggestions), base priority (number 0..100), mix mode (Select of replace | max | add).
  • Effect generator. Optional "fill cues from a preset" — pulse, chase, color cycle, fade-rainbow. TagTable has this in app.js around line 2976. Port the four most useful ones.
Below the cue table: live preview that scrubs the sequence at 1× speed without writing to hardware. Useful for designing.

Built-in presets

Ship 8 starter sequences. Inspired by TagTable's generatePresetTemplates but generalized to fixture profiles. All target fixture rgb, universe 1, channel 1 — the user re-targets each one to their actual rig once.

| Name | Color | Duration | Loop | Pattern |
|---|---|---|---|---|
| Warm Wash | #FF8C1E | 60 s | yes | 6 cues, 3s fades, oranges |
| Color Cycle | #FF3366 | 24 s | yes | 8 cues, R→Y→G→C→B→M→W→off |
| Slow Fade Blue | #3B82F6 | 8 s | yes | 2 cues, 4s fade up + down |
| Strobe Test | #FFFFFF | 4 s | yes | 8 cues alternating white/off |
| Police | #EF4444 | 1 s | yes | 4 cues red/blue alternating, no fade |
| Gentle Lounge | #8B5CF6 | 30 s | yes | 6 cues, slow purples + magentas |
| Bass Hit | #FBBF24 | 0.4 s | no | 1 cue at t=0 yellow, snaps to off at t=0.4 |
| Blackout | #000000 | 1 s | no | 1 cue at t=0 all-zero |

Loaded on first run via a "Load defaults" button (skipped if a sequence with the same name already exists, like TagTable does).

Inputs from pads → other sinks

Each pad fires its hotkey signature and a per-cue signature when a cue with emit lands. The router routes those exactly like keyboard / OSC / MIDI events. So:

  • Wire a pad's pad:warm-wash:hotkey signature to a Resolume out node → starting the pad also fires Resolume.
  • Wire a cue's emit.signature: "drop" to an OSC packet → the bass-drop cue fires an OSC packet at exactly that beat.
This is the integration that makes pads useful beyond just lighting.

Outputs to pads (via inputs)

The reverse direction works the same way. An input source wired to a pad's signature starts/stops the pad. Examples:

  • A keyboard key bound to pad:warm-wash:hotkey triggers it without the user clicking the pad.
  • A resolume-in watching /composition/dashboard/playPause wired through a transform: edge (rise) into the pad signature plays/pauses pads in sync with Resolume.

What you'll write

src/features/sequences/
├── PadView.tsx              # main grid view
├── Pad.tsx                  # one pad cell
├── PadEditorModal.tsx       # the modal
├── EffectGenerator.tsx      # optional preset fillers (4 effects)
├── padTypes.ts              # the persisted pad list shape
├── usePads.ts               # store hook returning pad list + active layers
├── padHotkeys.ts            # registers pad hotkeys with the keyboard input layer
├── pad-view.css
├── pad.css
└── pad-editor-modal.css

src/components/
└── FixtureTargetPicker.tsx # shared with DmxOutInspector — extracted into ui/

src/store/store.ts # add settings.dmx.sequences + ui.activeView
src/components/Topbar.tsx # Pads / Graph toggle
src/App.tsx # render PadView vs GraphCanvas based on activeView

Don't do

  • Don't put pads on the React Flow canvas. The router treats them as virtual sources/sinks via signatures; the canvas would only get more crowded.
  • Don't sync pad state across windows (multi-window is declined for v0.6).
  • Don't ship a "pattern recorder" that captures live channel writes. Cool but a v0.7 idea.