@omnimedia/omnitool 1.1.0-82 → 1.1.0-84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +64 -9
  2. package/package.json +1 -1
  3. package/s/timeline/index.ts +2 -2
  4. package/s/timeline/parts/animations/make.ts +38 -0
  5. package/s/timeline/parts/animations/presets.ts +138 -0
  6. package/s/timeline/parts/{animations.ts → animations/properties.ts} +2 -24
  7. package/s/timeline/parts/animations/registry.ts +13 -0
  8. package/s/timeline/parts/animations/types.ts +69 -0
  9. package/s/timeline/sugar/helpers.ts +32 -18
  10. package/s/timeline/sugar/o.ts +25 -17
  11. package/s/timeline/utils/anim.ts +2 -2
  12. package/x/demo/demo.bundle.min.js +100 -100
  13. package/x/demo/demo.bundle.min.js.map +4 -4
  14. package/x/index.html +2 -2
  15. package/x/tests.bundle.min.js +102 -102
  16. package/x/tests.bundle.min.js.map +4 -4
  17. package/x/tests.html +1 -1
  18. package/x/timeline/index.d.ts +2 -2
  19. package/x/timeline/index.js +2 -2
  20. package/x/timeline/index.js.map +1 -1
  21. package/x/timeline/parts/animations/make.d.ts +3 -0
  22. package/x/timeline/parts/animations/make.js +29 -0
  23. package/x/timeline/parts/animations/make.js.map +1 -0
  24. package/x/timeline/parts/animations/presets.d.ts +170 -0
  25. package/x/timeline/parts/animations/presets.js +135 -0
  26. package/x/timeline/parts/animations/presets.js.map +1 -0
  27. package/x/timeline/parts/{animations.d.ts → animations/properties.d.ts} +1 -20
  28. package/x/timeline/parts/{animations.js → animations/properties.js} +2 -2
  29. package/x/timeline/parts/animations/properties.js.map +1 -0
  30. package/x/timeline/parts/animations/registry.d.ts +218 -0
  31. package/x/timeline/parts/animations/registry.js +11 -0
  32. package/x/timeline/parts/animations/registry.js.map +1 -0
  33. package/x/timeline/parts/animations/types.d.ts +51 -0
  34. package/x/timeline/parts/animations/types.js +2 -0
  35. package/x/timeline/parts/animations/types.js.map +1 -0
  36. package/x/timeline/sugar/helpers.d.ts +2 -1
  37. package/x/timeline/sugar/helpers.js +23 -16
  38. package/x/timeline/sugar/helpers.js.map +1 -1
  39. package/x/timeline/sugar/o.d.ts +1 -0
  40. package/x/timeline/sugar/o.js +18 -16
  41. package/x/timeline/sugar/o.js.map +1 -1
  42. package/x/timeline/utils/anim.d.ts +2 -2
  43. package/x/timeline/utils/anim.js.map +1 -1
  44. package/x/timeline/parts/animations.js.map +0 -1
package/README.md CHANGED
@@ -150,7 +150,7 @@ Animated spatial transforms:
150
150
 
151
151
  ```ts
152
152
  const timeline = omni.timeline(o => {
153
- const slideIn = o.animatedSpatial(
153
+ const customMotion = o.animatedSpatial(
154
154
  o.anim.transform("linear", [
155
155
  [0, o.transform({position: [-400, 0]})],
156
156
  [1000, o.transform({position: [0, 0]})],
@@ -161,7 +161,7 @@ const timeline = omni.timeline(o => {
161
161
  duration: 2000,
162
162
  styles: {fill: "white", fontSize: 36}
163
163
  })
164
- o.set(title.id, {spatialId: slideIn.id})
164
+ o.set(title.id, {spatialId: customMotion.id})
165
165
 
166
166
  return o.stack(
167
167
  o.video(clip, {duration: 4000}),
@@ -170,6 +170,33 @@ const timeline = omni.timeline(o => {
170
170
  })
171
171
  ```
172
172
 
173
+ Built-in spatial animations:
174
+
175
+ ```ts
176
+ const animOut = {
177
+ duration: 500,
178
+ offset: item.duration - 500,
179
+ }
180
+ const slideIn = o.animatedSpatial(o.anim.presets.slideIn())
181
+ const slideOut = o.animatedSpatial(o.anim.presets.slideOut(animOut))
182
+ const spinIn = o.animatedSpatial(o.anim.presets.spinIn())
183
+ const spinOut = o.animatedSpatial(o.anim.presets.spinOut(animOut))
184
+ const zoomIn = o.animatedSpatial(o.anim.presets.zoomIn())
185
+ const zoomOut = o.animatedSpatial(o.anim.presets.zoomOut(animOut))
186
+ const bounceIn = o.animatedSpatial(o.anim.presets.bounceIn())
187
+ const bounceOut = o.animatedSpatial(o.anim.presets.bounceOut(animOut))
188
+ ```
189
+
190
+ Built-in scalar animations:
191
+
192
+ ```ts
193
+ const fadeInPreset = o.anim.presets.fadeIn()
194
+ const fadeIn = o.animate.opacity.make(fadeInPreset.terp, fadeInPreset.track)
195
+
196
+ const fadeOutPreset = o.anim.presets.fadeOut({duration: 500})
197
+ const fadeOut = o.animate.opacity.make(fadeOutPreset.terp, fadeOutPreset.track)
198
+ ```
199
+
173
200
  Animation application:
174
201
 
175
202
  ```ts
@@ -215,29 +242,57 @@ const timeline = omni.timeline(o => {
215
242
  })
216
243
  ```
217
244
 
218
- Animation registry:
245
+ Animation metadata:
219
246
 
220
247
  ```ts
221
- import {animations} from "@omnimedia/omnitool"
248
+ import {animatableProperties, animationPresets} from "@omnimedia/omnitool"
222
249
 
223
- Object.entries(animations).forEach(([property, meta]) => {
250
+ Object.entries(animatableProperties).forEach(([property, meta]) => {
224
251
  console.log(property, meta.type, meta.defaultTerp, meta.channels)
225
252
  // transform transform linear [...]
226
253
  // opacity scalar linear [...]
227
254
  })
255
+
256
+ Object.entries(animationPresets).forEach(([preset, meta]) => {
257
+ console.log(preset, meta.type, meta.label, meta.defaults)
258
+ // slideIn motion Slide in {...}
259
+ // slideOut motion Slide out {...}
260
+ // spinIn motion Spin in {...}
261
+ // spinOut motion Spin out {...}
262
+ // zoomIn motion Zoom in {...}
263
+ // zoomOut motion Zoom out {...}
264
+ // bounceIn motion Bounce in {...}
265
+ // bounceOut motion Bounce out {...}
266
+ // fadeIn scalar Fade in {...}
267
+ // fadeOut scalar Fade out {...}
268
+ })
228
269
  ```
229
270
 
230
- Each animation definition describes the semantic shape of the animation: its value kind, default interpolation, and numeric channels with defaults and units. This is useful for tools that need to create valid keyframes without hardcoding Omnitool's track layout.
271
+ Animatable properties describe what can be keyframed, such as `transform` and `opacity`.
272
+ Animation presets describe built-in recipes, such as `slideIn` and `fadeIn`, that create animation data.
273
+ Use `animationPresets` to list available recipes, and `o.anim.presets` to create animation data from them.
274
+
275
+ Preset options:
276
+ - `duration` sets the animation duration, defaulting to `700`.
277
+ - `offset` shifts generated keyframes in item-local time.
278
+ Useful for out animations: `item.duration - 500` starts `slideOut` 500ms before the item ends.
279
+ - `from` sets the start value, like opacity `0` or position `[-400, 0]`.
280
+ - `to` sets the end value, like opacity `1` or position `[0, 0]`.
281
+ - `terp` sets interpolation, defaulting to the preset's `terp`.
231
282
 
232
283
  Utils:
233
284
 
234
285
  ```ts
235
- import {resolveTransform} from "@omnimedia/omnitool"
286
+ import {resolveScalarAnimation, resolveTransformAnimation} from "@omnimedia/omnitool"
236
287
 
237
- const transform = resolveTransform(spatial, localTime)
288
+ const transform = resolveTransformAnimation(localTime, spatial.anim)
289
+ const opacity = resolveScalarAnimation(localTime, opacityAnimation)
238
290
  ```
239
291
 
240
- `resolveTransform` gets a spatial item's current transform. It returns the static transform for `Item.Spatial`, or resolves the animated transform for `Item.AnimatedSpatial` at the given local time.
292
+ `resolveTransformAnimation` resolves an animated transform at the given local time.
293
+ `resolveScalarAnimation` resolves an animated scalar value at the given local time.
294
+ `localTime` is time relative to the item being resolved.
295
+ `clamp` is the default and currently only extrapolation mode, holding the first or last keyframe value outside the authored range.
241
296
 
242
297
  Worker URL notes:
243
298
  - `Driver.setup()` defaults to `/node_modules/@omnimedia/omnitool/x/driver/driver.worker.bundle.min.js`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnimedia/omnitool",
3
- "version": "1.1.0-82",
3
+ "version": "1.1.0-84",
4
4
  "description": "open source video processing tools",
5
5
  "license": "MIT",
6
6
  "author": "Przemysław Gałęzki",
@@ -1,13 +1,13 @@
1
1
 
2
+ export * from "./types.js"
2
3
  export * from "./parts/basics.js"
3
- export * from "./parts/animations.js"
4
4
  export * from "./parts/filters.js"
5
5
  export * from "./parts/item.js"
6
6
  export * from "./parts/media.js"
7
7
  export * from "./parts/resource-pool.js"
8
8
  export * from "./parts/resource.js"
9
9
  export * from "./parts/filmstrip.js"
10
- export * from "./types.js"
10
+ export * from "./parts/animations/registry.js"
11
11
 
12
12
  export * from "./parts/waveform/waveform.js"
13
13
  export * from "./parts/waveform/parts/types.js"
@@ -0,0 +1,38 @@
1
+
2
+ import {animationPresets} from "./presets.js"
3
+ import {AnimationPresetActions, MotionAnimationOptions, ScalarAnimationOptions} from "./types.js"
4
+ import {Anim, Interpolation, Keyframes, TrackTransform, Transform, TransformOptions} from "../../types.js"
5
+
6
+ export function makeAnimationPresets(
7
+ scalar: (terp: Interpolation, track: Keyframes) => Anim<Keyframes>,
8
+ transform: (terp: Interpolation, source: Keyframes<Transform>) => Anim<TrackTransform>,
9
+ transformFrom: (options: TransformOptions) => Transform,
10
+ ): AnimationPresetActions {
11
+ const entries = Object.entries(animationPresets).map(([name, preset]) => {
12
+ const action = preset.type === "motion"
13
+ ? (options?: MotionAnimationOptions): Anim<TrackTransform> => {
14
+ const offset = options?.offset ?? 0
15
+ return transform(options?.terp ?? preset.defaults.terp, [
16
+ [offset, transformFrom({
17
+ ...preset.transform.from,
18
+ ...(options?.from === undefined ? {} : {position: options.from}),
19
+ })],
20
+ [offset + (options?.duration ?? preset.defaults.duration), transformFrom({
21
+ ...preset.transform.to,
22
+ ...(options?.to === undefined ? {} : {position: options.to}),
23
+ })],
24
+ ])
25
+ }
26
+ : (options?: ScalarAnimationOptions): Anim<Keyframes> => {
27
+ const offset = options?.offset ?? 0
28
+ return scalar(options?.terp ?? preset.defaults.terp, [
29
+ [offset, options?.from ?? preset.defaults.from],
30
+ [offset + (options?.duration ?? preset.defaults.duration), options?.to ?? preset.defaults.to],
31
+ ])
32
+ }
33
+
34
+ return [name, action]
35
+ })
36
+
37
+ return Object.fromEntries(entries) as AnimationPresetActions
38
+ }
@@ -0,0 +1,138 @@
1
+
2
+ import type {AnimationPresetDefinition} from "./types.js"
3
+
4
+ export const animationPresets = {
5
+ slideIn: {
6
+ type: "motion",
7
+ label: "Slide in",
8
+ defaults: {
9
+ duration: 700,
10
+ from: [-400, 0],
11
+ to: [0, 0],
12
+ terp: "easeOut",
13
+ },
14
+ transform: {
15
+ from: {position: [-400, 0]},
16
+ to: {position: [0, 0]},
17
+ },
18
+ },
19
+ slideOut: {
20
+ type: "motion",
21
+ label: "Slide out",
22
+ defaults: {
23
+ duration: 700,
24
+ from: [0, 0],
25
+ to: [400, 0],
26
+ terp: "easeIn",
27
+ },
28
+ transform: {
29
+ from: {position: [0, 0]},
30
+ to: {position: [400, 0]},
31
+ },
32
+ },
33
+ spinIn: {
34
+ type: "motion",
35
+ label: "Spin in",
36
+ defaults: {
37
+ duration: 700,
38
+ from: [0, 0],
39
+ to: [0, 0],
40
+ terp: "easeOut",
41
+ },
42
+ transform: {
43
+ from: {scale: [0, 0], rotation: -Math.PI},
44
+ to: {scale: [1, 1], rotation: 0},
45
+ },
46
+ },
47
+ spinOut: {
48
+ type: "motion",
49
+ label: "Spin out",
50
+ defaults: {
51
+ duration: 700,
52
+ from: [0, 0],
53
+ to: [0, 0],
54
+ terp: "easeIn",
55
+ },
56
+ transform: {
57
+ from: {scale: [1, 1], rotation: 0},
58
+ to: {scale: [0, 0], rotation: Math.PI},
59
+ },
60
+ },
61
+ zoomIn: {
62
+ type: "motion",
63
+ label: "Zoom in",
64
+ defaults: {
65
+ duration: 700,
66
+ from: [0, 0],
67
+ to: [0, 0],
68
+ terp: "easeOut",
69
+ },
70
+ transform: {
71
+ from: {scale: [0, 0]},
72
+ to: {scale: [1, 1]},
73
+ },
74
+ },
75
+ zoomOut: {
76
+ type: "motion",
77
+ label: "Zoom out",
78
+ defaults: {
79
+ duration: 700,
80
+ from: [0, 0],
81
+ to: [0, 0],
82
+ terp: "easeIn",
83
+ },
84
+ transform: {
85
+ from: {scale: [1, 1]},
86
+ to: {scale: [0, 0]},
87
+ },
88
+ },
89
+ bounceIn: {
90
+ type: "motion",
91
+ label: "Bounce in",
92
+ defaults: {
93
+ duration: 700,
94
+ from: [0, 0],
95
+ to: [0, 0],
96
+ terp: "bounce",
97
+ },
98
+ transform: {
99
+ from: {scale: [0, 0]},
100
+ to: {scale: [1, 1]},
101
+ },
102
+ },
103
+ bounceOut: {
104
+ type: "motion",
105
+ label: "Bounce out",
106
+ defaults: {
107
+ duration: 700,
108
+ from: [0, 0],
109
+ to: [0, 0],
110
+ terp: "bounce",
111
+ },
112
+ transform: {
113
+ from: {scale: [1, 1]},
114
+ to: {scale: [0, 0]},
115
+ },
116
+ },
117
+ fadeIn: {
118
+ type: "scalar",
119
+ label: "Fade in",
120
+ defaults: {
121
+ duration: 700,
122
+ from: 0,
123
+ to: 1,
124
+ terp: "easeIn",
125
+ },
126
+ },
127
+ fadeOut: {
128
+ type: "scalar",
129
+ label: "Fade out",
130
+ defaults: {
131
+ duration: 700,
132
+ from: 1,
133
+ to: 0,
134
+ terp: "easeOut",
135
+ },
136
+ },
137
+ } as const satisfies Record<string, AnimationPresetDefinition>
138
+
@@ -1,23 +1,5 @@
1
1
 
2
- import type {Interpolation} from "../types.js"
3
-
4
- export type AnimationType = "scalar" | "transform"
5
- export type AnimationChannelType = "number"
6
- export type AnimationUnit = "pixel" | "scale" | "radian" | "ratio"
7
-
8
- export type AnimationChannel = {
9
- path?: string
10
- type: AnimationChannelType
11
- default: number
12
- unit?: AnimationUnit
13
- range?: readonly [min: number, max: number]
14
- }
15
-
16
- export type AnimationDefinition = {
17
- type: AnimationType
18
- defaultTerp: Interpolation
19
- channels: readonly AnimationChannel[]
20
- }
2
+ import type {AnimationDefinition} from "./types.js"
21
3
 
22
4
  export const spatialAnimations = {
23
5
  transform: {
@@ -45,12 +27,8 @@ export const visualAnimations = {
45
27
 
46
28
  // const audioAnimations = {}
47
29
 
48
- export const animations = {
30
+ export const animatableProperties = {
49
31
  ...spatialAnimations,
50
32
  ...visualAnimations,
51
33
  } as const
52
34
 
53
- export type SpatialAnimationProperty = keyof typeof spatialAnimations
54
- export type VisualAnimationProperty = keyof typeof visualAnimations
55
- export type AnimationProperty = keyof typeof animations
56
-
@@ -0,0 +1,13 @@
1
+
2
+ import {animationPresets} from "./presets.js"
3
+ import {animatableProperties} from "./properties.js"
4
+
5
+ export const animationRegistry = {
6
+ presets: animationPresets,
7
+ properties: animatableProperties,
8
+ } as const
9
+
10
+ export * from "./make.js"
11
+ export * from "./presets.js"
12
+ export * from "./properties.js"
13
+ export * from "./types.js"
@@ -0,0 +1,69 @@
1
+
2
+ import {animationPresets} from "./presets.js"
3
+ import {spatialAnimations, visualAnimations, animatableProperties} from "./properties.js"
4
+ import {Anim, Interpolation, Keyframes, TrackTransform, TransformOptions, Vec2} from "../../types.js"
5
+
6
+ export type AnimationType = "scalar" | "transform"
7
+ export type AnimationChannelType = "number"
8
+ export type AnimationUnit = "pixel" | "scale" | "radian" | "ratio"
9
+
10
+ export type AnimationChannel = {
11
+ path?: string
12
+ type: AnimationChannelType
13
+ default: number
14
+ unit?: AnimationUnit
15
+ range?: readonly [min: number, max: number]
16
+ }
17
+
18
+ export type AnimationDefinition = {
19
+ type: AnimationType
20
+ defaultTerp: Interpolation
21
+ channels: readonly AnimationChannel[]
22
+ }
23
+
24
+ export type MotionAnimationPresetDefinition = {
25
+ type: "motion"
26
+ label: string
27
+ defaults: Required<Omit<MotionAnimationOptions, "offset">>
28
+ transform: {
29
+ from: TransformOptions
30
+ to: TransformOptions
31
+ }
32
+ }
33
+
34
+ export type ScalarAnimationPresetDefinition = {
35
+ type: "scalar"
36
+ label: string
37
+ defaults: Required<Omit<ScalarAnimationOptions, "offset">>
38
+ }
39
+
40
+ export type AnimationPresetDefinition =
41
+ | MotionAnimationPresetDefinition
42
+ | ScalarAnimationPresetDefinition
43
+
44
+ export type SpatialAnimationProperty = keyof typeof spatialAnimations
45
+ export type VisualAnimationProperty = keyof typeof visualAnimations
46
+ export type AnimationProperty = keyof typeof animatableProperties
47
+ export type AnimationPreset = keyof typeof animationPresets
48
+
49
+ type AnimationPresetAction<TPreset extends AnimationPresetDefinition> =
50
+ TPreset extends MotionAnimationPresetDefinition
51
+ ? (options?: MotionAnimationOptions) => Anim<TrackTransform>
52
+ : TPreset extends ScalarAnimationPresetDefinition
53
+ ? (options?: ScalarAnimationOptions) => Anim<Keyframes>
54
+ : never
55
+
56
+ export type AnimationPresetActions = {
57
+ [TName in AnimationPreset]: AnimationPresetAction<(typeof animationPresets)[TName]>
58
+ }
59
+
60
+ export type AnimationPresetOptions<Value> = {
61
+ duration?: number
62
+ offset?: number
63
+ from?: Value
64
+ to?: Value
65
+ terp?: Interpolation
66
+ }
67
+
68
+ export type MotionAnimationOptions = AnimationPresetOptions<Vec2>
69
+ export type ScalarAnimationOptions = AnimationPresetOptions<number>
@@ -5,10 +5,34 @@ import {O} from "./o.js"
5
5
  import {Media} from "../parts/media.js"
6
6
  import {TimelineFile} from "../parts/basics.js"
7
7
  import {FilterAction} from "../parts/filters.js"
8
- import {visualAnimations} from "../parts/animations.js"
9
8
  import {filters, FilterParams, FilterType} from "../parts/filters.js"
10
9
  import {Crop, FilterableItem, Item, VisualAnimatableItem} from "../parts/item.js"
11
- import {Anim, AnimateAction, Interpolation, Keyframes, TrackTransform, Transform, Vec2, VisualAnimations} from "../types.js"
10
+ import {makeAnimationPresets, visualAnimations} from "../parts/animations/registry.js"
11
+ import {Anim, AnimateAction, Interpolation, Keyframes, TrackTransform, Transform, TransformOptions, Vec2, VisualAnimations} from "../types.js"
12
+
13
+ const transformFrom = (options: TransformOptions): Transform => [
14
+ options.position ?? [0, 0],
15
+ options.scale ?? [1, 1],
16
+ options.rotation ?? 0,
17
+ ]
18
+
19
+ const transformAnimation = (terp: Interpolation, source: Keyframes<Transform>): Anim<TrackTransform> => {
20
+ const track: TrackTransform = {
21
+ position: {x: [], y: []},
22
+ scale: {x: [], y: []},
23
+ rotation: [],
24
+ }
25
+
26
+ for (const [time, [position, scale, rotation]] of source) {
27
+ track.position.x.push([time, position[0]])
28
+ track.position.y.push([time, position[1]])
29
+ track.scale.x.push([time, scale[0]])
30
+ track.scale.y.push([time, scale[1]])
31
+ track.rotation.push([time, rotation])
32
+ }
33
+
34
+ return {terp, track}
35
+ }
12
36
 
13
37
  export type Build<T extends Item.Any = Item.Any> = (o: O) => T
14
38
  type BuildVisualAnimateActions = {
@@ -99,23 +123,13 @@ export const anim = {
99
123
  return {terp, track}
100
124
  },
101
125
 
102
- transform(terp: Interpolation, source: Keyframes<Transform>): Anim<TrackTransform> {
103
- const track: TrackTransform = {
104
- position: {x: [], y: []},
105
- scale: {x: [], y: []},
106
- rotation: [],
107
- }
108
-
109
- for (const [time, [position, scale, rotation]] of source) {
110
- track.position.x.push([time, position[0]])
111
- track.position.y.push([time, position[1]])
112
- track.scale.x.push([time, scale[0]])
113
- track.scale.y.push([time, scale[1]])
114
- track.rotation.push([time, rotation])
115
- }
126
+ transform: transformAnimation,
116
127
 
117
- return {terp, track}
118
- },
128
+ presets: makeAnimationPresets(
129
+ (terp, track) => ({terp, track}),
130
+ transformAnimation,
131
+ transformFrom,
132
+ ),
119
133
  }
120
134
 
121
135
  interface BuildFilterAction<TFilter extends FilterType> {
@@ -5,7 +5,7 @@ import {Media} from "../parts/media.js"
5
5
  import {Id, TimelineFile} from "../parts/basics.js"
6
6
  import {FilterAction, FilterActions} from "../parts/filters.js"
7
7
  import {filters, FilterParams, FilterType} from "../parts/filters.js"
8
- import {visualAnimations} from "../parts/animations.js"
8
+ import {makeAnimationPresets, visualAnimations} from "../parts/animations/registry.js"
9
9
  import {Crop, Effect, FilterableItem, Item, Kind, VisualAnimatableItem} from "../parts/item.js"
10
10
  import {Anim, AnimateAction, Interpolation, Keyframes, TrackTransform, Transform, TransformOptions, Vec2, VisualAnimations} from "../types.js"
11
11
 
@@ -87,6 +87,24 @@ export class O {
87
87
  return item
88
88
  }
89
89
 
90
+ #transformAnimation = (terp: Interpolation, source: Keyframes<Transform>): Anim<TrackTransform> => {
91
+ const track: TrackTransform = {
92
+ position: {x: [], y: []},
93
+ scale: {x: [], y: []},
94
+ rotation: [],
95
+ }
96
+
97
+ for (const [time, [position, scale, rotation]] of source) {
98
+ track.position.x.push([time, position[0]])
99
+ track.position.y.push([time, position[1]])
100
+ track.scale.x.push([time, scale[0]])
101
+ track.scale.y.push([time, scale[1]])
102
+ track.rotation.push([time, rotation])
103
+ }
104
+
105
+ return {terp, track}
106
+ }
107
+
90
108
  anim = {
91
109
  scalar: (terp: Interpolation, track: Keyframes): Anim<Keyframes> => ({terp, track}),
92
110
 
@@ -101,23 +119,13 @@ export class O {
101
119
  return {terp, track}
102
120
  },
103
121
 
104
- transform: (terp: Interpolation, source: Keyframes<Transform>): Anim<TrackTransform> => {
105
- const track: TrackTransform = {
106
- position: {x: [], y: []},
107
- scale: {x: [], y: []},
108
- rotation: [],
109
- }
110
-
111
- for (const [time, [position, scale, rotation]] of source) {
112
- track.position.x.push([time, position[0]])
113
- track.position.y.push([time, position[1]])
114
- track.scale.x.push([time, scale[0]])
115
- track.scale.y.push([time, scale[1]])
116
- track.rotation.push([time, rotation])
117
- }
122
+ transform: this.#transformAnimation,
118
123
 
119
- return {terp, track}
120
- },
124
+ presets: makeAnimationPresets(
125
+ (terp, track) => ({terp, track}),
126
+ this.#transformAnimation,
127
+ options => this.transform(options),
128
+ ),
121
129
  }
122
130
 
123
131
  #makeFilter = <TFilter extends FilterType>(type: TFilter) => {
@@ -1,7 +1,7 @@
1
1
 
2
2
  import {resolveTerp} from "./terps.js"
3
3
  import {Item, Kind} from "../parts/item.js"
4
- import {Anim, Keyframes, ScalarAnimation, TrackTransform, Transform} from "../types.js"
4
+ import {Anim, Keyframes, ScalarAnimation, Transform, TransformAnimation} from "../types.js"
5
5
 
6
6
  const resolveScalar =(
7
7
  time: number,
@@ -44,7 +44,7 @@ const resolveScalar =(
44
44
 
45
45
  export const resolveTransformAnimation =(
46
46
  time: number,
47
- anim: Anim<TrackTransform>,
47
+ anim: TransformAnimation,
48
48
  ): Transform => ([
49
49
  [
50
50
  resolveScalar(time, anim.track.position.x, anim.terp),