From 3e89d2998588f8e35c524e523ba2ee853f0f6475 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Mon, 20 Apr 2026 11:31:17 +0200 Subject: refactor: restructure files to their domains, new preview overlay system, and dep graph --- .../commands/timeline/element/keyframes/index.ts | 6 -- .../keyframes/remove-effect-param-keyframe.ts | 69 ------------- .../timeline/element/keyframes/remove-keyframe.ts | 107 --------------------- .../timeline/element/keyframes/retime-keyframe.ts | 75 --------------- .../keyframes/update-scalar-keyframe-curve.ts | 85 ---------------- .../keyframes/upsert-effect-param-keyframe.ts | 104 -------------------- .../timeline/element/keyframes/upsert-keyframe.ts | 96 ------------------ 7 files changed, 542 deletions(-) delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/index.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/remove-effect-param-keyframe.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/remove-keyframe.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/retime-keyframe.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/update-scalar-keyframe-curve.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/upsert-effect-param-keyframe.ts delete mode 100644 apps/web/src/lib/commands/timeline/element/keyframes/upsert-keyframe.ts (limited to 'apps/web/src/lib/commands/timeline/element/keyframes') diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/index.ts b/apps/web/src/lib/commands/timeline/element/keyframes/index.ts deleted file mode 100644 index 319a827b..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from "./remove-effect-param-keyframe"; -export * from "./remove-keyframe"; -export * from "./retime-keyframe"; -export * from "./update-scalar-keyframe-curve"; -export * from "./upsert-effect-param-keyframe"; -export * from "./upsert-keyframe"; diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/remove-effect-param-keyframe.ts b/apps/web/src/lib/commands/timeline/element/keyframes/remove-effect-param-keyframe.ts deleted file mode 100644 index b1ef4aef..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/remove-effect-param-keyframe.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { EditorCore } from "@/core"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { removeEffectParamKeyframe } from "@/lib/animation/effect-param-channel"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import { isVisualElement } from "@/lib/timeline/element-utils"; -import type { SceneTracks } from "@/lib/timeline"; - -export class RemoveEffectParamKeyframeCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly effectId: string; - private readonly paramKey: string; - private readonly keyframeId: string; - - constructor({ - trackId, - elementId, - effectId, - paramKey, - keyframeId, - }: { - trackId: string; - elementId: string; - effectId: string; - paramKey: string; - keyframeId: string; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.effectId = effectId; - this.paramKey = paramKey; - this.keyframeId = keyframeId; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - elementPredicate: isVisualElement, - update: (element) => { - const animations = removeEffectParamKeyframe({ - animations: element.animations, - effectId: this.effectId, - paramKey: this.paramKey, - keyframeId: this.keyframeId, - }); - return { ...element, animations }; - }, - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/remove-keyframe.ts b/apps/web/src/lib/commands/timeline/element/keyframes/remove-keyframe.ts deleted file mode 100644 index 3c3d1c6b..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/remove-keyframe.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { EditorCore } from "@/core"; -import { - hasKeyframesForPath, - removeElementKeyframe, - resolveAnimationTarget, -} from "@/lib/animation"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import type { AnimationPath, AnimationValue } from "@/lib/animation/types"; -import type { SceneTracks, TimelineElement } from "@/lib/timeline"; - -function removeKeyframeAndPersist({ - element, - propertyPath, - keyframeId, - valueAtPlayhead, -}: { - element: TimelineElement; - propertyPath: AnimationPath; - keyframeId: string; - valueAtPlayhead: AnimationValue | null; -}): TimelineElement { - const target = resolveAnimationTarget({ element, path: propertyPath }); - if (!target) { - return element; - } - - const nextAnimations = removeElementKeyframe({ - animations: element.animations, - propertyPath, - keyframeId, - }); - - const isChannelNowEmpty = !hasKeyframesForPath({ - animations: nextAnimations, - propertyPath, - }); - - // When clearing all keyframes, preserve the value at the playhead (what the user was seeing) - const shouldPersistToBase = isChannelNowEmpty && valueAtPlayhead !== null; - - const baseElement = shouldPersistToBase - ? target.setBaseValue({ value: valueAtPlayhead }) - : element; - - return { ...baseElement, animations: nextAnimations }; -} - -export class RemoveKeyframeCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly propertyPath: AnimationPath; - private readonly keyframeId: string; - private readonly valueAtPlayhead: AnimationValue | null; - - constructor({ - trackId, - elementId, - propertyPath, - keyframeId, - valueAtPlayhead, - }: { - trackId: string; - elementId: string; - propertyPath: AnimationPath; - keyframeId: string; - valueAtPlayhead: AnimationValue | null; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.propertyPath = propertyPath; - this.keyframeId = keyframeId; - this.valueAtPlayhead = valueAtPlayhead; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - update: (element) => - removeKeyframeAndPersist({ - element, - propertyPath: this.propertyPath, - keyframeId: this.keyframeId, - valueAtPlayhead: this.valueAtPlayhead, - }), - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/retime-keyframe.ts b/apps/web/src/lib/commands/timeline/element/keyframes/retime-keyframe.ts deleted file mode 100644 index ad7f5651..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/retime-keyframe.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { EditorCore } from "@/core"; -import { resolveAnimationTarget, retimeElementKeyframe } from "@/lib/animation"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import type { AnimationPath } from "@/lib/animation/types"; -import type { SceneTracks } from "@/lib/timeline"; - -export class RetimeKeyframeCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly propertyPath: AnimationPath; - private readonly keyframeId: string; - private readonly nextTime: number; - - constructor({ - trackId, - elementId, - propertyPath, - keyframeId, - nextTime, - }: { - trackId: string; - elementId: string; - propertyPath: AnimationPath; - keyframeId: string; - nextTime: number; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.propertyPath = propertyPath; - this.keyframeId = keyframeId; - this.nextTime = nextTime; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - update: (element) => { - if (!resolveAnimationTarget({ element, path: this.propertyPath })) { - return element; - } - - const boundedTime = Math.max(0, Math.min(this.nextTime, element.duration)); - return { - ...element, - animations: retimeElementKeyframe({ - animations: element.animations, - propertyPath: this.propertyPath, - keyframeId: this.keyframeId, - time: boundedTime, - }), - }; - }, - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/update-scalar-keyframe-curve.ts b/apps/web/src/lib/commands/timeline/element/keyframes/update-scalar-keyframe-curve.ts deleted file mode 100644 index 9a4c2304..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/update-scalar-keyframe-curve.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { EditorCore } from "@/core"; -import { - resolveAnimationTarget, - updateScalarKeyframeCurve, -} from "@/lib/animation"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import type { - AnimationPath, - ScalarCurveKeyframePatch, -} from "@/lib/animation/types"; -import type { SceneTracks } from "@/lib/timeline"; - -export class UpdateScalarKeyframeCurveCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly propertyPath: AnimationPath; - private readonly componentKey: string; - private readonly keyframeId: string; - private readonly patch: ScalarCurveKeyframePatch; - - constructor({ - trackId, - elementId, - propertyPath, - componentKey, - keyframeId, - patch, - }: { - trackId: string; - elementId: string; - propertyPath: AnimationPath; - componentKey: string; - keyframeId: string; - patch: ScalarCurveKeyframePatch; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.propertyPath = propertyPath; - this.componentKey = componentKey; - this.keyframeId = keyframeId; - this.patch = patch; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - update: (element) => { - if (!resolveAnimationTarget({ element, path: this.propertyPath })) { - return element; - } - - return { - ...element, - animations: updateScalarKeyframeCurve({ - animations: element.animations, - propertyPath: this.propertyPath, - componentKey: this.componentKey, - keyframeId: this.keyframeId, - patch: this.patch, - }), - }; - }, - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/upsert-effect-param-keyframe.ts b/apps/web/src/lib/commands/timeline/element/keyframes/upsert-effect-param-keyframe.ts deleted file mode 100644 index f436721a..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/upsert-effect-param-keyframe.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { EditorCore } from "@/core"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { - buildEffectParamPath, - resolveAnimationTarget, - upsertPathKeyframe, -} from "@/lib/animation"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import { isVisualElement } from "@/lib/timeline/element-utils"; -import type { AnimationInterpolation } from "@/lib/animation/types"; -import type { SceneTracks } from "@/lib/timeline"; - -export class UpsertEffectParamKeyframeCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly effectId: string; - private readonly paramKey: string; - private readonly time: number; - private readonly value: number | string | boolean; - private readonly interpolation: AnimationInterpolation | undefined; - private readonly keyframeId: string | undefined; - - constructor({ - trackId, - elementId, - effectId, - paramKey, - time, - value, - interpolation, - keyframeId, - }: { - trackId: string; - elementId: string; - effectId: string; - paramKey: string; - time: number; - value: number | string | boolean; - interpolation?: AnimationInterpolation; - keyframeId?: string; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.effectId = effectId; - this.paramKey = paramKey; - this.time = time; - this.value = value; - this.interpolation = interpolation; - this.keyframeId = keyframeId; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - elementPredicate: isVisualElement, - update: (element) => { - const boundedTime = Math.max(0, Math.min(this.time, element.duration)); - const propertyPath = buildEffectParamPath({ - effectId: this.effectId, - paramKey: this.paramKey, - }); - const target = resolveAnimationTarget({ - element, - path: propertyPath, - }); - if (!target) { - return element; - } - - const animations = upsertPathKeyframe({ - animations: element.animations, - propertyPath, - time: boundedTime, - value: this.value, - interpolation: this.interpolation, - keyframeId: this.keyframeId, - kind: target.kind, - defaultInterpolation: target.defaultInterpolation, - coerceValue: target.coerceValue, - }); - return { ...element, animations }; - }, - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} diff --git a/apps/web/src/lib/commands/timeline/element/keyframes/upsert-keyframe.ts b/apps/web/src/lib/commands/timeline/element/keyframes/upsert-keyframe.ts deleted file mode 100644 index f77e69b8..00000000 --- a/apps/web/src/lib/commands/timeline/element/keyframes/upsert-keyframe.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { EditorCore } from "@/core"; -import { Command, type CommandResult } from "@/lib/commands/base-command"; -import { resolveAnimationTarget, upsertPathKeyframe } from "@/lib/animation"; -import { updateElementInSceneTracks } from "@/lib/timeline"; -import type { SceneTracks } from "@/lib/timeline"; -import type { - AnimationPath, - AnimationInterpolation, - AnimationValue, -} from "@/lib/animation/types"; - -export class UpsertKeyframeCommand extends Command { - private savedState: SceneTracks | null = null; - private readonly trackId: string; - private readonly elementId: string; - private readonly propertyPath: AnimationPath; - private readonly time: number; - private readonly value: AnimationValue; - private readonly interpolation: AnimationInterpolation | undefined; - private readonly keyframeId: string | undefined; - - constructor({ - trackId, - elementId, - propertyPath, - time, - value, - interpolation, - keyframeId, - }: { - trackId: string; - elementId: string; - propertyPath: AnimationPath; - time: number; - value: AnimationValue; - interpolation?: AnimationInterpolation; - keyframeId?: string; - }) { - super(); - this.trackId = trackId; - this.elementId = elementId; - this.propertyPath = propertyPath; - this.time = time; - this.value = value; - this.interpolation = interpolation; - this.keyframeId = keyframeId; - } - - execute(): CommandResult | undefined { - const editor = EditorCore.getInstance(); - this.savedState = editor.scenes.getActiveScene().tracks; - - const updatedTracks = updateElementInSceneTracks({ - tracks: this.savedState, - trackId: this.trackId, - elementId: this.elementId, - update: (element) => { - const target = resolveAnimationTarget({ - element, - path: this.propertyPath, - }); - if (!target) { - return element; - } - - const boundedTime = Math.max(0, Math.min(this.time, element.duration)); - return { - ...element, - animations: upsertPathKeyframe({ - animations: element.animations, - propertyPath: this.propertyPath, - time: boundedTime, - value: this.value, - interpolation: this.interpolation, - keyframeId: this.keyframeId, - kind: target.kind, - defaultInterpolation: target.defaultInterpolation, - coerceValue: target.coerceValue, - }), - }; - }, - }); - - editor.timeline.updateTracks(updatedTracks); - return undefined; - } - - undo(): void { - if (!this.savedState) { - return; - } - - const editor = EditorCore.getInstance(); - editor.timeline.updateTracks(this.savedState); - } -} -- cgit v1.3.1