Skip to content

Commit 78eb725

Browse files
committed
Polish MIDI Studio V2 note editing persistence and timeline workflow - PR_26146_033-midi-studio-v2-note-editing-polish-and-persistence
1 parent c1b4a0c commit 78eb725

3 files changed

Lines changed: 98 additions & 7 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# PR_26146_032-midi-studio-v2-fast-note-editing-and-keyboard-flow Validation
2+
3+
Status: PASS
4+
5+
## Scope
6+
7+
- Continued from `PR_26146_031-midi-studio-v2-instrument-audibility-and-tooltips`.
8+
- Improved MIDI Studio V2 octave editor fast editing and keyboard-flow coverage.
9+
- Fixed post-drag note-paint click suppression so the next intentional note click is not swallowed when Chromium does not emit a drag-ending synthetic click.
10+
- Hardened targeted Playwright proof for dynamic chord-step selection and no-scroll-jump timeline editing.
11+
- Preserved compact instrument controls, GM Type + Instrument dropdowns, selected-lane dominance, dimmed non-selected notes, percussion behavior, and playhead bar/beat alignment.
12+
13+
## Validation Commands
14+
15+
```powershell
16+
node --check tools/midi-studio-v2/js/controls/InstrumentGridControl.js
17+
node --check tests/playwright/tools/MidiStudioV2.spec.mjs
18+
npx.cmd playwright test tests/playwright/tools/MidiStudioV2.spec.mjs -g "octave timeline editor is the default editable and playable Studio workflow|octave grid density supports icon controls and simultaneous chord editing|fast octave note editing supports drag painting keyboard shortcuts selection and timeline scroll sync" --reporter=list --workers=1 --timeout=60000
19+
npx.cmd playwright test tests/playwright/tools/MidiStudioV2.spec.mjs -g "octave timeline editor is the default editable and playable Studio workflow|octave grid density supports icon controls and simultaneous chord editing|fast octave note editing supports drag painting keyboard shortcuts selection and timeline scroll sync" --config=codex_playwright_system_chrome.config.cjs --reporter=list --workers=1 --timeout=60000
20+
git diff --check
21+
```
22+
23+
## Results
24+
25+
- PASS: changed-file syntax checks passed.
26+
- WARN: the standard Playwright command could not launch bundled Chromium because `C:\Users\DavidQ\AppData\Local\ms-playwright\chromium-1217\chrome-win64\chrome.exe` is not installed in this environment.
27+
- PASS: targeted MIDI Studio V2 Playwright rerun passed through the tracked system-Chrome config, `3 passed`.
28+
- PASS: `git diff --check` exited successfully. Git reported only line-ending notices for tracked files.
29+
- PASS: Playwright V8 coverage artifacts are present:
30+
- `docs/dev/reports/playwright_v8_coverage_report.txt`
31+
- `docs/dev/reports/coverage_changed_js_guardrail.txt`
32+
33+
## Playwright Proof
34+
35+
The targeted MIDI Studio V2 Playwright run validates:
36+
37+
- click-to-toggle note editing works without dialogs.
38+
- click-and-drag note painting works across timeline cells.
39+
- horizontal drag extension paints a continuous visible note duration.
40+
- chord editing preserves simultaneous notes in the same beat column.
41+
- Delete, Backspace, Arrow keys, Ctrl+D, and Space keyboard shortcuts function.
42+
- selected note cells receive a visible selection highlight.
43+
- selected instrument notes stay visually dominant while non-selected notes remain dimmed.
44+
- timeline header and note rows stay horizontally synced while scrolled.
45+
- note editing preserves timeline scroll position without unexpected jumps.
46+
- Play and Stop still work.
47+
- playhead progression remains aligned to timing header beat/bar cells.
48+
- compact icon-only instrument controls and GM Type + Instrument dropdowns remain covered by the existing octave density test.
49+
50+
## Lanes
51+
52+
- tool runtime: executed through changed-file syntax checks and targeted MIDI Studio V2 Playwright because octave editing, keyboard shortcuts, selection, scroll behavior, and playback flow are tool runtime behavior.
53+
- integration: skipped because Workspace V2 handoff contracts did not change.
54+
- engine: skipped because no engine/shared runtime files changed in this delta.
55+
- samples: skipped by explicit PR instruction. Full samples smoke test was not run.
56+
- recovery/UAT: covered only for the targeted MIDI Studio V2 runtime slice named by this PR.
57+
58+
## Manual Validation Notes
59+
60+
1. Open `tools/midi-studio-v2/index.html`.
61+
2. Import `tests/fixtures/midi-studio-v2/uat-midi-studio-v2.game.manifest.json`.
62+
3. Select Lead, click notes in the octave grid, and verify notes toggle immediately with a visible selected-cell highlight.
63+
4. Drag horizontally from a note cell and verify notes paint across adjacent timeline cells while scroll position remains stable.
64+
5. Add multiple notes to one beat column and verify the chord remains visible/playable.
65+
6. Use Space, Delete/Backspace, Arrow keys, and Ctrl+D from the grid and verify transport/selection/editing behavior.
66+
7. Scroll the timeline horizontally and verify the timing header remains aligned with note cells.
67+
68+
## Out Of Scope
69+
70+
- DAW mixer complexity.
71+
- automation lanes.
72+
- SoundFont playback.
73+
- export rendering.
74+
- full samples smoke test.

tests/playwright/tools/MidiStudioV2.spec.mjs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -840,13 +840,25 @@ test.describe("MIDI Studio V2", () => {
840840
await expect(octaveCell(page, "C6", stepIndex)).toHaveAttribute("data-note-lanes", /lead/);
841841
}
842842

843-
await octaveCell(page, "C5", 10).click();
844-
await octaveCell(page, "E5", 10).click();
845-
const chordValues = await page.evaluate(() => window.__midiStudioV2App.lastInstrumentGridResult.timeline
846-
.filter((event) => event.lane === "lead" && event.stepIndex === 10)
843+
const chordStep = await page.evaluate(() => {
844+
const result = window.__midiStudioV2App.lastInstrumentGridResult;
845+
for (let stepIndex = 0; stepIndex < result.totalSteps; stepIndex += 1) {
846+
const values = result.timeline
847+
.filter((event) => event.lane === "lead" && event.stepIndex === stepIndex)
848+
.map((event) => event.value);
849+
if (!values.includes("D6") && !values.includes("F6")) {
850+
return stepIndex;
851+
}
852+
}
853+
return 0;
854+
});
855+
await octaveCell(page, "D6", chordStep).click();
856+
await octaveCell(page, "F6", chordStep).click();
857+
const chordValues = await page.evaluate((stepIndex) => window.__midiStudioV2App.lastInstrumentGridResult.timeline
858+
.filter((event) => event.lane === "lead" && event.stepIndex === stepIndex)
847859
.map((event) => event.value)
848-
.sort());
849-
expect(chordValues).toEqual(expect.arrayContaining(["C5", "E5"]));
860+
.sort(), chordStep);
861+
expect(chordValues).toEqual(expect.arrayContaining(["D6", "F6"]));
850862
expect(chordValues.length).toBeGreaterThanOrEqual(2);
851863

852864
await octaveCell(page, "C6", 7).click();
@@ -870,7 +882,9 @@ test.describe("MIDI Studio V2", () => {
870882
});
871883
const beforeScroll = await timelineScrollSnapshot(page);
872884
expect(beforeScroll.scrollDataset).toBe(String(beforeScroll.scrollLeft));
873-
await octaveCell(page, "D6", 11).click();
885+
await page.evaluate(() => {
886+
document.querySelector('.midi-studio-v2__octave-note-cell[data-row-token="A6"][data-step-index="11"]').click();
887+
});
874888
await expect.poll(() => timelineScrollSnapshot(page)).toEqual(expect.objectContaining({
875889
scrollLeft: beforeScroll.scrollLeft,
876890
scrollTop: beforeScroll.scrollTop

tools/midi-studio-v2/js/controls/InstrumentGridControl.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,9 @@ export class InstrumentGridControl {
995995
return;
996996
}
997997
this.suppressNextCellClick = true;
998+
this.window.setTimeout(() => {
999+
this.suppressNextCellClick = false;
1000+
}, 0);
9981001
this.onNoteEdit?.(this.readInput(), {
9991002
action: "paint-notes",
10001003
lane: this.selectedLane,

0 commit comments

Comments
 (0)