authorgravatar for Noojuno@users.noreply.github.comJono Kemball <Noojuno@users.noreply.github.com> 2026-03-11 05:18:22+13:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-10 09:18:22-07:00
logb8d07eb852e5ea30717f4079595eb68515e930cf
tree9f94ba809257e78dfa2c394cf2894ce84ef0e9f6
parent223c3dc8005b583b19c502320f5de929958a7efd
signature Signed by PGP key B5690EEEBB952194

Add downloads page and shared marketing layout (#802)


4 files changed, 574 insertions(+), 241 deletions(-)

apps/marketing/src/layouts/Layout.astro created+228
...@@ -0,0 +1,228 @@
1---
2interface Props {
3 title?: string;
4 description?: string;
5}
6
7const {
8 title = "T3 Code",
9 description = "T3 Code — The best way to code with AI.",
10} = Astro.props;
11---
12
13<html lang="en">
14 <head>
15 <meta charset="UTF-8" />
16 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
17 <meta name="description" content={description} />
18 <link rel="preconnect" href="https://fonts.googleapis.com" />
19 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
20 <link
21 href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap"
22 rel="stylesheet"
23 />
24 <link rel="icon" href="/favicon.ico" sizes="48x48" />
25 <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32" />
26 <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16" />
27 <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
28 <title>{title}</title>
29 </head>
30 <body>
31 <div class="page">
32 <nav class="nav">
33 <a href="/" class="nav-brand">
34 <img src="/icon.png" alt="T3" class="nav-icon" />
35 </a>
36 <a
37 href="https://github.com/pingdotgg/t3code"
38 target="_blank"
39 rel="noopener noreferrer"
40 class="nav-github"
41 >
42 GitHub
43 <span class="nav-github-arrow" aria-hidden="true">&#8599;</span>
44 </a>
45 </nav>
46
47 <main class="main">
48 <slot />
49 </main>
50
51 <footer class="footer">
52 <span class="footer-copy">&copy; {new Date().getFullYear()} T3 Tools Inc</span>
53 <div class="footer-links">
54 <a href="https://github.com/pingdotgg/t3code" target="_blank" rel="noopener noreferrer">GitHub</a>
55 <a href="https://discord.gg/jn4EGJjrvv" target="_blank" rel="noopener noreferrer">Discord</a>
56 </div>
57 </footer>
58 </div>
59 </body>
60</html>
61
62<style is:global>
63 :root {
64 --bg: #09090b;
65 --fg: #fafafa;
66 --fg-muted: #a1a1aa;
67 --fg-dim: #71717a;
68 --border: rgba(255, 255, 255, 0.08);
69 }
70
71 * {
72 box-sizing: border-box;
73 margin: 0;
74 padding: 0;
75 }
76
77 html {
78 color-scheme: dark;
79 }
80
81 body {
82 background: var(--bg);
83 color: var(--fg);
84 font-family: "DM Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
85 -webkit-font-smoothing: antialiased;
86 -moz-osx-font-smoothing: grayscale;
87 min-height: 100vh;
88 overflow-x: hidden;
89 }
90
91 body::after {
92 content: "";
93 position: fixed;
94 inset: 0;
95 pointer-events: none;
96 opacity: 0.035;
97 background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
98 background-repeat: repeat;
99 background-size: 256px 256px;
100 z-index: 9999;
101 }
102
103 a {
104 color: inherit;
105 text-decoration: none;
106 }
107
108 img {
109 display: block;
110 max-width: 100%;
111 }
112
113 @keyframes fade-in {
114 from {
115 opacity: 0;
116 transform: translateY(8px);
117 }
118 to {
119 opacity: 1;
120 transform: translateY(0);
121 }
122 }
123</style>
124
125<style>
126 /* ── Page ── */
127
128 .page {
129 min-height: 100vh;
130 display: flex;
131 flex-direction: column;
132 overflow-x: hidden;
133 }
134
135 /* ── Navbar ── */
136
137 .nav {
138 display: flex;
139 align-items: center;
140 justify-content: space-between;
141 padding: 1.5rem 2.5rem;
142 opacity: 0.5;
143 transition: opacity 0.4s ease;
144 }
145
146 .nav:hover {
147 opacity: 1;
148 }
149
150 .nav-brand {
151 display: flex;
152 align-items: center;
153 }
154
155 .nav-icon {
156 width: 28px;
157 height: 28px;
158 border-radius: 6px;
159 }
160
161 .nav-github {
162 display: flex;
163 align-items: center;
164 gap: 0.35rem;
165 color: var(--fg-muted);
166 font-size: 0.875rem;
167 transition: color 0.3s ease;
168 }
169
170 .nav-github:hover {
171 color: var(--fg);
172 }
173
174 .nav-github-arrow {
175 display: inline-block;
176 transition: transform 0.3s ease;
177 }
178
179 .nav-github:hover .nav-github-arrow {
180 transform: translateX(2px) translateY(-1px);
181 }
182
183 /* ── Main content ── */
184
185 .main {
186 flex: 1;
187 display: flex;
188 flex-direction: column;
189 align-items: center;
190 }
191
192 /* ── Footer ── */
193
194 .footer {
195 display: flex;
196 align-items: center;
197 justify-content: space-between;
198 padding: 1.5rem 2.5rem;
199 font-size: 0.8rem;
200 color: var(--fg-dim);
201 }
202
203 .footer-links {
204 display: flex;
205 gap: 1.25rem;
206 }
207
208 .footer-links a {
209 color: var(--fg-dim);
210 transition: color 0.3s ease;
211 }
212
213 .footer-links a:hover {
214 color: var(--fg);
215 }
216
217 /* ── Mobile ── */
218
219 @media (max-width: 640px) {
220 .nav {
221 padding: 1.25rem;
222 }
223
224 .footer {
225 padding: 1.25rem;
226 }
227 }
228</style>
apps/marketing/src/lib/releases.ts created+30
...@@ -0,0 +1,30 @@
1const REPO = "pingdotgg/t3code";
2
3export const RELEASES_URL = `https://github.com/${REPO}/releases`;
4
5const API_URL = `https://api.github.com/repos/${REPO}/releases/latest`;
6const CACHE_KEY = "t3code-latest-release";
7
8export interface ReleaseAsset {
9 name: string;
10 browser_download_url: string;
11}
12
13export interface Release {
14 tag_name: string;
15 html_url: string;
16 assets: ReleaseAsset[];
17}
18
19export async function fetchLatestRelease(): Promise<Release> {
20 const cached = sessionStorage.getItem(CACHE_KEY);
21 if (cached) return JSON.parse(cached);
22
23 const data = await fetch(API_URL).then((r) => r.json());
24
25 if (data?.assets) {
26 sessionStorage.setItem(CACHE_KEY, JSON.stringify(data));
27 }
28
29 return data;
30}
apps/marketing/src/pages/download.astro created+271
...@@ -0,0 +1,271 @@
1---
2import Layout from "../layouts/Layout.astro";
3---
4
5<Layout title="Download — T3 Code" description="Download T3 Code for macOS, Windows, or Linux.">
6 <h1 class="heading">Download T3 Code</h1>
7 <p class="subheading">
8 <span id="version-label">Loading latest release&hellip;</span>
9 <a id="changelog-link" class="changelog-link" href="#" target="_blank" rel="noopener noreferrer" style="display:none">View changelog<span aria-hidden="true"> &#8599;</span></a>
10 </p>
11
12 <div class="platforms" id="platforms">
13 <!-- macOS -->
14 <section class="platform-section">
15 <div class="platform-header">
16 <svg class="platform-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 1000" aria-hidden="true"><path fill="currentColor" d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg>
17 <h2 class="platform-name">macOS</h2>
18 </div>
19 <div class="download-cards">
20 <a class="download-card" data-asset="arm64.dmg" href="#">
21 <span class="card-arch">Apple Silicon (arm64)</span>
22 <span class="card-format">.dmg</span>
23 </a>
24 <a class="download-card" data-asset="x64.dmg" href="#">
25 <span class="card-arch">Intel (x64)</span>
26 <span class="card-format">.dmg</span>
27 </a>
28 </div>
29 </section>
30
31 <!-- Windows -->
32 <section class="platform-section">
33 <div class="platform-header">
34 <svg class="platform-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88 88" aria-hidden="true"><path fill="currentColor" d="m0 12.402 35.687-4.86.016 34.423-35.67.203zm35.67 33.529.028 34.453L.028 75.48.026 45.7zm4.326-39.025L87.314 0v41.527l-47.318.376zm47.329 39.349-.011 41.34-47.318-6.678-.066-34.739z"/></svg>
35 <h2 class="platform-name">Windows</h2>
36 </div>
37 <div class="download-cards">
38 <a class="download-card" data-asset="x64.exe" href="#">
39 <span class="card-arch">Windows 10, 11</span>
40 <span class="card-format">.exe</span>
41 </a>
42 </div>
43 </section>
44
45 <!-- Linux -->
46 <section class="platform-section">
47 <div class="platform-header">
48 <svg class="platform-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 295" aria-hidden="true"><defs><linearGradient id="lt0" x1="48.548%" x2="51.047%" y1="115.276%" y2="41.364%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt6" x1="49.984%" x2="49.984%" y1="89.845%" y2="40.632%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt8" x1="49.841%" x2="50.241%" y1="13.229%" y2="94.673%"><stop offset="0%" stop-color="#FFF" stop-opacity=".8"/><stop offset="100%" stop-color="#FFF" stop-opacity="0"/></linearGradient><linearGradient id="ltc" x1="53.467%" x2="38.949%" y1="48.921%" y2="98.1%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lte" x1="30.581%" x2="65.887%" y1="34.024%" y2="89.175%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lti" x1="49.733%" x2="50.558%" y1="17.609%" y2="99.385%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient></defs><g fill="none"><path fill="#000" d="M63.213 215.474c-11.387-16.346-13.591-69.606 12.947-102.39C89.292 97.383 92.69 86.455 93.7 71.67c.734-16.805-11.846-66.851 35.537-70.616 48.027-3.857 45.364 43.526 45.088 68.596-.183 21.12 15.52 33.15 26.355 49.68 19.927 30.303 18.274 82.461-3.765 110.745-27.916 35.354-51.791 20.018-67.678 21.304-29.752 1.745-30.762 17.54-66.024-35.905"/><path fill="url(#lt6)" d="M81.027 145.684c6.52-14.785 20.386-40.772 20.662-60.883 0-15.978 47.843-19.835 51.7-3.856 3.856 15.978 13.59 39.853 19.834 51.424 6.245 11.478 24.335 48.118 5.051 80.074-17.356 28.284-69.973 50.69-98.073-3.856-9.55-18.917-7.806-42.333.826-62.903"/><path fill="url(#lt8)" d="M166.428 151.285c0 16.162-15.519 37.1-42.15 36.916-27.456.183-39.118-20.754-39.118-36.916 0-16.161 18.182-29.293 40.588-29.293 22.498.092 40.68 13.132 40.68 29.293"/><path fill="#000" stroke="#000" stroke-width=".977" d="M176.805 117.86c13.59 11.02 38.292 49.587 2.204 74.748-11.846 7.806 10.468 32.508 23.049 19.927 43.618-43.894-1.102-94.308-16.53-111.664-13.774-15.151-25.987 3.49-8.723 16.989z"/><path fill="#000" stroke="#000" stroke-width="1.25" d="M79.925 122.727c-8.907 14.509-30.211 48.669-1.652 66.484 38.384 23.6 27.548 47.108-7.53 25.895-49.404-29.568-5.97-89.257 13.774-112.03 22.59-25.529 4.316 4.683-4.592 19.65z"/><path fill="url(#ltc)" stroke="#E68C3F" stroke-width="6.25" d="M51.835 258.542c-20.57-10.928-50.414 2.112-39.578-27.457 2.204-6.704-3.214-16.805.275-23.325 4.133-7.989 13.04-6.244 18.366-11.57 5.234-5.51 8.54-15.06 18.366-13.59 9.734 1.468 16.254 13.406 23.049 28.099 5.05 10.468 22.865 25.253 21.672 37.007-1.47 17.998-21.948 21.396-42.15 10.836z" transform="translate(10)"/><path fill="url(#lte)" stroke="#E68C3F" stroke-width="6.251" d="M194.445 253.49c15.06-18.273 48.578-14.508 25.988-39.577-4.775-5.418-3.306-16.989-9.183-21.947-6.887-6.061-14.509-1.102-21.488-4.224-6.979-3.398-14.325-9.918-22.865-5.327-8.54 4.684-9.459 16.805-10.285 32.783-.735 11.479-11.203 30.671-5.602 41.231 8.081 16.346 29.11 14.142 43.435-2.938z" transform="translate(10)"/><path fill="url(#lti)" stroke="#E68C3F" stroke-width="3.75" d="M97.107 66.344c3.673-3.398 12.58-13.774 29.477-2.939 3.122 2.02 5.693 2.204 11.662 4.775 12.03 4.96 6.336 16.897-6.52 20.937-5.51 1.745-10.468 8.449-20.386 7.806-8.54-.46-10.744-6.06-15.978-9.091-9.275-5.234-10.652-12.305-5.602-16.07 5.051-3.765 6.98-5.143 7.347-5.418z" transform="translate(10)"/><path fill="#000" d="M133.186 57.712c-.092 5.234 2.48 9.458 5.877 9.458 3.306 0 6.153-4.224 6.245-9.366.091-5.234-2.48-9.459-5.878-9.459-3.397 0-6.152 4.225-6.244 9.367m-21.212.092c.459 4.316-1.194 7.989-3.582 8.356-2.387.276-4.683-2.938-5.142-7.254-.46-4.316 1.194-7.99 3.581-8.357 2.388-.275 4.684 2.939 5.143 7.255"/></g></svg>
49 <h2 class="platform-name">Linux</h2>
50 </div>
51 <div class="download-cards">
52 <a class="download-card" data-asset="x86_64.AppImage" href="#">
53 <span class="card-arch">x86_64</span>
54 <span class="card-format">AppImage</span>
55 </a>
56 </div>
57 </section>
58 </div>
59
60 <p class="releases-link">
61 Looking for older versions? Check the
62 <a href="https://github.com/pingdotgg/t3code/releases" target="_blank" rel="noopener noreferrer">
63 GitHub releases page<span aria-hidden="true"> &#8599;</span>
64 </a>
65 </p>
66</Layout>
67
68<script>
69 import { fetchLatestRelease, RELEASES_URL } from "../lib/releases";
70
71 async function init() {
72 const versionLabel = document.getElementById("version-label");
73 const cards = document.querySelectorAll<HTMLAnchorElement>(".download-card");
74
75 try {
76 const release = await fetchLatestRelease();
77
78 if (versionLabel && release.tag_name) {
79 versionLabel.textContent = `Latest (${release.tag_name})`;
80 }
81
82 const changelogLink = document.getElementById("changelog-link") as HTMLAnchorElement | null;
83 if (changelogLink && release.html_url) {
84 changelogLink.href = release.html_url;
85 changelogLink.style.display = "";
86 }
87
88 cards.forEach((card) => {
89 const suffix = card.dataset.asset;
90 if (!suffix) return;
91
92 const match = (release.assets ?? []).find((a) => a.name.endsWith(`-${suffix}`));
93 if (match) {
94 card.href = match.browser_download_url;
95 } else {
96 card.href = RELEASES_URL;
97 }
98 });
99 } catch {
100 if (versionLabel) {
101 versionLabel.textContent = "Could not load release info.";
102 }
103 cards.forEach((card) => {
104 card.href = RELEASES_URL;
105 });
106 }
107 }
108
109 init();
110</script>
111
112<style>
113 .main {
114 padding: 8vh 1.5rem 4rem;
115 }
116
117 /* ── Heading ── */
118
119 .heading {
120 font-weight: 500;
121 font-size: clamp(1.75rem, 4vw, 2.75rem);
122 letter-spacing: -0.035em;
123 line-height: 1.15;
124 text-align: center;
125 margin-bottom: 0.5rem;
126 opacity: 0;
127 animation: fade-in 1s ease-out forwards;
128 }
129
130 .subheading {
131 font-size: 0.9rem;
132 color: var(--fg-dim);
133 margin-bottom: 3.5rem;
134 opacity: 0;
135 animation: fade-in 1s ease-out 0.1s forwards;
136 display: flex;
137 align-items: center;
138 gap: 0.75rem;
139 }
140
141 .changelog-link {
142 color: var(--fg-muted);
143 font-size: 0.8rem;
144 text-decoration: underline;
145 text-decoration-color: rgba(161, 161, 170, 0.4);
146 text-underline-offset: 3px;
147 transition: color 0.3s ease, text-decoration-color 0.3s ease;
148 }
149
150 .changelog-link:hover {
151 color: var(--fg);
152 text-decoration-color: var(--fg);
153 }
154
155 /* ── Platforms ── */
156
157 .platforms {
158 width: 100%;
159 max-width: 720px;
160 display: flex;
161 flex-direction: column;
162 gap: 2.5rem;
163 opacity: 0;
164 animation: fade-in 1s ease-out 0.2s forwards;
165 }
166
167 .platform-section {
168 display: flex;
169 flex-direction: column;
170 gap: 0.75rem;
171 }
172
173 .platform-header {
174 display: flex;
175 align-items: center;
176 gap: 0.6rem;
177 padding-bottom: 0.5rem;
178 border-bottom: 1px solid var(--border);
179 }
180
181 .platform-icon {
182 width: 1.15em;
183 height: 1.15em;
184 color: var(--fg-muted);
185 flex-shrink: 0;
186 }
187
188 .platform-name {
189 font-weight: 500;
190 font-size: 1.1rem;
191 letter-spacing: -0.01em;
192 }
193
194 /* ── Download cards ── */
195
196 .download-cards {
197 display: grid;
198 grid-template-columns: repeat(2, 1fr);
199 gap: 0.5rem;
200 }
201
202 .download-card {
203 display: flex;
204 flex-direction: column;
205 gap: 0.2rem;
206 padding: 0.85rem 1rem;
207 border-radius: 10px;
208 border: 1px solid var(--border);
209 background: rgba(255, 255, 255, 0.02);
210 transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
211 }
212
213 .download-card:hover {
214 background: rgba(255, 255, 255, 0.06);
215 border-color: rgba(255, 255, 255, 0.15);
216 transform: translateY(-1px);
217 }
218
219 .download-card:active {
220 transform: translateY(0);
221 }
222
223 .card-arch {
224 font-weight: 600;
225 font-size: 0.95rem;
226 }
227
228 .card-format {
229 font-size: 0.8rem;
230 color: var(--fg-dim);
231 }
232
233 /* ── Releases link ── */
234
235 .releases-link {
236 margin-top: 3rem;
237 font-size: 0.825rem;
238 color: var(--fg-dim);
239 opacity: 0;
240 animation: fade-in 1s ease-out 0.35s forwards;
241 }
242
243 .releases-link a {
244 color: var(--fg-muted);
245 text-decoration: underline;
246 text-decoration-color: rgba(161, 161, 170, 0.4);
247 text-underline-offset: 3px;
248 transition: color 0.3s ease, text-decoration-color 0.3s ease;
249 }
250
251 .releases-link a:hover {
252 color: var(--fg);
253 text-decoration-color: var(--fg);
254 }
255
256 /* ── Mobile ── */
257
258 @media (max-width: 640px) {
259 .main {
260 padding: 5vh 1.25rem 4rem;
261 }
262
263 .platforms {
264 padding: 0 0.25rem;
265 }
266
267 .download-cards {
268 grid-template-columns: 1fr;
269 }
270 }
271</style>
apps/marketing/src/pages/index.astro+45-241
...@@ -1,75 +1,30 @@...@@ -1,75 +1,30 @@
1---1---
2import Layout from "../layouts/Layout.astro";
2---3---
34
4<html lang="en">5<Layout>
5 <head>6 <h1 class="tagline">T3 Code is the best way to code with AI.</h1>
6 <meta charset="UTF-8" />7
7 <meta name="viewport" content="width=device-width, initial-scale=1.0" />8 <a
8 <meta name="description" content="T3 Code — The best way to code with AI." />9 id="download-btn"
9 <link rel="preconnect" href="https://fonts.googleapis.com" />10 href="https://github.com/pingdotgg/t3code/releases"
10 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />11 class="hero-button"
11 <link12 >
12 href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600&display=swap"13 <svg class="hero-button-icon hero-button-icon--apple" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 1000" aria-hidden="true"><path fill="currentColor" d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg>
13 rel="stylesheet"14 <svg class="hero-button-icon hero-button-icon--windows" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88 88" aria-hidden="true"><path fill="currentColor" d="m0 12.402 35.687-4.86.016 34.423-35.67.203zm35.67 33.529.028 34.453L.028 75.48.026 45.7zm4.326-39.025L87.314 0v41.527l-47.318.376zm47.329 39.349-.011 41.34-47.318-6.678-.066-34.739z"/></svg>
14 />15 <svg class="hero-button-icon hero-button-icon--linux" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 295" aria-hidden="true"><defs><linearGradient id="lt0" x1="48.548%" x2="51.047%" y1="115.276%" y2="41.364%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt6" x1="49.984%" x2="49.984%" y1="89.845%" y2="40.632%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt8" x1="49.841%" x2="50.241%" y1="13.229%" y2="94.673%"><stop offset="0%" stop-color="#FFF" stop-opacity=".8"/><stop offset="100%" stop-color="#FFF" stop-opacity="0"/></linearGradient><linearGradient id="ltc" x1="53.467%" x2="38.949%" y1="48.921%" y2="98.1%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lte" x1="30.581%" x2="65.887%" y1="34.024%" y2="89.175%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lti" x1="49.733%" x2="50.558%" y1="17.609%" y2="99.385%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient></defs><g fill="none"><path fill="#000" d="M63.213 215.474c-11.387-16.346-13.591-69.606 12.947-102.39C89.292 97.383 92.69 86.455 93.7 71.67c.734-16.805-11.846-66.851 35.537-70.616 48.027-3.857 45.364 43.526 45.088 68.596-.183 21.12 15.52 33.15 26.355 49.68 19.927 30.303 18.274 82.461-3.765 110.745-27.916 35.354-51.791 20.018-67.678 21.304-29.752 1.745-30.762 17.54-66.024-35.905"/><path fill="url(#lt6)" d="M81.027 145.684c6.52-14.785 20.386-40.772 20.662-60.883 0-15.978 47.843-19.835 51.7-3.856 3.856 15.978 13.59 39.853 19.834 51.424 6.245 11.478 24.335 48.118 5.051 80.074-17.356 28.284-69.973 50.69-98.073-3.856-9.55-18.917-7.806-42.333.826-62.903"/><path fill="url(#lt8)" d="M166.428 151.285c0 16.162-15.519 37.1-42.15 36.916-27.456.183-39.118-20.754-39.118-36.916 0-16.161 18.182-29.293 40.588-29.293 22.498.092 40.68 13.132 40.68 29.293"/><path fill="#000" stroke="#000" stroke-width=".977" d="M176.805 117.86c13.59 11.02 38.292 49.587 2.204 74.748-11.846 7.806 10.468 32.508 23.049 19.927 43.618-43.894-1.102-94.308-16.53-111.664-13.774-15.151-25.987 3.49-8.723 16.989z"/><path fill="#000" stroke="#000" stroke-width="1.25" d="M79.925 122.727c-8.907 14.509-30.211 48.669-1.652 66.484 38.384 23.6 27.548 47.108-7.53 25.895-49.404-29.568-5.97-89.257 13.774-112.03 22.59-25.529 4.316 4.683-4.592 19.65z"/><path fill="url(#ltc)" stroke="#E68C3F" stroke-width="6.25" d="M51.835 258.542c-20.57-10.928-50.414 2.112-39.578-27.457 2.204-6.704-3.214-16.805.275-23.325 4.133-7.989 13.04-6.244 18.366-11.57 5.234-5.51 8.54-15.06 18.366-13.59 9.734 1.468 16.254 13.406 23.049 28.099 5.05 10.468 22.865 25.253 21.672 37.007-1.47 17.998-21.948 21.396-42.15 10.836z" transform="translate(10)"/><path fill="url(#lte)" stroke="#E68C3F" stroke-width="6.251" d="M194.445 253.49c15.06-18.273 48.578-14.508 25.988-39.577-4.775-5.418-3.306-16.989-9.183-21.947-6.887-6.061-14.509-1.102-21.488-4.224-6.979-3.398-14.325-9.918-22.865-5.327-8.54 4.684-9.459 16.805-10.285 32.783-.735 11.479-11.203 30.671-5.602 41.231 8.081 16.346 29.11 14.142 43.435-2.938z" transform="translate(10)"/><path fill="url(#lti)" stroke="#E68C3F" stroke-width="3.75" d="M97.107 66.344c3.673-3.398 12.58-13.774 29.477-2.939 3.122 2.02 5.693 2.204 11.662 4.775 12.03 4.96 6.336 16.897-6.52 20.937-5.51 1.745-10.468 8.449-20.386 7.806-8.54-.46-10.744-6.06-15.978-9.091-9.275-5.234-10.652-12.305-5.602-16.07 5.051-3.765 6.98-5.143 7.347-5.418z" transform="translate(10)"/><path fill="#000" d="M133.186 57.712c-.092 5.234 2.48 9.458 5.877 9.458 3.306 0 6.153-4.224 6.245-9.366.091-5.234-2.48-9.459-5.878-9.459-3.397 0-6.152 4.225-6.244 9.367m-21.212.092c.459 4.316-1.194 7.989-3.582 8.356-2.387.276-4.683-2.938-5.142-7.254-.46-4.316 1.194-7.99 3.581-8.357 2.388-.275 4.684 2.939 5.143 7.255"/></g></svg>
15 <link rel="icon" href="/favicon.ico" sizes="48x48" />16 <span id="download-label">Download now</span>
16 <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32" />17 </a>
17 <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16" />18
18 <link rel="apple-touch-icon" href="/apple-touch-icon.png" />19 <a href="/download" class="other-platforms">Other platforms</a>
19 <title>T3 Code</title>20
20 </head>21 <div class="screenshot-wrap">
21 <body>22 <img src="/screenshot.jpeg" alt="T3 Code" class="screenshot" />
22 <div class="page">23 </div>
23 <nav class="nav">24</Layout>
24 <a href="/" class="nav-brand">
25 <img src="/icon.png" alt="T3" class="nav-icon" />
26 </a>
27 <a
28 href="https://github.com/pingdotgg/t3code"
29 target="_blank"
30 rel="noopener noreferrer"
31 class="nav-github"
32 >
33 GitHub
34 <span class="nav-github-arrow" aria-hidden="true">&#8599;</span>
35 </a>
36 </nav>
37
38 <main class="main">
39 <h1 class="tagline">T3 Code is the best way to code with AI.</h1>
40
41 <a
42 id="download-btn"
43 href="https://github.com/pingdotgg/t3code/releases"
44 class="hero-button"
45 >
46 <svg class="hero-button-icon hero-button-icon--apple" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 1000" aria-hidden="true"><path fill="currentColor" d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg>
47 <svg class="hero-button-icon hero-button-icon--windows" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88 88" aria-hidden="true"><path fill="currentColor" d="m0 12.402 35.687-4.86.016 34.423-35.67.203zm35.67 33.529.028 34.453L.028 75.48.026 45.7zm4.326-39.025L87.314 0v41.527l-47.318.376zm47.329 39.349-.011 41.34-47.318-6.678-.066-34.739z"/></svg>
48 <svg class="hero-button-icon hero-button-icon--linux" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 295" aria-hidden="true"><defs><linearGradient id="lt0" x1="48.548%" x2="51.047%" y1="115.276%" y2="41.364%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt6" x1="49.984%" x2="49.984%" y1="89.845%" y2="40.632%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt8" x1="49.841%" x2="50.241%" y1="13.229%" y2="94.673%"><stop offset="0%" stop-color="#FFF" stop-opacity=".8"/><stop offset="100%" stop-color="#FFF" stop-opacity="0"/></linearGradient><linearGradient id="ltc" x1="53.467%" x2="38.949%" y1="48.921%" y2="98.1%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lte" x1="30.581%" x2="65.887%" y1="34.024%" y2="89.175%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lti" x1="49.733%" x2="50.558%" y1="17.609%" y2="99.385%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient></defs><g fill="none"><path fill="#000" d="M63.213 215.474c-11.387-16.346-13.591-69.606 12.947-102.39C89.292 97.383 92.69 86.455 93.7 71.67c.734-16.805-11.846-66.851 35.537-70.616 48.027-3.857 45.364 43.526 45.088 68.596-.183 21.12 15.52 33.15 26.355 49.68 19.927 30.303 18.274 82.461-3.765 110.745-27.916 35.354-51.791 20.018-67.678 21.304-29.752 1.745-30.762 17.54-66.024-35.905"/><path fill="url(#lt6)" d="M81.027 145.684c6.52-14.785 20.386-40.772 20.662-60.883 0-15.978 47.843-19.835 51.7-3.856 3.856 15.978 13.59 39.853 19.834 51.424 6.245 11.478 24.335 48.118 5.051 80.074-17.356 28.284-69.973 50.69-98.073-3.856-9.55-18.917-7.806-42.333.826-62.903"/><path fill="url(#lt8)" d="M166.428 151.285c0 16.162-15.519 37.1-42.15 36.916-27.456.183-39.118-20.754-39.118-36.916 0-16.161 18.182-29.293 40.588-29.293 22.498.092 40.68 13.132 40.68 29.293"/><path fill="#000" stroke="#000" stroke-width=".977" d="M176.805 117.86c13.59 11.02 38.292 49.587 2.204 74.748-11.846 7.806 10.468 32.508 23.049 19.927 43.618-43.894-1.102-94.308-16.53-111.664-13.774-15.151-25.987 3.49-8.723 16.989z"/><path fill="#000" stroke="#000" stroke-width="1.25" d="M79.925 122.727c-8.907 14.509-30.211 48.669-1.652 66.484 38.384 23.6 27.548 47.108-7.53 25.895-49.404-29.568-5.97-89.257 13.774-112.03 22.59-25.529 4.316 4.683-4.592 19.65z"/><path fill="url(#ltc)" stroke="#E68C3F" stroke-width="6.25" d="M51.835 258.542c-20.57-10.928-50.414 2.112-39.578-27.457 2.204-6.704-3.214-16.805.275-23.325 4.133-7.989 13.04-6.244 18.366-11.57 5.234-5.51 8.54-15.06 18.366-13.59 9.734 1.468 16.254 13.406 23.049 28.099 5.05 10.468 22.865 25.253 21.672 37.007-1.47 17.998-21.948 21.396-42.15 10.836z" transform="translate(10)"/><path fill="url(#lte)" stroke="#E68C3F" stroke-width="6.251" d="M194.445 253.49c15.06-18.273 48.578-14.508 25.988-39.577-4.775-5.418-3.306-16.989-9.183-21.947-6.887-6.061-14.509-1.102-21.488-4.224-6.979-3.398-14.325-9.918-22.865-5.327-8.54 4.684-9.459 16.805-10.285 32.783-.735 11.479-11.203 30.671-5.602 41.231 8.081 16.346 29.11 14.142 43.435-2.938z" transform="translate(10)"/><path fill="url(#lti)" stroke="#E68C3F" stroke-width="3.75" d="M97.107 66.344c3.673-3.398 12.58-13.774 29.477-2.939 3.122 2.02 5.693 2.204 11.662 4.775 12.03 4.96 6.336 16.897-6.52 20.937-5.51 1.745-10.468 8.449-20.386 7.806-8.54-.46-10.744-6.06-15.978-9.091-9.275-5.234-10.652-12.305-5.602-16.07 5.051-3.765 6.98-5.143 7.347-5.418z" transform="translate(10)"/><path fill="#000" d="M133.186 57.712c-.092 5.234 2.48 9.458 5.877 9.458 3.306 0 6.153-4.224 6.245-9.366.091-5.234-2.48-9.459-5.878-9.459-3.397 0-6.152 4.225-6.244 9.367m-21.212.092c.459 4.316-1.194 7.989-3.582 8.356-2.387.276-4.683-2.938-5.142-7.254-.46-4.316 1.194-7.99 3.581-8.357 2.388-.275 4.684 2.939 5.143 7.255"/></g></svg>
49 <span id="download-label">Download now</span>
50 </a>
51
52 <div class="screenshot-wrap">
53 <img src="/screenshot.jpeg" alt="T3 Code" class="screenshot" />
54 </div>
55
56 </main>
57
58 <footer class="footer">
59 <span class="footer-copy">&copy; {new Date().getFullYear()} T3 Tools Inc</span>
60 <div class="footer-links">
61 <a href="https://github.com/pingdotgg/t3code" target="_blank" rel="noopener noreferrer">GitHub</a>
62 <a href="https://discord.gg/jn4EGJjrvv" target="_blank" rel="noopener noreferrer">Discord</a>
63 </div>
64 </footer>
65 </div>
66 </body>
67</html>
6825
69<script>26<script>
70 const REPO = "pingdotgg/t3code";27 import { fetchLatestRelease, RELEASES_URL, type ReleaseAsset } from "../lib/releases";
71 const RELEASES_URL = `https://github.com/${REPO}/releases`;
72 const API_URL = `https://api.github.com/repos/${REPO}/releases/latest`;
7328
74 type Platform = { os: "mac" | "win" | "linux"; label: string; arch?: string };29 type Platform = { os: "mac" | "win" | "linux"; label: string; arch?: string };
7530
...@@ -87,10 +42,7 @@...@@ -87,10 +42,7 @@
87 return null;42 return null;
88 }43 }
8944
90 function pickAsset(45 function pickAsset(assets: ReleaseAsset[], platform: Platform): string | null {
91 assets: Array<{ name: string; browser_download_url: string }>,
92 platform: Platform,
93 ): string | null {
94 if (platform.os === "win") {46 if (platform.os === "win") {
95 return (47 return (
96 assets.find((a) => a.name.endsWith("-x64.exe"))48 assets.find((a) => a.name.endsWith("-x64.exe"))
...@@ -125,16 +77,8 @@...@@ -125,16 +77,8 @@
125 label.textContent = platform.label;77 label.textContent = platform.label;
12678
127 try {79 try {
128 const cached = sessionStorage.getItem("t3code-latest-release");80 const release = await fetchLatestRelease();
129 const data = cached81 const url = pickAsset(release.assets ?? [], platform);
130 ? JSON.parse(cached)
131 : await fetch(API_URL).then((r) => r.json());
132
133 if (!cached && data?.assets) {
134 sessionStorage.setItem("t3code-latest-release", JSON.stringify(data));
135 }
136
137 const url = pickAsset(data.assets ?? [], platform);
138 if (url) {82 if (url) {
139 btn.href = url;83 btn.href = url;
140 btn.removeAttribute("target");84 btn.removeAttribute("target");
...@@ -149,120 +93,7 @@...@@ -149,120 +93,7 @@
149</script>93</script>
15094
151<style>95<style>
152 :root {
153 --bg: #09090b;
154 --fg: #fafafa;
155 --fg-muted: #a1a1aa;
156 --fg-dim: #71717a;
157 --border: rgba(255, 255, 255, 0.08);
158 }
159
160 * {
161 box-sizing: border-box;
162 margin: 0;
163 padding: 0;
164 }
165
166 html {
167 color-scheme: dark;
168 }
169
170 body {
171 background: var(--bg);
172 color: var(--fg);
173 font-family: "DM Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
174 -webkit-font-smoothing: antialiased;
175 -moz-osx-font-smoothing: grayscale;
176 min-height: 100vh;
177 overflow-x: hidden;
178 }
179
180 body::after {
181 content: "";
182 position: fixed;
183 inset: 0;
184 pointer-events: none;
185 opacity: 0.035;
186 background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
187 background-repeat: repeat;
188 background-size: 256px 256px;
189 z-index: 9999;
190 }
191
192 a {
193 color: inherit;
194 text-decoration: none;
195 }
196
197 img {
198 display: block;
199 max-width: 100%;
200 }
201
202 /* ── Page ── */
203
204 .page {
205 min-height: 100vh;
206 display: flex;
207 flex-direction: column;
208 overflow-x: hidden;
209 }
210
211 /* ── Navbar ── */
212
213 .nav {
214 display: flex;
215 align-items: center;
216 justify-content: space-between;
217 padding: 1.5rem 2.5rem;
218 opacity: 0.5;
219 transition: opacity 0.4s ease;
220 }
221
222 .nav:hover {
223 opacity: 1;
224 }
225
226 .nav-brand {
227 display: flex;
228 align-items: center;
229 }
230
231 .nav-icon {
232 width: 28px;
233 height: 28px;
234 border-radius: 6px;
235 }
236
237 .nav-github {
238 display: flex;
239 align-items: center;
240 gap: 0.35rem;
241 color: var(--fg-muted);
242 font-size: 0.875rem;
243 transition: color 0.3s ease;
244 }
245
246 .nav-github:hover {
247 color: var(--fg);
248 }
249
250 .nav-github-arrow {
251 display: inline-block;
252 transition: transform 0.3s ease;
253 }
254
255 .nav-github:hover .nav-github-arrow {
256 transform: translateX(2px) translateY(-1px);
257 }
258
259 /* ── Main content ── */
260
261 .main {96 .main {
262 flex: 1;
263 display: flex;
264 flex-direction: column;
265 align-items: center;
266 padding-top: 10vh;97 padding-top: 10vh;
267 }98 }
26899
...@@ -291,7 +122,7 @@...@@ -291,7 +122,7 @@
291 border-radius: 999px;122 border-radius: 999px;
292 font-weight: 600;123 font-weight: 600;
293 font-size: 0.9rem;124 font-size: 0.9rem;
294 margin-bottom: 5vh;125 margin-bottom: 1.25rem;
295 opacity: 0;126 opacity: 0;
296 animation: fade-in 1s ease-out 0.15s forwards;127 animation: fade-in 1s ease-out 0.15s forwards;
297 transition: transform 0.25s ease, box-shadow 0.25s ease;128 transition: transform 0.25s ease, box-shadow 0.25s ease;
...@@ -325,6 +156,25 @@...@@ -325,6 +156,25 @@
325 display: block;156 display: block;
326 }157 }
327158
159 /* ── Other platforms link ── */
160
161 .other-platforms {
162 font-size: 0.825rem;
163 color: var(--fg-dim);
164 margin-bottom: 5vh;
165 opacity: 0;
166 animation: fade-in 1s ease-out 0.3s forwards;
167 transition: color 0.3s ease;
168 text-decoration: underline;
169 text-decoration-color: rgba(113, 113, 122, 0.4);
170 text-underline-offset: 3px;
171 }
172
173 .other-platforms:hover {
174 color: var(--fg-muted);
175 text-decoration-color: var(--fg-muted);
176 }
177
328 /* ── Screenshot ── */178 /* ── Screenshot ── */
329179
330 .screenshot-wrap {180 .screenshot-wrap {
...@@ -358,44 +208,6 @@...@@ -358,44 +208,6 @@
358 pointer-events: none;208 pointer-events: none;
359 }209 }
360210
361 /* ── Footer ── */
362
363 .footer {
364 display: flex;
365 align-items: center;
366 justify-content: space-between;
367 padding: 1.5rem 2.5rem;
368 font-size: 0.8rem;
369 color: var(--fg-dim);
370 }
371
372 .footer-links {
373 display: flex;
374 gap: 1.25rem;
375 }
376
377 .footer-links a {
378 color: var(--fg-dim);
379 transition: color 0.3s ease;
380 }
381
382 .footer-links a:hover {
383 color: var(--fg);
384 }
385
386 /* ── Animations ── */
387
388 @keyframes fade-in {
389 from {
390 opacity: 0;
391 transform: translateY(8px);
392 }
393 to {
394 opacity: 1;
395 transform: translateY(0);
396 }
397 }
398
399 @keyframes screenshot-in {211 @keyframes screenshot-in {
400 from {212 from {
401 opacity: 0;213 opacity: 0;
...@@ -410,10 +222,6 @@...@@ -410,10 +222,6 @@
410 /* ── Mobile ── */222 /* ── Mobile ── */
411223
412 @media (max-width: 640px) {224 @media (max-width: 640px) {
413 .nav {
414 padding: 1.25rem 1.25rem;
415 }
416
417 .main {225 .main {
418 padding-top: 7vh;226 padding-top: 7vh;
419 }227 }
...@@ -425,9 +233,5 @@...@@ -425,9 +233,5 @@
425 .screenshot-wrap {233 .screenshot-wrap {
426 width: 95vw;234 width: 95vw;
427 }235 }
428
429 .footer {
430 padding: 1.25rem;
431 }
432 }236 }
433</style>237</style>