ui-builder.js — UI Components

Generates the per-module parameter control cards, handles canvas drawing for waveform and envelope visualisation, and synchronises lock states.

Module Sections

buildModuleSection(container, mod, params, lockedParams, onChange)

Creates a card for one module. Each card contains:

┌─────────────────────────────────────────────┐
│  Module Label  [🔓] [🎲]      ┌──────────┐ │
│  Param Label  ═══●═════  val  [🔓]      │ canvas │
│  Param Label  ══○═══════ val  [🔓]      │  (if   │
│  ...                                    │  mod.  │
│                                         │canvasId│
│                                         └────────┘ │
└─────────────────────────────────────────────┘
  • Section lock button (🔓/🔒) toggles all params in that section
  • Randomise button (🎲) randomises unlocked params and calls onChange
  • Each param row has label, control (range/select/checkbox), value display, lock
  • Optional inline canvas to the right of controls when mod.canvasId is set. Set mod.canvasExternal = true to suppress inline canvas creation — the canvas is placed in the HTML template instead and drawn by doRender() via its ID.

Supports three control types: - type: 'range'<input type="range"> + value <span> - type: 'select'<select> with options - type: 'checkbox'<input type="checkbox">

For select params, set ui: 'pills' to render the options as clickable pill buttons instead of a dropdown:

pitchCurve: { type: 'select', options: ['exponential', 'linear'], default: 'exponential', label: 'Curve', ui: 'pills' }

syncModuleUI(container, modules, params)

Syncs UI controls ([data-key] elements) with current param values. Used after randomise or preset/template load. Builds a param-def lookup from modules for proper formatValue rendering (units, note names).

syncLockUI(container, lockedParams)

Updates all per-param lock buttons ([data-lock-key]) and section lock buttons (.section-lock) to reflect the current lockedParams state. Used when a template is applied or locks are cleared programmatically.

Canvas Drawing

drawEnvelopeCurve(c, fn, colour)

Draws a normalised envelope curve on a 2D canvas context. fn(t) receives t in [0, 1] and returns a value in [0, 1]. The curve is drawn with: - Theme-aware background (dark/light) - Light horizontal grid lines - Filled area under the curve at reduced opacity - Stroked curve at full opacity - "time" label at bottom-right

drawWaveform(c, samples)

Draws a PCM waveform as a centred line graph. samples is a Float32Array. Down-samples to match canvas width. Theme colours are applied by the caller.

isDarkTheme() → boolean

Returns true when data-bs-theme attribute is "dark".

formatValue(pd, val) → string

Formats a param value using its definition: - Appends unit string (Hz, s, dB) where present - Hz values show nearest note: "220 Hz (A3)" - Non-unit values get 2 decimal places - Log-scale Hz params (marked log: true) show 2 decimal places for fine control at low rates (e.g. "0.75 Hz")

Slider types

Property Effect
log: true Maps slider position logarithmically for fine control at low end of range
step: <number> Explicit step size (default: (max-min)/200)