@omnimedia/omnitool 1.1.0-47 → 1.1.0-48

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 (308) hide show
  1. package/README.md +28 -1
  2. package/package.json +2 -2
  3. package/s/demo/demo.bundle.ts +97 -48
  4. package/s/demo/demo.css +244 -14
  5. package/s/demo/routines/export-test.ts +12 -4
  6. package/s/demo/routines/filmstrip-test.ts +22 -18
  7. package/s/demo/routines/load-video.ts +2 -3
  8. package/s/demo/routines/playback-test.ts +67 -10
  9. package/s/demo/routines/timeline-setup.ts +2 -2
  10. package/s/demo/routines/transcode-test.ts +11 -1
  11. package/s/demo/routines/waveform-test.ts +7 -6
  12. package/s/driver/driver.ts +7 -13
  13. package/s/driver/fns/schematic.ts +1 -1
  14. package/s/driver/fns/work.ts +22 -32
  15. package/s/index.html.ts +103 -25
  16. package/s/tests.bundle.ts +11 -0
  17. package/s/tests.html.ts +28 -0
  18. package/s/timeline/index.ts +2 -1
  19. package/s/timeline/parts/filmstrip.ts +1 -1
  20. package/s/timeline/parts/item.ts +20 -10
  21. package/s/timeline/parts/media.ts +3 -2
  22. package/s/timeline/parts/resource-pool.ts +1 -2
  23. package/s/timeline/renderers/export/parts/audio-gain.ts +17 -0
  24. package/s/timeline/renderers/export/parts/audio-mix.ts +133 -0
  25. package/s/timeline/renderers/export/parts/cursor.ts +109 -0
  26. package/s/timeline/renderers/export/parts/produce-audio.ts +64 -0
  27. package/s/timeline/renderers/export/parts/produce-video.ts +50 -0
  28. package/s/timeline/renderers/export/parts/resamplers.ts +48 -0
  29. package/s/timeline/renderers/export/produce.ts +28 -0
  30. package/s/timeline/renderers/parts/handy.ts +360 -0
  31. package/s/timeline/renderers/parts/samplers/audio/parts/find.ts +19 -0
  32. package/s/timeline/renderers/parts/samplers/audio/parts/init.ts +60 -0
  33. package/s/timeline/renderers/parts/samplers/audio/parts/sink.ts +38 -0
  34. package/s/timeline/renderers/parts/samplers/audio/parts/types.ts +16 -0
  35. package/s/timeline/renderers/parts/samplers/audio/sampler.ts +35 -0
  36. package/s/timeline/renderers/parts/samplers/visual/parts/defaults.ts +16 -0
  37. package/s/timeline/renderers/parts/samplers/visual/parts/sample.ts +59 -0
  38. package/s/timeline/renderers/parts/samplers/visual/parts/sequence.ts +111 -0
  39. package/s/timeline/renderers/parts/samplers/visual/parts/sink.ts +38 -0
  40. package/s/timeline/renderers/parts/samplers/visual/parts/transition.ts +28 -0
  41. package/s/timeline/renderers/parts/samplers/visual/parts/types.ts +10 -0
  42. package/s/timeline/renderers/parts/samplers/visual/sampler.ts +28 -0
  43. package/s/timeline/renderers/parts/schedulers.ts +96 -0
  44. package/s/timeline/renderers/player/parts/playback.ts +123 -0
  45. package/s/timeline/renderers/player/player.ts +71 -0
  46. package/s/timeline/renderers/renderers.test.ts +387 -0
  47. package/s/timeline/sugar/helpers.ts +85 -0
  48. package/s/timeline/sugar/o.ts +9 -7
  49. package/s/timeline/sugar/omni.test.ts +210 -0
  50. package/s/timeline/sugar/omni.ts +21 -23
  51. package/s/timeline/utils/checksum.ts +3 -1
  52. package/s/units/fps.ts +8 -0
  53. package/s/units/ms.ts +8 -0
  54. package/s/units/seconds.ts +8 -0
  55. package/x/WebGLRenderer-7X274AYV.js +2 -0
  56. package/x/WebGPURenderer-XMCMEXAO.js +2 -0
  57. package/x/browserAll-6TVTCHHE.js +2 -0
  58. package/x/browserAll-6TVTCHHE.js.map +7 -0
  59. package/x/{demo/chunk-X2GHKWPJ.js → chunk-4ONWQOPX.js} +2 -2
  60. package/x/chunk-4ONWQOPX.js.map +7 -0
  61. package/x/{demo/chunk-LAJHJD2S.js → chunk-63NSCXPX.js} +2 -2
  62. package/x/chunk-63NSCXPX.js.map +7 -0
  63. package/x/{demo/chunk-TBWCKYN2.js → chunk-A45M2HJC.js} +2 -2
  64. package/x/chunk-A45M2HJC.js.map +7 -0
  65. package/x/{demo/chunk-TLDBHU4V.js → chunk-OTQK6FAJ.js} +2 -2
  66. package/x/chunk-OTQK6FAJ.js.map +7 -0
  67. package/x/{demo/chunk-6DBMQOFE.js → chunk-Q7JBQNE4.js} +2 -2
  68. package/x/chunk-Q7JBQNE4.js.map +7 -0
  69. package/x/{demo/chunk-2RBLPWNG.js → chunk-W33LM336.js} +2 -2
  70. package/x/chunk-W33LM336.js.map +7 -0
  71. package/x/{demo/chunk-RFNLITDQ.js → chunk-W5CN46AR.js} +2 -2
  72. package/x/chunk-W5CN46AR.js.map +7 -0
  73. package/x/{demo/chunk-LQU5JKKZ.js → chunk-WFT3KTZG.js} +1 -1
  74. package/x/chunk-WFT3KTZG.js.map +7 -0
  75. package/x/demo/WebGLRenderer-NLGJGAXK.js +2 -0
  76. package/x/demo/WebGPURenderer-RBOFXPL5.js +2 -0
  77. package/x/demo/WebGPURenderer-RBOFXPL5.js.map +7 -0
  78. package/x/demo/browserAll-5AZHDDG6.js +2 -0
  79. package/x/demo/chunk-5ZZYIILO.js +393 -0
  80. package/x/demo/{chunk-2RBLPWNG.js.map → chunk-5ZZYIILO.js.map} +1 -1
  81. package/x/demo/chunk-P3PTHHFE.js +42 -0
  82. package/x/demo/{chunk-6DBMQOFE.js.map → chunk-P3PTHHFE.js.map} +1 -1
  83. package/x/demo/chunk-PYG4RZZ2.js +269 -0
  84. package/x/demo/{chunk-LQU5JKKZ.js.map → chunk-PYG4RZZ2.js.map} +1 -1
  85. package/x/demo/chunk-Q4MWBZHL.js +157 -0
  86. package/x/demo/{chunk-X2GHKWPJ.js.map → chunk-Q4MWBZHL.js.map} +1 -1
  87. package/x/demo/chunk-T3METYEY.js +15 -0
  88. package/x/demo/{chunk-TLDBHU4V.js.map → chunk-T3METYEY.js.map} +1 -1
  89. package/x/demo/chunk-USLRKDKD.js +2 -0
  90. package/x/demo/{chunk-TBWCKYN2.js.map → chunk-USLRKDKD.js.map} +1 -1
  91. package/x/demo/chunk-YISSXWBT.js +327 -0
  92. package/x/demo/{chunk-RFNLITDQ.js.map → chunk-YISSXWBT.js.map} +1 -1
  93. package/x/demo/chunk-YJQWVIHX.js +2 -0
  94. package/x/demo/demo.bundle.js +87 -43
  95. package/x/demo/demo.bundle.js.map +1 -1
  96. package/x/demo/demo.bundle.min.js +10 -9
  97. package/x/demo/demo.bundle.min.js.map +4 -4
  98. package/x/demo/demo.css +244 -14
  99. package/x/demo/routines/export-test.d.ts +1 -1
  100. package/x/demo/routines/export-test.js +6 -3
  101. package/x/demo/routines/export-test.js.map +1 -1
  102. package/x/demo/routines/filmstrip-test.d.ts +1 -1
  103. package/x/demo/routines/filmstrip-test.js +20 -17
  104. package/x/demo/routines/filmstrip-test.js.map +1 -1
  105. package/x/demo/routines/load-video.d.ts +1 -1
  106. package/x/demo/routines/load-video.js +1 -2
  107. package/x/demo/routines/load-video.js.map +1 -1
  108. package/x/demo/routines/playback-test.d.ts +1 -1
  109. package/x/demo/routines/playback-test.js +58 -10
  110. package/x/demo/routines/playback-test.js.map +1 -1
  111. package/x/demo/routines/timeline-setup.js +1 -1
  112. package/x/demo/routines/timeline-setup.js.map +1 -1
  113. package/x/demo/routines/transcode-test.js +7 -1
  114. package/x/demo/routines/transcode-test.js.map +1 -1
  115. package/x/demo/routines/waveform-test.d.ts +1 -1
  116. package/x/demo/routines/waveform-test.js +7 -6
  117. package/x/demo/routines/waveform-test.js.map +1 -1
  118. package/x/demo/webworkerAll-QKIC5O27.js +2 -0
  119. package/x/demo/webworkerAll-QKIC5O27.js.map +7 -0
  120. package/x/driver/driver.d.ts +5 -1
  121. package/x/driver/driver.js +6 -13
  122. package/x/driver/driver.js.map +1 -1
  123. package/x/driver/driver.worker.bundle.min.js +1 -1
  124. package/x/driver/driver.worker.bundle.min.js.map +3 -3
  125. package/x/driver/fns/host.d.ts +1 -1
  126. package/x/driver/fns/schematic.d.ts +1 -1
  127. package/x/driver/fns/work.d.ts +1 -1
  128. package/x/driver/fns/work.js +22 -31
  129. package/x/driver/fns/work.js.map +1 -1
  130. package/x/index.html +347 -39
  131. package/x/index.html.js +103 -25
  132. package/x/index.html.js.map +1 -1
  133. package/x/tests.bundle.js +8 -0
  134. package/x/tests.bundle.js.map +1 -0
  135. package/x/tests.bundle.min.js +2464 -0
  136. package/x/tests.bundle.min.js.map +7 -0
  137. package/x/tests.html +316 -0
  138. package/x/tests.html.d.ts +2 -0
  139. package/x/tests.html.js +22 -0
  140. package/x/tests.html.js.map +1 -0
  141. package/x/timeline/index.d.ts +2 -1
  142. package/x/timeline/index.js +2 -1
  143. package/x/timeline/index.js.map +1 -1
  144. package/x/timeline/parts/filmstrip.d.ts +1 -1
  145. package/x/timeline/parts/item.d.ts +8 -0
  146. package/x/timeline/parts/item.js.map +1 -1
  147. package/x/timeline/parts/media.js +3 -2
  148. package/x/timeline/parts/media.js.map +1 -1
  149. package/x/timeline/parts/resource-pool.d.ts +2 -1
  150. package/x/timeline/parts/resource-pool.js.map +1 -1
  151. package/x/timeline/renderers/export/parts/audio-gain.d.ts +1 -0
  152. package/x/timeline/renderers/export/parts/audio-gain.js +13 -0
  153. package/x/timeline/renderers/export/parts/audio-gain.js.map +1 -0
  154. package/x/timeline/renderers/export/parts/audio-mix.d.ts +21 -0
  155. package/x/timeline/renderers/export/parts/audio-mix.js +89 -0
  156. package/x/timeline/renderers/export/parts/audio-mix.js.map +1 -0
  157. package/x/timeline/renderers/export/parts/cursor.d.ts +19 -0
  158. package/x/timeline/renderers/export/parts/cursor.js +80 -0
  159. package/x/timeline/renderers/export/parts/cursor.js.map +1 -0
  160. package/x/timeline/renderers/export/parts/produce-audio.d.ts +6 -0
  161. package/x/timeline/renderers/export/parts/produce-audio.js +41 -0
  162. package/x/timeline/renderers/export/parts/produce-audio.js.map +1 -0
  163. package/x/timeline/renderers/export/parts/produce-video.d.ts +10 -0
  164. package/x/timeline/renderers/export/parts/produce-video.js +27 -0
  165. package/x/timeline/renderers/export/parts/produce-video.js.map +1 -0
  166. package/x/timeline/renderers/export/parts/resamplers.d.ts +12 -0
  167. package/x/timeline/renderers/export/parts/resamplers.js +29 -0
  168. package/x/timeline/renderers/export/parts/resamplers.js.map +1 -0
  169. package/x/timeline/renderers/export/produce.d.ts +13 -0
  170. package/x/timeline/renderers/export/produce.js +15 -0
  171. package/x/timeline/renderers/export/produce.js.map +1 -0
  172. package/x/timeline/renderers/parts/handy.d.ts +30 -0
  173. package/x/timeline/renderers/parts/handy.js +219 -0
  174. package/x/timeline/renderers/parts/handy.js.map +1 -0
  175. package/x/timeline/renderers/parts/samplers/audio/parts/find.d.ts +6 -0
  176. package/x/timeline/renderers/parts/samplers/audio/parts/find.js +15 -0
  177. package/x/timeline/renderers/parts/samplers/audio/parts/find.js.map +1 -0
  178. package/x/timeline/renderers/parts/samplers/audio/parts/init.d.ts +5 -0
  179. package/x/timeline/renderers/parts/samplers/audio/parts/init.js +40 -0
  180. package/x/timeline/renderers/parts/samplers/audio/parts/init.js.map +1 -0
  181. package/x/timeline/renderers/parts/samplers/audio/parts/sink.d.ts +8 -0
  182. package/x/timeline/renderers/parts/samplers/audio/parts/sink.js +24 -0
  183. package/x/timeline/renderers/parts/samplers/audio/parts/sink.js.map +1 -0
  184. package/x/timeline/renderers/parts/samplers/audio/parts/types.d.ts +14 -0
  185. package/x/timeline/renderers/parts/samplers/audio/parts/types.js +2 -0
  186. package/x/timeline/renderers/parts/samplers/audio/parts/types.js.map +1 -0
  187. package/x/timeline/renderers/parts/samplers/audio/sampler.d.ts +11 -0
  188. package/x/timeline/renderers/parts/samplers/audio/sampler.js +22 -0
  189. package/x/timeline/renderers/parts/samplers/audio/sampler.js.map +1 -0
  190. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.d.ts +5 -0
  191. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.js +10 -0
  192. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.js.map +1 -0
  193. package/x/timeline/renderers/parts/samplers/visual/parts/sample.d.ts +5 -0
  194. package/x/timeline/renderers/parts/samplers/visual/parts/sample.js +38 -0
  195. package/x/timeline/renderers/parts/samplers/visual/parts/sample.js.map +1 -0
  196. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.d.ts +5 -0
  197. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.js +75 -0
  198. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.js.map +1 -0
  199. package/x/timeline/renderers/parts/samplers/visual/parts/sink.d.ts +8 -0
  200. package/x/timeline/renderers/parts/samplers/visual/parts/sink.js +24 -0
  201. package/x/timeline/renderers/parts/samplers/visual/parts/sink.js.map +1 -0
  202. package/x/timeline/renderers/parts/samplers/visual/parts/transition.d.ts +3 -0
  203. package/x/timeline/renderers/parts/samplers/visual/parts/transition.js +18 -0
  204. package/x/timeline/renderers/parts/samplers/visual/parts/transition.js.map +1 -0
  205. package/x/timeline/renderers/parts/samplers/visual/parts/types.d.ts +8 -0
  206. package/x/timeline/renderers/parts/samplers/visual/parts/types.js +2 -0
  207. package/x/timeline/renderers/parts/samplers/visual/parts/types.js.map +1 -0
  208. package/x/timeline/renderers/parts/samplers/visual/sampler.d.ts +7 -0
  209. package/x/timeline/renderers/parts/samplers/visual/sampler.js +17 -0
  210. package/x/timeline/renderers/parts/samplers/visual/sampler.js.map +1 -0
  211. package/x/timeline/renderers/parts/schedulers.d.ts +17 -0
  212. package/x/timeline/renderers/parts/schedulers.js +64 -0
  213. package/x/timeline/renderers/parts/schedulers.js.map +1 -0
  214. package/x/timeline/renderers/player/parts/playback.d.ts +30 -0
  215. package/x/timeline/renderers/player/parts/playback.js +88 -0
  216. package/x/timeline/renderers/player/parts/playback.js.map +1 -0
  217. package/x/timeline/renderers/player/player.d.ts +23 -0
  218. package/x/timeline/renderers/player/player.js +50 -0
  219. package/x/timeline/renderers/player/player.js.map +1 -0
  220. package/x/timeline/renderers/renderers.test.d.ts +32 -0
  221. package/x/timeline/renderers/renderers.test.js +306 -0
  222. package/x/timeline/renderers/renderers.test.js.map +1 -0
  223. package/x/timeline/sugar/helpers.d.ts +30 -0
  224. package/x/timeline/sugar/helpers.js +46 -0
  225. package/x/timeline/sugar/helpers.js.map +1 -0
  226. package/x/timeline/sugar/o.d.ts +5 -8
  227. package/x/timeline/sugar/o.js +7 -6
  228. package/x/timeline/sugar/o.js.map +1 -1
  229. package/x/timeline/sugar/omni.d.ts +5 -3
  230. package/x/timeline/sugar/omni.js +17 -15
  231. package/x/timeline/sugar/omni.js.map +1 -1
  232. package/x/timeline/sugar/omni.test.d.ts +27 -0
  233. package/x/timeline/sugar/omni.test.js +128 -0
  234. package/x/timeline/sugar/omni.test.js.map +1 -0
  235. package/x/timeline/utils/checksum.d.ts +3 -2
  236. package/x/timeline/utils/checksum.js.map +1 -1
  237. package/x/units/fps.d.ts +6 -0
  238. package/x/units/fps.js +2 -0
  239. package/x/units/fps.js.map +1 -0
  240. package/x/units/ms.d.ts +6 -0
  241. package/x/units/ms.js +2 -0
  242. package/x/units/ms.js.map +1 -0
  243. package/x/units/seconds.d.ts +6 -0
  244. package/x/units/seconds.js +2 -0
  245. package/x/units/seconds.js.map +1 -0
  246. package/x/webworkerAll-VVIU3M54.js +2 -0
  247. package/x/webworkerAll-VVIU3M54.js.map +7 -0
  248. package/s/tests.test.ts +0 -8
  249. package/s/timeline/parts/renderers/export.ts +0 -76
  250. package/s/timeline/parts/renderers/parts/html-tree.ts +0 -37
  251. package/s/timeline/parts/renderers/parts/schedulers.ts +0 -95
  252. package/s/timeline/parts/renderers/parts/tree-builder.ts +0 -201
  253. package/s/timeline/parts/renderers/parts/webcodecs-tree.ts +0 -30
  254. package/s/timeline/parts/renderers/playback.ts +0 -85
  255. package/s/timeline/parts/renderers/samplers/html.ts +0 -129
  256. package/s/timeline/parts/renderers/samplers/webcodecs.ts +0 -61
  257. package/s/timeline/sugar/builders.ts +0 -102
  258. package/s/timeline/sugar/omni-test.ts +0 -40
  259. package/s/timeline/utils/audio-stream.ts +0 -15
  260. package/s/timeline/utils/video-cursor.ts +0 -40
  261. package/x/demo/WebGLRenderer-Q3OV2JVE.js +0 -2
  262. package/x/demo/WebGPURenderer-FUFF62QA.js +0 -2
  263. package/x/demo/browserAll-PGQYU756.js +0 -2
  264. package/x/demo/webworkerAll-3YNCLHCR.js +0 -2
  265. package/x/tests.test.js +0 -6
  266. package/x/tests.test.js.map +0 -1
  267. package/x/timeline/parts/renderers/export.d.ts +0 -10
  268. package/x/timeline/parts/renderers/export.js +0 -62
  269. package/x/timeline/parts/renderers/export.js.map +0 -1
  270. package/x/timeline/parts/renderers/parts/html-tree.d.ts +0 -3
  271. package/x/timeline/parts/renderers/parts/html-tree.js +0 -40
  272. package/x/timeline/parts/renderers/parts/html-tree.js.map +0 -1
  273. package/x/timeline/parts/renderers/parts/schedulers.d.ts +0 -15
  274. package/x/timeline/parts/renderers/parts/schedulers.js +0 -70
  275. package/x/timeline/parts/renderers/parts/schedulers.js.map +0 -1
  276. package/x/timeline/parts/renderers/parts/tree-builder.d.ts +0 -37
  277. package/x/timeline/parts/renderers/parts/tree-builder.js +0 -165
  278. package/x/timeline/parts/renderers/parts/tree-builder.js.map +0 -1
  279. package/x/timeline/parts/renderers/parts/webcodecs-tree.d.ts +0 -3
  280. package/x/timeline/parts/renderers/parts/webcodecs-tree.js +0 -28
  281. package/x/timeline/parts/renderers/parts/webcodecs-tree.js.map +0 -1
  282. package/x/timeline/parts/renderers/playback.d.ts +0 -24
  283. package/x/timeline/parts/renderers/playback.js +0 -70
  284. package/x/timeline/parts/renderers/playback.js.map +0 -1
  285. package/x/timeline/parts/renderers/samplers/html.d.ts +0 -3
  286. package/x/timeline/parts/renderers/samplers/html.js +0 -115
  287. package/x/timeline/parts/renderers/samplers/html.js.map +0 -1
  288. package/x/timeline/parts/renderers/samplers/webcodecs.d.ts +0 -3
  289. package/x/timeline/parts/renderers/samplers/webcodecs.js +0 -52
  290. package/x/timeline/parts/renderers/samplers/webcodecs.js.map +0 -1
  291. package/x/timeline/sugar/builders.d.ts +0 -1
  292. package/x/timeline/sugar/builders.js +0 -104
  293. package/x/timeline/sugar/builders.js.map +0 -1
  294. package/x/timeline/sugar/omni-test.d.ts +0 -1
  295. package/x/timeline/sugar/omni-test.js +0 -31
  296. package/x/timeline/sugar/omni-test.js.map +0 -1
  297. package/x/timeline/utils/audio-stream.d.ts +0 -6
  298. package/x/timeline/utils/audio-stream.js +0 -17
  299. package/x/timeline/utils/audio-stream.js.map +0 -1
  300. package/x/timeline/utils/video-cursor.d.ts +0 -10
  301. package/x/timeline/utils/video-cursor.js +0 -36
  302. package/x/timeline/utils/video-cursor.js.map +0 -1
  303. /package/x/{demo/WebGLRenderer-Q3OV2JVE.js.map → WebGLRenderer-7X274AYV.js.map} +0 -0
  304. /package/x/{demo/WebGPURenderer-FUFF62QA.js.map → WebGPURenderer-XMCMEXAO.js.map} +0 -0
  305. /package/x/demo/{webworkerAll-3YNCLHCR.js.map → WebGLRenderer-NLGJGAXK.js.map} +0 -0
  306. /package/x/demo/{browserAll-PGQYU756.js.map → browserAll-5AZHDDG6.js.map} +0 -0
  307. /package/x/demo/{chunk-LAJHJD2S.js.map → chunk-YJQWVIHX.js.map} +0 -0
  308. /package/x/{tests.test.d.ts → tests.bundle.d.ts} +0 -0
package/README.md CHANGED
@@ -19,6 +19,8 @@ npm i @omnimedia/omnitool
19
19
 
20
20
  ## 📦 Quick Start
21
21
 
22
+ #### Declaring the timeline
23
+
22
24
  ```ts
23
25
  import {Driver, Omni, Datafile} from "@omnimedia/omnitool"
24
26
 
@@ -49,6 +51,30 @@ const timeline = omni.timeline(o => {
49
51
  })
50
52
  ```
51
53
 
54
+ Declarative helper style (no explicit `o` in timeline declarations):
55
+
56
+ ```ts
57
+ import {
58
+ Driver, Omni, Datafile,
59
+ timeline, stack, video, audio, text, gap, transition
60
+ } from "@omnimedia/omnitool"
61
+
62
+ const driver = await Driver.setup()
63
+ const omni = new Omni(driver)
64
+ const {clip} = await omni.load({clip: Datafile.make(file)})
65
+
66
+ const timeline = timeline(
67
+ stack(
68
+ video(clip, {start: 0, duration: 3000}),
69
+ text("Hello world", {duration: 1500}),
70
+ ),
71
+ gap(400),
72
+ transition.crossfade(500),
73
+ video(clip, {start: 5000, duration: 2500}),
74
+ audio(clip, {start: 5000, duration: 2500})
75
+ )
76
+ ```
77
+
52
78
  ## 🧭 Spatial Transforms
53
79
 
54
80
  ```ts
@@ -132,7 +158,7 @@ Timeline items:
132
158
  - 8 `TextStyle`
133
159
 
134
160
  ## 🗺️ Roadmap
135
- - Planned CLI commands (not available in this repo yet):
161
+ - CLI commands:
136
162
 
137
163
  ```bash
138
164
  # build a reusable template from a timeline
@@ -152,5 +178,6 @@ omnitool ai "make a 15s promo for tea"
152
178
  ```
153
179
 
154
180
  - smooth seeking
181
+ - keyframes
155
182
  - server-side, not just browsers
156
183
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnimedia/omnitool",
3
- "version": "1.1.0-47",
3
+ "version": "1.1.0-48",
4
4
  "description": "open source video processing tools",
5
5
  "license": "MIT",
6
6
  "author": "Przemysław Gałęzki",
@@ -19,7 +19,7 @@
19
19
  "_ln-s": "ln -s \"$(realpath s)\" x/s",
20
20
  "_ln-assets": "ln -s \"$(realpath assets)\" x/assets",
21
21
  "_scute": "scute -v",
22
- "test": "node x/tests.test.js",
22
+ "test": "echo \"node tests disabled for now\"",
23
23
  "test-debug": "node inspect x/tests.test.js"
24
24
  },
25
25
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
 
2
2
  import {Driver} from "../driver/driver.js"
3
- import {exportTest} from "./routines/export-test.js"
3
+ import type {Omni, TimelineFile} from "../timeline/index.js"
4
4
  import {playbackTest} from "./routines/playback-test.js"
5
5
  import {waveformTest} from "./routines/waveform-test.js"
6
6
  import {TimelineSchemaTest } from "./routines/timeline-setup.js"
@@ -8,16 +8,15 @@ import {filmstripTest} from "./routines/filmstrip-test.js"
8
8
  import {setupTranscodeTest} from "./routines/transcode-test.js"
9
9
 
10
10
  const driver = await Driver.setup({workerUrl: new URL("../driver/driver.worker.bundle.min.js", import.meta.url)})
11
- const results = document.querySelector(".results")!
12
11
 
13
- const fetchButton = document.querySelector(".fetch")
14
- const fileInput = document.querySelector(".file-input") as HTMLInputElement
12
+ const transcodeCard = document.querySelector("[data-demo='transcode']") as HTMLElement
13
+ const filmstripCard = document.querySelector("[data-demo='filmstrip']") as HTMLElement
14
+ const waveformCard = document.querySelector("[data-demo='waveform']") as HTMLElement
15
+ const playbackCard = document.querySelector("[data-demo='playback']") as HTMLElement
16
+ const exportCard = document.querySelector("[data-demo='export']") as HTMLElement
17
+ const exportButton = exportCard.querySelector("[data-action='export']") as HTMLButtonElement
15
18
 
16
- fetchButton?.addEventListener("click", startDemoFetch)
17
- fileInput?.addEventListener("input", startDemoImport)
18
-
19
- waveformTest(driver)
20
- // const transcriber = await transcriberTest(driver)
19
+ let exportState: {timeline: TimelineFile; omni: Omni} | null = null
21
20
 
22
21
  // hello world test
23
22
  {
@@ -26,53 +25,103 @@ waveformTest(driver)
26
25
  else console.error("❌ FAIL driver call didn't work")
27
26
  }
28
27
 
29
- // transcoding tests
30
- async function startDemoImport(e: Event)
28
+ const setProgress = (card: HTMLElement, state: "idle" | "running" | "done") => {
29
+ const progress = card.querySelector(".progress") as HTMLProgressElement
30
+ const status = card.querySelector(".status") as HTMLSpanElement
31
+
32
+ if (state === "running") {
33
+ progress.removeAttribute("value")
34
+ status.textContent = "running"
35
+ } else if (state === "done") {
36
+ progress.value = 1
37
+ status.textContent = "done"
38
+ } else {
39
+ progress.value = 0
40
+ status.textContent = "idle"
41
+ }
42
+ }
43
+
44
+ const bindDemo = (
45
+ card: HTMLElement,
46
+ run: (file: File, card: HTMLElement) => Promise<void>
47
+ ) => {
48
+ const input = card.querySelector("input[type='file']") as HTMLInputElement
49
+ const button = card.querySelector("[data-action='run']") as HTMLButtonElement
50
+
51
+ button.disabled = true
52
+ input.addEventListener("input", () => {
53
+ button.disabled = !input.files?.length
54
+ })
55
+
56
+ button.addEventListener("click", async () => {
57
+ const file = input.files?.[0]
58
+ if (!file)
59
+ return
60
+
61
+ button.disabled = true
62
+ setProgress(card, "running")
63
+ try {
64
+ await run(file, card)
65
+ setProgress(card, "done")
66
+ } finally {
67
+ button.disabled = false
68
+ }
69
+ })
70
+ }
71
+
72
+ bindDemo(transcodeCard, async (file, card) => {
73
+ const preview = card.querySelector(".demo-preview") as HTMLDivElement
74
+ const transcode = setupTranscodeTest(driver, file)
75
+ preview.replaceChildren(transcode.canvas)
76
+ await transcode.run()
77
+ })
78
+
79
+ bindDemo(filmstripCard, async (file, card) => {
80
+ await filmstripTest(file, card)
81
+ })
82
+
83
+ bindDemo(waveformCard, async (file, card) => {
84
+ await waveformTest(driver, file, card)
85
+ })
86
+
31
87
  {
32
- const file = fileInput.files?.[0]
33
- if(file) {
34
- const transcode = setupTranscodeTest(driver, file)
35
- await filmstripTest(file)
36
- run(transcode, file.name)
37
- // await transcriber.transcribe(file)
88
+ const input = playbackCard.querySelector("input[type='file']") as HTMLInputElement
89
+ input.addEventListener("input", async () => {
90
+ const file = input.files?.[0]
91
+ if (!file)
92
+ return
38
93
 
39
94
  const {timeline, omni} = await TimelineSchemaTest(driver, file)
40
-
41
- playbackTest(timeline, omni)
42
- exportTest(omni, timeline)
43
- }
44
- // const [fileHandle] = await window.showOpenFilePicker()
45
- // const file = await fileHandle.getFile()
95
+ await playbackTest(timeline, omni, playbackCard)
96
+ })
46
97
  }
47
98
 
48
- async function startDemoFetch()
49
99
  {
100
+ const input = exportCard.querySelector("input[type='file']") as HTMLInputElement
101
+ input.addEventListener("input", async () => {
102
+ const file = input.files?.[0]
103
+ if (!file)
104
+ return
50
105
 
51
- // which videos to run tests on
52
- const videos = [
53
- "/assets/temp/gl.mp4",
54
- ]
55
-
56
- // running each test in sequence
57
- for (const url of videos) {
58
- const transcode = setupTranscodeTest(driver, "/assets/temp/gl.mp4")
59
- run(transcode, url)
60
- }
106
+ setProgress(exportCard, "running")
107
+ const {timeline, omni} = await TimelineSchemaTest(driver, file)
108
+ exportState = {timeline, omni}
109
+ exportButton.disabled = false
110
+
111
+ const preview = exportCard.querySelector(".demo-preview") as HTMLDivElement
112
+ const player = await omni.playback(timeline)
113
+ await player.seek(0)
114
+ preview.replaceChildren(player.canvas)
115
+ setProgress(exportCard, "done")
116
+ })
61
117
  }
62
118
 
63
- async function run(transcode: ReturnType<typeof setupTranscodeTest>, label: string) {
64
- // create result div
65
- const div = document.createElement("div")
66
- results.append(div)
67
-
68
- // add video label
69
- const p = document.createElement("p")
70
- p.textContent = label
71
- div.append(p)
119
+ exportButton.addEventListener("click", async () => {
120
+ if (!exportState)
121
+ return
72
122
 
73
- // add the canvas to dom
74
- div.append(transcode.canvas)
123
+ setProgress(exportCard, "running")
124
+ await exportState.omni.render(exportState.timeline)
125
+ setProgress(exportCard, "done")
126
+ })
75
127
 
76
- // run the test
77
- await transcode.run()
78
- }
package/s/demo/demo.css CHANGED
@@ -1,11 +1,16 @@
1
1
 
2
- @layer vars, basics, page;
2
+ @layer vars, basics, page, demo;
3
3
 
4
4
  @layer vars {
5
5
  :root {
6
- --link: cyan;
7
- --color: #fffa;
8
- --background: #111;
6
+ --ink: #f2f4f8;
7
+ --muted: #9fb0c3;
8
+ --surface: #0f141c;
9
+ --panel: #121a26;
10
+ --accent: #2cffd7;
11
+ --accent-2: #ff9a3c;
12
+ --border: color-mix(in oklab, #ffffff 10%, transparent);
13
+ --shadow: 0 20px 60px #00000066;
9
14
  }
10
15
  }
11
16
 
@@ -20,16 +25,20 @@
20
25
  @layer page {
21
26
  html {
22
27
  font-size: 10px;
23
- color: var(--color);
24
- background: var(--background);
28
+ color: var(--ink);
29
+ background:
30
+ radial-gradient(1200px 600px at 10% -10%, #1f314e 0%, transparent 60%),
31
+ radial-gradient(800px 500px at 90% -20%, #2a1f4e 0%, transparent 55%),
32
+ linear-gradient(160deg, #0a0f16 0%, #0b1018 45%, #0b0f14 100%);
33
+ font-family: "Space Grotesk", system-ui, sans-serif;
25
34
  }
26
35
 
27
36
  body {
28
- padding: 2em;
37
+ padding: 3.2em;
29
38
  }
30
39
 
31
40
  .results {
32
- margin-top: 1em;
41
+ margin-top: 2em;
33
42
 
34
43
  display: flex;
35
44
  flex-direction: column;
@@ -37,8 +46,10 @@
37
46
 
38
47
  > div {
39
48
  font-size: 1.5em;
40
- border: 1px solid color-mix(in lch, transparent, var(--color) 20%);
49
+ border: 1px solid var(--border);
41
50
  padding: 1em;
51
+ background: var(--panel);
52
+ box-shadow: var(--shadow);
42
53
  }
43
54
 
44
55
  canvas {
@@ -46,14 +57,233 @@
46
57
  }
47
58
  }
48
59
 
49
- canvas {
50
- width: 500px;
51
- height: 300px;
60
+ }
61
+
62
+ @layer demo {
63
+ .hero {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-between;
67
+ gap: 2em;
68
+ margin-bottom: 2.4em;
69
+ }
70
+
71
+ .hero h1 {
72
+ font-family: "Share Tech", system-ui, sans-serif;
73
+ font-size: 3.4em;
74
+ letter-spacing: 0.05em;
75
+ text-transform: uppercase;
76
+ }
77
+
78
+ .hero h1 small {
79
+ font-size: 0.5em;
80
+ color: var(--muted);
81
+ }
82
+
83
+ .hero p {
84
+ font-size: 1.4em;
85
+ color: var(--muted);
86
+ margin-top: 0.6em;
87
+ max-width: 60ch;
88
+ }
89
+
90
+ .demo-grid {
91
+ display: grid;
92
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
93
+ gap: 1.8em;
94
+ margin-bottom: 2.4em;
95
+ }
96
+
97
+ .demo-card {
98
+ background: linear-gradient(160deg, #111a25 0%, #0f1620 60%, #0d121a 100%);
99
+ border: 1px solid var(--border);
100
+ border-radius: 16px;
101
+ padding: 1.6em;
102
+ box-shadow: var(--shadow);
103
+ display: grid;
104
+ gap: 1.2em;
105
+ }
106
+
107
+ .demo-card h2 {
108
+ font-size: 1.8em;
109
+ letter-spacing: 0.03em;
110
+ }
111
+
112
+ .demo-card p {
113
+ color: var(--muted);
114
+ font-size: 1.2em;
115
+ }
116
+
117
+ .demo-controls {
118
+ display: grid;
119
+ gap: 0.8em;
120
+ }
121
+
122
+ .demo-progress {
123
+ display: grid;
124
+ grid-template-columns: 1fr auto;
125
+ align-items: center;
126
+ gap: 0.8em;
127
+ font-size: 1.1em;
128
+ color: var(--muted);
129
+ }
130
+
131
+ .demo-progress .status {
132
+ letter-spacing: 0.06em;
133
+ text-transform: uppercase;
134
+ font-size: 0.9em;
135
+ }
136
+
137
+ progress.progress {
138
+ width: 100%;
139
+ height: 10px;
140
+ border-radius: 999px;
141
+ overflow: hidden;
142
+ background: #0b1118;
143
+ border: 1px solid var(--border);
144
+ }
145
+
146
+ progress.progress::-webkit-progress-bar {
147
+ background: #0b1118;
148
+ }
149
+
150
+ progress.progress::-webkit-progress-value {
151
+ background: linear-gradient(120deg, var(--accent), #4df1ff);
152
+ }
153
+
154
+ progress.progress::-moz-progress-bar {
155
+ background: linear-gradient(120deg, var(--accent), #4df1ff);
156
+ }
157
+
158
+ .demo-preview {
159
+ border: 1px solid var(--border);
160
+ border-radius: 12px;
161
+ min-height: 160px;
162
+ background: #0b1118;
163
+ display: grid;
164
+ place-items: center;
165
+ overflow: hidden;
166
+ }
167
+
168
+ .demo-preview canvas {
169
+ width: 100%;
170
+ height: auto;
52
171
  }
53
172
 
54
- #filmstrip {
173
+ .filmstrip-controls,
174
+ .waveform-controls {
175
+ display: grid;
176
+ gap: 0.6em;
177
+ font-size: 1.1em;
178
+ color: var(--muted);
179
+ }
180
+
181
+ .filmstrip-controls input[type="range"],
182
+ .waveform-controls input[type="range"] {
183
+ width: 100%;
184
+ }
185
+
186
+ input[type="file"] {
187
+ background: #0b111a;
188
+ color: var(--ink);
189
+ border: 1px dashed #2b3b52;
190
+ border-radius: 10px;
191
+ padding: 0.8em;
192
+ font-size: 1.2em;
193
+ }
194
+
195
+ button {
196
+ background: linear-gradient(120deg, var(--accent), #4df1ff);
197
+ border: none;
198
+ color: #0a0f14;
199
+ font-weight: 600;
200
+ letter-spacing: 0.03em;
201
+ border-radius: 10px;
202
+ padding: 0.8em 1.2em;
203
+ cursor: pointer;
204
+ transition: transform 120ms ease, box-shadow 120ms ease;
205
+ box-shadow: 0 10px 20px #00ffd533;
206
+ }
207
+
208
+ button[data-action="export"] {
209
+ background: linear-gradient(120deg, var(--accent-2), #ffd479);
210
+ box-shadow: 0 10px 20px #ffb35a33;
211
+ }
212
+
213
+ button:disabled {
214
+ opacity: 0.6;
215
+ cursor: not-allowed;
216
+ transform: none;
217
+ box-shadow: none;
218
+ }
219
+
220
+ button:not(:disabled):hover {
221
+ transform: translateY(-1px);
222
+ }
223
+
224
+ .filmstrip {
55
225
  display: flex;
56
226
  overflow-x: scroll;
227
+ gap: 0.4em;
228
+ padding: 0.4em 0;
229
+ }
230
+
231
+ .player {
232
+ margin-top: 1.2em;
233
+ display: grid;
234
+ gap: 0.8em;
57
235
  }
58
- }
59
236
 
237
+ .player .timeline {
238
+ display: grid;
239
+ gap: 0.6em;
240
+ }
241
+
242
+ .player .track {
243
+ position: relative;
244
+ height: 10px;
245
+ border-radius: 999px;
246
+ background:
247
+ linear-gradient(90deg, #1e1e1e, #1a1a1a),
248
+ repeating-linear-gradient(90deg, #ffffff14 0 6px, transparent 6px 12px);
249
+ border: 1px solid #ffffff22;
250
+ overflow: hidden;
251
+ }
252
+
253
+ .player .playhead {
254
+ position: absolute;
255
+ left: 0%;
256
+ top: -6px;
257
+ width: 2px;
258
+ height: 22px;
259
+ background: #3cff9c;
260
+ box-shadow: 0 0 12px #3cff9c99;
261
+ }
262
+
263
+ .player .scrub {
264
+ width: 100%;
265
+ }
266
+
267
+ .player .timecode {
268
+ font-size: 1.2em;
269
+ letter-spacing: 0.06em;
270
+ color: #c7ffe3;
271
+ }
272
+
273
+ .player .controls {
274
+ display: flex;
275
+ gap: 0.8em;
276
+ }
277
+
278
+ .player-canvas {
279
+ border: 1px solid var(--border);
280
+ border-radius: 10px;
281
+ padding: 0.6em;
282
+ background: #0b1118;
283
+ }
284
+
285
+ canvas {
286
+ width: 100%;
287
+ height: auto;
288
+ }
289
+ }
@@ -1,8 +1,16 @@
1
1
  import {Omni, TimelineFile} from "../../timeline/index.js"
2
2
 
3
- export function exportTest(omni: Omni, timeline: TimelineFile) {
4
- const exportButton = document.querySelector(".export") as HTMLButtonElement
5
- exportButton!.addEventListener("click", () => {
6
- omni.render(timeline).then(() => console.log("done"))
3
+ export function exportTest(
4
+ omni: Omni,
5
+ timeline: TimelineFile,
6
+ exportButton: HTMLButtonElement,
7
+ onStatus?: (state: "running" | "done") => void
8
+ ) {
9
+ exportButton.addEventListener("click", () => {
10
+ onStatus?.("running")
11
+ omni.render(timeline).then(() => {
12
+ console.log("done")
13
+ onStatus?.("done")
14
+ })
7
15
  })
8
16
  }
@@ -1,14 +1,16 @@
1
1
  import {Filmstrip} from "../../timeline/parts/filmstrip.js"
2
2
 
3
- export async function filmstripTest(file: File) {
4
- const rangeSlider = document.querySelector(".range") as HTMLInputElement
5
- const rangeView = document.querySelector(".range-view")!
6
- const rangeSizeSlider = document.querySelector(".range-size")! as HTMLInputElement
7
- const frequencySlider = document.querySelector(".frequency")! as HTMLInputElement
8
- const frequencyView = document.querySelector(".frequency-view")!
9
- const container = document.querySelector("#filmstrip")!
10
- const FPS_10 = 1000/10 / 1000
3
+ export async function filmstripTest(file: File, root: HTMLElement) {
4
+ const rangeSlider = root.querySelector(".range") as HTMLInputElement
5
+ const rangeView = root.querySelector(".range-view")!
6
+ const rangeSizeSlider = root.querySelector(".range-size")! as HTMLInputElement
7
+ const frequencySlider = root.querySelector(".frequency")! as HTMLInputElement
8
+ const frequencyView = root.querySelector(".frequency-view")!
9
+ const container = root.querySelector(".filmstrip")!
10
+ const FPS_10 = 1 / 10
11
11
  let rangeSize = 0.5
12
+ container.replaceChildren()
13
+
12
14
  const filmstrip = await Filmstrip.init(
13
15
  file,
14
16
  {
@@ -27,22 +29,24 @@ export async function filmstripTest(file: File) {
27
29
  fit: "fill"
28
30
  }
29
31
  }
30
- )
31
- rangeSizeSlider.addEventListener("change", () => {
32
+ )
33
+ rangeSizeSlider.oninput = () => {
32
34
  rangeSize = +rangeSizeSlider.value
33
- const [start, end] = [+rangeSlider.value, +rangeSlider.value+rangeSize]
35
+ const start = +rangeSlider.value
36
+ const end = start + rangeSize
34
37
  filmstrip.range = [start, end]
35
38
  rangeView.textContent = `visible time range: [${start}, ${end}]`
36
- })
37
- rangeSlider.addEventListener("change", () => {
38
- const [start, end] = [+rangeSlider.value, +rangeSlider.value+rangeSize]
39
+ }
40
+ rangeSlider.oninput = () => {
41
+ const start = +rangeSlider.value
42
+ const end = start + rangeSize
39
43
  filmstrip.range = [start, end]
40
44
  rangeView.textContent = `visible time range: [${start}, ${end}]`
41
- })
42
- frequencySlider.addEventListener("change", () => {
43
- filmstrip.frequency = 1000/+frequencySlider.value/1000
45
+ }
46
+ frequencySlider.oninput = () => {
47
+ filmstrip.frequency = 1 / +frequencySlider.value
44
48
  frequencyView.textContent = `frame every ${filmstrip.frequency.toFixed(3)} second (${frequencySlider.value} frames per second)`
45
- })
49
+ }
46
50
  filmstrip.range = [10, 10.5]
47
51
  }
48
52
 
@@ -1,7 +1,6 @@
1
1
 
2
- export async function loadVideo(url: string): Promise<ArrayBuffer> {
2
+ export async function loadVideo(url: string) {
3
3
  return fetch(url)
4
- .then(response => response.bytes())
5
- .then(bytes => bytes.buffer)
4
+ .then(response => response.blob())
6
5
  }
7
6