New shared component src/ui/preview.js (appFrameUrl + previewLink): song + seed + frame + venue/venueSel deep-links. App honors ?frame= (warm seek on bank-song load) and ?venueSel= via shared pinVenueShell helper (src/venues/pin.js), which filmstrip and venue-gallery now also use. Filmstrip figures and venue-gallery cards wrap canvases; gallery cells stay unlinked (isolated scene probes, not reproducible in-app).
45 lines
1.9 KiB
JavaScript
45 lines
1.9 KiB
JavaScript
// Pin one venue shell onto a look.
|
|
//
|
|
// The same shell-swap in three places: the filmstrip's `venueSel`, the venue
|
|
// gallery's venue picker, and the app's `?venueSel=`. Only the shell is
|
|
// forced — module/name/archetype. The VenueSpec population stays the census
|
|
// one (counts overlap between archetypes), so this is what makes a pinned
|
|
// preview the exact image the app reproduces, rather than a nearby one.
|
|
|
|
import { venues } from './registry.js';
|
|
|
|
/**
|
|
* Force `look.venue` to render as the named venue.
|
|
*
|
|
* @param {object} look LookSpec from generateLook (mutated in place)
|
|
* @param {string} name venue name, e.g. 'Ride'
|
|
* @param {object} [opts]
|
|
* @param {number} [opts.seed] seed for a from-scratch spec (default 1)
|
|
* @param {boolean} [opts.buildIfMissing] build a neutral spec when the
|
|
* census produced no venue at all (the venue gallery does; the filmstrip
|
|
* keeps the no-venue video instead)
|
|
* @returns {boolean} true when a venue is pinned afterwards
|
|
*/
|
|
export function pinVenueShell(look, name, { seed = 1, buildIfMissing = false } = {}) {
|
|
if (!name || !look) return false;
|
|
const picked = venues.find((v) => v.name === name);
|
|
if (!picked) throw new Error(`unknown venue "${name}"`);
|
|
if (!look.venue) {
|
|
if (!buildIfMissing) return false;
|
|
look.venue = {
|
|
archetype: picked.archetype, name: picked.name, seed,
|
|
shell: { kind: picked.archetype }, projection: { kind: 'screen' },
|
|
population: { kind: 'scatter', count: 5, spread: 0.7, jitter: 0.25 },
|
|
paletteMap: [0, 1, 2, 3],
|
|
perSection: (look.sections || []).map(
|
|
() => ({ light: 0.7, fog: 0.35, popMul: 0.65, reachMul: 0.85 })),
|
|
venue: true, readsDepth: false, module: picked,
|
|
};
|
|
return true;
|
|
}
|
|
look.venue.module = picked;
|
|
look.venue.name = picked.name;
|
|
look.venue.archetype = picked.archetype;
|
|
return true;
|
|
}
|