// 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; }