cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

fix/architecture-review-findings
goq / website / index.html
index.html 14.1K
1<!doctype html>2<html lang="en">3<head>4 <meta charset="utf-8" />5 <meta name="viewport" content="width=device-width, initial-scale=1" />6 <title>goq.sh: one-to-one SteamOS streaming over iroh</title>7 <meta name="description" content="goq.sh pairs Portal, a native client, with Sigil, a headless Gamescope host, for games over QUIC. One-to-one, low-latency SteamOS streaming over iroh. Your key is the address." />8 <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024' shape-rendering='crispEdges'%3E%3Crect x='100' y='100' width='824' height='824' rx='185' fill='%23ece3d2'/%3E%3Cg transform='translate(224,356) scale(44)' fill='%232b2119' fill-opacity='0.18'%3E%3Crect width='6' height='8'/%3E%3Crect x='6' y='3' width='8' height='2'/%3E%3Crect x='9' y='5' width='2' height='2'/%3E%3Crect x='12' y='5' width='2' height='3'/%3E%3C/g%3E%3Cg transform='translate(204,336) scale(44)'%3E%3Crect width='6' height='8' fill='%23b5623b'/%3E%3Crect x='2' y='3' width='2' height='2' fill='%23ece3d2'/%3E%3Crect x='6' y='3' width='8' height='2' fill='%23c98a3a'/%3E%3Crect x='9' y='5' width='2' height='2' fill='%236b7145'/%3E%3Crect x='12' y='5' width='2' height='3' fill='%236b7145'/%3E%3C/g%3E%3C/svg%3E" />9 <link rel="stylesheet" href="./styles.css" />10</head>11<body>12 <a class="skip" href="#main">Skip to content</a>1314 <!-- Portal is downloaded as a signed desktop app. Sigil is installed on a15 dedicated Bazzite machine through the fail-closed bootstrap command. -->16 <!-- ─── First screen: full-viewport dither with a floating panel ─── -->17 <div class="screen">18 <header class="topbar">19 <a class="topbar-github" href="https://github.com/FelineStateMachine/goq" rel="noopener">source&nbsp;</a>20 <nav class="topbar-nav">21 <a href="#features">features</a>22 <a href="#roadmap">next</a>23 <a href="#how">how</a>24 <a href="#start">start</a>25 </nav>26 </header>2728 <section class="hero">29 <canvas class="hero-canvas" aria-hidden="true"></canvas>30 <div class="hero-panel">31 <!-- pixel security key mark -->32 <svg class="hero-key" viewBox="0 0 26 12" width="78" height="36" aria-hidden="true">33 <rect x="0" y="1" width="8" height="10" fill="var(--terracotta)" />34 <rect x="3" y="5" width="2" height="2" fill="var(--paper)" />35 <rect x="8" y="5" width="18" height="2" fill="var(--ochre)" />36 <rect x="14" y="7" width="2" height="3" fill="var(--moss)" />37 <rect x="19" y="7" width="2" height="2" fill="var(--moss)" />38 </svg>39 <pre class="hero-ascii" role="img" aria-label="goq.sh">░█▀█░█▀█░█▀█░░░█▀▀░█░█40░█▄█░█░█░█▄█░░░▀▀█░█▀█41░▄▄█░▀▀▀░░░█░▀░▀▀▀░▀░▀</pre>42 <p class="hero-tagline">Your key is the address. Plug in, tap, play.</p>43 <div class="install-group">44 <div class="seg" role="radiogroup" aria-label="Get goq">45 <label class="seg-opt">46 <input type="radio" name="release-target" value="portal" checked />47 <span>portal</span>48 </label>49 <label class="seg-opt">50 <input type="radio" name="release-target" value="sigil" />51 <span>sigil</span>52 </label>53 </div>54 <div class="release-action" data-release-target="portal">55 <div class="portal-picker">56 <div class="seg" role="radiogroup" aria-label="Operating system">57 <label class="seg-opt">58 <input type="radio" name="portal-os" value="macos" checked />59 <span>macos</span>60 </label>61 <label class="seg-opt">62 <input type="radio" name="portal-os" value="linux" />63 <span>linux</span>64 </label>65 <label class="seg-opt">66 <input type="radio" name="portal-os" value="windows" />67 <span>windows</span>68 </label>69 </div>70 <div class="seg" role="radiogroup" aria-label="Architecture">71 <label class="seg-opt">72 <input type="radio" name="portal-arch" value="arm" checked />73 <span>arm</span>74 </label>75 <label class="seg-opt">76 <input type="radio" name="portal-arch" value="x86" />77 <span>x86</span>78 </label>79 </div>80 </div>81 <a class="portal-download disabled" id="portal-download" aria-disabled="true">no macos arm64 build yet</a>82 <p class="release-note"><span id="portal-release-status">portal for macos/arm64 is not released yet · macos arm64 comes first</span> · <a class="release-history" href="https://github.com/FelineStateMachine/goq/releases" rel="noopener">release history</a></p>83 </div>84 <div class="release-action" data-release-target="sigil" hidden>85 <div class="install" data-copy="curl -fsSL https://goq.sh/install-sigil | bash">86 <code class="install-cmd"><span class="install-prompt">$</span> <span class="install-text">curl -fsSL https://goq.sh/install-sigil | bash</span></code>87 <button class="install-copy" type="button" aria-label="Copy Sigil install command">copy</button>88 </div>89 <p class="release-note">non-root Bazzite setup · signed release channel pending</p>90 </div>91 </div>92 <p class="hero-note">Games over QUIC: one-to-one SteamOS streaming over iroh <br> Work in progress. Not a finished product.</p>93 </div>94 </section>95 </div>9697 <main id="main">98 <!-- ─── Features ─────────────────────────────────────────── -->99 <section class="features" id="features">100 <div class="section-rule" aria-hidden="true"></div>101 <h2 class="section-title"><span aria-hidden="true">##</span> why goq</h2>102 <ol class="feature-grid">103 <li class="feature reveal">104 <h3>Your key is the address</h3>105 <p>The FIDO2 key's hmac-secret seeds the iroh identity. Host and client derive the same node ID from the same physical key. No pairing codes, no accounts.</p>106 </li>107 <li class="feature reveal">108 <h3>Headless Sigil host</h3>109 <p>A pure-Rust daemon on bare-metal Linux, no desktop, no display. Gamescope runs a private SteamOS session; PipeWire feeds a hardware H.264 encoder.</p>110 </li>111 <li class="feature reveal">112 <h3>Controller-first</h3>113 <p>A virtual Xbox-style gamepad, keyboard, and relative mouse injected via uinput. D-pad PIN pad and a Back+Start escape chord, built for a couch.</p>114 </li>115 <li class="feature reveal">116 <h3>Audio included</h3>117 <p>PipeWire capture to Opus in bounded datagrams, played back through an AudioWorklet next to the WebCodecs picture.</p>118 </li>119 <li class="feature reveal">120 <h3>Bounded everything</h3>121 <p>Frame handoff capped at four, decode queue at two, every buffer bounded. Stale frames are dropped, not queued, so latency never drifts.</p>122 </li>123 <li class="feature reveal">124 <h3>One host, one client</h3>125 <p>A single active client, enforced, over an end-to-end encrypted iroh link, relay-assisted when a direct path isn't possible. No third-party streaming service.</p>126 </li>127 </ol>128 </section>129130 <!-- ─── Promoted hardening roadmap ─────────────────────── -->131 <section class="roadmap" id="roadmap">132 <div class="section-rule" aria-hidden="true"></div>133 <h2 class="section-title"><span aria-hidden="true">##</span> hardening next</h2>134 <p class="roadmap-intro">The first target stays deliberately narrow: hardware H.264 at 1280×800/60. These are the promoted steps from a proven stream to one that adapts without accumulating latency.</p>135 <ol class="roadmap-grid">136 <li class="roadmap-item reveal">137 <span class="roadmap-status">promoted · transport</span>138 <h3><a href="https://github.com/FelineStateMachine/goq/issues/7" rel="noopener">Iroh/MoQ media objects</a></h3>139 <p>Prioritized, cancellable video objects with explicit GOP boundaries and keyframe recovery. Input remains independent.</p>140 </li>141 <li class="roadmap-item reveal">142 <span class="roadmap-status">promoted · control</span>143 <h3><a href="https://github.com/FelineStateMachine/goq/issues/8" rel="noopener">Adaptive bitrate</a></h3>144 <p>Feed RTT, loss, backpressure, and decode backlog into a bounded controller with measured recovery and no queue growth.</p>145 </li>146 <li class="roadmap-item reveal">147 <span class="roadmap-status">promoted · motion</span>148 <h3><a href="https://github.com/FelineStateMachine/goq/issues/9" rel="noopener">Motion-sensitive resolution</a></h3>149 <p>Favor fresh, smooth motion at lower resolution, then restore detail after motion settles without breaking pointer mapping.</p>150 </li>151 <li class="roadmap-item reveal">152 <span class="roadmap-status">promoted · codec</span>153 <h3><a href="https://github.com/FelineStateMachine/goq/issues/10" rel="noopener">Auto Codec</a></h3>154 <p>Select from end-to-end hardware support and measured latency. H.264 remains the safe baseline; compression ratio alone never wins.</p>155 </li>156 </ol>157 </section>158159 <!-- ─── How it works ─────────────────────────────────────── -->160 <section class="how" id="how">161 <div class="section-rule" aria-hidden="true"></div>162 <h2 class="section-title"><span aria-hidden="true">##</span> how it works</h2>163164 <div class="diagram">165 <!-- host column -->166 <div class="dg-node reveal">167 <span class="dg-label">sigil · bare-metal linux</span>168 <ol class="dg-steps">169 <li>Steam and your game</li>170 <li>headless Gamescope session</li>171 <li>PipeWire video + audio capture</li>172 <li>hardware H.264 + Opus encode</li>173 </ol>174 <span class="dg-foot-in">gamepad + kb/m injected via uinput</span>175 </div>176177 <!-- channel: media out, input back -->178 <div class="dg-channel" aria-hidden="true">179 <div class="dg-rail dg-video">180 <span class="dg-pill">media · iroh</span>181 <span class="dg-head">▶</span>182 </div>183 <div class="dg-rail dg-input">184 <span class="dg-pill">input · iroh</span>185 <span class="dg-head">◀</span>186 </div>187 </div>188189 <!-- client column -->190 <div class="dg-node reveal">191 <span class="dg-label">portal · native app</span>192 <ol class="dg-steps">193 <li>native iroh endpoint</li>194 <li>WebCodecs + AudioWorklet</li>195 <li>picture and sound appear</li>196 <li>controller, keyboard, mouse</li>197 </ol>198 <span class="dg-foot-in">any machine, near or far</span>199 </div>200 </div>201202 <ul class="dg-notes">203 <li>Paired by your <strong>FIDO2 security key</strong>: same key, same address. No passwords, no accounts.</li>204 <li><strong>One host, one client</strong>. Media and input ride separate end-to-end encrypted iroh connections.</li>205 <li><strong>Every queue bounded</strong>. Stale frames are dropped, not queued, so it never drifts behind.</li>206 </ul>207 </section>208209 <!-- ─── Quick start ──────────────────────────────────────── -->210 <section class="start" id="start">211 <div class="section-rule" aria-hidden="true"></div>212 <h2 class="section-title"><span aria-hidden="true">##</span> three taps to steam</h2>213 <ol class="start-grid">214 <li class="start-step reveal">215 <span class="start-num" aria-hidden="true">01</span>216 <h3>provision sigil</h3>217 <p>Run the Sigil setup command on a dedicated AMD Bazzite machine. It accepts only signed runtime packages; Gamescope becomes the headless display.</p>218 </li>219 <li class="start-step reveal">220 <span class="start-num" aria-hidden="true">02</span>221 <h3>open portal</h3>222 <p>Download a signed Portal build on your client machine. Tap your FIDO2 key; the D-pad PIN pad keeps onboarding couch-friendly.</p>223 </li>224 <li class="start-step reveal">225 <span class="start-num" aria-hidden="true">03</span>226 <h3>tap to play <kbd>back+start</kbd></h3>227 <p>Tap the same key anywhere else: SteamOS appears, your controller just works. Hold Back+Start for a second to escape the session.</p>228 </li>229 </ol>230 <p class="start-note">You'll need a FIDO2 key with hmac-secret support (YubiKey, Google Titan, …) and an AMD Bazzite machine for Sigil. The first signed Portal release targets macOS; other client packages remain source builds until they receive an equally strict release path. <a class="footer-link" href="https://github.com/FelineStateMachine/goq" rel="noopener">Runbook and source →</a></p>231 </section>232 </main>233234 <footer class="footer">235 <div class="section-rule" aria-hidden="true"></div>236 <div class="footer-inner">237 <ul class="stack-row" aria-label="Tech stack">238 <li>rust</li>239 <li>tauri v2</li>240 <li>iroh</li>241 <li>gamescope</li>242 <li>pipewire</li>243 <li>h.264 + opus</li>244 <li>webcodecs</li>245 <li>uinput</li>246 <li>ctap-hid-fido2</li>247 <li>no npm · no build step</li>248 </ul>249 <div class="footer-meta">250 <span>MIT licensed</span>251 <a class="footer-link" href="https://github.com/FelineStateMachine/goq" rel="noopener">Source</a>252 <span class="footer-domain">goq.sh</span>253 </div>254 </div>255 </footer>256257 <script src="./dither.js"></script>258</body>259</html>