cat / goq
clone

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

fix/hero-release-note
goq / website / index.html
index.html 14.7K
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"><a class="release-history" href="https://github.com/FelineStateMachine/goq/releases" rel="noopener">release history</a></p>84 </div>85 <div class="release-action" data-release-target="sigil" hidden>86 <div class="install" data-copy="curl -fsSL https://goq.sh/install-sigil | bash">87 <code class="install-cmd"><span class="install-prompt">$</span> <span class="install-text">curl -fsSL https://goq.sh/install-sigil | bash</span></code>88 <button class="install-copy" type="button" aria-label="Copy Sigil install command">copy</button>89 </div>90 <p class="release-note">dedicated bazzite machine</p>91 </div>92 </div>93 <p class="hero-note">Games over QUIC: low-latency SteamOS streaming over iroh <br> Work in progress. Not a finished product.</p>94 </div>95 </section>96 </div>9798 <main id="main">99 <!-- ─── Features ─────────────────────────────────────────── -->100 <section class="features" id="features">101 <div class="section-rule" aria-hidden="true"></div>102 <h2 class="section-title"><span aria-hidden="true">##</span> why goq</h2>103 <ol class="feature-grid">104 <li class="feature reveal">105 <h3>Your key is the address</h3>106 <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>107 </li>108 <li class="feature reveal">109 <h3>Headless Sigil host</h3>110 <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>111 </li>112 <li class="feature reveal">113 <h3>Controller-first</h3>114 <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>115 </li>116 <li class="feature reveal">117 <h3>Audio included</h3>118 <p>PipeWire capture to Opus in bounded datagrams, played back through an AudioWorklet next to the WebCodecs picture.</p>119 </li>120 <li class="feature reveal">121 <h3>Bounded everything</h3>122 <p>Frame handoff capped at four, decode queue at two, every buffer bounded. Stale frames are dropped, not queued, so latency never drifts.</p>123 </li>124 <li class="feature reveal">125 <h3>One host, a few viewers</h3>126 <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>127 </li>128 </ol>129 </section>130131 <!-- ─── Promoted hardening roadmap ─────────────────────── -->132 <section class="roadmap" id="roadmap">133 <div class="section-rule" aria-hidden="true"></div>134 <h2 class="section-title"><span aria-hidden="true">##</span> hardening next</h2>135 <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>136 <ol class="roadmap-grid">137 <li class="roadmap-item reveal">138 <span class="roadmap-status">promoted · control</span>139 <h3><a href="https://github.com/FelineStateMachine/goq/issues/8" rel="noopener">Adaptive bitrate</a></h3>140 <p>Feed RTT, loss, backpressure, and decode backlog into a bounded controller with measured recovery and no queue growth.</p>141 </li>142 <li class="roadmap-item reveal">143 <span class="roadmap-status">promoted · motion</span>144 <h3><a href="https://github.com/FelineStateMachine/goq/issues/9" rel="noopener">Motion-sensitive resolution</a></h3>145 <p>Favor fresh, smooth motion at lower resolution, then restore detail after motion settles without breaking pointer mapping.</p>146 </li>147 <li class="roadmap-item reveal">148 <span class="roadmap-status">promoted · codec</span>149 <h3><a href="https://github.com/FelineStateMachine/goq/issues/10" rel="noopener">Auto Codec</a></h3>150 <p>Select from end-to-end hardware support and measured latency. H.264 remains the safe baseline; compression ratio alone never wins.</p>151 </li>152 </ol>153 </section>154155 <!-- ─── How it works ─────────────────────────────────────── -->156 <section class="how" id="how">157 <div class="section-rule" aria-hidden="true"></div>158 <h2 class="section-title"><span aria-hidden="true">##</span> how it works</h2>159160 <div class="diagram">161 <!-- host column -->162 <div class="dg-node reveal">163 <span class="dg-label">sigil · bare-metal linux</span>164 <ol class="dg-steps">165 <li>Steam and your game</li>166 <li>headless Gamescope session</li>167 <li>PipeWire video + audio capture</li>168 <li>hardware H.264 + Opus encode</li>169 </ol>170 <span class="dg-foot-in">gamepad + kb/m injected via uinput</span>171 </div>172173 <!-- channel: media out, input back -->174 <div class="dg-channel" aria-hidden="true">175 <div class="dg-rail dg-video">176 <span class="dg-pill">media · iroh</span>177 <span class="dg-head">▶</span>178 </div>179 <div class="dg-rail dg-input">180 <span class="dg-pill">input · iroh</span>181 <span class="dg-head">◀</span>182 </div>183 </div>184185 <!-- client column -->186 <div class="dg-node reveal">187 <span class="dg-label">portal · native app</span>188 <ol class="dg-steps">189 <li>native iroh endpoint</li>190 <li>WebCodecs + AudioWorklet</li>191 <li>picture and sound appear</li>192 <li>controller, keyboard, mouse</li>193 </ol>194 <span class="dg-foot-in">any machine, near or far</span>195 </div>196 </div>197198 <ul class="dg-notes">199 <li>Paired by your <strong>FIDO2 security key</strong>: same key, same address. No passwords, no accounts.</li>200 <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>201 <li><strong>Every queue bounded</strong>. Stale frames are dropped, not queued, so it never drifts behind.</li>202 </ul>203 </section>204205 <!-- ─── Quick start ──────────────────────────────────────── -->206 <section class="start" id="start">207 <div class="section-rule" aria-hidden="true"></div>208 <h2 class="section-title"><span aria-hidden="true">##</span> three taps to steam</h2>209 <ol class="start-grid">210 <li class="start-step reveal">211 <span class="start-num" aria-hidden="true">01</span>212 <h3>provision sigil</h3>213 <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. First-time pairing still needs a shell on the host.</p>214 </li>215 <li class="start-step reveal">216 <span class="start-num" aria-hidden="true">02</span>217 <h3>open portal</h3>218 <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>219 </li>220 <li class="start-step reveal">221 <span class="start-num" aria-hidden="true">03</span>222 <h3>tap to play <kbd>back+start</kbd></h3>223 <p>Tap the same key anywhere else: SteamOS appears, your controller just works. Hold Back+Start for a second to escape the session.</p>224 </li>225 </ol>226 <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>227 </section>228 </main>229230 <footer class="footer">231 <div class="section-rule" aria-hidden="true"></div>232 <div class="footer-inner">233 <ul class="stack-row" aria-label="Tech stack">234 <li>rust</li>235 <li>tauri v2</li>236 <li>iroh</li>237 <li>gamescope</li>238 <li>pipewire</li>239 <li>h.264 + opus</li>240 <li>webcodecs</li>241 <li>uinput</li>242 <li>decky loader</li>243 <li>ctap-hid-fido2</li>244 <li>no npm · no build step</li>245 </ul>246 <div class="footer-meta">247 <span>MIT licensed</span>248 <a class="footer-link" href="https://github.com/FelineStateMachine/goq" rel="noopener">Source</a>249 <span class="footer-domain">goq.sh</span>250 </div>251 </div>252 </footer>253254 <script src="./dither.js"></script>255</body>256</html>