Skip to content

feat: standalone parameters, corrected scale math, pointer events, and first tests - #11

Merged
maxwellmattryan merged 1 commit into
developfrom
feat/scale-math-standalone-params-and-events
Aug 7, 2026
Merged

maxwellmattryan merged 1 commit into
developfrom
feat/scale-math-standalone-params-and-events

Conversation

@maxwellmattryan

Copy link
Copy Markdown
Contributor

Summary

Makes nectar usable by standalone web apps (no JUCE backend), fixes the scale math, extends the event manager to pointer input, and adds the repo's first test suite. Version 0.3.0.

Scale math (src/math/scale.ts, new)

applyScale/unapplyScale are now pure, exported functions with corrected curves:

Scale Before After
logarithmic 10^(2n-2) — a fixed 100:1 curve that ignored min/max and was discontinuous at n=0 (a 20 Hz–20 kHz parameter jumped 20 → ~220 Hz at the bottom of travel, and read 651.8 Hz at quarter travel where a log sweep reads 112.5 Hz) min * (max/min)^n — true ratio curve; requires min > 0, else falls back to linear with a one-time warning
quadratic / cubic silently linear n² / n³
exponential n² deprecated alias of logarithmic (nothing anywhere set scale:, verified across every consumer repo)

Parameters without JUCE

  • FloatParameter/BooleanParameter/ChoiceParameter are now exported — they were always backend-free; only ParameterManager coupled them to JUCE
  • new ParameterManager({ backend: 'auto' | 'juce' | 'none' }), default 'auto', which detects a real JUCE host via the initialisation data platform. Without a host, the relay is skipped, so defaults are no longer clobbered to zero by the placeholder slider state, and initializeParameters() rejects fast instead of awaiting a native call that never resolves
  • setDisplayValue now clamps, notifies listeners, and honours source (it previously did none of those, silently desyncing subscribers)
  • Constructor and normalizedDefaultValue clamp into [0, 1] (a log-scale default near min used to produce a negative normalized value)
  • displayToJuceNormalized gains the guard the other midpoint path already had (midpoint == min used to return 1 for every input; < min returned NaN — straight to JUCE)

Event manager

  • pointerdown replaces mousedown internally (covers mouse + touch + pen); subscribeToClick remains as a deprecated alias of subscribeToPointerDown
  • subscribeToKey(key, cb, { target?, repeat? }) — element scoping (one containment check per subscriber, still one document listener) and opt-in auto-repeat for held keys
  • Handled-protocol: a callback returning true marks the event consumed and the manager calls preventDefault() — consumers no longer have to call it unconditionally
  • Pressed state survives the last unsubscribe (previously a held modifier's state was zeroed)
  • beginDrag(event, { onMove, onEnd }) hosts one shared pointermove/pointerup/pointercancel set per gesture with central pointer capture — one drag ever active, so component libraries stop attaching their own document listeners per knob

Tests (first in the repo — 67)

vitest run: scale round-trips across all curves plus the 20 Hz–20 kHz oracle table (20 / 112.47 / 632.46 / 20 000), math utils incl. deliberate pins of gainToDecibels' NaN-above-unity behavior, parameter regressions (default preservation, setDisplayValue notification, midpoint guards), and event manager lifecycle (exactly three document listeners regardless of subscription count, scoping, handled-protocol, repeat, drag listener removal on up and cancel).

CI

cd.publish-automatic.yml now requires the triggering Build run to have succeeded — it previously fired on completed, so a failed build with a version bump still published to npm.

Migration notes (template-plugin)

Nothing breaks at publish — template-plugin pins 0.2.0 exactly. When it bumps to 0.3.0:

  • ParameterManager behavior is unchanged inside a real JUCE WebView ('auto' detects the host); pass { backend: 'juce' } to force the old unconditional wiring
  • subscribeToClick still works (deprecated); switch to subscribeToPointerDown when convenient
  • Key callbacks may now return true to consume events — existing void callbacks behave as before, but preventDefault is no longer called unless a callback opts in

Testing

  • yarn test — 67/67
  • yarn build — clean; dist/index.d.ts verified to export the parameter classes, scale functions, and new event manager API
  • npx eslint + prettier --check — clean
  • Exercised end to end by the hush PWA (blackboxaudio/honey#pointer-input PR and the eden hush PR), including offline-rendered spectral verification through FloatParameter's log scale

…d first tests

- Extract pure applyScale/unapplyScale into src/math/scale.ts and fix all curves:
  logarithmic is now the ratio curve min*(max/min)^n (the old 10^(2n-2) ignored
  min/max and was discontinuous at n=0), quadratic/cubic are real power curves
  (previously silently linear), exponential is a deprecated alias of logarithmic,
  and min <= 0 falls back to linear with a warning
- Export the concrete FloatParameter/BooleanParameter/ChoiceParameter classes so
  standalone web apps can use parameters without a JUCE backend
- ParameterManager takes { backend: 'auto' | 'juce' | 'none' } (default 'auto',
  detecting a real JUCE host), no longer clobbers defaults to zero through the
  placeholder relay, and initializeParameters() fails fast without a backend
- FloatParameter: setDisplayValue now notifies listeners, honours source, and
  clamps; constructor and normalizedDefaultValue clamp into [0, 1];
  displayToJuceNormalized gains the missing midpoint guard
- GlobalEventManager: pointerdown replaces mousedown (subscribeToClick kept as a
  deprecated alias), key subscriptions gain element scoping, a handled-protocol
  (return true -> preventDefault), and opt-in auto-repeat; pressed state survives
  the last unsubscribe; beginDrag() hosts one shared pointermove/up/cancel set
  per gesture with central pointer capture
- First test suite in the repo (67 tests): scale round-trips and oracles, math
  utils, parameter behavior regressions, event manager efficiency and lifecycle
- CI: publish-automatic now requires the Build workflow to have succeeded
- Version 0.3.0
@maxwellmattryan maxwellmattryan self-assigned this Aug 7, 2026
@maxwellmattryan
maxwellmattryan merged commit 4d07648 into develop Aug 7, 2026
1 check passed
@maxwellmattryan
maxwellmattryan deleted the feat/scale-math-standalone-params-and-events branch August 7, 2026 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant