Files
creator/app/src/primitives/AnimatedEntities.ts
enricobuehler e3098c4400 ui improvements
add timeline animations
2023-05-31 15:16:27 +02:00

195 lines
5.0 KiB
TypeScript

import { z } from "zod";
import {
BaseEntity,
EllipseEntity,
EntityType,
RectEntity,
TextEntity,
} from "./Entities";
import { AnimatedTransform, AnimatedVec2 } from "./Values";
import { TextPaint } from "./Paint";
import { AnimatedProperties } from "./AnimatedProperty";
export const AnimationData = z.object({
offset: z.number(),
duration: z.number(),
visible: z.boolean().optional().default(true),
});
export const AnimatedStaggeredTextEntity = BaseEntity.extend({
/** Transform applied to the whole layer. */
transform: AnimatedTransform,
/** The staggered delay that is applied for each letter. Gets multiplied by the index of the letter. */
stagger: z.number().min(0),
/** These properties get applied to each letter */
letter: z.object({
transform: AnimatedTransform,
paint: TextPaint,
}),
text: z.string(),
origin: AnimatedVec2,
animation_data: AnimationData,
type: z.literal(EntityType.Enum.StaggeredText),
});
export const AnimatedRectEntity = RectEntity.extend({
position: AnimatedVec2,
size: AnimatedVec2,
origin: AnimatedVec2,
transform: AnimatedTransform.optional(),
animation_data: AnimationData,
});
export const AnimatedTextEntity = TextEntity.extend({
origin: AnimatedVec2,
transform: AnimatedTransform.optional(),
animation_data: AnimationData,
});
export const AnimatedEllipseEntity = EllipseEntity.extend({
radius: AnimatedVec2,
position: AnimatedVec2,
origin: AnimatedVec2,
transform: AnimatedTransform.optional(),
animation_data: AnimationData,
});
export const AnimatedEntity = z.discriminatedUnion("type", [
AnimatedRectEntity,
AnimatedTextEntity,
AnimatedStaggeredTextEntity,
AnimatedEllipseEntity,
]);
export const AnimatedEntities = z.array(AnimatedEntity);
export function animatedTransformToAnimatedProperties(
animatedTransform: z.input<typeof AnimatedTransform>,
basePath?: string
): z.input<typeof AnimatedProperties> {
return [
{
animatedValue: animatedTransform.translate,
label: "Translation",
propertyPath: basePath
? basePath + ".transform.translate"
: "transform.translate",
},
{
animatedValue: animatedTransform.rotate,
label: "Rotation",
propertyPath: basePath
? basePath + ".transform.rotate"
: "transform.rotate",
},
{
animatedValue: animatedTransform.scale,
label: "Scale",
propertyPath: basePath
? basePath + ".transform.scale"
: "transform.scale",
},
{
animatedValue: animatedTransform.skew,
label: "Skew",
propertyPath: basePath ? basePath + ".transform.skew" : "transform.skew",
},
];
}
export function getAnimatedPropertiesByAnimatedEntity(
animatedEntity: z.input<typeof AnimatedEntity>
) {
const animatedProperties: z.input<typeof AnimatedProperties> = [];
switch (animatedEntity.type) {
case "Ellipse":
animatedProperties.push({
propertyPath: "origin",
animatedValue: animatedEntity.origin,
label: "Origin",
});
animatedProperties.push({
propertyPath: "radius",
animatedValue: animatedEntity.radius,
label: "Radius",
});
if (animatedEntity.transform) {
animatedProperties.push(
...animatedTransformToAnimatedProperties(animatedEntity.transform)
);
}
break;
case "Rect":
animatedProperties.push({
propertyPath: "origin",
animatedValue: animatedEntity.origin,
label: "Origin",
});
animatedProperties.push({
propertyPath: "size",
animatedValue: animatedEntity.size,
label: "Size",
});
if (animatedEntity.transform) {
animatedProperties.push(
...animatedTransformToAnimatedProperties(animatedEntity.transform)
);
}
break;
case "StaggeredText":
animatedProperties.push({
propertyPath: "origin",
animatedValue: animatedEntity.origin,
label: "Origin",
});
if (animatedEntity.transform) {
animatedProperties.push(
...animatedTransformToAnimatedProperties(animatedEntity.transform)
);
}
if (animatedEntity.letter.transform) {
animatedProperties.push(
...animatedTransformToAnimatedProperties(
animatedEntity.letter.transform,
"letter"
)
);
}
break;
case "Text":
animatedProperties.push({
propertyPath: "origin",
animatedValue: animatedEntity.origin,
label: "Origin",
});
if (animatedEntity.transform) {
animatedProperties.push(
...animatedTransformToAnimatedProperties(animatedEntity.transform)
);
}
break;
}
return animatedProperties;
}
export function getAnimatedPropertiesByAnimatedEnties(
animatedEntities: z.input<typeof AnimatedEntities>
) {
const animatedProperties: z.input<typeof AnimatedProperties> = [];
animatedEntities.forEach((aEnt) => {
animatedProperties.push(...getAnimatedPropertiesByAnimatedEntity(aEnt));
});
}