diff --git a/web/src/pages/app/modules/preview.ts b/web/src/pages/app/modules/preview.ts index d96aaf9..525a538 100644 --- a/web/src/pages/app/modules/preview.ts +++ b/web/src/pages/app/modules/preview.ts @@ -868,15 +868,36 @@ function resetPreviewPlaybackScene() { } function buildPreviewFrameTimes(frames: P_OPERATION["OPERATION"]["frames"]) { + const parsedTimes = frames.map((frame) => Number(frame.time)); + if (shouldTreatFrameTimeAsInterval(parsedTimes)) { + let accumulatedTime = 0; + return parsedTimes.map((time, index) => { + const intervalMs = Number.isFinite(time) + ? Math.max(0, time * SECOND_MS) + : DEFAULT_PREVIEW_FRAME_INTERVAL_MS; + accumulatedTime += index === 0 ? 0 : intervalMs; + return accumulatedTime; + }); + } + let previousTime = 0; - return frames.map((frame, index) => { - const parsed = Number(frame.time); + return parsedTimes.map((parsed, index) => { const timeMs = Number.isFinite(parsed) ? Math.max(0, parsed * SECOND_MS) : index * DEFAULT_PREVIEW_FRAME_INTERVAL_MS; previousTime = index === 0 ? timeMs : Math.max(previousTime + 1, timeMs); return previousTime; }); } +function shouldTreatFrameTimeAsInterval(times: number[]) { + const validTimes = times.filter(Number.isFinite); + if (validTimes.length < 2) return false; + let repeatedCount = 0; + for (let index = 1; index < validTimes.length; index += 1) { + if (Math.abs(validTimes[index] - validTimes[index - 1]) < 0.000001) repeatedCount += 1; + } + return repeatedCount >= Math.max(1, Math.floor(validTimes.length * 0.6)); +} + function resolvePreviewFrameIndex(currentTimeMs: number, frameTimesMs: number[]) { let index = -1; for (let i = 0; i < frameTimesMs.length; i += 1) {