Skip to content

feat(editor): "Bar 1 here" re-anchor + Lead-in region + import nudge (tempo PR 6) - #233

Merged
byrongamatos merged 2 commits into
mainfrom
feat/editor-bar1-here
Jul 12, 2026
Merged

feat(editor): "Bar 1 here" re-anchor + Lead-in region + import nudge (tempo PR 6)#233
byrongamatos merged 2 commits into
mainfrom
feat/editor-bar1-here

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tempo-track PR 6 of the assisted-tempo charrette (UX P4 / trans P4 / rhythm G2). Everything you need to line a chart up to a recording that doesn't start at 0:00.

What's new

  • "Bar 1 here" — an inspector button (and a bar-1 pole right-click item, listed above the pickup item) shifts the grid, every part's notes/chords/anchors/drums, and the sections so bar 1's downbeat lands at the playhead. The audio never moves — this is a chart re-anchor riding the same undoable TempoOffsetCmd as a manual offset nudge (S.appliedOffset accrues; Ctrl+Z restores exactly). Status: "Bar 1 → 6.57s — chart and notes shifted; audio unchanged."
  • Lead-in region — the space before bar 1 now draws as a labelled hatched wash, mirroring the Unmapped-tail treatment from feat(editor): Tempo Map legibility S-pack — HUD legend, unmapped tail, barline copy #220.
  • Import nudge (SUGGEST only, never auto-shift) — when an import lands bar 1 at ~0 but the first detected onset is clearly later, the status line points the user at Tempo Map ▸ "Bar 1 here". Skipped for warp imports (already bar-by-bar aligned).
  • The pickup right-click item is relabelled "(partial first bar — for music that starts before beat 1)" so it reads distinctly from the new re-anchor.

Design authority

docs/TEMPO-MAPPING-DESIGN.md + the charrette. Re-anchoring goes through PR 1's offset command (#218); the region treatment mirrors PR 2 (#220). Both deps are on main.

Implementation

New pures in src/tempo.js: _firstDownbeatTimePure, _tempoBar1ShiftPure, _importBar1NudgePure, plus the _tempoSetBar1Here verb. Wired into the tempo-map inspector strip, the context menu, and the _tempoMapDraw pass. src/create.js reads the first onset (_ensureOnsets, ready after the awaited loadAudio) for the import nudge.

Tests / gates

tests/bar1_here.test.mjs (14): the three pures, the nudge gating (fires only when bar 1 ≈ 0 and the onset is clearly + meaningfully later), and the command round-trip across a 2-arrangement song + drums + sections with exec → undo → redo deep-equality. 122 JS suites green, lint 0 errors (3 pre-existing ratchet warnings). routes.py untouched → no pytest.

Verified live

On AC/DC — Back In Black: entered Tempo Map, moved the playhead, clicked Bar 1 here → grid re-anchored to 6.57s, the Lead-in wash rendered before bar 1, offset field synced to 6.5666, status read as designed. No page errors from the change.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added “Bar 1 here” actions in Tempo Map mode (inspector button and right-click) to align bar 1’s downbeat to the playhead while keeping recordings stationary.
    • Added visual “Lead-in” labeling/shading before bar 1 in the grid.
    • Added import-time guidance when bar 1 placement may need adjustment.
    • Added undo/redo support for bar 1 repositioning, restoring prior timing accurately.
  • Bug Fixes
    • Improved labeling and alignment behavior for pickup/partial first bars.

…(tempo PR 6)

Tempo-track PR 6 (charrette UX P4 / trans P4 / rhythm G2). Three related
moves for lining a chart up to a recording that doesn't start at 0:00:

- "Bar 1 here": an inspector button and a bar-1 pole right-click item (listed
  above the pickup item) shift the grid, every part's notes/chords/anchors/
  drums, and the sections so bar 1's downbeat lands at the playhead. The audio
  never moves — it is a chart re-anchor riding the SAME undoable TempoOffsetCmd
  as a manual offset nudge (S.appliedOffset accrues; Ctrl+Z restores exactly).
- Lead-in region: the space before bar 1 now draws as a labelled hatched wash,
  mirroring the Unmapped tail's treatment.
- Import nudge (SUGGEST only, never auto-shift): when an import lands bar 1 at
  ~0 but the first detected onset is clearly later, the status line points the
  user at Tempo Map ▸ "Bar 1 here".
- The pickup right-click item is relabelled "(partial first bar — for music
  that starts before beat 1)" so it reads distinctly from the new re-anchor.

New pures in src/tempo.js: _firstDownbeatTimePure, _tempoBar1ShiftPure,
_importBar1NudgePure (+ the _tempoSetBar1Here verb). tests/bar1_here.test.mjs
(14): the pures, the nudge gating, and the command round-trip across a
2-arrangement song + drums + sections with exec/undo/redo. 122 JS suites green,
lint 0-err (3 pre-existing ratchet warnings). routes.py untouched.

Verified live on AC/DC — Back In Black: entered Tempo Map, clicked "Bar 1
here" at the playhead → "Bar 1 → 6.57s — chart and notes shifted; audio
unchanged", the whole grid re-anchored, and the Lead-in wash rendered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ec3fb6d-fe59-452c-a519-29b557ec0132

📥 Commits

Reviewing files that changed from the base of the PR and between f80c04d and 14fe252.

📒 Files selected for processing (2)
  • src/create.js
  • tests/bar1_here.test.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/bar1_here.test.mjs
  • src/create.js

📝 Walkthrough

Walkthrough

Adds Tempo Map controls to align bar 1 with the playhead, shifts musical timing through an undoable command, renders lead-in space, and appends import-time guidance when the first onset starts after the inferred grid.

Changes

Bar 1 tempo-grid anchoring

Layer / File(s) Summary
Tempo grid contracts and controls
src/tempo.js, tests/bar1_here.test.mjs
Adds lead-in rendering, bar 1 timing helpers, inspector and context-menu actions, and tests for grid calculations and import guidance conditions.
Undoable bar 1 re-anchoring
src/tempo.js, tests/bar1_here.test.mjs
Shifts the tempo grid and related musical parts through TempoOffsetCmd, synchronizes state and status, and validates undo, redo, no-op, and missing-grid behavior.
Import-time bar 1 guidance
src/create.js, CHANGELOG.md
Appends an onset-based “Bar 1 here” suggestion after applicable imports and documents the new behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant _tempoSetBar1Here
  participant TempoOffsetCmd
  participant EditorState
  User->>_tempoSetBar1Here: Select Bar 1 here
  _tempoSetBar1Here->>TempoOffsetCmd: Apply bar 1 shift
  TempoOffsetCmd->>EditorState: Shift tempo grid and musical parts
  EditorState-->>User: Update alignment and status
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main changes: Bar 1 re-anchoring, Lead-in UI, and import nudge support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/editor-bar1-here

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/bar1_here.test.mjs (1)

91-153: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Round-trip test never asserts anchors actually shift forward.

timesSnapshot() captures anchors and the undo-restore check (line 147) confirms the snapshot returns to before, but no assertion checks that S.arrangements[X].anchors[Y].time actually moved by delta after _tempoSetBar1Here() (unlike notes, chords, handshapes, drums, and sections, which are all explicitly checked at lines 134-139). If a regression stopped anchors from being reprojected, this suite would still pass, since the undo-restore comparison only proves round-trip consistency of whatever was touched, not that anchors were touched at all — yet the command's own docstring (and PR objectives) explicitly claim anchors are shifted.

✅ Suggested addition
     assert.ok(near(S.drumTab.hits[0].t, 4.0), 'drum hit +delta');
     assert.ok(near(S.sections[0].start_time, 3.0), 'section +delta');
+    assert.ok(near(S.arrangements[0].anchors[0].time, 3.0), 'anchor +delta');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/bar1_here.test.mjs` around lines 91 - 153, Add an explicit
post-_tempoSetBar1Here assertion for an anchor in seedMultiPart, such as
arrangements[1].anchors[0].time, verifying it advances by the applied +2.0
delta. Keep the existing timesSnapshot undo/redo checks unchanged.
src/tempo.js (1)

243-294: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Lead-in wash duplicates the Unmapped-tail wash almost verbatim.

Both blocks compute clamped x0/x1, fill the same wash color, call _tempoHatchRect, and conditionally draw a bold label — differing only in the time range and label text/threshold. Worth extracting a shared helper to avoid drift if the hatch styling ever changes.

♻️ Suggested extraction
+function _tempoDrawHatchedSpan(t0, t1, w, gridBottom, label, minWidthForLabel) {
+    const x0 = Math.max(LABEL_W, timeToX(t0));
+    const x1 = Math.min(w, timeToX(t1));
+    const top = (TIMELINE_TOP + WAVEFORM_H);
+    if (x1 <= x0 + 2) return;
+    ctx.fillStyle = 'rgba(100,116,139,0.06)';
+    ctx.fillRect(x0, top, x1 - x0, gridBottom - top);
+    _tempoHatchRect(x0, top, x1 - x0, gridBottom - top, '`#64748b`', 8, 0.10);
+    if (x1 - x0 > minWidthForLabel) {
+        ctx.fillStyle = '`#64748b`';
+        ctx.font = 'bold 10px monospace';
+        ctx.textAlign = 'left';
+        ctx.textBaseline = 'top';
+        ctx.fillText(label, x0 + 6, top + 6);
+    }
+}

Then both the "Unmapped tail" and "Lead-in" blocks collapse to a single call each, e.g. _tempoDrawHatchedSpan(_lastDbTime, tailEndT, w, gridBottom, 'Unmapped', 66) and _tempoDrawHatchedSpan(0, _bar1T, w, gridBottom, 'Lead-in', 56).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tempo.js` around lines 243 - 294, Extract the duplicated hatched-region
rendering from the Unmapped tail and Lead-in blocks into a shared
_tempoDrawHatchedSpan helper that handles clamped coordinates, wash fill, hatch
drawing, and conditional labeling. Replace both inline rendering blocks with
calls using their existing time ranges, labels, and width thresholds, preserving
the current guards and visual behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/create.js`:
- Around line 2052-2063: Update the status update at the end of the sync-message
flow around _syncAppliedMessagePure and the _msg nudge handling to call
setStatus unconditionally, including when _msg is an empty string. Preserve the
existing function-type guard, but remove the truthiness check so stale editor
status text is cleared.

---

Nitpick comments:
In `@src/tempo.js`:
- Around line 243-294: Extract the duplicated hatched-region rendering from the
Unmapped tail and Lead-in blocks into a shared _tempoDrawHatchedSpan helper that
handles clamped coordinates, wash fill, hatch drawing, and conditional labeling.
Replace both inline rendering blocks with calls using their existing time
ranges, labels, and width thresholds, preserving the current guards and visual
behavior.

In `@tests/bar1_here.test.mjs`:
- Around line 91-153: Add an explicit post-_tempoSetBar1Here assertion for an
anchor in seedMultiPart, such as arrangements[1].anchors[0].time, verifying it
advances by the applied +2.0 delta. Keep the existing timesSnapshot undo/redo
checks unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7788b348-8366-45c6-8189-e33852d2b51e

📥 Commits

Reviewing files that changed from the base of the PR and between c36378a and f80c04d.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • src/create.js
  • src/tempo.js
  • tests/bar1_here.test.mjs

Comment thread src/create.js Outdated
@byrongamatos
byrongamatos merged commit 6eb4022 into main Jul 12, 2026
4 checks passed
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.

2 participants