Files
DndGamePlayer/app/renderer/editor/graph/sceneCardById.ts
T
Ivan Fontosh 8f8eef53c9 feat(project): optimize image imports and converter
- Optimize imported scene preview images (smart WebP/JPEG/PNG, preserve alpha, keep pixel size)

- Update converter to re-encode existing image assets with same algorithm

- Improve import/export progress overlay and reduce presentation slide stutter

Made-with: Cursor
2026-04-23 17:59:57 +08:00

71 lines
2.4 KiB
TypeScript

import type { Project } from '../../../shared/types';
import type { SceneId } from '../../../shared/types/ids';
import type { SceneGraphSceneAudioSummary, SceneGraphSceneCard } from './SceneGraph';
export function stableSceneGraphAudios(
prevCard: SceneGraphSceneCard | undefined,
nextRaw: SceneGraphSceneAudioSummary[],
): readonly SceneGraphSceneAudioSummary[] {
if (!prevCard) return nextRaw;
const pa = prevCard.audios;
if (pa.length !== nextRaw.length) return nextRaw;
for (let i = 0; i < nextRaw.length; i++) {
const p = pa[i];
const n = nextRaw[i];
if (p?.assetId !== n?.assetId || p?.loop !== n?.loop || p?.autoplay !== n?.autoplay) return nextRaw;
}
return pa;
}
export function buildNextSceneCardById(
prevRecord: Record<SceneId, SceneGraphSceneCard>,
project: Project,
): Record<SceneId, SceneGraphSceneCard> {
const nextMap: Record<SceneId, SceneGraphSceneCard> = {};
for (const id of Object.keys(project.scenes) as SceneId[]) {
const s = project.scenes[id];
if (!s) continue;
const prevCard = prevRecord[id];
const nextAudiosRaw: SceneGraphSceneAudioSummary[] = s.media.audios.map((a) => ({
assetId: a.assetId,
loop: a.loop,
autoplay: a.autoplay,
}));
const audios = stableSceneGraphAudios(prevCard, nextAudiosRaw);
const loopVideo = s.settings.loopVideo;
if (
prevCard?.title === s.title &&
prevCard.previewAssetId === s.previewAssetId &&
prevCard.previewThumbAssetId === s.previewThumbAssetId &&
prevCard.previewAssetType === s.previewAssetType &&
prevCard.previewVideoAutostart === s.previewVideoAutostart &&
prevCard.previewRotationDeg === s.previewRotationDeg &&
prevCard.loopVideo === loopVideo &&
prevCard.audios === audios
) {
nextMap[id] = prevCard;
} else {
nextMap[id] = {
title: s.title,
previewAssetId: s.previewAssetId,
previewThumbAssetId: s.previewThumbAssetId,
previewAssetType: s.previewAssetType,
previewVideoAutostart: s.previewVideoAutostart,
previewRotationDeg: s.previewRotationDeg,
loopVideo,
audios,
};
}
}
const prevKeys = Object.keys(prevRecord);
const nextKeys = Object.keys(nextMap);
const reuseRecord =
prevKeys.length === nextKeys.length &&
nextKeys.every((k) => prevRecord[k as SceneId] === nextMap[k as SceneId]);
return reuseRecord ? prevRecord : nextMap;
}