diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-06 01:23:47 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-06 01:23:47 +0200 |
| commit | fcc09e80e253831a163e2e4941542e0b34f80740 (patch) | |
| tree | 4cc7aafd0756bb3fa23dfd41080237e462b5ecf2 /apps/web/src/lib/animation/resolve.ts | |
| parent | c56d6f8188cc1c0e72d75611269a8bda7b79e727 (diff) | |
| parent | dedb13546a16235e7d6649961d0c9b235f62aa34 (diff) | |
| download | opencut-fcc09e80e253831a163e2e4941542e0b34f80740.tar.gz | |
Merge branch 'temp'
Diffstat (limited to 'apps/web/src/lib/animation/resolve.ts')
| -rw-r--r-- | apps/web/src/lib/animation/resolve.ts | 311 |
1 files changed, 176 insertions, 135 deletions
diff --git a/apps/web/src/lib/animation/resolve.ts b/apps/web/src/lib/animation/resolve.ts index 5c356f28..67f4a487 100644 --- a/apps/web/src/lib/animation/resolve.ts +++ b/apps/web/src/lib/animation/resolve.ts @@ -1,135 +1,176 @@ -import type {
- AnimationPropertyPath,
- ElementAnimations,
-} from "@/lib/animation/types";
-import type { Transform } from "@/lib/rendering";
-import {
- getColorValueAtTime,
- getNumberChannelValueAtTime,
- getVectorChannelValueAtTime,
-} from "./interpolation";
-import { getColorChannelForPath } from "./color-channel";
-import { getNumberChannelForPath } from "./number-channel";
-import { getVectorChannelForPath } from "./vector-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: getVectorChannelValueAtTime({
- channel: getVectorChannelForPath({
- animations,
- propertyPath: "transform.position",
- }),
- time: safeLocalTime,
- fallbackValue: baseTransform.position,
- }),
- scaleX: getNumberChannelValueAtTime({
- channel: getNumberChannelForPath({
- animations,
- propertyPath: "transform.scaleX",
- }),
- time: safeLocalTime,
- fallbackValue: baseTransform.scaleX,
- }),
- scaleY: getNumberChannelValueAtTime({
- channel: getNumberChannelForPath({
- animations,
- propertyPath: "transform.scaleY",
- }),
- time: safeLocalTime,
- fallbackValue: baseTransform.scaleY,
- }),
- 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 resolveNumberAtTime({
- baseValue,
- animations,
- propertyPath,
- localTime,
-}: {
- baseValue: number;
- animations: ElementAnimations | undefined;
- propertyPath: AnimationPropertyPath;
- localTime: number;
-}): number {
- return getNumberChannelValueAtTime({
- channel: getNumberChannelForPath({ animations, propertyPath }),
- time: Math.max(0, localTime),
- fallbackValue: baseValue,
- });
-}
-
-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,
- });
-}
+import type { + AnimationColorPropertyPath, + AnimationNumericPropertyPath, + AnimationPath, + AnimationPropertyPath, + AnimationValueForPath, + ElementAnimations, +} from "@/lib/animation/types"; +import type { Transform } from "@/lib/rendering"; +import { + type AnimationComponentValue, + composeAnimationValue, + decomposeAnimationValue, +} from "./binding-values"; +import { + getChannelValueAtTime, +} from "./interpolation"; + +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: resolveAnimationPathValueAtTime({ + animations, + propertyPath: "transform.position", + localTime: safeLocalTime, + fallbackValue: baseTransform.position, + }), + scaleX: resolveAnimationPathValueAtTime({ + animations, + propertyPath: "transform.scaleX", + localTime: safeLocalTime, + fallbackValue: baseTransform.scaleX, + }), + scaleY: resolveAnimationPathValueAtTime({ + animations, + propertyPath: "transform.scaleY", + localTime: safeLocalTime, + fallbackValue: baseTransform.scaleY, + }), + rotate: resolveAnimationPathValueAtTime({ + animations, + propertyPath: "transform.rotate", + localTime: safeLocalTime, + fallbackValue: baseTransform.rotate, + }), + }; +} + +export function resolveOpacityAtTime({ + baseOpacity, + animations, + localTime, +}: { + baseOpacity: number; + animations: ElementAnimations | undefined; + localTime: number; +}): number { + return resolveAnimationPathValueAtTime({ + animations, + propertyPath: "opacity", + localTime: Math.max(0, localTime), + fallbackValue: baseOpacity, + }); +} + +export function resolveNumberAtTime({ + baseValue, + animations, + propertyPath, + localTime, +}: { + baseValue: number; + animations: ElementAnimations | undefined; + propertyPath: AnimationNumericPropertyPath; + localTime: number; +}): number { + return resolveAnimationPathValueAtTime({ + animations, + propertyPath, + localTime: Math.max(0, localTime), + fallbackValue: baseValue, + }); +} + +export function resolveColorAtTime({ + baseColor, + animations, + propertyPath, + localTime, +}: { + baseColor: string; + animations: ElementAnimations | undefined; + propertyPath: AnimationColorPropertyPath; + localTime: number; +}): string { + return resolveAnimationPathValueAtTime({ + animations, + propertyPath, + localTime: Math.max(0, localTime), + fallbackValue: baseColor, + }); +} + +export function resolveAnimationPathValueAtTime<TPath extends AnimationPath>({ + animations, + propertyPath, + localTime, + fallbackValue, +}: { + animations: ElementAnimations | undefined; + propertyPath: TPath; + localTime: number; + fallbackValue: AnimationValueForPath<TPath>; +}): AnimationValueForPath<TPath> { + const binding = animations?.bindings[propertyPath]; + if (!binding) { + return fallbackValue; + } + + const fallbackComponents = decomposeAnimationValue({ + kind: binding.kind, + value: fallbackValue, + }); + if (!fallbackComponents) { + return fallbackValue; + } + + const componentValues = Object.fromEntries( + binding.components.map((component) => { + const channel = animations?.channels[component.channelId]; + return [ + component.key, + getChannelValueAtTime({ + channel, + time: localTime, + fallbackValue: + fallbackComponents[component.key] ?? + (channel?.kind === "discrete" ? false : 0), + }), + ]; + }), + ) as Record<string, AnimationComponentValue | undefined>; + return (composeAnimationValue({ + binding, + componentValues, + }) ?? fallbackValue) as AnimationValueForPath<TPath>; +} |
