diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
| commit | 3e89d2998588f8e35c524e523ba2ee853f0f6475 (patch) | |
| tree | 57221f96c1259b3b07e3ddf8c1adefc502b9d8eb /apps/web/src/lib/timeline/update-pipeline.ts | |
| parent | 729d10592f4e802f91c555c309ff3ba4b119f843 (diff) | |
| download | opencut-3e89d2998588f8e35c524e523ba2ee853f0f6475.tar.gz | |
refactor: restructure files to their domains, new preview overlay system, and dep graph
Diffstat (limited to 'apps/web/src/lib/timeline/update-pipeline.ts')
| -rw-r--r-- | apps/web/src/lib/timeline/update-pipeline.ts | 211 |
1 files changed, 0 insertions, 211 deletions
diff --git a/apps/web/src/lib/timeline/update-pipeline.ts b/apps/web/src/lib/timeline/update-pipeline.ts deleted file mode 100644 index 2be73441..00000000 --- a/apps/web/src/lib/timeline/update-pipeline.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { clampAnimationsToDuration } from "@/lib/animation"; -import { - clampRetimeRate, - getSourceSpanAtClipTime, - getTimelineDurationForSourceSpan, -} from "@/lib/retime"; -import type { RetimeConfig, SceneTracks, TimelineElement } from "@/lib/timeline"; -import { isRetimableElement } from "@/lib/timeline"; - -type ElementUpdateField = keyof TimelineElement | string; - -export interface ElementUpdateContext { - tracks: SceneTracks; - trackId: string; -} - -interface ElementUpdateRuleResult { - element: TimelineElement; - changedFields?: ElementUpdateField[]; -} - -interface ElementUpdateRuleParams { - element: TimelineElement; - originalElement: TimelineElement; - patch: Partial<TimelineElement>; - context: ElementUpdateContext; -} - -interface ElementUpdateRule { - triggers: ElementUpdateField[]; - apply: (params: ElementUpdateRuleParams) => ElementUpdateRuleResult; -} - -const deriveRules: ElementUpdateRule[] = [ - { - triggers: ["retime"], - apply: ({ element, originalElement, patch }) => { - if (!("retime" in patch) || !isRetimableElement(element)) { - return { element }; - } - - const nextRetime = patch.retime - ? { - ...patch.retime, - rate: clampRetimeRate({ rate: patch.retime.rate }), - } - : undefined; - - const sourceDuration = getSourceDuration({ - trimStart: originalElement.trimStart, - trimEnd: originalElement.trimEnd, - duration: originalElement.duration, - sourceDuration: isRetimableElement(originalElement) - ? originalElement.sourceDuration - : undefined, - retime: isRetimableElement(originalElement) - ? originalElement.retime - : undefined, - }); - const visibleSourceSpan = Math.max( - 0, - sourceDuration - element.trimStart - element.trimEnd, - ); - const nextDuration = getTimelineDurationForSourceSpan({ - sourceSpan: visibleSourceSpan, - retime: nextRetime, - }); - - return { - element: { - ...element, - retime: nextRetime, - duration: nextDuration, - }, - changedFields: ["retime", "duration"], - }; - }, - }, -]; - -const enforceRules: ElementUpdateRule[] = [ - { - triggers: ["duration"], - apply: ({ element }) => ({ - element: { - ...element, - animations: clampAnimationsToDuration({ - animations: element.animations, - duration: element.duration, - }), - }, - }), - }, - { - triggers: ["startTime"], - apply: ({ element, context }) => { - const requestedStartTime = Math.max(0, element.startTime); - if (context.trackId !== context.tracks.main.id) { - return { - element: { - ...element, - startTime: requestedStartTime, - }, - }; - } - - const earliestElement = context.tracks.main.elements - .filter((candidate) => candidate.id !== element.id) - .reduce<TimelineElement | null>((earliest, candidate) => { - if (!earliest || candidate.startTime < earliest.startTime) { - return candidate; - } - return earliest; - }, null); - - return { - element: { - ...element, - startTime: - !earliestElement || requestedStartTime <= earliestElement.startTime - ? 0 - : requestedStartTime, - }, - }; - }, - }, -]; - -export function applyElementUpdate({ - element, - patch, - context, -}: { - element: TimelineElement; - patch: Partial<TimelineElement>; - context: ElementUpdateContext; -}): TimelineElement { - let nextElement = { ...element, ...patch } as TimelineElement; - const changedFields = new Set( - Object.keys(patch) as ElementUpdateField[], - ); - - for (const rule of deriveRules) { - if (!shouldApplyRule({ rule, changedFields })) { - continue; - } - - const result = rule.apply({ - element: nextElement, - originalElement: element, - patch, - context, - }); - nextElement = result.element; - for (const field of result.changedFields ?? []) { - changedFields.add(field); - } - } - - for (const rule of enforceRules) { - if (!shouldApplyRule({ rule, changedFields })) { - continue; - } - - nextElement = rule.apply({ - element: nextElement, - originalElement: element, - patch, - context, - }).element; - } - - return nextElement; -} - -function shouldApplyRule({ - rule, - changedFields, -}: { - rule: ElementUpdateRule; - changedFields: Set<ElementUpdateField>; -}): boolean { - return rule.triggers.some((trigger) => changedFields.has(trigger)); -} - -function getSourceDuration({ - trimStart, - trimEnd, - duration, - sourceDuration, - retime, -}: { - trimStart: number; - trimEnd: number; - duration: number; - sourceDuration?: number; - retime?: RetimeConfig; -}): number { - if (typeof sourceDuration === "number") { - return sourceDuration; - } - - return ( - trimStart + - getSourceSpanAtClipTime({ - clipTime: duration, - retime, - }) + - trimEnd - ); -} |
