openarm / openarm.html
haixuantao's picture
Upload folder using huggingface_hub
c7cb2b8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenArm 3D Visualizer - xoq</title>
<script type="module" crossorigin src="./assets/openarm-BF3lx1-l.js"></script>
<link rel="modulepreload" crossorigin href="./assets/modulepreload-polyfill-B5Qt9EMX.js">
<link rel="modulepreload" crossorigin href="./assets/openarm-settings-Cing9rdF.js">
<link rel="modulepreload" crossorigin href="./assets/connect-C3lO3qk6.js">
<link rel="modulepreload" crossorigin href="./assets/URDFLoader-BpNv9rVq.js">
<link rel="stylesheet" crossorigin href="./assets/openarm-settings-CsiNG4Tl.css">
<link rel="stylesheet" crossorigin href="./assets/openarm-B5atNJ-X.css">
</head>
<body>
<script>
(function() {
var hasMSE = typeof MediaSource !== 'undefined' || typeof ManagedMediaSource !== 'undefined';
var hasWebCodecs = typeof VideoDecoder !== 'undefined';
if (!hasMSE) {
document.addEventListener('DOMContentLoaded', function() {
var b = document.createElement('div');
b.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;background:#b91c1c;color:#fff;padding:8px 16px;text-align:center;font:14px/1.4 system-ui,sans-serif;';
b.innerHTML = 'This browser does not support <b>MediaSource Extensions</b>. Color video playback requires MSE.';
document.body.prepend(b);
});
} else if (!hasWebCodecs) {
document.addEventListener('DOMContentLoaded', function() {
var b = document.createElement('div');
b.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;background:#d97706;color:#fff;padding:8px 16px;text-align:center;font:14px/1.4 system-ui,sans-serif;';
b.innerHTML = 'Depth and point cloud features are unavailable (WebCodecs not supported). Color video will work normally.';
document.body.prepend(b);
});
}
})();
</script>
<div class="top-bar">
<div class="top-bar-main">
<h1>OpenArm 3D</h1>
<button id="startBtn">Connect</button>
<button id="stopBtn" disabled>Disconnect</button>
<button id="audioBtn" disabled title="Toggle audio playback">&#128263; Audio</button>
<button id="recordBtn" disabled title="Record live streams to MP4 files"><span class="rec-dot"></span> Record</button>
<button id="replayBtn" title="Replay a recorded .mp4 file">Replay</button>
<input type="file" id="replayFile" accept=".mp4,.bin,.log" multiple style="display:none" />
<span id="audioLevel" style="color:#555; font-size:0.65rem; font-family:monospace; letter-spacing:-1px; white-space:nowrap;" title="Audio level (RMS)">--</span>
<span id="statusText" style="color:#888; font-size:0.8rem;">Idle</span>
<span id="viewerCount" style="color:#888; font-size:0.8rem; margin-left:0.25rem;">0 viewers</span>
<span style="font-size:0.8rem; margin-left:0.25rem;" title="Video stream latency and FPS"><span id="streamPing" style="color:#555; display:inline-block; width:5.5em; text-align:right;">--</span> <span id="streamFps" style="color:#555; display:inline-block; width:3.5em; text-align:right;">--</span></span>
<button id="settingsToggle" class="settings-toggle" aria-label="Settings">&#9881;</button>
</div>
</div>
<div class="replay-bar" id="replayBar">
<button id="replayPlayPause">Play</button>
<span class="replay-time" id="replayCurrentTime">0:00</span>
<input type="range" id="replayTimeline" min="0" max="1000" value="0" step="1" />
<span class="replay-time" id="replayDuration">0:00</span>
<select id="replaySpeed">
<option value="0.25">0.25x</option>
<option value="0.5">0.5x</option>
<option value="1" selected>1x</option>
<option value="2">2x</option>
<option value="4">4x</option>
</select>
<button id="replayClose">X</button>
</div>
<div class="main">
<div class="canvas-container" id="view3d">
<canvas id="threeCanvas"></canvas>
<div class="canvas-overlay">
<span>Drag to orbit / Scroll to zoom / Right-drag to pan</span>
</div>
</div>
<div class="camera-split" id="cameraSplit"></div>
<div class="settings-panel" id="settingsPanel"></div>
<div class="side-panel">
<div id="armPanelsContainer"></div>
<div class="panel-section" id="panelStats">
<h3>Stats</h3>
<div class="stats-grid">
<div class="stat">
<div class="stat-label">Frames</div>
<div class="stat-value" id="frameCount">0</div>
</div>
<div class="stat">
<div class="stat-label">Bytes</div>
<div class="stat-value" id="bytesReceived">0 B</div>
</div>
<div class="stat">
<div class="stat-label">FPS</div>
<div class="stat-value" id="canFps">0</div>
</div>
<div class="stat">
<div class="stat-label">Last</div>
<div class="stat-value" id="lastUpdate">-</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-bar" id="tabBar">
<button class="tab-btn active" data-tab="3d">3D</button>
<button class="tab-btn" data-tab="arms">Arms</button>
<button class="tab-btn" data-tab="camera">Cam</button>
<button class="tab-btn" data-tab="stats">Stats</button>
<button class="tab-btn" data-tab="log">Log</button>
<button class="tab-btn" data-tab="settings">&#9881;</button>
</div>
<div class="log-panel" id="log"></div>
<div class="chat-bar">
<input type="text" id="chatUsername" placeholder="Name" />
<input type="text" id="chatInput" placeholder="@robot pick up the yellow cube and put it in the green box" value="@robot pick up the yellow cube and put it in the green box" />
</div>
<div class="toast-container" id="toasts"></div>
</body>
</html>