@omnimedia/omnitool 1.1.0-46 → 1.1.0-47
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 +117 -81
- package/package.json +1 -1
- package/s/demo/demo.bundle.ts +1 -1
- package/s/demo/routines/playback-test.ts +3 -4
- package/s/timeline/parts/renderers/export.ts +4 -5
- package/s/timeline/sugar/omni.ts +15 -4
- package/x/demo/demo.bundle.js +1 -1
- package/x/demo/demo.bundle.js.map +1 -1
- package/x/demo/demo.bundle.min.js +5 -5
- package/x/demo/demo.bundle.min.js.map +3 -3
- package/x/demo/routines/playback-test.d.ts +1 -2
- package/x/demo/routines/playback-test.js +3 -3
- package/x/demo/routines/playback-test.js.map +1 -1
- package/x/index.html +2 -2
- package/x/timeline/parts/renderers/export.d.ts +2 -3
- package/x/timeline/parts/renderers/export.js +4 -6
- package/x/timeline/parts/renderers/export.js.map +1 -1
- package/x/timeline/sugar/omni.d.ts +3 -1
- package/x/timeline/sugar/omni.js +7 -3
- package/x/timeline/sugar/omni.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,120 +1,156 @@
|
|
|
1
1
|
|
|
2
2
|
# 🚧 Work In Progress
|
|
3
3
|
|
|
4
|
-
> **Note:**
|
|
4
|
+
> **Note:** Omnitool is under development. Expect breaking changes, evolving APIs, and experimental features.
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## ✅ What this library is
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
- API for building and rendering timelines in the browser
|
|
11
|
+
- Uses WebCodecs, Web Workers, and the File System Access API for export
|
|
12
|
+
- usage is currently JavaScript/TypeScript only, cli soon
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
## 🚀 Install
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
```bash
|
|
17
|
+
npm i @omnimedia/omnitool
|
|
18
|
+
```
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
## 📦 Quick Start
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
```ts
|
|
23
|
+
import {Driver, Omni, Datafile} from "@omnimedia/omnitool"
|
|
24
|
+
|
|
25
|
+
const driver = await Driver.setup()
|
|
26
|
+
const omni = new Omni(driver)
|
|
27
|
+
|
|
28
|
+
const {clip} = await omni.load({
|
|
29
|
+
clip: Datafile.make(file) // file is a File or Blob
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const timeline = omni.timeline(o => {
|
|
33
|
+
const caption = o.text("Hello world", {
|
|
34
|
+
duration: 1500,
|
|
35
|
+
styles: {fill: "white", fontSize: 48}
|
|
36
|
+
})
|
|
37
|
+
const xfade = o.transition.crossfade(500)
|
|
38
|
+
|
|
39
|
+
return o.sequence(
|
|
40
|
+
o.stack(
|
|
41
|
+
o.video(clip, {start: 0, duration: 3000}),
|
|
42
|
+
caption
|
|
43
|
+
),
|
|
44
|
+
o.gap(400),
|
|
45
|
+
xfade,
|
|
46
|
+
o.video(clip, {start: 5000, duration: 2500}),
|
|
47
|
+
o.audio(clip, {start: 5000, duration: 2500})
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
```
|
|
21
51
|
|
|
22
|
-
|
|
52
|
+
## 🧭 Spatial Transforms
|
|
23
53
|
|
|
24
|
-
|
|
54
|
+
```ts
|
|
55
|
+
const timeline = omni.timeline(o => {
|
|
56
|
+
const move = o.spatial(o.transform({
|
|
57
|
+
position: [120, 40],
|
|
58
|
+
scale: [0.6, 0.6],
|
|
59
|
+
rotation: 0.2
|
|
60
|
+
}))
|
|
61
|
+
|
|
62
|
+
const title = o.text("Lower third", {
|
|
63
|
+
duration: 2000,
|
|
64
|
+
styles: {fill: "white", fontSize: 36}
|
|
65
|
+
})
|
|
66
|
+
o.set(title.id, {spatialId: move.id})
|
|
67
|
+
|
|
68
|
+
return o.stack(
|
|
69
|
+
o.video(clip, {duration: 4000}),
|
|
70
|
+
title
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
```
|
|
25
74
|
|
|
26
|
-
|
|
75
|
+
Worker URL notes:
|
|
76
|
+
- `Driver.setup()` defaults to `/node_modules/@omnimedia/omnitool/x/driver/driver.worker.bundle.min.js`.
|
|
77
|
+
- If you serve the worker from a different location, pass `workerUrl`:
|
|
27
78
|
|
|
28
|
-
```
|
|
29
|
-
|
|
79
|
+
```ts
|
|
80
|
+
const workerUrl = new URL(
|
|
81
|
+
"/path/to/driver.worker.bundle.min.js",
|
|
82
|
+
window.location.href
|
|
83
|
+
)
|
|
84
|
+
const driver = await Driver.setup({workerUrl})
|
|
30
85
|
```
|
|
31
86
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## 📦 Example (Programmatic Timeline)
|
|
87
|
+
## ▶️ Playback
|
|
35
88
|
|
|
36
89
|
```ts
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const timeline = sequence(
|
|
43
|
-
video("opening-credits.mp4"),
|
|
44
|
-
xfade,
|
|
45
|
-
stack(
|
|
46
|
-
video("skateboarding.mp4"),
|
|
47
|
-
watermark
|
|
48
|
-
),
|
|
49
|
-
xfade,
|
|
50
|
-
stack(
|
|
51
|
-
video("biking.mp4"),
|
|
52
|
-
watermark
|
|
53
|
-
)
|
|
54
|
-
)
|
|
55
|
-
|
|
90
|
+
const player = await omni.playback(timeline)
|
|
91
|
+
|
|
92
|
+
document.body.appendChild(player.canvas)
|
|
93
|
+
player.play()
|
|
56
94
|
```
|
|
57
95
|
|
|
58
|
-
|
|
96
|
+
Notes:
|
|
97
|
+
- Call `player.update(timeline)` if you update the timeline.
|
|
98
|
+
|
|
99
|
+
## 📤 Export
|
|
59
100
|
|
|
60
|
-
|
|
101
|
+
```ts
|
|
102
|
+
await omni.render(timeline, framerate)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 🧩 Timeline Format (TimelineFile)
|
|
61
106
|
|
|
62
|
-
|
|
107
|
+
All durations and timestamps are in milliseconds.
|
|
63
108
|
|
|
64
109
|
```json
|
|
65
110
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
111
|
+
"format": "timeline",
|
|
112
|
+
"info": "https://omniclip.app/",
|
|
113
|
+
"version": 0,
|
|
114
|
+
"rootId": 123,
|
|
115
|
+
"items": [
|
|
116
|
+
{"id": 123, "kind": 0, "childrenIds": [456, 789]},
|
|
117
|
+
{"id": 456, "kind": 2, "mediaHash": "...", "start": 0, "duration": 3000},
|
|
118
|
+
{"id": 789, "kind": 4, "content": "Hello", "duration": 1500}
|
|
119
|
+
]
|
|
75
120
|
}
|
|
76
121
|
```
|
|
77
122
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
123
|
+
Timeline items:
|
|
124
|
+
- 0 `Sequence`
|
|
125
|
+
- 1 `Stack`
|
|
126
|
+
- 2 `Video`
|
|
127
|
+
- 3 `Audio`
|
|
128
|
+
- 4 `Text`
|
|
129
|
+
- 5 `Gap`
|
|
130
|
+
- 6 `Spatial`
|
|
131
|
+
- 7 `Transition`
|
|
132
|
+
- 8 `TextStyle`
|
|
81
133
|
|
|
82
|
-
##
|
|
134
|
+
## 🗺️ Roadmap
|
|
135
|
+
- Planned CLI commands (not available in this repo yet):
|
|
83
136
|
|
|
84
137
|
```bash
|
|
85
|
-
#
|
|
138
|
+
# build a reusable template from a timeline
|
|
86
139
|
omnitool build-template promo.json
|
|
87
|
-
|
|
88
|
-
# Validate structure
|
|
140
|
+
# validate a timeline file
|
|
89
141
|
omnitool validate promo.json
|
|
90
|
-
|
|
91
|
-
# Render video
|
|
142
|
+
# export a timeline to a video file
|
|
92
143
|
omnitool export promo.json --output final.mp4
|
|
93
|
-
|
|
94
|
-
# Batch render
|
|
144
|
+
# batch export multiple timelines
|
|
95
145
|
omnitool batch-export ./projects/* --output-dir ./exports
|
|
146
|
+
# headless timeline viewer
|
|
147
|
+
omnitool preview promo.json
|
|
148
|
+
# auto-fit timeline elements
|
|
149
|
+
omnitool optimize promo.json
|
|
150
|
+
# prompt-to-timeline generation
|
|
151
|
+
omnitool ai "make a 15s promo for tea"
|
|
96
152
|
```
|
|
97
153
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
## ✅ Use Cases
|
|
101
|
-
|
|
102
|
-
- Render videos from scripts, templates, or AI
|
|
103
|
-
- Build and test timelines without opening the UI
|
|
104
|
-
- Generate video pipelines from code or prompts
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## 📘 More to come
|
|
109
|
-
|
|
110
|
-
- `omnitool preview` – headless timeline viewer
|
|
111
|
-
- `omnitool optimize` – auto-fit timeline elements
|
|
112
|
-
- `omnitool ai` – native prompt-to-timeline generation
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## 🧠 Learn More
|
|
117
|
-
|
|
118
|
-
Omni Tools powers AI agents, programmatic editing, and upcoming new version of omniclip video editor.
|
|
154
|
+
- smooth seeking
|
|
155
|
+
- server-side, not just browsers
|
|
119
156
|
|
|
120
|
-
→ [Visit Omniclip](https://omniclip.app)
|
package/package.json
CHANGED
package/s/demo/demo.bundle.ts
CHANGED
|
@@ -38,7 +38,7 @@ async function startDemoImport(e: Event)
|
|
|
38
38
|
|
|
39
39
|
const {timeline, omni} = await TimelineSchemaTest(driver, file)
|
|
40
40
|
|
|
41
|
-
playbackTest(
|
|
41
|
+
playbackTest(timeline, omni)
|
|
42
42
|
exportTest(omni, timeline)
|
|
43
43
|
}
|
|
44
44
|
// const [fileHandle] = await window.showOpenFilePicker()
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
3
|
-
import {O, Omni, TimelineFile, VideoPlayer} from "../../timeline/index.js"
|
|
2
|
+
import {O, Omni, TimelineFile} from "../../timeline/index.js"
|
|
4
3
|
|
|
5
|
-
export async function playbackTest(
|
|
4
|
+
export async function playbackTest(timeline: TimelineFile, omni: Omni) {
|
|
6
5
|
const playButton = document.querySelector(".play") as HTMLButtonElement
|
|
7
6
|
const stopButton = document.querySelector(".stop") as HTMLButtonElement
|
|
8
7
|
const seekButton = document.querySelector(".seek") as HTMLButtonElement
|
|
9
8
|
const o = new O({project: timeline})
|
|
10
|
-
const player = await
|
|
9
|
+
const player = await omni.playback(timeline)
|
|
11
10
|
document.body.appendChild(player.canvas)
|
|
12
11
|
|
|
13
12
|
playButton.addEventListener("click", () => player.play())
|
|
@@ -9,8 +9,7 @@ export class Export {
|
|
|
9
9
|
#sampler
|
|
10
10
|
constructor(
|
|
11
11
|
private driver: Driver,
|
|
12
|
-
private
|
|
13
|
-
private resolveMedia: (hash: string) => DecoderSource = _hash => "/assets/temp/gl.mp4"
|
|
12
|
+
private resolveMedia: (hash: string) => DecoderSource
|
|
14
13
|
) {
|
|
15
14
|
this.#sampler = makeWebCodecsSampler(this.driver, this.resolveMedia)
|
|
16
15
|
}
|
|
@@ -21,7 +20,7 @@ export class Export {
|
|
|
21
20
|
return await buildWebCodecsNodeTree(rootItem, items, this.#sampler)
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
async render(timeline: TimelineFile) {
|
|
23
|
+
async render(timeline: TimelineFile, framerate: number) {
|
|
25
24
|
const root = await this.#build(timeline)
|
|
26
25
|
|
|
27
26
|
const videoStream = new TransformStream<VideoFrame, VideoFrame>()
|
|
@@ -50,10 +49,10 @@ export class Export {
|
|
|
50
49
|
|
|
51
50
|
const videoPromise = (async () => {
|
|
52
51
|
let i = 0
|
|
53
|
-
const dt = 1 /
|
|
52
|
+
const dt = 1 / framerate
|
|
54
53
|
|
|
55
54
|
await fixedStep(
|
|
56
|
-
{fps:
|
|
55
|
+
{fps: framerate, duration: root.duration ?? 0},
|
|
57
56
|
async t => {
|
|
58
57
|
const layers = await root.visuals?.sampleAt(t) ?? []
|
|
59
58
|
const composed = await this.driver.composite(layers)
|
package/s/timeline/sugar/omni.ts
CHANGED
|
@@ -7,14 +7,17 @@ import {Datafile} from "../utils/datafile.js"
|
|
|
7
7
|
import {TimelineFile} from "../parts/basics.js"
|
|
8
8
|
import {Export} from "../parts/renderers/export.js"
|
|
9
9
|
import {ResourcePool} from "../parts/resource-pool.js"
|
|
10
|
-
import {
|
|
10
|
+
import {VideoPlayer} from "../parts/renderers/playback.js"
|
|
11
11
|
|
|
12
12
|
export class Omni {
|
|
13
13
|
resources = new ResourcePool()
|
|
14
14
|
#export: Export
|
|
15
15
|
|
|
16
16
|
constructor(private driver: Driver) {
|
|
17
|
-
this.#export = new Export(
|
|
17
|
+
this.#export = new Export(
|
|
18
|
+
driver,
|
|
19
|
+
(hash) => this.resources.require(hash).url
|
|
20
|
+
)
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
load = async<S extends Record<string, Promise<Datafile>>>(spec: S) => {
|
|
@@ -38,8 +41,16 @@ export class Omni {
|
|
|
38
41
|
return o.state.project
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
await
|
|
44
|
+
playback = async (timeline: TimelineFile) => {
|
|
45
|
+
return await VideoPlayer.create(
|
|
46
|
+
this.driver,
|
|
47
|
+
timeline,
|
|
48
|
+
(hash) => this.resources.require(hash).url
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
render = async (timeline: TimelineFile, framerate: number = 30) => {
|
|
53
|
+
await this.#export.render(timeline, framerate)
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
|
package/x/demo/demo.bundle.js
CHANGED
|
@@ -30,7 +30,7 @@ async function startDemoImport(e) {
|
|
|
30
30
|
run(transcode, file.name);
|
|
31
31
|
// await transcriber.transcribe(file)
|
|
32
32
|
const { timeline, omni } = await TimelineSchemaTest(driver, file);
|
|
33
|
-
playbackTest(
|
|
33
|
+
playbackTest(timeline, omni);
|
|
34
34
|
exportTest(omni, timeline);
|
|
35
35
|
}
|
|
36
36
|
// const [fileHandle] = await window.showOpenFilePicker()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"demo.bundle.js","sourceRoot":"","sources":["../../s/demo/demo.bundle.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAC,UAAU,EAAC,MAAM,2BAA2B,CAAA;AACpD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAA;AACxD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAA;AACxD,OAAO,EAAC,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAC,kBAAkB,EAAC,MAAM,8BAA8B,CAAA;AAE/D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAC,SAAS,EAAE,IAAI,GAAG,CAAC,uCAAuC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAC,CAAC,CAAA;AACjH,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAE,CAAA;AAEnD,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;AACpD,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,aAAa,CAAqB,CAAA;AAE3E,WAAW,EAAE,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;AACtD,SAAS,EAAE,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;AAErD,YAAY,CAAC,MAAM,CAAC,CAAA;AACpB,oDAAoD;AAEpD,mBAAmB;AACnB,CAAC;IACA,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;IAChC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;;QACxD,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;AACrD,CAAC;AAED,oBAAoB;AACpB,KAAK,UAAU,eAAe,CAAC,CAAQ;IAEtC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACjC,IAAG,IAAI,EAAE,CAAC;QACT,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAClD,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QACzB,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QACzB,qCAAqC;QAErC,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAC,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAE/D,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"demo.bundle.js","sourceRoot":"","sources":["../../s/demo/demo.bundle.ts"],"names":[],"mappings":"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"}
|