Skip to content

feat(editor): chord inspector — author chord name + fingering (E1)#7

Merged
byrongamatos merged 1 commit into
mainfrom
feat/editor-chord-inspector
Jun 20, 2026
Merged

feat(editor): chord inspector — author chord name + fingering (E1)#7
byrongamatos merged 1 commit into
mainfrom
feat/editor-chord-inspector

Conversation

@byrongamatos

Copy link
Copy Markdown
Collaborator

What

Adds a Chord section to the arrangement-editor inspector, shown whenever the selection resolves to a chord (≥2 notes sharing a save-time group). A charter can author the shared chord template inline:

  • Name and Display name (text inputs)
  • Per-string fingering — one <select> per sounding string (/open/1–4), width-aware via lanes() so 7/8-string charts work
  • Arpeggio toggle

All controls are inline DOM — no window.prompt() (it's a silent no-op in the bundled Electron).

How

  • Every edit goes through a new EditChordTemplateCmd undo command (exec/rollback, like EditAnchorFretWidthCmd). It finds-or-creates the matching arr.chord_templates entry keyed by the width-L fret pattern.
  • The fret key is resolved from the full save-time group (time.toFixed(4)), exactly as reconstructChords() groups — so a partial selection (e.g. rectangle-selecting 2 of a 3-note chord) still authors the chord's real key and the metadata survives the save-time rebuild via relinkChordTemplate.
  • displayName/arp now round-trip end to end (E0 deferred them):
    • relinkChordTemplate carries displayName (fallback to name) and arp.
    • routes.py wire writer emits templates[].displayName + arp; XML writer emits the chordTemplate displayName attribute.
    • routes.py read side (_song_to_dict + the two GP import serializers) surfaces displayName/arp off the core ChordTemplate, so reload repopulates the inspector.
    • Core lib/song.py already models display_name/arpeggio and arrangement_from_wire already reads displayName/arp, so the round-trip is lossless with no core change.

Notes / limitations

  • Template-level arp is wire-only. RS-XML arpeggio lives on <handShape>, not <chordTemplate>, so template arp persists/reloads through the sloppak wire but is not emitted as a chordTemplate XML attribute — it's reconstructed from the handshape layer. Bridging template arp<handShape> is future work.
  • Same-fret chords share one template (first-wins), so renaming one occurrence affects all occurrences of that fret pattern. Acceptable for E1; a per-_chordId split is future (E2-adjacent) work.

Verify

  • node --check screen.js — parses.
  • node tests/chord_relink.test.js — 6/6 pass, including new displayName/arp carry + fallback + blank assertions.
  • python -m pytest tests/ — 67 pass (the one failure, test_populates_empty_notation_only_arrangement, is pre-existing on main and unrelated to chord templates; test_xml_export.py/test_arrangement_xml_alignment.py 57/57 green).

Closes #4. Part of got-feedBack/feedBack#334.

🤖 Generated with Claude Code

Add a "Chord" section to the arrangement-editor inspector, shown whenever the
selection resolves to a chord (>=2 notes sharing a save-time group). It authors
the shared chord template: name, displayName, per-string fingering, and an
arpeggio toggle — all inline controls (no window.prompt, which is a silent
no-op in the bundled Electron).

Edits go through a new EditChordTemplateCmd undo command, which finds-or-creates
the matching arr.chord_templates entry keyed by the width-L fret pattern. The
fret key is resolved from the full save-time group (time.toFixed(4)) exactly as
reconstructChords() does, so a partial selection still authors the chord's real
key and the metadata survives the save-time rebuild via relinkChordTemplate.

displayName/arp now round-trip end to end (E0 deferred them):
- relinkChordTemplate carries displayName (fallback to name) and arp.
- routes.py wire writer emits templates[].displayName + arp; XML writer emits
  the chordTemplate displayName attribute. Template-level arp is wire-only —
  RS-XML arpeggio lives on <handShape>, so it's reconstructed there, not emitted
  on chordTemplate.
- routes.py read side (_song_to_dict + GP import serializers) surfaces
  displayName/arp off the core ChordTemplate, so reload repopulates the
  inspector. Core lib/song.py already models display_name/arpeggio, so the
  round-trip is lossless with no core change.

Tests: extend tests/chord_relink.test.js to assert displayName/arp are carried
(matching pattern + fallback + blank cases).

Note: same-fret chords share one template (first-wins), so renaming one
occurrence affects all occurrences of that fret pattern — acceptable for E1; a
per-_chordId split is future work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[E1] Chord inspector: author chord name + per-string fingering

1 participant