| 1 | --- |
| 2 | import RetroIcon from "../components/RetroIcon.astro"; |
| 3 | import RetroBox from "../components/RetroBox.astro"; |
| 4 | import { GITHUB_REPOSITORY_URL, MARKETING_STATS } from "../lib/site"; |
| 5 | import "../styles/retro.css"; |
| 6 | |
| 7 | const agents = [ |
| 8 | { |
| 9 | name: "Claude Code", |
| 10 | slug: "claude-code", |
| 11 | caption: "Now with manners.", |
| 12 | artwork: "Cream and orange software box with a bow-tied desktop computer and a gold PLEASE sticker.", |
| 13 | }, |
| 14 | { |
| 15 | name: "Codex", |
| 16 | slug: "codex", |
| 17 | caption: "Some assembly automated.", |
| 18 | artwork: "Silver and green software box with a robot hand stacking glowing code blocks.", |
| 19 | }, |
| 20 | { |
| 21 | name: "Cursor", |
| 22 | slug: "cursor", |
| 23 | caption: "Point. Click. Question everything.", |
| 24 | artwork: "Black and chrome software box with an enormous silver arrow and lightning bolts.", |
| 25 | }, |
| 26 | { |
| 27 | name: "Grok", |
| 28 | slug: "grok", |
| 29 | caption: "Adult supervision sold separately.", |
| 30 | artwork: "Black and red software box with a spacecraft and an UH OH sticker.", |
| 31 | }, |
| 32 | { |
| 33 | name: "OpenCode", |
| 34 | slug: "opencode", |
| 35 | caption: "Please copy this floppy.", |
| 36 | artwork: "Purple shareware box with floppy disks spilling from an open carton.", |
| 37 | }, |
| 38 | { |
| 39 | name: "Antigravity", |
| 40 | slug: "antigravity", |
| 41 | caption: "System requirement: no gravity.", |
| 42 | artwork: "Blue and violet software box with a floating chrome triangle and metallic spheres.", |
| 43 | }, |
| 44 | ]; |
| 45 | const userDigits = MARKETING_STATS.users.replaceAll(",", "").padStart(7, "0").split(""); |
| 46 | --- |
| 47 | |
| 48 | <!doctype html> |
| 49 | <html lang="en"> |
| 50 | <head> |
| 51 | <meta charset="UTF-8" /> |
| 52 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 53 | <meta name="description" content="Introducing T3 Code. All your coding agents in one happy little window. Free, open source, and available without six CD-ROMs." /> |
| 54 | <meta name="theme-color" content="#000000" /> |
| 55 | <link rel="icon" href="/favicon.ico" sizes="48x48" /> |
| 56 | <title>T3 Code '95 | The future is now. Like, right now.</title> |
| 57 | </head> |
| 58 | <body> |
| 59 | <a class="skip-link retro-button" href="#main-content">Skip to the sales pitch</a> |
| 60 | |
| 61 | <nav class="desktop-icons" aria-label="Desktop shortcuts"> |
| 62 | <a href="/" class="desktop-icon"><RetroIcon name="computer" /><span>My Computer</span></a> |
| 63 | <a href="/download" class="desktop-icon"><RetroIcon name="disk" /><span>Install T3 Code</span></a> |
| 64 | <a href={GITHUB_REPOSITORY_URL} class="desktop-icon"><RetroIcon name="globe" /><span>Network<br />Neighborhood</span></a> |
| 65 | <button type="button" class="desktop-icon" data-dialog="recycle"><RetroIcon name="bin" /><span>Bad Ideas</span></button> |
| 66 | </nav> |
| 67 | |
| 68 | <div class="desktop"> |
| 69 | <div class="browser-window raised" id="sales-window"> |
| 70 | <header class="window-title" id="window-title" tabindex="0" aria-label="Move browser window. Drag or use arrow keys. Double-click to maximize."> |
| 71 | <span class="window-name"><RetroIcon name="globe" size={18} /><span>T3 Code '95 - Internet Explorer</span></span> |
| 72 | <div class="window-controls"> |
| 73 | <button class="retro-button window-control" type="button" id="minimize" aria-label="Minimize window"><span aria-hidden="true">_</span></button> |
| 74 | <button class="retro-button window-control" type="button" id="maximize" aria-label="Maximize window" aria-pressed="false"><span class="maximize-icon" aria-hidden="true"></span></button> |
| 75 | <button class="retro-button window-control" type="button" data-dialog="close" aria-label="Close window"><span aria-hidden="true">×</span></button> |
| 76 | </div> |
| 77 | </header> |
| 78 | |
| 79 | <nav class="browser-menu" aria-label="Page navigation"> |
| 80 | <a href="#nightly"><u>N</u>ightly</a> |
| 81 | <a href="#features"><u>F</u>eatures</a> |
| 82 | <a href="#agents"><u>A</u>gents</a> |
| 83 | <a href="#order"><u>O</u>rder now</a> |
| 84 | <a href={GITHUB_REPOSITORY_URL}><u>S</u>ource</a> |
| 85 | <button type="button" data-dialog="help"><u>H</u>elp</button> |
| 86 | </nav> |
| 87 | |
| 88 | <div class="address-bar"> |
| 89 | <span>Address</span> |
| 90 | <div class="address-field sunken"><RetroIcon name="globe" size={16} /><span>https://t3.codes/95</span></div> |
| 91 | <a class="retro-button address-go" href="/">Go <span aria-hidden="true">↗</span></a> |
| 92 | </div> |
| 93 | |
| 94 | <main id="main-content" tabindex="0"> |
| 95 | <section class="hero" aria-labelledby="hero-title"> |
| 96 | <div class="hero-copy"> |
| 97 | <h1 id="hero-title">All your agents.<br />One happy<br /><span>little window.</span></h1> |
| 98 | <p class="hero-explanation">Your coding agents in one free, open-source app.<br />You bring the subscriptions. We bring the buttons.</p> |
| 99 | <div class="platform-line"><span>AVAILABLE FOR</span><strong>Windows</strong><b>·</b><strong>macOS</strong><b>·</b><strong>Linux</strong></div> |
| 100 | </div> |
| 101 | |
| 102 | <div class="edition-packages" aria-label="Choose Stable or Nightly"> |
| 103 | <a class="hero-package" href="/download" aria-label="Download T3 Code stable"> |
| 104 | <RetroBox image="t3-code-lime" alt="T3 Code in a lime and teal software box." sizes="(max-width: 620px) 38vw, 170px" eager /> |
| 105 | <span class="retro-button edition-download">Get Stable <span aria-hidden="true">↗</span></span> |
| 106 | </a> |
| 107 | <a class="hero-package nightly-package" id="nightly" href="/download?channel=nightly" aria-label="Download T3 Code Nightly preview builds"> |
| 108 | <RetroBox image="t3-code-nightly-clouds" alt="T3 Code Nightly in a navy box with violet clouds." sizes="(max-width: 620px) 38vw, 170px" eager /> |
| 109 | <span class="retro-button edition-download">Get Nightly <span aria-hidden="true">↗</span></span> |
| 110 | </a> |
| 111 | </div> |
| 112 | </section> |
| 113 | |
| 114 | <section class="agents-section" id="agents" aria-labelledby="agents-title"> |
| 115 | <div class="section-heading"><h2 id="agents-title">Bring your favorite agents.</h2></div> |
| 116 | <div class="agent-list"> |
| 117 | {agents.map((agent, index) => ( |
| 118 | <figure class="agent"> |
| 119 | <img |
| 120 | class="agent-box" |
| 121 | src={`/95/providers/${agent.slug}-640.webp`} |
| 122 | srcset={[320, 640, 960].map((width) => `/95/providers/${agent.slug}-${width}.webp ${width}w`).join(", ")} |
| 123 | sizes="auto, (max-width: 620px) 43vw, (max-width: 1100px) 27vw, 280px" |
| 124 | alt={agent.artwork} |
| 125 | width="640" |
| 126 | height="800" |
| 127 | loading={index < 3 ? "eager" : "lazy"} |
| 128 | decoding="async" |
| 129 | /> |
| 130 | <figcaption> |
| 131 | <h3>{agent.name}</h3> |
| 132 | <p>{agent.caption}</p> |
| 133 | </figcaption> |
| 134 | </figure> |
| 135 | ))} |
| 136 | </div> |
| 137 | <p class="agents-note">Use the providers and subscriptions you already have. Provider charges still apply.</p> |
| 138 | <p class="agents-note">Parody packaging. No actual boxes for sale.</p> |
| 139 | </section> |
| 140 | |
| 141 | <section class="features-section" id="features" aria-labelledby="features-title"> |
| 142 | <div class="section-heading"><h2 id="features-title">Inside every copy.</h2></div> |
| 143 | <div class="feature-grid"> |
| 144 | <article class="feature-window raised"> |
| 145 | <div class="feature-titlebar"><span>01_multitasking.exe</span><span aria-hidden="true">■</span></div> |
| 146 | <div class="feature-body"><RetroIcon name="computer" size={38} /><h3>More agents.<br />Less window aerobics.</h3><p>Run agents side by side. Keep your threads, terminals, and diffs together. Reclaim your Alt-Tab finger.</p></div> |
| 147 | </article> |
| 148 | <article class="feature-window raised"> |
| 149 | <div class="feature-titlebar"><span>02_remote_access.exe</span><span aria-hidden="true">■</span></div> |
| 150 | <div class="feature-body"><RetroIcon name="globe" size={38} /><h3>Your computer.<br />Now over there.</h3><p>Connect from the web, desktop, or mobile. Your agents keep working on your machine. You may approach the couch.</p></div> |
| 151 | </article> |
| 152 | <article class="feature-window raised"> |
| 153 | <div class="feature-titlebar"><span>03_source_code.txt</span><span aria-hidden="true">■</span></div> |
| 154 | <div class="feature-body"><RetroIcon name="folder" size={38} /><h3>We left the<br />source code in.</h3><p>Read it. Change it. Fork the whole thing. It's MIT licensed, because your tools should actually be yours.</p><a class="feature-tag" href={GITHUB_REPOSITORY_URL}>View source <span aria-hidden="true">↗</span></a></div> |
| 155 | </article> |
| 156 | <article class="feature-window raised"> |
| 157 | <div class="feature-titlebar"><span>04_terminal.exe</span><span aria-hidden="true">■</span></div> |
| 158 | <div class="feature-body"><RetroIcon name="computer" size={38} /><h3>A terminal.<br />Right where you work.</h3><p>Run commands alongside your agents. Keep the output with the project.</p></div> |
| 159 | </article> |
| 160 | <article class="feature-window raised"> |
| 161 | <div class="feature-titlebar"><span>05_changes.diff</span><span aria-hidden="true">■</span></div> |
| 162 | <div class="feature-body"><RetroIcon name="folder" size={38} /><h3>See what<br />actually changed.</h3><p>Inspect file diffs and review the work before you ship it.</p></div> |
| 163 | </article> |
| 164 | <article class="feature-window raised"> |
| 165 | <div class="feature-titlebar"><span>06_checkpoint.bak</span><span aria-hidden="true">■</span></div> |
| 166 | <div class="feature-body"><RetroIcon name="disk" size={38} /><h3>A way<br />back.</h3><p>Use turn checkpoints to inspect changes and restore earlier work.</p></div> |
| 167 | </article> |
| 168 | </div> |
| 169 | </section> |
| 170 | |
| 171 | <section class="order-section" id="order" aria-labelledby="order-title"> |
| 172 | <div class="order-pitch"><h2 id="order-title">For just <span>0 easy payments</span><br />of absolutely nothing.</h2><p>Get the app. Keep your subscriptions.</p><a class="retro-button primary-cta" href="/download"><RetroIcon name="disk" size={25} /><span>GET T3 CODE. IT'S FREE.</span><span aria-hidden="true">→</span></a><p class="offer-note">T3 Code is free. Your AI provider may charge for use.</p></div> |
| 173 | <div class="run-window raised"><div class="window-title"><span>Run</span><RetroIcon name="computer" size={18} /></div><div class="run-body"><p>Too cool for an installer?</p><label for="run-command">Type this in your terminal.</label><div class="command-row"><input id="run-command" class="sunken" value="npx t3" readonly spellcheck="false" aria-label="Terminal command" /><button type="button" class="retro-button" id="copy-command">Copy</button></div><p class="command-feedback" id="command-feedback" role="status">Node.js required. Modem optional.</p><div class="run-divider"></div><b>System requirements</b><ul><li>A modern computer</li><li>A supported coding agent</li><li>A dream, ideally a small one</li></ul><p class="requirements-note">Does not actually run on Windows 95.</p></div></div> |
| 174 | </section> |
| 175 | |
| 176 | <section class="faq-section" aria-labelledby="faq-title"> |
| 177 | <h2 id="faq-title">Questions</h2> |
| 178 | <details><summary>Wait. Is this a real product?</summary><p>Yes. T3 Code is a real, free, open-source app used by {MARKETING_STATS.users} developers. The packaging is a joke. The app is not. <a href="/">Visit the regular website.</a></p></details> |
| 179 | <details><summary>Does this replace my Claude or Codex subscription?</summary><p>No. T3 Code connects to the coding agents you already use. Keep your provider accounts and subscriptions. T3 Code gives you one app to work with them.</p></details> |
| 180 | <details><summary>Will it run on Windows 95?</summary><p>Absolutely not. We brought back the look, not the driver problems. <a href="/download">Get a build for a current version of Windows, macOS, or Linux.</a></p></details> |
| 181 | <details><summary>Where do I mail my check?</summary><p>Please do not mail us a check for zero dollars. Just download the app. The entire accounts department is a download button.</p></details> |
| 182 | </section> |
| 183 | |
| 184 | <footer class="site-footer"> |
| 185 | <div class="visitor-counter"><div class="counter-digits" aria-label={`${MARKETING_STATS.users} users`}>{userDigits.map((digit) => <span aria-hidden="true">{digit}</span>)}</div><span>developers use T3 Code.</span></div> |
| 186 | <p>© {new Date().getFullYear()} T3 Tools Inc.</p> |
| 187 | <nav aria-label="Footer"><a href="/">Back to the present</a><a href={GITHUB_REPOSITORY_URL}>GitHub</a><a href="/privacy-policy">Privacy</a><a href="/terms-of-service">Terms</a></nav> |
| 188 | </footer> |
| 189 | </main> |
| 190 | |
| 191 | <div class="browser-status"><span class="sunken">Done.</span><span class="sunken"><RetroIcon name="globe" size={14} /> Internet</span><span class="resize-grip" aria-hidden="true"></span></div> |
| 192 | </div> |
| 193 | |
| 194 | <div class="minimized-message" id="minimized-message" hidden><RetroIcon name="computer" size={64} /><h1>The future is minimized.</h1><p>Your productivity is one click away.</p><button type="button" class="retro-button" data-restore>Restore T3 Code '95</button></div> |
| 195 | </div> |
| 196 | |
| 197 | <div class="taskbar raised"> |
| 198 | <details class="start-menu" id="start-menu"><summary class="retro-button start-button"><span class="start-mark" aria-hidden="true"><i></i><i></i><i></i><i></i></span>Start</summary><nav class="start-panel raised" aria-label="Start menu"><div class="start-brand">T3 CODE <b>95</b></div><div><a href="/download"><RetroIcon name="disk" size={24} />Install T3 Code</a><button type="button" data-restore><RetroIcon name="computer" size={24} />Restore the future</button><a href={GITHUB_REPOSITORY_URL}><RetroIcon name="folder" size={24} />Explore source code</a><a href="/"><RetroIcon name="globe" size={24} />Return to the present</a></div></nav></details> |
| 199 | <span class="taskbar-divider" aria-hidden="true"></span> |
| 200 | <button class="task-button sunken" type="button" data-restore><RetroIcon name="globe" size={20} /><span>T3 Code '95</span></button> |
| 201 | <div class="taskbar-clock sunken"><span aria-hidden="true">◷</span><span>4:04 PM</span></div> |
| 202 | </div> |
| 203 | |
| 204 | <dialog class="retro-dialog raised" id="sales-dialog" aria-labelledby="dialog-title" aria-describedby="dialog-message"><div class="window-title"><span id="dialog-title">T3 Code '95</span><button type="button" class="retro-button window-control" data-dismiss aria-label="Close dialog">×</button></div><div class="dialog-content"><RetroIcon name="computer" size={42} /><p id="dialog-message"></p></div><div class="dialog-actions"><button class="retro-button" type="button" data-dismiss autofocus>OK, fine.</button><a class="retro-button" href="/download">Get T3 Code</a></div></dialog> |
| 205 | |
| 206 | <script> |
| 207 | const salesWindow = document.querySelector<HTMLElement>("#sales-window"); |
| 208 | const minimizedMessage = document.querySelector<HTMLElement>("#minimized-message"); |
| 209 | const minimizeButton = document.querySelector<HTMLButtonElement>("#minimize"); |
| 210 | const maximizeButton = document.querySelector<HTMLButtonElement>("#maximize"); |
| 211 | const startMenu = document.querySelector<HTMLDetailsElement>("#start-menu"); |
| 212 | const taskButton = document.querySelector<HTMLButtonElement>(".task-button"); |
| 213 | const titleBar = document.querySelector<HTMLElement>("#window-title"); |
| 214 | const taskbar = document.querySelector<HTMLElement>(".taskbar"); |
| 215 | let windowX = 0; |
| 216 | let windowY = 0; |
| 217 | |
| 218 | // Keep the entire window above the taskbar, including after a viewport resize. |
| 219 | function moveWindow(x: number, y: number) { |
| 220 | if (!salesWindow || document.body.classList.contains("maximized")) return; |
| 221 | const rect = salesWindow.getBoundingClientRect(); |
| 222 | const originX = rect.left - windowX; |
| 223 | const originY = rect.top - windowY; |
| 224 | const bottom = taskbar?.getBoundingClientRect().top ?? window.innerHeight; |
| 225 | windowX = Math.max(-originX, Math.min(x, window.innerWidth - rect.width - originX)); |
| 226 | windowY = Math.max(-originY, Math.min(y, bottom - rect.height - originY)); |
| 227 | salesWindow.style.setProperty("--window-x", `${windowX}px`); |
| 228 | salesWindow.style.setProperty("--window-y", `${windowY}px`); |
| 229 | } |
| 230 | |
| 231 | function toggleMaximize() { |
| 232 | if (!maximizeButton) return; |
| 233 | const maximized = document.body.classList.toggle("maximized"); |
| 234 | maximizeButton.setAttribute("aria-pressed", String(maximized)); |
| 235 | maximizeButton.setAttribute("aria-label", maximized ? "Restore window size" : "Maximize window"); |
| 236 | if (!maximized) moveWindow(windowX, windowY); |
| 237 | } |
| 238 | |
| 239 | if (titleBar && salesWindow) { |
| 240 | let drag: { pointerId: number; startX: number; startY: number; x: number; y: number } | undefined; |
| 241 | |
| 242 | titleBar.addEventListener("pointerdown", (event) => { |
| 243 | if (!event.isPrimary || event.button !== 0 || document.body.classList.contains("maximized")) return; |
| 244 | if (event.target instanceof Element && event.target.closest("button")) return; |
| 245 | drag = { pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, x: windowX, y: windowY }; |
| 246 | titleBar.focus({ preventScroll: true }); |
| 247 | titleBar.setPointerCapture(event.pointerId); |
| 248 | titleBar.classList.add("dragging"); |
| 249 | }); |
| 250 | titleBar.addEventListener("pointermove", (event) => { |
| 251 | if (!drag || event.pointerId !== drag.pointerId) return; |
| 252 | moveWindow(drag.x + event.clientX - drag.startX, drag.y + event.clientY - drag.startY); |
| 253 | }); |
| 254 | const stopDrag = () => { |
| 255 | drag = undefined; |
| 256 | titleBar.classList.remove("dragging"); |
| 257 | }; |
| 258 | titleBar.addEventListener("pointerup", stopDrag); |
| 259 | titleBar.addEventListener("pointercancel", stopDrag); |
| 260 | titleBar.addEventListener("lostpointercapture", stopDrag); |
| 261 | titleBar.addEventListener("dblclick", (event) => { |
| 262 | if (event.target instanceof Element && event.target.closest("button")) return; |
| 263 | toggleMaximize(); |
| 264 | }); |
| 265 | titleBar.addEventListener("keydown", (event) => { |
| 266 | if (event.target !== titleBar || event.altKey || event.ctrlKey || event.metaKey) return; |
| 267 | const step = event.shiftKey ? 1 : 10; |
| 268 | switch (event.key) { |
| 269 | case "ArrowLeft": moveWindow(windowX - step, windowY); break; |
| 270 | case "ArrowRight": moveWindow(windowX + step, windowY); break; |
| 271 | case "ArrowUp": moveWindow(windowX, windowY - step); break; |
| 272 | case "ArrowDown": moveWindow(windowX, windowY + step); break; |
| 273 | default: return; |
| 274 | } |
| 275 | event.preventDefault(); |
| 276 | }); |
| 277 | } |
| 278 | |
| 279 | window.addEventListener("resize", () => { |
| 280 | if (!salesWindow?.hidden) moveWindow(windowX, windowY); |
| 281 | }); |
| 282 | |
| 283 | minimizeButton?.addEventListener("click", () => { |
| 284 | if (!salesWindow || !minimizedMessage) return; |
| 285 | salesWindow.hidden = true; |
| 286 | minimizedMessage.hidden = false; |
| 287 | taskButton?.focus(); |
| 288 | }); |
| 289 | |
| 290 | document.querySelectorAll<HTMLButtonElement>("[data-restore]").forEach((button) => { |
| 291 | button.addEventListener("click", () => { |
| 292 | if (!salesWindow || !minimizedMessage) return; |
| 293 | salesWindow.hidden = false; |
| 294 | minimizedMessage.hidden = true; |
| 295 | if (startMenu) startMenu.open = false; |
| 296 | moveWindow(windowX, windowY); |
| 297 | minimizeButton?.focus({ preventScroll: true }); |
| 298 | }); |
| 299 | }); |
| 300 | |
| 301 | maximizeButton?.addEventListener("click", toggleMaximize); |
| 302 | |
| 303 | const messages = { |
| 304 | recycle: { title: "Recycle Bin", message: "Contents: 47 abandoned side projects, 12 startup ideas, and one very ambitious TODO comment. T3 Code cannot fix your commitment issues. But it can help you ship." }, |
| 305 | close: { title: "Close the future?", message: "You are about to return to a world with too many terminal windows. Are you sure? Our sales department would prefer that you download T3 Code." }, |
| 306 | help: { title: "Windows Help", message: "It looks like you're trying to ship software. Have you tried putting all your coding agents in one app? Click Get T3 Code. No paperclip will follow you home." }, |
| 307 | }; |
| 308 | const dialog = document.querySelector<HTMLDialogElement>("#sales-dialog"); |
| 309 | const dialogTitle = document.querySelector<HTMLElement>("#dialog-title"); |
| 310 | const dialogMessage = document.querySelector<HTMLElement>("#dialog-message"); |
| 311 | |
| 312 | document.querySelectorAll<HTMLButtonElement>("[data-dialog]").forEach((button) => { |
| 313 | button.addEventListener("click", () => { |
| 314 | const kind = button.dataset.dialog; |
| 315 | if (!dialog || !dialogTitle || !dialogMessage) return; |
| 316 | if (kind !== "recycle" && kind !== "close" && kind !== "help") return; |
| 317 | dialogTitle.textContent = messages[kind].title; |
| 318 | dialogMessage.textContent = messages[kind].message; |
| 319 | dialog.showModal(); |
| 320 | }); |
| 321 | }); |
| 322 | document.querySelectorAll<HTMLButtonElement>("[data-dismiss]").forEach((button) => { |
| 323 | button.addEventListener("click", () => dialog?.close()); |
| 324 | }); |
| 325 | |
| 326 | document.addEventListener("keydown", (event) => { |
| 327 | if (event.key === "Escape" && startMenu?.open) { |
| 328 | startMenu.open = false; |
| 329 | startMenu.querySelector("summary")?.focus(); |
| 330 | } |
| 331 | }); |
| 332 | document.addEventListener("click", (event) => { |
| 333 | if (startMenu?.open && event.target instanceof Node && !startMenu.contains(event.target)) { |
| 334 | startMenu.open = false; |
| 335 | } |
| 336 | }); |
| 337 | |
| 338 | const copyButton = document.querySelector<HTMLButtonElement>("#copy-command"); |
| 339 | const command = document.querySelector<HTMLInputElement>("#run-command"); |
| 340 | const feedback = document.querySelector<HTMLElement>("#command-feedback"); |
| 341 | copyButton?.addEventListener("click", async () => { |
| 342 | if (!command || !feedback) return; |
| 343 | try { |
| 344 | await navigator.clipboard.writeText(command.value); |
| 345 | feedback.textContent = "Copied! Paste it in your terminal. Welcome to the future."; |
| 346 | } catch { |
| 347 | command.focus(); |
| 348 | command.select(); |
| 349 | feedback.textContent = "Select and copy the command, then paste it in your terminal."; |
| 350 | } |
| 351 | }); |
| 352 | </script> |
| 353 | </body> |
| 354 | </html> |