{"version":1,"optionsVersion":41,"baseUrl":"/app","contract":"Exercises are configured entirely by URL query params on /app.\nRules:\n- Base path: /app. Append params as a query string, e.g. /app?subject=scales&voicing=triads.\n- Omit any param to accept its default (defaults listed per param below).\n- Arrays (inv, ct, bn) are comma-separated: inv=0,1,2 — ct=0,1 — bn=0,2,4.\n- Booleans are true / false: reqinv=false.\n- URL-encode special characters in values (e.g. key=F# becomes key=F%23, a space becomes %20 or +).\n- Most user preferences (theme, sound, ear/jumper tuning, etc.) are set on\n  /preferences and cannot be driven from a URL. EXCEPTION: a small whitelist of\n  display prefs — staff/notation, root highlight, fingering (see \"URL-overridable\n  preferences\" below) — CAN be set in the URL. Those overrides apply only to that\n  visit and are NOT saved, so a shared link never changes the visitor's prefs.","params":[{"param":"activity","key":"activity","type":"enum","values":"piano, naming, ear, jumper","default":"piano","description":"What the user does in the exercise: piano (live MIDI play), naming (multiple-choice naming), ear (audio recognition), jumper (metronome rhythm game)."},{"param":"subject","key":"subject","type":"enum","values":"chords, scales, progressions, songs, melodies","default":"chords","description":"Musical subject the exercise draws from. Tab order (chords → scales → progressions → songs → melodies) drives the /preferences segmented control."},{"param":"key","key":"key","type":"enum","values":"C, C#, D, D#, E, F, F#, G, G#, A, A#, B, Db, Eb, Gb, Ab, Bb","default":"C","description":"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."},{"param":"scale","key":"scale","type":"enum","values":"major, minor, harmonicMinor, melodicMinor","default":"major","description":"Scale type built off the root key."},{"param":"inv","key":"inversions","type":"array","values":"array of 0–3 (comma-separated in URL)","default":[0],"description":"Inversion indices to drill, comma-separated in the URL (e.g. inv=0,1,2)."},{"param":"voicing","key":"voicing","type":"enum","values":"singleNotes, triads, sevenths, ninths, progression, intM2, int2, intM3, int3, int4, intTT, int5, intM6, int6, intM7, int7, int8","default":"triads","description":"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."},{"param":"hand","key":"hand","type":"enum","values":"any, left, right, both","default":"right","description":"Which hand the exercise practices. \"any\" accepts either one-hand or two-hand play (single chord or chord doubled across octaves)."},{"param":"lplay","key":"leftPlays","type":"enum","values":"same, root, lowest, octaves, fifths, nothing","default":"same","description":"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\"."},{"param":"tempo","key":"tempo","type":"number","values":"20 – 300","default":60,"description":"Metronome tempo in beats per minute."},{"param":"meter","key":"metrum","type":"enum","values":"4/4, 3/4, 6/8","default":"4/4","description":"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."},{"param":"acc","key":"accidentals","type":"enum","values":"sharp, flat, random, auto","default":"auto","description":"Black-key spelling: always sharps, always flats, random per render, or auto-derived from the current scale."},{"param":"reqinv","key":"requireInversion","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"ct","key":"chordTypes","type":"array","values":"array of 0–67 (comma-separated in URL)","default":[0],"description":"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."},{"param":"bn","key":"baseNotes","type":"array","values":"array of 0–11 (comma-separated in URL)","default":[0,2,4,5,7,9,11],"description":"Pitch classes (0..11, C=0) allowed as chord roots when drawing. At least one must remain selected."},{"param":"nj","key":"ninjaMode","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"njl","key":"ninjaLeft","type":"array","values":"array of 0–21 (comma-separated in URL)","default":[],"description":"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."},{"param":"njr","key":"ninjaRight","type":"array","values":"array of 0–21 (comma-separated in URL)","default":[0],"description":"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."},{"param":"sv","key":"specificVoicing","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"svl","key":"specificVoicingLeft","type":"array","values":"array of string (comma-separated in URL)","default":[1],"description":"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."},{"param":"svr","key":"specificVoicingRight","type":"array","values":"array of string (comma-separated in URL)","default":[3,5],"description":"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."},{"param":"seq","key":"sequence","type":"enum","values":"random, inOrder, harmonized, allInversions, inOrderUpDown, inOrderUpDownPeak, circleFifthsCW, circleFifthsCCW, chromaticUp, chromaticDown","default":"random","description":"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."},{"param":"mode","key":"scaleType","type":"enum","values":"major, naturalMinor, harmonicMinor, melodicMinor, ionian, dorian, phrygian, lydian, mixolydian, aeolian, locrian, tetrachordsMajor, tetrachordsMinor, pentascaleMajor, pentascaleMinor, pentatonicMajor, pentatonicMinor, blues, bebopDominant, bebopMajor, bebopMinor, chromatic","default":"major","description":"Scale mode for subject=scales — slug from the 20-mode V1 taxonomy (major..chromatic). Non-diatonic slugs (pentatonic*, blues, bebop*, chromatic) force voicing=singleNotes."},{"param":"repeat","key":"scaleRepeat","type":"enum","values":"none, end, top, both","default":"end","description":"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."},{"param":"sloop","key":"scaleLoopCount","type":"string","values":"string","description":"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`.)"},{"param":"sloopok","key":"scaleLoopFlawlessOnly","type":"string","values":"string","description":"Legacy (scales subject): the old all-keys \"only flawless\" flag. Migrated into `scaleAfterRepeatsFlawlessOnly` when it arrives with a retired all-keys sequence; otherwise ignored."},{"param":"safter","key":"scaleAfterRepeats","type":"enum","values":"done, cofCW, cofCCW, chromaticUp, chromaticDown","default":"done","description":"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."},{"param":"safn","key":"scaleAfterRepeatsCount","type":"number","values":"1 – 99","default":1,"description":"Scales subject only: how many completed passes trigger `scaleAfterRepeats`. 1..99. Default 1."},{"param":"safok","key":"scaleAfterRepeatsFlawlessOnly","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"prog","key":"progression","type":"string","values":"string","default":"","description":"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."},{"param":"spec","key":"specific","type":"string","values":"string","default":"D, G, C","description":"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`)."},{"param":"spsn","key":"songsSingleNotes","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"sui","key":"songsUseInversions","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"title","key":"songTitle","type":"string","values":"string","description":"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."},{"param":"advrep","key":"advanceAfterRepeats","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"advrepn","key":"advanceAfterRepeatsCount","type":"number","values":"1 – 99","default":3,"description":"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."},{"param":"advrepd","key":"advanceAfterRepeatsDirection","type":"enum","values":"cofCW, cofCCW, chromaticUp, chromaticDown","default":"cofCW","description":"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."},{"param":"advrepok","key":"advanceAfterRepeatsFlawlessOnly","type":"string","values":"string","description":"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."},{"param":"ptempo","key":"progressiveTempo","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"ptfrom","key":"progressiveTempoFrom","type":"number","values":"20 – 300","default":60,"description":"Progressive tempo: starting BPM (bottom rung of the ladder). 20..300."},{"param":"ptto","key":"progressiveTempoTo","type":"number","values":"20 – 300","default":200,"description":"Progressive tempo: target BPM (top rung, always played after the last full step). 20..300."},{"param":"ptstep","key":"progressiveTempoStep","type":"number","values":"1 – 200","default":20,"description":"Progressive tempo: BPM increment between rungs. 1..200. Default 20."},{"param":"ptafter","key":"progressiveTempoAfter","type":"number","values":"1 – 99","default":1,"description":"Progressive tempo: how many clean (flawless) repeats to play at each rung before bumping up. 1..99. Default 1."},{"param":"ptdec","key":"progressiveTempoDecreaseOnFailure","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"qls","key":"questionLabelStyle","type":"enum","values":"chord, roman, romanQuality, arabic, function","default":"chord","description":"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."},{"param":"mmode","key":"melodyMode","type":"enum","values":"levels, custom","default":"levels","description":"Melodies subject (/repeat): the level ladder, or the custom fields below. Ladder exercises ignore the other melody* fields."},{"param":"mkey","key":"melodyKey","type":"enum","values":"C, C#, D, D#, E, F, F#, G, G#, A, A#, B, Db, Eb, Gb, Ab, Bb","default":"C","description":"Melodies custom mode: root key of the note pool. Own field, so a melody link never overwrites the Scales/Progressions key."},{"param":"mscale","key":"melodyScale","type":"enum","values":"major, naturalMinor, pentatonicMajor, pentatonicMinor, blues, harmonicMinor, melodicMinor, dorian, mixolydian, lydian, phrygianDominant","default":"major","description":"Melodies custom mode: scale of the note pool."},{"param":"mrange","key":"melodyRange","type":"enum","values":"five, octave, two-octaves","default":"five","description":"Melodies custom mode: note-pool width."},{"param":"mleap","key":"melodyLeap","type":"number","values":"-9007199254740991 – 9007199254740991","default":4,"description":"Melodies custom mode: largest leap in scale steps, 1..7, or 999 for no limit."},{"param":"mear","key":"melodyEar","type":"boolean","values":"true / false","default":false,"description":"Melodies custom mode: play by ear, hide the keys the app plays (doubles points)."}],"userOverrides":[{"param":"nd","key":"notationDisplay","type":"enum","values":"chordNames, staff","default":"chordNames","description":"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."},{"param":"smel","key":"staffMelodic","type":"enum","values":"off, asc, desc, random","default":"off","description":"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)."},{"param":"swhole","key":"staffWholeNotes","type":"boolean","values":"true / false","default":false,"description":"Staff notes rendered as quarter notes (default — filled noteheads with stems hidden) vs whole notes (open noteheads)."},{"param":"sroot","key":"staffHighlightRoot","type":"boolean","values":"true / false","default":false,"description":"When notationDisplay=staff, paint the root note of each chord in orange so the bass note stands out."},{"param":"soct","key":"staffOctaveShift","type":"string","values":"string","default":0,"description":"Octave shift for staff rendering: -1 / 0 / +1. Default 0 anchors at middle C."},{"param":"sclef","key":"staffShowClef","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"clef","key":"staffClef","type":"enum","values":"auto, treble, bass","default":"auto","description":"Clef used for staff rendering. `auto` derives from the active hand (left → bass, right or both/any → treble). `treble` and `bass` force the choice."},{"param":"hlroot","key":"highlightRootKey","type":"boolean","values":"true / false","default":false,"description":"Mark the chord root on the on-screen piano keyboard with the root color cue. Helps beginners locate the bass note at a glance."},{"param":"fing","key":"showFingering","type":"boolean","values":"true / false","default":false,"description":"Display piano fingerings (digits 1-5) on keyboard hints. Scales subject + singleNotes voicing only; mutually exclusive with hlType (engaging fingerings overrides scale tint)."},{"param":"hl","key":"hlType","type":"enum","values":"off, keys, bullets","default":"off","description":"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)."},{"param":"instr","key":"instrument","type":"enum","values":"piano, guitar","default":"piano","description":"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."},{"param":"nota","key":"notation","type":"enum","values":"american, german, solfege, jazz","default":"american","description":"Chord + note naming convention shown everywhere on screen."},{"param":"cnf","key":"chordNameForm","type":"enum","values":"short, long","default":"short","description":"Chord-label rendering form. Short = \"Cm7\" / \"Cmaj9\"; long = \"C minor 7\" / \"C dur9\". V1 parity with #chord_names_0/1."},{"param":"slash","key":"slashInversions","type":"boolean","values":"true / false","default":false,"description":"Render inverted chords as slash bass (e.g. C/E) instead of \"1st inv\" pill. V1 parity with #o-23."},{"param":"chinv","key":"chartInversions","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"colinv","key":"colorfulInversions","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"scn","key":"showChordName","type":"boolean","values":"true / false","default":true,"description":"Show the chord name above the question on /app. Hide via the preferences toggle or by long-pressing the label."},{"param":"balls","key":"showAnswerBalls","type":"boolean","values":"true / false","default":true,"description":"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)."},{"param":"keys","key":"showAnswerKeyboard","type":"boolean","values":"true / false","default":true,"description":"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)."},{"param":"hintsset","key":"answerHintsChosen","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"chart","key":"showChordChart","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"invpill","key":"showInversionPill","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"hints","key":"hintsAlways","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"hintmiss","key":"autoHintsOnMiss","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"qcol","key":"questionColors","type":"boolean","values":"true / false","default":false,"description":"Tint the chord-question block by quality (major, minor, dim, …) for visual recall."},{"param":"queue","key":"chordQueueEnabled","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"queuen","key":"chordQueueSize","type":"number","values":"2 – 8","default":4,"description":"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."},{"param":"rootless","key":"rootlessMode","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"onenote","key":"oneNoteMode","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"extras","key":"extraNotesPolicy","type":"enum","values":"any, chordTones, strict","default":"chordTones","description":"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."},{"param":"forgive","key":"allowConsecutiveMistakes","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"mfm","key":"moveForwardOnMistake","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"rlearn","key":"reinforcementLearning","type":"boolean","values":"true / false","default":true,"description":"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."},{"param":"dbl","key":"doubleMode","type":"boolean","values":"true / false","default":false,"description":"Repeat each chord N times before advancing (where N is `doubleModeValue`). Reinforces voicing + timing on the same chord before moving on."},{"param":"dbln","key":"doubleModeValue","type":"number","values":"2 – 10","default":3,"description":"How many times each chord must be played in a row before advancing, when `doubleMode` is on. 2..10."},{"param":"chunks","key":"playInChunks","type":"boolean","values":"true / false","default":false,"description":"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."},{"param":"chunkn","key":"chunkLength","type":"number","values":"2 – 7","default":3,"description":"V1 #o-388 parity. Number of consecutive degrees in each chart chunk when `playInChunks` is on. Clamped to 2..7."},{"param":"chunkmode","key":"chunkMode","type":"enum","values":"cumulative, window","default":"cumulative","description":"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."}],"legends":{"chordQualities":[{"id":0,"name":"major","kind":"chord","pattern":[0,4,7]},{"id":1,"name":"minor","kind":"chord","pattern":[0,3,7]},{"id":2,"name":"diminished","kind":"chord","pattern":[0,3,6]},{"id":3,"name":"augmented","kind":"chord","pattern":[0,4,8]},{"id":4,"name":"suspended 2nd","kind":"chord","pattern":[0,2,7]},{"id":5,"name":"suspended 4th","kind":"chord","pattern":[0,5,7]},{"id":6,"name":"major 7","kind":"chord","pattern":[0,4,7,11]},{"id":7,"name":"minor 7","kind":"chord","pattern":[0,3,7,10]},{"id":8,"name":"dominant 7","kind":"chord","pattern":[0,4,7,10]},{"id":9,"name":"half-diminished 7","kind":"chord","pattern":[0,3,6,10]},{"id":10,"name":"diminished 7","kind":"chord","pattern":[0,3,6,9]},{"id":11,"name":"augmented 7","kind":"chord","pattern":[0,4,8,10]},{"id":12,"name":"augmented major 7","kind":"chord","pattern":[0,4,8,11]},{"id":13,"name":"minor-major 7","kind":"chord","pattern":[0,3,7,11]},{"id":14,"name":"minor 7 sharp 5","kind":"chord","pattern":[0,3,8,10]},{"id":15,"name":"major 6","kind":"chord","pattern":[0,4,7,9]},{"id":16,"name":"minor 6","kind":"chord","pattern":[0,3,7,9]},{"id":17,"name":"add 9","kind":"chord","pattern":[0,4,7,14]},{"id":18,"name":"minor add 9","kind":"chord","pattern":[0,3,7,14]},{"id":19,"name":"major 9","kind":"chord","pattern":[0,4,7,11,14]},{"id":20,"name":"minor 9","kind":"chord","pattern":[0,3,7,10,14]},{"id":21,"name":"dominant 9","kind":"chord","pattern":[0,4,7,10,14]},{"id":22,"name":"half-diminished 9","kind":"chord","pattern":[0,3,6,10,14]},{"id":23,"name":"minor-major 9","kind":"chord","pattern":[0,3,7,11,14]},{"id":24,"name":"major 9 sharp 5","kind":"chord","pattern":[0,4,8,11,14]},{"id":25,"name":"minor 11","kind":"chord","pattern":[0,3,7,10,14,17]},{"id":26,"name":"major 11","kind":"chord","pattern":[0,4,7,11,14,17]},{"id":27,"name":"dominant 11","kind":"chord","pattern":[0,4,7,10,14,17]},{"id":28,"name":"half-diminished 11","kind":"chord","pattern":[0,3,6,10,14,17]},{"id":29,"name":"minor-major 11","kind":"chord","pattern":[0,3,7,11,14,17]},{"id":30,"name":"augmented major 11","kind":"chord","pattern":[0,4,8,11,14,17]},{"id":31,"name":"major 13","kind":"chord","pattern":[0,4,7,11,14,17,21]},{"id":32,"name":"minor 13","kind":"chord","pattern":[0,3,7,10,14,17,21]},{"id":33,"name":"dominant 13","kind":"chord","pattern":[0,4,7,10,14,17,21]},{"id":34,"name":"half-diminished 13","kind":"chord","pattern":[0,3,6,10,14,17,21]},{"id":35,"name":"minor-major 13","kind":"chord","pattern":[0,3,7,11,14,17,21]},{"id":36,"name":"major 13 sharp 5","kind":"chord","pattern":[0,4,8,11,14,17,21]},{"id":37,"name":"minor 2nd","kind":"interval","pattern":[0,1]},{"id":38,"name":"major 2nd","kind":"interval","pattern":[0,2]},{"id":39,"name":"minor 3rd","kind":"interval","pattern":[0,3]},{"id":40,"name":"major 3rd","kind":"interval","pattern":[0,4]},{"id":41,"name":"perfect 4th","kind":"interval","pattern":[0,5]},{"id":42,"name":"tritone","kind":"interval","pattern":[0,6]},{"id":43,"name":"perfect 5th","kind":"interval","pattern":[0,7]},{"id":44,"name":"minor 6th","kind":"interval","pattern":[0,8]},{"id":45,"name":"major 6th","kind":"interval","pattern":[0,9]},{"id":46,"name":"minor 7th","kind":"interval","pattern":[0,10]},{"id":47,"name":"major 7th","kind":"interval","pattern":[0,11]},{"id":48,"name":"octave","kind":"interval","pattern":[0,12]},{"id":49,"name":"note","kind":"note","pattern":[0]},{"id":50,"name":"minor 7 flat 9","kind":"chord","pattern":[0,3,7,10,13]},{"id":51,"name":"half-diminished 7 flat 9","kind":"chord","pattern":[0,3,6,10,13]},{"id":52,"name":"dominant 13 sharp 11","kind":"chord","pattern":[0,4,7,10,14,18,21]},{"id":53,"name":"dominant 7 sharp 9 sharp 5","kind":"chord","pattern":[0,4,8,10,15]},{"id":54,"name":"power chord","kind":"chord","pattern":[0,7,12]},{"id":55,"name":"dominant 7 sus4","kind":"chord","pattern":[0,5,7,10]},{"id":56,"name":"dominant 7 sus2","kind":"chord","pattern":[0,2,7,10]},{"id":57,"name":"six-nine","kind":"chord","pattern":[0,4,7,9,14]},{"id":58,"name":"minor six-nine","kind":"chord","pattern":[0,3,7,9,14]},{"id":59,"name":"add 11","kind":"chord","pattern":[0,4,7,17]},{"id":60,"name":"dominant 7 flat 5","kind":"chord","pattern":[0,4,6,10]},{"id":61,"name":"dominant 7 flat 9","kind":"chord","pattern":[0,4,7,10,13]},{"id":62,"name":"dominant 7 sharp 9","kind":"chord","pattern":[0,4,7,10,15]},{"id":63,"name":"dominant 7 sharp 11","kind":"chord","pattern":[0,4,7,10,18]},{"id":64,"name":"dominant 9 flat 5","kind":"chord","pattern":[0,4,6,10,14]},{"id":65,"name":"dominant 9 sharp 11","kind":"chord","pattern":[0,4,7,10,14,18]},{"id":66,"name":"major 7 sharp 11","kind":"chord","pattern":[0,4,7,11,18]},{"id":67,"name":"major 9 sharp 11","kind":"chord","pattern":[0,4,7,11,14,18]}],"pitchClasses":[{"value":0,"note":"C"},{"value":1,"note":"C#"},{"value":2,"note":"D"},{"value":3,"note":"D#"},{"value":4,"note":"E"},{"value":5,"note":"F"},{"value":6,"note":"F#"},{"value":7,"note":"G"},{"value":8,"note":"G#"},{"value":9,"note":"A"},{"value":10,"note":"A#"},{"value":11,"note":"B"}],"intervalVoicings":[{"voicing":"intM2","interval":"minor 2nd"},{"voicing":"int2","interval":"major 2nd"},{"voicing":"intM3","interval":"minor 3rd"},{"voicing":"int3","interval":"major 3rd"},{"voicing":"int4","interval":"perfect 4th"},{"voicing":"intTT","interval":"tritone"},{"voicing":"int5","interval":"perfect 5th"},{"voicing":"intM6","interval":"minor 6th"},{"voicing":"int6","interval":"major 6th"},{"voicing":"intM7","interval":"minor 7th"},{"voicing":"int7","interval":"major 7th"},{"voicing":"int8","interval":"octave"}]},"recipes":[{"slug":"major-triads-all-keys","title":"Major triads in every key","phrase":"Practice major triads in all twelve keys, root position.","url":"/app?subject=chords&voicing=triads&ct=0&inv=0"},{"slug":"major-minor-triads","title":"Major & minor triads mixed","phrase":"Drill major and minor triads together.","url":"/app?subject=chords&voicing=triads&ct=0%2C1&inv=0"},{"slug":"all-triad-qualities","title":"All four triad qualities","phrase":"Major, minor, diminished and augmented triads.","url":"/app?subject=chords&voicing=triads&ct=0%2C1%2C2%2C3"},{"slug":"triads-all-inversions","title":"Triads through all inversions","phrase":"Major and minor triads in root, first and second inversion.","url":"/app?subject=chords&voicing=triads&ct=0%2C1&inv=0%2C1%2C2"},{"slug":"white-key-triads","title":"White-key triads (beginner)","phrase":"Triads rooted only on the white keys.","url":"/app?subject=chords&voicing=triads&ct=0%2C1&bn=0%2C2%2C4%2C5%2C7%2C9%2C11"},{"slug":"seventh-chords-core","title":"Core seventh chords","phrase":"maj7, m7 and dominant 7 chords.","url":"/app?subject=chords&voicing=sevenths&ct=6%2C7%2C8"},{"slug":"diminished-sevenths","title":"Diminished 7th chords","phrase":"Diminished seventh chords in all keys.","url":"/app?subject=chords&voicing=sevenths&ct=10"},{"slug":"two-hands-root-bass","title":"Triads, both hands, root in the bass","phrase":"Right hand the triad, left hand just the root.","url":"/app?subject=chords&voicing=triads&ct=0%2C1&hand=both&lplay=root"},{"slug":"c-major-scale-notes","title":"C major scale, note by note","phrase":"Walk up the C major scale one note at a time.","url":"/app?subject=scales&key=C&mode=major&voicing=singleNotes&seq=inOrder"},{"slug":"diatonic-triads-major","title":"Diatonic triads of the major scale","phrase":"Harmonize the major scale in triads, in order.","url":"/app?subject=scales&mode=major&voicing=triads&seq=inOrder&inv=0"},{"slug":"diatonic-sevenths-major","title":"Diatonic seventh chords of the major scale","phrase":"Harmonize the major scale in seventh chords.","url":"/app?subject=scales&mode=major&voicing=sevenths&seq=inOrder"},{"slug":"natural-minor-scale","title":"Natural minor scale notes","phrase":"Play the natural minor scale, ascending.","url":"/app?subject=scales&mode=naturalMinor&voicing=singleNotes&seq=inOrder"},{"slug":"harmonic-minor-scale","title":"Harmonic minor scale notes","phrase":"Play the harmonic minor scale.","url":"/app?subject=scales&mode=harmonicMinor&voicing=singleNotes&seq=inOrder"},{"slug":"major-pentatonic","title":"Major pentatonic scale","phrase":"Practice the major pentatonic scale.","url":"/app?subject=scales&mode=pentatonicMajor&voicing=singleNotes&seq=inOrder"},{"slug":"blues-scale","title":"Blues scale","phrase":"Run the blues scale.","url":"/app?subject=scales&mode=blues&voicing=singleNotes&seq=inOrder"},{"slug":"dorian-mode","title":"Dorian mode","phrase":"Play the Dorian mode.","url":"/app?subject=scales&mode=dorian&voicing=singleNotes&seq=inOrder"},{"slug":"scale-thirds","title":"Scale in diatonic thirds","phrase":"Play the major scale harmonized a third above each degree.","url":"/app?subject=scales&mode=major&voicing=int3&seq=inOrder"},{"slug":"scale-octaves","title":"Scale in octaves","phrase":"Play the major scale doubled at the octave.","url":"/app?subject=scales&mode=major&voicing=int8&seq=inOrder"},{"slug":"scale-all-keys-twice","title":"Minor scale through all keys, twice each","phrase":"Play the natural minor scale twice in each key around the circle of fifths before moving on.","url":"/app?subject=scales&mode=naturalMinor&seq=inOrder&safter=cofCW&safn=2"},{"slug":"ii-v-i-all-keys","title":"ii–V–I through all keys (circle of fifths)","phrase":"Practice the ii–V–I jazz cadence in every key around the circle of fifths.","url":"/app?subject=progressions&prog=ii+V+I&advrep=true&advrepn=2&advrepd=cofCW"},{"slug":"pop-axis","title":"I–V–vi–IV pop progression","phrase":"The four-chord pop progression.","url":"/app?subject=progressions&prog=I+V+vi+IV"},{"slug":"doo-wop","title":"I–vi–IV–V doo-wop changes","phrase":"The 50s doo-wop progression.","url":"/app?subject=progressions&prog=I+vi+IV+V"},{"slug":"twelve-bar-blues","title":"12-bar blues","phrase":"Play a 12-bar blues in I–IV–V.","url":"/app?subject=progressions&prog=I+I+I+I+IV+IV+I+I+V+IV+I+V"},{"slug":"roman-numeral-analysis","title":"Progression with Roman-numeral labels","phrase":"Show the Roman numeral for each chord in the progression.","url":"/app?subject=progressions&prog=I+vi+IV+V&qls=roman"},{"slug":"ear-training-triads","title":"Ear training — recognize triad qualities","phrase":"Hear a chord and identify whether it is major, minor, diminished or augmented.","url":"/app?activity=ear&subject=chords&voicing=triads&ct=0%2C1%2C2%2C3"},{"slug":"naming-sevenths","title":"Multiple-choice naming — seventh chords","phrase":"Name seventh chords from a multiple-choice list.","url":"/app?activity=naming&subject=chords&voicing=sevenths&ct=6%2C7%2C8"},{"slug":"jumper-rhythm","title":"Rhythm game at 80 BPM","phrase":"Metronome rhythm game, moderate tempo.","url":"/app?activity=jumper&tempo=80"},{"slug":"staff-triads-fsharp","title":"F# major triads, read on the staff","phrase":"Diatonic triads of F# major, shown as notes on the staff, up and down.","url":"/app?subject=scales&key=F%23&mode=major&voicing=triads&seq=inOrderUpDown&nd=staff"},{"slug":"staff-triads-melodic","title":"Triads on the staff, broken (melodic) ascending","phrase":"Sight-read diatonic triads as a melodic line, ascending.","url":"/app?subject=scales&mode=major&voicing=triads&seq=inOrder&nd=staff&smel=asc"},{"slug":"staff-sevenths-bass","title":"Seventh chords on the bass-clef staff","phrase":"Read diatonic seventh chords in the bass clef.","url":"/app?subject=scales&mode=major&voicing=sevenths&seq=inOrder&nd=staff&clef=bass"},{"slug":"staff-single-notes-bass","title":"Single notes on the staff (bass clef sight-reading)","phrase":"Name the notes of the C major scale read off the bass-clef staff.","url":"/app?subject=scales&key=C&mode=major&voicing=singleNotes&seq=inOrder&nd=staff&clef=bass"},{"slug":"triads-root-and-fingering","title":"Triads with the root highlighted and fingering shown","phrase":"Major and minor triads with the root note marked and finger numbers displayed.","url":"/app?subject=chords&voicing=triads&ct=0%2C1&hlroot=true&fing=true"},{"slug":"melody-single-notes","title":"Play a melody, one note at a time","phrase":"Practice the melody C D E F G A B as single notes.","url":"/app?subject=songs&spec=C+D+E+F+G+A+B&spsn=true&seq=inOrder"},{"slug":"melody-ode-to-joy","title":"A real tune as single notes","phrase":"Practice the opening of Ode to Joy note by note.","url":"/app?subject=songs&spec=E+E+F+G+G+F+E+D+C+C+D+E+E+D+D&spsn=true&seq=inOrder"},{"slug":"melody-with-bars","title":"A melody written in bars","phrase":"Practice a melody with bar lines, in order.","url":"/app?subject=songs&spec=C+D+E+F+%7C+G+A+B+C+%7C+B+A+G+F+%7C+E+D+C&spsn=true&seq=inOrder"},{"slug":"song-chord-sequence","title":"A specific chord sequence","phrase":"Practice the chords D, G and C in order.","url":"/app?subject=songs&spec=D+G+C&seq=inOrder"},{"slug":"song-chords-with-inversions","title":"A chord sequence with written inversions","phrase":"Practice Am first inversion, Cmaj7, then F#m7b5 over A.","url":"/app?subject=songs&spec=Am.1+Cmaj7+F%23m7b5%2FA+C%2FE&seq=inOrder"},{"slug":"diatonic-ninths-major","title":"Diatonic ninth chords of a major scale","phrase":"Play the ninth chord built on every degree of C major.","url":"/app?subject=scales&key=C&mode=major&voicing=ninths&seq=inOrder"},{"slug":"diatonic-ninths-minor","title":"Diatonic ninth chords of a natural minor scale","phrase":"Play the ninth chord on every degree of A natural minor.","url":"/app?subject=scales&key=A&mode=naturalMinor&voicing=ninths&seq=inOrder"},{"slug":"flat-nine-chords","title":"The two ♭9 chords on their own","phrase":"Drill m7♭9 and m7♭5♭9 in every key.","url":"/app?subject=chords&voicing=sevenths&ct=50%2C51&inv=0"}]}