URL params reference
Every setting PianoKitty accepts in a URL — so you can build and share an exact practice link. Exercise preferences change per exercise and can go in the URL (e.g. ?tempo=60); user preferences are your global defaults. Each row lists the setting's name on the Preferences page, its URL param, the allowed values, and an example.
| Param name | Option name | Possible values | Description | Examples |
|---|---|---|---|---|
| Exercise preferences | ||||
activity | Activity | piano, naming, ear, jumper | What the user does in the exercise: piano (live MIDI play), naming (multiple-choice naming), ear (audio recognition), jumper (metronome rhythm game). | ?activity=piano?activity=naming |
subject | Subject | chords, scales, progressions, songs, melodies | Musical subject the exercise draws from. Tab order (chords → scales → progressions → songs → melodies) drives the /preferences segmented control. | ?subject=chords?subject=scales |
key | Key | C, C#, D, D#, E, F, F#, G, G#, A, A#, B, Db, Eb, Gb, Ab, Bb | Root key of the exercise. 12 chromatic spellings + 5 flat enharmonics (Db, Eb, Gb, Ab, Bb) for scale tonics that read more naturally with flats. | ?key=C?key=C%23 |
scale | Scale | major, minor, harmonicMinor, melodicMinor | Scale type built off the root key. | ?scale=major?scale=minor |
inv | Inversions | array of 0–3 (comma-separated in URL) | Inversion indices to drill, comma-separated in the URL (e.g. inv=0,1,2). | ?inv=0,1 |
voicing | Voicing | singleNotes, triads, sevenths, ninths, progression, intM2, int2, intM3, int3, int4, intTT, int5, intM6, int6, intM7, int7, int8 | Chord voicing. singleNotes / triads / sevenths apply to both chord-pool and scales subjects; ninths is scales-only and drills the diatonic 9th on each degree (not available for harmonicMinor or the non-diatonic scales). intM2..int8 are 2-note interval voicings (scales subject only): the scale degree is the lower note, the named interval is added above. progression is reserved for the deferred Roman/Arabic custom progression mode. | ?voicing=singleNotes?voicing=triads |
hand | Hand | any, left, right, both | Which hand the exercise practices. "any" accepts either one-hand or two-hand play (single chord or chord doubled across octaves). | ?hand=any?hand=left |
lplay | Left hand plays | same, root, lowest, octaves, fifths, nothing | When hand="both", what the left hand plays alongside the right-hand chord: "same" = the chord doubled, "root" = only the chord root note (inversion-agnostic), "lowest" = only the bass (inversion-aware — in root position root IS the lowest), "octaves" = the root note doubled (two roots one octave apart), "fifths" = root + perfect fifth (two notes), "nothing" = only the right hand grades. Ignored unless hand="both". | ?lplay=same?lplay=root |
tempo | Tempo (BPM) | 20 – 300 | Metronome tempo in beats per minute. | ?tempo=60 |
meter | Meter | 4/4, 3/4, 6/8 | Time signature driving the metronome strong-beat accent. 4/4 and 3/4 accent beat 1; 6/8 is compound — accent on beat 1 (strong) and beat 4 (medium). Subject-invariant (all tabs), like tempo. | ?meter=4%2F4?meter=3%2F4 |
acc | Black-key spelling | sharp, flat, random, auto | Black-key spelling: always sharps, always flats, random per render, or auto-derived from the current scale. | ?acc=sharp?acc=flat |
reqinv | Any inversion is fine | true / false | When true, the MIDI evaluator demands the played chord to match the asked inversion (bass note matters); when false, any inversion with the same notes counts as a hit. | ?reqinv=true |
ct | Chord types | array of 0–67 (comma-separated in URL) | Quality ids the random-draw pool may pick from (e.g. 0 = major triad, 7 = m7, 49 = single note). At least one must be selected. | ?ct=0,1 |
bn | Base notes | array of 0–11 (comma-separated in URL) | Pitch classes (0..11, C=0) allowed as chord roots when drawing. At least one must remain selected. | ?bn=0,1 |
nj | Ninja mode | true / false | Ninja mode (chords subject, piano activity): the user picks the exact voicing per hand via the ninjaLeft/ninjaRight step sets. While on, chordTypes / inversions / hand are ignored by grading and by the exercise identity, the question label shows only the root, and the keyboard hint marks both hands. | ?nj=true |
njl | Ninja mode · L | array of 0–21 (comma-separated in URL) | Ninja mode: left-hand steps as semitone offsets from the right-hand root (members of NINJA_STEPS in $lib/music/chord/ninja; 0=root … 21=13th). The left hand sounds two octaves below the right root, so its steps can never collide with right-hand pitches. | ?njl=0,1 |
njr | Ninja mode · R | array of 0–21 (comma-separated in URL) | Ninja mode: right-hand steps as semitone offsets from the root (members of NINJA_STEPS). At least one step across both hands must stay selected; the UI enforces it and the engine falls back to a bare root. | ?njr=0,1 |
sv | Specific voicing | true / false | Specific Voicing (all subjects, piano activity): the user assigns generic chord parts (root/3rd/5th/7th/9th/11th/13th) to each hand and the drawn chord decides the exact notes. While on, hand / leftPlays / requireInversion / rootless / one-note are bypassed by grading; a part the drawn chord lacks is skipped, a part ticked in neither hand is omitted, and a chord with no assignable part grades as a normal full chord. Ninja mode wins over this in the chords subject. | ?sv=true |
svl | Specific voicing · L | array of string (comma-separated in URL) | Specific Voicing: parts the LEFT hand plays, as degree numbers (1=root, 3, 5, 7, 9, 11, 13 — see VOICING_PARTS in $lib/music/chord/specific-voicing). The hint places them two octaves below the right-hand root; grading is octave-free. | ?svl=value |
svr | Specific voicing · R | array of string (comma-separated in URL) | Specific Voicing: parts the RIGHT hand plays, as degree numbers. At least one part across both hands must stay selected; the UI enforces it and an empty pair falls back to normal grading. | ?svr=value |
seq | Order | random, inOrder, harmonized, allInversions, inOrderUpDown, inOrderUpDownPeak, circleFifthsCW, circleFifthsCCW, chromaticUp, chromaticDown | Draw order. `random` picks a random pick each draw (scales subject: natural degree order, random inversion per cell); `inOrder` walks the pool in order; `inOrderUpDown` / `inOrderUpDownPeak` walk up then back down (scales subject); `allInversions` drills every inversion of each degree (scales subject). `harmonized` is reserved and falls back to inOrder. `circleFifthsCW`/`circleFifthsCCW`/`chromaticUp`/`chromaticDown` are RETIRED (still parsed for old links/data): they normalize to `inOrder` + the matching `scaleAfterRepeats` direction. | ?seq=random?seq=inOrder |
mode | Scale | major, naturalMinor, harmonicMinor, melodicMinor, ionian, dorian, phrygian, lydian, mixolydian, aeolian, locrian, tetrachordsMajor, tetrachordsMinor, pentascaleMajor, pentascaleMinor, pentatonicMajor, pentatonicMinor, blues, bebopDominant, bebopMajor, bebopMinor, chromatic | Scale mode for subject=scales — slug from the 20-mode V1 taxonomy (major..chromatic). Non-diatonic slugs (pentatonic*, blues, bebop*, chromatic) force voicing=singleNotes. | ?mode=major?mode=naturalMinor |
repeat | Repeat the first chord at the end (in-order) | none, end, top, both | For subject=scales, sequence=inOrder. `end` appends the tonic after the last degree before looping (resolves the scale). `top` (deferred, used by inOrderUpDown) repeats the peak before descent. `both` does both. `none` plays the bare degree list. | ?repeat=none?repeat=end |
sloop | All inversions (per chord) · Play … times each | string | Scales subject, sequence=allInversions only: play each degree's inversion run N times before moving to the next degree (per-degree loop). Absent/1 = one run per degree. 1..100. Optional so it stays absent on the vast majority of exercises. (Passes before the "Then" action are `scaleAfterRepeatsCount`.) | ?sloop=value |
sloopok | exercise.scaleLoopFlawlessOnly | string | Legacy (scales subject): the old all-keys "only flawless" flag. Migrated into `scaleAfterRepeatsFlawlessOnly` when it arrives with a retired all-keys sequence; otherwise ignored. | ?sloopok=value |
safter | After repeats · Then | done, cofCW, cofCCW, chromaticUp, chromaticDown | Scales subject only: what happens after `scaleAfterRepeatsCount` completed passes through the scale (any sequence). done = mark the exercise as done (records a completion, once per session); cofCW = next key around the circle of fifths clockwise (C→G→D→…); cofCCW = counter-clockwise (C→F→Bb→…); chromaticUp = semitone up; chromaticDown = semitone down. Independent of the progressions `advanceAfterRepeats*` fields. | ?safter=done?safter=cofCW |
safn | After repeats · Repeats | 1 – 99 | Scales subject only: how many completed passes trigger `scaleAfterRepeats`. 1..99. Default 1. | ?safn=1 |
safok | After repeats · only after correct | true / false | Scales subject only: when true (default), only FLAWLESS passes count toward `scaleAfterRepeatsCount` and a flawed pass restarts the count (N clean passes in a row). When false, every completed pass counts. | ?safok=true |
prog | Progression | string | Verbatim Roman/Arabic numeral progression text (e.g. "I vi IV V" or "1.2 5 6.2 4") for subject=progressions. Empty value triggers auto-seed to "ii V I" when subject flips to progressions. Per-chord dot-notation inversion overrides the global inversions option. | ?prog=value |
spec | Custom chord list | string | Verbatim chord-name list (e.g. "D, G, C" or "Am.1 Cmaj7 F#m7b5/A C/E") for subject=songs. Tokens split on whitespace, comma, or colon. Each token accepts dot-inversion (e.g. "Cm7.2") and slash-bass (e.g. "C/E"). The `|` token marks a bar boundary and is preserved in the parsed list. Reused by the V1-port chord-text parser (`parseSpecific`). | ?spec=value |
spsn | Single notes | true / false | Songs subject only: when true, each parsed chord in `specific` is graded as a single-note exercise on its root (quality=49, inversion=0). Lets a "C F.2 G" string drive a C → F → G single-note drill instead of full chord voicings. Ignored for other subjects. | ?spsn=true |
sui | Use these inversions | true / false | Songs subject only: when true, the chords from `specific` keep their root + quality but IGNORE any per-token inversion (C/E, C.2 → C) and are instead drilled through the selected `inversions` set. The play pool = {parsed chords} × {selected inversions} (a pair is skipped when the inversion exceeds the chord quality’s max), walked per `sequence` (random = uniform draw; in-sequence = inversion-major: all chords at the lowest inversion, then the next). Overridden by `songsSingleNotes`. Ignored for other subjects. | ?sui=true |
title | exercise.songTitle | string | Songs subject only: optional display title ("Artist - Song") carried from /songs or /editor via the ?title= param. Shown on the ExID card in place of the chord list. Display-only — deliberately excluded from the canonical exid hash (tab-fields) so it never changes an exercise’s identity, pet-name, or difficulty; it rides only in the ?d= slug. Optional so it stays absent (not "") on the vast majority of exercises. | ?title=value |
advrep | After repeats · Then | true / false | Progressions subject only: when true, after `advanceAfterRepeatsCount` loops the exercise key auto-advances in the direction given by `advanceAfterRepeatsDirection`. When false ("Mark as done"), the same threshold records the exercise as done once per session instead. Ignored for other subjects. | ?advrep=true |
advrepn | After repeats · Repeats | 1 – 99 | Progressions subject only: how many loops trigger the "Then" action (key advance when `advanceAfterRepeats` is true, mark as done when false). 1..99. Default 3. | ?advrepn=3 |
advrepd | After repeats · Then (direction) | cofCW, cofCCW, chromaticUp, chromaticDown | Progressions subject only: how the key advances when the repeats threshold is hit. cofCW = circle of fifths clockwise (C→G→D→A→…); cofCCW = counter-clockwise (C→F→Bb→…); chromaticUp = semitone up (C→C#→D→…); chromaticDown = semitone down. Reuses the existing nextCofKey / nextChromaticKey helpers. | ?advrepd=cofCW?advrepd=cofCCW |
advrepok | After repeats · only after correct | string | Progressions subject only: when true, only FLAWLESS loops count toward advanceAfterRepeatsCount — any miss resets the flawless progress, so the "Then" action fires after N clean loops in a row. Absent/false (default) = every completed loop counts regardless of mistakes. Optional so it stays absent on the vast majority of exercises. | ?advrepok=value |
ptempo | Progressive tempo | true / false | When true, the metronome climbs ("tempo stepping") from progressiveTempoFrom to progressiveTempoTo in progressiveTempoStep increments, playing the current material progressiveTempoAfter clean repeats per rung before bumping up. On reaching the top rung it triggers the mode's natural advance (next key / scale) or a goal board (chords / songs) and resets to the bottom. Subject-invariant (all tabs). While on, it becomes the authority for rep-counting and advancement, suppressing advanceAfterRepeats / scaleLoopCount auto-advance. | ?ptempo=true |
ptfrom | Progressive tempo · From | 20 – 300 | Progressive tempo: starting BPM (bottom rung of the ladder). 20..300. | ?ptfrom=60 |
ptto | Progressive tempo · To | 20 – 300 | Progressive tempo: target BPM (top rung, always played after the last full step). 20..300. | ?ptto=200 |
ptstep | Progressive tempo · Step | 1 – 200 | Progressive tempo: BPM increment between rungs. 1..200. Default 20. | ?ptstep=20 |
ptafter | Progressive tempo · After … repeats | 1 – 99 | Progressive tempo: how many clean (flawless) repeats to play at each rung before bumping up. 1..99. Default 1. | ?ptafter=1 |
ptdec | Decrease on failure | true / false | Progressive tempo: when a run of clean repeats is broken by a wrong chord, drop one rung (tempo -= step, floored at from) and restart the rep count for that rung. When false, a break only restarts the rep count without dropping the tempo. Default true. | ?ptdec=true |
qls | Question label style | chord, roman, romanQuality, arabic, function | What the /app question label shows when subject is "scales" or "progressions". `chord` (default) keeps the chord long-name. `roman` shows the scale-degree Roman numeral ("ii", "V", "vi"; with a dot-inversion suffix like "V.1" when colorfulInversions is OFF). `romanQuality` adds the chord-quality glyph (UPPER for major, lower for minor, ° dim, + aug) when subject=scales AND the voicing is diatonic triads/sevenths; silently degrades to plain `roman` for progressions, single-note voicing, intervals, and non-diatonic scales. `arabic` shows the bare degree number. `function` shows the locale-aware function name. V1 had this as display-1/2/3 multi-checkboxes; V2 collapses them into one exclusive picker. | ?qls=chord?qls=roman |
mmode | exercise.melodyMode | levels, custom | Melodies subject (/repeat): the level ladder, or the custom fields below. Ladder exercises ignore the other melody* fields. | ?mmode=levels?mmode=custom |
mkey | exercise.melodyKey | C, C#, D, D#, E, F, F#, G, G#, A, A#, B, Db, Eb, Gb, Ab, Bb | Melodies custom mode: root key of the note pool. Own field, so a melody link never overwrites the Scales/Progressions key. | ?mkey=C?mkey=C%23 |
mscale | exercise.melodyScale | major, naturalMinor, pentatonicMajor, pentatonicMinor, blues, harmonicMinor, melodicMinor, dorian, mixolydian, lydian, phrygianDominant | Melodies custom mode: scale of the note pool. | ?mscale=major?mscale=naturalMinor |
mrange | exercise.melodyRange | five, octave, two-octaves | Melodies custom mode: note-pool width. | ?mrange=five?mrange=octave |
mleap | exercise.melodyLeap | -9007199254740991 – 9007199254740991 | Melodies custom mode: largest leap in scale steps, 1..7, or 999 for no limit. | ?mleap=4 |
mear | exercise.melodyEar | true / false | Melodies custom mode: play by ear, hide the keys the app plays (doubles points). | ?mear=true |
| User preferences | ||||
| — | Theme | light, playful | UI theme. `light` = Professional, `playful` = Playful. (The dark theme was removed; stored `dark` values fall back to light via catch.) | Set via /preferences. |
| — | Play piano sound when pressing keys P on /testing | true / false | Play a piano sample on every key click and MIDI noteOn. | Set via /preferences. |
| — | Piano volume | 0 – 100 | Piano-sample volume, 0–100. 0 silences the engine even when pianoSound is on. | Set via /preferences. |
| — | Metronome volume | 0 – 100 | Metronome click + visual-flash volume, 0–100. 0 silences the click; the visual flash still runs when metronomeStyle includes "visual". | Set via /preferences. |
| — | Audio feedback on key change | true / false | Play a gong when an auto-advance changes the key (Scales all-keys walks + Progressions after-repeats). | Set via /preferences. |
| — | user.activityChosen | true / false | True once the user has explicitly picked a practice activity (preferences select or the J shortcut). While false, suggested-exercise cards may default to Naming on narrow/mobile screens with no MIDI; once true, the chosen activity is always honored. | Set via /preferences. |
| — | Keep screen awake | true / false | Keep the screen from dimming or locking while practicing (uses the Wake Lock API; silently ignored on unsupported browsers). | Set via /preferences. |
| — | Chord notation | american, german, solfege, jazz | Chord + note naming convention shown everywhere on screen. | Set via /preferences. |
| — | user.splitPoint | string | Keyboard-split point (MIDI note, inclusive) or null=off. When set, only MIDI notes on splitSide of this note are assessed; the other hand still sounds + records. Set via the / or \ shortcut. | Set via /preferences. |
| — | user.splitSide | left, right | Which side of splitPoint is graded: right = notes >= splitPoint, left = notes <= splitPoint. | Set via /preferences. |
| — | Color chord blocks by quality | true / false | Tint the chord-question block by quality (major, minor, dim, …) for visual recall. | Set via /preferences. |
| — | Game mode (hearts + game-over) G on /app | true / false | Show heart counter; lose a heart on miss, gain one every 5-streak. Reset on game-over. | Set via /preferences. |
| — | user.babyMode | true / false | Simplified kid-friendly preferences UI (baby mode); advanced options hidden. | Set via /preferences. |
| — | Consecutive mistakes allowed | true / false | When true, missing twice in a row only costs one purple heart; the second consecutive miss is forgiven (V1 strict-mode guard). Game-mode only. | Set via /preferences. |
| — | Playing more notes than expected | any, chordTones, strict | What extra HELD keys beyond the expected answer do to a match. The segmenter deliberately tolerates keys sustained across questions (common-tone legato); this decides how far that goes. any = a matching candidate wins regardless of what else is held (pre-2026-09 behavior); chordTones (default) = extras are fine while every held key is a correct pitch class (octave doublings, sustained chord tones) and one foreign pc fails as wrong-notes; strict = the held count must equal the expected count, any extra key fails as wrong-count. Applied to the graded side only — a keyboard split still exempts the other hand entirely. | Set via /preferences. |
| — | Rootless chords | true / false | V1 #o-20 parity. When true, the chord root is dropped from the expected pitch classes during evaluation, so a C major question accepts E + G alone. Single-note questions short-circuit (no-op). Inversion strictness is suspended in this mode — the bass becomes the lowest non-root note and the "wrong-inversion" outcome no longer fires. | Set via /preferences. |
| — | Root note only O on /app | true / false | One-note mode. Whatever the exercise draws — a chord, a scale degree, a progression step, a song chord — the RIGHT hand only has to play the chord root; nothing else about the question changes (the same chord is drawn, named and hinted). The left hand is unaffected: `leftPlays` still decides what it owes. Wins over `rootlessMode` when both are on (rootless drops the note one-note keeps); a ninja pattern still overrides both. Single-note questions are unaffected. | Set via /preferences. |
| — | Play in chunks | true / false | V1 #o-38 parity. When true and the subject is scales with sequence=inOrder, the chart is fed in growing chunks: a flawless full pass through the active chunk advances the chunk (per `chunkMode`). The chord-chart strip visualizes the active chunk via the existing selectedIndices highlight pipeline. User chart-clicks are suppressed while this mode is on. | Set via /preferences. |
| — | Chunk length | 2 – 7 | V1 #o-388 parity. Number of consecutive degrees in each chart chunk when `playInChunks` is on. Clamped to 2..7. | Set via /preferences. |
| — | Chunk advance mode | cumulative, window | How the chart chunk advances per flawless loop. `cumulative` grows the chunk by one cell on each pass (V1 default — C → CD → CDE …). `window` slides a fixed-length window forward by `chunkLength` cells each pass (CDE → DEF → GAB …). Both wrap on overflow. | Set via /preferences. |
| — | Chart selection on key change | any, autoAdvance, never | How a chart-chord selection survives key/scaleType changes. `any`: persist through manual and auto (loop) key/scaleType changes. `autoAdvance`: persist only through the loop auto-advance; a manual key/scaleType change clears it. `never`: clear on any key/scaleType change (legacy behavior). Selection always resets on voicing/scaleRepeat/progression changes that alter the cell set. | Set via /preferences. |
| — | Daily practice target | 0 – 1440 | Daily practice goal in minutes. The streak badge turns orange once today's practice time crosses this value. Set to 0 to disable the indicator. | Set via /preferences. |
| — | Slash inversions (C/E) | true / false | Render inverted chords as slash bass (e.g. C/E) instead of "1st inv" pill. V1 parity with #o-23. | Set via /preferences. |
| — | Display inversions in the chart | true / false | Show inversion info in the chord chart labels: slash form (C/E) when slashInversions is on, else dot form (C.2). Off = plain chord names. | Set via /preferences. |
| — | Fireworks | true / false | Confetti burst on every correct chord, +1 heart gained, and level-over. V1 parity with #o-26. The library is lazy-loaded only when this is on. Default ON for everyone, but SUPPRESSED while the OS asks for `prefers-reduced-motion` and the user has not touched the toggle — see `fireworksChosen`. | Set via /preferences. |
| — | user.fireworksChosen | true / false | Set the first time the user works the fireworks toggle on /preferences (either direction), and by baby mode, which asks for the playful experience outright. Once set, the stored `fireworks` value is final and the OS `prefers-reduced-motion` setting stops suppressing the confetti. | Set via /preferences. |
| — | Chord-name form | short, long | Chord-label rendering form. Short = "Cm7" / "Cmaj9"; long = "C minor 7" / "C dur9". V1 parity with #chord_names_0/1. | Set via /preferences. |
| — | Exercise icons | identicon, bottts, none | "Mood" of the exid avatar. `identicon` = abstract geometric pattern (default); `bottts` = playful robot; `none` = hide the avatar/chip on every exid surface (cards, badges, footer). Same seed → same image per style. | Set via /preferences. |
| — | User-friendly exercise labels | true / false | Show the human pet name (e.g. "Mighty Owl") on exid cards. Default on. When off, the card head-line drops the pet span and only the chord/scale info remains. The schema-driven slug + identicon are still computed; this only gates the visible label. | Set via /preferences. |
| — | Color each inversion | true / false | Use per-inversion colors (root #111, 1st #82a905, 2nd #7952b3, 3rd orange) on the /app inversion pill, the chord-balls bass-note stroke, and the /preferences inversion buttons. When off, all inversions render in neutral black. | Set via /preferences. |
| — | Metronome style | audio, visual, audioVisual | How the /app metronome announces each beat: `audio` plays the click only, `visual` flashes the BPM number only, `audioVisual` (default) does both. | Set via /preferences. |
| — | Chord queue | true / false | When on, /app shows a row of upcoming chords (the queue) instead of just the current chord. The queue advances by one on every correct answer. | Set via /preferences. |
| — | Queue slots (2–8) | 2 – 8 | How many slots the chord queue shows when chordQueueEnabled is on. Slot 1 is the currently-graded chord; the rest are the upcoming queue. 2..8. | Set via /preferences. |
| — | Animate queue changes | true / false | Animate the queue shift after a correct answer (snappy ~120 ms slide-left + fade-in). Disable for a hard instant swap or to respect reduced-motion preferences manually. | Set via /preferences. |
| — | Repeat each chord | true / false | Repeat each chord N times before advancing (where N is `doubleModeValue`). Reinforces voicing + timing on the same chord before moving on. | Set via /preferences. |
| — | Repetitions | 2 – 10 | How many times each chord must be played in a row before advancing, when `doubleMode` is on. 2..10. | Set via /preferences. |
| — | including mistakes | true / false | In `doubleMode`, count a wrong attempt as one of the N reps. Speeds up sessions by not punishing slips; off (default) means only correct answers count toward the rep target. | Set via /preferences. |
| — | Highlight root note on the keyboard | true / false | Mark the chord root on the on-screen piano keyboard with the root color cue. Helps beginners locate the bass note at a glance. | Set via /preferences. |
| — | Show chord name | true / false | Show the chord name above the question on /app. Hide via the preferences toggle or by long-pressing the label. | Set via /preferences. |
| — | Note circles B on /app | true / false | Show the ball-notes hint inside the answer panel on /app. Half of the hint TYPE pair behind the single Hints container on /preferences (B shortcut); at least one of the pair stays on, so the panel — and the Naming quiz question — is never empty. Hide via that control or by long-pressing the balls. Only consulted once `answerHintsChosen` is true — until then the screen width picks the default (narrow → off). | Set via /preferences. |
| — | Piano keyboard K on /app | true / false | Show the on-screen piano keyboard inside the answer panel on /app. The other half of the hint TYPE pair (K shortcut; see showAnswerBalls). Hide via the Hints container or by long-pressing the keyboard. Only consulted once `answerHintsChosen` is true — until then the screen width picks the default (narrow → off). | Set via /preferences. |
| — | user.answerHintsChosen | true / false | True once the user has explicitly toggled either answer hint (balls / keyboard) on /preferences. While false, both default to OFF on a narrow screen and ON otherwise — a phone has no room to show the answer beside the question, and showing it there gave the answer away before the player had tried. Once true, the stored `showAnswerBalls` / `showAnswerKeyboard` values are honored on every device. | Set via /preferences. |
| — | Show chord chart | true / false | In Scales / Progressions / Songs subjects, show the chord-chart strip — a horizontal row of every chord in the current cycle. Click a cell to restrict the draw pool to a subset (inOrder walks click-order, random picks within the subset). Hide via the /preferences toggle or by long-pressing the strip. | Set via /preferences. |
| — | Show inversion bar | true / false | Show the inversion pill (current chord inversion + hand icons) on /app across Chords, Progressions and Scales subjects, regardless of the notation/chord-label question mode. Colored by colorfulInversions when that option is on. Hide via the /preferences toggle or by long-pressing the pill. | Set via /preferences. |
| — | Keep hints always visible H on /app | true / false | Keep the answer panel (balls + keyboard) visible at all times, not only after Space-to-reveal or a wrong attempt. The H shortcut toggles it; B / K choose WHICH surface the panel holds (at least one stays on). V1 `o-0` parity. | Set via /preferences. |
| — | Show hints automatically when you are about to lose | true / false | Auto-show the answer panel once the player is NEAR DEATH — on the last purple heart, game mode only — and keep it up. Historic key name: the reveal-after-a-wrong-attempt it used to gate is now unconditional (a mistake always reveals the answer, V1 default behavior), so this box is the third of the three behaviors: default / always visible / auto on the last life. Renaming the key would break existing share links and synced states. | Set via /preferences. |
| — | Reinforcement learning (random mode) | true / false | When on, the random-draw weights drift toward chords you miss more often and away from chords you nail. Only effective when the exercise sequence is "random". See /chord-stats for the live ranking. | Set via /preferences. |
| — | Scale steps highlighting | off, keys, bullets | Scale-note keyboard highlighting (scales subject only). `off` paints nothing; `keys` tints the whole white/black key behind every scale-degree pitch class; `bullets` marks each scale-degree key with a colored dot (green on non-root pitches, red on the tonic). | Set via /preferences. |
| — | Display fingerings (1–5) F on /app | true / false | Display piano fingerings (digits 1-5) on keyboard hints. Scales subject + singleNotes voicing only; mutually exclusive with hlType (engaging fingerings overrides scale tint). | Set via /preferences. |
| — | Instrument | piano, guitar | Visual instrument used by the chord-hint panel under the Q&A. `piano` (default) renders the existing PianoKeyboard SVG. `guitar` renders a 6-string fretboard via the svguitar library, with chord shapes sourced from @tombatossals/chords-db and matched to the exercise inversion. Both libraries are lazy-loaded so piano-only users pay zero bytes. Ukulele defers to Phase 2. | Set via /preferences. |
| — | How questions are shown N on /app,/preferences | chordNames, staff | How the question is rendered on /app. `chordNames` (default) shows the chord label (e.g. "Am7"); `staff` shows the notes on a music staff (VexFlow renderer). Toggled with the N keyboard shortcut. When `staff`, see the staff* sub-options. | Set via /preferences. |
| — | Notes on the staff · Layout | off, asc, desc, random | Staff layout when notationDisplay=staff. `off` = harmonic (notes stacked vertically as a chord); `asc`/`desc`/`random` = melodic (chord split into single notes laid out left-to-right in the chosen order). | Set via /preferences. |
| — | Whole notes | true / false | Staff notes rendered as quarter notes (default — filled noteheads with stems hidden) vs whole notes (open noteheads). | Set via /preferences. |
| — | Highlight root note (orange) | true / false | When notationDisplay=staff, paint the root note of each chord in orange so the bass note stands out. | Set via /preferences. |
| — | Octave shift | string | Octave shift for staff rendering: -1 / 0 / +1. Default 0 anchors at middle C. | Set via /preferences. |
| — | Show clef + key signature | true / false | Show the clef glyph and the key-signature accidentals at the staff head. When on, per-note accidentals that the signature already covers are stripped, so diatonic chords read clean. Default ON — the per-key spelling pipeline relies on the user being able to see which signature they are in. | Set via /preferences. |
| — | Clef | auto, treble, bass | Clef used for staff rendering. `auto` derives from the active hand (left → bass, right or both/any → treble). `treble` and `bass` force the choice. | Set via /preferences. |
| — | user.naming | string | Chord-naming (multiple-choice quiz) preferences — used when exercise.activity=naming. | Set via /preferences. |
| — | user.layout | string | Element-layout preferences for /app (3-column responsive grid). | Set via /preferences. |
| — | user.rewards | string | Reward-image preferences. V1 parity for `o-39 displayCats` + `o-40 rewardMilestones`. | Set via /preferences. |
| — | user.ear | string | Ear-training (audio quiz) preferences — used when exercise.activity=ear. | Set via /preferences. |
| — | user.jumper | string | Jumper-game preferences — used when exercise.activity=jumper. | Set via /preferences. |
Building exercises with an AI assistant? Machine-readable versions of this reference: params.md, params.json, recipe cookbook, also in llms.txt.
Options schema version: 41