thebird 1.2.107 → 1.2.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gm/lastskill +1 -1
- package/docs/index.html +408 -298
- package/package.json +1 -1
package/.gm/lastskill
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
planning
|
package/docs/index.html
CHANGED
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
<meta name="theme-color" content="#3FA93A" media="(prefers-color-scheme: dark)">
|
|
8
8
|
<meta name="color-scheme" content="light dark">
|
|
9
9
|
<title>thebird / web os</title>
|
|
10
|
-
<meta name="description" content="thebird — browser-native web OS. agentic
|
|
10
|
+
<meta name="description" content="thebird — browser-native web OS. agentic AI, POSIX terminal, live preview, IDB filesystem. serverless. no Docker. no server. powered by acptoapi.">
|
|
11
11
|
<meta name="author" content="247420 / AnEntrypoint">
|
|
12
|
-
<meta name="keywords" content="thebird, web os, browser terminal, anthropic, gemini, openai, acptoapi, anentrypoint">
|
|
12
|
+
<meta name="keywords" content="thebird, web os, browser terminal, anthropic, gemini, openai, acptoapi, serverless, anentrypoint">
|
|
13
13
|
<link rel="canonical" href="https://anentrypoint.github.io/thebird/">
|
|
14
14
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='0' fill='%23247420'/><text x='16' y='22' font-family='monospace' font-size='13' font-weight='700' fill='%23EFE9DD' text-anchor='middle'>tb</text></svg>">
|
|
15
15
|
<meta property="og:type" content="website">
|
|
16
16
|
<meta property="og:title" content="thebird / web os">
|
|
17
|
-
<meta property="og:description" content="browser-native web OS — agentic
|
|
17
|
+
<meta property="og:description" content="browser-native web OS — agentic AI, POSIX terminal, live preview. no server. no Docker. serverless.">
|
|
18
18
|
<meta property="og:url" content="https://anentrypoint.github.io/thebird/">
|
|
19
19
|
<meta property="og:site_name" content="247420 / thebird">
|
|
20
20
|
<meta name="twitter:card" content="summary_large_image">
|
|
@@ -25,13 +25,15 @@
|
|
|
25
25
|
<style>
|
|
26
26
|
@import url('https://fonts.googleapis.com/css2?family=Archivo+Black&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
|
|
27
27
|
|
|
28
|
-
/* ── landing shell ── */
|
|
29
28
|
.land {
|
|
30
29
|
background: var(--paper);
|
|
31
30
|
color: var(--ink);
|
|
32
31
|
font-family: var(--ff-mono);
|
|
33
32
|
font-size: 13px;
|
|
34
33
|
line-height: 1.5;
|
|
34
|
+
min-height: 100vh;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
/* ── topbar ── */
|
|
@@ -45,33 +47,67 @@
|
|
|
45
47
|
align-items: center;
|
|
46
48
|
padding: 0 2ch;
|
|
47
49
|
height: 40px;
|
|
48
|
-
gap:
|
|
50
|
+
gap: 0;
|
|
49
51
|
}
|
|
50
52
|
.land-bar .brand {
|
|
51
53
|
font-weight: 700;
|
|
52
54
|
font-size: 13px;
|
|
53
55
|
letter-spacing: 0.02em;
|
|
54
56
|
color: var(--ink);
|
|
57
|
+
margin-right: 2ch;
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
}
|
|
60
|
+
.land-bar .slash { color: var(--ink-dim); padding: 0 0.3ch; font-weight: 400; }
|
|
61
|
+
.land-bar .brand-tabs {
|
|
62
|
+
display: flex;
|
|
63
|
+
height: 40px;
|
|
64
|
+
gap: 0;
|
|
65
|
+
}
|
|
66
|
+
.brand-tab {
|
|
67
|
+
background: none;
|
|
68
|
+
border: none;
|
|
69
|
+
border-bottom: 2px solid transparent;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
color: var(--ink-dim);
|
|
72
|
+
font-family: var(--ff-mono);
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
letter-spacing: 0.04em;
|
|
76
|
+
text-transform: uppercase;
|
|
77
|
+
padding: 0 1.5ch;
|
|
78
|
+
height: 40px;
|
|
79
|
+
transition: color 80ms, border-color 80ms;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
}
|
|
82
|
+
.brand-tab:hover { color: var(--ink); }
|
|
83
|
+
.brand-tab.active { color: var(--green); border-bottom-color: var(--green); }
|
|
84
|
+
.brand-tab .live-dot {
|
|
85
|
+
display: inline-block;
|
|
86
|
+
width: 5px; height: 5px;
|
|
87
|
+
border-radius: 50%;
|
|
88
|
+
background: var(--green);
|
|
89
|
+
margin-left: 6px;
|
|
90
|
+
vertical-align: middle;
|
|
91
|
+
animation: pulse 2s infinite;
|
|
92
|
+
}
|
|
93
|
+
.land-bar .bar-right {
|
|
94
|
+
margin-left: auto;
|
|
55
95
|
display: flex;
|
|
56
96
|
align-items: center;
|
|
97
|
+
gap: 0;
|
|
57
98
|
}
|
|
58
|
-
.land-bar .
|
|
59
|
-
.land-bar .leaf { color: var(--green); }
|
|
60
|
-
.land-bar nav { display: flex; gap: 0; margin-left: auto; }
|
|
61
|
-
.land-bar nav a {
|
|
99
|
+
.land-bar .bar-right a {
|
|
62
100
|
color: var(--ink-dim);
|
|
63
101
|
text-decoration: none;
|
|
64
|
-
padding: 0 1.5ch;
|
|
65
102
|
font-size: 12px;
|
|
66
|
-
line-height: 40px;
|
|
67
103
|
font-weight: 600;
|
|
68
104
|
letter-spacing: 0.04em;
|
|
69
105
|
text-transform: uppercase;
|
|
70
|
-
|
|
71
|
-
|
|
106
|
+
padding: 0 1.5ch;
|
|
107
|
+
line-height: 40px;
|
|
108
|
+
transition: color 80ms;
|
|
72
109
|
}
|
|
73
|
-
.land-bar
|
|
74
|
-
.land-bar nav a.active { color: var(--green); border-bottom-color: var(--green); }
|
|
110
|
+
.land-bar .bar-right a:hover { color: var(--ink); }
|
|
75
111
|
.land-bar .theme-btn {
|
|
76
112
|
background: none;
|
|
77
113
|
border: none;
|
|
@@ -82,6 +118,14 @@
|
|
|
82
118
|
line-height: 40px;
|
|
83
119
|
}
|
|
84
120
|
.land-bar .theme-btn:hover { color: var(--ink); }
|
|
121
|
+
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
|
|
122
|
+
|
|
123
|
+
/* ── page panels ── */
|
|
124
|
+
.page-panel { display: none; flex: 1; flex-direction: column; }
|
|
125
|
+
.page-panel.active { display: flex; }
|
|
126
|
+
|
|
127
|
+
/* ── overview page ── */
|
|
128
|
+
#page-overview { overflow-y: auto; }
|
|
85
129
|
|
|
86
130
|
/* ── hero ── */
|
|
87
131
|
.hero {
|
|
@@ -89,6 +133,8 @@
|
|
|
89
133
|
border-bottom: 1px solid var(--ink-hair);
|
|
90
134
|
max-width: 1200px;
|
|
91
135
|
margin: 0 auto;
|
|
136
|
+
width: 100%;
|
|
137
|
+
box-sizing: border-box;
|
|
92
138
|
}
|
|
93
139
|
.hero-eyebrow {
|
|
94
140
|
font-size: 11px;
|
|
@@ -105,16 +151,26 @@
|
|
|
105
151
|
letter-spacing: -0.02em;
|
|
106
152
|
color: var(--ink);
|
|
107
153
|
margin: 0 0 24px 0;
|
|
108
|
-
max-width:
|
|
154
|
+
max-width: 18ch;
|
|
109
155
|
}
|
|
110
156
|
.hero h1 em { font-style: normal; color: var(--green); }
|
|
111
157
|
.hero .lede {
|
|
112
158
|
font-size: 15px;
|
|
113
159
|
color: var(--ink-dim);
|
|
114
|
-
max-width:
|
|
160
|
+
max-width: 66ch;
|
|
161
|
+
line-height: 1.65;
|
|
162
|
+
margin: 0 0 12px 0;
|
|
163
|
+
}
|
|
164
|
+
.hero .motivation {
|
|
165
|
+
font-size: 13px;
|
|
166
|
+
color: var(--ink-dim);
|
|
167
|
+
max-width: 66ch;
|
|
115
168
|
line-height: 1.6;
|
|
116
|
-
margin: 0 0
|
|
169
|
+
margin: 0 0 32px 0;
|
|
170
|
+
border-left: 2px solid var(--green);
|
|
171
|
+
padding-left: 1.5ch;
|
|
117
172
|
}
|
|
173
|
+
.hero .motivation strong { color: var(--ink); }
|
|
118
174
|
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
|
|
119
175
|
.btn-primary {
|
|
120
176
|
background: var(--green);
|
|
@@ -148,8 +204,6 @@
|
|
|
148
204
|
display: inline-block;
|
|
149
205
|
}
|
|
150
206
|
.btn-ghost:hover { border-color: var(--ink); background: var(--surface-2); }
|
|
151
|
-
|
|
152
|
-
/* ── install strip ── */
|
|
153
207
|
.install-strip {
|
|
154
208
|
display: inline-flex;
|
|
155
209
|
align-items: center;
|
|
@@ -160,7 +214,6 @@
|
|
|
160
214
|
font-size: 12px;
|
|
161
215
|
}
|
|
162
216
|
.install-strip .prompt { color: var(--green); font-weight: 700; }
|
|
163
|
-
.install-strip .cmd { color: var(--ink); }
|
|
164
217
|
.install-strip .copy-btn {
|
|
165
218
|
background: none; border: none; cursor: pointer;
|
|
166
219
|
color: var(--ink-dim); font-size: 11px; font-family: var(--ff-mono);
|
|
@@ -169,21 +222,66 @@
|
|
|
169
222
|
}
|
|
170
223
|
.install-strip .copy-btn:hover { color: var(--green); }
|
|
171
224
|
|
|
225
|
+
/* ── serverless callout ── */
|
|
226
|
+
.serverless-strip {
|
|
227
|
+
background: var(--surface, rgba(11,11,9,0.04));
|
|
228
|
+
border-top: 1px solid var(--ink-hair);
|
|
229
|
+
border-bottom: 1px solid var(--ink-hair);
|
|
230
|
+
padding: 20px 2ch;
|
|
231
|
+
}
|
|
232
|
+
.serverless-strip .inner {
|
|
233
|
+
max-width: 1200px;
|
|
234
|
+
margin: 0 auto;
|
|
235
|
+
display: grid;
|
|
236
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
237
|
+
gap: 0;
|
|
238
|
+
}
|
|
239
|
+
.sl-item {
|
|
240
|
+
padding: 16px 20px;
|
|
241
|
+
border-right: 1px solid var(--ink-hair);
|
|
242
|
+
}
|
|
243
|
+
.sl-item:last-child { border-right: 0; }
|
|
244
|
+
.sl-item .sl-icon { font-size: 18px; display: block; margin-bottom: 6px; color: var(--green); }
|
|
245
|
+
.sl-item .sl-label {
|
|
246
|
+
font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
|
|
247
|
+
color: var(--ink); margin-bottom: 4px;
|
|
248
|
+
}
|
|
249
|
+
.sl-item .sl-desc { font-size: 11px; color: var(--ink-dim); line-height: 1.5; }
|
|
250
|
+
@media (max-width: 600px) { .sl-item { border-right: 0; border-bottom: 1px solid var(--ink-hair); } }
|
|
251
|
+
|
|
252
|
+
/* ── motivation section ── */
|
|
253
|
+
.motivation-section {
|
|
254
|
+
padding: 48px 2ch 40px 2ch;
|
|
255
|
+
max-width: 1200px;
|
|
256
|
+
margin: 0 auto;
|
|
257
|
+
width: 100%;
|
|
258
|
+
box-sizing: border-box;
|
|
259
|
+
border-bottom: 1px solid var(--ink-hair);
|
|
260
|
+
}
|
|
261
|
+
.section-head {
|
|
262
|
+
font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
|
|
263
|
+
color: var(--ink-dim); margin-bottom: 24px; padding-bottom: 8px;
|
|
264
|
+
border-bottom: 1px solid var(--ink-hair);
|
|
265
|
+
}
|
|
266
|
+
.mot-grid {
|
|
267
|
+
display: grid;
|
|
268
|
+
grid-template-columns: 1fr 1fr;
|
|
269
|
+
gap: 32px;
|
|
270
|
+
}
|
|
271
|
+
@media (max-width: 700px) { .mot-grid { grid-template-columns: 1fr; } }
|
|
272
|
+
.mot-block h3 {
|
|
273
|
+
font-size: 13px; font-weight: 700; color: var(--ink); margin: 0 0 8px 0;
|
|
274
|
+
text-transform: lowercase; letter-spacing: 0.02em;
|
|
275
|
+
}
|
|
276
|
+
.mot-block p { font-size: 12px; color: var(--ink-dim); line-height: 1.6; margin: 0; }
|
|
277
|
+
|
|
172
278
|
/* ── features grid ── */
|
|
173
279
|
.features {
|
|
174
280
|
padding: 48px 2ch;
|
|
175
281
|
max-width: 1200px;
|
|
176
282
|
margin: 0 auto;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
font-size: 11px;
|
|
180
|
-
font-weight: 600;
|
|
181
|
-
letter-spacing: 0.1em;
|
|
182
|
-
text-transform: uppercase;
|
|
183
|
-
color: var(--ink-dim);
|
|
184
|
-
margin-bottom: 24px;
|
|
185
|
-
padding-bottom: 8px;
|
|
186
|
-
border-bottom: 1px solid var(--ink-hair);
|
|
283
|
+
width: 100%;
|
|
284
|
+
box-sizing: border-box;
|
|
187
285
|
}
|
|
188
286
|
.feat-grid {
|
|
189
287
|
display: grid;
|
|
@@ -198,37 +296,17 @@
|
|
|
198
296
|
}
|
|
199
297
|
.feat-card:hover { background: var(--surface-2); }
|
|
200
298
|
.feat-card .glyph {
|
|
201
|
-
font-size: 20px;
|
|
202
|
-
margin-bottom: 12px;
|
|
203
|
-
display: block;
|
|
204
|
-
color: var(--green);
|
|
205
|
-
font-style: normal;
|
|
299
|
+
font-size: 20px; margin-bottom: 12px; display: block; color: var(--green); font-style: normal;
|
|
206
300
|
}
|
|
207
301
|
.feat-card h3 {
|
|
208
|
-
font-family: var(--ff-mono);
|
|
209
|
-
|
|
210
|
-
font-weight: 700;
|
|
211
|
-
color: var(--ink);
|
|
212
|
-
margin: 0 0 8px 0;
|
|
213
|
-
text-transform: lowercase;
|
|
214
|
-
letter-spacing: 0.02em;
|
|
215
|
-
}
|
|
216
|
-
.feat-card p {
|
|
217
|
-
font-size: 12px;
|
|
218
|
-
color: var(--ink-dim);
|
|
219
|
-
line-height: 1.55;
|
|
220
|
-
margin: 0 0 12px 0;
|
|
302
|
+
font-family: var(--ff-mono); font-size: 13px; font-weight: 700; color: var(--ink);
|
|
303
|
+
margin: 0 0 8px 0; text-transform: lowercase; letter-spacing: 0.02em;
|
|
221
304
|
}
|
|
305
|
+
.feat-card p { font-size: 12px; color: var(--ink-dim); line-height: 1.55; margin: 0 0 12px 0; }
|
|
222
306
|
.feat-tag {
|
|
223
|
-
display: inline-block;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
letter-spacing: 0.08em;
|
|
227
|
-
text-transform: uppercase;
|
|
228
|
-
color: var(--green);
|
|
229
|
-
border: 1px solid var(--green);
|
|
230
|
-
padding: 1px 6px;
|
|
231
|
-
margin: 2px 2px 0 0;
|
|
307
|
+
display: inline-block; font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
|
|
308
|
+
text-transform: uppercase; color: var(--green); border: 1px solid var(--green);
|
|
309
|
+
padding: 1px 6px; margin: 2px 2px 0 0;
|
|
232
310
|
}
|
|
233
311
|
|
|
234
312
|
/* ── receipt panel ── */
|
|
@@ -236,101 +314,49 @@
|
|
|
236
314
|
padding: 0 2ch 48px 2ch;
|
|
237
315
|
max-width: 1200px;
|
|
238
316
|
margin: 0 auto;
|
|
317
|
+
width: 100%;
|
|
318
|
+
box-sizing: border-box;
|
|
239
319
|
display: grid;
|
|
240
320
|
grid-template-columns: 1fr 1fr;
|
|
241
321
|
gap: 32px;
|
|
242
322
|
align-items: start;
|
|
243
323
|
}
|
|
244
324
|
@media (max-width: 700px) { .receipt-section { grid-template-columns: 1fr; } }
|
|
245
|
-
.kv-panel {
|
|
246
|
-
border: 1px solid var(--ink-hair);
|
|
247
|
-
}
|
|
325
|
+
.kv-panel { border: 1px solid var(--ink-hair); }
|
|
248
326
|
.kv-panel .panel-head {
|
|
249
|
-
border-bottom: 1px solid var(--ink-hair);
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
font-weight: 700;
|
|
253
|
-
letter-spacing: 0.08em;
|
|
254
|
-
text-transform: uppercase;
|
|
255
|
-
color: var(--ink-dim);
|
|
256
|
-
display: flex;
|
|
257
|
-
justify-content: space-between;
|
|
327
|
+
border-bottom: 1px solid var(--ink-hair); padding: 8px 16px;
|
|
328
|
+
font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
|
|
329
|
+
color: var(--ink-dim); display: flex; justify-content: space-between;
|
|
258
330
|
}
|
|
259
331
|
.kv-panel table { width: 100%; border-collapse: collapse; }
|
|
260
332
|
.kv-panel td {
|
|
261
|
-
padding: 7px 16px;
|
|
262
|
-
font-size: 12px;
|
|
263
|
-
border-bottom: 1px solid var(--ink-hair);
|
|
264
|
-
vertical-align: top;
|
|
333
|
+
padding: 7px 16px; font-size: 12px; border-bottom: 1px solid var(--ink-hair); vertical-align: top;
|
|
265
334
|
}
|
|
266
335
|
.kv-panel td:first-child { color: var(--ink-dim); width: 40%; white-space: nowrap; }
|
|
267
336
|
.kv-panel td:last-child { color: var(--ink); font-weight: 500; }
|
|
268
337
|
.kv-panel tr:last-child td { border-bottom: 0; }
|
|
269
|
-
|
|
270
|
-
/* ── providers strip ── */
|
|
271
|
-
.providers {
|
|
272
|
-
display: flex; flex-wrap: wrap; gap: 8px;
|
|
273
|
-
}
|
|
338
|
+
.providers { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
274
339
|
.chip {
|
|
275
|
-
font-size: 10px;
|
|
276
|
-
|
|
277
|
-
letter-spacing: 0.06em;
|
|
278
|
-
text-transform: uppercase;
|
|
279
|
-
padding: 3px 8px;
|
|
280
|
-
border: 1px solid var(--ink-hair);
|
|
281
|
-
color: var(--ink-dim);
|
|
282
|
-
white-space: nowrap;
|
|
340
|
+
font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
|
|
341
|
+
padding: 3px 8px; border: 1px solid var(--ink-hair); color: var(--ink-dim); white-space: nowrap;
|
|
283
342
|
}
|
|
284
343
|
.chip.green { border-color: var(--green); color: var(--green); }
|
|
285
|
-
|
|
286
|
-
/* ── architecture diagram ── */
|
|
287
344
|
.arch {
|
|
288
|
-
background: var(--surface, rgba(11,11,9,0.04));
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
font-size: 12px;
|
|
292
|
-
line-height: 1.7;
|
|
293
|
-
white-space: pre;
|
|
294
|
-
overflow-x: auto;
|
|
295
|
-
font-family: var(--ff-mono);
|
|
296
|
-
color: var(--ink);
|
|
345
|
+
background: var(--surface, rgba(11,11,9,0.04)); border: 1px solid var(--ink-hair);
|
|
346
|
+
padding: 20px; font-size: 12px; line-height: 1.7; white-space: pre; overflow-x: auto;
|
|
347
|
+
font-family: var(--ff-mono); color: var(--ink);
|
|
297
348
|
}
|
|
298
349
|
.arch .hl { color: var(--green); font-weight: 700; }
|
|
299
350
|
|
|
300
|
-
/* ── live app
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
background: var(--paper);
|
|
351
|
+
/* ── live app panel ── */
|
|
352
|
+
#page-app {
|
|
353
|
+
overflow: hidden;
|
|
304
354
|
}
|
|
305
|
-
.app-section-head {
|
|
306
|
-
padding: 0 2ch;
|
|
307
|
-
height: 40px;
|
|
308
|
-
background: var(--paper);
|
|
309
|
-
border-bottom: 1px solid var(--ink-hair);
|
|
310
|
-
display: flex;
|
|
311
|
-
align-items: center;
|
|
312
|
-
gap: 2ch;
|
|
313
|
-
font-size: 11px;
|
|
314
|
-
font-weight: 700;
|
|
315
|
-
letter-spacing: 0.08em;
|
|
316
|
-
text-transform: uppercase;
|
|
317
|
-
color: var(--ink-dim);
|
|
318
|
-
}
|
|
319
|
-
.app-section-head .live-dot {
|
|
320
|
-
width: 6px; height: 6px;
|
|
321
|
-
border-radius: 50%;
|
|
322
|
-
background: var(--green);
|
|
323
|
-
display: inline-block;
|
|
324
|
-
animation: pulse 2s infinite;
|
|
325
|
-
}
|
|
326
|
-
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
|
|
327
|
-
|
|
328
|
-
/* ── live app embed ── */
|
|
329
355
|
.app-embed {
|
|
330
356
|
display: flex;
|
|
331
357
|
flex-direction: column;
|
|
332
|
-
|
|
333
|
-
|
|
358
|
+
flex: 1;
|
|
359
|
+
overflow: hidden;
|
|
334
360
|
}
|
|
335
361
|
</style>
|
|
336
362
|
<script>
|
|
@@ -352,194 +378,274 @@
|
|
|
352
378
|
</head>
|
|
353
379
|
<body>
|
|
354
380
|
|
|
355
|
-
<!-- ── LANDING ── -->
|
|
356
381
|
<div class="land">
|
|
357
382
|
|
|
358
|
-
<!-- topbar -->
|
|
383
|
+
<!-- topbar with top-level tabs -->
|
|
359
384
|
<header class="land-bar">
|
|
360
|
-
<span class="brand">
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
385
|
+
<span class="brand">247420<span class="slash">/</span>thebird</span>
|
|
386
|
+
<div class="brand-tabs">
|
|
387
|
+
<button class="brand-tab active" id="ptab-overview" onclick="switchPage('overview')">overview</button>
|
|
388
|
+
<button class="brand-tab" id="ptab-app" onclick="switchPage('app')">live app <span class="live-dot"></span></button>
|
|
389
|
+
</div>
|
|
390
|
+
<div class="bar-right">
|
|
366
391
|
<a href="https://github.com/AnEntrypoint/thebird">source ↗</a>
|
|
367
|
-
|
|
368
|
-
|
|
392
|
+
<button class="theme-btn" onclick="toggleTheme()" title="Toggle theme">◐</button>
|
|
393
|
+
</div>
|
|
369
394
|
</header>
|
|
370
395
|
|
|
371
|
-
<!--
|
|
372
|
-
<
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
<
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<
|
|
387
|
-
|
|
396
|
+
<!-- OVERVIEW PAGE -->
|
|
397
|
+
<div class="page-panel active" id="page-overview">
|
|
398
|
+
|
|
399
|
+
<!-- hero -->
|
|
400
|
+
<section class="hero">
|
|
401
|
+
<div class="hero-eyebrow">247420 / anentrypoint</div>
|
|
402
|
+
<h1>agentic os.<br>zero <em>server.</em></h1>
|
|
403
|
+
<p class="lede">
|
|
404
|
+
thebird is a browser-native operating system — agentic AI chat, a full POSIX terminal,
|
|
405
|
+
live preview, and an IndexedDB filesystem. loads in the browser like a webpage.
|
|
406
|
+
no Docker. no server. no install.
|
|
407
|
+
</p>
|
|
408
|
+
<p class="motivation">
|
|
409
|
+
<strong>why?</strong> safe agentic orchestration needs an isolated runtime —
|
|
410
|
+
traditionally that means a Docker container per user. thebird replaces that with the browser:
|
|
411
|
+
<strong>POSIX + Node.js in V8</strong>, sandboxed by design, spun up in milliseconds,
|
|
412
|
+
accessible anywhere. your api key never leaves localStorage.
|
|
413
|
+
</p>
|
|
414
|
+
<div class="hero-actions">
|
|
415
|
+
<button class="btn-primary" onclick="switchPage('app')">try it live →</button>
|
|
416
|
+
<a href="https://github.com/AnEntrypoint/thebird" class="btn-ghost">source ↗</a>
|
|
417
|
+
<div class="install-strip" id="install-strip">
|
|
418
|
+
<span class="prompt">$</span>
|
|
419
|
+
<span class="cmd">npm install acptoapi</span>
|
|
420
|
+
<button class="copy-btn" onclick="copyInstall()">copy</button>
|
|
421
|
+
</div>
|
|
388
422
|
</div>
|
|
389
|
-
</
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
423
|
+
</section>
|
|
424
|
+
|
|
425
|
+
<!-- serverless callout strip -->
|
|
426
|
+
<div class="serverless-strip">
|
|
427
|
+
<div class="inner">
|
|
428
|
+
<div class="sl-item">
|
|
429
|
+
<em class="sl-icon">⚡</em>
|
|
430
|
+
<div class="sl-label">zero cold start</div>
|
|
431
|
+
<div class="sl-desc">browser loads in ms. no container spin-up. no provisioning.</div>
|
|
432
|
+
</div>
|
|
433
|
+
<div class="sl-item">
|
|
434
|
+
<em class="sl-icon">🔒</em>
|
|
435
|
+
<div class="sl-label">sandboxed by default</div>
|
|
436
|
+
<div class="sl-desc">V8 isolate + browser security model. no root access. no escape.</div>
|
|
437
|
+
</div>
|
|
438
|
+
<div class="sl-item">
|
|
439
|
+
<em class="sl-icon">🌐</em>
|
|
440
|
+
<div class="sl-label">works anywhere</div>
|
|
441
|
+
<div class="sl-desc">any device with a browser. phones, tablets, locked-down corp laptops.</div>
|
|
442
|
+
</div>
|
|
443
|
+
<div class="sl-item">
|
|
444
|
+
<em class="sl-icon">🗄️</em>
|
|
445
|
+
<div class="sl-label">persistent storage</div>
|
|
446
|
+
<div class="sl-desc">IndexedDB filesystem survives reloads. install npm packages. write files.</div>
|
|
447
|
+
</div>
|
|
448
|
+
<div class="sl-item">
|
|
449
|
+
<em class="sl-icon">🔑</em>
|
|
450
|
+
<div class="sl-label">api key stays local</div>
|
|
451
|
+
<div class="sl-desc">stored in localStorage. never sent to any proxy. zero server trust required.</div>
|
|
452
|
+
</div>
|
|
404
453
|
</div>
|
|
454
|
+
</div>
|
|
405
455
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
<
|
|
411
|
-
|
|
412
|
-
|
|
456
|
+
<!-- motivation -->
|
|
457
|
+
<section class="motivation-section">
|
|
458
|
+
<div class="section-head">why browser-native?</div>
|
|
459
|
+
<div class="mot-grid">
|
|
460
|
+
<div class="mot-block">
|
|
461
|
+
<h3>the docker problem</h3>
|
|
462
|
+
<p>every agentic AI workflow needs a safe place to run code — read files, execute shell commands, install dependencies. the default answer is Docker: one container per user, per session. that means servers, provisioning, cost, latency, and ops burden. thebird eliminates all of it by moving the sandbox into the browser tab.</p>
|
|
463
|
+
</div>
|
|
464
|
+
<div class="mot-block">
|
|
465
|
+
<h3>browser as runtime</h3>
|
|
466
|
+
<p>V8 already implements a full JavaScript engine. xstate v5 provides a state machine for orchestrating shell execution. IndexedDB gives you a persistent filesystem. a service worker intercepts HTTP to serve files from that filesystem. thebird wires these four primitives together into a real POSIX shell + Node REPL, no native dependencies required.</p>
|
|
467
|
+
</div>
|
|
468
|
+
<div class="mot-block">
|
|
469
|
+
<h3>fast agentic loop</h3>
|
|
470
|
+
<p>when an AI agent wants to run a command, it calls <code>run_command</code>. the shell executes it in V8, returns stdout. no HTTP round trip to a backend, no container spawn, no SSH. latency is measured in microseconds. the agent can iterate 100x faster than any remote sandbox.</p>
|
|
471
|
+
</div>
|
|
472
|
+
<div class="mot-block">
|
|
473
|
+
<h3>acptoapi: any provider</h3>
|
|
474
|
+
<p>the AI routing layer (acptoapi) translates any Anthropic-format message to Gemini, OpenAI, or 20+ providers in-browser. no proxy server needed. the format registry × provider registry design means adding a new provider is one file. circuit breaker, retry, stream guards, capability stripping — all in-browser.</p>
|
|
475
|
+
</div>
|
|
413
476
|
</div>
|
|
477
|
+
</section>
|
|
478
|
+
|
|
479
|
+
<!-- features grid -->
|
|
480
|
+
<section class="features" id="features">
|
|
481
|
+
<div class="section-head">capabilities</div>
|
|
482
|
+
<div class="feat-grid">
|
|
483
|
+
|
|
484
|
+
<div class="feat-card">
|
|
485
|
+
<em class="glyph">⬡</em>
|
|
486
|
+
<h3>agentic chat</h3>
|
|
487
|
+
<p>tool-calling AI chat running entirely in-browser via acptoapi. tools: read_file, write_file, list_files (idb-backed), run_command, read_terminal, send_to_terminal. no proxy server required. streaming events.</p>
|
|
488
|
+
<span class="feat-tag">in-browser</span>
|
|
489
|
+
<span class="feat-tag">tool-use</span>
|
|
490
|
+
<span class="feat-tag">streaming</span>
|
|
491
|
+
</div>
|
|
414
492
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
493
|
+
<div class="feat-card">
|
|
494
|
+
<em class="glyph">▶</em>
|
|
495
|
+
<h3>posix terminal</h3>
|
|
496
|
+
<p>browser-native shell (xstate v5 state machine, V8 eval) backed by IndexedDB. built-ins: ls, cat, cd, mkdir, rm, cp, mv, echo, env, export, node, npm install, grep, sed, sort, uniq, tr. node repl with persistent scope + require() from idb node_modules.</p>
|
|
497
|
+
<span class="feat-tag">posix</span>
|
|
498
|
+
<span class="feat-tag">node repl</span>
|
|
499
|
+
<span class="feat-tag">idb-fs</span>
|
|
500
|
+
</div>
|
|
422
501
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
502
|
+
<div class="feat-card">
|
|
503
|
+
<em class="glyph">◈</em>
|
|
504
|
+
<h3>live preview</h3>
|
|
505
|
+
<p>iframe served by a service worker reading files from IndexedDB at /preview/*. hot-reloads 5s after any file write. build and run html/css/js apps entirely in-browser, no webpack, no vite, no bundler needed.</p>
|
|
506
|
+
<span class="feat-tag">service worker</span>
|
|
507
|
+
<span class="feat-tag">hot reload</span>
|
|
508
|
+
<span class="feat-tag">serverless</span>
|
|
509
|
+
</div>
|
|
431
510
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
511
|
+
<div class="feat-card">
|
|
512
|
+
<em class="glyph">⟐</em>
|
|
513
|
+
<h3>acptoapi bridge</h3>
|
|
514
|
+
<p>translate any Anthropic-format message to Gemini, OpenAI-compat, or any configured provider. format registry × provider registry. xstate streaming actor. flowie transform pipelines. normalized event stream.</p>
|
|
515
|
+
<span class="feat-tag">multi-provider</span>
|
|
516
|
+
<span class="feat-tag">streaming</span>
|
|
517
|
+
<span class="feat-tag">zero-config</span>
|
|
518
|
+
</div>
|
|
439
519
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
520
|
+
<div class="feat-card">
|
|
521
|
+
<em class="glyph">◧</em>
|
|
522
|
+
<h3>idb filesystem</h3>
|
|
523
|
+
<p>persistent IndexedDB-backed virtual filesystem. files survive page reloads. npm packages install and require() from idb node_modules. http.createServer polyfill for running express-style servers entirely in-browser.</p>
|
|
524
|
+
<span class="feat-tag">persistent</span>
|
|
525
|
+
<span class="feat-tag">node compat</span>
|
|
526
|
+
<span class="feat-tag">serverless</span>
|
|
527
|
+
</div>
|
|
448
528
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
529
|
+
<div class="feat-card">
|
|
530
|
+
<em class="glyph">⊞</em>
|
|
531
|
+
<h3>sdk clients</h3>
|
|
532
|
+
<p>drop-in Anthropic and OpenAI SDK clients via acptoapi. <code>new Anthropic({provider,apiKey})</code> backed by any provider. works in-browser and in node. circuit breaker, capability stripping, stream guards included.</p>
|
|
533
|
+
<span class="feat-tag">anthropic sdk</span>
|
|
534
|
+
<span class="feat-tag">openai sdk</span>
|
|
535
|
+
<span class="feat-tag">browser</span>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<div class="feat-card">
|
|
539
|
+
<em class="glyph">⚙</em>
|
|
540
|
+
<h3>http proxy server</h3>
|
|
541
|
+
<p>server.js exposes a local Anthropic-compatible proxy at localhost:3456 backed by acptoapi. route /v1/messages to any provider. /debug/state endpoint for live circuit-breaker and provider state inspection.</p>
|
|
542
|
+
<span class="feat-tag">local proxy</span>
|
|
543
|
+
<span class="feat-tag">observability</span>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<div class="feat-card">
|
|
547
|
+
<em class="glyph">◎</em>
|
|
548
|
+
<h3>multi-provider routing</h3>
|
|
549
|
+
<p>createRouter() picks provider+model per request based on taskType and token count. circuit breaker per provider, capability registry, retry with backoff. gemini, openai-compat, 20+ providers. failover automatic.</p>
|
|
550
|
+
<span class="feat-tag">routing</span>
|
|
551
|
+
<span class="feat-tag">circuit breaker</span>
|
|
552
|
+
<span class="feat-tag">retry</span>
|
|
553
|
+
</div>
|
|
456
554
|
|
|
457
|
-
<div class="feat-card">
|
|
458
|
-
<em class="glyph">◎</em>
|
|
459
|
-
<h3>multi-provider routing</h3>
|
|
460
|
-
<p>createRouter() picks provider+model per request based on taskType, token count vs longContextThreshold. circuit breaker, capability registry, stream guards, retry with backoff. gemini, openai-compat, 20+ providers.</p>
|
|
461
|
-
<span class="feat-tag">routing</span>
|
|
462
|
-
<span class="feat-tag">circuit breaker</span>
|
|
463
|
-
<span class="feat-tag">retry</span>
|
|
464
555
|
</div>
|
|
556
|
+
</section>
|
|
465
557
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
</table>
|
|
497
|
-
</div>
|
|
558
|
+
<!-- receipt + architecture -->
|
|
559
|
+
<section class="receipt-section">
|
|
560
|
+
<div class="kv-panel">
|
|
561
|
+
<div class="panel-head"><span>project receipt</span><span style="color:var(--green)">● live</span></div>
|
|
562
|
+
<table>
|
|
563
|
+
<tr><td>status</td><td>live · ships continuously</td></tr>
|
|
564
|
+
<tr><td>license</td><td>MIT</td></tr>
|
|
565
|
+
<tr><td>runtime</td><td>browser (V8) + node ≥18</td></tr>
|
|
566
|
+
<tr><td>server required</td><td><strong style="color:var(--green)">none</strong> — 100% serverless</td></tr>
|
|
567
|
+
<tr><td>deps</td><td>acptoapi, @google/genai, xstate, flowie</td></tr>
|
|
568
|
+
<tr><td>frontend</td><td>no framework · vanilla js + webjsx</td></tr>
|
|
569
|
+
<tr><td>storage</td><td>IndexedDB (no server, no cloud)</td></tr>
|
|
570
|
+
<tr><td>api key</td><td>localStorage only · never leaves browser</td></tr>
|
|
571
|
+
<tr><td>providers</td>
|
|
572
|
+
<td>
|
|
573
|
+
<div class="providers">
|
|
574
|
+
<span class="chip green">gemini</span>
|
|
575
|
+
<span class="chip">openai</span>
|
|
576
|
+
<span class="chip">together</span>
|
|
577
|
+
<span class="chip">fireworks</span>
|
|
578
|
+
<span class="chip">perplexity</span>
|
|
579
|
+
<span class="chip">groq</span>
|
|
580
|
+
<span class="chip">ollama</span>
|
|
581
|
+
<span class="chip">openrouter</span>
|
|
582
|
+
<span class="chip">20+ more</span>
|
|
583
|
+
</div>
|
|
584
|
+
</td>
|
|
585
|
+
</tr>
|
|
586
|
+
</table>
|
|
587
|
+
</div>
|
|
498
588
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
├── docs/ browser UI
|
|
504
|
-
│ ├── chat agentic
|
|
505
|
-
│ ├── terminal posix shell · idb
|
|
589
|
+
<div>
|
|
590
|
+
<div class="kv-panel" style="margin-bottom:24px">
|
|
591
|
+
<div class="panel-head"><span>architecture</span></div>
|
|
592
|
+
<pre class="arch" style="border:0;margin:0"><span class="hl">thebird</span> (browser web os)
|
|
593
|
+
├── docs/ browser UI (GH Pages)
|
|
594
|
+
│ ├── chat agentic AI · tool calling
|
|
595
|
+
│ ├── terminal posix shell · node repl · idb-fs
|
|
506
596
|
│ └── preview service worker · hot reload
|
|
507
|
-
├── serve.js static file server
|
|
597
|
+
├── serve.js local static file server
|
|
508
598
|
└── server.js anthropic-compat proxy
|
|
509
599
|
|
|
510
|
-
<span class="hl">acptoapi</span> (npm
|
|
600
|
+
<span class="hl">acptoapi</span> (npm — runs in browser + node)
|
|
511
601
|
├── lib/formats/ anthropic · openai · gemini · acp
|
|
512
602
|
├── lib/providers/ gemini · openai-compat · router
|
|
513
|
-
├── lib/machine.js xstate streaming actor
|
|
514
|
-
├── lib/translate any → any
|
|
515
|
-
└── lib/sdk/ Anthropic + OpenAI clients
|
|
516
|
-
|
|
603
|
+
├── lib/machine.js xstate v5 streaming actor
|
|
604
|
+
├── lib/translate any format → any provider
|
|
605
|
+
└── lib/sdk/ Anthropic + OpenAI SDK clients
|
|
606
|
+
|
|
607
|
+
<span class="hl">browser sandbox</span> (replaces Docker)
|
|
608
|
+
├── V8 javascript execution engine
|
|
609
|
+
├── xstate v5 shell state machine orchestrator
|
|
610
|
+
├── IndexedDB persistent virtual filesystem
|
|
611
|
+
└── ServiceWorker HTTP server from IDB files</pre>
|
|
612
|
+
</div>
|
|
517
613
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
614
|
+
<div class="kv-panel">
|
|
615
|
+
<div class="panel-head"><span>quick start</span></div>
|
|
616
|
+
<table>
|
|
617
|
+
<tr><td>open in browser</td><td><a href="https://anentrypoint.github.io/thebird/" style="color:var(--green)">anentrypoint.github.io/thebird ↗</a></td></tr>
|
|
618
|
+
<tr><td>local dev</td><td><code>node serve.js</code> → localhost:8080</td></tr>
|
|
619
|
+
<tr><td>proxy server</td><td><code>node server.js</code> → localhost:3456</td></tr>
|
|
620
|
+
<tr><td>acptoapi sdk</td><td><code>npm install acptoapi</code></td></tr>
|
|
621
|
+
<tr><td>source</td><td><a href="https://github.com/AnEntrypoint/thebird" style="color:var(--green)">github.com/AnEntrypoint/thebird ↗</a></td></tr>
|
|
622
|
+
</table>
|
|
623
|
+
</div>
|
|
526
624
|
</div>
|
|
527
|
-
</
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
<span
|
|
534
|
-
<span
|
|
535
|
-
<
|
|
536
|
-
|
|
537
|
-
|
|
625
|
+
</section>
|
|
626
|
+
|
|
627
|
+
<!-- footer -->
|
|
628
|
+
<footer style="border-top:1px solid var(--ink-hair);padding:16px 2ch;display:flex;gap:2ch;align-items:center;font-size:11px;color:var(--ink-dim);margin-top:auto">
|
|
629
|
+
<span>247420 / anentrypoint</span>
|
|
630
|
+
<span style="color:var(--ink-hair)">·</span>
|
|
631
|
+
<span>thebird</span>
|
|
632
|
+
<span style="color:var(--ink-hair)">·</span>
|
|
633
|
+
<a href="https://github.com/AnEntrypoint/thebird" style="color:var(--ink-dim);text-decoration:none">source ↗</a>
|
|
634
|
+
<span style="color:var(--ink-hair)">·</span>
|
|
635
|
+
<a href="https://github.com/AnEntrypoint/acptoapi" style="color:var(--ink-dim);text-decoration:none">acptoapi ↗</a>
|
|
636
|
+
<span style="margin-left:auto;color:var(--green)">probably emerging 🌀</span>
|
|
637
|
+
</footer>
|
|
638
|
+
|
|
639
|
+
</div><!-- /page-overview -->
|
|
640
|
+
|
|
641
|
+
<!-- LIVE APP PAGE -->
|
|
642
|
+
<div class="page-panel" id="page-app">
|
|
538
643
|
<div class="app-embed">
|
|
539
644
|
<div class="tui-tabs">
|
|
540
645
|
<button id="tab-chat" class="tui-tab active" onclick="switchTab('chat')">chat</button>
|
|
541
646
|
<button id="tab-term" class="tui-tab" onclick="switchTab('term')">terminal</button>
|
|
542
647
|
<button id="tab-preview" class="tui-tab" onclick="switchTab('preview')">preview</button>
|
|
648
|
+
<span style="margin-left:auto;padding:0 2ch;font-size:10px;color:var(--ink-dim);line-height:36px">api key in localStorage · no server · <a href="https://github.com/AnEntrypoint/thebird" style="color:var(--ink-dim)">source ↗</a></span>
|
|
543
649
|
</div>
|
|
544
650
|
<div id="pane-chat" style="flex:1;overflow:hidden;display:flex;flex-direction:column">
|
|
545
651
|
<bird-chat></bird-chat>
|
|
@@ -554,23 +660,27 @@
|
|
|
554
660
|
<iframe id="preview-frame" style="width:100%;flex:1;border:0;background:var(--paper)" sandbox="allow-scripts allow-same-origin allow-forms"></iframe>
|
|
555
661
|
</div>
|
|
556
662
|
</div>
|
|
557
|
-
</
|
|
558
|
-
|
|
559
|
-
<!-- footer -->
|
|
560
|
-
<footer style="border-top:1px solid var(--ink-hair);padding:16px 2ch;display:flex;gap:2ch;align-items:center;font-size:11px;color:var(--ink-dim)">
|
|
561
|
-
<span>247420 / anentrypoint</span>
|
|
562
|
-
<span style="color:var(--ink-hair)">·</span>
|
|
563
|
-
<span>thebird</span>
|
|
564
|
-
<span style="color:var(--ink-hair)">·</span>
|
|
565
|
-
<a href="https://github.com/AnEntrypoint/thebird" style="color:var(--ink-dim);text-decoration:none">source ↗</a>
|
|
566
|
-
<span style="color:var(--ink-hair)">·</span>
|
|
567
|
-
<a href="https://github.com/AnEntrypoint/acptoapi" style="color:var(--ink-dim);text-decoration:none">acptoapi ↗</a>
|
|
568
|
-
<span style="margin-left:auto;color:var(--green)">probably emerging 🌀</span>
|
|
569
|
-
</footer>
|
|
663
|
+
</div><!-- /page-app -->
|
|
570
664
|
|
|
571
665
|
</div><!-- /land -->
|
|
572
666
|
|
|
573
667
|
<script>
|
|
668
|
+
function switchPage(p) {
|
|
669
|
+
['overview', 'app'].forEach(id => {
|
|
670
|
+
document.getElementById('page-' + id).classList.toggle('active', id === p);
|
|
671
|
+
document.getElementById('ptab-' + id).classList.toggle('active', id === p);
|
|
672
|
+
});
|
|
673
|
+
if (p === 'app') {
|
|
674
|
+
document.getElementById('page-app').style.height = (window.innerHeight - 40) + 'px';
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
window.addEventListener('resize', () => {
|
|
679
|
+
if (document.getElementById('page-app').classList.contains('active')) {
|
|
680
|
+
document.getElementById('page-app').style.height = (window.innerHeight - 40) + 'px';
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
|
|
574
684
|
function copyInstall() {
|
|
575
685
|
navigator.clipboard?.writeText('npm install acptoapi');
|
|
576
686
|
const btn = document.querySelector('#install-strip .copy-btn');
|
package/package.json
CHANGED