Deep-link view settings survive file drops

Dropped files ignored pins while the URL still claimed them, so the census venue replaced the demo's pinned room. Drop loads now inherit venueSel/viz from the query, and stale bank addressing (song/seed/frame/warm) is cleared on drop while view settings stay.
This commit is contained in:
Dejvino
2026-09-21 21:14:02 +02:00
parent 56919ed819
commit 3df4b3545b
+38 -3
View File
@@ -104,7 +104,20 @@ async function loadFile(file, { seed = null, pins = null, frame = null, warm = n
if (state.busy) return;
state.busy = true;
stopPlayback();
// A dropped file carries no pins of its own — inherit the view settings
// from the URL (a demo deep-link's venueSel/viz), so the room and subject
// you came to see survive the new track. The bank path always passes an
// explicit pins object and is unaffected. Frame/warm never carry over:
// they address the old song's timeline.
const fromDrop = pins == null;
if (fromDrop) {
try {
const q = new URLSearchParams(location.search);
if (q.get('venueSel') || q.get('viz')) {
pins = { venueSel: q.get('venueSel'), viz: q.get('viz') };
}
} catch { /* non-browser — no pins */ }
}
if (dom.overlay) {
dom.overlay.hidden = true;
dom.overlay.style.display = 'none';
@@ -136,8 +149,8 @@ async function loadFile(file, { seed = null, pins = null, frame = null, warm = n
// Deep link from a preview (filmstrip figure, venue-gallery card):
// pins ride into load() so the arc builds pinned layers once, then
// the exact frame with the probe's warm-up so stateful layers land
// converged like the probe render. Dropped files never carry pins —
// only `?song=` loads pass them.
// converged like the probe render. Dropped files carry inherited
// pins (above) but always start at frame 0.
const deepLink = !!(pins && (pins.venueSel || pins.viz)) || Number.isFinite(frame);
// Prime before the landing seek on deep-link loads: programs link
// asynchronously and a draw against an unlinked program is wrong
@@ -146,6 +159,7 @@ async function loadFile(file, { seed = null, pins = null, frame = null, warm = n
if (deepLink) state.show.prime();
seekTo(Number.isFinite(frame) ? frame : 0,
Number.isFinite(warm) ? { warmup: warm } : {});
if (fromDrop) clearBankParamsFromUrl();
renderPanel();
document.title = `flow-state · ${state.show.fileName}`;
console.info('[flow-state]', describeLook(state.show.look));
@@ -174,6 +188,27 @@ if (dom.changeTrack) dom.changeTrack.addEventListener('click', () => dom.fileInp
dom.fileInput.addEventListener('change', (e) => {
if (e.target.files[0]) loadFile(e.target.files[0]);
});
/**
* A dropped file has no URL identity, so the bank addressing it by name
* (?song=&seed=&frame=&warm=) must go once the file loads — otherwise the
* URL keeps describing the previous song while another plays (and rerolls
* would persist a seed against the wrong name). View settings
* (?venue=&venueSel=&viz=) stay: they describe how you watch, not what.
* Uses replaceState — no reload, no history spam.
*/
function clearBankParamsFromUrl() {
try {
const q = new URLSearchParams(location.search);
if (!q.get('song') && !q.get('seed') && !q.get('frame') && !q.get('warm')) return;
q.delete('song');
q.delete('seed');
q.delete('frame');
q.delete('warm');
const rest = q.toString();
history.replaceState(null, '', rest ? `${location.pathname}?${rest}` : location.pathname);
} catch { /* non-browser or sandboxed iframe */ }
}
/**
* `?song=centre` — open a bank song straight from a debug page.
*