mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
style: format remaining owned runtime modules
This commit is contained in:
1 parent
ae99843c14
commit
2aca7aecbb
94 files changed
+8865
-3151
No files matched your search
+223
-76
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user