summaryrefslogtreecommitdiff
path: root/apps/web/src/timeline/animation-targets.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/timeline/animation-targets.ts')
-rw-r--r--apps/web/src/timeline/animation-targets.ts214
1 files changed, 105 insertions, 109 deletions
diff --git a/apps/web/src/timeline/animation-targets.ts b/apps/web/src/timeline/animation-targets.ts
index f9d53fcc..4ee764b6 100644
--- a/apps/web/src/timeline/animation-targets.ts
+++ b/apps/web/src/timeline/animation-targets.ts
@@ -1,17 +1,9 @@
import type {
- AnimationBindingKind,
AnimationInterpolation,
AnimationPath,
- AnimationValue,
NumericSpec,
} from "@/animation/types";
import {
- coerceAnimationParamValue,
- getAnimationParamDefaultInterpolation,
- getAnimationParamNumericRange,
- getAnimationParamValueKind,
-} from "@/animation/animated-params";
-import {
parseEffectParamPath,
} from "@/animation/effect-param-channel";
import {
@@ -19,38 +11,97 @@ import {
} from "@/animation/graphic-param-channel";
import { effectsRegistry, registerDefaultEffects } from "@/effects";
import { getGraphicDefinition } from "@/graphics";
-import type { ParamDefinition } from "@/params";
+import {
+ coerceParamValue,
+ getParamDefaultInterpolation,
+ getParamChannelLayout,
+ getParamNumericRange,
+ type ParamChannelLayout,
+ type ParamDefinition,
+ type ParamValue,
+ type ParamValues,
+} from "@/params";
+import {
+ getElementParam,
+} from "@/params/registry";
import type { TimelineElement } from "@/timeline";
import { isVisualElement } from "@/timeline/element-utils";
-import { isAnimationPropertyPath } from "@/animation/path";
-import {
- coerceAnimationValueForProperty,
- getAnimationPropertyDefinition,
- getElementBaseValueForProperty,
- withElementBaseValueForProperty,
-} from "./animation-properties";
export interface AnimationPathDescriptor {
- kind: AnimationBindingKind;
+ channelLayout: ParamChannelLayout;
defaultInterpolation: AnimationInterpolation;
numericRanges?: Partial<Record<string, NumericSpec>>;
- coerceValue: ({ value }: { value: AnimationValue }) => AnimationValue | null;
- getBaseValue: () => AnimationValue | null;
- setBaseValue: ({ value }: { value: AnimationValue }) => TimelineElement;
+ coerceValue: ({ value }: { value: ParamValue }) => ParamValue | null;
+ getBaseValue: () => ParamValue | null;
+ setBaseValue: ({ value }: { value: ParamValue }) => TimelineElement;
}
-// Number/discrete bindings expose a single component named "value"
-// (see binding-values.ts). Multi-component kinds (vector2, color) don't carry
-// numeric ranges yet — revisit when one does.
+// Leaf params expose a single component named "value". Composite params don't
+// carry numeric ranges yet — revisit when one does.
function paramNumericRanges({
param,
}: {
param: ParamDefinition;
}): Partial<Record<string, NumericSpec>> | undefined {
- const range = getAnimationParamNumericRange({ param });
+ const range = getParamNumericRange({ param });
return range ? { value: range } : undefined;
}
+function buildParamDescriptor({
+ param,
+ baseParams,
+ setParams,
+}: {
+ param: ParamDefinition;
+ baseParams: ParamValues;
+ setParams: (params: ParamValues) => TimelineElement;
+}): AnimationPathDescriptor | null {
+ if (param.keyframable === false) {
+ return null;
+ }
+
+ return {
+ channelLayout: getParamChannelLayout({ param }),
+ defaultInterpolation: getParamDefaultInterpolation({ param }),
+ numericRanges: paramNumericRanges({ param }),
+ coerceValue: ({ value }) => coerceParamValue({ param, value }),
+ getBaseValue: () => baseParams[param.key] ?? param.default,
+ setBaseValue: ({ value }) => {
+ const coercedValue = coerceParamValue({ param, value });
+ if (coercedValue === null) {
+ return setParams(baseParams);
+ }
+
+ return setParams({
+ ...baseParams,
+ [param.key]: coercedValue,
+ });
+ },
+ };
+}
+
+function buildElementParamDescriptor({
+ element,
+ paramKey,
+}: {
+ element: TimelineElement;
+ paramKey: string;
+}): AnimationPathDescriptor | null {
+ const param = getElementParam({ element, key: paramKey });
+ if (!param) {
+ return null;
+ }
+
+ return buildParamDescriptor({
+ param,
+ baseParams: element.params,
+ setParams: (params) => ({
+ ...element,
+ params,
+ }),
+ });
+}
+
function buildGraphicParamDescriptor({
element,
paramKey,
@@ -70,27 +121,14 @@ function buildGraphicParamDescriptor({
return null;
}
- return {
- kind: getAnimationParamValueKind({ param }),
- defaultInterpolation: getAnimationParamDefaultInterpolation({ param }),
- numericRanges: paramNumericRanges({ param }),
- coerceValue: ({ value }) => coerceAnimationParamValue({ param, value }),
- getBaseValue: () => element.params[param.key] ?? param.default,
- setBaseValue: ({ value }) => {
- const coercedValue = coerceAnimationParamValue({ param, value });
- if (coercedValue === null) {
- return element;
- }
-
- return {
- ...element,
- params: {
- ...element.params,
- [param.key]: coercedValue,
- },
- };
- },
- };
+ return buildParamDescriptor({
+ param,
+ baseParams: element.params,
+ setParams: (params) => ({
+ ...element,
+ params,
+ }),
+ });
}
function buildEffectParamDescriptor({
@@ -118,35 +156,22 @@ function buildEffectParamDescriptor({
return null;
}
- return {
- kind: getAnimationParamValueKind({ param }),
- defaultInterpolation: getAnimationParamDefaultInterpolation({ param }),
- numericRanges: paramNumericRanges({ param }),
- coerceValue: ({ value }) => coerceAnimationParamValue({ param, value }),
- getBaseValue: () => effect.params[param.key] ?? param.default,
- setBaseValue: ({ value }) => {
- const coercedValue = coerceAnimationParamValue({ param, value });
- if (coercedValue === null) {
- return element;
- }
-
- return {
- ...element,
- effects:
- element.effects?.map((candidate) =>
- candidate.id !== effectId
- ? candidate
- : {
- ...candidate,
- params: {
- ...candidate.params,
- [param.key]: coercedValue,
- },
- },
- ) ?? element.effects,
- };
- },
- };
+ return buildParamDescriptor({
+ param,
+ baseParams: effect.params,
+ setParams: (params) => ({
+ ...element,
+ effects:
+ element.effects?.map((candidate) =>
+ candidate.id !== effectId
+ ? candidate
+ : {
+ ...candidate,
+ params,
+ },
+ ) ?? element.effects,
+ }),
+ });
}
export function resolveAnimationTarget({
@@ -156,41 +181,12 @@ export function resolveAnimationTarget({
element: TimelineElement;
path: AnimationPath;
}): AnimationPathDescriptor | null {
- if (isAnimationPropertyPath(path)) {
- const propertyDefinition = getAnimationPropertyDefinition({
- propertyPath: path,
- });
- if (!propertyDefinition.supportsElement({ element })) {
- return null;
- }
-
- return {
- kind: propertyDefinition.kind,
- defaultInterpolation: propertyDefinition.defaultInterpolation,
- numericRanges: propertyDefinition.numericRanges,
- coerceValue: ({ value }) =>
- coerceAnimationValueForProperty({
- propertyPath: path,
- value,
- }),
- getBaseValue: () =>
- getElementBaseValueForProperty({
- element,
- propertyPath: path,
- }),
- setBaseValue: ({ value }) => {
- const coercedValue = propertyDefinition.coerceValue({ value });
- if (coercedValue === null) {
- return element;
- }
-
- return withElementBaseValueForProperty({
- element,
- propertyPath: path,
- value: coercedValue,
- });
- },
- };
+ const elementParamTarget = buildElementParamDescriptor({
+ element,
+ paramKey: path,
+ });
+ if (elementParamTarget) {
+ return elementParamTarget;
}
const graphicParamTarget = parseGraphicParamPath({ propertyPath: path });