summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/ripple/apply.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-06 00:02:23 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-06 00:02:23 +0200
commit44d8c4c8764d49a8e8d0ae713432c07f07cb7597 (patch)
tree4657187279adb475ea710231feb3d0bd4add36ed /apps/web/src/lib/ripple/apply.ts
parent20235d0724a70e6787b6cbdbfa054b1c5d8f62e9 (diff)
downloadopencut-44d8c4c8764d49a8e8d0ae713432c07f07cb7597.tar.gz
refactor: unify element updates into pipeline and centralize ripple
Diffstat (limited to 'apps/web/src/lib/ripple/apply.ts')
-rw-r--r--apps/web/src/lib/ripple/apply.ts65
1 files changed, 65 insertions, 0 deletions
diff --git a/apps/web/src/lib/ripple/apply.ts b/apps/web/src/lib/ripple/apply.ts
new file mode 100644
index 00000000..098a0247
--- /dev/null
+++ b/apps/web/src/lib/ripple/apply.ts
@@ -0,0 +1,65 @@
+import type { TimelineTrack } from "@/lib/timeline/types";
+import { rippleShiftElements } from "./shift";
+
+export interface RippleAdjustment {
+ trackId: string;
+ afterTime: number;
+ shiftAmount: number;
+}
+
+export function applyRippleAdjustments({
+ tracks,
+ adjustments,
+}: {
+ tracks: TimelineTrack[];
+ adjustments: RippleAdjustment[];
+}): TimelineTrack[] {
+ if (adjustments.length === 0) {
+ return tracks;
+ }
+
+ const adjustmentsByTrack = new Map<string, RippleAdjustment[]>();
+ for (const adjustment of adjustments) {
+ const trackAdjustments = adjustmentsByTrack.get(adjustment.trackId) ?? [];
+ trackAdjustments.push(adjustment);
+ adjustmentsByTrack.set(adjustment.trackId, trackAdjustments);
+ }
+
+ return tracks.map((track) =>
+ applyTrackRippleAdjustments({
+ track,
+ adjustments: adjustmentsByTrack.get(track.id) ?? [],
+ }),
+ );
+}
+
+function applyTrackRippleAdjustments<
+ TElement extends TimelineTrack["elements"][number],
+ TTrack extends TimelineTrack & { elements: TElement[] },
+>({
+ track,
+ adjustments,
+}: {
+ track: TTrack;
+ adjustments: RippleAdjustment[];
+}): TTrack {
+ if (adjustments.length === 0) {
+ return track;
+ }
+
+ const sortedAdjustments = [...adjustments].sort(
+ (firstAdjustment, secondAdjustment) =>
+ secondAdjustment.afterTime - firstAdjustment.afterTime,
+ );
+
+ let elements: TElement[] = track.elements;
+ for (const adjustment of sortedAdjustments) {
+ elements = rippleShiftElements({
+ elements,
+ afterTime: adjustment.afterTime,
+ shiftAmount: adjustment.shiftAmount,
+ });
+ }
+
+ return { ...track, elements };
+}