/** * Scene recipes optimized for short social clips. * Each recipe is deterministic so repeated runs produce similar footage. */ import { expandNepalEvidencePack } from './nepalEvidencePack.js'; import { msg, t } from '../i18n/index.js'; const BHOTE_KOSHI_NEPAL_BASE_RECIPE = Object.freeze({ id: 'bhote-koshi-nepal-evidence-pack', version: 12, title: msg('Bhote Koshi Evidence Sequence'), style: 'normal', ui: { hidePanels: false, hudMode: 'full', safeFrame: '16:9' }, layers: { 'bhote-koshi-locator': false, }, releaseLayerIds: ['bhote-koshi-2026', 'bhote-koshi-locator'], post: { bloom: 0, sharpen: true, detectionMode: 'OFF', mapStack: 'photoreal', }, legacySceneBootstrap: { targetSceneTitle: 'Nepal Flood Incident', fromShotTitles: ['Shot 1', 'Shot 2', 'Shot 3'], cameraPath: [ { // i18n-ignore: stored shot title, matched verbatim title: 'Global Incident Context', lat: 27.5962, lon: 78.5718, alt: 15628002, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'nepal-context' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Nepal-Focused Globe Rotation', lat: 28.7248, lon: 81.3226, alt: 2068966, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'nepal-context' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Regional Approach', lat: 27.0354, lon: 84.6287, alt: 809543, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-regional' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Nearby Cities', lat: 27.891, lon: 85.428, alt: 225734, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-city-context' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Incident Corridor', lat: 28.0529, lon: 85.2189, alt: 126931, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 11, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-incident-places' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Flood Path', lat: 28.1691, lon: 85.352, alt: 60328, heading: 0, pitch: -90, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-flood-path' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Corridor Overview', lat: 27.8986, lon: 84.8723, alt: 53247, heading: 60, pitch: -48, roll: 0, duration: 4, hold: 0.9, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-path-overview' }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Upper Valley', lat: 28.4187, lon: 85.4341, alt: 7977, heading: 155, pitch: -28, roll: 0, duration: 4, hold: 8, layers: { 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-trigger-record' }, }, }, }, ], }, requiredShotTitles: [ 'Global Incident Context', 'Nepal-Focused Globe Rotation', 'Bhote Koshi Regional Approach', 'Bhote Koshi Nearby Cities', 'Bhote Koshi Incident Corridor', 'Bhote Koshi Flood Path', 'Bhote Koshi Corridor Overview', 'Bhote Koshi Upper Valley', 'Upper Valley Collapse', 'Debris-Dammed Lake', 'Nepal-China Border Gate', 'Timure Evidence Cluster', 'Syabru Besi Passage', 'Bidur / Trishuli Consequence', ], requiredSourcePackBeatIds: [ 'immediate-collapse-viewpoint', 'debris-dammed-lake', 'gyirong-border-gate', 'timure-cluster', 'syabru-besi', 'bidur-trishuli-bridge', ], requiredSourcePackLayerId: 'bhote-koshi-2026', photorealSurfaceBeatIds: [ 'gyirong-border-gate', 'timure-cluster', 'syabru-besi', 'bidur-trishuli-bridge', ], runtimeControlsByBeat: { 'immediate-collapse-viewpoint': { evidenceMediaAutoplay: true }, 'debris-dammed-lake': { evidenceMediaAutoplay: true }, 'gyirong-border-gate': { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 2.5, deferEvidenceUntilCameraSettled: true, evidenceRevealDurationSec: 2.5, }, 'timure-cluster': { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 4, }, 'syabru-besi': { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 4, }, 'bidur-trishuli-bridge': { evidenceSequence: true, evidenceSequenceDurationSec: 4, }, }, shotPatches: [ { // i18n-ignore: stored shot title, matched verbatim title: 'Global Incident Context', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'immediate-collapse-viewpoint', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Nepal-Focused Globe Rotation', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'debris-dammed-lake', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Regional Approach', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'gyirong-border-gate', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Nearby Cities', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'timure-cluster', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Incident Corridor', camera: { lat: 28.0529, lon: 85.2189, alt: 126931, heading: 0, pitch: -90, roll: 0, }, holdSec: 11, visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'syabru-besi', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Flood Path', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'bidur-trishuli-bridge', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Corridor Overview', visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'gyirong-border-gate', beatReveal: 0.36, split: 0.5, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bhote Koshi Upper Valley', holdSec: 8, visual: { mapStack: 'photoreal' }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'immediate-collapse-viewpoint', beatReveal: 0.36, split: 0.5, }, }, 'bhote-koshi-locator': { enabled: true, params: { presentation: 'bhote-koshi-trigger-record', }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Upper Valley Collapse', camera: { lat: 28.417, lon: 85.3937, alt: 9850, heading: 146, pitch: -34, roll: 0, }, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'immediate-collapse-viewpoint', beatReveal: 0.36, split: 0.5, sceneControls: { evidenceMediaAutoplay: true }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Nepal-China Border Gate', visual: { mapStack: 'photoreal' }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Timure Evidence Cluster', visual: { mapStack: 'photoreal' }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Syabru Besi Passage', visual: { mapStack: 'photoreal' }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bidur / Trishuli Consequence', visual: { mapStack: 'photoreal' }, }, ], cameraPath: [ { // i18n-ignore: stored shot title, matched verbatim title: 'Upper Valley Collapse', lat: 28.417, lon: 85.3937, alt: 9850, heading: 146, pitch: -34, roll: 0, duration: 4.2, hold: 1.4, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'immediate-collapse-viewpoint', beatReveal: 0.36, split: 0.5, sceneControls: { evidenceMediaAutoplay: true }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Debris-Dammed Lake', lat: 28.392914, lon: 85.570921, alt: 10744, heading: 232, pitch: -37, roll: 0, duration: 4.2, hold: 1.4, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'debris-dammed-lake', beatReveal: 0.36, split: 0.5, sceneControls: { evidenceMediaAutoplay: true }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Nepal-China Border Gate', mapStack: 'photoreal', lat: 28.316789, lon: 85.399734, alt: 5900, heading: 208, pitch: -42, roll: 0, duration: 4.2, hold: 2.5, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'gyirong-border-gate', beatReveal: 0.36, split: 0.5, sceneControls: { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 2.5, deferEvidenceUntilCameraSettled: true, evidenceRevealDurationSec: 2.5, }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Timure Evidence Cluster', mapStack: 'photoreal', lat: 28.285968, lon: 85.379136, alt: 5032, heading: 198, pitch: -40, roll: 0, duration: 4.2, hold: 4, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'timure-cluster', beatReveal: 0.36, split: 0.5, sceneControls: { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 4, }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Syabru Besi Passage', mapStack: 'photoreal', lat: 28.210306, lon: 85.361527, alt: 5893, heading: 205, pitch: -38, roll: 0, duration: 4.2, hold: 4, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'syabru-besi', beatReveal: 0.36, split: 0.5, sceneControls: { imageryComparison: true, evidenceSequence: true, evidenceSequenceDurationSec: 4, }, }, }, }, }, { // i18n-ignore: stored shot title, matched verbatim title: 'Bidur / Trishuli Consequence', mapStack: 'photoreal', lat: 27.981737, lon: 85.196273, alt: 7422, heading: 215, pitch: -40, roll: 0, duration: 4.2, hold: 4, layers: { 'bhote-koshi-2026': { enabled: true, params: { presentation: 'scene-beat', beatId: 'bidur-trishuli-bridge', beatReveal: 0.36, split: 0.5, sceneControls: { evidenceSequence: true, evidenceSequenceDurationSec: 4, }, }, }, }, }, ], }); const BHOTE_KOSHI_NEPAL_APPEND_RECIPE = BHOTE_KOSHI_NEPAL_BASE_RECIPE ? expandNepalEvidencePack(BHOTE_KOSHI_NEPAL_BASE_RECIPE) : null; // Fresh browser origins have no legacy three-shot Nepal project for the // append recipe to upgrade. Seed that exact legacy shape so SceneDirector can // run the same idempotent bootstrap used by existing browser-saved projects. const BHOTE_KOSHI_NEPAL_BOOTSTRAP_RECIPE = BHOTE_KOSHI_NEPAL_APPEND_RECIPE ? Object.freeze({ id: 'bhote-koshi-nepal-scene', title: msg('Nepal Flood Incident'), durationSec: 15, style: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.style, ui: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.ui, layers: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.layers, releaseLayerIds: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.releaseLayerIds, post: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.post, installAlongsideSceneId: 'bhote-koshi-flood', installAlongsideFallbackSceneId: 'flights-radar', cameraPath: BHOTE_KOSHI_NEPAL_APPEND_RECIPE.legacySceneBootstrap.cameraPath .slice(0, 3) .map((keyframe, index) => ({ ...keyframe, // i18n-ignore: legacy shot titles the bootstrap matches verbatim title: `Shot ${index + 1}`, })), }) : null; const EVENT_RECIPES = [BHOTE_KOSHI_NEPAL_BOOTSTRAP_RECIPE].filter(Boolean); const PUBLIC_SCENE_RECIPES = [ { id: 'flights-radar', title: msg('Global Flights Radar'), durationSec: 30, style: 'retro', ui: { hidePanels: true, hudMode: 'minimal', safeFrame: '16:9' }, layers: { flights: true, satellites: false, earthquakes: false, traffic: false, }, post: { bloom: 62, sharpen: true, detectionMode: 'OFF', }, cameraPath: [ { lat: 20.0, lon: -30.0, alt: 19000000, heading: 25, pitch: -65, roll: 0, duration: 6, hold: 1, }, { lat: 46.0, lon: 2.0, alt: 8000000, heading: 40, pitch: -52, roll: 0, duration: 5, hold: 1, }, { lat: 35.0, lon: 139.0, alt: 4200000, heading: 22, pitch: -46, roll: 0, duration: 5, hold: 1, }, { lat: 37.6, lon: -122.4, alt: 1700000, heading: 8, pitch: -40, roll: 0, duration: 5, hold: 1, }, { lat: 0.0, lon: -20.0, alt: 12000000, heading: -10, pitch: -70, roll: 0, duration: 4, hold: 0, }, ], }, { id: 'orbital-watch', title: msg('Orbital Watch'), durationSec: 32, style: 'surveillance', ui: { hidePanels: true, hudMode: 'full', safeFrame: '16:9' }, layers: { flights: false, satellites: true, earthquakes: false, traffic: false, }, post: { bloom: 58, sharpen: false, detectionMode: 'SPARSE', styleParams: { surveillance: { gain: 0.62, bloom: 0.38, scanlineStr: 0.9, pixelation: 2.1, }, }, }, cameraPath: [ { lat: 28.0, lon: -82.0, alt: 22000000, heading: 0, pitch: -82, roll: 0, duration: 7, hold: 1, }, { lat: 10.0, lon: 20.0, alt: 12000000, heading: 18, pitch: -74, roll: 0, duration: 5, hold: 1, }, { lat: 35.7, lon: 139.7, alt: 6500000, heading: 24, pitch: -64, roll: 0, duration: 5, hold: 1, }, { lat: 48.8, lon: 2.3, alt: 3000000, heading: 32, pitch: -58, roll: 0, duration: 5, hold: 1, }, { lat: 30.0, lon: -25.0, alt: 15000000, heading: -20, pitch: -78, roll: 0, duration: 4, hold: 0, }, ], }, { id: 'thermal-threats', title: msg('Thermal Threat Board'), durationSec: 26, style: 'thermal', ui: { hidePanels: true, hudMode: 'full', safeFrame: '16:9' }, layers: { flights: false, satellites: false, earthquakes: true, traffic: false, }, post: { bloom: 72, sharpen: true, detectionMode: 'OFF', styleParams: { thermal: { sensitivity: 0.84, bloom: 0.78, mode: 0.0, pixelation: 1.9, }, }, }, cameraPath: [ { lat: 37.0, lon: -121.0, alt: 5200000, heading: 20, pitch: -62, roll: 0, duration: 5, hold: 1, }, { lat: 35.7, lon: 140.0, alt: 3100000, heading: 5, pitch: -55, roll: 0, duration: 5, hold: 1, }, { lat: -36.8, lon: 174.7, alt: 2600000, heading: -12, pitch: -50, roll: 0, duration: 5, hold: 1, }, { lat: 38.0, lon: -10.0, alt: 9000000, heading: 12, pitch: -70, roll: 0, duration: 4, hold: 0, }, ], }, { id: 'city-overload', title: msg('City Overload'), durationSec: 30, style: 'surveillance', ui: { hidePanels: true, hudMode: 'minimal', safeFrame: '9:16' }, layers: { flights: true, satellites: true, earthquakes: false, traffic: true, }, post: { bloom: 65, sharpen: true, detectionMode: 'PANOPTIC', styleParams: { surveillance: { gain: 0.68, bloom: 0.42, scanlineStr: 1.0, pixelation: 2.4, }, }, }, cameraPath: [ { lat: 40.73, lon: -74.0, alt: 1500000, heading: 25, pitch: -44, roll: 0, duration: 5, hold: 1, }, { lat: 40.73, lon: -74.0, alt: 550000, heading: 58, pitch: -36, roll: 0, duration: 4, hold: 1, }, { lat: 40.73, lon: -74.0, alt: 260000, heading: 102, pitch: -33, roll: 0, duration: 4, hold: 1, }, { lat: 34.05, lon: -118.24, alt: 1200000, heading: 45, pitch: -42, roll: 0, duration: 5, hold: 1, }, { lat: 51.5, lon: -0.12, alt: 1200000, heading: 22, pitch: -44, roll: 0, duration: 5, hold: 0, }, ], }, { id: 'omniscience-pullback', title: msg('Omniscience Pullback'), durationSec: 36, style: 'retro', ui: { hidePanels: true, hudMode: 'full', safeFrame: '16:9' }, layers: { flights: true, satellites: true, earthquakes: true, traffic: true, }, post: { bloom: 68, sharpen: true, detectionMode: 'SPARSE', styleParams: { retro: { pixelation: 4.4, distortion: 0.42, instability: 0.58, }, }, }, cameraPath: [ { lat: 35.68, lon: 139.76, alt: 280000, heading: 30, pitch: -26, roll: 0, duration: 5, hold: 1, }, { lat: 35.68, lon: 139.76, alt: 900000, heading: 26, pitch: -38, roll: 0, duration: 4, hold: 1, }, { lat: 35.68, lon: 139.76, alt: 3800000, heading: 18, pitch: -52, roll: 0, duration: 5, hold: 1, }, { lat: 20.0, lon: 110.0, alt: 9500000, heading: 8, pitch: -66, roll: 0, duration: 5, hold: 1, }, { lat: 5.0, lon: 30.0, alt: 18000000, heading: -8, pitch: -78, roll: 0, duration: 6, hold: 0, }, ], }, ]; /** Build the recipe list without mutating stored user-authored projects. */ function createSceneRecipes({ localDemoRecipes = EVENT_RECIPES } = {}) { return [...localDemoRecipes, ...PUBLIC_SCENE_RECIPES]; } export const SCENE_RECIPES = createSceneRecipes(); export const SCENE_APPEND_RECIPES = BHOTE_KOSHI_NEPAL_APPEND_RECIPE ? [BHOTE_KOSHI_NEPAL_APPEND_RECIPE] : []; function getSceneRecipeById(id) { return SCENE_RECIPES.find((recipe) => recipe.id === id) || null; } export function getSceneAppendRecipeById(id) { return SCENE_APPEND_RECIPES.find((recipe) => recipe.id === id) || null; } // Built-in shot titles stay English in recipes and saved projects (upgrades // and bindings match them verbatim). These are their display names; a title // the user typed shows as typed. Place names inside them stay Latin. const BUILTIN_SHOT_TITLES = new Set([ msg('Global Incident Context'), msg('Nepal-Focused Globe Rotation'), msg('Bhote Koshi Regional Approach'), msg('Bhote Koshi Nearby Cities'), msg('Bhote Koshi Incident Corridor'), msg('Bhote Koshi Flood Path'), msg('Bhote Koshi Corridor Overview'), msg('Bhote Koshi Upper Valley'), msg('Upper Valley Collapse'), msg('Debris-Dammed Lake'), msg('Nepal-China Border Gate'), msg('Timure Evidence Cluster'), msg('Syabru Besi Passage'), msg('Bidur / Trishuli Consequence'), msg('Second landslide'), msg('Mailung / Upper Trishuli bridge'), msg('Dandagaun viewpoint restaurant'), msg('Devighat / Taadi Khola Bridge'), msg('Final view'), ]); /** * Display title for a scene: the localized recipe name while the stored title * still matches the built-in verbatim, the stored title otherwise. * @param {{id?: string, title?: string}} scene * @returns {string} */ export function displaySceneTitle(scene) { const builtin = SCENE_RECIPES.find((recipe) => recipe.id === scene?.id); if (builtin?.title && scene.title === builtin.title) return t(builtin.title); const title = scene?.title || ''; // Only the generated "Scene N" localizes; an operator-typed "Scene 007" // keeps its digits, so the number stays a string (no Number() round trip). const numbered = /^Scene ([1-9]\d*)$/.exec(title); return numbered ? t('Scene {n}', { n: numbered[1] }) : title; } /** * Display title for a shot: built-in titles and the numbered "Shot N" * fallback localize; any other title shows as stored. * * With `shot`, a built-in title localizes only for a recipe shot * (`sourcePackId`), so a typed title that matches a built-in one stays as * typed. Without `shot`, the title alone decides. * @param {string} title * @param {{id?: string, sourcePackId?: string}} [shot] * @param {{id?: string, appliedShotPacks?: Array<{id?: string, shotBindings?: Object}>}} [scene] * The shot's scene, for projects saved before shots recorded their source * pack. * @returns {string} */ export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, shot, text) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); return numbered ? t('Shot {n}', { n: numbered[1] }) : text; } /** Whether the built-in recipe behind a scene declares this shot's title. */ function recipeDeclaresShotTitle(scene, shot, title) { const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; if (!recipe) return false; const declares = (path) => Array.isArray(path) && path.some((keyframe) => keyframe?.title === title); if (declares(recipe.cameraPath)) return true; // A bootstrap recipe seeds legacy "Shot N" keyframes; the upgrade replaces // them with the append recipe's bootstrap shots, which carry no source pack. // The pack marker binds each of those titles to its shot id, so a shot the // operator later gave the same title stays as typed. return SCENE_APPEND_RECIPES.some( (append) => append.legacySceneBootstrap?.targetSceneTitle === recipe.title && declares(append.legacySceneBootstrap.cameraPath) && Boolean(shot?.id) && (Array.isArray(scene.appliedShotPacks) ? scene.appliedShotPacks : [] ).some( (marker) => marker?.id === append.id && marker.shotBindings?.[title] === shot.id, ), ); }