Skip to content

Add configurable weighted track path finder with on-demand search, diagnostics, persisted settings, and path cost controls - #6

Merged
samsta merged 28 commits into
mainfrom
copilot/add-path-finding-feature
May 21, 2026
Merged

samsta merged 28 commits into
mainfrom
copilot/add-path-finding-feature

Conversation

Copilot AI commented May 21, 2026 •

Copy link
Copy Markdown
Contributor
  • Fix invalid textAnchor value "beginning" → "start" (valid SVG/TS value)
  • Bump version from 0.4.0 → 0.5.0 in package.json and package-lock.json
  • Verify build passes and all 22 tests pass
  • Add "Transition costs" heading above the cost input grid
  • Use consistent wording: 'cost' (not 'weight'), 'transition' (not 'step') throughout Path Finder UI
  • Add build workflow badge to README.md
Original prompt

Implement a path-finding feature in the samsta/KeyBpmMap repository.

Requirements:

  • Add UI that lets the user choose a start track and an end track.
  • Compute navigation paths from the first track to the second track across tracks using key and tempo transitions.
  • Use weighted transitions with the following default costs:
    • same key: 0
    • one up: 1
    • one down: 1
    • A->B: 2
    • B->A: 2
    • xA -> (x+3)B: 1
    • jump across the center (e.g. xA -> (x+6)A): 4
    • tempo change: 1 per %
  • Optionally allow key change by tempo:
    • for each track, optionally consider speeding it up by 5.946% (raises the key by a semitone, equivalent to -5 on the circle of fifths)
    • or slowing it down by 5.61% (lowers the key by a semitone, equivalent to +5 on the circle of fifths)
    • assign a weight of 3 to this operation, then continue evaluating using the normal rules from that adjusted point
  • Allow each weight to be configurable in the UI.
  • Persist the configurable weights in local storage.
  • Add a configurable maximum total cost.
  • Prune all but the 5 best paths.
  • Provide a graphical representation of the resulting paths and a list representation; for example, clicking a path in the graph should show its step-by-step list/details.

Additional constraints from repo review instructions:

  • The app version shown in the UI comes from package.json.
  • Every pull request must bump package.json to a newer version before merge.
  • The version must be strictly greater than the version on the base branch.
  • Project convention is to increment the minor version for each PR.

Please implement the feature, update any necessary tests/docs, and bump package.json to the next minor version relative to the repository base branch before creating the PR.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: Add a path finder to navigate from one track to the next. Allow the user to pick two tracks and then find paths along tracks to navigate from the first track to the second track along keys and tempo with the following weights:

same key: 0
one up: 1
one down: 1
A->B: 2
B->A: 2
xA -> (x+3)B: 1
jump across the center (e.g. xA -> (x+6)A): 4
tempo change: 1 per %

optionally, allow key change by tempo, i.e. for each track consider speeding it up by 5.946% (which increases the key by a semitone, or -5 on the circle of fifths) or slowing it down by 5.61% (which decreases the key by a semitone, or +5 on the circle of fifths), assign a weight of 3 to this operation, and then evaluate from that point according to the above rules.

Allow each weight to be configurable, persisting the values in local storage.

Cap at a configurable max cost. Prune all but the 5 best paths. Find a good way to represent the info graphically and as a list, e.g. show the list when a path is clicked in the graph.

Ask for clarification if you're unsure

Assistant: I’m waiting for your response to the GitHub confirmation dialog before I can continue.

This pull request was created from Copilot chat.

Copilot AI changed the title [WIP] Add path-finding feature with configurable weights Add configurable weighted track path finder with graph/list results and persisted settings May 21, 2026
Copilot AI requested a review from samsta May 21, 2026 09:14
Copilot finished work on behalf of samsta May 21, 2026 09:14
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot please address the following feedback:

  1. There seems to be a tight/endless loop somewhere in the path calculation. It freezes the browser
  2. Only search the path on demand, i.e. add a button "Find Path"
  3. Move the path finder to the bottom
  4. Add the xB -> (x-3)A as another criteria
  5. It's worth noting that xA -> (x+3)B is actually going from minor to major, which becomes blindingly obvious when looking at the musical notation for the key
  6. Make the labels of the weights consistent in casing, all other labels start on uppercase
  7. Give an example (in smaller, slightly darker font, or whatever seems suitable) for each of the weights, e.g. 5A->6A for one up etc
  8. Try your best in adding a little help blurb explaining what those weights mean
  9. Extend the mock crate so finding a path is actually feasible
  10. Be consistent with key representation, e.g. use openkey notation for the weights when that's what the user has selected
  11. Add small buttons to each track listed in "selected region" to set it as either start track or end track
  12. Make the start track and end track input element so that you can start typing and the list automatically reduces to matches (combo box?)

Copilot AI and others added 2 commits May 21, 2026 09:53

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please address the following feedback:

  1. There seems to be a tight/endless loop somewhere in the path calculation. It freezes the browser
    ...

Addressed in 9adf69a (main feedback in 810d076).

Implemented:

  • On-demand search via Find Path button (no automatic recalculation).
  • Added exploration guard in path search to prevent runaway computation.
  • Added xB→(x-3)A transition rule + configurable weight.
  • Updated weight labels to consistent casing, added per-weight examples and help text.
  • Made weight notation representation-aware (Camelot/Open Key/Musical).
  • Added quick actions in Selected region: set track as Start/End.
  • Replaced Start/End selects with searchable datalist inputs.
  • Extended mock crate with additional route-friendly tracks.
  • Moved Path Finder to the bottom of the page layout.

Screenshot: /tmp/pathfinder-feedback-ui.png

Copilot AI changed the title Add configurable weighted track path finder with graph/list results and persisted settings Add configurable weighted track path finder with on-demand search, improved UX, and persisted settings May 21, 2026
Copilot finished work on behalf of samsta May 21, 2026 09:56
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot there's the following issues:

  1. in some (all?) playlists, tracks are missing from the plots. e.g. it would say there's 38 tracks in scope, but only 9 are shown in the plots. Maybe add an optionally displayable table of the tracks in scope so I can diagnose this? Might be useful anyway. Add buttons for adding as start/end track as well in this list for bonus points
  2. weight explanations: A -> B is better explained as jumping from the inner ring to the outer ring or jumping from a minor key to its relative major, B -> A is better explained as jumping from the outer ring to the inner ring or jumping from a major key to its relative minor.
  3. For musical notation, the second to the seventh label should be "One 5th up", "One 5th down", "min -> rel maj", "maj -> rel min", "min -> maj", "maj -> min"
  4. In the graph, add the artist and title in small font underneath each step, artist and title on separate lines, with artist bold
  5. The combo boxes misbehave, please double check. For instance, I'd expect the little 'x' to the right to clear the field, but it doesn't

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot there's the following issues:

  1. in some (all?) playlists, tracks are missing from the plots. e.g. it would say there's 38 tracks in scope, but only 9 are shown in the plots. Maybe add an ...

Addressed in 3eea3eb (with the main bulk in 9899f9f).

Implemented:

  • Added an optional Tracks in Scope table to diagnose plot visibility, including an In Plots reason (Yes, No (missing BPM), No (hidden by key filter)), plus Start/End buttons in that list.
  • Updated A→B and B→A explanations to inner/outer ring + relative major/minor wording.
  • Added the requested musical labels for weights 2–7:
    • One 5th up / One 5th down / min → rel maj / maj → rel min / min → maj / maj → min
  • Added artist + title under each node in the path graph (small, artist emphasized).
  • Fixed Start/End combo behavior so fields can be cleared and edited normally.
  • Bumped version to 0.6.0 (package.json + package-lock.json).

Screenshot: /tmp/pathfinder-followup-ui.png

Copilot AI changed the title Add configurable weighted track path finder with on-demand search, improved UX, and persisted settings Add configurable weighted track path finder with on-demand search, diagnostics, improved UX, and persisted settings May 21, 2026
Copilot finished work on behalf of samsta May 21, 2026 10:50
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot for some of the tracks listed as 'no bpm' I don't quite understand how that comes about. Here's one example that shows up without BPM, but it's 122.0:

INSERT INTO Track VALUES(1167,2,380,NULL,NULL,'../DJ/Techno - Club/ALIIRA - Escucha (NILU (DK) & Phonique Remix).aiff','ALIIRA - Escucha (NILU (DK) & Phonique Remix).aiff',2117,122.0,388,100577678,'Escucha (NILU (DK) & Phonique Remix)','ALIIRA','Escucha',NULL,'Visit https://aliira.bandcamp.com',NULL,NULL,NULL,23,60,'image://planck/0',1770017430,1,'aiff',1,1757050338,1756987200,1,0,0,266800070911393620,1,0,NULL,NULL,0,'2c89c4c8-4be3-48b3-b287-5e25fbd28bc2',1167,0,0,1770017430,NULL);

Copilot AI and others added 2 commits May 21, 2026 11:40

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot for some of the tracks listed as 'no bpm' I don't quite understand how that comes about. Here's one example that shows up without BPM, but it's 122.0:

...

Great catch — you’re absolutely right about the two BPM columns. I fixed this in c3c000c (follow-up cleanup in 8f16b4c).

The importer now explicitly prefers bpmAnalyzed (REAL) and only falls back to bpm (INTEGER) if analyzed BPM is missing. I also made column-name matching more robust across schema variants, and fixed one BPM display check so only null is treated as “No BPM”.

Copilot finished work on behalf of samsta May 21, 2026 11:42
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot can you please also calculate the average cost and the max cost per step for each path, allow paths to be sorted by total cost, average cost, or max cost, and allow to set a max cost per step (default 4) and a max average cost (default 3).
It also looks like the height of the input boxes for the weights isn't the same for all of them

Comment thread package.json Outdated
"name": "keybpmmap",
"private": true,
"version": "0.4.0",
"version": "0.7.0",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@copilot We only need to bump the version once per PR. Keep this at 0.5.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 51ae953 — version is now 0.5.0 in both package.json and package-lock.json.

Copilot finished work on behalf of samsta May 21, 2026 21:54
Copilot AI requested a review from samsta May 21, 2026 21:54
Comment thread src/App.tsx
Comment on lines +940 to +972
<div className="field-grid path-weight-grid">
{PATH_WEIGHT_FIELDS.map((field) => {
const helpText = `${field.description}${
field.exampleFrom && field.exampleTo
? ` Example: ${formatVisibleKey(field.exampleFrom)} → ${formatVisibleKey(field.exampleTo)}.`
: ` ${field.exampleText ?? ''}`
}`

return (
<label key={field.key}>
<span className="path-weight-label-row">
<span className="path-weight-label-text">
{formatWeightLabel(field.key, field.label, keyRepresentation)}
</span>
<span
className="path-weight-tooltip"
title={helpText}
aria-label={helpText}
tabIndex={0}
>
ⓘ
</span>
</span>
<input
type="number"
step="0.1"
value={pathFinderSettings.weights[field.key]}
onChange={(event) => handlePathWeightChange(field.key, event.target.value)}
/>
</label>
)
})}
</div>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@copilot Group these under a heading "Transition costs"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 7f650de — added a "Transition costs" heading above the weight inputs grid.

@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot make pathfinder wording consistent: don't use 'step' and 'transition', only 'transition'; don't use 'cost' and 'weight', only 'weight'

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot make pathfinder wording consistent: don't use 'step' and 'transition', only 'transition'; don't use 'cost' and 'weight', only 'weight'

Done in cef98d9. All Path Finder UI text now consistently uses "weight" (not "cost") and "transition" (not "step") — labels, headings, sort options, aria-labels, inline descriptions, and the detail view.

Copilot finished work on behalf of samsta May 21, 2026 22:02
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot please have a look at the workflow results:
Run npm run build
...

Fixed in 57272a8 — changed the invalid textAnchor value "beginning" to "start" (the correct SVG/TypeScript value) in HeatmapChart.tsx. Version also bumped to 0.7.0.

@copilot this was actually happening on 'main' as well and I didn't notice. Please add a badge for this workflow to the README.md as well

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please have a look at the workflow results:
Run npm run build
...
...

Done in 2a890bd — added a ![Build](…/deploy.yml/badge.svg) badge to the README, next to the existing Tests badge.

Copilot finished work on behalf of samsta May 21, 2026 22:04
@samsta

samsta commented May 21, 2026

Copy link
Copy Markdown
Owner

@copilot make pathfinder wording consistent: don't use 'step' and 'transition', only 'transition'; don't use 'cost' and 'weight', only 'weight'

Done in cef98d9. All Path Finder UI text now consistently uses "weight" (not "cost") and "transition" (not "step") — labels, headings, sort options, aria-labels, inline descriptions, and the detail view.

@copilot actually, I changed my mind. Use "cost" instead of "weight", I think that makes more sense to the average user

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot make pathfinder wording consistent: don't use 'step' and 'transition', only 'transition'; don't use 'cost' and 'weight', only 'weight'

Done in cef98d9. All Path Finder UI text no...

Done in 0c61856 — all Path Finder UI text now uses "cost" (labels, headings, sort options, aria-labels, descriptions, and the detail view).

Copilot finished work on behalf of samsta May 21, 2026 22:08
@samsta
samsta marked this pull request as ready for review May 21, 2026 22:17
@samsta
samsta merged commit 8c18683 into main May 21, 2026
3 checks passed
@samsta
samsta deleted the copilot/add-path-finding-feature branch May 27, 2026 07:29
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.

3 participants