UNPKG

@omnimedia/omnitool

Version:

open source video processing tools

425 lines (367 loc) 9.03 kB
<!doctype html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width,initial-scale=1"/> <meta name="darkreader-lock"/> <title>omnitool</title> <style> @layer vars, basics, page, demo; @layer vars { :root { --ink: #f2f4f8; --muted: #9fb0c3; --surface: #0f141c; --panel: #121a26; --accent: #2cffd7; --accent-2: #ff9a3c; --border: color-mix(in oklab, #ffffff 10%, transparent); --shadow: 0 20px 60px #00000066; } } @layer basics { * { margin: 0; padding: 0; box-sizing: border-box; } } @layer page { html { font-size: 10px; color: var(--ink); background: radial-gradient(1200px 600px at 10% -10%, #1f314e 0%, transparent 60%), radial-gradient(800px 500px at 90% -20%, #2a1f4e 0%, transparent 55%), linear-gradient(160deg, #0a0f16 0%, #0b1018 45%, #0b0f14 100%); font-family: "Space Grotesk", system-ui, sans-serif; } body { padding: 3.2em; } .results { margin-top: 2em; display: flex; flex-direction: column; gap: 1em; > div { font-size: 1.5em; border: 1px solid var(--border); padding: 1em; background: var(--panel); box-shadow: var(--shadow); } canvas { width: 20em; } } } @layer demo { .hero { display: flex; align-items: center; justify-content: space-between; gap: 2em; margin-bottom: 2.4em; } .hero h1 { font-family: "Share Tech", system-ui, sans-serif; font-size: 3.4em; letter-spacing: 0.05em; text-transform: uppercase; } .hero h1 small { font-size: 0.5em; color: var(--muted); } .hero p { font-size: 1.4em; color: var(--muted); margin-top: 0.6em; max-width: 60ch; } .demo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.8em; margin-bottom: 2.4em; } .demo-card { background: linear-gradient(160deg, #111a25 0%, #0f1620 60%, #0d121a 100%); border: 1px solid var(--border); border-radius: 16px; padding: 1.6em; box-shadow: var(--shadow); display: grid; gap: 1.2em; } .demo-card h2 { font-size: 1.8em; letter-spacing: 0.03em; } .demo-card p { color: var(--muted); font-size: 1.2em; } .demo-controls { display: grid; gap: 0.8em; } .demo-progress { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 0.8em; font-size: 1.1em; color: var(--muted); } .demo-progress .status { letter-spacing: 0.06em; text-transform: uppercase; font-size: 0.9em; } progress.progress { width: 100%; height: 10px; border-radius: 999px; overflow: hidden; background: #0b1118; border: 1px solid var(--border); } progress.progress::-webkit-progress-bar { background: #0b1118; } progress.progress::-webkit-progress-value { background: linear-gradient(120deg, var(--accent), #4df1ff); } progress.progress::-moz-progress-bar { background: linear-gradient(120deg, var(--accent), #4df1ff); } .demo-preview { border: 1px solid var(--border); border-radius: 12px; min-height: 160px; background: #0b1118; display: grid; place-items: center; overflow: hidden; } .demo-preview canvas { width: 100%; height: auto; } .filmstrip-controls, .waveform-controls { display: grid; gap: 0.6em; font-size: 1.1em; color: var(--muted); } .filmstrip-controls input[type="range"], .waveform-controls input[type="range"] { width: 100%; } input[type="file"] { background: #0b111a; color: var(--ink); border: 1px dashed #2b3b52; border-radius: 10px; padding: 0.8em; font-size: 1.2em; } button { background: linear-gradient(120deg, var(--accent), #4df1ff); border: none; color: #0a0f14; font-weight: 600; letter-spacing: 0.03em; border-radius: 10px; padding: 0.8em 1.2em; cursor: pointer; transition: transform 120ms ease, box-shadow 120ms ease; box-shadow: 0 10px 20px #00ffd533; } button[data-action="export"] { background: linear-gradient(120deg, var(--accent-2), #ffd479); box-shadow: 0 10px 20px #ffb35a33; } button:disabled { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; } button:not(:disabled):hover { transform: translateY(-1px); } .filmstrip { display: flex; overflow-x: scroll; gap: 0.4em; padding: 0.4em 0; } .player { margin-top: 1.2em; display: grid; gap: 0.8em; } .player .timeline { display: grid; gap: 0.6em; } .player .track { position: relative; height: 10px; border-radius: 999px; background: linear-gradient(90deg, #1e1e1e, #1a1a1a), repeating-linear-gradient(90deg, #ffffff14 0 6px, transparent 6px 12px); border: 1px solid #ffffff22; overflow: hidden; } .player .playhead { position: absolute; left: 0%; top: -6px; width: 2px; height: 22px; background: #3cff9c; box-shadow: 0 0 12px #3cff9c99; } .player .scrub { width: 100%; } .player .timecode { font-size: 1.2em; letter-spacing: 0.06em; color: #c7ffe3; } .player .controls { display: flex; gap: 0.8em; } .player-canvas { border: 1px solid var(--border); border-radius: 10px; padding: 0.6em; background: #0b1118; } canvas { width: 100%; height: auto; } } </style> <script type=module src="demo/demo.bundle.min.js?v=46bd2b469440"></script> <meta name="theme-color" content="#3cff9c"> <meta property="og:type" content="website"> <meta property="og:site_name" content="omnitool.omniclip.app"> <meta property="og:title" content="omnitool"> <meta property="og:description" content="video processing toolkit"> <meta property="og:image" content="https://omnitool.omniclip.app/assets/favicon.png"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Share+Tech&family=Space+Grotesk:wght@400;600&display=swap" rel="stylesheet"> </head> <body> <section> <header class="hero"> <div> <h1>Omnitool <small>v1.1.0-120</small></h1> <p>Developer demos for decoding, preview, waveform, playback, and export.</p> </div> </header> <div class="demo-grid"> <article class="demo-card" data-demo="transcode"> <header> <h2>Transcode Test</h2> <p>Full decode + composite + encode pipeline.</p> </header> <div class="demo-controls"> <input type="file" accept="video/*" /> <button data-action="run">Run Transcode</button> </div> <div class="demo-progress"> <progress class="progress"></progress> <span class="status">idle</span> </div> <div class="demo-preview"></div> </article> <article class="demo-card" data-demo="filmstrip"> <header> <h2>Filmstrip</h2> <p>Thumbnail sampling across a time range.</p> </header> <div class="demo-controls"> <input type="file" accept="video/*" /> <button data-action="run">Generate Filmstrip</button> </div> <div class="filmstrip-controls"> <label>viewable range</label> <input type="range" min="0" max="100" step="1" value="10" class="range"> <div class="range-view"></div> <label>range size</label> <input type="range" class="range-size" min="0.1" max="10" step="0.1" value="0.5"> <label>frequency</label> <input type="range" class="frequency" min="0.1" max="120" step="0.1" value="10"> <div class="frequency-view">10 (fps)</div> </div> <div class="filmstrip"></div> </article> <article class="demo-card" data-demo="waveform"> <header> <h2>Waveform</h2> <p>Audio peak rendering with adjustable width.</p> </header> <div class="demo-controls"> <input type="file" accept="audio/*,video/*" /> <button data-action="run">Build Waveform</button> </div> <div class="waveform-controls"> <label>width</label> <input class="width" type="range" min="100" max="1000000" value="1000" step="100" /> </div> <div class="waveform-canvas"></div> </article> <article class="demo-card" data-demo="playback"> <header> <h2>Timeline Playback</h2> <p>Build timeline and run the playback engine.</p> </header> <div class="demo-controls"> <input type="file" accept="video/*,audio/*,image/*" /> </div> <div class="player-canvas"></div> <div class="player"> <div class="timeline"> <div class="track"> <div class="playhead"></div> </div> <input class="scrub" type="range" min="0" max="0" step="1" value="0"> </div> <div class="timecode">0:00.000 / 0:00.000</div> <div class="controls"> <button class=play disabled>play</button> <button class=stop disabled>stop</button> </div> </div> </article> <article class="demo-card" data-demo="export"> <header> <h2>Timeline Export</h2> <p>Build timeline and export a render.</p> </header> <div class="demo-controls"> <input type="file" accept="video/*,audio/*,image/*" /> <button data-action="export" disabled>Export</button> </div> <div class="demo-progress"> <progress class="progress"></progress> <span class="status">idle</span> </div> <div class="demo-preview"></div> </article> </div> </section> </body> </html>