Files
gibbz/public/index.html
T
matsandClaude Sonnet 5 5bde1757d6
Build and Publish / Metadata (push) Successful in 1s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 50s
Require a nickname before joining and add a quick-start help modal
New visitors (no nickname in localStorage) get a blocking welcome
modal instead of a silently-generated guest-N name, so everyone in a
room has a name they actually chose. It doubles as quick-start help
(join a channel, mic/deafen/share shortcuts, drag-to-reposition on the
spatial map) reachable any time via the new ? button. The sidebar nick
field no longer falls back to a random name when cleared — it now
just rejects the blank edit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 11:17:05 +02:00

152 lines
6.0 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>gibbz voice — POC</title>
<link rel="stylesheet" href="style.css" />
<script src="https://otel.k6n.net/static/otel-rum.js"></script>
<script>
window.rum = window.OtelRUM ? OtelRUM.init({
serviceName: "gibbz",
baseUrl: "https://otel.k6n.net",
release: window.__APP_RELEASE__ || "dev",
environment: "production",
traceHeaderOrigins: [window.location.origin]
}) : null;
</script>
</head>
<body>
<div id="app">
<!-- server rail -->
<nav id="rail">
<div class="rail-icon home" title="gibbz voice">G</div>
<div class="rail-sep"></div>
<div class="rail-icon" title="POC server">VP</div>
</nav>
<!-- channel sidebar -->
<aside id="sidebar">
<header id="server-name">gibbz voice <span class="poc-tag">POC</span></header>
<div class="channel-group-label">Text channels</div>
<div class="channel text" data-mx-room="gibbz-general">#
general <span class="hint">matrix</span></div>
<div class="channel-group-label">Voice channels</div>
<div class="channel voice" data-room="general">&#128266; General <span class="count" data-room-count="general"></span></div>
<div class="channel voice" data-room="gaming">&#128266; Gaming <span class="count" data-room-count="gaming"></span></div>
<div class="channel voice" data-room="lounge">&#128266; Lounge <span class="count" data-room-count="lounge"></span></div>
<footer id="user-panel">
<div class="me">
<div class="avatar" id="me-avatar">?</div>
<div class="me-meta">
<input id="nick" maxlength="24" spellcheck="false" title="Click to edit nickname" />
<div class="status-row" id="status-row" title="Not connected">
<span class="status-indicator" id="status-dot"></span>
<span id="voice-status">Disconnected</span>
</div>
</div>
</div>
<div class="user-buttons">
<button id="btn-mic" class="ctl" title="Toggle mic (M)">&#127908;</button>
<button id="btn-deafen" class="ctl" title="Toggle deafen (D)">&#128064;</button>
<button id="btn-share" class="ctl" title="Share your screen (S)">&#128421;&#65039;</button>
<button id="btn-settings" class="ctl" title="Voice &amp; ICE settings">&#9881;&#65039;</button>
<button id="btn-help" class="ctl" title="How to use gibbz voice">&#10067;</button>
</div>
</footer>
</aside>
<!-- main stage -->
<main id="main">
<div id="stage">
<div id="screens"></div>
<div id="stage-empty">
<div class="big-icon">&#128421;&#65039;</div>
<h2>No active screen shares</h2>
<p>When someone shares their screen, it will appear here. Click the screen button below or press <b>S</b> to share.</p>
</div>
</div>
<div id="spatial-wrap">
<div class="spatial-label">
<span>SPATIAL AUDIO</span>
<span class="hint">drag <b>your</b> avatar &mdash; others hear you shift; you hear them relative to position</span>
</div>
<div id="spatial"></div>
</div>
</main>
</div>
<!-- settings modal -->
<div id="modal-backdrop" class="hidden">
<div id="settings-modal" role="dialog" aria-modal="true">
<h2>Voice &amp; ICE settings</h2>
<p class="hint">Overrides the server-provided ICE configuration (stored in <code>localStorage</code>, applied on next join).</p>
<label class="toggle-row">
<input type="checkbox" id="override-enabled" />
<span>Use custom STUN/TURN (JSON below)</span>
</label>
<textarea id="ice-json" rows="12" spellcheck="false"></textarea>
<div class="modal-actions">
<button id="ice-reset" class="ghost">Reset to server defaults</button>
<span class="spacer"></span>
<button id="ice-cancel" class="ghost">Cancel</button>
<button id="ice-save">Save</button>
</div>
<h3>Server defaults</h3>
<pre id="ice-server-default" class="hint"></pre>
</div>
</div>
<!-- welcome / nickname / how-to-use modal -->
<div id="welcome-backdrop" class="hidden">
<div id="welcome-modal" role="dialog" aria-modal="true">
<h2>Welcome to gibbz voice</h2>
<p class="hint">Pick a name so others can recognize you.</p>
<label class="field-label" for="welcome-nick">Nickname</label>
<input id="welcome-nick" maxlength="24" spellcheck="false" autocomplete="off" placeholder="e.g. alex" />
<div id="welcome-nick-error" class="field-error hidden">Enter a nickname to continue.</div>
<h3>Quick start</h3>
<ul class="howto-list">
<li>Click a <b>voice channel</b> in the sidebar to join it — click another to switch.</li>
<li><b>Mic</b>, <b>Deafen</b> and <b>Share screen</b> are the buttons bottom-left, or press <b>M</b> / <b>D</b> / <b>S</b>.</li>
<li>On the <b>spatial audio</b> map, drag your dot around — you hear people relative to where they stand.</li>
<li>Screen shares show up at the top of the main area; pop one into its own window with <b>&#10726;</b>.</li>
</ul>
<div class="modal-actions">
<span class="spacer"></span>
<button id="welcome-continue">Continue</button>
</div>
</div>
</div>
<div id="mx-panel" class="hidden">
<div class="mx-header">
<span>#general <span class="poc-tag">matrix · experimental</span></span>
<button id="mx-close" class="ghost" title="Close">&times;</button>
</div>
<div id="mx-messages"></div>
<div class="mx-composer">
<textarea id="mx-input" rows="1" placeholder="Message #general (Enter to send)"></textarea>
<button id="mx-send">Send</button>
</div>
</div>
<div id="reconnect-banner" class="hidden" role="alert">
<div class="reconnect-spinner"></div>
<span id="reconnect-text">Connection lost</span>
<div class="reconnect-actions">
<button id="reconnect-retry">Retry now</button>
<button id="reconnect-dismiss" class="ghost">Dismiss</button>
</div>
</div>
<div id="toasts"></div>
<script type="module" src="/app.js"></script>
</body>
</html>