cat / goq
clone

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

release/v0.1.0-pins
goq / website / index.html
index.html 15.0K
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: low-latency 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. Low-latency SteamOS streaming over iroh, a few viewers and one controller. 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 compiled desktop app, ad-hoc signed rather than15 Apple-notarized. Sigil is installed on a dedicated Bazzite machine16 through the fail-closed bootstrap command. -->17 <!-- ─── First screen: full-viewport dither with a floating panel ─── -->18 <div class="screen">19 <header class="topbar">20 <a class="topbar-github" href="https://github.com/FelineStateMachine/goq" rel="noopener">source&nbsp;</a>21 <nav class="topbar-nav">22 <a href="#features">features</a>23 <a href="#roadmap">next</a>24 <a href="#how">how</a>25 <a href="#start">start</a>26 </nav>27 </header>2829 <section class="hero">30 <canvas class="hero-canvas" aria-hidden="true"></canvas>31 <div class="hero-panel">32 <!-- pixel security key mark -->33 <svg class="hero-key" viewBox="0 0 26 12" width="78" height="36" aria-hidden="true">34 <rect x="0" y="1" width="8" height="10" fill="var(--terracotta)" />35 <rect x="3" y="5" width="2" height="2" fill="var(--paper)" />36 <rect x="8" y="5" width="18" height="2" fill="var(--ochre)" />37 <rect x="14" y="7" width="2" height="3" fill="var(--moss)" />38 <rect x="19" y="7" width="2" height="2" fill="var(--moss)" />39 </svg>40 <pre class="hero-ascii" role="img" aria-label="goq.sh">░█▀█░█▀█░█▀█░░░█▀▀░█░█41░█▄█░█░█░█▄█░░░▀▀█░█▀█42░▄▄█░▀▀▀░░░█░▀░▀▀▀░▀░▀</pre>43 <p class="hero-tagline">Your key is the address. Plug in, tap, play.</p>44 <div class="install-group">45 <div class="seg" role="radiogroup" aria-label="Get goq">46 <label class="seg-opt">47 <input type="radio" name="release-target" value="portal" checked />48 <span>portal</span>49 </label>50 <label class="seg-opt">51 <input type="radio" name="release-target" value="sigil" />52 <span>sigil</span>53 </label>54 </div>55 <div class="release-action" data-release-target="portal">56 <div class="portal-picker">57 <div class="seg" role="radiogroup" aria-label="Operating system">58 <label class="seg-opt">59 <input type="radio" name="portal-os" value="macos" checked />60 <span>macos</span>61 </label>62 <label class="seg-opt">63 <input type="radio" name="portal-os" value="linux" />64 <span>linux</span>65 </label>66 <label class="seg-opt">67 <input type="radio" name="portal-os" value="windows" />68 <span>windows</span>69 </label>70 </div>71 <div class="seg" role="radiogroup" aria-label="Architecture">72 <label class="seg-opt">73 <input type="radio" name="portal-arch" value="arm" checked />74 <span>arm</span>75 </label>76 <label class="seg-opt">77 <input type="radio" name="portal-arch" value="x86" />78 <span>x86</span>79 </label>80 </div>81 </div>82 <a class="portal-download disabled" id="portal-download" aria-disabled="true">no macos arm64 build yet</a>83 <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>84 <p class="release-note">portal is not notarized by apple · macos blocks the first launch, then allow it under system settings › privacy &amp; security · verify the published sha-256 and the github build attestation before you open it</p>85 </div>86 <div class="release-action" data-release-target="sigil" hidden>87 <div class="install" data-copy="curl -fsSL https://goq.sh/install-sigil | bash">88 <code class="install-cmd"><span class="install-prompt">$</span> <span class="install-text">curl -fsSL https://goq.sh/install-sigil | bash</span></code>89 <button class="install-copy" type="button" aria-label="Copy Sigil install command">copy</button>90 </div>91 <p class="release-note">non-root Bazzite setup · signed release channel pending</p>92 </div>93 </div>94 <p class="hero-note">Games over QUIC: low-latency SteamOS streaming over iroh <br> Work in progress. Not a finished product.</p>95 </div>96 </section>97 </div>9899 <main id="main">100 <!-- ─── Features ─────────────────────────────────────────── -->101 <section class="features" id="features">102 <div class="section-rule" aria-hidden="true"></div>103 <h2 class="section-title"><span aria-hidden="true">##</span> why goq</h2>104 <ol class="feature-grid">105 <li class="feature reveal">106 <h3>Your key is the address</h3>107 <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>108 </li>109 <li class="feature reveal">110 <h3>Headless Sigil host</h3>111 <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>112 </li>113 <li class="feature reveal">114 <h3>Controller-first</h3>115 <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>116 </li>117 <li class="feature reveal">118 <h3>Audio included</h3>119 <p>PipeWire capture to Opus in bounded datagrams, played back through an AudioWorklet next to the WebCodecs picture.</p>120 </li>121 <li class="feature reveal">122 <h3>Bounded everything</h3>123 <p>Frame handoff capped at four, decode queue at two, every buffer bounded. Stale frames are dropped, not queued, so latency never drifts.</p>124 </li>125 <li class="feature reveal">126 <h3>One host, a few viewers</h3>127 <p>Three viewers by default, eight at most, sharing one encoded stream over end-to-end encrypted iroh links, relay-assisted when a direct path isn't possible. Exactly one holds the controller. No third-party streaming service.</p>128 </li>129 </ol>130 </section>131132 <!-- ─── Promoted hardening roadmap ─────────────────────── -->133 <section class="roadmap" id="roadmap">134 <div class="section-rule" aria-hidden="true"></div>135 <h2 class="section-title"><span aria-hidden="true">##</span> hardening next</h2>136 <p class="roadmap-intro">The first target stays deliberately narrow: hardware H.264 at 1280×800/60. <a href="https://github.com/FelineStateMachine/goq/issues/7" rel="noopener">Bounded Iroh/MoQ media objects</a> have landed: video now rides prioritized, cancellable groups with explicit GOP boundaries and keyframe recovery, and the legacy media tiers and JPEG fallback are gone. <a href="https://github.com/FelineStateMachine/goq/issues/74" rel="noopener">One to many viewers</a> has landed as well: one encoded generation now serves up to eight authenticated viewers with a single transferable slot-0 input focus and per-peer revocation, while legacy clients stay strictly exclusive. These are the promoted steps still ahead.</p>137 <ol class="roadmap-grid">138 <li class="roadmap-item reveal">139 <span class="roadmap-status">promoted · control</span>140 <h3><a href="https://github.com/FelineStateMachine/goq/issues/8" rel="noopener">Adaptive bitrate</a></h3>141 <p>Feed RTT, loss, backpressure, and decode backlog into a bounded controller with measured recovery and no queue growth.</p>142 </li>143 <li class="roadmap-item reveal">144 <span class="roadmap-status">promoted · motion</span>145 <h3><a href="https://github.com/FelineStateMachine/goq/issues/9" rel="noopener">Motion-sensitive resolution</a></h3>146 <p>Favor fresh, smooth motion at lower resolution, then restore detail after motion settles without breaking pointer mapping.</p>147 </li>148 <li class="roadmap-item reveal">149 <span class="roadmap-status">promoted · codec</span>150 <h3><a href="https://github.com/FelineStateMachine/goq/issues/10" rel="noopener">Auto Codec</a></h3>151 <p>Select from end-to-end hardware support and measured latency. H.264 remains the safe baseline; compression ratio alone never wins.</p>152 </li>153 </ol>154 </section>155156 <!-- ─── How it works ─────────────────────────────────────── -->157 <section class="how" id="how">158 <div class="section-rule" aria-hidden="true"></div>159 <h2 class="section-title"><span aria-hidden="true">##</span> how it works</h2>160161 <div class="diagram">162 <!-- host column -->163 <div class="dg-node reveal">164 <span class="dg-label">sigil · bare-metal linux</span>165 <ol class="dg-steps">166 <li>Steam and your game</li>167 <li>headless Gamescope session</li>168 <li>PipeWire video + audio capture</li>169 <li>hardware H.264 + Opus encode</li>170 </ol>171 <span class="dg-foot-in">gamepad + kb/m injected via uinput</span>172 </div>173174 <!-- channel: media out, input back -->175 <div class="dg-channel" aria-hidden="true">176 <div class="dg-rail dg-video">177 <span class="dg-pill">media · iroh</span>178 <span class="dg-head">▶</span>179 </div>180 <div class="dg-rail dg-input">181 <span class="dg-pill">input · iroh</span>182 <span class="dg-head">◀</span>183 </div>184 </div>185186 <!-- client column -->187 <div class="dg-node reveal">188 <span class="dg-label">portal · native app</span>189 <ol class="dg-steps">190 <li>native iroh endpoint</li>191 <li>WebCodecs + AudioWorklet</li>192 <li>picture and sound appear</li>193 <li>controller, keyboard, mouse</li>194 </ol>195 <span class="dg-foot-in">any machine, near or far</span>196 </div>197 </div>198199 <ul class="dg-notes">200 <li>Paired by your <strong>FIDO2 security key</strong>: same key, same address. No passwords, no accounts.</li>201 <li><strong>One host, up to eight viewers</strong>. Media and input ride separate end-to-end encrypted iroh connections, and only the focus holder's input reaches the host.</li>202 <li><strong>Every queue bounded</strong>. Stale frames are dropped, not queued, so it never drifts behind.</li>203 </ul>204 </section>205206 <!-- ─── Quick start ──────────────────────────────────────── -->207 <section class="start" id="start">208 <div class="section-rule" aria-hidden="true"></div>209 <h2 class="section-title"><span aria-hidden="true">##</span> three taps to steam</h2>210 <ol class="start-grid">211 <li class="start-step reveal">212 <span class="start-num" aria-hidden="true">01</span>213 <h3>provision sigil</h3>214 <p>Run the Sigil setup command on a dedicated AMD Bazzite machine. It accepts only signed runtime packages; Gamescope becomes the headless display. A controller-first Decky Loader plugin manages the appliance from the couch, no SSH or keyboard needed.</p>215 </li>216 <li class="start-step reveal">217 <span class="start-num" aria-hidden="true">02</span>218 <h3>open portal</h3>219 <p>Download the Portal build for your client machine and verify its published SHA-256. Tap your FIDO2 key; the D-pad PIN pad keeps onboarding couch-friendly.</p>220 </li>221 <li class="start-step reveal">222 <span class="start-num" aria-hidden="true">03</span>223 <h3>tap to play <kbd>back+start</kbd></h3>224 <p>Tap the same key anywhere else: SteamOS appears, your controller just works. Hold Back+Start for a second to escape the session.</p>225 </li>226 </ol>227 <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 Portal release targets macOS arm64. It is ad-hoc signed rather than Apple-notarized, so macOS blocks the first launch until you allow it. Linux and Windows are built and attested every release but are not published; build from source until they pass their own acceptance gate. <a class="footer-link" href="https://github.com/FelineStateMachine/goq" rel="noopener">Runbook and source →</a></p>228 </section>229 </main>230231 <footer class="footer">232 <div class="section-rule" aria-hidden="true"></div>233 <div class="footer-inner">234 <ul class="stack-row" aria-label="Tech stack">235 <li>rust</li>236 <li>tauri v2</li>237 <li>iroh</li>238 <li>gamescope</li>239 <li>pipewire</li>240 <li>h.264 + opus</li>241 <li>webcodecs</li>242 <li>uinput</li>243 <li>decky loader</li>244 <li>ctap-hid-fido2</li>245 <li>no npm · no build step</li>246 </ul>247 <div class="footer-meta">248 <span>MIT licensed</span>249 <a class="footer-link" href="https://github.com/FelineStateMachine/goq" rel="noopener">Source</a>250 <span class="footer-domain">goq.sh</span>251 </div>252 </div>253 </footer>254255 <script src="./dither.js"></script>256</body>257</html>