Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
2441 commits
Select commit Hold shift + click to select a range
4521cb2
Merge pull request #271 from stringsync/cursor
jaredjj3 Feb 23, 2025
c92d8ad
upgrade github pages action
jaredjj3 Feb 23, 2025
92d35f5
render double right stave connectors for measures with a repeat end b…
jaredjj3 Feb 23, 2025
0273b80
render boldDoubleRight vexml stave connectors when the endBarlineStyl…
jaredjj3 Feb 23, 2025
1871fa8
revert tmp change made to cursor spans
jaredjj3 Feb 23, 2025
5ae35c7
map the endBarlineStyle correctly for double and end barlines
jaredjj3 Feb 23, 2025
2131833
Merge pull request #272 from stringsync/staves
jaredjj3 Feb 23, 2025
11d09bc
fix eventmappingfactory.ts types
jaredjj3 Feb 23, 2025
56f611a
Release 0.1.3
jaredjj3 Feb 23, 2025
049b14a
upgrade vexflow to 5.0.0-beta.1
jaredjj3 Feb 25, 2025
2e5f3d0
Release 0.1.4
jaredjj3 Feb 25, 2025
a163685
update snapshots that changed upgrading to vexflow 5.0.0-beta.1
jaredjj3 Feb 25, 2025
0899b88
remove vexflow.KeySignature stave hack
jaredjj3 Feb 26, 2025
d55f622
delete legacy snapshots
jaredjj3 Feb 26, 2025
a10e3e9
Merge pull request #275 from stringsync/cleanup
jaredjj3 Feb 26, 2025
f953547
update vexflow to 5.0.0
jaredjj3 Mar 16, 2025
90bcdcb
add playback test suite
jaredjj3 Mar 17, 2025
ecdabd7
rename SequenceFactory LegacySequenceFactory
jaredjj3 Mar 17, 2025
e70993e
create SequenceFactory
jaredjj3 Mar 17, 2025
fec760c
add SequenceFactory test
jaredjj3 Mar 17, 2025
e1036dc
update test suite and impl something that pacifies the tests
jaredjj3 Mar 18, 2025
0c4aa9b
rename sequence to LegacySequence
jaredjj3 Mar 24, 2025
eee7547
fold SequenceFactory into Sequence and extend tests
jaredjj3 Mar 24, 2025
aaedf31
remove custom matcher
jaredjj3 Mar 24, 2025
658afdf
replace sequence with timeline concept
jaredjj3 Mar 30, 2025
3f3a01f
sort transitions to handle stop before start
jaredjj3 Mar 30, 2025
dc3c983
tweak timeline implementation and finish unit tests
jaredjj3 Mar 31, 2025
65a6621
create moment type
jaredjj3 Mar 31, 2025
d9fe841
group clusters of events as moments
jaredjj3 Apr 1, 2025
4568f2a
rename playback.Moment to playback.TimelineMoment
jaredjj3 Apr 1, 2025
f9c5bf4
create CursorFrame class
jaredjj3 Apr 1, 2025
da2444c
add hints to CursorFrame class
jaredjj3 Apr 2, 2025
f987c09
rename Cursor to LegacyCursor
jaredjj3 Apr 2, 2025
9c72134
move CursorFrame creation to cursorframe.ts
jaredjj3 Apr 3, 2025
01b557e
add measure and system data to TimelineMomentEvent types
jaredjj3 Apr 3, 2025
e72c72e
flesh out CursorFrameFactory
jaredjj3 Apr 3, 2025
7fca12e
scaffold cursor frame tests
jaredjj3 Apr 3, 2025
d90f1ec
finish rough cursorframe impl and unit test
jaredjj3 Apr 4, 2025
ac1dd6e
test CursorFrame creates for: single measure, single stave, same notes
jaredjj3 Apr 4, 2025
0503326
test CursorFrame creates for: single measure, multiple staves, differ…
jaredjj3 Apr 4, 2025
1a7afa3
test CursorFrame creates for: single measure, multiple staves, multip…
jaredjj3 Apr 4, 2025
d1ff47a
test CursorFrame creates for: multiple measures, single stave, differ…
jaredjj3 Apr 4, 2025
2f60818
test CursorFrame creates for: single measure, single stave, repeat
jaredjj3 Apr 4, 2025
2d094d0
test CursorFrame creates for: multiple measures, single stave, repeat…
jaredjj3 Apr 4, 2025
4a31994
test CursorFrame creates for: multiple measures, single stave, multip…
jaredjj3 Apr 4, 2025
8ef3fb8
create CursorFrameLocators
jaredjj3 Apr 4, 2025
0a94adf
implement new cursor API
jaredjj3 Apr 4, 2025
4d137f6
update README with new cursor API
jaredjj3 Apr 4, 2025
8d1d7fa
improve clarity on cursor internal indexes
jaredjj3 Apr 4, 2025
68bce8d
migrate to new cursor
jaredjj3 Apr 4, 2025
4c3b648
delete legacy cursor classes
jaredjj3 Apr 4, 2025
01457ff
fix issue with multiple repeat endings not excluding previous endings
jaredjj3 Apr 5, 2025
cefab47
simplify CursorFrame and add final test
jaredjj3 Apr 5, 2025
d452bdb
Merge pull request #277 from stringsync/playback
jaredjj3 Apr 5, 2025
58346f9
Release 0.1.5
jaredjj3 Apr 5, 2025
b5718fe
add playback backwards formatting test example
jaredjj3 Apr 9, 2025
689f058
group timeline moments to the nearest ms instead of nearest 100ms
jaredjj3 Apr 9, 2025
28e7933
improve CursorFrame method naming
jaredjj3 Apr 9, 2025
b2ac642
handle exceptional cases when a cursor frame would animate backwards
jaredjj3 Apr 9, 2025
29ecca1
test CursorFrame creates for documents that have backwards formatting
jaredjj3 Apr 9, 2025
fe4dd06
simplify multi system playback tests to reduce flakiness across platf…
jaredjj3 Apr 9, 2025
0beb0f9
Merge pull request #278 from stringsync/playback
jaredjj3 Apr 9, 2025
0f5d669
Release 0.1.6
jaredjj3 Apr 9, 2025
f044555
highlight that rendering a cursor component is optional
jaredjj3 Apr 9, 2025
63c31fb
rename CursorFrameHint to CursorStateHint and add StartHint and StopHint
jaredjj3 Apr 11, 2025
f889b3a
create CursorHintProvider interface, implement it, and add it to Curs…
jaredjj3 Apr 11, 2025
d786e52
introduce implementations of DefaultCursorFrame vs EmptyCursorFrame t…
jaredjj3 Apr 11, 2025
8477c92
rename Cursor.toIterator to Cursor.iterable
jaredjj3 Apr 11, 2025
752620f
test LazyCursorStateHintProvider, make playback tests more configurab…
jaredjj3 Apr 11, 2025
4e13f48
add failing test for chords
jaredjj3 Apr 11, 2025
60e48b8
make elements.Note return multiple pitches and surface the subtype
jaredjj3 Apr 11, 2025
23fcc61
Merge pull request #280 from stringsync/playback
jaredjj3 Apr 11, 2025
48180aa
Release 0.1.7
jaredjj3 Apr 11, 2025
eeea9b0
remove debug data from document
jaredjj3 Apr 11, 2025
bc6398b
rename MeasureSequenceIterator to LegacyMeasureSequenceIterator
jaredjj3 Apr 12, 2025
5d5c673
create ElementDescriber class
jaredjj3 Apr 14, 2025
d5e5d11
remove unused fragment
jaredjj3 Apr 14, 2025
bc39561
wire in ElementDescriber to CursorFrameDescriber
jaredjj3 Apr 14, 2025
d19d96f
standardize timeline descriptions
jaredjj3 Apr 14, 2025
f7d036c
create HintDescriber and use it to start testing LazyCursorStateHintP…
jaredjj3 May 1, 2025
ce328d9
test LazyCursorStateHintProvider provides for: single measure, multip…
jaredjj3 May 1, 2025
707aa95
test LazyCursorStateHintProvider provides for: multiple measures, sin…
jaredjj3 May 1, 2025
5511ac9
test LazyCursorStateHintProvider provides for: single measure, single…
jaredjj3 May 1, 2025
bdaea22
test LazyCursorStateHintProvider provides for: multiple measures, sin…
jaredjj3 May 1, 2025
665b198
test LazyCursorStateHintProvider provides for: multiple measures, sin…
jaredjj3 May 1, 2025
b42481c
test LazyCursorStateHintProvider provides for: documents that have ba…
jaredjj3 May 1, 2025
f20feed
test LazyCursorStateHintProvider provides for: chords
jaredjj3 May 1, 2025
346ab76
Merge pull request #283 from stringsync/hints
jaredjj3 May 1, 2025
5b2fa23
Release 0.1.8
jaredjj3 May 1, 2025
a3d0c72
add "Are you sure?" dialog to release script
jaredjj3 May 1, 2025
c5d2ba2
add CONTRIBUTING.md
jaredjj3 Dec 13, 2025
076210b
tweak CONTRIBUTING.md
jaredjj3 Dec 13, 2025
db7d59c
add mechanism to get timestamp from (x,y) position
jaredjj3 May 5, 2026
46e589f
Release 0.1.9
jaredjj3 May 5, 2026
888a62d
Release 0.1.10
jaredjj3 May 5, 2026
6c5f335
support rendering chord symbols as MusicXML harmony elements
jaredjj3 May 6, 2026
3423ac1
render chord name over accent element test
jaredjj3 May 6, 2026
ef78258
Release 0.1.11
jaredjj3 May 6, 2026
9a58aba
ensure the user is logged into npm before releasing
jaredjj3 May 6, 2026
77c4b5e
add support for fingerings as annotations
jaredjj3 May 9, 2026
0721f03
Merge pull request #289 from stringsync/fingerings
jaredjj3 May 9, 2026
5e7a4c9
avoid rounding errors when calculating timeline moments
jaredjj3 May 9, 2026
cc8866a
Merge pull request #290 from stringsync/jj
jaredjj3 May 9, 2026
0b56545
default empty first measure when fragmentizing
jaredjj3 May 9, 2026
5607a4d
Merge pull request #291 from stringsync/jj
jaredjj3 May 9, 2026
491eac4
Release 0.1.12
jaredjj3 May 9, 2026
5975f74
expose getCursorFrames to allow users to build complex interactions
jaredjj3 May 10, 2026
81de13c
remove CursorPath class
jaredjj3 May 10, 2026
fd42ea4
document the public score and cursor methods
jaredjj3 May 10, 2026
93671cd
Merge pull request #292 from stringsync/jj
jaredjj3 May 10, 2026
bbdbe3a
add commander to the project
jaredjj3 May 10, 2026
3c08c1d
create vex CLI
jaredjj3 May 10, 2026
9b9050b
ignore cli test from jest
jaredjj3 May 10, 2026
3c3ac89
refactor test command
jaredjj3 May 10, 2026
1094ae5
specify node 22.6.0 in github actions
jaredjj3 May 10, 2026
eea0493
upgrade canvas package
jaredjj3 May 10, 2026
3e7e5c6
specify --local flag for agents to run
jaredjj3 May 10, 2026
e16a0bc
remove unnecessary import file extensions
jaredjj3 May 10, 2026
decaab1
readd import file exteensions for Node's ESM resolver
jaredjj3 May 10, 2026
ee0087a
add explicit --ci option for tests
jaredjj3 May 10, 2026
4cd9f5c
Merge pull request #293 from stringsync/cli
jaredjj3 May 10, 2026
a096080
add failing MeasureSequenceIterator tests
jaredjj3 May 10, 2026
ba5315e
replace LegacyMeasureSequenceIterator with a more correct implementation
jaredjj3 May 10, 2026
1d33aa0
simplify MeasureSequenceIterator
jaredjj3 May 10, 2026
8aa720b
remove unnecessary comments
jaredjj3 May 10, 2026
bcca055
Merge pull request #294 from stringsync/jj
jaredjj3 May 10, 2026
12b9573
add continuation measures
jaredjj3 May 10, 2026
ded14de
add another part to continuation test and increase number of notes
jaredjj3 May 10, 2026
9714b1e
Merge pull request #295 from stringsync/jj
jaredjj3 May 10, 2026
bafc797
fix TypeScript compile issue
jaredjj3 May 10, 2026
d03190b
Release 0.2.0
jaredjj3 May 10, 2026
cde6c62
expose tab positions from note elements
jaredjj3 May 19, 2026
8ccc30b
Release 0.2.1
jaredjj3 May 19, 2026
5e8d994
add SHOW_TABS and SHOW_STANDARD_NOTATION config options
jaredjj3 May 20, 2026
0ea9b6e
return tab positions even if tabs are not rendered
jaredjj3 May 20, 2026
bef1ef5
Release 0.2.2
jaredjj3 May 20, 2026
8bcce61
return promise from scroller and account for interrupts
jaredjj3 May 21, 2026
9dbd585
Release 0.2.3
jaredjj3 May 22, 2026
690e5cb
migrate the internal parsing library to mdom
jaredjj3 Jun 22, 2026
6752456
Merge pull request #297 from stringsync/mdom
jaredjj3 Jun 22, 2026
659a170
start from scratch
jaredjj3 Jun 23, 2026
2f609c1
add basic render export
jaredjj3 Jun 23, 2026
d1fed7e
scaffold render
jaredjj3 Jun 23, 2026
e9dac9d
add basic test harness
jaredjj3 Jun 24, 2026
a441f8e
reorganize test helpers and fix biome
jaredjj3 Jun 24, 2026
7ff42ff
update testing signature
jaredjj3 Jun 24, 2026
29c6def
symlink CLAUDE.md
jaredjj3 Jun 24, 2026
10b82cc
improve testing strategy
jaredjj3 Jun 24, 2026
0c6c5f4
add canvas and handle diffs more intelligently
jaredjj3 Jun 24, 2026
7434658
remove unused musicxml file
jaredjj3 Jun 24, 2026
f52f7c3
render one part two staves
jaredjj3 Jun 24, 2026
c679013
render two parts with multiple stave combinations
jaredjj3 Jun 24, 2026
524fe1c
test clef rendering
jaredjj3 Jun 24, 2026
dd79035
add support for 4 string and 6 string tabs
jaredjj3 Jun 24, 2026
5612524
renamed the snapshots and made a roadmap
jaredjj3 Jun 24, 2026
bab37ac
render a bunch of notation features
jaredjj3 Jun 24, 2026
6aa60c5
refactor the layout system
jaredjj3 Jun 24, 2026
14715ad
rework render options and simplify test naming
jaredjj3 Jun 24, 2026
3130db5
improve test case declarations
jaredjj3 Jun 24, 2026
3be3b0c
improve test-musicxml skill and update render.test.ts to match
jaredjj3 Jun 24, 2026
e602ead
split up render into multipl files
jaredjj3 Jun 24, 2026
e7cfb28
export Layout type
jaredjj3 Jun 24, 2026
00316d8
audit render tests
jaredjj3 Jun 24, 2026
ca98491
improve the quality of the test cases
jaredjj3 Jun 24, 2026
21b0e68
draw measure attributes changes
jaredjj3 Jun 24, 2026
3cd316d
do not render the beginning barline
jaredjj3 Jun 24, 2026
60812ac
fix voice alignment
jaredjj3 Jun 24, 2026
60ae836
render thin-thick barlines for the last measure
jaredjj3 Jun 24, 2026
932e0e2
render a stave connector for each measure end barline
jaredjj3 Jun 24, 2026
3d8a58e
add Bravura to the assets
jaredjj3 Jun 24, 2026
ec42aa4
log how long the build took
jaredjj3 Jun 24, 2026
39177b1
support part labels
jaredjj3 Jun 24, 2026
fe900df
do not over render barlines if there are stave connectors
jaredjj3 Jun 24, 2026
4a51a5f
improve ledger lines tests and automatically determine stem direction…
jaredjj3 Jun 24, 2026
0be02bd
bolster beam variations test
jaredjj3 Jun 24, 2026
cf6deac
fix edge case with dotted notes not taking up their ticks
jaredjj3 Jun 24, 2026
1903b3b
improve slurs curvature and add more coverage
jaredjj3 Jun 24, 2026
afa8083
add complex slur test
jaredjj3 Jun 24, 2026
af917e7
add a voices grand staff example
jaredjj3 Jun 24, 2026
30f1ed5
make comment more idiomatic
jaredjj3 Jun 24, 2026
bb51169
test configuring font ui labels
jaredjj3 Jun 24, 2026
4343a28
improve README with canonical examples
jaredjj3 Jun 24, 2026
48fcfe9
fix examples
jaredjj3 Jun 24, 2026
b4e35be
add grace note, measure numbering, and tab slurs
jaredjj3 Jun 24, 2026
6b44b8b
consolidate similar tests
jaredjj3 Jun 25, 2026
1e48adf
make first pass at tab techniques
jaredjj3 Jun 25, 2026
87002f2
add quick README section for development
jaredjj3 Jun 25, 2026
a85f02d
combine text and label font configs
jaredjj3 Jun 25, 2026
8d11f60
update default text font
jaredjj3 Jun 25, 2026
a56be1d
add manage-render-options skill
jaredjj3 Jun 25, 2026
3d9ab6e
add options to render H, P, and sl.
jaredjj3 Jun 25, 2026
7d45c68
rename RenderOptions to Config and harden font config
jaredjj3 Jun 25, 2026
c448efa
bold tab notes
jaredjj3 Jun 25, 2026
a1c681d
log new screenshots after running tests
jaredjj3 Jun 25, 2026
c0483c0
refactor the codebase for maintainability
jaredjj3 Jun 25, 2026
c8703b8
improve screenshot reporting
jaredjj3 Jun 25, 2026
d6bb01e
render tab grace notes as smaller
jaredjj3 Jun 25, 2026
f41fee7
increase tab note size
jaredjj3 Jun 25, 2026
b3bbe6d
fix vibrato and bends
jaredjj3 Jun 25, 2026
d48a689
fix text over tab positions
jaredjj3 Jun 26, 2026
70d8121
test tab chords
jaredjj3 Jun 26, 2026
a32a2cd
add grace slurs and fix them
jaredjj3 Jun 26, 2026
8ec2948
nudge the measure number for brackets
jaredjj3 Jun 26, 2026
037b8ba
switch to canvas rendering backend only
jaredjj3 Jun 26, 2026
2f04953
update formatting to happen across all staves
jaredjj3 Jun 26, 2026
8e45ad9
rename font-loader to fonts
jaredjj3 Jun 26, 2026
d87623d
center tablture under stave notes
jaredjj3 Jun 26, 2026
7d6d4fe
render harmonics
jaredjj3 Jun 26, 2026
e7fa51e
render aloof initially
jaredjj3 Jun 26, 2026
71bbaee
add diff-measures skill
jaredjj3 Jun 26, 2026
c0042c2
update test-musicxml skill how to use diff measures
jaredjj3 Jun 26, 2026
f5d667a
update skills for current workflow
jaredjj3 Jun 26, 2026
37f956f
do not render clefs or time signatures for tabs
jaredjj3 Jun 26, 2026
df8e0e9
split aloof into separate files and prevent testing using `bun test`
jaredjj3 Jun 26, 2026
4cf9812
add tempo tests
jaredjj3 Jun 26, 2026
3292f19
fix type errors
jaredjj3 Jun 26, 2026
43e64ad
increase the default pxPerTick value
jaredjj3 Jun 26, 2026
b1a20dc
ensure bracket when rendering tab+notation clef
jaredjj3 Jun 26, 2026
cf6b768
fix ties that span multiple systems
jaredjj3 Jun 26, 2026
8a0a073
add musicxml validation
jaredjj3 Jun 26, 2026
4d05db9
ensure all musicxml documents are valid
jaredjj3 Jun 26, 2026
179b01f
make validate.sh less verbose
jaredjj3 Jun 26, 2026
a806d43
add a render command to vex
jaredjj3 Jun 26, 2026
ffe607f
add render-musicxml skill
jaredjj3 Jun 26, 2026
22cd334
remove describe-measure and manage-vexml-config skills
jaredjj3 Jun 26, 2026
a7496ee
centralize magic numbers in constants.ts
jaredjj3 Jun 26, 2026
26adc9d
split up tie tests
jaredjj3 Jun 26, 2026
b7b550a
fix ties between chords
jaredjj3 Jun 26, 2026
0481a46
split slur tests and simplify ledger line tests
jaredjj3 Jun 26, 2026
13576d9
fix tabs with rest alignment with notation stave
jaredjj3 Jun 26, 2026
5d58d65
thicken the hammer-on and pull-off tab curves
jaredjj3 Jun 26, 2026
fde1f1b
vary the pxPerTick based on the duration
jaredjj3 Jun 26, 2026
cd16d2e
add a vex dev command that brings up a dev server
jaredjj3 Jun 26, 2026
206b282
add ability to add JSON config to vex render and add options to the site
jaredjj3 Jun 27, 2026
b1fa586
separate config controls in the site
jaredjj3 Jun 27, 2026
d017e72
fix cross-system tab curves
jaredjj3 Jun 27, 2026
980deda
justify single systems
jaredjj3 Jun 27, 2026
1f99210
ensure renderings do not get cutoff from above
jaredjj3 Jun 27, 2026
47a42af
fix formatting in aloof_measure7
jaredjj3 Jun 27, 2026
aeac119
improve app to remember MusicXML
jaredjj3 Jun 27, 2026
df02152
show a loading backdrop in the dev app
jaredjj3 Jun 27, 2026
e085a52
use flat beams for complex beam structures
jaredjj3 Jun 27, 2026
d75a77b
keep accents at the notehead
jaredjj3 Jun 27, 2026
901d5b4
split up tab techniques into separate tests
jaredjj3 Jun 27, 2026
9f5b5f9
make several changes for tab clefs
jaredjj3 Jun 27, 2026
b2561fe
add a deploy command and fix notation
jaredjj3 Jun 27, 2026
0f992b6
readd github workflows back to the project
jaredjj3 Jun 27, 2026
5959db8
fix test workflow
jaredjj3 Jun 27, 2026
c23fd2a
update dockerignore
jaredjj3 Jun 27, 2026
49a10e7
Merge branch 'master' into refactor2
jaredjj3 Jun 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 34 additions & 0 deletions .agents/skills/render-musicxml/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: render-musicxml
description: Render a MusicXML file in vexml by running `vex render -i <path/to/musicxml>`, inspect the generated screenshot when needed, and delete ephemeral render output when finished.
---

# Render MusicXML

Use this skill when the user asks to render a MusicXML file, inspect how a MusicXML fixture looks, generate a quick screenshot from MusicXML, or verify rendering behavior visually without adding or updating an integration test.

## Command

Run the render command from the project root:

```sh
vex render -i <path/to/musicxml>
```

Replace `<path/to/musicxml>` with the project-relative or absolute path to the MusicXML file the user wants rendered.

## Workflow

1. Identify the MusicXML input path from the user's request or from the repository.
2. Run `vex render -i <path/to/musicxml>` from `vexml`.
3. Read the command output to find the generated screenshot path.
4. If visual inspection is needed, open or inspect the generated screenshot with available tools.
5. When finished, delete the generated screenshot if it was only meant to be ephemeral.

## Ephemeral Output

Treat the generated screenshot as ephemeral when it was created only for quick inspection, debugging, or answering a one-off question.

Do **not** delete the screenshot when the user explicitly asks to keep it, save it, compare it later, attach it to a report, or use it as a baseline/test artifact.

When deleting an ephemeral screenshot, remove only the screenshot generated by the `vex render` command you just ran. Do not remove existing fixtures, baselines, or unrelated image files.
108 changes: 108 additions & 0 deletions .agents/skills/test-musicxml/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
name: test-musicxml
description: Add or update vexml MusicXML integration tests, validate screenshot output, implement rendering fixes, and selectively update baselines.
---

# Test MusicXML

Use this skill when adding or updating a `vexml` MusicXML rendering test case, especially when the work involves integration fixtures, screenshots, or baseline updates.

## Workflow

**Important:** Use the `vex test` commands shown below, plus selective `vex test --update <name>` only after reviewing the screenshot output.

1. First, check whether an existing test in `tests/integration/` already covers the use case.
- Inspect the relevant integration case definitions and existing files under `tests/integration/__data__/`.
- Reuse or extend an existing case when that is the least surprising option.

2. If the use case is not already covered, add it to `tests/integration/__data__/` — preferably as a new measure inside the existing fixture for that category rather than as a brand-new file.

**Bundle by category; treat each measure as a pseudo unit test.** A category fixture (e.g. `key.musicxml`, `time.musicxml`, `note.musicxml`, `slur.musicxml`) is one MusicXML document whose measures each isolate one variant of that category's behavior — the way a unit-test file holds many small cases. The measure is the unit of isolation, not the file. For example, `key.musicxml` proves a sharp key, a flat key, a mid-system key change, and a no-redraw continuation across M1-M3; `slur.musicxml` walks nine slur scenarios across nine measures. When adding a new variant of an already-covered category, append a measure to that category's fixture (and a `M<n>:` bullet to its comment) instead of creating a near-duplicate file. When you find existing same-category fixtures that each test one variant (e.g. `key_sharps` + `key_flats` + `key_change`), consolidate them into one.

- **When bundling does NOT apply:** some things are fixed for a whole document and can't vary per measure — the `<part-list>` and each part's stave configuration (stave count, tab string count, braces). Those stay as separate `category_variant.musicxml` files. This is why `structure_*` (different part-lists) and `clef_*` (single stave vs grand staff vs 4-/6-line tab) are not bundled: each needs a different part/stave structure, not just a different measure. Rule of thumb: bundle what varies per measure (keys, meters, note/rest/accidental/articulation/beam/slur/tie/tuplet variants, voices); keep separate what needs a different part or stave layout.
- Name a fixture that covers a whole category `category.musicxml` (e.g. `key`, `time`, `note`, `slur`). Use `category_variant.musicxml` only when different part/stave structures force more than one file in that category (e.g. `clef_tab_4_string`, `structure_grand_staff`). Categories: `structure`, `clef`, `key`, `time`, `note`, `rest`, `accidental`, `measures`, …; match the existing files in `tests/integration/__data__/`.
- Register it in `tests/integration/render.test.ts` by adding `testCase('<filename>.musicxml', '<filename>.png')` to the `TEST_CASES` array. Pass any non-default `Config` as the third argument.
- Keep `TEST_CASES` ordered by increasing rendering complexity. A `render` implementer should be able to build a correct renderer progressively by going through the tests in array order: basic structure before clefs, clefs before key/time signatures, simple notes/rests before accidentals, measures, beams, chords, ties/slurs, tuplets, articulations, voices, system layout, and broad stress cases. Insert new cases where they fit this progression; the array order is the only ordering — there is no numeric prefix. A bundled category fixture sits in its category's slot; let its most complex measure set the position.
- Above each `testCase(...)` declaration, write a detailed comment describing what the screenshot should render: the clefs, staves, notes, and any distinctive notation or layout (positions, accidentals, beams, slurs, ledger lines, system breaks, …). Describe what is actually drawn so the comment alone tells a reader what to expect without opening the PNG. Match the descriptive style of the surrounding cases.
- For cases spanning more than one measure, split the comment by measure for readability. Start with a one-line lead describing the global setup (stave/clef/time signature and any wrap behavior), then add one bulleted line per measure using a stable `M<n>:` marker (`M2-3:` for a span). Wrap continuation lines so they align under the bullet text. For multi-voice cases, use inline `V<n>` markers (e.g. `V1`, `V2`) inside each measure bullet. This keeps the comment scannable for humans and greppable for tools, with each `M<n>` mapping directly to a `<measure number="n">` in the fixture. Example:

```ts
// Treble stave, 4/4: dotted-note variations.
// - M1: dotted-quarter + eighth pairs (single dots).
// - M2: double-dotted-quarter + sixteenth pairs (double dots).
testCase('dotted_notes.musicxml', 'dotted_notes.png'),
```
- Each measure should test only one thing. Vary one feature per measure and keep everything else stable (pitch, duration, clef); don't vary unrelated musical features within a measure unless the variation is part of what that measure is proving. The fixture as a whole deliberately spans many variants of its category — but each measure isolates exactly one.
- Wrong pattern: when testing articulations, do not vary duration or pitch needlessly; use stable, boring notes unless pitch or duration affects the articulation behavior being tested.
- Right pattern: when testing beams, varying pitch can be useful if the goal is to show how the beam renders under normal and extreme stem/ledger-line conditions. There should be a clear reason for every extra variation.
- Keep each measure as small as practical while still demonstrating its variant, and the fixture as a whole no larger than its variants require.
- Keep generated MusicXML fixtures as simple and barebones as possible; inspect nearby existing files and match their minimal structure and style.

3. Run the integration test command:

```sh
vex test
```

4. Interpret screenshot results carefully. Screenshot tests can fail or pass for two different reasons:
- **False positive:** a newly added test may pass only because its first generated screenshot was automatically accepted as the baseline. In this state the test accepts any current rendering as correct, even if the rendering is visibly wrong. Leave a `TODO` comment above the `testCase(...)` explicitly calling out this failure mode, for example: `// TODO: False positive: this baseline was probably created from the current render, so it may be accepting an incorrect screenshot. Review the render, then run vex test <name> --update only after the image is confirmed correct.` If the user provides a golden-standard image for the case, compare it against vexml's render before accepting. Eventually, the agent must run `vex test <name> --update` to intentionally accept the reviewed screenshot.
- **True negative:** an existing screenshot test failed because a previously accepted baseline is no longer reproducible. Inspect the diff artifact and leave a `TODO` comment above the `testCase(...)` that describes the visual difference in plain language and links to the diff. Do not prescribe a fix unless the root cause is already clear. Prefer wording like: `// TODO: True negative: the accepted baseline shows <expected visual>, but the new render shows <actual visual>. Diff: <path-or-link>.`
- In both cases, describe what a human should look for in the screenshot. Make the TODO specific enough that another agent can continue from it without opening unrelated files.
- If the correct rendering is ambiguous, ask the user for feedback and include file links to the relevant screenshot diff or artifact.

5. Update the implementation in `src/` to fill the rendering gap.
- Prefer a minimal, root-cause fix.
- Keep changes consistent with the existing renderer and test patterns.

6. Run the test command again:

```sh
vex test
```

7. The target test may still fail. That is useful if it shows the implementation changed the rendered output.
- For the target test file, inspect the new render and confirm it matches the intended rendering described by the relevant test comment or TODO.
- Before updating any screenshot baseline, always perform the screenshot review checklist below.
- If a `TODO` describes a false positive, keep it until the screenshot has been manually reviewed and intentionally accepted with `vex test <name> --update`.
- If a `TODO` describes a true negative, keep it until the changed screenshot has been explained, fixed, or intentionally accepted.
- Do not update baselines until you have evaluated the screenshot output.

## Screenshot Review Checklist

Always run this checklist before accepting or updating a screenshot baseline. Answer these questions from the actual screenshot or diff artifact, not from assumptions about the code:

- Is everything visible? Look for clefs, key signatures, time signatures, notes, rests, articulations, accidentals, ledger lines, beams, ties, slurs, lyrics, barlines, and other symbols that are cut off by the image bounds or page margins.
- Are the results sized appropriately for the render options and the fixture? The image should not look accidentally zoomed in, zoomed out, cropped, or padded with excessive empty space.
- Are musical glyphs clashing when they should not? Check collisions between noteheads, stems, beams, flags, accidentals, dots, rests, text, ties, slurs, clefs, key signatures, time signatures, and neighboring staves/measures.
- Given the render options, does the music feel too cramped? Look for notation that is technically visible but hard to read because horizontal or vertical spacing is too tight.
- Given the render options, does the music feel too spaced out? Look for measures, systems, or glyphs that are spread so far apart that the fixture no longer demonstrates the intended behavior clearly.
- What does the test comment describe? Does the screenshot match that description, including the named clefs, staves, notes, rests, accidentals, beams, slurs, ledger lines, system breaks, and layout expectations?
- Are all expected musical elements present exactly once, with no obvious duplicates, missing glyphs, wrong glyphs, or stale artifacts from a previous render?
- Are stems, beams, flags, dots, accidentals, and rests positioned in musically plausible places relative to the staff and notes?
- If this is a diff, can you explain the visual change in plain language from the diff artifact before updating the baseline?
- If any answer is uncertain, do not update the baseline yet. Add or keep a `TODO` that names the uncertainty and links to the screenshot or diff artifact.

8. If the target render passes the screenshot review checklist, update only that baseline:

```sh
vex test --update <name>
```

Where `<name>` is the test title — the screenshot filename passed as the second argument to `testCase()` in `tests/integration/render.test.ts` (helper in `tests/testing/test-case.ts`), e.g. `clef_treble.png`. The pattern matches by prefix, so `clef_treble` also matches.

9. Validate that there are no regressions.
- Run `vex test` again after the selective baseline update.
- Per project rules, also run `vex fix` after code changes.
- If you deleted any integration test cases, run `vex test --clean` globally to remove orphaned screenshot baselines. Do not target a single test when cleaning deleted cases.
- If regressions appear, eagerly add or list `TODO` comments for each regression using the false-positive or true-negative language from step 4. Include the plain-language visual difference and the relevant diff path or artifact link.
- Do not update the whole suite by default. Create a plan for each regression and explain whether it is expected or unexpected.

## Describing Screenshot Diffs

Whenever you need to verbalize a screenshot difference — a regression diff artifact in `tests/integration/__diffs__`, or a comparison of vexml's current render against a golden-standard image the user provided (common for new test cases) — inspect the original image path(s) directly and describe the difference in plain language.

Do **not** create transformed derivatives for diff work unless there is no other practical way to understand the artifact. Prefer the original screenshot or diff artifact. For a `__diffs__` artifact, remember that the image has old / diff / new vertical sections. For a golden-standard comparison, keep clear which image is the vexml render and which is the golden image.

## Baseline Update Guidance

Avoid running `vex test --update` for the whole suite unless the change is intentionally global and every affected render has passed the screenshot review checklist. Prefer one-by-one baseline updates after confirming why each render changed.
1 change: 1 addition & 0 deletions .claude/skills
23 changes: 0 additions & 23 deletions .github/ISSUE_TEMPLATE/bug-report.md

This file was deleted.

42 changes: 13 additions & 29 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,53 +1,37 @@
# Simple workflow for deploying static content to GitHub Pages
# See https://vitejs.dev/guide/static-deploy#github-pages
# Builds the site/ playground and deploys it to GitHub Pages (vexml.dev).
# Pages source must be set to "GitHub Actions" in repo settings.
name: deploy

on:
# Runs on pushes targeting the default branch
push:
branches:
- 'master'

# Allows you to run this workflow manually from the Actions tab
- "master"
workflow_dispatch:

# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

# Allow one concurrent deployment
# One deploy at a time; newer pushes cancel in-flight runs.
concurrency:
group: 'pages'
group: "pages"
cancel-in-progress: true

jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
# Includes @rollup/rollup-linux-x64-gnu, which is an optional dependency required for Vite.
run: npm install @rollup/rollup-linux-x64-gnu --save-dev
- name: Build
run: npx vex build site
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bunx vite build site
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: './site/dist'
- name: Deploy to GitHub Pages
id: deployment
path: "./site/dist"
- id: deployment
uses: actions/deploy-pages@v4
33 changes: 21 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Premerge checks: format/lint/typecheck + unit and visual-regression tests.
# `vex test` builds the Dockerfile and runs the suite inside it, so screenshot
# baselines match local runs. Docker is preinstalled on ubuntu-latest.
name: test

on:
pull_request:
push:
Expand All @@ -10,16 +14,21 @@ jobs:
name: run premerge code checks
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: echo "$PWD/bin" >> "$GITHUB_PATH"
- run: vex fix --check
# Build the test image once with gha layer caching and load it into the
# daemon. vex test then reuses it (VEX_TEST_SKIP_BUILD) instead of rebuilding.
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
node-version: 22.6.0
cache: npm
- name: install
run: npm ci
- name: fix
run: npx vex fix --check
- name: test
run: npx vex test --ci
context: .
load: true
tags: vexml-tests
cache-from: type=gha
cache-to: type=gha,mode=max
- run: vex test
env:
VEX_TEST_SKIP_BUILD: '1'
11 changes: 5 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
dist
node_modules
.DS_STORE
__diff_output__
coverage
__tmp_image_snapshots__
.claude
site/dist
.zed
tests/integration/__diffs__/
.DS_Store
.playwright-mcp
1 change: 0 additions & 1 deletion .npmrc

This file was deleted.

3 changes: 0 additions & 3 deletions .prettierignore

This file was deleted.

8 changes: 0 additions & 8 deletions .prettierrc.json

This file was deleted.

7 changes: 3 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Use the `vex` or command for development. If it's not available, use `npx vex` instead.
After making code changes:

After making changes, format, lint, typecheck, and run tests in the packages that were affected.
`vex fix`
`vex test --local`
- Run `vex fix` to typecheck, format, and lint the project.
- Run `vex test` to test the project.
1 change: 0 additions & 1 deletion CLAUDE.md

This file was deleted.

1 change: 1 addition & 0 deletions CLAUDE.md
Loading
Loading