diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-29 10:37:39 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-05-02 03:27:23 +0200 |
| commit | 401cc35743aafc4c8bdfb8055501650390bde88b (patch) | |
| tree | 98385fb2f252ff6bb227a844d96b664a8fe87835 /apps/web/src/animation/interpolation.ts | |
| parent | b8d08df244b97b1d3131cb2d076166838189eeb0 (diff) | |
| download | opencut-401cc35743aafc4c8bdfb8055501650390bde88b.tar.gz | |
refactor: animate params over time
Diffstat (limited to 'apps/web/src/animation/interpolation.ts')
| -rw-r--r-- | apps/web/src/animation/interpolation.ts | 91 |
1 files changed, 66 insertions, 25 deletions
diff --git a/apps/web/src/animation/interpolation.ts b/apps/web/src/animation/interpolation.ts index 5d5212a6..cdb8bcc9 100644 --- a/apps/web/src/animation/interpolation.ts +++ b/apps/web/src/animation/interpolation.ts @@ -1,13 +1,14 @@ import type { AnimationChannel, AnimationInterpolation, - AnimationValue, + Channel, DiscreteAnimationChannel, DiscreteValue, ScalarAnimationChannel, ScalarAnimationKey, ScalarSegmentType, } from "@/animation/types"; +import type { ParamValue } from "@/params"; import { mediaTime } from "@/wasm"; import { getBezierPoint, @@ -111,7 +112,7 @@ function normalizeScalarKey({ }; } -function normalizeScalarChannel({ +export function normalizeScalarChannel({ channel, }: { channel: ScalarAnimationChannel; @@ -154,17 +155,11 @@ function normalizeScalarChannel({ }; } -export function normalizeChannel<TChannel extends AnimationChannel>({ +export function normalizeDiscreteChannel({ channel, }: { - channel: TChannel; -}): TChannel { - if (channel.kind === "scalar") { - return normalizeScalarChannel({ - channel, - }) as TChannel; - } - + channel: DiscreteAnimationChannel; +}): DiscreteAnimationChannel { return { ...channel, keys: [...channel.keys].sort((leftKeyframe, rightKeyframe) => @@ -173,7 +168,39 @@ export function normalizeChannel<TChannel extends AnimationChannel>({ rightTime: rightKeyframe.time, }), ), - } as TChannel; + }; +} + +export function isScalarChannel(channel: AnimationChannel): channel is ScalarAnimationChannel { + return ( + "extrapolation" in channel || + channel.keys.some((keyframe) => "segmentToNext" in keyframe) + ); +} + +export function normalizeChannel({ + channel, +}: { + channel: ScalarAnimationChannel; +}): ScalarAnimationChannel; +export function normalizeChannel({ + channel, +}: { + channel: DiscreteAnimationChannel; +}): DiscreteAnimationChannel; +export function normalizeChannel({ + channel, +}: { + channel: AnimationChannel; +}): AnimationChannel; +export function normalizeChannel({ + channel, +}: { + channel: AnimationChannel; +}): AnimationChannel { + return isScalarChannel(channel) + ? normalizeScalarChannel({ channel }) + : normalizeDiscreteChannel({ channel }); } function extrapolateScalarEdge({ @@ -216,7 +243,7 @@ export function getScalarChannelValueAtTime({ time, fallbackValue, }: { - channel: ScalarAnimationChannel | undefined; + channel: Channel<number> | undefined; time: number; fallbackValue: number; }): number { @@ -224,9 +251,7 @@ export function getScalarChannelValueAtTime({ return fallbackValue; } - const normalizedChannel = normalizeChannel({ - channel, - }); + const normalizedChannel = normalizeScalarChannel({ channel }); const firstKey = normalizedChannel.keys[0]; const lastKey = normalizedChannel.keys[normalizedChannel.keys.length - 1]; if (!firstKey || !lastKey) { @@ -328,7 +353,7 @@ export function getDiscreteChannelValueAtTime({ time, fallbackValue, }: { - channel: DiscreteAnimationChannel | undefined; + channel: Channel<DiscreteValue> | undefined; time: number; fallbackValue: DiscreteValue; }): DiscreteValue { @@ -336,9 +361,7 @@ export function getDiscreteChannelValueAtTime({ return fallbackValue; } - const normalizedChannel = normalizeChannel({ - channel, - }); + const normalizedChannel = normalizeDiscreteChannel({ channel }); let currentValue = fallbackValue; for (const key of normalizedChannel.keys) { if (time < key.time) { @@ -354,16 +377,34 @@ export function getChannelValueAtTime({ time, fallbackValue, }: { + channel: Channel<number> | undefined; + time: number; + fallbackValue: number; +}): number; +export function getChannelValueAtTime<TValue extends DiscreteValue>({ + channel, + time, + fallbackValue, +}: { + channel: DiscreteAnimationChannel | undefined; + time: number; + fallbackValue: TValue; +}): TValue; +export function getChannelValueAtTime({ + channel, + time, + fallbackValue, +}: { channel: AnimationChannel | undefined; time: number; - fallbackValue: AnimationValue; -}): AnimationValue { + fallbackValue: ParamValue; +}): ParamValue { if (!channel || channel.keys.length === 0) { return fallbackValue; } - if (channel.kind === "scalar") { - return typeof fallbackValue === "number" + if (typeof fallbackValue === "number") { + return isScalarChannel(channel) ? getScalarChannelValueAtTime({ channel, time, @@ -377,7 +418,7 @@ export function getChannelValueAtTime({ } return getDiscreteChannelValueAtTime({ - channel, + channel: isScalarChannel(channel) ? undefined : channel, time, fallbackValue, }); |
