Skip to content

Latest commit

 

History

History
152 lines (129 loc) · 37.3 KB

File metadata and controls

152 lines (129 loc) · 37.3 KB

Browser Test Matrix

Test the published PWA over HTTPS. Browser extensions, power-saving modes, and audio-device routing can change the result, so record the browser version and device with each manual run.

Current evidence

Browser Platform MIDI, shortcuts, and audio MusicXML, playback, practice Resize and offline Status
Headless Chromium 149 Linux (archie) Prior audio unlock, polyphony, analyser, and shortcut pass; Web MIDI rerun pending Supported and malformed import, score schedule, paired-row navigation/playback/Practice, practice start/abort/retry, random measure Canvas batches, paired-row responsive widths, unload/reload, view toggling, and published offline reload Prior non-MIDI pass, 2026-08-02; rerun required
Chrome stable Primary laptop Pending physical FP-10 audio and latency check Pending Pending install check Manual pass required
Edge stable Desktop Pending Pending Pending install check Manual pass required
Firefox 153.0.1 Linux (archie) FP-10 enumeration, permission flow, piano-sample audio, and a physical C8 note-on passed; full endpoint/shortcut pass pending Pending Pending offline check Physical MIDI smoke pass, 2026-09-11
Safari stable macOS No test device selected No test device selected No test device selected Access decision required

Manual pass

Use one supported MusicXML fixture and one malformed file.

  1. Connect and power on the MIDI piano, load the page over HTTPS or localhost, and grant MIDI permission. In Firefox, select Remember this decision to enable automatic reconnection on later visits. Confirm the Audio panel names both the MIDI input and output and Enable audio can recover after a blocked or failed attempt.
  2. Play the A0 and C8 endpoints, then hold a chord and release each piano key. Switch views with V, resize the window, and confirm pitch, velocity response, highlighting, and release behavior without stuck notes.
  3. Confirm A W S E D F R J U K I L ;, Z/X, and 1–8 do not play or remap notes. Use Tab, Enter, Space, Escape, Page Up/Down, and the arrow keys for their browser-native behavior. Type in the file input and notation-focus selector without triggering piano commands.
  4. Load the supported score. Use the buttons and [/] to navigate. Enable Edit fingering, select notes by canvas and by the note list, assign and remove fingerings, then use Regenerate all fingerings and confirm that every number is replaced while hand assignments remain unchanged. Play and restart the score with P.
  5. Start practice with T, play it from the MIDI piano, abort with C, retry, and hide the tab during a second run. The hidden run must abort and release audio.
  6. Play a random measure with M. Return to the loaded score and play it again.
  7. Close the tab after the online load, go offline, reopen the installed or cached PWA, and confirm the shell starts. MusicXML fixtures must still come from user file selection.

Record console errors, audible glitches, stuck notes, focus loss, and controls without a visible focus ring as failures.

Imported-score paired grand staff

Use a score with at least 16 measures, preferably the local Humpty-Dumpty.mxl fixture when available. Also select a range of five measures or fewer and a range whose last page is partial. Do not add local MusicXML fixtures to source control.

Scenario Action Expected result Result
Initial preload Load the long score while the grand staff is visible. The upper row shows measures 1–5 and is labeled Current. The lower row shows measures 6–10 and is labeled Look ahead. Pass — Chromium 149, 2026-08-02
Upper-to-lower handoff Start playback or Practice and cross the measure 5/6 boundary. The cursor appears on the lower row only. The upper row is then recycled to measures 11–15 without an audible restart. Visual/continuity pass — Chromium 149, 2026-08-02; physical audio pending
Lower-to-upper handoff Continue across the measure 10/11 boundary. The cursor appears on the preloaded upper row only. The lower row is then recycled to measures 16–20, or the available partial page. Pass — Chromium 149, 2026-08-02
Final partial page Let playback or Practice finish on a partial final page. The final page stays visible and labeled Current; the immediately previous page remains in the inactive row. Pass — Chromium 149, 2026-08-02
Short selected range Select five measures or fewer. One labeled grand-staff row is visible. No empty or duplicate second row appears. Pass — Chromium 149, 2026-08-02
Manual navigation While idle, use Previous/Next and [/]. Repeat while playback and Practice are active. Idle navigation advances one logical five-measure page and updates Current. Navigation is disabled and ignored while either following mode is active. Pass — Chromium 149, 2026-08-02
Restart and range reset Browse away from the first page, then use Play / restart. Change the selected measure range. Both actions return to the selected range's first current/look-ahead pair. Pass — Chromium 149, 2026-08-02
Practice overlays During Practice, hold notes and cross two page boundaries. Verdict colors persist after recycling. The cursor and held-note indicators appear only on their owning row. Pass — Chromium 149, 2026-08-02
View toggle During playback and Practice, switch staff → piano roll → staff. Unload and reload the score afterward. The paired rows return with the correct pages and cursors. The console shows no stale-element, interop, resize-observer, or disposal errors. Pass — Chromium 149, 2026-08-02
Responsive widths Repeat initial load and both handoffs at 1440, 1024, 768, and 320 CSS pixels. Clefs, signatures, notes, ledgers, ties, barlines, labels, and cursor remain legible without an internal score scroller. At 320 px, horizontal document scrolling preserves the score's minimum readable width. Pass — Chromium 149, 2026-08-02
Fingering selection Enable Edit fingering and select notes in both rows by canvas and by the note list. Include two members of the same chord. The selected note has a visible ring, the editor identifies its measure, beat, pitch, and hand, and each chord member selects independently. Pending
Fingering edit Assign 1–5 to notes with and without imported fingerings, switch selected notes between Right hand and Left hand, change an existing fingering, then remove one. The grand-staff label and selected hand update immediately. Replacing an imported number retains its established placement behavior, and no sibling note changes. Headless Chrome 149 right-to-left hand edit pass, 2026-09-14; number/removal manual checks pending
Fingering edit state While editing, navigate pages and change the selected measure range and meter. Then start playback and Practice. Completed edits remain. Navigation, range, or meter changes clear stale selection; playback and Practice leave edit mode and cannot modify notes. Pending
Fingering generation Set deliberately incorrect finger numbers on notes assigned to both hands, then select Regenerate all fingerings. Cancel once and confirm once. Cancel leaves every number unchanged. Confirm replaces all finger numbers, keeps every hand assignment, displays all generated labels, and reports that Save changes is required for a saved score. Confirmed action/status and no console errors pass — headless Firefox 153.0.1, 2026-09-14; cancel and visual hand checks pending
Fingering save round-trip Edit an imported score and use Save score. Edit a loaded library score and use Save changes, then reload each entry. Assigned hands plus assigned, changed, and removed fingerings match the saved state after reload. Headless Chrome 149 number and hand save/update/reload pass, 2026-09-14; manual removal check pending
Saved-score deletion Delete a non-current entry and cancel once, then confirm. Repeat for the currently open entry. Cancel preserves the row. Confirm removes it from the list and database. Deleting the open entry keeps the score open and changes Save changes to Save score. Headless Chrome 149 cancel, non-current, and current-entry pass, 2026-09-14

Free Play measure-boundary ties

Run these checks on the live grand staff. Record the browser, viewport, sound source, time signature, and result for each row.

Scenario Action Expected result Result
Internal barline In 4/4, press a note on the final beat of a measure and hold it into the next measure. Two noteheads appear inside their measures with one tie between them. The sound continues without a second attack. Notation pass — headless Firefox 157 and Chromium 153, 1400 px, 120 BPM 4/4, 2026-10-06 (mock MIDI notes pressed at a controlled audio-clock phase: a 300 ms note across a barline shows two heads and a tie, the same note mid-measure shows one head; one audio-node start and one stop per press, no listening). A short first press that happens to land on a barline therefore shows two heads — it is this tie, not a duplicate note. Physical keyboard and by-ear check pending
Five-measure rollover Hold a note across the boundary after the fifth visible measure. The next view starts with a continuation head and incoming tie stub inside the score area. No note element enters the clef or signature strip. Pending
Exact boundary release Release a note as the cursor reaches a barline. The finished measure contains one notehead. No empty continuation head or extra tie appears. Pending
Accidental Hold a sharp or flat pitch across a barline. The accidental appears at the attack and does not repeat on continuation heads. Pending
Chord Hold two or more pitches across a barline, then release their keys separately. Each pitch receives its own fragments and ties. Each sound stops once on its key release. Pending
Time signature Repeat the internal and rollover checks in 3/4. Fragment boundaries follow the 3-beat measures, and playback remains continuous. Pending
Sound source Repeat an internal crossing with piano, then synth. Both sources sustain through the barline without a new attack. Pending
Responsive layout Repeat an internal crossing in a narrow viewport and a wide viewport. Ties stay clipped to the score and keep the same staff-relative curve and stroke proportions. Pending
Piano roll Switch to the piano roll while holding a note across a grand-staff barline. The performance still appears as one continuous piano-roll bar. Pending

Free Play paired grand staff

Run these checks on the live grand staff with audio enabled and no score or exercise loaded. Record the browser, viewport, tempo, and result for each row.

Scenario Action Expected result Result
Initial layout Open the page and compare it with a loaded exercise at the same width. Two stacked grand staves are shown, each as tall as an exercise row (15–19 rem). The cursor is on the upper one. Pass — headless Firefox 153, 1400 px, 2026-10-06; also Firefox 157 and headless Chromium 153 (Chrome for Testing 153.0.8010.12), 1400 px (304 px rows) and 390 px (240 px rows), 2026-10-06
Row handoff Play notes in the first five measures, then cross the measure 5/6 boundary and play more. The cursor moves to the lower row only. The upper row keeps its notes. Pass — headless Firefox 153, 1400 px, 2026-10-06 (key events, no sound check); also Firefox 157 and Chromium 153, 1400 px and 390 px, 2026-10-06 (mock MIDI; cursor sequence upper → lower → upper → lower over 28 s at 150 BPM, never on both rows, x increasing within each row)
Wrap Continue across the measure 10/11 boundary. The cursor returns to the upper row, which is cleared for measures 11–15. The lower row keeps the notes of measures 6–10. Pass — headless Firefox 153, 1400 px, 2026-10-06 (key events, no sound check); also Firefox 157 and Chromium 153, 1400 px and 390 px, 2026-10-06 (mock MIDI, no sound check)
Held note across rows Hold a note across the measure 5/6 boundary, then release it. The upper row ends the note with a tie to its right edge. The lower row continues it from its left edge as the live trail, which closes on release. Pass — headless Firefox 153, 1400 px, 2026-10-06 (key events, no sound check); also Firefox 157 and Chromium 153, 1400 px and 390 px, 2026-10-06 (mock MIDI; one audio-node start and one stop for the held note, no listening)
Shared octave fit Play a very low and a very high note in different rows, or change the keyboard octave. Both staves keep the same size and vertical position. They are drawn at the staff size of an exercise row (about 9.9 px per staff space in a 19 rem row) and shrink only when the played notes and the keyboard octave do not fit at that size. No note, ledger line, or accidental is clipped. Pass — headless Firefox 153, 1400 px (19 rem rows) and 1000 px (15 rem rows), 2026-10-06 (mock MIDI input and the octave selector, no sound check; staff size compared with an exercise row in the same session); also Firefox 157 and Chromium 153, 1400 px and 390 px, 2026-10-06 (mock MIDI; staff spaces measured by pixel-scanning the canvas bitmap: octaves 1–6 empty 9.85–9.90 px at 304 px rows and 7.52–7.54 px at 240 px rows against 9.90 and 7.52 for an exercise row in the same session, octave 7 and 8 shrink to 8.8 and 7.8 px (304) / 6.7 and 5.9 px (240), A0 + C8 chords 7.13 px (304) / 5.38 px (240), at octave 8 6.42 / 4.9; both rows identical in size and position at every step; at least 27 px of clear canvas above and below the ink; Firefox and Chromium bitmaps differ in under 0.6 % of pixels, only around glyph edges)
Octave controls Open Play & MIDI tools. Use Down, Up and the Octave select, the arrow keys with the select focused, and the digits 1–8 on the play surface. Change the octave while the cursor is on the lower row. The summary, status, both canvas labels and both staves follow the octave. Down is disabled at 1 and Up at 8. Digit keys do nothing on the play surface (only a focused select reacts, by its native type-ahead). Returning to the previous octave redraws the previous picture exactly, no stale or ghost notes remain, and the cursor keeps moving and wraps. Pass — Firefox 157 and Chromium 153, 1400 px, 2026-10-06 (mock MIDI; real pointer clicks on the buttons, change events on the select, real arrow and digit key events; with notes in both rows, octave 4 → 1 → 8 → 7 → 6 → 4 redraws at 9.87, 9.92, 7.04, 7.87, 9.00, 9.87 px and returns to a byte-identical picture in both rows; with extreme notes in both rows 4 → 5 → 4 and 4 → 8 → 4 are byte-identical too; no sound check)
Responsive layout Repeat the initial layout at 390 px. Both rows keep a 40 rem minimum width inside a horizontal scroller, as in the imported-score view. Pass — headless Firefox 157 and Chromium 153, 390 px, 2026-10-06 (both rows are 640 × 240 px inside the one .piano-canvas-stack-score scroller, scrollWidth 640 against clientWidth 335, document width 390, no page-level overflow; staff space matches an exercise row; the held-note and wrap flows also pass at this width); earlier layout pass — headless Firefox 153, 390 px, 2026-10-06
Piano roll Switch to the piano roll and back. The second row disappears with the piano roll and returns with its cursor. Pass — Firefox 157 and Chromium 153, 1400 px and 390 px, 2026-10-06 (mock MIDI; ten staff → roll → staff cycles by the button and by V, a note held through the toggle, a toggle while the cursor was on the lower row, and 12 rapid toggles: the lower row is hidden in the roll and returns at its full size with exactly one cursor on the correct row; row bitmaps before and after are byte-identical; two canvases, two cursor elements, four observed elements and one animation loop (60 frames per second) after every cycle; the held note had one audio start and one stop; no console errors)

USB MIDI lifecycle

Use the Roland FP-10 through its USB COMPUTER port.

Scenario Action Expected result Result
Initial permission Open the app on localhost or HTTPS and allow MIDI access. The Audio panel reports Roland Digital Piano; playing a key starts audio and highlights the matching full-piano key. Firefox 153.0.1 physical pass with C8, 2026-09-11
Authorized reload Reload the page after granting MIDI permission. The existing Roland input reconnects without another in-page action. Firefox 153.0.1 physical pass, 2026-09-11
Velocity Play the same key softly and firmly using the PC piano sound source. Both attacks register and the selected sample layer follows the MIDI velocity. Pending
FP-10 sound Select FP-10, play physical keys, then use Play test note and score playback. Physical keys sound once through the piano; generated notes use the FP-10's selected tone and speakers. The MIDI output summary names Roland rather than Midi Through. Automated routing pass; physical audio pending, 2026-09-12
Note-off forms Play and release notes normally. Explicit note-off and zero-velocity note-on messages both release without sticking. Automated pass, 2026-09-11
Hot disconnect Hold a chord and unplug the USB cable. Reconnect it afterward. Held app notes release, status changes to no input, and the reconnected piano is detected without a page reload. Pending
Computer note keys removed Press the former note and octave shortcuts. No note sounds and the notation focus does not change; remaining command shortcuts continue to work. Automated pass, 2026-09-11
Quick tap on an unloaded velocity layer After Enable audio, play a note whose velocity layer has not been used yet (firm, 96 or more, or soft, under 64; the default layer loads with Enable audio) and release it within 150 ms. Repeat after a sustain-pedal press (the app ignores controller messages), as note on, off, on again, and with a note on that is repeated while the first is still loading. The tap sounds as a short note with its normal release and stops on its own: one audio-node start and one stop per press, and the sample never keeps ringing after the key is released. A second press is never cut by the first press's release. Pass — headless Firefox 157 and Chromium 153 (Chrome for Testing 153.0.8010.12), 2026-10-06 (mock MIDI velocity 100 on a fresh page each time, released after 50, 100, 150, 300 and 700 ms: one start and one stop each and every source ended; pedal press, on/off/on and the repeated note on also pass, the app drops the repeated note on; 88-key piano taps after the click also start and stop once; before the fix the 50–150 ms holds had one start, no stop and the source was still playing 3 s later; no listening, the audible result is pending a physical check)
Audio at page load Open the page in a fresh profile without touching it, then select Enable audio. Repeat in a browser that permits audio without a gesture. Nothing creates or resumes an audio context before the click: no AudioContext was not allowed to start console warning in Chromium, the status asks to select Enable audio, and the click gives a running context. Where the browser permits it (Firefox with the site allowed to autoplay, Chromium after the page has had a user gesture, also on reload) audio is enabled at load. Pass — headless Firefox 157 and Chromium 153, 2026-10-06 (fresh profile: no context created before the click, no warning in either browser, click gives running, mock MIDI and 88-key piano taps are ignored before it and work after; Firefox with media.autoplay.default 0 and Chromium after a click and a reload both enabled audio at load with no click and no warning; before the fix Chromium logged the warning on every load). Chromium started with --autoplay-policy=no-user-gesture-required also needs the click now, because Chromium has no way to report that setting; an installed PWA and an enterprise autoplay policy are unverified
Updated script after a code change Load the app from the server, change a js/*.js module that the app code calls (for example add an export), restart the server with the new build, and reload the tab normally (not a hard reload). Also open the app in a browser that loaded it before the server sent Cache-Control: no-cache for its own files. The reload runs the changed module: the network log shows a conditional request for it (304 when unchanged), the page shows no The value '...' is not a function error, and the app's own files (/js, /css, index.html, manifest) carry Cache-Control: no-cache while /_framework keeps its own and /audio samples carry none. A browser that already holds an older copy stored without the header keeps it until it expires (hours to days), so open /js/audio.js once and press F5, or clear the site's cached files. Pass — headless Firefox 157 and Chromium 153 (Chrome for Testing 153.0.8010.12), 2026-10-06, fresh profile each, through a reverse proxy that serves an old audio.js with a 30-day-old Last-Modified: without the header both browsers kept the old module through a reload and a new navigation with no request to the server; with it the reload sent If-None-Match and got the new file, later loads got 304. A browser that had loaded the app before the header kept the stale module after the server was upgraded, and recovered after opening /js/audio.js and pressing F5 (Firefox, Chromium). Chromium's hard reload (Page.reload with ignoreCache) did not evict it. Firefox's hard reload and the physical-keyboard app on the user's own make run browser are pending

Note-reading exercise

Covers the generated note-reading exercise panel: transitions, review, every input source, local-storage history, the reading and rhythm presets, both pacings, timing aids, mistake review, adaptation, and the guided path. Automated coverage already exists for the underlying logic (composer, coordinator, session, mapper, input adapters — see PianoMapper.Tests); the rows below are the browser-only behaviors that logic can't verify by itself.

Status wording: Mocked-MIDI pass means the scenario was run on 2026-10-02 in headless Firefox (the implementer's scripts press keys through a fake Web MIDI input and read the real page, audio clock, and canvas), so the real page and grading were exercised but not the physical keyboard, the speakers, or a person's timing. Pixel pass means the canvas was screenshotted at the smallest clamped height (1000 px viewport, 240 px canvas). A row is marked passed only for what was actually run; everything that needs the physical MIDI keyboard or listening stays Pending.

Scenario Action Expected result Result
Clean Generate/Retry/End transitions Generate an exercise, retry it, retry only the missed notes after completing it, then end it. Repeat starting a new exercise mid-review without ending first. Each transition clears prior progress/mistakes as appropriate, never leaves a stuck note from the previous exercise, and the panel's buttons enable/disable correctly (Retry only while active, Retry missed only when review has misses, End only while active). Pending
Hidden until review, revealed on review Play through an exercise, including at least one wrong attempt on a prompt. Note names and fingerings stay hidden while the exercise is active. Once complete, the summary shows first-try accuracy and the mistake counts, a Mistakes to look at list names each mistake, and the note names and fingerings are revealed. Mocked-MIDI pass (summary, list, and hidden-while-active) — physical keyboard pending
Input source: MIDI Complete an exercise using only the connected MIDI piano. Every prompt grades correctly; no stuck notes after completion. Pending
Input source: on-screen piano Complete an exercise using only pointer/mouse clicks (and, on a touch device, touch) on the on-screen 88-key piano. Every prompt grades correctly; no stuck notes; multitouch on a touch device can hold a chord prompt. Pending
Input source: computer keyboard Enable the computer-key toggle and complete an exercise using only the keyboard. Every prompt grades correctly; no stuck notes; releasing focus mid-hold (switch tabs, then return) does not leave a key permanently unresponsive. Pending
Local-storage history failure Block or fill local storage (e.g. via browser dev tools), then complete an exercise. The exercise still completes and grades normally; the app does not crash; history/mastery-based weighting silently falls back to the balanced generator instead of erroring. Pending
Representative presets Generate one exercise each for five-note, ledger-lines, G major (key signature), and chords, on both treble and bass staff, and once with the grand-staff option on. Each preset's notation matches its documented range/key/chord content; grand staff alternates hands correctly. Pending
4/4 basic rhythm Generate an exercise with the Basic rhythm preset. The count-in plays for one full 4/4 measure before grading starts; note values (quarter/half/eighth pairs) render and grade correctly against tempo-relative timing. Pending
6/8 compound rhythm Generate an exercise with the Compound rhythm preset. The count-in plays for one full 6/8 measure; dotted-quarter/eighth-triplet groupings render and grade correctly. Pending
Adaptive generation Deliberately miss the same pitch repeatedly across a few completed exercises, then generate a new one. The new exercise's prompts noticeably favor the repeatedly-missed pitch more than a fresh/neutral history would, while every pitch in the preset's palette still appears. Pending
Mode ladder and tempo Pick Rhythm only, then Pitch + rhythm at 60 and at 90 pulses per minute; check the Timing card while the exercise runs. The count-in lasts one measure at the chosen tempo (about 4.0 s at 60, 2.7 s at 90 in 4/4), the Timing card mirrors the exercise tempo and meter with its inputs disabled, and they are restored when the exercise ends. Mocked-MIDI pass (count-in measured 3.96 s and 2.64 s) — physical keyboard pending
Click, beat indicator, and live feedback In a timed mode with Keep the click going while playing on, play along to the click; then try End, Generate, a hidden tab, and the setting off. The click runs through the whole exercise and stops at review, End, Generate, and focus loss; both beat indicators pulse together; the chip shows "N ms early/late · median …". Mocked-MIDI pass (click observed through the metronome button state, the DOM, and hooked oscillator nodes; no human listening) — by-ear check and physical keyboard pending
Timed-click ownership During a timed count-in and active run, try the central metronome button and Keep the click going while playing; then repeat after review. Timed runs keep their original audio-clock anchor; their click controls are unavailable until review/end, while pitch-only runs retain manual-click access. Automated .NET policy and coordinator tests pass — browser and by-ear check pending
6/8 accents Start the metronome or a 6/8 exercise click and listen. The click counts ONE two three TWO two three. Hooked oscillator frequencies pass (1760, 1320, 1320, 1540, 1320, 1320 Hz) — by-ear check pending
Score playback with click Select Play with click, start/restart a 4/4 and 6/8 score, then stop it and repeat with the option off. With the option on, score and click share one future audio-clock anchor; with it off, no prior manual click remains. Stop, restart, and completion release the click. Automated explicit-anchor and ownership tests pass — browser and by-ear check pending
Manual meter options In 5/8 and 7/8, select each offered grouping and start the manual click; also try Soft/Bright and Quiet/Medium/Full. Group starts are accented exactly as selected, sound controls affect the next manual grid, and the beat text resets within each group. Core, .NET interop, and hooked-oscillator tests pass — browser and by-ear check pending
Rhythm only Tap a Basic rhythm on arbitrary keys. Only onset verdicts are given; any key matches; the summary reports timing, not pitch. Mocked-MIDI pass (one key, one late note reported) — physical keyboard pending
Wait for me versus Play along Complete one run in each pacing, deliberately skipping a note in Play along; abort another with Generate, End, and a hidden tab. Play along counts in, moves a cursor, grades the skipped note Missed and continues, and shows the verdict counts; Wait for me is unchanged. History gains exactly one entry per finished run and none for an aborted one. Mocked-MIDI pass — physical keyboard pending
Pitch and timing reported apart Play a Pitch + rhythm exercise with a right key played late. First-try accuracy drops while the pitch count stays whole ("pitch 8 of 8 first-try · 2 timing mistake(s)"). Mocked-MIDI pass
Coach hints With Coach hints off, miss the same prompt five times; then turn it on and miss it twice and four times. Off: the status text never changes. On: a direction hint after two wrong keys and the note name after four, in Wait for me only; no key is lit. Mocked-MIDI pass
Retry missed in a timed mode Miss a note in measure 2 of a rhythm exercise and choose Retry missed notes. The whole measure comes back with its rhythm (and any tie only if its other measure is replayed). Mocked-MIDI pass for a Fixed rhythm (whole measure replayed); Basic, tie, and rest cases covered by automated tests
History upgrade Seed browser history with sessions written by the first schema, then complete new exercises. The old sessions still list (marked "older session") and new sessions are appended; nothing is lost. Mocked-MIDI pass in a throwaway Firefox profile
Progress, drill, and guided path After several sessions with deliberate errors, open Progress; use Drill my weak notes; clear history and use Start recommended exercise three times with perfect play. Weak spots and habits reflect the errors and the drill uses only the weak notes of the range; with no history Level 1 is the next step, and after three clean runs Level 2 is. Mocked-MIDI pass — whether the recommendation feels right for a real beginner is Pending
Hands together Tick Grand staff and Hands together with the five-note range and play both hands on each prompt. Both staves show one note per prompt, the two keys light together with next-key hints, and the prompt completes when both are played. Pixel pass and mocked-MIDI pass (8 of 8) — physical keyboard pending
Pattern select Choose Melodic and Same interval (Thirds) and generate. Melodic shows steps with repeats and the occasional skip; Same interval moves by the chosen interval every time; the select is disabled for chords, ledger lines, accidentals, and rhythm only. Pixel pass for the UI and two exercises; playing them Pending
New keys and accidentals Generate D major, B♭ major, A minor, and Accidentals on treble and bass. Key signatures sit on both staves, notes carry no redundant accidentals, accidentals clear the barline and the previous note, and a letter altered earlier in a measure is never shown plain later in it. Pixel pass (all three keys on both staves; accidentals on treble, 6 exercises) — playing them and accidentals on bass Pending
Chord inversions Generate Chords on treble and bass with 16 notes. Nine voicings (three inversions each of I, IV, and V) appear, drawn as stacked thirds. Pixel pass — playing them Pending
Extended, 3/4, 2/4, 6/8 patterns Generate each rhythm preset in Pitch + rhythm. Dotted notes show their dot clear of the stem, whole notes are open without a stem, rests and flagged or beamed eighths draw, and the time signature reads 3/4 or 2/4. Pixel pass — timing them with the physical keyboard Pending
Syncopated ties Generate Syncopated 4/4, including with 3 measures per page. A tie joins each tied pair inside a measure and across a barline; a pair is one key press; a tie that leaves the page is a half tie. Pixel pass and a mocked-MIDI Pitch-only run (10 of 10); pixel pass again on 2026-10-03 after ties were made at least 1.2 px thick at the 240 px canvas and a tie arriving at the start of a row was given room (it was not drawn before) — the by-hand rhythm run on the physical keyboard is Pending
Review marks, Wait for me Complete Pitch only (with wrong keys), then Pitch + rhythm (Fixed, with notes played late and early and some wrong keys); repeat with Chords, bass Ledger lines, a grand staff, and Hands together. Look at the staff before and after the last prompt. While the exercise is active no ring is drawn, even after wrong keys. In review each prompt that was not first-try clean has a halo, matching the Mistakes to look at list: a thicker solid red ring where a wrong key was played, a solid orange ring for early or late, no ring for a clean note; a chord has one ring around the whole stack and a hands-together prompt one ring per hand. Mocked-MIDI pass and pixel pass on 2026-10-02 for every case named (marks counted against the list each time) — physical keyboard pending
Review marks, Play along Complete a Basic 4/4 play-along (beamed eighths and a quarter rest) deliberately playing some notes late, some wrong, and skipping some; repeat with Accidentals and Syncopated 4/4. The skipped notes carry a dashed grey ring, late notes an orange ring, wrong keys a red ring, clean notes none, and the rings match the Mistakes to look at list and the run's verdict counts. Mocked-MIDI pass and pixel pass on 2026-10-02 (Basic with a rest and beamed pairs, bass Basic, Accidentals + Syncopated with ties) — physical keyboard pending
Review marks clear of the notation Look at review marks at the smallest clamped height on single notes, a beamed eighth pair, a chord, ledger lines, a measure beside a rest, and an exercise with ties and accidentals. No ring crosses the annotation strip or cuts into a notehead; a ring wraps its own accidental; a stem is drawn over its own ring; the tie, rest and neighbouring heads, stems and beams are not drawn over. Two adjacent marked eighth notes may touch at this width. Pixel pass on 2026-10-02 at the 240 px canvas (1000 px viewport) for every case named, plus a scripted check of 23 generated scenes — a ring beside a barline (the last note of a measure, or a measure-leading accidental) can touch it, and the first pixels of a tie meet the ring beside it; wider windows leave more room
Review marks only for exercises Load an imported score; between two runs of an exercise use Retry; generate a new exercise. An imported score never shows a ring; Retry and Generate start without the previous run's rings. Observed on 2026-10-02 (imported scores in the before/after renderer check; Retry between the two passes of each play-along run) — changing the Mode or Pacing select while a review is showing leaves the displayed exercise, its rings and its verdict colors as they were (fixed 2026-10-03; the selects only choose what the next Generate, Retry or Retry missed uses)
Review marks read at a glance On the physical keyboard, finish a mixed exercise and say which notes were pitch, timing, and missed mistakes from the rings alone, with the browser piano sound and the FP-10's own sound. Orange, red and dashed grey rings are told apart without reading the list. Pending — needs a person and the physical keyboard
Long exercises Choose 32 and 64 notes (Pitch only, fixed quarter notes), generate, and play to the end with the MIDI keyboard. Both rows keep showing the current page and the page after it; the rows turn over at measures 6, 11 and 16 as the cursor reaches them; the exercise completes after the last note and is saved to history once. Mocked-MIDI pass on 2026-10-03 (64 notes, 16 measures, 100%) — physical keyboard pending
Review paging After a 64-note exercise, use Previous measures and Next measures (and [ and ]). The buttons appear only for an exercise of more than two pages, are disabled at the first and last page, and bring the earlier measures and their review marks on screen. The two rows alternate by page parity, so one step near the last page leaves the same two rows on screen, as in a loaded score. Mocked-MIDI pass on 2026-10-03 for the buttons (shortcut keys Pending)
Start the next exercise automatically Leave the setting at its default (ticked); finish a Wait for me and a Play along run; let the countdown run out; also try Stay here, paging in review, switching tabs during the countdown, and a Play along run without playing. Next exercise in N s counts down from 10 and the next exercise starts with the current settings (a Play along run starts its count-in); Stay here and leaving the window cancel it; paging restarts it; a run with nothing played shows no countdown; the setting is on by default and unticking it removes the countdown. Mocked-MIDI pass on 2026-10-03 (Wait for me, Play along, Stay here, paging, simulated focus loss, an unplayed Play along run) — physical keyboard pending
Timing-offset measurement On the physical keyboard, tap along to 16 clicks and record the median deviation, with the browser piano sound and with the FP-10's own sound. Median deviation under 25 ms: no calibration is needed. Otherwise a calibration action is built (not built yet). Pending — needs the physical keyboard and speakers