From 49426f19cd8eaed7cf6c47999b66fee7ee637a56 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 27 Feb 2026 16:33:57 +0100 Subject: feat: implement keyframe animation system Add keyframe support for transform, opacity, and volume properties. Includes animation engine (interpolation, mutations, resolvers), timeline markers with selection/snapping, properties panel toggles, keyframe-aware renderer, and full undo/redo command support. Also refactor element command constructors to object params, extract timeline pixel math to pixel-utils.ts, and update cursor rules. --- .../timeline/element/update-element-duration.ts | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'apps/web/src/lib/commands/timeline/element/update-element-duration.ts') diff --git a/apps/web/src/lib/commands/timeline/element/update-element-duration.ts b/apps/web/src/lib/commands/timeline/element/update-element-duration.ts index 6b3a860b..3366548d 100644 --- a/apps/web/src/lib/commands/timeline/element/update-element-duration.ts +++ b/apps/web/src/lib/commands/timeline/element/update-element-duration.ts @@ -1,28 +1,48 @@ import { Command } from "@/lib/commands/base-command"; import type { TimelineTrack } from "@/types/timeline"; import { EditorCore } from "@/core"; +import { clampAnimationsToDuration } from "@/lib/animation"; export class UpdateElementDurationCommand extends Command { private savedState: TimelineTrack[] | null = null; + private readonly trackId: string; + private readonly elementId: string; + private readonly duration: number; - constructor( - private trackId: string, - private elementId: string, - private duration: number, - ) { + constructor({ + trackId, + elementId, + duration, + }: { + trackId: string; + elementId: string; + duration: number; + }) { super(); + this.trackId = trackId; + this.elementId = elementId; + this.duration = duration; } execute(): void { const editor = EditorCore.getInstance(); this.savedState = editor.timeline.getTracks(); - const updatedTracks = this.savedState.map((t) => { - if (t.id !== this.trackId) return t; - const newElements = t.elements.map((el) => - el.id === this.elementId ? { ...el, duration: this.duration } : el, + const updatedTracks = this.savedState.map((track) => { + if (track.id !== this.trackId) return track; + const newElements = track.elements.map((element) => + element.id === this.elementId + ? { + ...element, + duration: this.duration, + animations: clampAnimationsToDuration({ + animations: element.animations, + duration: this.duration, + }), + } + : element, ); - return { ...t, elements: newElements } as typeof t; + return { ...track, elements: newElements } as typeof track; }); editor.timeline.updateTracks(updatedTracks); -- cgit v1.3.1