← Commit history

Migrate asset from Helium wiki

Kyle Bergstedt ·8fe13d5f66 ·4mo ago ·parent 8b79548
1 file changed +227
demo-player.htmladded+227
@@ -0,0 +1,227 @@+<!DOCTYPE html>+<html lang="en">+<head><script>(function(){var n=0;function show(p,m){var el=document.createElement('div');el.style.cssText='position:fixed;left:0;right:0;background:#e04040;color:#fff;padding:6px 12px;z-index:'+(99999-n)+';font:13px/1.4 monospace;white-space:pre-wrap;border-bottom:1px solid #b02020;top:'+n*30+'px';el.textContent=p+m;document.body.appendChild(el);n++}window.onerror=function(msg,src,line){show('ERROR '+(src||'').split('/').pop()+':'+line+' \u2014 ',msg)};window.addEventListener('unhandledrejection',function(e){show('REJECT \u2014 ',e.reason&&e.reason.message||e.reason||'unknown')})})()</script>+<meta charset="UTF-8">+<meta name="viewport" content="width=device-width, initial-scale=1.0">+<title>Movie Maker — Smart Player</title>+<style>+* { margin: 0; padding: 0; box-sizing: border-box; }+body {+  background: #0d1117; color: #e6edf3;+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;+  height: 100vh; display: flex; flex-direction: column; overflow: hidden;+}+.player-container {+  flex: 1; display: flex; flex-direction: column; padding: 16px; gap: 12px;+}+.player-title {+  font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 8px;+}+.back-btn {+  background: none; border: none; color: #8b949e; cursor: pointer;+  font-size: 14px; padding: 4px 8px;+}+.video-area {+  flex: 1; background: #000; border-radius: 8px; border: 1px solid #21262d;+  position: relative; overflow: hidden; display: flex; align-items: center;+  justify-content: center; min-height: 200px;+}+.video-area canvas { width: 100%; height: 100%; }+.speed-indicator {+  position: absolute; top: 12px; right: 12px;+  background: rgba(210, 153, 34, 0.9); color: #fff;+  padding: 4px 10px; border-radius: 4px; font-size: 12px; font-weight: 600;+  display: none;+}+.speed-indicator.active { display: block; }+.player-timeline { padding: 0 4px; }+.timeline-bar {+  position: relative; height: 12px; background: #21262d; border-radius: 6px;+  cursor: pointer; overflow: visible;+}+.timeline-progress {+  position: absolute; top: 0; left: 0; height: 100%; background: #30363d;+  border-radius: 6px; pointer-events: none;+}+.timeline-playhead {+  position: absolute; top: -2px; width: 4px; height: 16px;+  background: #e6edf3; border-radius: 2px; pointer-events: none;+  transition: left 0.1s linear;+}+.timeline-silence {+  position: absolute; top: 0; height: 100%; background: #d29922;+  opacity: 0.5; border-radius: 2px; cursor: pointer;+}+.timeline-silence:hover { opacity: 0.8; }+.timeline-labels {+  display: flex; justify-content: space-between; font-size: 11px;+  color: #8b949e; margin-top: 4px; font-variant-numeric: tabular-nums;+}+.player-bar {+  display: flex; align-items: center; justify-content: space-between;+  flex-wrap: wrap; gap: 8px;+}+.silence-nav { display: flex; align-items: center; gap: 8px; }+.silence-nav button {+  padding: 4px 10px; font-size: 11px; border-radius: 4px;+  background: #21262d; color: #e6edf3; border: 1px solid #30363d;+  cursor: pointer; font-family: inherit;+}+.silence-nav button:hover { background: #30363d; }+.nav-label { color: #d29922; font-size: 12px; font-weight: 500; }+.smart-toggle {+  display: flex; align-items: center; gap: 8px;+  color: #8b949e; font-size: 12px;+}+.smart-toggle input { accent-color: #d29922; width: 14px; height: 14px; }+.smart-toggle .active-label { color: #d29922; font-weight: 600; }+.controls { display: flex; gap: 8px; }+.ctrl-btn {+  padding: 6px 14px; font-size: 12px; border-radius: 5px; border: none;+  font-family: inherit; font-weight: 500; cursor: pointer;+  display: inline-flex; align-items: center; gap: 5px;+}+.btn-play { background: #238636; color: #fff; }+.btn-secondary { background: #21262d; color: #e6edf3; border: 1px solid #30363d; }+.legend {+  display: flex; gap: 16px; font-size: 11px; color: #8b949e;+  padding: 4px 0; align-items: center;+}+.legend-dot {+  display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 4px;+}+.demo-note {+  position: fixed; bottom: 8px; right: 12px; color: #484f58; font-size: 10px;+}+</style>+</head>+<body>+<div class="player-container">+  <div class="player-title">+    <button class="back-btn">&larr;</button>+    PCB Review — Rev B+  </div>+  <div class="video-area">+    <canvas id="vid-canvas" width="640" height="360"></canvas>+    <div class="speed-indicator" id="speed-ind">16x &raquo;</div>+  </div>+  <div class="player-timeline">+    <div class="timeline-bar" id="timeline-bar">+      <div class="timeline-progress" id="progress" style="width:35%"></div>+      <div class="timeline-playhead" id="playhead" style="left:35%"></div>+    </div>+    <div class="timeline-labels">+      <span id="current-time">2:01</span>+      <span>5:47</span>+    </div>+  </div>+  <div class="player-bar">+    <div class="silence-nav">+      <button>&laquo; Prev</button>+      <span class="nav-label">4 silences</span>+      <button>Next &raquo;</button>+    </div>+    <label class="smart-toggle">+      <input type="checkbox" checked id="smart-cb">+      <span class="active-label">Smart Playback ON</span> — skipping silence at 16x+    </label>+  </div>+  <div class="controls">+    <button class="ctrl-btn btn-secondary">&#10074;&#10074; Pause</button>+    <button class="ctrl-btn btn-secondary">Copy Link</button>+  </div>+  <div class="legend">+    <span><span class="legend-dot" style="background:#d29922;"></span>Silence region (click to jump)</span>+    <span><span class="legend-dot" style="background:#30363d;"></span>Playback progress</span>+    <span><span class="legend-dot" style="background:#e6edf3;"></span>Playhead</span>+  </div>+</div>+<div class="demo-note">Demo — simulated data</div>+<script>+// Simulated silence regions for a 347s video+const duration = 347;+const silences = [+  {startMs: 12000, endMs: 18000},+  {startMs: 45000, endMs: 52000},+  {startMs: 120000, endMs: 135000},+  {startMs: 210000, endMs: 218000}+];++// Render silence markers on timeline+const bar = document.getElementById('timeline-bar');+silences.forEach((r, i) => {+  const left = (r.startMs / 1000) / duration * 100;+  const width = ((r.endMs - r.startMs) / 1000) / duration * 100;+  const el = document.createElement('div');+  el.className = 'timeline-silence';+  el.style.left = left + '%';+  el.style.width = Math.max(width, 0.5) + '%';+  el.title = 'Silence ' + (i + 1);+  bar.appendChild(el);+});++// Animate playback simulation+let pos = 0.35;+const speedInd = document.getElementById('speed-ind');+const progress = document.getElementById('progress');+const playhead = document.getElementById('playhead');+const currentTime = document.getElementById('current-time');++function fmtTime(s) {+  const m = Math.floor(s / 60);+  const sec = Math.floor(s % 60);+  return m + ':' + String(sec).padStart(2, '0');+}++setInterval(() => {+  const sec = pos * duration;+  const inSilence = silences.some(r => sec * 1000 >= r.startMs && sec * 1000 <= r.endMs);+  const step = inSilence ? 0.004 : 0.0003;+  pos = Math.min(pos + step, 1);+  progress.style.width = (pos * 100) + '%';+  playhead.style.left = (pos * 100) + '%';+  currentTime.textContent = fmtTime(pos * duration);+  speedInd.classList.toggle('active', inSilence);+  if (pos >= 1) pos = 0;+}, 50);++// Draw fake video frame+const canvas = document.getElementById('vid-canvas');+const ctx = canvas.getContext('2d');+const grd = ctx.createLinearGradient(0, 0, 640, 360);+grd.addColorStop(0, '#0d2636');+grd.addColorStop(1, '#1a3a4a');+ctx.fillStyle = grd;+ctx.fillRect(0, 0, 640, 360);+// Fake toolbar+ctx.fillStyle = '#161b22';+ctx.fillRect(0, 0, 640, 32);+ctx.fillStyle = '#8b949e';+ctx.font = '12px sans-serif';+ctx.fillText('Gallia Viewer — PCB Review', 10, 21);+// Fake PCB outline+ctx.strokeStyle = '#00b8b0';+ctx.lineWidth = 2;+ctx.strokeRect(150, 80, 340, 220);+ctx.strokeStyle = '#30363d';+ctx.lineWidth = 1;+for (let x = 170; x < 480; x += 40) {+  for (let y = 100; y < 280; y += 30) {+    ctx.beginPath();+    ctx.arc(x, y, 3, 0, Math.PI * 2);+    ctx.stroke();+  }+}+// Fake component rectangles+ctx.fillStyle = '#21262d';+ctx.fillRect(200, 120, 80, 40);+ctx.fillRect(320, 180, 60, 60);+ctx.fillRect(250, 240, 100, 30);+ctx.fillStyle = '#3fb950';+ctx.font = '9px sans-serif';+ctx.fillText('U1', 230, 145);+ctx.fillText('C3', 340, 215);+ctx.fillText('R7-R12', 275, 260);+</script>+</body>+</html>\ No newline at end of file