diff --git a/src/components/canvas/players/player.ts b/src/components/canvas/players/player.ts index 1624730c..40e00037 100644 --- a/src/components/canvas/players/player.ts +++ b/src/components/canvas/players/player.ts @@ -19,7 +19,7 @@ import { import { Pointer } from "@inputs/pointer"; import { type Size, type Vector } from "@layouts/geometry"; import { relativeToAbsolute, absoluteToRelative } from "@layouts/position-builder"; -import { type Clip, type ResolvedClip, type Keyframe } from "@schemas"; +import { type Clip, type ResolvedClip } from "@schemas"; import * as pixi from "pixi.js"; import { Entity } from "../../../core/shared/entity"; @@ -222,13 +222,13 @@ export abstract class Player extends Entity { this.rotationKeyframeBuilder.addLayer(transitionSet.out.rotationKeyframes); // Mask keyframes (reveal effect) - const maskXKeyframes: Keyframe[] = [...transitionSet.in.maskXKeyframes, ...transitionSet.out.maskXKeyframes]; + const maskXKeyframes = [...transitionSet.in.maskXKeyframes, ...transitionSet.out.maskXKeyframes]; if (maskXKeyframes.length) { this.maskXKeyframeBuilder = new KeyframeBuilder(maskXKeyframes, length); } // Wipe brightness sweep (wipeLeft/wipeRight) — driven through WipeFilter, not a mask. - const brightnessKeyframes: Keyframe[] = [...transitionSet.in.brightnessKeyframes, ...transitionSet.out.brightnessKeyframes]; + const brightnessKeyframes = [...transitionSet.in.brightnessKeyframes, ...transitionSet.out.brightnessKeyframes]; if (brightnessKeyframes.length) { this.wipeBrightnessBuilder = new KeyframeBuilder(brightnessKeyframes, length); this.wipeInFromRight = transitionSet.in.wipeFromRight; diff --git a/src/core/animations/composed-keyframe-builder.ts b/src/core/animations/composed-keyframe-builder.ts index 0fd009c0..61413f39 100644 --- a/src/core/animations/composed-keyframe-builder.ts +++ b/src/core/animations/composed-keyframe-builder.ts @@ -1,4 +1,4 @@ -import { type Keyframe } from "@schemas"; +import { type AnimationKeyframe } from "@schemas"; import { KeyframeBuilder } from "./keyframe-builder"; @@ -31,7 +31,7 @@ export class ComposedKeyframeBuilder { * For additive mode, keyframes should represent deltas (e.g., 0 → 0.1 means "move by 0.1") * For multiplicative mode, keyframes should represent factors (e.g., 1 → 1.3 means "scale by 1.3x") */ - addLayer(keyframes: Keyframe[]): void { + addLayer(keyframes: AnimationKeyframe[]): void { if (keyframes.length === 0) return; const neutralValue = this.mode === "additive" ? 0 : 1; diff --git a/src/core/animations/keyframe-builder.ts b/src/core/animations/keyframe-builder.ts index 21c1b32d..bcd6cef6 100644 --- a/src/core/animations/keyframe-builder.ts +++ b/src/core/animations/keyframe-builder.ts @@ -1,4 +1,4 @@ -import { type Keyframe, type NumericKeyframe } from "@schemas"; +import { type AnimationKeyframe, type NumericKeyframe } from "@schemas"; import { CurveInterpolator } from "./curve-interpolator"; @@ -18,7 +18,7 @@ export class KeyframeBuilder { private cachedIndex = 0; - constructor(value: Keyframe[] | number, length: number, initialValue = 0) { + constructor(value: AnimationKeyframe[] | number, length: number, initialValue = 0) { this.property = this.createKeyframes(value, length, initialValue); this.length = length; @@ -110,7 +110,7 @@ export class KeyframeBuilder { return -1; } - private createKeyframes(value: Keyframe[] | number, length: number, initialValue = 0): NumericKeyframe[] { + private createKeyframes(value: AnimationKeyframe[] | number, length: number, initialValue = 0): NumericKeyframe[] { if (typeof value === "number") { return [{ start: 0, length, from: value, to: value }]; } @@ -127,9 +127,9 @@ export class KeyframeBuilder { return this.insertFillerKeyframes(normalizedKeyframes, length, initialValue); } - private createNormalizedKeyframes(keyframes: Keyframe[]): NumericKeyframe[] { + private createNormalizedKeyframes(keyframes: AnimationKeyframe[]): NumericKeyframe[] { return keyframes - .filter((kf): kf is Keyframe & { start: number; length: number } => typeof kf.start === "number" && typeof kf.length === "number") + .filter((kf): kf is AnimationKeyframe & { start: number; length: number } => typeof kf.start === "number" && typeof kf.length === "number") .sort((a, b) => a.start - b.start) .map(keyframe => ({ start: keyframe.start, diff --git a/src/core/animations/transition-preset-builder.ts b/src/core/animations/transition-preset-builder.ts index 944bb726..2dcbec68 100644 --- a/src/core/animations/transition-preset-builder.ts +++ b/src/core/animations/transition-preset-builder.ts @@ -1,14 +1,14 @@ -import { type ResolvedClip, type Keyframe } from "@schemas"; +import { type ResolvedClip, type AnimationKeyframe } from "@schemas"; export type TransitionKeyframeSet = { - offsetXKeyframes: Keyframe[]; - offsetYKeyframes: Keyframe[]; - opacityKeyframes: Keyframe[]; - scaleKeyframes: Keyframe[]; - rotationKeyframes: Keyframe[]; - maskXKeyframes: Keyframe[]; + offsetXKeyframes: AnimationKeyframe[]; + offsetYKeyframes: AnimationKeyframe[]; + opacityKeyframes: AnimationKeyframe[]; + scaleKeyframes: AnimationKeyframe[]; + rotationKeyframes: AnimationKeyframe[]; + maskXKeyframes: AnimationKeyframe[]; /** Wipe brightness sweep (+1 hidden → −1 revealed), applied through WipeFilter. */ - brightnessKeyframes: Keyframe[]; + brightnessKeyframes: AnimationKeyframe[]; /** Wipe reveal direction for this phase: true = from the right edge inward, false = from the left. */ wipeFromRight: boolean; }; diff --git a/src/core/schemas/index.ts b/src/core/schemas/index.ts index ac339e8d..4d14c6aa 100644 --- a/src/core/schemas/index.ts +++ b/src/core/schemas/index.ts @@ -122,13 +122,16 @@ export type ExtendedCaptionAsset = CaptionAsset & { // ─── Internal Animation Types ─────────────────────────────────────────────── // Keyframes with all required fields and numeric values for animation interpolation +/** A tween as the animation code reads it. */ +export type AnimationKeyframe = Tween; + export interface NumericKeyframe { start: number; length: number; from: number; to: number; interpolation?: Tween["interpolation"]; - easing?: Tween["easing"]; + easing?: AnimationKeyframe["easing"]; } // ─── Zod Schemas (for validation) ──────────────────────────────────────────