@omnimedia/omnitool 1.1.0-75 → 1.1.0-77
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 +54 -4
- package/package.json +2 -1
- package/s/driver/fns/schematic.ts +11 -2
- package/s/driver/parts/compositor.ts +49 -3
- package/s/driver/utils/find-pixi-filter.ts +24 -0
- package/s/timeline/index.ts +1 -1
- package/s/timeline/parts/filters.ts +484 -0
- package/s/timeline/parts/item.ts +17 -1
- package/s/timeline/renderers/parts/samplers/visual/parts/sample.ts +9 -3
- package/s/timeline/sugar/helpers.ts +35 -2
- package/s/timeline/sugar/o.ts +38 -1
- package/s/timeline/types.ts +2 -0
- package/x/WebGLRenderer-4CHIZDHY.js +2 -0
- package/x/WebGPURenderer-O6WXU2QR.js +2 -0
- package/x/browserAll-WNIOTNNP.js +2 -0
- package/x/{demo/chunk-USLRKDKD.js → chunk-23FOBGX6.js} +2 -2
- package/x/{chunk-A45M2HJC.js.map → chunk-23FOBGX6.js.map} +1 -1
- package/x/{chunk-MWCIWPRL.js → chunk-73XOWA4F.js} +3 -3
- package/x/{chunk-Q7JBQNE4.js → chunk-IAWJKNX5.js} +2 -2
- package/x/{demo/chunk-Q4MWBZHL.js → chunk-KCMVLWBS.js} +2 -2
- package/x/{chunk-4ONWQOPX.js.map → chunk-KCMVLWBS.js.map} +1 -1
- package/x/{chunk-D5CIWPNS.js → chunk-MR32SQ27.js} +2 -2
- package/x/{chunk-W5CN46AR.js → chunk-VCUJJYRJ.js} +3 -3
- package/x/{chunk-WFT3KTZG.js → chunk-XNIZ4L5W.js} +2 -2
- package/x/{chunk-OTQK6FAJ.js → chunk-ZLGNQFUI.js} +2 -2
- package/x/demo/WebGLRenderer-RSJAHIG2.js +2 -0
- package/x/demo/WebGPURenderer-MGFAJCYY.js +2 -0
- package/x/demo/browserAll-PTRBXBRP.js +2 -0
- package/x/demo/{chunk-P3PTHHFE.js → chunk-CUYOGHWU.js} +2 -2
- package/x/demo/{chunk-P3PTHHFE.js.map → chunk-CUYOGHWU.js.map} +1 -1
- package/x/demo/{chunk-IRDQEA6B.js → chunk-DGTDNJ7W.js} +2 -2
- package/x/demo/{chunk-T3METYEY.js → chunk-FZ5BYF63.js} +2 -2
- package/x/demo/{chunk-T3METYEY.js.map → chunk-FZ5BYF63.js.map} +1 -1
- package/x/demo/{chunk-PYG4RZZ2.js → chunk-KWN4NNES.js} +15 -15
- package/x/demo/{chunk-PYG4RZZ2.js.map → chunk-KWN4NNES.js.map} +1 -1
- package/x/{chunk-4ONWQOPX.js → demo/chunk-OJ3FPXW7.js} +2 -2
- package/x/demo/{chunk-Q4MWBZHL.js.map → chunk-OJ3FPXW7.js.map} +1 -1
- package/x/demo/{chunk-RWJ2UHV4.js → chunk-PSLUOGTZ.js} +3 -3
- package/x/demo/{chunk-RWJ2UHV4.js.map → chunk-PSLUOGTZ.js.map} +1 -1
- package/x/demo/{chunk-YISSXWBT.js → chunk-VLCVEIFU.js} +3 -3
- package/x/demo/{chunk-YISSXWBT.js.map → chunk-VLCVEIFU.js.map} +1 -1
- package/x/demo/chunk-ZWCPT5FR.js +2 -0
- package/x/demo/demo.bundle.min.js +4921 -11
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/demo/webworkerAll-JENRT6BT.js +2 -0
- package/x/driver/fns/schematic.d.ts +10 -1
- package/x/driver/parts/compositor.js +35 -1
- package/x/driver/parts/compositor.js.map +1 -1
- package/x/driver/utils/find-pixi-filter.d.ts +5 -0
- package/x/driver/utils/find-pixi-filter.js +13 -0
- package/x/driver/utils/find-pixi-filter.js.map +1 -0
- package/x/index.html +2 -2
- package/x/tests.bundle.min.js +4926 -16
- package/x/tests.bundle.min.js.map +4 -4
- package/x/tests.html +1 -1
- package/x/timeline/index.d.ts +1 -0
- package/x/timeline/index.js +1 -0
- package/x/timeline/index.js.map +1 -1
- package/x/timeline/parts/filters.d.ts +113 -0
- package/x/timeline/parts/filters.js +355 -0
- package/x/timeline/parts/filters.js.map +1 -0
- package/x/timeline/parts/item.d.ts +16 -2
- package/x/timeline/parts/item.js +1 -0
- package/x/timeline/parts/item.js.map +1 -1
- package/x/timeline/parts/waveform/parts/collect.d.ts +1 -1
- package/x/timeline/renderers/parts/samplers/visual/parts/sample.js +8 -2
- package/x/timeline/renderers/parts/samplers/visual/parts/sample.js.map +1 -1
- package/x/timeline/sugar/helpers.d.ts +11 -2
- package/x/timeline/sugar/helpers.js +15 -0
- package/x/timeline/sugar/helpers.js.map +1 -1
- package/x/timeline/sugar/o.d.ts +3 -1
- package/x/timeline/sugar/o.js +31 -0
- package/x/timeline/sugar/o.js.map +1 -1
- package/x/webworkerAll-RLCTMSDD.js +2 -0
- package/x/WebGLRenderer-7X274AYV.js +0 -2
- package/x/WebGPURenderer-XMCMEXAO.js +0 -2
- package/x/browserAll-LRGVU2GN.js +0 -2
- package/x/chunk-A45M2HJC.js +0 -2
- package/x/demo/WebGLRenderer-NLGJGAXK.js +0 -2
- package/x/demo/WebGPURenderer-RBOFXPL5.js +0 -2
- package/x/demo/browserAll-QEV2P3ED.js +0 -2
- package/x/demo/webworkerAll-ELLD4M57.js +0 -2
- package/x/webworkerAll-KR5SWEBU.js +0 -2
- /package/x/{WebGLRenderer-7X274AYV.js.map → WebGLRenderer-4CHIZDHY.js.map} +0 -0
- /package/x/{WebGPURenderer-XMCMEXAO.js.map → WebGPURenderer-O6WXU2QR.js.map} +0 -0
- /package/x/{browserAll-LRGVU2GN.js.map → browserAll-WNIOTNNP.js.map} +0 -0
- /package/x/{chunk-MWCIWPRL.js.map → chunk-73XOWA4F.js.map} +0 -0
- /package/x/{chunk-Q7JBQNE4.js.map → chunk-IAWJKNX5.js.map} +0 -0
- /package/x/{chunk-D5CIWPNS.js.map → chunk-MR32SQ27.js.map} +0 -0
- /package/x/{chunk-W5CN46AR.js.map → chunk-VCUJJYRJ.js.map} +0 -0
- /package/x/{chunk-WFT3KTZG.js.map → chunk-XNIZ4L5W.js.map} +0 -0
- /package/x/{chunk-OTQK6FAJ.js.map → chunk-ZLGNQFUI.js.map} +0 -0
- /package/x/demo/{WebGLRenderer-NLGJGAXK.js.map → WebGLRenderer-RSJAHIG2.js.map} +0 -0
- /package/x/demo/{WebGPURenderer-RBOFXPL5.js.map → WebGPURenderer-MGFAJCYY.js.map} +0 -0
- /package/x/demo/{browserAll-QEV2P3ED.js.map → browserAll-PTRBXBRP.js.map} +0 -0
- /package/x/demo/{chunk-IRDQEA6B.js.map → chunk-DGTDNJ7W.js.map} +0 -0
- /package/x/demo/{chunk-USLRKDKD.js.map → chunk-ZWCPT5FR.js.map} +0 -0
- /package/x/demo/{webworkerAll-ELLD4M57.js.map → webworkerAll-JENRT6BT.js.map} +0 -0
- /package/x/{webworkerAll-KR5SWEBU.js.map → webworkerAll-RLCTMSDD.js.map} +0 -0
package/README.md
CHANGED
|
@@ -37,10 +37,11 @@ const timeline = omni.timeline(o => {
|
|
|
37
37
|
styles: {fill: "white", fontSize: 48}
|
|
38
38
|
})
|
|
39
39
|
const xfade = o.transition.crossfade(500)
|
|
40
|
+
const softened = o.filter.blur.make({strength: 8, quality: 4})
|
|
40
41
|
|
|
41
42
|
return o.sequence(
|
|
42
43
|
o.stack(
|
|
43
|
-
o.video(clip, {start: 0, duration: 3000}),
|
|
44
|
+
o.video(clip, {start: 0, duration: 3000, filterIds: [softened.id]}),
|
|
44
45
|
caption
|
|
45
46
|
),
|
|
46
47
|
o.gap(400),
|
|
@@ -56,7 +57,7 @@ Declarative helper style (no explicit `o` in timeline declarations):
|
|
|
56
57
|
```ts
|
|
57
58
|
import {
|
|
58
59
|
Driver, Omni, Datafile,
|
|
59
|
-
timeline, stack, video, audio, text, gap, transition
|
|
60
|
+
timeline, stack, video, audio, text, gap, transition, filter
|
|
60
61
|
} from "@omnimedia/omnitool"
|
|
61
62
|
|
|
62
63
|
const driver = await Driver.setup()
|
|
@@ -65,7 +66,10 @@ const {clip} = await omni.load({clip: Datafile.make(file)})
|
|
|
65
66
|
|
|
66
67
|
const timeline = timeline(
|
|
67
68
|
stack(
|
|
68
|
-
|
|
69
|
+
filter.blur(
|
|
70
|
+
video(clip, {start: 0, duration: 3000}),
|
|
71
|
+
{strength: 8, quality: 4}
|
|
72
|
+
),
|
|
69
73
|
text("Hello world", {duration: 1500}),
|
|
70
74
|
),
|
|
71
75
|
gap(400),
|
|
@@ -75,6 +79,52 @@ const timeline = timeline(
|
|
|
75
79
|
)
|
|
76
80
|
```
|
|
77
81
|
|
|
82
|
+
## 🎛 Filters
|
|
83
|
+
|
|
84
|
+
Inline filter application:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const timeline = omni.timeline(o =>
|
|
88
|
+
o.stack(
|
|
89
|
+
o.filter.blur(
|
|
90
|
+
o.video(clip, {duration: 3000}),
|
|
91
|
+
{strength: 8, quality: 4}
|
|
92
|
+
),
|
|
93
|
+
o.filter.glow(
|
|
94
|
+
o.text("Hello world", {duration: 3000}),
|
|
95
|
+
{distance: 12, outerStrength: 2, color: "#ffffff"}
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Reusable filter items:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const timeline = omni.timeline(o => {
|
|
105
|
+
const blur = o.filter.blur.make({strength: 8, quality: 4})
|
|
106
|
+
|
|
107
|
+
return o.stack(
|
|
108
|
+
o.video(clip, {duration: 3000, filterIds: [blur.id]}),
|
|
109
|
+
o.text("Caption", {duration: 3000, styles: {fill: "white"}})
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Filter metadata for UI:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import {
|
|
118
|
+
filterTypes,
|
|
119
|
+
filterSchemas,
|
|
120
|
+
getFilterDefaultParams
|
|
121
|
+
} from "@omnimedia/omnitool"
|
|
122
|
+
|
|
123
|
+
const available = Object.entries(filterTypes)
|
|
124
|
+
const schema = filterSchemas.BlurFilter
|
|
125
|
+
const defaults = getFilterDefaultParams("BlurFilter")
|
|
126
|
+
```
|
|
127
|
+
|
|
78
128
|
## 🧭 Spatial Transforms
|
|
79
129
|
|
|
80
130
|
```ts
|
|
@@ -156,6 +206,7 @@ Timeline items:
|
|
|
156
206
|
- 6 `Spatial`
|
|
157
207
|
- 7 `Transition`
|
|
158
208
|
- 8 `TextStyle`
|
|
209
|
+
- 9 `Filter`
|
|
159
210
|
|
|
160
211
|
## 🗺️ Roadmap
|
|
161
212
|
- CLI commands:
|
|
@@ -180,4 +231,3 @@ omnitool ai "make a 15s promo for tea"
|
|
|
180
231
|
- smooth seeking
|
|
181
232
|
- keyframes
|
|
182
233
|
- server-side, not just browsers
|
|
183
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnimedia/omnitool",
|
|
3
|
-
"version": "1.1.0-
|
|
3
|
+
"version": "1.1.0-77",
|
|
4
4
|
"description": "open source video processing tools",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Przemysław Gałęzki",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"gsap": "^3.14.2",
|
|
44
44
|
"lit": "^3.3.2",
|
|
45
45
|
"mediabunny": "^1.27.3",
|
|
46
|
+
"pixi-filters": "^6.1.5",
|
|
46
47
|
"pixi.js": "^8.14.3",
|
|
47
48
|
"wavesurfer.js": "^7.12.1"
|
|
48
49
|
},
|
|
@@ -3,9 +3,10 @@ import {TextStyleOptions} from "pixi.js"
|
|
|
3
3
|
import {AsSchematic} from "@e280/comrade"
|
|
4
4
|
import type {AudioEncodingConfig, StreamTargetChunk, VideoEncodingConfig} from "mediabunny"
|
|
5
5
|
|
|
6
|
-
import {Mat6} from "../../timeline/utils/matrix.js"
|
|
7
6
|
import {Id} from "../../timeline/index.js"
|
|
8
7
|
import {Crop} from "../../timeline/parts/item.js"
|
|
8
|
+
import {Mat6} from "../../timeline/utils/matrix.js"
|
|
9
|
+
import {FilterParams, FilterType} from "../../timeline/parts/filters.js"
|
|
9
10
|
|
|
10
11
|
export type DriverSchematic = AsSchematic<{
|
|
11
12
|
|
|
@@ -74,6 +75,13 @@ export interface MuxOpts {
|
|
|
74
75
|
|
|
75
76
|
export type Composition = Layer | (Layer | Composition)[]
|
|
76
77
|
|
|
78
|
+
export type FilterSpec = {
|
|
79
|
+
[TFilter in FilterType]: {
|
|
80
|
+
type: TFilter
|
|
81
|
+
params?: FilterParams<TFilter>
|
|
82
|
+
}
|
|
83
|
+
}[FilterType]
|
|
84
|
+
|
|
77
85
|
export type TextLayer = {
|
|
78
86
|
id: Id
|
|
79
87
|
kind: 'text'
|
|
@@ -81,6 +89,7 @@ export type TextLayer = {
|
|
|
81
89
|
style?: TextStyleOptions
|
|
82
90
|
matrix?: Mat6
|
|
83
91
|
crop?: Crop
|
|
92
|
+
filters?: FilterSpec[]
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
export type ImageLayer = {
|
|
@@ -89,6 +98,7 @@ export type ImageLayer = {
|
|
|
89
98
|
frame: VideoFrame
|
|
90
99
|
matrix?: Mat6
|
|
91
100
|
crop?: Crop
|
|
101
|
+
filters?: FilterSpec[]
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
export type TransitionLayer = {
|
|
@@ -112,4 +122,3 @@ export type Audio = {
|
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
export type Layer = TextLayer | ImageLayer | TransitionLayer | GapLayer
|
|
115
|
-
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
|
|
2
2
|
import {pub} from "@e280/stz"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
autoDetectRenderer,
|
|
5
|
+
ColorMatrixFilter,
|
|
6
|
+
Container,
|
|
7
|
+
FederatedPointerEvent,
|
|
8
|
+
Filter,
|
|
9
|
+
Graphics,
|
|
10
|
+
Renderer,
|
|
11
|
+
Sprite,
|
|
12
|
+
Text,
|
|
13
|
+
Texture
|
|
14
|
+
} from "pixi.js"
|
|
15
|
+
import * as PixiFilters from "pixi-filters"
|
|
4
16
|
|
|
5
17
|
import {Id} from "../../timeline/index.js"
|
|
6
18
|
import {Crop} from "../../timeline/parts/item.js"
|
|
7
|
-
import {
|
|
19
|
+
import {findPixiFilter} from "../utils/find-pixi-filter.js"
|
|
20
|
+
import {Composition, FilterSpec, Layer} from "../fns/schematic.js"
|
|
8
21
|
import {Mat6, mat6ToMatrix} from "../../timeline/utils/matrix.js"
|
|
9
22
|
import {makeTransition} from "../../features/transition/transition.js"
|
|
10
23
|
|
|
@@ -99,6 +112,7 @@ export class Compositor {
|
|
|
99
112
|
const sprite = this.#findOrCreate<Text>(layer)!
|
|
100
113
|
this.#applyTransform(sprite, layer.matrix)
|
|
101
114
|
this.#applyCrop(sprite, layer.crop)
|
|
115
|
+
this.#applyFilters(sprite, layer.filters)
|
|
102
116
|
parent.addChild(sprite)
|
|
103
117
|
return {
|
|
104
118
|
dispose: () => {}
|
|
@@ -119,6 +133,7 @@ export class Compositor {
|
|
|
119
133
|
sprite.texture = texture
|
|
120
134
|
this.#applyTransform(sprite, layer.matrix)
|
|
121
135
|
this.#applyCrop(sprite, layer.crop)
|
|
136
|
+
this.#applyFilters(sprite, layer.filters)
|
|
122
137
|
parent.addChild(sprite)
|
|
123
138
|
|
|
124
139
|
return {
|
|
@@ -164,7 +179,10 @@ export class Compositor {
|
|
|
164
179
|
return
|
|
165
180
|
|
|
166
181
|
const [top, right, bottom, left] = crop
|
|
182
|
+
const activeMask = target.mask
|
|
183
|
+
target.mask = null
|
|
167
184
|
const bounds = target.getLocalBounds()
|
|
185
|
+
target.mask = activeMask
|
|
168
186
|
const x = bounds.x + bounds.width * left
|
|
169
187
|
const y = bounds.y + bounds.height * top
|
|
170
188
|
const width = bounds.width * Math.max(0, 1 - left - right)
|
|
@@ -180,6 +198,35 @@ export class Compositor {
|
|
|
180
198
|
this.#cropMasks.set(target, mask)
|
|
181
199
|
}
|
|
182
200
|
|
|
201
|
+
#applyFilters(target: Container, specs: FilterSpec[] | undefined) {
|
|
202
|
+
if (!specs?.length) {
|
|
203
|
+
target.filters = null
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
target.filters = specs
|
|
208
|
+
.map((spec): Filter | undefined => {
|
|
209
|
+
switch (spec.type) {
|
|
210
|
+
case "ColorMatrixFilter": {
|
|
211
|
+
const {matrix, ...params} = spec.params ?? {}
|
|
212
|
+
const filter = new ColorMatrixFilter(params)
|
|
213
|
+
if (matrix)
|
|
214
|
+
filter.matrix = matrix
|
|
215
|
+
return filter
|
|
216
|
+
}
|
|
217
|
+
case "EmbossFilter":
|
|
218
|
+
return new PixiFilters.EmbossFilter(spec.params?.strength)
|
|
219
|
+
case "PixelateFilter":
|
|
220
|
+
return new PixiFilters.PixelateFilter(spec.params?.size)
|
|
221
|
+
default: {
|
|
222
|
+
const PixiFilter = findPixiFilter(spec.type)
|
|
223
|
+
return PixiFilter ? new PixiFilter(spec.params) : undefined
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.filter((filter): filter is Filter => !!filter)
|
|
228
|
+
}
|
|
229
|
+
|
|
183
230
|
#findOrCreate<T = Container>(layer: Layer) {
|
|
184
231
|
const object = this.#activeObjects.get(layer.id)
|
|
185
232
|
if(!object) {
|
|
@@ -261,4 +308,3 @@ export class Compositor {
|
|
|
261
308
|
}
|
|
262
309
|
}
|
|
263
310
|
}
|
|
264
|
-
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AlphaFilter,
|
|
3
|
+
BlurFilter,
|
|
4
|
+
ColorMatrixFilter,
|
|
5
|
+
NoiseFilter,
|
|
6
|
+
Filter,
|
|
7
|
+
} from "pixi.js"
|
|
8
|
+
import * as PixiFilters from "pixi-filters"
|
|
9
|
+
|
|
10
|
+
import type {FilterType} from "../../timeline/parts/filters.js"
|
|
11
|
+
|
|
12
|
+
type FilterConstructor = new (options?: any) => Filter
|
|
13
|
+
|
|
14
|
+
const pixiFilters: Partial<Record<FilterType, FilterConstructor>> = {
|
|
15
|
+
AlphaFilter,
|
|
16
|
+
BlurFilter,
|
|
17
|
+
ColorMatrixFilter,
|
|
18
|
+
NoiseFilter,
|
|
19
|
+
...PixiFilters
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function findPixiFilter(type: FilterType) {
|
|
23
|
+
return pixiFilters[type]
|
|
24
|
+
}
|
package/s/timeline/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
export * from "./parts/basics.js"
|
|
3
|
+
export * from "./parts/filters.js"
|
|
3
4
|
export * from "./parts/item.js"
|
|
4
5
|
export * from "./parts/media.js"
|
|
5
6
|
export * from "./parts/resource-pool.js"
|
|
@@ -16,4 +17,3 @@ export * from "./sugar/omni.js"
|
|
|
16
17
|
|
|
17
18
|
export * from "./utils/checksum.js"
|
|
18
19
|
export * from "./utils/datafile.js"
|
|
19
|
-
|