style: format remaining owned runtime modules

This commit is contained in:
Sameh Khamis committed 2026-09-15 07:26:32 -07:00
1 parent ae99843c14
commit 2aca7aecbb
94 files changed
+8865 -3151

No files matched your search

+223 -76
View File
@@ -60,7 +60,10 @@ function normalizeLayerEntry(entry) {
if (entry && typeof entry === 'object') {
return {
enabled: !!entry.enabled,
params: entry.params && typeof entry.params === 'object' ? deepClone(entry.params) : undefined,
params:
entry.params && typeof entry.params === 'object'
? deepClone(entry.params)
: undefined,
};
}
return { enabled: !!entry };
@@ -75,13 +78,18 @@ function normalizeLayerEntry(entry) {
* @param {number} [options.fallbackIntensity] - Default intensity if not stored
* @returns {{ enabled: boolean, intensity: number, version: number }}
*/
function normalizeBloomState(rawBloom = {}, { projectVersion = PROJECT_VERSION, fallbackIntensity = 50 } = {}) {
function normalizeBloomState(
rawBloom = {},
{ projectVersion = PROJECT_VERSION, fallbackIntensity = 50 } = {},
) {
// Determine which bloom scale the stored value was encoded under.
// Older projects (version < PROJECT_VERSION) used scale version 1.
const explicitVersion = Number(rawBloom.version);
const bloomVersion = Number.isFinite(explicitVersion)
? explicitVersion
: (projectVersion >= PROJECT_VERSION ? BLOOM_SCALE_VERSION : 1);
: projectVersion >= PROJECT_VERSION
? BLOOM_SCALE_VERSION
: 1;
const rawIntensity = Number.isFinite(Number(rawBloom.intensity))
? Number(rawBloom.intensity)
@@ -104,9 +112,10 @@ function normalizeBloomState(rawBloom = {}, { projectVersion = PROJECT_VERSION,
function recipeToScene(recipe) {
const post = recipe.post || {};
const ui = recipe.ui || {};
const styleParams = post.styleParams && typeof post.styleParams === 'object'
? deepClone(post.styleParams)
: {};
const styleParams =
post.styleParams && typeof post.styleParams === 'object'
? deepClone(post.styleParams)
: {};
// Normalize layer targets from the recipe into canonical form
const layers = {};
@@ -138,13 +147,15 @@ function recipeToScene(recipe) {
style: recipe.style || 'normal',
bloom: {
enabled: typeof post.bloom === 'number' ? post.bloom > 0 : !!post.bloom,
intensity: typeof post.bloom === 'number'
? decodeBloomIntensity(post.bloom, 1)
: BLOOM_INTENSITY_DEFAULT,
intensity:
typeof post.bloom === 'number'
? decodeBloomIntensity(post.bloom, 1)
: BLOOM_INTENSITY_DEFAULT,
version: BLOOM_SCALE_VERSION,
},
sharpen: {
enabled: typeof post.sharpen === 'boolean' ? post.sharpen : !!post.sharpen,
enabled:
typeof post.sharpen === 'boolean' ? post.sharpen : !!post.sharpen,
intensity: 65,
},
hud: {
@@ -190,7 +201,11 @@ function createDefaultProject() {
* @param {number} [options.projectVersion] - Schema version of the enclosing project
* @returns {Object} Fully normalized shot
*/
function normalizeShot(rawShot, index = 0, { projectVersion = PROJECT_VERSION } = {}) {
function normalizeShot(
rawShot,
index = 0,
{ projectVersion = PROJECT_VERSION } = {},
) {
const camera = rawShot?.camera || {};
const visual = rawShot?.visual || {};
const bloom = visual.bloom || {};
@@ -201,7 +216,10 @@ function normalizeShot(rawShot, index = 0, { projectVersion = PROJECT_VERSION }
return {
id: rawShot?.id || uid('shot'),
title: rawShot?.title || `Shot ${index + 1}`,
durationSec: Math.max(0.2, Number(rawShot?.durationSec) || DEFAULT_SHOT_DURATION_SEC),
durationSec: Math.max(
0.2,
Number(rawShot?.durationSec) || DEFAULT_SHOT_DURATION_SEC,
),
holdSec: Math.max(0, Number(rawShot?.holdSec) || 0),
camera: {
lat: Number(camera.lat) || 0,
@@ -213,10 +231,21 @@ function normalizeShot(rawShot, index = 0, { projectVersion = PROJECT_VERSION }
},
visual: {
style: visual.style || 'normal',
bloom: normalizeBloomState(bloom, { projectVersion, fallbackIntensity: 50 }),
bloom: normalizeBloomState(bloom, {
projectVersion,
fallbackIntensity: 50,
}),
sharpen: {
enabled: !!sharpen.enabled,
intensity: Math.max(0, Math.min(100, Number.isFinite(Number(sharpen.intensity)) ? Number(sharpen.intensity) : 65)),
intensity: Math.max(
0,
Math.min(
100,
Number.isFinite(Number(sharpen.intensity))
? Number(sharpen.intensity)
: 65,
),
),
},
hud: {
visible: typeof hud.visible === 'boolean' ? hud.visible : true,
@@ -224,12 +253,26 @@ function normalizeShot(rawShot, index = 0, { projectVersion = PROJECT_VERSION }
},
detection: {
mode: typeof detection.mode === 'string' ? detection.mode : 'OFF',
density: Math.max(0, Math.min(100, Number.isFinite(Number(detection.density)) ? Number(detection.density) : 35)),
density: Math.max(
0,
Math.min(
100,
Number.isFinite(Number(detection.density))
? Number(detection.density)
: 35,
),
),
},
styleParams: visual.styleParams && typeof visual.styleParams === 'object' ? deepClone(visual.styleParams) : {},
styleParams:
visual.styleParams && typeof visual.styleParams === 'object'
? deepClone(visual.styleParams)
: {},
},
layers: Object.fromEntries(
Object.entries(rawShot?.layers || {}).map(([layerId, value]) => [layerId, normalizeLayerEntry(value)])
Object.entries(rawShot?.layers || {}).map(([layerId, value]) => [
layerId,
normalizeLayerEntry(value),
]),
),
};
}
@@ -241,7 +284,8 @@ function normalizeShot(rawShot, index = 0, { projectVersion = PROJECT_VERSION }
* @returns {Object} Fully normalized project at the current PROJECT_VERSION
*/
function normalizeProject(rawProject) {
if (!rawProject || typeof rawProject !== 'object') return createDefaultProject();
if (!rawProject || typeof rawProject !== 'object')
return createDefaultProject();
const projectVersion = Number.isFinite(Number(rawProject.version))
? Number(rawProject.version)
: 1;
@@ -250,7 +294,9 @@ function normalizeProject(rawProject) {
const scenes = scenesRaw
.map((scene, sceneIdx) => {
const shotsRaw = Array.isArray(scene?.shots) ? scene.shots : [];
const shots = shotsRaw.map((shot, shotIdx) => normalizeShot(shot, shotIdx, { projectVersion }));
const shots = shotsRaw.map((shot, shotIdx) =>
normalizeShot(shot, shotIdx, { projectVersion }),
);
return {
id: scene?.id || uid('scene'),
title: scene?.title || `Scene ${sceneIdx + 1}`,
@@ -316,12 +362,21 @@ export class SceneDirector {
this._selectedSceneId = this._project.scenes[0]?.id || null;
this._selectedShotId = this._project.scenes[0]?.shots[0]?.id || null;
this._presentation = { status: 'Ready', progress: 0, runtime: '', playbackActive: false, keyboardEnabled: false };
this._state = createStateChannel(() => ({ ...this.getPlaybackStatus(), ...this._presentation, hasRun: !!this._lastRunJson }));
this._presentation = {
status: 'Ready',
progress: 0,
runtime: '',
playbackActive: false,
keyboardEnabled: false,
};
this._state = createStateChannel(() => ({
...this.getPlaybackStatus(),
...this._presentation,
hasRun: !!this._lastRunJson,
}));
this._initUI();
}
_trackWork(promise) {
this._pendingWork ||= new Set();
this._pendingWork.add(promise);
@@ -372,7 +427,10 @@ export class SceneDirector {
// Private browsing / block-all-cookies / quota-exceeded throws here. The
// in-memory project stays usable this session, but persistence failed —
// tell the user instead of crashing the caller (M11).
console.warn('[Scenes] Could not persist project (storage unavailable):', e);
console.warn(
'[Scenes] Could not persist project (storage unavailable):',
e,
);
this._toastStorageError();
}
}
@@ -391,17 +449,30 @@ export class SceneDirector {
toast.classList.remove('visible');
}, 2600);
}
} catch { /* toast is best-effort */ }
} catch {
/* toast is best-effort */
}
}
/** Immutable playback snapshots and completed editing actions. */
subscribe(listener, options) { return this._state.subscribe(listener, options); }
subscribe(listener, options) {
return this._state.subscribe(listener, options);
}
_publish(change) { this._state?.publish(change); }
_publish(change) {
this._state?.publish(change);
}
_shotOutcome(type, scene, shot, index = scene.shots.indexOf(shot)) {
if (type === 'shot-loaded') this._presentation.status = `Loaded: ${scene.title} / ${shot.title}`;
this._publish({ type, sceneId: scene.id, sceneTitle: scene.title, shot, index });
if (type === 'shot-loaded')
this._presentation.status = `Loaded: ${scene.title} / ${shot.title}`;
this._publish({
type,
sceneId: scene.id,
sceneTitle: scene.title,
shot,
index,
});
}
/**
@@ -424,7 +495,10 @@ export class SceneDirector {
this._selectedShotId = this._getSelectedScene()?.shots[0]?.id || null;
this._renderShotList();
},
selectShot: (id) => { this._selectedShotId = id; this._publish({ type: 'selection-changed' }); },
selectShot: (id) => {
this._selectedShotId = id;
this._publish({ type: 'selection-changed' });
},
renameShot: (sceneId, shotId, title) => {
const { scene, shot } = this._getShot(sceneId, shotId);
if (!shot) return;
@@ -450,7 +524,9 @@ export class SceneDirector {
/** Rebuild the scene dropdown options and sync the selected value. */
_renderSceneSelect() {
if (!this._project.scenes.some((scene) => scene.id === this._selectedSceneId)) {
if (
!this._project.scenes.some((scene) => scene.id === this._selectedSceneId)
) {
this._selectedSceneId = this._project.scenes[0]?.id || null;
}
this._publish({ type: 'scene-options-changed' });
@@ -463,7 +539,10 @@ export class SceneDirector {
*/
_renderShotList() {
const scene = this._getSelectedScene();
if (scene?.shots.length && !scene.shots.some((shot) => shot.id === this._selectedShotId)) {
if (
scene?.shots.length &&
!scene.shots.some((shot) => shot.id === this._selectedShotId)
) {
this._selectedShotId = scene.shots[0].id;
}
this._publish({ type: 'shots-changed' });
@@ -474,7 +553,11 @@ export class SceneDirector {
* @returns {Object|null} The scene, or null if no valid selection
*/
_getSelectedScene() {
return this._project.scenes.find((scene) => scene.id === this._selectedSceneId) || null;
return (
this._project.scenes.find(
(scene) => scene.id === this._selectedSceneId,
) || null
);
}
/**
@@ -511,7 +594,9 @@ export class SceneDirector {
const scene = this._getSelectedScene();
if (!scene) return;
this._project.scenes = this._project.scenes.filter((item) => item.id !== scene.id);
this._project.scenes = this._project.scenes.filter(
(item) => item.id !== scene.id,
);
// Restore default recipes if the user deleted all scenes
if (!this._project.scenes.length) {
this._project = createDefaultProject();
@@ -553,15 +638,18 @@ export class SceneDirector {
return;
}
const shot = normalizeShot({
id: uid('shot'),
title: `Shot ${scene.shots.length + 1}`,
durationSec: DEFAULT_SHOT_DURATION_SEC,
holdSec: DEFAULT_HOLD_SEC,
camera,
visual: this.styleManager.getVisualState(),
layers: this._captureLayerStates(),
}, scene.shots.length);
const shot = normalizeShot(
{
id: uid('shot'),
title: `Shot ${scene.shots.length + 1}`,
durationSec: DEFAULT_SHOT_DURATION_SEC,
holdSec: DEFAULT_HOLD_SEC,
camera,
visual: this.styleManager.getVisualState(),
layers: this._captureLayerStates(),
},
scene.shots.length,
);
scene.shots.push(shot);
this._selectedShotId = shot.id;
@@ -628,7 +716,8 @@ export class SceneDirector {
* @param {number} [options.flyDuration=2.2] - Camera flight duration in seconds
*/
loadShot(sceneId, shotId, options) {
if (this._destroyed) return Promise.resolve({ started: false, reason: 'destroyed' });
if (this._destroyed)
return Promise.resolve({ started: false, reason: 'destroyed' });
return this._trackWork(this._loadShot(sceneId, shotId, options));
}
@@ -652,7 +741,9 @@ export class SceneDirector {
this._renderSceneSelect();
this._renderShotList();
await this.styleManager.applyVisualState(shot.visual, { isCurrent: () => !token.cancelled });
await this.styleManager.applyVisualState(shot.visual, {
isCurrent: () => !token.cancelled,
});
if (token.cancelled) return;
await this._applyLayerStates(shot.layers || {}, token);
if (token.cancelled) return;
@@ -693,8 +784,12 @@ export class SceneDirector {
*/
_claimCameraOwnership() {
// Older/headless style managers may predate the facade — proceed then.
if (typeof this.styleManager?.runImmediateNavigation !== 'function') return true;
const claimed = this.styleManager.runImmediateNavigation('scene', () => true);
if (typeof this.styleManager?.runImmediateNavigation !== 'function')
return true;
const claimed = this.styleManager.runImmediateNavigation(
'scene',
() => true,
);
if (claimed === false) {
this._updateStatus('Camera unavailable — exit cockpit first');
return false;
@@ -712,13 +807,16 @@ export class SceneDirector {
if (!this._project.scenes.length) return [];
// Rotate the scene list so startSceneId comes first
const startIdx = Math.max(0, this._project.scenes.findIndex((scene) => scene.id === startSceneId));
const startIdx = Math.max(
0,
this._project.scenes.findIndex((scene) => scene.id === startSceneId),
);
const ordered = single
? this._project.scenes.slice(startIdx, startIdx + 1)
: [
...this._project.scenes.slice(startIdx),
...this._project.scenes.slice(0, startIdx),
];
...this._project.scenes.slice(startIdx),
...this._project.scenes.slice(0, startIdx),
];
// Flatten scenes into a sequential shot queue
const queue = [];
@@ -748,12 +846,17 @@ export class SceneDirector {
* @returns {{id: string, title: string, shots: number}|null}
*/
findSceneByQuery(query) {
const q = String(query ?? '').trim().toLowerCase();
const q = String(query ?? '')
.trim()
.toLowerCase();
if (!q) return null;
const scene = this._project.scenes.find((item) => item.id === query)
|| this._project.scenes.find((item) => item.title.toLowerCase() === q)
|| this._project.scenes.find((item) => item.title.toLowerCase().includes(q));
return scene ? { id: scene.id, title: scene.title, shots: scene.shots.length } : null;
const scene =
this._project.scenes.find((item) => item.id === query) ||
this._project.scenes.find((item) => item.title.toLowerCase() === q) ||
this._project.scenes.find((item) => item.title.toLowerCase().includes(q));
return scene
? { id: scene.id, title: scene.title, shots: scene.shots.length }
: null;
}
/**
@@ -765,8 +868,12 @@ export class SceneDirector {
running: this._running,
selectedSceneId: this._selectedSceneId,
selectedShotId: this._selectedShotId,
elapsedMs: this._activeRun ? Math.max(0, Date.now() - Date.parse(this._activeRun.startedAt)) : null,
estimatedDurationMs: this._activeRun ? Math.round(this._activeRun.estimatedDurationSec * 1000) : null,
elapsedMs: this._activeRun
? Math.max(0, Date.now() - Date.parse(this._activeRun.startedAt))
: null,
estimatedDurationMs: this._activeRun
? Math.round(this._activeRun.estimatedDurationSec * 1000)
: null,
sceneCount: this._project.scenes.length,
};
}
@@ -792,14 +899,18 @@ export class SceneDirector {
* @returns {Promise<{started: boolean, reason?: string, shots?: number}>}
*/
startScene(sceneId, options) {
if (this._destroyed) return Promise.resolve({ started: false, reason: 'destroyed' });
if (this._destroyed)
return Promise.resolve({ started: false, reason: 'destroyed' });
return this._trackWork(this._startScene(sceneId, options));
}
async _startScene(sceneId, { single = false } = {}) {
if (this._running) return { started: false, reason: 'already-running' };
const queue = this._buildPlaybackQueue(sceneId || this._selectedSceneId || this._project.scenes[0]?.id, { single });
const queue = this._buildPlaybackQueue(
sceneId || this._selectedSceneId || this._project.scenes[0]?.id,
{ single },
);
if (!queue.length) {
this._updateStatus('No shots to run');
return { started: false, reason: 'no-shots' };
@@ -872,7 +983,9 @@ export class SceneDirector {
this._renderSceneSelect();
this._renderShotList();
this._updateStatus(`Running ${idx + 1}/${queue.length}: ${scene.title} / ${shot.title}`);
this._updateStatus(
`Running ${idx + 1}/${queue.length}: ${scene.title} / ${shot.title}`,
);
this._updateRuntime(`${scene.title} · ${shot.title}`);
this._logEvent('shot_start', {
@@ -897,7 +1010,11 @@ export class SceneDirector {
if (token.cancelled) break;
await this._applyLayerStates(shot.layers || {}, token);
if (token.cancelled) break;
await this._flyCamera(shot.camera, shot.durationSec || DEFAULT_SHOT_DURATION_SEC, token);
await this._flyCamera(
shot.camera,
shot.durationSec || DEFAULT_SHOT_DURATION_SEC,
token,
);
if (token.cancelled) break;
// Hold on the final frame before transitioning to the next shot
await this._sleep((shot.holdSec || 0) * 1000, token);
@@ -917,7 +1034,9 @@ export class SceneDirector {
}
} catch (error) {
this._updateStatus(`Error: ${error.message || 'run failed'}`);
this._logEvent('scene_run_error', { message: error.message || 'unknown error' });
this._logEvent('scene_run_error', {
message: error.message || 'unknown error',
});
} finally {
this._finishRun();
}
@@ -930,13 +1049,17 @@ export class SceneDirector {
async runNextScene() {
if (this._destroyed || this._running) return;
const queue = this._buildPlaybackQueue(this._selectedSceneId || this._project.scenes[0]?.id);
const queue = this._buildPlaybackQueue(
this._selectedSceneId || this._project.scenes[0]?.id,
);
if (!queue.length) return;
// Find the shot after the current selection, wrapping to the start
let next = queue[0];
if (this._selectedShotId) {
const idx = queue.findIndex((item) => item.shot.id === this._selectedShotId);
const idx = queue.findIndex(
(item) => item.shot.id === this._selectedShotId,
);
if (idx >= 0) next = queue[(idx + 1) % queue.length];
}
@@ -1064,13 +1187,24 @@ export class SceneDirector {
if (token?.cancelled) return abort();
const signal = token?.signal;
const registered = new Set(this.dataManager.getAll().map((layer) => layer.id));
for (const { id, enabled, params } of sceneLayerPlan(targetStates, registered)) {
const settled = await this.dataManager.setEnabled(id, enabled, signal ? { signal } : undefined);
const registered = new Set(
this.dataManager.getAll().map((layer) => layer.id),
);
for (const { id, enabled, params } of sceneLayerPlan(
targetStates,
registered,
)) {
const settled = await this.dataManager.setEnabled(
id,
enabled,
signal ? { signal } : undefined,
);
if (token?.cancelled) return abort();
if (settled === false) {
refused.push(id);
console.warn(`[Scenes] Layer refused: ${id} → ${enabled ? 'on' : 'off'}`);
console.warn(
`[Scenes] Layer refused: ${id} → ${enabled ? 'on' : 'off'}`,
);
continue;
}
applied.push(id);
@@ -1105,7 +1239,8 @@ export class SceneDirector {
*/
async _exitIsolatingContextMode() {
// Older/headless style managers may predate the Context facade.
if (typeof this.styleManager?.getContextModeState !== 'function') return false;
if (typeof this.styleManager?.getContextModeState !== 'function')
return false;
if (typeof this.styleManager?.setContextMode !== 'function') return false;
const state = this.styleManager.getContextModeState() || {};
@@ -1115,9 +1250,17 @@ export class SceneDirector {
const result = await this.styleManager.setContextMode('off');
if (result && result.ok === false) {
console.warn(`[Scenes] Could not exit ${mode}:`, result.error || 'unknown reason');
this._updateStatus(`Could not exit ${mode} — scene layers may be refused`);
this._logEvent('context_mode_exit_failed', { mode, error: result.error || null });
console.warn(
`[Scenes] Could not exit ${mode}:`,
result.error || 'unknown reason',
);
this._updateStatus(
`Could not exit ${mode} — scene layers may be refused`,
);
this._logEvent('context_mode_exit_failed', {
mode,
error: result.error || null,
});
return false;
}
this._logEvent('context_mode_exited', { mode });
@@ -1140,11 +1283,14 @@ export class SceneDirector {
// a free-text search the shot has already flown away from.
this.styleManager?.clearSearchedLocation?.();
const duration = Math.max(0.2, Number(durationSec) || DEFAULT_SHOT_DURATION_SEC);
const duration = Math.max(
0.2,
Number(durationSec) || DEFAULT_SHOT_DURATION_SEC,
);
const destination = Cesium.Cartesian3.fromDegrees(
cameraState.lon,
cameraState.lat,
cameraState.alt
cameraState.alt,
);
await new Promise((resolve) => {
@@ -1244,7 +1390,9 @@ export class SceneDirector {
* Editing controls are disabled during a run; stop is disabled when idle.
* @param {boolean} isRunning
*/
_setButtons(isRunning) { this._publish({ type: 'buttons-changed', running: isRunning }); }
_setButtons(isRunning) {
this._publish({ type: 'buttons-changed', running: isRunning });
}
_setPlaybackActive(active) {
this._presentation.playbackActive = active;
@@ -1297,5 +1445,4 @@ export class SceneDirector {
payload: payload || null,
});
}
}
+240 -24
View File
@@ -22,11 +22,56 @@ export const SCENE_RECIPES = [
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 },
{
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,
},
],
},
{
@@ -55,11 +100,56 @@ export const SCENE_RECIPES = [
},
},
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 },
{
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,
},
],
},
{
@@ -88,10 +178,46 @@ export const SCENE_RECIPES = [
},
},
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 },
{
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,
},
],
},
{
@@ -120,11 +246,56 @@ export const SCENE_RECIPES = [
},
},
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 },
{
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,
},
],
},
{
@@ -152,11 +323,56 @@ export const SCENE_RECIPES = [
},
},
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 },
{
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,
},
],
},
];
+18 -9
View File
@@ -80,7 +80,8 @@ export const SCENE_SELECTION_PARAM_PATTERN =
*/
export function stripSceneTrackingParams(params) {
if (!params || typeof params !== 'object') return undefined;
if (!SCENE_TRACKING_PARAM_KEYS.some((key) => Object.hasOwn(params, key))) return params;
if (!SCENE_TRACKING_PARAM_KEYS.some((key) => Object.hasOwn(params, key)))
return params;
const kept = {};
for (const [key, value] of Object.entries(params)) {
@@ -122,10 +123,12 @@ export const SCENE_EXCLUSIVITY_PROBE_LAYER_ID = '__scene-exclusivity-probe__';
*/
export function sceneRequiresContextModeExit(contextMode) {
if (!contextMode) return false;
return contextLayerEnableBlockReason({
contextMode,
change: { layerId: SCENE_EXCLUSIVITY_PROBE_LAYER_ID, enabled: true },
}) !== null;
return (
contextLayerEnableBlockReason({
contextMode,
change: { layerId: SCENE_EXCLUSIVITY_PROBE_LAYER_ID, enabled: true },
}) !== null
);
}
/**
@@ -144,9 +147,12 @@ export function sceneRequiresContextModeExit(contextMode) {
* @returns {Array<{ id: string, enabled: boolean, params: Object|undefined }>}
*/
export function sceneLayerPlan(targetStates, registeredIds) {
const known = registeredIds instanceof Set
? registeredIds
: (registeredIds ? new Set(registeredIds) : null);
const known =
registeredIds instanceof Set
? registeredIds
: registeredIds
? new Set(registeredIds)
: null;
const plan = [];
for (const [id, target] of Object.entries(targetStates || {})) {
@@ -154,7 +160,10 @@ export function sceneLayerPlan(targetStates, registeredIds) {
plan.push({
id,
enabled: !!(target && target.enabled),
params: target && target.params ? stripSceneTrackingParams(target.params) : undefined,
params:
target && target.params
? stripSceneTrackingParams(target.params)
: undefined,
});
}
return plan;