@bongos/core 1.19.93 → 1.19.94

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.
@@ -1,634 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Cloud Bongos — building software is laying down a beat</title>
7
- <!-- Launch-safety metadata (task 1002746). Until the front door moves to the
8
- landing page (see docs/design/front-door-and-hub-direction.md), THIS page is
9
- what answers cloudbongos.com/ — so it is what search results and link
10
- previews describe. It shipped with an internal-sounding title, no
11
- description, and no social tags; the whole host is noindex today, so none of
12
- it bit yet, but all of it bites the moment the pre-launch lock comes off.
13
- The absolute cloudbongos.com URLs match the domain space.js already pins. -->
14
- <meta name="description" content="An open-source, AI-first build platform. AI agents claim tasks and write the code; you set the scope and the gates. Explore the live projects, or start your own." />
15
- <link rel="canonical" href="https://cloudbongos.com/" />
16
- <meta property="og:type" content="website" />
17
- <meta property="og:site_name" content="Cloud Bongos" />
18
- <meta property="og:url" content="https://cloudbongos.com/" />
19
- <meta property="og:title" content="Cloud Bongos — building software is laying down a beat" />
20
- <meta property="og:description" content="An open-source, AI-first build platform. AI agents claim tasks and write the code; you set the scope and the gates." />
21
- <meta property="og:image" content="https://cloudbongos.com/buddha.png" />
22
- <meta name="twitter:card" content="summary_large_image" />
23
- <meta name="twitter:title" content="Cloud Bongos — building software is laying down a beat" />
24
- <meta name="twitter:description" content="An open-source, AI-first build platform. AI agents claim tasks and write the code; you set the scope and the gates." />
25
- <meta name="twitter:image" content="https://cloudbongos.com/buddha.png" />
26
- <link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet" />
27
- <link rel="stylesheet" href="space.css" />
28
- <!-- Anti-flash (task 1985 follow-up): on a direct-orbs load — a vanity door
29
- redirected here with ?entered=1 — hide the type-"bongos" entry from the
30
- FIRST paint so it never flashes before space.js opens the orbs. This runs in
31
- <head>, before <body> paints; space.js's openSpaceDirect() then clears
32
- .direct-orbs so ESC-back-to-entry still works. Keep the door test below in
33
- sync with brandForHost() in space.js. -->
34
- <script>
35
- (function () {
36
- try {
37
- var h = (location.hostname || '').toLowerCase();
38
- var isDoor = /(^|\.)(claude|gemini)bongos\.com$/.test(h);
39
- var entered = /[?&]entered=1(?:&|$)/.test(location.search || '');
40
- if (entered && !isDoor) document.documentElement.className += ' direct-orbs';
41
- } catch (e) {}
42
- })();
43
- </script>
44
- <style>html.direct-orbs #entry { display: none !important; }</style>
45
- <style>
46
- *{ box-sizing:border-box; margin:0; padding:0; }
47
- html,body{ height:100%; }
48
- body{ font-family:"Baloo 2",system-ui,sans-serif; overflow:hidden; background:#0a0820; cursor:default; }
49
- .stage{ position:fixed; inset:0; overflow:hidden; }
50
-
51
- /* ---- moving sky-temple world ---- */
52
- .world{ position:absolute; inset:0; z-index:0; }
53
- .scene{ position:absolute; inset:-8%; width:116%; height:116%;
54
- background:url("../world/assets/plates/scene-establishing.png") center/cover no-repeat;
55
- animation:kenburns 40s ease-in-out infinite alternate; will-change:transform; }
56
- /* zoomed further out than the original 1.06→1.16 so more of the sky-temple reads */
57
- @keyframes kenburns{ 0%{transform:scale(1.0) translate(0,0)} 100%{transform:scale(1.08) translate(-2%,-3%)} }
58
- .clouds-near{ position:absolute; left:-30%; right:-30%; bottom:-4%; height:46%;
59
- background:url("../world/assets/plates/plate-clouds-near.png") center/contain repeat-x;
60
- opacity:.85; animation:driftL 32s linear infinite; }
61
- /* a thin drifting wisp (not the bubbly cloud-puff — off-theme vs the painterly sky) */
62
- .puff{ position:absolute; top:15%; left:-24%; width:42%; aspect-ratio:1000/450;
63
- background:url("../world/assets/plates/plate-clouds-near.png") center/contain no-repeat;
64
- opacity:.7; animation:driftR 46s linear infinite; }
65
- @keyframes driftL{ from{transform:translateX(0)} to{transform:translateX(-26%)} }
66
- @keyframes driftR{ from{transform:translateX(0)} to{transform:translateX(180%)} }
67
- .scene.plunge{ animation:plunge 1.5s ease-in forwards; }
68
- @keyframes plunge{ to{ transform:scale(1.55) translateY(8%); } }
69
-
70
- /* ---- descent: clouds rushing up + a warm flash ---- */
71
- .crush-wrap{ position:absolute; inset:0; z-index:3; pointer-events:none; }
72
- .crush{ position:absolute; bottom:-34%; aspect-ratio:720/401;
73
- background:url("../world/assets/clouds/cloud-puff.png") center/contain no-repeat; opacity:0; }
74
- .stage.falling .crush{ animation:crush var(--d) cubic-bezier(.4,.05,.3,1) var(--del) forwards; }
75
- @keyframes crush{ 0%{transform:translateY(0) scale(var(--s));opacity:0} 14%{opacity:.96} 84%{opacity:.85}
76
- 100%{transform:translateY(-135vh) scale(var(--s));opacity:0} }
77
- .flash{ position:absolute; inset:0; z-index:4; pointer-events:none; opacity:0;
78
- background:radial-gradient(40% 35% at 50% 52%, rgba(255,240,205,.95), rgba(249,115,22,.35) 45%, transparent 72%); }
79
- .stage.falling .flash{ animation:flash .7s ease-out forwards; }
80
- @keyframes flash{ 0%{opacity:0;transform:scale(.5)} 28%{opacity:.92} 100%{opacity:0;transform:scale(1.7)} }
81
-
82
- /* ---- scenes (transforms here are on the SCENE containers — they compose with
83
- the per-pane drag transform on the children, so the two never fight) ---- */
84
- .scene-l{ position:absolute; inset:0; z-index:2; display:flex; flex-direction:column;
85
- align-items:center; justify-content:center; gap:20px; padding:30px; }
86
- .gate{ transition:opacity .5s ease, transform .8s cubic-bezier(.4,0,.7,1), filter .6s ease; }
87
- .stage.falling .gate{ opacity:0; transform:scale(1.28); filter:blur(9px); pointer-events:none; }
88
- .land{ opacity:0; transform:translateY(54px) scale(.97); pointer-events:none;
89
- transition:opacity .9s ease .25s, transform 1s cubic-bezier(.2,.8,.2,1) .25s; }
90
- .stage.arrived .land{ opacity:1; transform:none; pointer-events:auto; }
91
-
92
- /* the wordmark IS the logo (task 1893): no circle coin, one consistent brand
93
- gold across every appearance of "{Brand} Bongos". */
94
- .mark{ font-weight:700; font-size:21px; letter-spacing:.4px; color:var(--cb-gold);
95
- display:flex; align-items:center; gap:10px; text-shadow:0 2px 12px rgba(40,20,6,.6); }
96
- .mark b{ color:var(--cb-gold); }
97
-
98
- .el{ position:relative; }
99
- .el .lens{ position:absolute; border-radius:16px; }
100
- .el img{ position:relative; display:block; width:100%; height:100%; object-fit:contain;
101
- filter:drop-shadow(0 13px 28px rgba(30,16,4,.36)); pointer-events:none;
102
- -webkit-user-drag:none; user-drag:none; }
103
-
104
- .terminal{ width:464px; height:96px; }
105
- .terminal .lens{ inset:16% 3%; -webkit-backdrop-filter:blur(2px) saturate(1.2);
106
- backdrop-filter:blur(2px) saturate(1.2) url(#disp-bar); }
107
- .cli{ position:absolute; inset:0; display:flex; align-items:center; padding:0 30px; z-index:2;
108
- font-family:"Fira Code",monospace; font-size:27px; font-weight:500; letter-spacing:1px; user-select:none; }
109
- .cli.shake{ animation:shake .32s; }
110
- @keyframes shake{ 0%,100%{transform:translateX(0)} 20%{transform:translateX(-7px)} 40%{transform:translateX(6px)}
111
- 60%{transform:translateX(-4px)} 80%{transform:translateX(3px)} }
112
- .cli .p{ color:#fb923c; margin-right:14px; text-shadow:0 0 10px rgba(251,146,60,.5); }
113
- .cli .c{ color:#f0e6d6; margin-right:.42em; }
114
- .cli .typed b{ display:inline-block; color:#ffd98a; text-shadow:0 0 14px rgba(246,201,118,.6);
115
- animation:pop .22s cubic-bezier(.2,1.4,.4,1); }
116
- @keyframes pop{ 0%{transform:translateY(5px) scale(.4);opacity:0} 100%{transform:translateY(0) scale(1);opacity:1} }
117
- .caret{ display:inline-block; width:12px; height:28px; background:#ffd98a; margin-left:3px; vertical-align:-4px;
118
- box-shadow:0 0 12px rgba(246,201,118,.8); animation:blink 1.05s steps(1) infinite; }
119
- @keyframes blink{ 0%,50%{opacity:1} 50.01%,100%{opacity:0} }
120
-
121
- .hint{ font-family:"Fira Code",monospace; font-size:13px; letter-spacing:.4px; color:#f3ead9; height:18px;
122
- text-shadow:0 1px 8px rgba(30,16,4,.8); }
123
- .hint.flash-x{ color:#ffb0bd; }
124
- .hint b{ color:#ffd98a; }
125
-
126
- /* enter key — reveal uses opacity + blur ONLY (no transform), so the drag owns
127
- transform once 'bongos' is typed. */
128
- .enter{ width:150px; height:128px; opacity:0; filter:blur(6px); pointer-events:none;
129
- transition:opacity .6s cubic-bezier(.2,.9,.25,1.1), filter .6s ease; }
130
- .enter.lit{ opacity:1; filter:blur(0); pointer-events:auto; }
131
- .enter .lens{ inset:13% 16%; -webkit-backdrop-filter:blur(1.5px) saturate(1.3);
132
- backdrop-filter:blur(1.5px) saturate(1.3) url(#disp-key); box-shadow:0 0 42px rgba(249,115,22,.55); border-radius:18px; }
133
-
134
- .search{ width:464px; height:62px; }
135
- .search .lens{ inset:15% 2%; -webkit-backdrop-filter:blur(2px) saturate(1.2);
136
- backdrop-filter:blur(2px) saturate(1.2) url(#disp-bar); }
137
- .agent{ font-family:"Fira Code",monospace; font-size:12.5px; color:#4a3f37; display:flex; align-items:center; gap:7px;
138
- text-shadow:0 1px 5px rgba(255,250,240,.7); }
139
- .agent .dot{ width:7px; height:7px; border-radius:50%; background:#16a34a; box-shadow:0 0 9px #16a34a;
140
- animation:pulse 1.6s ease-in-out infinite; }
141
- @keyframes pulse{ 0%,100%{opacity:.45} 50%{opacity:1} }
142
- .tiles{ display:flex; gap:18px; }
143
- .tile{ width:136px; height:126px; }
144
- .tile .lens{ inset:12% 11% 20% 11%; -webkit-backdrop-filter:blur(2.5px) saturate(1.2);
145
- backdrop-filter:blur(2.5px) saturate(1.2) url(#disp-flat); }
146
-
147
- .replay{ position:absolute; right:16px; bottom:14px; z-index:5; display:flex; align-items:center; gap:6px;
148
- font-family:"Fira Code",monospace; font-size:11px; color:#fff; background:rgba(30,18,8,.4);
149
- border:1px solid rgba(255,255,255,.25); border-radius:20px; padding:7px 14px; cursor:pointer;
150
- opacity:0; pointer-events:none; transition:opacity .4s; }
151
- .replay.show{ opacity:1; pointer-events:auto; }
152
-
153
- /* draggable panes — the task-1534 elastic-tether physics, re-applied to the
154
- drawn sprites (task 1541). Each pane keeps its laid-out spot as "home"; we
155
- only ever apply transform:translate, so the responsive layout is untouched. */
156
- .drag{ cursor:grab; touch-action:none; -webkit-user-select:none; user-select:none; will-change:transform; }
157
- .drag.grabbing{ cursor:grabbing; }
158
- </style>
159
- </head>
160
- <body class="view-entry">
161
- <!-- No-JS fallback (task 1002746). The sky is entirely JS-built: without it this
162
- page rendered blank, so a non-executing crawler or a JS-off visitor saw
163
- nothing at all on the domain's front door. Inline styles because every
164
- stylesheet rule here is scoped to a body view-class this block must ignore.
165
- Keep the copy in sync with the meta description above. -->
166
- <noscript>
167
- <div style="position:fixed;inset:0;z-index:9999;overflow:auto;background:#0b1020;color:#e9edf7;font-family:'Baloo 2',system-ui,sans-serif;padding:2rem;">
168
- <div style="max-width:34rem;margin:12vh auto 0;">
169
- <h1 style="font-size:1.9rem;line-height:1.2;margin:0 0 .75rem;">Cloud&nbsp;Bongos</h1>
170
- <p style="font-size:1.05rem;line-height:1.6;margin:0 0 1rem;color:#c3cbe0;">
171
- An open-source, AI-first build platform. AI agents claim tasks and write the
172
- code; you set the scope and the gates.
173
- </p>
174
- <p style="font-size:1.05rem;line-height:1.6;margin:0 0 1.5rem;color:#c3cbe0;">
175
- The interactive map of live projects needs JavaScript, but everything below
176
- works without it.
177
- </p>
178
- <p style="margin:0 0 .6rem;"><a href="/projects" style="color:#ffd98a;">Your projects</a> — find and manage the projects you own.</p>
179
- <p style="margin:0 0 .6rem;"><a href="/create" style="color:#ffd98a;">Start a project</a> — stand up a new one.</p>
180
- <p style="margin:0;"><a href="https://builders.cloudbongos.com" style="color:#ffd98a;">Builders' Hall</a> — where the work happens.</p>
181
- </div>
182
- </div>
183
- </noscript>
184
- <!-- ═══ dive cinematic (task 1729): clicking the Cloud Bongos orb flies you
185
- from the space constellation, down through the clouds, into the Cloud
186
- Bongos world (the download page). space.js plays #descent on the self-orb
187
- click, then hands off to view-download under the flash. Skippable
188
- (click/key/scroll); reduced motion drops straight into the world. The
189
- island + clouds reuse the world's own art (../world/assets). -->
190
- <div id="descent" aria-hidden="true">
191
- <div class="descent-stars far" id="descent-stars-far"></div>
192
- <div class="descent-stars near" id="descent-stars-near"></div>
193
- <div class="descent-glow"></div>
194
- <div class="descent-deck"></div>
195
- <div class="descent-island"></div>
196
- <div class="descent-clouds">
197
- <span class="ic" style="--x:2%; --w:44%; --s:1.25; --d:1.2s; --del:0.85s"></span>
198
- <span class="ic" style="--x:56%; --w:50%; --s:1.5; --d:1.15s; --del:0.97s"></span>
199
- <span class="ic" style="--x:28%; --w:34%; --s:.95; --d:1.3s; --del:1.08s"></span>
200
- <span class="ic" style="--x:-10%; --w:38%; --s:1.1; --d:1.25s; --del:1.18s"></span>
201
- <span class="ic" style="--x:72%; --w:26%; --s:.7; --d:1.35s; --del:1.28s"></span>
202
- <span class="ic" style="--x:18%; --w:42%; --s:1.35; --d:1.2s; --del:1.40s"></span>
203
- </div>
204
- <div class="descent-flash"></div>
205
- </div>
206
-
207
- <!-- ═══ space: the entry gate + the pannable sky of projects (tasks 1721, 1722) ═══
208
- Every visit lands on the entry gate (type "bongos", in space); entering
209
- reveals the circles. Click the Cloud Bongos orb to dive to the download
210
- scene below; ESC rises back here. -->
211
- <div id="space">
212
- <div class="stars" id="starfield" aria-hidden="true"></div>
213
- <!-- space-time sheet (task): a faint blueprint grid that dimples under each
214
- orb's gravity (mass ∝ size³, same law as the physics). Drawn in space.js
215
- behind the orbs so they rest ON the warped sheet. -->
216
- <canvas id="space-grid" aria-hidden="true"></canvas>
217
- <div id="space-canvas"></div>
218
-
219
- <!-- entry gate: type "bongos" to enter, set in space (task 1722). Reuses the
220
- terminal/enter sprites + CSS; driven by space.js, not the inline gate script. -->
221
- <div class="scene-l entry" id="entry">
222
- <div class="el terminal">
223
- <div class="lens"></div>
224
- <img src="sprites/terminal-blank.png" alt="" />
225
- <div class="cli" id="cli">
226
- <span class="p">&gt;</span><span class="c">cloud</span><span class="typed" id="typed"></span><span class="caret" id="caret"></span>
227
- </div>
228
- </div>
229
- <div class="hint" id="hint">type <b>bongos</b> to enter</div>
230
- <div class="el enter" id="enter"><div class="lens"></div><img src="sprites/enter.png" alt="enter" /></div>
231
- </div>
232
-
233
- <!-- self-typing logo (task 1902): idles as the brand wordmark, then swaps the
234
- lead word "Cloud" for lowercase platforms (claude, gemini, …) and re-types
235
- "bongos" each time — like a terminal. Driven by mountLogoTerminal() in
236
- space.js; .mk-lead is set by JS so applyBrand door-branding is handled
237
- there (BRAND.display) at rest. -->
238
- <div class="space-mark"><span class="mk-lead" id="mk-lead">cloud</span><b class="mk-tail" id="mk-tail">&nbsp;bongos</b><span class="mk-caret" id="mk-caret"></span></div>
239
- <div class="space-help">
240
- <span><kbd>drag</kbd>pan</span><span class="sep">·</span>
241
- <span><kbd>scroll</kbd>zoom</span><span class="sep">·</span>
242
- <span><kbd>shift</kbd>search what's in view</span><span class="sep">·</span>
243
- <span><kbd>click sky</kbd>add a project</span>
244
- </div>
245
- <!-- the door to the owner's manage surface (task 1002696): /projects was
246
- orphaned in navigation — nothing linked in. Space view only. -->
247
- <a class="space-projects" href="/projects">your projects</a>
248
- <!-- idle "create a project" ghost orb (task 1896): a faint dashed circle that
249
- trails the cursor over EMPTY sky, lightly nudging the click-to-create
250
- gesture. space.js positions it + toggles .show. -->
251
- <div id="ghost-orb" aria-hidden="true"><span class="ghost-plus">+</span><span class="ghost-label">click to create a project</span></div>
252
- <!-- minimap (task 1897): a live overview of the whole orb cluster in the
253
- bottom-right, with a viewport rectangle for the current pan/zoom. Click
254
- or drag it to recentre the view. Drawn in space.js drawMinimap(). -->
255
- <div id="minimap" aria-hidden="true"><canvas id="minimap-canvas"></canvas></div>
256
- <!-- space whale (task 1898): flies from the Cloud Bongos orb to a project when
257
- it updates, and back again when a project pushes a module. Positioned +
258
- animated in screen space by space.js so it tracks the live orb motion. -->
259
- <div id="whale" aria-hidden="true"><img id="whale-img" src="" alt="" decoding="async" /></div>
260
- </div>
261
-
262
- <!-- top-left ESC button (task 1913): return to the orbs from download/detail -->
263
- <button id="esc-btn" type="button" aria-label="Back to the orbs"><kbd>esc</kbd> back</button>
264
-
265
- <!-- ═══ view toggle: circle sky ⇄ table directory (task 1731) ═══
266
- Shown only while browsing (view-space / view-table). Circles stay the
267
- default landing; Table is the scannable/searchable/sortable alternative. -->
268
- <div id="view-toggle" role="tablist" aria-label="Project view">
269
- <button class="vt-btn active" id="vt-circles" role="tab" aria-selected="true" type="button" title="Circle sky view">
270
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="7" cy="8.5" r="3"></circle><circle cx="16.5" cy="7" r="2"></circle><circle cx="14.5" cy="16" r="3.6"></circle></svg>Sky
271
- </button>
272
- <button class="vt-btn" id="vt-table" role="tab" aria-selected="false" type="button" title="Table view">
273
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><line x1="4" y1="7" x2="20" y2="7"></line><line x1="4" y1="12" x2="20" y2="12"></line><line x1="4" y1="17" x2="20" y2="17"></line></svg>Table
274
- </button>
275
- </div>
276
-
277
- <!-- ═══ top-right cluster: enter builders' hall + GitHub identity chip ═══
278
- Present on every post-entry view (orbs, table, download, detail) so the
279
- way in and the account are always in the same corner.
280
- • #cb-hall — the door into a builders' hall, where a visitor can request
281
- access. PROJECT-AWARE (task 1002676, setHallDoor in space.js): on a
282
- project's detail view it points at THAT project's own hall
283
- (<origin>/builders — each instance canonicalizes to builders.<apex>);
284
- on the directory views it points at the platform hall below. The href
285
- here is only the pre-JS/default target.
286
- • #cb-account (task 2094) — the one-stop GitHub login: signed out shows
287
- "Sign in with GitHub"; signed in shows the avatar + login with a quiet
288
- sign-out. Filled by space.js from /api/bongos/me. -->
289
- <div id="cb-topright">
290
- <a id="cb-hall" class="cb-hall" href="https://builders.cloudbongos.com">
291
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 1.8 14 5.2H2L8 1.8Z"/><path d="M3.4 5.6v6.4M6 5.6v6.4M10 5.6v6.4M12.6 5.6v6.4"/><path d="M2 12.4h12M1.4 14.2h13.2"/></svg>
292
- <span class="cb-hall__label">Enter builders' hall</span>
293
- </a>
294
- <div id="cb-account" aria-live="polite"></div>
295
- </div>
296
-
297
- <!-- ═══ table directory: every project, searchable + sortable (task 1731) ═══
298
- A scannable alternative to the circle sky. Rows are built from the same
299
- PROJECTS data in space.js; clicking a row dives in exactly like an orb. -->
300
- <div id="table-view">
301
- <div class="tv-head">
302
- <div class="tv-mark">Cloud <b>Bongos</b><span class="tv-sub">project directory</span></div>
303
- <div class="tv-search">
304
- <svg class="mag" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><line x1="16.5" y1="16.5" x2="21" y2="21"></line></svg>
305
- <input id="tv-search-input" type="text" autocomplete="off" spellcheck="false" placeholder="Search projects by name, tag, description…" aria-label="Search projects" />
306
- <span class="tv-count" id="tv-count"></span>
307
- </div>
308
- <button class="tv-add" id="tv-create" type="button"><span class="plus" aria-hidden="true">+</span> Open a project</button>
309
- </div>
310
- <div class="tv-scroll">
311
- <table>
312
- <thead>
313
- <tr>
314
- <th class="sortable" data-sort="name" scope="col">Project<span class="sort-ind" aria-hidden="true"></span></th>
315
- <th class="sortable num" data-sort="builders" scope="col">Builders<span class="sort-ind" aria-hidden="true"></span></th>
316
- <th class="sortable col-type" data-sort="type" scope="col">Type<span class="sort-ind" aria-hidden="true"></span></th>
317
- <th class="col-tags" scope="col">Tags</th>
318
- <th class="col-act" scope="col"><span class="cc-sr">Open</span></th>
319
- </tr>
320
- </thead>
321
- <tbody id="tv-body"></tbody>
322
- </table>
323
- </div>
324
- <div class="tv-foot"><kbd>esc</kbd> back to entry · click a row to open · click a column to sort</div>
325
- </div>
326
-
327
- <!-- hover card, dive flash, search overlay, create panel, non-self detail -->
328
- <div id="hovercard" aria-hidden="true"></div>
329
- <div class="dive-flash" id="dive-flash" aria-hidden="true"></div>
330
-
331
- <div id="searchbar" role="search">
332
- <div class="bar">
333
- <svg class="mag" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><line x1="16.5" y1="16.5" x2="21" y2="21"></line></svg>
334
- <input id="search-input" type="text" autocomplete="off" spellcheck="false" placeholder="Search projects in view…" aria-label="Search projects in view" />
335
- <span class="esc"><kbd>esc</kbd></span>
336
- </div>
337
- <div class="ctx"><span class="dot"></span>searching <b id="search-ctx-count">0</b> projects in view<span class="ai-soon"> · a Claude agent will answer here (coming soon)</span></div>
338
- </div>
339
-
340
- <div class="overlay-scrim" id="create-scrim">
341
- <div id="createpanel" role="dialog" aria-modal="true" aria-label="Open a Cloud Bongos project">
342
- <h3>Open a project</h3>
343
- <p class="sub">Drop a new circle into the sky. Give your Cloud Bongos project a name to get started.</p>
344
- <label for="create-name">Project name</label>
345
- <input id="create-name" type="text" autocomplete="off" placeholder="Northwind Notes" />
346
- <div class="row">
347
- <button class="btn-ghost" id="create-cancel" type="button">Cancel</button>
348
- <button class="btn-go" id="create-go" type="button">Create project</button>
349
- </div>
350
- <div class="note" id="create-auth-note">Places your circle in the sky, then continues into the build wizard — you'll sign in with GitHub so the project is yours from the first beat.</div>
351
- </div>
352
- </div>
353
-
354
- <!-- signed-out create gate (task 2094): a signed-out visitor who tries to
355
- create a project is encouraged to sign in with GitHub first, instead of
356
- being handed the name field and bounced through sign-in later. -->
357
- <div class="overlay-scrim" id="signin-scrim">
358
- <div id="signinpanel" role="dialog" aria-modal="true" aria-label="Sign in to create a project">
359
- <h3>Sign in to create a project</h3>
360
- <p class="sub">Every Cloud Bongos project belongs to you from the first beat — its own repository, its own hall of AI builders. Sign in with GitHub, then name your project.</p>
361
- <a class="signin-go" id="signin-go" href="#">
362
- <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.6 7.6 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
363
- Sign in with GitHub
364
- </a>
365
- <button class="signin-dismiss" id="signin-dismiss" type="button">Not now</button>
366
- </div>
367
- </div>
368
-
369
- <!-- handoff toast (task 2087): shown for a beat while the named orb settles,
370
- before the page hands over to the /create build wizard -->
371
- <div id="handoff-toast" role="status" aria-live="polite"></div>
372
-
373
- <div id="detail" aria-hidden="true">
374
- <div class="card"></div>
375
- <div class="esc-hint"><kbd>esc</kbd> back to space</div>
376
- </div>
377
-
378
- <div class="stage" id="stage" tabindex="0">
379
- <div class="world">
380
- <div class="scene" id="scene"></div>
381
- <div class="clouds-near"></div>
382
- <div class="puff"></div>
383
- </div>
384
-
385
- <div class="crush-wrap" aria-hidden="true">
386
- <div class="crush" style="--d:1.5s;--del:0s;--s:1.3; left:6%; width:40%"></div>
387
- <div class="crush" style="--d:1.45s;--del:.12s;--s:1.5; right:2%; width:46%"></div>
388
- <div class="crush" style="--d:1.7s;--del:.26s;--s:.9; left:30%; width:30%"></div>
389
- <div class="crush" style="--d:1.85s;--del:.4s;--s:.7; left:60%; width:24%"></div>
390
- <div class="crush" style="--d:1.6s;--del:.18s;--s:1.1; left:-6%; width:34%"></div>
391
- <div class="crush" style="--d:1.9s;--del:.5s;--s:.65; left:78%; width:22%"></div>
392
- </div>
393
- <div class="flash" aria-hidden="true"></div>
394
-
395
- <!-- the download page (task 1722): reached DIRECTLY by clicking the Cloud
396
- Bongos orb — no type-"bongos" gate here anymore (that moved to entry). -->
397
- <div class="scene-l land" id="land">
398
- <!-- the Bongo Buddha idle (ADR 0088 sprite), floating above the search bar
399
- on a thin painterly cloud (frames injected + cycled by space.js). Not
400
- draggable — it carries no .el/.mark class, so the stage drag script
401
- leaves it alone. -->
402
- <div class="buddha" id="buddha" aria-hidden="true">
403
- <div class="buddha-glow"></div>
404
- <img class="buddha-cloud" src="../world/assets/plates/plate-clouds-near.png" alt="" draggable="false" />
405
- <div class="buddha-fig" id="buddha-fig"></div>
406
- </div>
407
- <div class="mark">Cloud <b>Bongos</b></div>
408
- <div class="el search"><div class="lens"></div><img src="sprites/search.png" alt="search" /></div>
409
- <div class="agent"><span class="dot"></span>a Claude agent is handling your search</div>
410
- <div class="tiles">
411
- <div class="el tile"><div class="lens"></div><img src="sprites/tile.png" alt="download" /></div>
412
- <div class="el tile"><div class="lens"></div><img src="sprites/tile.png" alt="download" /></div>
413
- <div class="el tile"><div class="lens"></div><img src="sprites/tile.png" alt="download" /></div>
414
- </div>
415
- </div>
416
- </div>
417
-
418
- <svg width="0" height="0" style="position:absolute" aria-hidden="true">
419
- <defs>
420
- <filter id="disp-bar" x="-15%" y="-15%" width="130%" height="130%" color-interpolation-filters="sRGB">
421
- <feImage href="dispmaps/bar.png" preserveAspectRatio="none" width="100%" height="100%" result="m" />
422
- <feDisplacementMap in="SourceGraphic" in2="m" scale="48" xChannelSelector="R" yChannelSelector="G" />
423
- </filter>
424
- <filter id="disp-key" x="-15%" y="-15%" width="130%" height="130%" color-interpolation-filters="sRGB">
425
- <feImage href="dispmaps/key.png" preserveAspectRatio="none" width="100%" height="100%" result="m" />
426
- <feDisplacementMap in="SourceGraphic" in2="m" scale="64" xChannelSelector="R" yChannelSelector="G" />
427
- </filter>
428
- <filter id="disp-flat" x="-15%" y="-15%" width="130%" height="130%" color-interpolation-filters="sRGB">
429
- <feImage href="dispmaps/flat.png" preserveAspectRatio="none" width="100%" height="100%" result="m" />
430
- <feDisplacementMap in="SourceGraphic" in2="m" scale="26" xChannelSelector="R" yChannelSelector="G" />
431
- </filter>
432
- </defs>
433
- </svg>
434
-
435
- <script>
436
- (function(){
437
- /* ═══ download page (task 1722) ═══
438
- The search + download-tiles "land" scene, over the temple world. Reached
439
- DIRECTLY by clicking the Cloud Bongos orb (space.js) — the type-"bongos"
440
- gate moved to the entry (in space), so there is no gate here. This script
441
- now owns only the download reveal + the elastic-tether drag for its
442
- sprites. */
443
- var stage=document.getElementById('stage'), scene=document.getElementById('scene');
444
-
445
- function showDownload(){ stage.classList.add('arrived'); setTimeout(function(){ measure(); }, 60); }
446
- function hideDownload(){ stage.classList.remove('arrived','falling'); scene.classList.remove('plunge'); }
447
- document.addEventListener('cb:show-download', showDownload);
448
- document.addEventListener('cb:hide-download', hideDownload);
449
-
450
- /* ═══ 1534: elastic-tether drag, re-applied to the drawn sprite panes ═══
451
- TUNING — harder to pull free → THRESHOLD↑ · slower return → DRIFT_MAXV↓ ·
452
- wider wander → WMAG↑ / TURN↓ · bouncier snap-back → DAMP↑. A tap (move <
453
- DEADZONE) is NOT a drag — it falls through to type/dive, so the panes stay
454
- both draggable AND clickable. */
455
- var THRESHOLD=160, HOVER=3000, RETETHER=46, DEADZONE=5;
456
- var DRIFT_MAXV=0.60, WMAG=0.060, TURN=0.22, K_DRIFT=0.0006, WCALM=150, DRIFT_DAMP=0.94;
457
- var BOB_X=1.5, BOB_Y=1.3, BOB_EASE=0.12;
458
- var K_HOME=0.022, STIFF=140, K_PULL=0.09, DAMP=0.867;
459
- var K_FREE=0.34, DAMP_FREE=0.60;
460
- var FRICTION=0.88, MAXV=70, DT=1000/60;
461
-
462
- var marks = Array.prototype.slice.call(document.querySelectorAll('.stage .mark'));
463
- var panes = Array.prototype.slice.call(document.querySelectorAll('.stage .el'));
464
- var els = marks.concat(panes);
465
- var tilesEl = document.querySelector('.stage .tiles');
466
-
467
- var items = els.map(function(el,i){
468
- el.classList.add('drag');
469
- return { el:el, isTile:el.classList.contains('tile'),
470
- hx:0,hy:0,hw:0,hh:0, ox:0,oy:0, pox:0,poy:0, vx:0,vy:0, tx:0,ty:0,
471
- free:false, dragging:false, pending:false, moved:false, drifting:false, active:false,
472
- restAt:null, driftStart:0, wTheta:Math.random()*6.283, bob:1,
473
- phase:i*1.7, fjit:(i%5)*0.09-0.18, lastTX:0, lastTY:0, grabDX:0, grabDY:0, sx:0, sy:0 };
474
- });
475
-
476
- var W=innerWidth, H=innerHeight, zTop=10, tilesActive=0;
477
-
478
- function measure(){
479
- W=innerWidth; H=innerHeight;
480
- items.forEach(function(it){
481
- var r=it.el.getBoundingClientRect();
482
- it.hx = r.left + r.width/2 - it.lastTX;
483
- it.hy = r.top + r.height/2 - it.lastTY;
484
- it.hw = r.width/2; it.hh = r.height/2;
485
- });
486
- }
487
- measure();
488
- if(document.fonts && document.fonts.ready){ document.fonts.ready.then(measure); }
489
- addEventListener('resize', measure);
490
- /* the two scenes translate/scale as you dive + replay; re-measure home once a
491
- scene settles so a freshly-revealed pane drags from the right spot. */
492
- ['land'].forEach(function(id){
493
- var sc=document.getElementById(id);
494
- if(sc) sc.addEventListener('transitionend', function(e){ if(e.propertyName==='transform') measure(); });
495
- });
496
-
497
- function activate(it){
498
- if(!it.active){ it.active=true; if(it.isTile) tilesActive++; }
499
- it.el.style.zIndex = String(++zTop);
500
- if(it.isTile && tilesEl) tilesEl.style.zIndex = String(++zTop);
501
- }
502
- function settle(it){
503
- if(it.active){ it.active=false;
504
- if(it.isTile){ tilesActive=Math.max(0,tilesActive-1); if(tilesActive===0 && tilesEl) tilesEl.style.zIndex=''; } }
505
- it.el.style.zIndex='';
506
- }
507
-
508
- items.forEach(function(it){
509
- it.el.addEventListener('dragstart', function(e){ e.preventDefault(); });
510
- it.el.addEventListener('pointerdown', function(e){
511
- it.pending=true; it.moved=false; it.dragging=false;
512
- it.sx=e.clientX; it.sy=e.clientY;
513
- it.drifting=false; it.restAt=null; it.driftStart=0;
514
- it.grabDX = e.clientX - (it.hx+it.ox); it.grabDY = e.clientY - (it.hy+it.oy);
515
- it.tx=it.ox; it.ty=it.oy;
516
- try{ it.el.setPointerCapture(e.pointerId); }catch(_){}
517
- /* NOTE: no preventDefault here — a tap must still focus the terminal (to
518
- type) and fire the enter "dive". Drag only engages past DEADZONE. */
519
- });
520
- it.el.addEventListener('pointermove', function(e){
521
- if(!it.pending) return;
522
- if(!it.dragging){
523
- if(Math.hypot(e.clientX-it.sx, e.clientY-it.sy) < DEADZONE) return;
524
- it.dragging=true; it.moved=true; it.wTheta=Math.random()*6.283;
525
- it.el.classList.add('grabbing'); activate(it);
526
- }
527
- e.preventDefault();
528
- it.tx = (e.clientX-it.grabDX) - it.hx;
529
- it.ty = (e.clientY-it.grabDY) - it.hy;
530
- });
531
- function endDrag(e){
532
- if(!it.pending) return;
533
- var wasDrag=it.dragging;
534
- it.pending=false; it.dragging=false; it.el.classList.remove('grabbing');
535
- try{ it.el.releasePointerCapture(e.pointerId); }catch(_){}
536
- if(wasDrag){
537
- if(it.free && Math.hypot(it.ox,it.oy)<RETETHER){ it.free=false; it.drifting=false; it.restAt=null; }
538
- }
539
- /* a tap (no drag) on a download pane has no action yet */
540
- }
541
- it.el.addEventListener('pointerup', endDrag);
542
- it.el.addEventListener('pointercancel', endDrag);
543
- it.el.addEventListener('dblclick', function(){ it.free=false; it.drifting=false; it.restAt=null; });
544
- });
545
-
546
- function clampOffset(it){
547
- var minx=(it.hw+4)-it.hx, maxx=(W-it.hw-4)-it.hx;
548
- if(maxx>minx){ if(it.ox<minx)it.ox=minx; else if(it.ox>maxx)it.ox=maxx; }
549
- var miny=(it.hh+4)-it.hy, maxy=(H-it.hh-4)-it.hy;
550
- if(maxy>miny){ if(it.oy<miny)it.oy=miny; else if(it.oy>maxy)it.oy=maxy; }
551
- }
552
-
553
- var simNow=performance.now(), acc=0, last=simNow;
554
-
555
- function step(){
556
- simNow+=DT;
557
- for(var k=0;k<items.length;k++){
558
- var it=items[k]; it.pox=it.ox; it.poy=it.oy;
559
- var d, stiff, ax, ay;
560
- if(it.dragging){
561
- if(!it.free){
562
- d=Math.hypot(it.ox,it.oy)||0.0001; stiff=Math.min(4,1+d/STIFF);
563
- ax=(-it.ox)*K_HOME*stiff+(it.tx-it.ox)*K_PULL;
564
- ay=(-it.oy)*K_HOME*stiff+(it.ty-it.oy)*K_PULL;
565
- it.vx=(it.vx+ax)*DAMP; it.vy=(it.vy+ay)*DAMP;
566
- } else {
567
- ax=(it.tx-it.ox)*K_FREE; ay=(it.ty-it.oy)*K_FREE;
568
- it.vx=(it.vx+ax)*DAMP_FREE; it.vy=(it.vy+ay)*DAMP_FREE;
569
- }
570
- if(it.vx>MAXV)it.vx=MAXV; else if(it.vx<-MAXV)it.vx=-MAXV;
571
- if(it.vy>MAXV)it.vy=MAXV; else if(it.vy<-MAXV)it.vy=-MAXV;
572
- } else if(!it.free){
573
- d=Math.hypot(it.ox,it.oy)||0.0001; stiff=Math.min(4,1+d/STIFF);
574
- ax=(-it.ox)*K_HOME*stiff; ay=(-it.oy)*K_HOME*stiff;
575
- it.vx=(it.vx+ax)*DAMP; it.vy=(it.vy+ay)*DAMP;
576
- if(it.vx>MAXV)it.vx=MAXV; else if(it.vx<-MAXV)it.vx=-MAXV;
577
- if(it.vy>MAXV)it.vy=MAXV; else if(it.vy<-MAXV)it.vy=-MAXV;
578
- } else if(!it.drifting){
579
- it.vx*=FRICTION; it.vy*=FRICTION; it.driftStart=0;
580
- if(Math.hypot(it.vx,it.vy)<0.05){ it.vx=0; it.vy=0; if(it.restAt===null) it.restAt=simNow; }
581
- else it.restAt=null;
582
- if(it.restAt!==null && simNow-it.restAt>=HOVER) it.drifting=true;
583
- } else {
584
- if(!it.driftStart) it.driftStart=simNow;
585
- d=Math.hypot(it.ox,it.oy)||0.0001;
586
- it.wTheta += (Math.random()-0.5)*TURN;
587
- var wScale=Math.min(1,d/WCALM);
588
- var elapsed=simNow-it.driftStart;
589
- var homeGain=K_DRIFT*(1+Math.max(0,(elapsed-12000)/10000)*5);
590
- ax=(-it.ox)*homeGain + Math.cos(it.wTheta)*WMAG*wScale;
591
- ay=(-it.oy)*homeGain + Math.sin(it.wTheta)*WMAG*wScale;
592
- it.vx=(it.vx+ax)*DRIFT_DAMP; it.vy=(it.vy+ay)*DRIFT_DAMP;
593
- var sp=Math.hypot(it.vx,it.vy);
594
- if(sp>1e-4){ var cap=DRIFT_MAXV*Math.tanh(sp/DRIFT_MAXV), f=cap/sp; it.vx*=f; it.vy*=f; }
595
- if(d<3 && sp<0.3){ it.free=false; it.drifting=false; it.restAt=null;
596
- it.ox=0; it.oy=0; it.pox=0; it.poy=0; it.vx=0; it.vy=0; settle(it); continue; }
597
- }
598
-
599
- it.bob += ((it.dragging?0:1)-it.bob)*BOB_EASE;
600
- it.ox+=it.vx; it.oy+=it.vy;
601
- clampOffset(it);
602
-
603
- if(it.dragging && !it.free && Math.hypot(it.ox,it.oy)>THRESHOLD){ it.free=true; it.restAt=null; }
604
- if(!it.dragging && !it.free && Math.hypot(it.vx,it.vy)<0.06 && Math.hypot(it.ox,it.oy)<0.5){
605
- it.ox=0; it.oy=0; it.vx=0; it.vy=0; if(it.active) settle(it);
606
- }
607
- }
608
- }
609
-
610
- function render(alpha, now){
611
- for(var k=0;k<items.length;k++){
612
- var it=items[k];
613
- var ix=it.pox+(it.ox-it.pox)*alpha, iy=it.poy+(it.oy-it.poy)*alpha;
614
- var bx=Math.sin(now*0.0011*(1+it.fjit)+it.phase)*BOB_X*it.bob;
615
- var by=Math.cos(now*0.00094*(1+it.fjit)+it.phase*1.3)*BOB_Y*it.bob;
616
- it.lastTX=ix+bx; it.lastTY=iy+by;
617
- it.el.style.transform='translate('+it.lastTX.toFixed(2)+'px,'+it.lastTY.toFixed(2)+'px)';
618
- }
619
- }
620
-
621
- function tick(now){
622
- var ft=now-last; last=now; if(ft>250)ft=250; acc+=ft;
623
- var guard=0;
624
- while(acc>=DT && guard<10){ step(); acc-=DT; guard++; }
625
- if(guard>=10) acc=0;
626
- render(Math.max(0,Math.min(1,acc/DT)), now);
627
- requestAnimationFrame(tick);
628
- }
629
- requestAnimationFrame(tick);
630
- })();
631
- </script>
632
- <script src="space.js"></script>
633
- </body>
634
- </html>