@omnimedia/omnitool
Version:
open source video processing tools
425 lines (367 loc) • 9.03 kB
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>