OpenCut/apps/web/src/lib/animation/resolve.ts

131 lines
2.9 KiB
TypeScript

import type { AnimationPropertyPath, ElementAnimations } from "@/types/animation";
import type { Transform } from "@/types/timeline";
import { getColorValueAtTime, getNumberChannelValueAtTime } from "./interpolation";
import { getColorChannelForPath } from "./color-channel";
import { getNumberChannelForPath } from "./number-channel";
export function getElementLocalTime({
timelineTime,
elementStartTime,
elementDuration,
}: {
timelineTime: number;
elementStartTime: number;
elementDuration: number;
}): number {
const localTime = timelineTime - elementStartTime;
if (localTime <= 0) {
return 0;
}
if (localTime >= elementDuration) {
return elementDuration;
}
return localTime;
}
export function resolveTransformAtTime({
baseTransform,
animations,
localTime,
}: {
baseTransform: Transform;
animations: ElementAnimations | undefined;
localTime: number;
}): Transform {
const safeLocalTime = Math.max(0, localTime);
return {
position: {
x: getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "transform.position.x",
}),
time: safeLocalTime,
fallbackValue: baseTransform.position.x,
}),
y: getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "transform.position.y",
}),
time: safeLocalTime,
fallbackValue: baseTransform.position.y,
}),
},
scale: getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "transform.scale",
}),
time: safeLocalTime,
fallbackValue: baseTransform.scale,
}),
rotate: getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "transform.rotate",
}),
time: safeLocalTime,
fallbackValue: baseTransform.rotate,
}),
};
}
export function resolveOpacityAtTime({
baseOpacity,
animations,
localTime,
}: {
baseOpacity: number;
animations: ElementAnimations | undefined;
localTime: number;
}): number {
return getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "opacity",
}),
time: Math.max(0, localTime),
fallbackValue: baseOpacity,
});
}
export function resolveColorAtTime({
baseColor,
animations,
propertyPath,
localTime,
}: {
baseColor: string;
animations: ElementAnimations | undefined;
propertyPath: AnimationPropertyPath;
localTime: number;
}): string {
return getColorValueAtTime({
channel: getColorChannelForPath({ animations, propertyPath }),
time: Math.max(0, localTime),
fallbackValue: baseColor,
});
}
export function resolveVolumeAtTime({
baseVolume,
animations,
localTime,
}: {
baseVolume: number;
animations: ElementAnimations | undefined;
localTime: number;
}): number {
return getNumberChannelValueAtTime({
channel: getNumberChannelForPath({
animations,
propertyPath: "volume",
}),
time: Math.max(0, localTime),
fallbackValue: baseVolume,
});
}