Skip to content

Settings Reference

The exhaustive companion to Settings. Every setting the app stores, what it is called, what it accepts, and what happens when you give it something it does not accept.

Settings are opened from the gear in the top bar — there is no menu entry. They are stored per browser origin under the localStorage key rmt:settings:v1. Every change applies immediately: there is no OK/Apply/Cancel, and the app's Undo/Redo does not cover settings. The only way back is a reset.

Every setting, in one table

Five sections, one per panel tab. A tab's id is also its section name.

PathTypeDefaultRange / valuesControl
appearance.themeIdstring'classic-orange'classic-orange, slate-cyan, mono-light, high-contrastTheme dropdown
appearance.overridesobject{}sparse map of token → hexThe 15 color pickers
appearance.note.heightWUnumber228 – 60, step 1Note height
appearance.note.borderPxAtZoom1number10 – 6, step 0.5Border thickness
appearance.note.roundedCornerPxAtZoom1number60 – 20, step 1Corner radius
arrows.enabledbooleantrueShow note arrows
arrows.modestring'reciprocal'reciprocal, independentArrow mode
arrows.up{n, d, label}{n: 2, d: 1, label: null}positive integers; 1/16 ≤ n/d ≤ 16; n/d ≠ 1Up interval + quick-pick chips
arrows.down{n, d, label}{n: 1, d: 2, label: null}same; derived from up in reciprocal modeDown interval — shown in independent mode only
audio.masterVolumenumber10 – 1, step 0.01Master volume (and the transport slider)
audio.defaultInstrumentstring'sine-wave'the nine instrument namesDefault instrument
audio.reverb.enabledbooleantrueEnable reverb
audio.reverb.roomSizenumber0.50 – 1, step 0.01Room size
audio.reverb.decaySecnumber1.80.1 – 12, step 0.1Decay
audio.reverb.dampingnumber0.50 – 1, step 0.01Damping
audio.reverb.preDelayMsnumber200 – 200, step 1Pre-delay
audio.reverb.wetnumber0.250 – 1, step 0.01Reverb amount
audio.stereo.enabledbooleanfalseSpread notes by pitch
audio.stereo.widthnumber0.60 – 1, step 0.01Amount
audio.limiter.enabledbooleantrueLimiter
library.iconSizePxnumber5632 – 96, step 4Icon size
library.showCentsbooleantrueShow cents
library.layoutVersionnumber2any numberno UI, no consumer
scale.xnumber1clamped into scale.limits.xMin … xMaxHorizontal (time)
scale.ynumber1clamped into scale.limits.yMin … yMaxVertical (pitch)
scale.limits.xMinnumber0.30.001 – 1000Horizontal range
scale.limits.xMaxnumber20.001 – 1000Horizontal range
scale.limits.yMinnumber0.30.001 – 1000Vertical range
scale.limits.yMaxnumber50.001 – 1000Vertical range

Defaults reproduce the app's pre-settings behaviour exactly, with one deliberate exception: reverb now defaults on. Stereo defaults off; the limiter defaults on.

Appearance

The Settings panel on the Appearance tab, showing the theme dropdown, the three note-geometry sliders, and the colour pickers grouped under Interface, Workspace and Dependency highlights

ControlTypeRangeDefaultHint shown
Themedropdown4 presetsClassic Orange"Presets apply a full color set and note geometry; pick one, then customize below."
Note heightslider, N wu8 – 60, step 122 wu"Bar thickness in world units."
Border thicknessslider, N px0 – 6, step 0.51 px
Corner radiusslider, N px0 – 20, step 16 px
Reset colors to themebuttonDisabled while you have no overrides

Then fifteen color pickers (a native swatch plus an uppercase hex readout), in three groups.

Choosing a preset discards your color overrides — and re-seeds the geometry sliders

The theme dropdown clears appearance.overrides before it applies the preset, with no confirmation, and writes the preset's declared note geometry into appearance.note — picking High Contrast lands border 2 px / corner 4 px, overwriting whatever the sliders held. Only the Reset colors to theme button asks first (and it, unlike the dropdown, leaves geometry alone).

Theme tokens

The fifteen tokens with a picker, and their value in each preset:

GroupPicker labelTokenClassic OrangeSlate CyanMono LightHigh Contrast
InterfaceAccentaccent#ffa800#38bdf8#d17400#ffd400
InterfaceBackgroundbg#151525#0b1120#f5f5f0#000000
InterfacePanel surfacesurface#151525#111a2e#ffffff#0a0a0a
InterfacePanel bordersurfaceBorder#3a3a4a#26334d#cfcfc7#ffffff
InterfaceTexttextPrimary#ffffff#e6f0ff#1a1a1a#ffffff
InterfaceMuted texttextSecondary#aaaaaa#8fa3c0#666660#dddddd
InterfaceActive / deletedanger#ff0000#f43f5e#c62828#ff2d2d
WorkspaceNote bordernoteBorder#636363#5a6a85#9a9a92#ffffff
WorkspacePlayheadplayhead#ffa800#38bdf8#d17400#ffd400
WorkspaceMeasure barsmeasureBar#ffffff#cbd5e1#333333#ffffff
WorkspaceSelection ringselectionRing#ffffff#38bdf8#d17400#ffd400
WorkspaceHover ringhoverRing#ffffff#cbd5e1#333333#ffffff
Dependency highlightsFrequencydepFrequency#ff8000#fb923c#e06600#ff8000
Dependency highlightsStart timedepStartTime#00ffff#22d3ee#0088aa#00ffff
Dependency highlightsDurationdepDuration#9d00ff#a78bfa#7a2fd0#c46bff

Each token is also published as a CSS custom property on <html>: --rmt-accent, --rmt-bg, --rmt-surface, --rmt-surface-border, --rmt-text-primary, --rmt-text-secondary, --rmt-danger, --rmt-note-border, --rmt-playhead, --rmt-measure-bar, --rmt-selection-ring, --rmt-hover-ring, --rmt-dep-frequency, --rmt-dep-start-time, --rmt-dep-duration, plus --rmt-accent-text, --rmt-note-default-saturation, and the RGB triplets --rmt-accent-rgb, --rmt-bg-rgb, --rmt-surface-rgb, --rmt-danger-rgb for rgba(var(--x), α) forms — --rmt-surface-rgb is what drives every 0.88-alpha panel background.

Every preset also carries three values with no picker: accentText, noteDefaultSaturation and newNoteColorMode. noteDefaultSaturation is consumed — published as --rmt-note-default-saturation, it sets the saturation of the random colour a new note gets — but you can only change it by picking a different preset. accentText and newNoteColorMode are declared and read by nothing.

What each workspace picker reaches:

  • Selection ring colours the ring around a selected note, the selection wash, the group (multi-select) ring, and the outline of a selected BaseNote or measure triangle. The rubber-band marquee rectangle follows the Accent picker, not this one.
  • Hover ring colours the hover ring on notes, the BaseNote and measure triangles.
  • Frequency / Start time / Duration (Dependency highlights) colour both the dependency rings and the dependency link lines.
  • Text (textPrimary) also recolours all on-note glyph text — fraction labels, the word "silence", the octave arrows, and the BaseNote fraction.
  • Panel surface drives the translucent panel backgrounds via rgba(var(--rmt-surface-rgb), 0.88).

Selecting a preset also applies its declared note geometry, re-seeding the three sliders — High Contrast lands border 2 px / corner 4 px. The sliders remain the way to fine-tune afterwards, and Reset colors to theme never touches geometry.

Arrows

ControlTypeRange / optionsDefaultHint shown
Show note arrowscheckboxon"Turn the ▲/▼ interval arrows on notes off entirely."
Arrow modedropdownReciprocal (up ×r, down ÷r), Independent up/downReciprocal
Up interval (ratio)two number fields n / d + a live cents readoutpositive integers; 1/16 ≤ n/d ≤ 16; ≠ 12 / 1 (1200.0¢)"Down applies the reciprocal in reciprocal mode."
Quick picksix chipssee below

Quick-pick chips and the cents they show:

ChipRatioCents
Octave 2/12/11200.0¢
Fifth 3/23/2702.0¢
Fourth 4/34/3498.0¢
Major 3rd 5/45/4386.3¢
Whole tone 9/89/8203.9¢
Syntonic comma 81/8081/8021.5¢

Rules:

  • In reciprocal mode, arrows.down is re-derived as d/n on every write of arrows.up. Set up to 3/2 and down becomes 2/3.
  • An invalid ratio heals to your previous value, per field: a bad numerator or denominator restores just that field from the ratio you had, while a wholly out-of-range ratio (17/1, 1/20) or one equal to 1 (3/3) reverts wholesale. Only a corrupt store loaded fresh — with no previous value to heal from — falls back to the default 2/1. The number fields carry a min of 1 but no max, so the browser lets you type 100; the store is what corrects it, and it visibly rewrites the fields with the healed value.
  • Nothing forbids an "up" ratio below 1. Set arrows.up to 1/2 and ▲ transposes downward.
  • Unchecking Show note arrows dims the ratio editor and the chips but leaves them editable. The values take effect when you switch arrows back on.

In Independent up/down mode a Down interval (ratio) row renders below the up editor — the same two number fields and live cents readout, hinted "Only used in independent mode". (It is hidden in reciprocal mode, where down auto-derives.)

Audio

ControlTypeRangeDefaultHint shown
Master volumeslider, %0 – 1, step 0.01100%
Default instrumentdropdownnine namessine-wave
Room / Reverb
Enable reverbcheckboxon"Adds spatial ambience to the output."
Room sizeslider0 – 1, step 0.010.5
Decayslider, N.N s0.1 – 12, step 0.11.8 s
Dampingslider0 – 1, step 0.010.5
Pre-delayslider, N ms0 – 200, step 120 ms
Reverb amountslider, %0 – 1, step 0.0125%"How much reverb is mixed in on top of the dry signal (0% = dry, 100% = fully wet)."
Stereo width
Spread notes by pitchcheckboxoff"Places low notes toward the left speaker and high notes toward the right, as if seated at the instrument. Off = centered (mono-position)."
Amountslider, %0 – 1, step 0.0160%
Master
Limitercheckboxon"Gentle output limiting to avoid clipping."

The tab's footer reads: "Reverb, stereo and the limiter apply live during playback."

Instrument names

sine-wave, square-wave, sawtooth-wave, triangle-wave, organ, vibraphone, fm-epiano, piano, violin.

audio.defaultInstrument is the fallback, not an override: a note uses it only when neither it nor anything up its frequency chain pins an instrument. See instrument inheritance.

Behaviour worth knowing

  • Master volume is two-way bound to the transport volume slider in the top bar. Dragging either moves the other. The transport slider only persists on release; while you drag it, it emits a live echo the panel follows.
  • Room size, Decay and Damping re-render the reverb impulse response, debounced by 250 ms. Reverb amount, pre-delay and the enable toggle are live parameters.
  • Stereo width is applied when a note is scheduled, so it changes newly-started voices, not ones already sounding.
  • The limiter is a peak catcher: −6 dB threshold, knee 6, ratio 12, attack 0.003 s, release 0.25 s.

Library

ControlTypeRangeDefaultHint shown
Icon sizeslider, N px32 – 96, step 456 px
Show centscheckboxon"Display cents alongside ratios in the module library."

Both apply live to the module bar.

library.layoutVersion is stored and validated but has no control and no consumer. It is not a user setting.

Scale

This tab and the small accent dot at the bottom-left of the screen are two views of the same two numbers. Touch either and the other follows.

ControlTypeRangeDefaultHint shown
Horizontal (time)slider + editable numberspans the horizontal limits1"How far apart notes sit along the time axis."
Vertical (pitch)slider + editable numberspans the vertical limits1"How far apart octaves sit along the frequency axis."
Slider limits
Horizontal rangetwo number boxes, min – maxeach 0.001 – 10000.3 – 2
Vertical rangetwo number boxes, min – maxeach 0.001 – 10000.3 – 5

Rules:

  • Scale persists across reloads. You come back at the density you left.
  • The number box is how you land on an exact value. It clamps into the current limits — widen the limits first to go further.
  • The slider's detent is derived from its range: about a fiftieth of the span, snapped to a 1/2/5 ladder. At the default limits that is 0.02 horizontally and 0.1 vertically — both keep exactly 1.0 reachable by dragging.
  • Editing the limits retunes both this tab's sliders and the bottom-left widget's sliders, live.
  • If you type a min that is not below the max, the field you just edited wins and the other gives way by a factor of ten, rather than the edit being rejected.
  • Narrowing the limits pulls an out-of-range scale value back in with them.

Resets

Every tab ends with two buttons, at the bottom of its scroll flow.

ButtonResetsConfirm button
Reset this tabthe section of the same name as the tabYes, Reset Tab
Reset allall five sectionsYes, Reset All
Reset colors to theme (Appearance only)appearance.overrides only — geometry is untouchedYes, Reset Colors

All three ask first. The confirmation dialog focuses Cancel, and is dismissed by Cancel, by Escape, or by clicking outside it.

Settings changes are not undoable — the app's Undo/Redo covers the module, not the settings. A reset is the only way back.

The stored envelope

Everything lives in one localStorage key.

Keyrmt:settings:v1
Schema version1
Scopeper browser origin
json
{
  "version": 1,
  "appearance": {
    "themeId": "classic-orange",
    "overrides": {},
    "note": { "heightWU": 22, "borderPxAtZoom1": 1, "roundedCornerPxAtZoom1": 6 }
  },
  "arrows": {
    "enabled": true,
    "mode": "reciprocal",
    "up":   { "n": 2, "d": 1, "label": null },
    "down": { "n": 1, "d": 2, "label": null }
  },
  "audio": {
    "masterVolume": 1,
    "defaultInstrument": "sine-wave",
    "reverb": { "enabled": true, "roomSize": 0.5, "decaySec": 1.8, "damping": 0.5, "preDelayMs": 20, "wet": 0.25 },
    "stereo": { "enabled": false, "width": 0.6 },
    "limiter": { "enabled": true }
  },
  "library": { "iconSizePx": 56, "showCents": true, "layoutVersion": 2 },
  "scale": {
    "x": 1,
    "y": 1,
    "limits": { "xMin": 0.3, "xMax": 2, "yMin": 0.3, "yMax": 5 }
  }
}

Paths are dot-delimited: arrows.up, audio.reverb.wet, appearance.themeId, scale.limits.

How a bad value is handled

The whole tree is re-validated on every single write, then persisted. That is what keeps derived invariants (the reciprocal down) true and what makes a hand-edited storage entry safe. validateSettings(raw, prev) takes an optional second parameter — the pre-edit tree — and the store passes it on every set/setSection, which is what lets an invalid arrow ratio heal to the value you previously had instead of a schema default. Load and migrate paths pass no prev. The envelope, key and version are unchanged.

SituationResult
Key missingDefaults
Corrupt JSONWarn to the console, then defaults
A number out of rangeClamped into range
A field of the wrong typeReplaced by its default
An invalid arrow ratioHealed to your previous ratio (per-field); only a fresh load with nothing to heal from falls back to 2/1
An inverted scale range (min ≥ max)That axis's limits fall back to their defaults wholesale
Scale limits narrowed around a far-off valueThe limits are validated first, then the value is clamped into them
localStorage full, or private modeNon-fatal: settings work for the session but are not saved

There is no migration code. v1 is the first and only version — the versioned envelope is scaffolding for a future one. Partial or corrupt stored settings are healed by validation, not by migration.

What is not a setting

  • No import/export of settings, no settings file, no cloud or account sync.
  • No per-module settings — settings belong to the browser, not to the composition.
  • No undo for a settings change.
  • No OS light/dark detection. mono-light is a preset you pick by hand; there is no prefers-color-scheme handling.
  • No custom named themes. Four presets plus a flat override map is the whole story.
  • The panel's position is not persisted across reloads (it does survive close → reopen).
  • The instrument dropdown is a fixed list. A newly registered instrument would not appear in it automatically.

See also

Released under the MIT License