@omnimedia/omnitool 1.1.0-83 → 1.1.0-85

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.
package/README.md CHANGED
@@ -173,14 +173,18 @@ const timeline = omni.timeline(o => {
173
173
  Built-in spatial animations:
174
174
 
175
175
  ```ts
176
+ const animOut = {
177
+ duration: 500,
178
+ offset: item.duration - 500,
179
+ }
176
180
  const slideIn = o.animatedSpatial(o.anim.presets.slideIn())
177
- const slideOut = o.animatedSpatial(o.anim.presets.slideOut({duration: 500}))
181
+ const slideOut = o.animatedSpatial(o.anim.presets.slideOut(animOut))
178
182
  const spinIn = o.animatedSpatial(o.anim.presets.spinIn())
179
- const spinOut = o.animatedSpatial(o.anim.presets.spinOut())
183
+ const spinOut = o.animatedSpatial(o.anim.presets.spinOut(animOut))
180
184
  const zoomIn = o.animatedSpatial(o.anim.presets.zoomIn())
181
- const zoomOut = o.animatedSpatial(o.anim.presets.zoomOut())
185
+ const zoomOut = o.animatedSpatial(o.anim.presets.zoomOut(animOut))
182
186
  const bounceIn = o.animatedSpatial(o.anim.presets.bounceIn())
183
- const bounceOut = o.animatedSpatial(o.anim.presets.bounceOut())
187
+ const bounceOut = o.animatedSpatial(o.anim.presets.bounceOut(animOut))
184
188
  ```
185
189
 
186
190
  Built-in scalar animations:
@@ -229,7 +233,7 @@ const timeline = omni.timeline(o => {
229
233
  duration: 2000,
230
234
  styles: {fill: "white", fontSize: 36},
231
235
  })
232
- o.set(title.id, {animationId: fadeIn.id})
236
+ o.set(title.id, {animationIds: [fadeIn.id]})
233
237
 
234
238
  return o.stack(
235
239
  o.video(clip, {duration: 4000}),
@@ -268,6 +272,14 @@ Animatable properties describe what can be keyframed, such as `transform` and `o
268
272
  Animation presets describe built-in recipes, such as `slideIn` and `fadeIn`, that create animation data.
269
273
  Use `animationPresets` to list available recipes, and `o.anim.presets` to create animation data from them.
270
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`.
282
+
271
283
  Utils:
272
284
 
273
285
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnimedia/omnitool",
3
- "version": "1.1.0-83",
3
+ "version": "1.1.0-85",
4
4
  "description": "open source video processing tools",
5
5
  "license": "MIT",
6
6
  "author": "Przemysław Gałęzki",
@@ -32,7 +32,7 @@ export async function TimelineSchemaTest(driver: Driver, file: File) {
32
32
  )
33
33
 
34
34
  const video = o.video(videoA, {duration: 3000, start: 1000})
35
- o.set<Item.Text>(text.id, {styleId: style.id, spatialId: textSpatial.id, animationId: fade.id})
35
+ o.set<Item.Text>(text.id, {styleId: style.id, spatialId: textSpatial.id, animationIds: [fade.id]})
36
36
  o.set<Item.Video>(video.id, {spatialId: videoSpatial.id})
37
37
 
38
38
  return o.sequence(
@@ -10,22 +10,26 @@ export function makeAnimationPresets(
10
10
  ): AnimationPresetActions {
11
11
  const entries = Object.entries(animationPresets).map(([name, preset]) => {
12
12
  const action = preset.type === "motion"
13
- ? (options?: MotionAnimationOptions): Anim<TrackTransform> =>
14
- transform(options?.terp ?? preset.defaults.terp, [
15
- [0, transformFrom({
13
+ ? (options?: MotionAnimationOptions): Anim<TrackTransform> => {
14
+ const offset = options?.offset ?? 0
15
+ return transform(options?.terp ?? preset.defaults.terp, [
16
+ [offset, transformFrom({
16
17
  ...preset.transform.from,
17
18
  ...(options?.from === undefined ? {} : {position: options.from}),
18
19
  })],
19
- [options?.duration ?? preset.defaults.duration, transformFrom({
20
+ [offset + (options?.duration ?? preset.defaults.duration), transformFrom({
20
21
  ...preset.transform.to,
21
22
  ...(options?.to === undefined ? {} : {position: options.to}),
22
23
  })],
23
24
  ])
24
- : (options?: ScalarAnimationOptions): Anim<Keyframes> =>
25
- scalar(options?.terp ?? preset.defaults.terp, [
26
- [0, options?.from ?? preset.defaults.from],
27
- [options?.duration ?? preset.defaults.duration, options?.to ?? preset.defaults.to],
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],
28
31
  ])
32
+ }
29
33
 
30
34
  return [name, action]
31
35
  })
@@ -24,7 +24,7 @@ export type AnimationDefinition = {
24
24
  export type MotionAnimationPresetDefinition = {
25
25
  type: "motion"
26
26
  label: string
27
- defaults: Required<MotionAnimationOptions>
27
+ defaults: Required<Omit<MotionAnimationOptions, "offset">>
28
28
  transform: {
29
29
  from: TransformOptions
30
30
  to: TransformOptions
@@ -34,7 +34,7 @@ export type MotionAnimationPresetDefinition = {
34
34
  export type ScalarAnimationPresetDefinition = {
35
35
  type: "scalar"
36
36
  label: string
37
- defaults: Required<ScalarAnimationOptions>
37
+ defaults: Required<Omit<ScalarAnimationOptions, "offset">>
38
38
  }
39
39
 
40
40
  export type AnimationPresetDefinition =
@@ -59,6 +59,7 @@ export type AnimationPresetActions = {
59
59
 
60
60
  export type AnimationPresetOptions<Value> = {
61
61
  duration?: number
62
+ offset?: number
62
63
  from?: Value
63
64
  to?: Value
64
65
  terp?: Interpolation
@@ -94,7 +94,7 @@ export namespace Item {
94
94
  start: number
95
95
  duration: number
96
96
  spatialId?: Id
97
- animationId?: Id
97
+ animationIds?: Id[]
98
98
  filterIds?: Id[]
99
99
  }
100
100
 
@@ -113,7 +113,7 @@ export namespace Item {
113
113
  content: string
114
114
  duration: number
115
115
  spatialId?: Id
116
- animationId?: Id
116
+ animationIds?: Id[]
117
117
  styleId?: Id
118
118
  filterIds?: Id[]
119
119
  }
@@ -1,4 +1,5 @@
1
1
 
2
+ import {Keyframes} from '../../types.js'
2
3
  import {ms, Ms} from '../../../units/ms.js'
3
4
  import {Id, TimelineFile} from '../../parts/basics.js'
4
5
  import { SampleContext } from './samplers/visual/parts/types.js'
@@ -366,12 +367,30 @@ export function computeOpacity(
366
367
  item: Item.Any,
367
368
  time: Ms,
368
369
  ) {
369
- if (!("animationId" in item) || item.animationId === undefined)
370
+ if (!("animationIds" in item) || item.animationIds === undefined)
370
371
  return 1
371
372
 
372
- const animation = ctx.items.get(item.animationId) as Item.Animation | undefined
373
- return animation?.enabled && animation.anims.opacity
374
- ? resolveScalarAnimation(time, animation.anims.opacity)
375
- : 1
373
+ let opacity = 1
374
+ for (const id of item.animationIds) {
375
+ const animation = ctx.items.get(id) as Item.Animation | undefined
376
+ const anim = animation?.anims.opacity
377
+ if (animation?.enabled && anim && keyframesActiveAt(anim.track, time))
378
+ opacity = resolveScalarAnimation(time, anim)
379
+ }
380
+ return opacity
381
+ }
382
+
383
+ function keyframesActiveAt(keys: Keyframes, time: Ms) {
384
+ if (keys.length === 0)
385
+ return false
386
+
387
+ let start = keys[0][0]
388
+ let end = keys[0][0]
389
+ for (const [keyTime] of keys) {
390
+ start = Math.min(start, keyTime)
391
+ end = Math.max(end, keyTime)
392
+ }
393
+
394
+ return time >= start && time <= end
376
395
  }
377
396
 
@@ -177,7 +177,7 @@ export class O {
177
177
  const animation = make(terp, track)
178
178
  const next = {
179
179
  ...item,
180
- animationId: animation.id
180
+ animationIds: [...(item.animationIds ?? []), animation.id]
181
181
  }
182
182
  this.set<T>(item.id, next as Partial<T>)
183
183
  return next