summaryrefslogtreecommitdiff
path: root/apps/web/src/animation/graph-channels.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/animation/graph-channels.ts')
-rw-r--r--apps/web/src/animation/graph-channels.ts99
1 files changed, 99 insertions, 0 deletions
diff --git a/apps/web/src/animation/graph-channels.ts b/apps/web/src/animation/graph-channels.ts
new file mode 100644
index 00000000..d6482602
--- /dev/null
+++ b/apps/web/src/animation/graph-channels.ts
@@ -0,0 +1,99 @@
+import type {
+ AnimationBindingInstance,
+ AnimationPath,
+ ElementAnimations,
+ ScalarAnimationChannel,
+ ScalarGraphChannel,
+ ScalarGraphKeyframeContext,
+} from "@/animation/types";
+
+export interface EditableScalarChannels {
+ binding: AnimationBindingInstance;
+ channels: ScalarGraphChannel[];
+}
+
+function isScalarAnimationChannel(
+ channel: ElementAnimations["channels"][string],
+): channel is ScalarAnimationChannel {
+ return channel?.kind === "scalar";
+}
+
+export function getEditableScalarChannels({
+ animations,
+ propertyPath,
+}: {
+ animations: ElementAnimations | undefined;
+ propertyPath: AnimationPath;
+}): EditableScalarChannels | null {
+ const binding = animations?.bindings[propertyPath];
+ if (!binding) {
+ return null;
+ }
+
+ const channels = binding.components.flatMap((component) => {
+ const channel = animations?.channels[component.channelId];
+ if (!isScalarAnimationChannel(channel)) {
+ return [];
+ }
+
+ return [
+ {
+ propertyPath,
+ componentKey: component.key,
+ channelId: component.channelId,
+ channel,
+ } satisfies ScalarGraphChannel,
+ ];
+ });
+
+ return { binding, channels };
+}
+
+export function getEditableScalarChannel({
+ animations,
+ propertyPath,
+ componentKey,
+}: {
+ animations: ElementAnimations | undefined;
+ propertyPath: AnimationPath;
+ componentKey: string;
+}): ScalarGraphChannel | null {
+ const result = getEditableScalarChannels({ animations, propertyPath });
+ return result?.channels.find((channel) => channel.componentKey === componentKey) ?? null;
+}
+
+export function getScalarKeyframeContext({
+ animations,
+ propertyPath,
+ componentKey,
+ keyframeId,
+}: {
+ animations: ElementAnimations | undefined;
+ propertyPath: AnimationPath;
+ componentKey: string;
+ keyframeId: string;
+}): ScalarGraphKeyframeContext | null {
+ const scalarChannel = getEditableScalarChannel({
+ animations,
+ propertyPath,
+ componentKey,
+ });
+ if (!scalarChannel) {
+ return null;
+ }
+
+ const keyframeIndex = scalarChannel.channel.keys.findIndex(
+ (keyframe) => keyframe.id === keyframeId,
+ );
+ if (keyframeIndex < 0) {
+ return null;
+ }
+
+ return {
+ ...scalarChannel,
+ keyframe: scalarChannel.channel.keys[keyframeIndex],
+ keyframeIndex,
+ previousKey: scalarChannel.channel.keys[keyframeIndex - 1] ?? null,
+ nextKey: scalarChannel.channel.keys[keyframeIndex + 1] ?? null,
+ };
+}