- Settings: reference note duration slider (0.5-4s, default 1.5s) applies to
ear-training auto-play, sight-reading auto-play and the manual Play Note
button/keys alike.
- Settings: 'Wait for Silence' toggle holds the next reference note until the
mic detects the instrument has gone quiet (a still-ringing string masking
the next note was easy to miss). Safety cap of 8s so continuously
detectable room noise can't stall the app; without a mic it plays
immediately. The quiet state is a boolean dep (not the per-frame pitch
object) so the play timer isn't reset 60x/sec.
- Gate all live feedback (staff preview, readout, tuner) during speaker
playback: the mic inevitably hears the reference note and would briefly
leak the target in ear training. Virtual fretboard taps (explicit user
input) still display instantly.
- color-scheme per theme so native controls (selects, checkboxes, number
inputs, sliders) render dark-native instead of black-on-black.
- Themed .control-select text color; new .control-input class replaces
hardcoded white-on-black inline input styles.
- Tuner widget stays mounted when enabled: idle state (dimmed, needle parked,
'—') instead of appearing/disappearing. Fully theme-var based (was
hardcoded white — invisible in light mode).
- Remove CSS transitions on per-frame values (tuner needle, level meter):
transitions interrupted 60x/sec are left stuck by WebKit/Safari; the
display EMA from the detection loop replaces them.
- VexFlow notation: resolve CSS var() to concrete colors (SVG attributes
can't resolve var(), silently fell back to black) and override VexFlow's
hardcoded #444 ledger-line default; re-render on theme changes
(useLayoutEffect so children read the updated attribute in time).
- Themed switch toggles (were hardcoded #ddd / white — glowed in dark mode).
- Fixed-height pitch readout so the layout stops jumping when a note starts
or stops sounding.
- Split SettingsContext into context/Provider/hook files (fast-refresh);
memoized provider functions; typed webkitAudioContext; prefer-const;
removed 'as any' casts. ESLint now passes clean.