@ibgib/space-gib 0.0.32 → 0.0.34

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.
Files changed (112) hide show
  1. package/dist/client/bootstrap.mjs +24 -51
  2. package/dist/client/chunk-25PXC4HP.mjs +9914 -0
  3. package/dist/client/chunk-RXWLL2AI.mjs +30 -0
  4. package/dist/client/css/activity-bar.css +417 -0
  5. package/dist/client/css/base.css +167 -0
  6. package/dist/client/css/components.css +218 -0
  7. package/dist/client/css/cosmic.css +557 -0
  8. package/dist/client/css/dev-tools.css +163 -0
  9. package/dist/client/css/landing.css +184 -0
  10. package/dist/client/css/layout.css +896 -0
  11. package/dist/client/css/onboarding.css +181 -0
  12. package/dist/client/css/repos.css +740 -0
  13. package/dist/client/css/variables.css +64 -0
  14. package/dist/client/index.html +202 -31
  15. package/dist/client/index.mjs +31 -31
  16. package/dist/client/script.mjs +1 -1
  17. package/dist/client/style.css +11 -1056
  18. package/dist/respec-gib.node.mjs +5 -0
  19. package/dist/server/server.mjs +6879 -3109
  20. package/package.json +6 -6
  21. package/src/client/AUTO-GENERATED-version.mts +1 -1
  22. package/src/client/cosmos/seed-cosmos-workspace.mts +69 -0
  23. package/src/client/css/activity-bar.css +417 -0
  24. package/src/client/css/base.css +167 -0
  25. package/src/client/css/components.css +218 -0
  26. package/src/client/css/cosmic.css +557 -0
  27. package/src/client/css/dev-tools.css +163 -0
  28. package/src/client/css/landing.css +184 -0
  29. package/src/client/css/layout.css +896 -0
  30. package/src/client/css/onboarding.css +181 -0
  31. package/src/client/css/repos.css +740 -0
  32. package/src/client/css/variables.css +64 -0
  33. package/src/client/dev-tools/vcs-workspace.mts +3 -3
  34. package/src/client/index.html +202 -31
  35. package/src/client/style.css +11 -1056
  36. package/src/client/ui/component/chat-view/IMPLEMENTATION.md +48 -0
  37. package/src/client/ui/component/chat-view/chat-view.css +381 -0
  38. package/src/client/ui/component/chat-view/chat-view.html +104 -0
  39. package/src/client/ui/component/chat-view/chat-view.mts +277 -0
  40. package/src/client/ui/component/chat-view/index.mts +9 -0
  41. package/src/client/ui/component/clone/IMPLEMENTATION.md +68 -0
  42. package/src/client/ui/component/clone/clone-constants.mts +16 -0
  43. package/src/client/ui/component/clone/clone-types.mts +60 -0
  44. package/src/client/ui/component/clone/clone.css +383 -0
  45. package/src/client/ui/component/clone/clone.html +89 -0
  46. package/src/client/ui/component/clone/clone.mts +620 -0
  47. package/src/client/ui/component/clone/index.mts +11 -0
  48. package/src/client/ui/component/code-editor/IMPLEMENTATION.md +89 -0
  49. package/src/client/ui/component/code-editor/code-editor.css +275 -0
  50. package/src/client/ui/component/code-editor/code-editor.html +54 -0
  51. package/src/client/ui/component/code-editor/code-editor.mts +427 -0
  52. package/src/client/ui/component/code-editor/index.mts +9 -0
  53. package/src/client/ui/component/cosmos-navigator/IMPLEMENTATION.md +31 -0
  54. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.css +864 -0
  55. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.html +97 -0
  56. package/src/client/ui/component/cosmos-navigator/cosmos-navigator.mts +1084 -0
  57. package/src/client/ui/component/cosmos-navigator/index.mts +18 -0
  58. package/src/client/ui/component/file-explorer/IMPLEMENTATION.md +42 -0
  59. package/src/client/ui/component/file-explorer/file-explorer.css +256 -0
  60. package/src/client/ui/component/file-explorer/file-explorer.html +75 -0
  61. package/src/client/ui/component/file-explorer/file-explorer.mts +346 -0
  62. package/src/client/ui/component/file-explorer/index.mts +9 -0
  63. package/src/client/ui/component/nested-chat/IMPLEMENTATION.md +18 -0
  64. package/src/client/ui/component/nested-chat/chat/IMPLEMENTATION.md +14 -0
  65. package/src/client/ui/component/nested-chat/chat/chat-constants.mts +14 -0
  66. package/src/client/ui/component/nested-chat/chat/chat-helpers.mts +66 -0
  67. package/src/client/ui/component/nested-chat/chat/chat.css +654 -0
  68. package/src/client/ui/component/nested-chat/chat/chat.html +90 -0
  69. package/src/client/ui/component/nested-chat/chat/chat.mts +646 -0
  70. package/src/client/ui/component/nested-chat/chat/index.mts +7 -0
  71. package/src/client/ui/component/nested-chat/index.mts +14 -0
  72. package/src/client/ui/component/nested-chat/nested-chat-constants.mts +12 -0
  73. package/src/client/ui/component/nested-chat/nested-chat-types.mts +53 -0
  74. package/src/client/ui/component/nested-chat/nested-chat.css +142 -0
  75. package/src/client/ui/component/nested-chat/nested-chat.html +11 -0
  76. package/src/client/ui/component/nested-chat/nested-chat.mts +393 -0
  77. package/src/client/ui/component/notes-explorer/index.mts +9 -0
  78. package/src/client/ui/component/notes-explorer/notes-explorer.css +313 -0
  79. package/src/client/ui/component/notes-explorer/notes-explorer.html +136 -0
  80. package/src/client/ui/component/notes-explorer/notes-explorer.mts +240 -0
  81. package/src/client/ui/component/notes-inspector/index.mts +9 -0
  82. package/src/client/ui/component/notes-inspector/notes-inspector.css +244 -0
  83. package/src/client/ui/component/notes-inspector/notes-inspector.html +97 -0
  84. package/src/client/ui/component/notes-inspector/notes-inspector.mts +152 -0
  85. package/src/client/ui/component/pitch/IMPLEMENTATION.md +48 -0
  86. package/src/client/ui/component/pitch/index.mts +9 -0
  87. package/src/client/ui/component/pitch/pitch.css +295 -0
  88. package/src/client/ui/component/pitch/pitch.html +97 -0
  89. package/src/client/ui/component/pitch/pitch.mts +135 -0
  90. package/src/client/ui/component/timeline/IMPLEMENTATION.md +33 -0
  91. package/src/client/ui/component/timeline/index.mts +9 -0
  92. package/src/client/ui/component/timeline/timeline.css +264 -0
  93. package/src/client/ui/component/timeline/timeline.html +23 -0
  94. package/src/client/ui/component/timeline/timeline.mts +317 -0
  95. package/src/client/ui/component/timeline-item-details/IMPLEMENTATION.md +28 -0
  96. package/src/client/ui/component/timeline-item-details/index.mts +9 -0
  97. package/src/client/ui/component/timeline-item-details/timeline-item-details.css +286 -0
  98. package/src/client/ui/component/timeline-item-details/timeline-item-details.html +64 -0
  99. package/src/client/ui/component/timeline-item-details/timeline-item-details.mts +194 -0
  100. package/src/client/ui/router/index.mts +3 -0
  101. package/src/client/ui/router/space-gib-router-helpers.mts +272 -0
  102. package/src/client/ui/router/space-gib-router-helpers.respec.mts +353 -0
  103. package/src/client/ui/router/space-gib-router-service.mts +186 -0
  104. package/src/client/ui/router/space-gib-router-types.mts +93 -0
  105. package/src/client/ui/shell/cosmic-big-bang.mts +844 -0
  106. package/src/client/ui/shell/space-gib-shell-constants.mts +7 -0
  107. package/src/client/ui/shell/space-gib-shell-service.mts +1728 -31
  108. package/src/server/server.mts +20 -1
  109. package/tsconfig.test.json +5 -1
  110. package/dist/client/chunk-AX6BROMT.mjs +0 -1
  111. package/dist/client/chunk-CIQUGV7U.mjs +0 -25
  112. package/dist/client/chunk-YPCHYDKL.mjs +0 -3102
@@ -0,0 +1,844 @@
1
+ /**
2
+ * @module cosmic-big-bang
3
+ *
4
+ * Cosmic Big Bang wireframe controller for space-gib Spaces view.
5
+ * Handles:
6
+ * - Background starry canvas with gentle drift and twinkling (bulletproof rendering).
7
+ * - "Big Bang" particle explosion / shockwave effect.
8
+ * - 1st-order node unfolding (Identity, Superspace, Agent Chat).
9
+ * - 2nd-order satellite unfolding (Code Space </>, Text Space 📝).
10
+ * - Sequential app launch:
11
+ * 1. Superspace galaxy moves to top-left header.
12
+ * 2. Activity Bar expands on left.
13
+ * 3. Code Space / Text Space buttons move to their Activity Bar slots.
14
+ * 4. Left Panel expands with new user empty-state (0 repos).
15
+ * 5. Center Panel presents new-user onboarding view.
16
+ * - Clicking the spinning galaxy in top-left (or activity bar cosmos button) returns to Cosmos view.
17
+ */
18
+
19
+ export interface AttachedSpace {
20
+ id: string;
21
+ type: 'code' | 'text';
22
+ name: string;
23
+ shortLabel: string;
24
+ icon: string;
25
+ }
26
+
27
+ export interface CosmicBigBangOptions {
28
+ onSwitchToRepos?: () => void;
29
+ onLaunchApp?: (space: AttachedSpace) => void;
30
+ onReturnToCosmos?: () => void;
31
+ }
32
+
33
+ export class CosmicBigBangController {
34
+ private canvas: HTMLCanvasElement | null = null;
35
+ private ctx: CanvasRenderingContext2D | null = null;
36
+ private animFrameId: number | null = null;
37
+ private resizeObserver: ResizeObserver | null = null;
38
+
39
+ // Stars
40
+ private stars: Array<{ x: number; y: number; r: number; alpha: number; speed: number; phase: number }> = [];
41
+
42
+ // Particles (for Big Bang explosion)
43
+ private particles: Array<{
44
+ x: number;
45
+ y: number;
46
+ vx: number;
47
+ vy: number;
48
+ r: number;
49
+ color: string;
50
+ alpha: number;
51
+ decay: number;
52
+ }> = [];
53
+
54
+ // Shockwave
55
+ private shockwaveRadius = 0;
56
+ private shockwaveAlpha = 0;
57
+
58
+ private isClusterExpanded = false;
59
+ private areSatellitesUnfolded = false;
60
+ private isIdentityDocked = false;
61
+ private isAgentDocked = false;
62
+
63
+ // Dynamic Cosmos Spaces
64
+ private attachedSpaces: AttachedSpace[] = [];
65
+ private codeSpaceCounter = 0;
66
+ private textSpaceCounter = 0;
67
+ private activeSpaceId: string | null = null;
68
+
69
+ private onSwitchToRepos?: () => void;
70
+ private onLaunchApp?: (space: AttachedSpace) => void;
71
+ private onReturnToCosmos?: () => void;
72
+
73
+ constructor(options?: CosmicBigBangOptions) {
74
+ this.onSwitchToRepos = options?.onSwitchToRepos;
75
+ this.onLaunchApp = options?.onLaunchApp;
76
+ this.onReturnToCosmos = options?.onReturnToCosmos;
77
+ }
78
+
79
+ public init(): void {
80
+ this.canvas = document.getElementById('cosmic-canvas') as HTMLCanvasElement | null;
81
+ if (!this.canvas) return;
82
+
83
+ this.ctx = this.canvas.getContext('2d');
84
+ if (!this.ctx) return;
85
+
86
+ this.resizeCanvas();
87
+
88
+ // Use ResizeObserver for bulletproof container tracking
89
+ if (typeof window !== 'undefined' && 'ResizeObserver' in window && this.canvas.parentElement) {
90
+ this.resizeObserver = new ResizeObserver(() => {
91
+ this.resizeCanvas();
92
+ });
93
+ this.resizeObserver.observe(this.canvas.parentElement);
94
+ }
95
+
96
+ window.addEventListener('resize', () => this.resizeCanvas());
97
+
98
+ this.initStars();
99
+ this.startLoop();
100
+ this.bindEvents();
101
+ }
102
+
103
+ public ensureStars(): void {
104
+ this.resizeCanvas();
105
+ if (this.stars.length === 0) {
106
+ this.initStars();
107
+ }
108
+
109
+ // Re-check after slight timeouts to ensure post-layout dimensions are caught
110
+ setTimeout(() => {
111
+ this.resizeCanvas();
112
+ if (this.stars.length === 0) {
113
+ this.initStars();
114
+ }
115
+ }, 50);
116
+
117
+ setTimeout(() => {
118
+ this.resizeCanvas();
119
+ }, 200);
120
+ }
121
+
122
+ private resizeCanvas(): void {
123
+ if (!this.canvas) return;
124
+ const parent = this.canvas.parentElement;
125
+ const parentW = parent && parent.clientWidth > 0 ? parent.clientWidth : window.innerWidth;
126
+ const parentH = parent && parent.clientHeight > 0 ? parent.clientHeight : (window.innerHeight - 100);
127
+ const targetW = Math.max(300, Math.floor(parentW));
128
+ const targetH = Math.max(300, Math.floor(parentH));
129
+
130
+ if (this.canvas.width !== targetW || this.canvas.height !== targetH) {
131
+ this.canvas.width = targetW;
132
+ this.canvas.height = targetH;
133
+ if (this.stars.length === 0) {
134
+ this.initStars();
135
+ }
136
+ }
137
+ }
138
+
139
+ private initStars(): void {
140
+ if (!this.canvas) return;
141
+ const w = Math.max(300, this.canvas.width);
142
+ const h = Math.max(300, this.canvas.height);
143
+ this.stars = [];
144
+ const count = Math.max(100, Math.min(250, Math.floor((w * h) / 3600)));
145
+ for (let i = 0; i < count; i++) {
146
+ this.stars.push({
147
+ x: Math.random() * w,
148
+ y: Math.random() * h,
149
+ r: Math.random() * 1.6 + 0.4,
150
+ alpha: Math.random() * 0.75 + 0.25,
151
+ speed: Math.random() * 0.015 + 0.005,
152
+ phase: Math.random() * Math.PI * 2,
153
+ });
154
+ }
155
+ }
156
+
157
+ private startLoop(): void {
158
+ const loop = () => {
159
+ this.render();
160
+ this.animFrameId = requestAnimationFrame(loop);
161
+ };
162
+ this.animFrameId = requestAnimationFrame(loop);
163
+ }
164
+
165
+ private render(): void {
166
+ if (!this.ctx || !this.canvas) return;
167
+ const ctx = this.ctx;
168
+ const width = this.canvas.width;
169
+ const height = this.canvas.height;
170
+
171
+ if (width < 50 || height < 50) {
172
+ this.resizeCanvas();
173
+ return;
174
+ }
175
+
176
+ // Clear with transparent void
177
+ ctx.clearRect(0, 0, width, height);
178
+
179
+ // Guarantee stars are populated
180
+ if (this.stars.length === 0) {
181
+ this.initStars();
182
+ }
183
+
184
+ // Draw Twinkling Stars (with bound wrapping)
185
+ for (const star of this.stars) {
186
+ if (star.x > width) star.x %= width;
187
+ if (star.y > height) star.y %= height;
188
+ star.phase += star.speed;
189
+ const currentAlpha = Math.max(0.15, Math.min(1, star.alpha + Math.sin(star.phase) * 0.35));
190
+ ctx.fillStyle = `rgba(255, 255, 255, ${currentAlpha})`;
191
+ ctx.beginPath();
192
+ ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
193
+ ctx.fill();
194
+ }
195
+
196
+ // Draw Shockwave
197
+ if (this.shockwaveAlpha > 0.01) {
198
+ ctx.save();
199
+ ctx.beginPath();
200
+ ctx.arc(width / 2, height / 2, this.shockwaveRadius, 0, Math.PI * 2);
201
+ ctx.strokeStyle = `rgba(120, 248, 126, ${this.shockwaveAlpha * 0.6})`;
202
+ ctx.lineWidth = 3;
203
+ ctx.stroke();
204
+
205
+ ctx.beginPath();
206
+ ctx.arc(width / 2, height / 2, Math.max(0, this.shockwaveRadius - 20), 0, Math.PI * 2);
207
+ ctx.strokeStyle = `rgba(180, 100, 255, ${this.shockwaveAlpha * 0.4})`;
208
+ ctx.lineWidth = 2;
209
+ ctx.stroke();
210
+ ctx.restore();
211
+
212
+ this.shockwaveRadius += 14;
213
+ this.shockwaveAlpha *= 0.94;
214
+ }
215
+
216
+ // Draw Particles
217
+ if (this.particles.length > 0) {
218
+ for (let i = this.particles.length - 1; i >= 0; i--) {
219
+ const p = this.particles[i];
220
+ p.x += p.vx;
221
+ p.y += p.vy;
222
+ p.vx *= 0.96;
223
+ p.vy *= 0.96;
224
+ p.alpha -= p.decay;
225
+
226
+ if (p.alpha <= 0.02) {
227
+ this.particles.splice(i, 1);
228
+ continue;
229
+ }
230
+
231
+ ctx.fillStyle = p.color.replace('ALPHA', p.alpha.toFixed(2));
232
+ ctx.beginPath();
233
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
234
+ ctx.fill();
235
+ }
236
+ }
237
+ }
238
+
239
+ private triggerBigBangExplosion(): void {
240
+ if (!this.canvas) return;
241
+ const cx = this.canvas.width / 2;
242
+ const cy = this.canvas.height / 2;
243
+
244
+ this.shockwaveRadius = 10;
245
+ this.shockwaveAlpha = 1.0;
246
+ this.particles = [];
247
+
248
+ const colors = [
249
+ 'rgba(120, 248, 126, ALPHA)', // ibgib green
250
+ 'rgba(180, 100, 255, ALPHA)', // cosmic violet
251
+ 'rgba(68, 170, 255, ALPHA)', // cyan blue
252
+ 'rgba(255, 204, 68, ALPHA)', // starlight gold
253
+ 'rgba(255, 255, 255, ALPHA)', // white
254
+ ];
255
+
256
+ const particleCount = 140;
257
+ for (let i = 0; i < particleCount; i++) {
258
+ const angle = Math.random() * Math.PI * 2;
259
+ const speed = Math.random() * 12 + 3;
260
+ const color = colors[Math.floor(Math.random() * colors.length)];
261
+ this.particles.push({
262
+ x: cx,
263
+ y: cy,
264
+ vx: Math.cos(angle) * speed,
265
+ vy: Math.sin(angle) * speed,
266
+ r: Math.random() * 3 + 1,
267
+ color,
268
+ alpha: 1.0,
269
+ decay: Math.random() * 0.025 + 0.015,
270
+ });
271
+ }
272
+ }
273
+
274
+ private bindEvents(): void {
275
+ // Singularity Button
276
+ const btnBigBang = document.getElementById('btn-big-bang');
277
+ if (btnBigBang) {
278
+ btnBigBang.addEventListener('click', () => this.initiateBigBang());
279
+ }
280
+
281
+ // Identity Node
282
+ const btnIdentity = document.getElementById('btn-cosmic-identity');
283
+ if (btnIdentity) {
284
+ btnIdentity.addEventListener('click', () => this.handleIdentityClick());
285
+ }
286
+
287
+ // Superspace (Galaxy) Node
288
+ const btnSuperspace = document.getElementById('btn-cosmic-superspace');
289
+ if (btnSuperspace) {
290
+ btnSuperspace.addEventListener('click', () => this.handleSuperspaceClick());
291
+ }
292
+
293
+ // Code Space Satellite (</>)
294
+ const btnCode = document.getElementById('btn-cosmic-code');
295
+ if (btnCode) {
296
+ btnCode.addEventListener('click', () => this.triggerAddSpace('code'));
297
+ }
298
+
299
+ // Text Space Satellite (📝)
300
+ const btnNotes = document.getElementById('btn-cosmic-notes');
301
+ if (btnNotes) {
302
+ btnNotes.addEventListener('click', () => this.triggerAddSpace('text'));
303
+ }
304
+
305
+ // Agent Chat Node (🤖)
306
+ const btnAgent = document.getElementById('btn-cosmic-agent');
307
+ if (btnAgent) {
308
+ btnAgent.addEventListener('click', () => this.handleAgentClick());
309
+ }
310
+
311
+ // Agent Footer/FAB Button
312
+ const agentFabBtn = document.getElementById('agent-fab-btn') || document.getElementById('btn-footer-agent');
313
+ if (agentFabBtn) {
314
+ agentFabBtn.addEventListener('click', () => {
315
+ alert('🤖 ibgib Agent: "Hello! I am your AI assistant across superspaces. How can I help you today?"');
316
+ });
317
+ }
318
+
319
+ // Reset Button
320
+ const btnReset = document.getElementById('btn-cosmic-reset');
321
+ if (btnReset) {
322
+ btnReset.addEventListener('click', () => this.resetToSingularity());
323
+ }
324
+
325
+ // Header Brand Galaxy (Return to Cosmos)
326
+ const brandLink = document.getElementById('space-gib-title-link');
327
+ if (brandLink) {
328
+ brandLink.addEventListener('click', (e) => {
329
+ e.preventDefault();
330
+ this.returnToCosmos();
331
+ });
332
+ }
333
+
334
+ // Activity Bar Cosmos Button (Top of Rail)
335
+ const activityCosmosBtn = document.getElementById('activity-btn-cosmos');
336
+ if (activityCosmosBtn) {
337
+ activityCosmosBtn.addEventListener('click', () => this.returnToCosmos());
338
+ }
339
+
340
+ // Onboarding Cosmos Return Buttons
341
+ const onboardingCosmosBtn = document.getElementById('btn-onboarding-cosmos');
342
+ if (onboardingCosmosBtn) {
343
+ onboardingCosmosBtn.addEventListener('click', () => this.returnToCosmos());
344
+ }
345
+ const onboardingCosmosTextBtn = document.getElementById('btn-onboarding-cosmos-text');
346
+ if (onboardingCosmosTextBtn) {
347
+ onboardingCosmosTextBtn.addEventListener('click', () => this.returnToCosmos());
348
+ }
349
+
350
+ // Side view Add Space (+) button
351
+ const btnSideAddSpace = document.getElementById('btn-side-add-space');
352
+ if (btnSideAddSpace) {
353
+ btnSideAddSpace.addEventListener('click', () => {
354
+ this.returnToCosmos();
355
+ // Automatically unfold satellites
356
+ const satellites = document.getElementById('superspace-satellites');
357
+ if (satellites) {
358
+ satellites.classList.remove('collapsed');
359
+ satellites.classList.add('unfolded');
360
+ this.areSatellitesUnfolded = true;
361
+ }
362
+ });
363
+ }
364
+
365
+ // Side view Cosmos Settings (⚙️) button
366
+ const btnSideCosmosSettings = document.getElementById('btn-side-cosmos-settings');
367
+ if (btnSideCosmosSettings) {
368
+ btnSideCosmosSettings.addEventListener('click', () => {
369
+ alert('⚙️ Cosmos Project Settings\n\nCosmos: my-cosmos\nTopology: Decentralized Multi-Space\nProtocol: ibgib v1 (Merkle DAG)');
370
+ });
371
+ }
372
+
373
+ // Empty state buttons
374
+ const btnEmptyInit = document.getElementById('btn-empty-init-space');
375
+ if (btnEmptyInit) {
376
+ btnEmptyInit.addEventListener('click', () => {
377
+ alert('🚀 Initialize Space\n\nCreating a new content-addressed DAG in browser storage.\n(Next phase implementation)');
378
+ });
379
+ }
380
+ const btnEmptyClone = document.getElementById('btn-side-clone-space');
381
+ if (btnEmptyClone) {
382
+ btnEmptyClone.addEventListener('click', () => {
383
+ alert('⬇ Clone Space\n\nConnect to remote ibgib space via address or URL.\n(Next phase implementation)');
384
+ });
385
+ }
386
+ const btnEmptyInitText = document.getElementById('btn-empty-init-text');
387
+ if (btnEmptyInitText) {
388
+ btnEmptyInitText.addEventListener('click', () => {
389
+ alert('📝 Create Note\n\nCreating a new markdown metatext node with inverted soft rel8n.\n(Next phase implementation)');
390
+ });
391
+ }
392
+ }
393
+
394
+ public initiateBigBang(): void {
395
+ const singularityContainer = document.getElementById('cosmic-singularity-container');
396
+ const cluster = document.getElementById('cosmic-cluster');
397
+ const controls = document.getElementById('cosmic-controls');
398
+
399
+ // Trigger particles & shockwave
400
+ this.triggerBigBangExplosion();
401
+
402
+ // Animate singularity collapse
403
+ if (singularityContainer) {
404
+ singularityContainer.classList.add('collapsed');
405
+ }
406
+
407
+ // Reset animation on drift wrappers so they start fresh from 0%
408
+ const nodeIdentityWrapper = document.getElementById('node-identity-wrapper');
409
+ const nodeAgentWrapper = document.getElementById('node-agent-wrapper');
410
+ if (nodeIdentityWrapper) {
411
+ nodeIdentityWrapper.classList.remove('shooting-to-top-right');
412
+ nodeIdentityWrapper.style.animation = 'none';
413
+ void nodeIdentityWrapper.offsetHeight; // trigger reflow
414
+ nodeIdentityWrapper.style.animation = '';
415
+ }
416
+ if (nodeAgentWrapper) {
417
+ nodeAgentWrapper.classList.remove('shooting-to-bottom-right');
418
+ nodeAgentWrapper.style.animation = 'none';
419
+ void nodeAgentWrapper.offsetHeight; // trigger reflow
420
+ nodeAgentWrapper.style.animation = '';
421
+ }
422
+
423
+ // Unfold 1st-order cluster after brief burst delay
424
+ setTimeout(() => {
425
+ if (cluster) {
426
+ cluster.classList.remove('hidden');
427
+ cluster.classList.add('expanded');
428
+ }
429
+ if (controls) {
430
+ controls.classList.remove('hidden');
431
+ }
432
+ this.isClusterExpanded = true;
433
+ }, 300);
434
+ }
435
+
436
+ public handleIdentityClick(): void {
437
+ if (this.isIdentityDocked) return;
438
+ const nodeIdentityWrapper = document.getElementById('node-identity-wrapper');
439
+ const identityHeaderContainer = document.getElementById('identity-header-container');
440
+
441
+ if (nodeIdentityWrapper) {
442
+ nodeIdentityWrapper.classList.add('shooting-to-top-right');
443
+ }
444
+
445
+ setTimeout(() => {
446
+ this.isIdentityDocked = true;
447
+ if (identityHeaderContainer) {
448
+ identityHeaderContainer.classList.add('identity-active-highlight');
449
+ }
450
+ }, 600);
451
+ }
452
+
453
+ public handleSuperspaceClick(): void {
454
+ const satellites = document.getElementById('superspace-satellites');
455
+ if (!satellites) { return; }
456
+
457
+ this.areSatellitesUnfolded = !this.areSatellitesUnfolded;
458
+ if (this.areSatellitesUnfolded) {
459
+ satellites.classList.remove('collapsed');
460
+ satellites.classList.add('unfolded');
461
+ } else {
462
+ satellites.classList.remove('unfolded');
463
+ satellites.classList.add('collapsed');
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Staggered sequence for dynamically adding a Space (Code Space or Text Space):
469
+ * 1. (0ms) Superspace galaxy moves towards top-left header.
470
+ * 2. (380ms) Activity Bar and Left Panel expand.
471
+ * 3. (650ms) Clicked button moves towards its new Activity Bar rail slot.
472
+ * 4. (1000ms) Space is instantiated, appended to Activity Bar, and its views are presented.
473
+ */
474
+ public triggerAddSpace(appType: 'code' | 'text'): void {
475
+ const nodeSuperspaceWrapper = document.getElementById('node-superspace-wrapper');
476
+ const headerBrandGalaxy = document.getElementById('header-brand-galaxy');
477
+ const activityBar = document.getElementById('activity-bar');
478
+ const leftPanel = document.getElementById('left-panel');
479
+ const btnCode = document.getElementById('btn-cosmic-code');
480
+ const btnNotes = document.getElementById('btn-cosmic-notes');
481
+
482
+ // Stage 1 (0ms): Superspace galaxy shoots towards top-left
483
+ if (nodeSuperspaceWrapper) {
484
+ nodeSuperspaceWrapper.classList.add('shooting-to-top-left');
485
+ }
486
+
487
+ // Stage 2 (380ms): Header galaxy activates; Activity Bar & Left Panel expand
488
+ setTimeout(() => {
489
+ if (headerBrandGalaxy) {
490
+ headerBrandGalaxy.classList.add('brand-galaxy-active');
491
+ }
492
+ if (activityBar) {
493
+ activityBar.classList.remove('collapsed');
494
+ activityBar.classList.add('expanded');
495
+ }
496
+ if (leftPanel) {
497
+ leftPanel.classList.remove('collapsed');
498
+ leftPanel.classList.add('expanded');
499
+ }
500
+ }, 380);
501
+
502
+ // Stage 3 (650ms): The clicked satellite button animates towards the rail
503
+ setTimeout(() => {
504
+ if (appType === 'code' && btnCode) {
505
+ btnCode.classList.add('shooting-to-activity-code');
506
+ } else if (appType === 'text' && btnNotes) {
507
+ btnNotes.classList.add('shooting-to-activity-text');
508
+ }
509
+ }, 650);
510
+
511
+ // Stage 4 (1000ms): Instantiate space, append to rail, and switch view
512
+ setTimeout(() => {
513
+ const space = this.createSpace(appType);
514
+ this.switchToSpace(space.id);
515
+
516
+ // Reset cluster elements for when user returns to Cosmos
517
+ if (btnCode) { btnCode.classList.remove('shooting-to-activity-code'); }
518
+ if (btnNotes) { btnNotes.classList.remove('shooting-to-activity-text'); }
519
+ const satellites = document.getElementById('superspace-satellites');
520
+ if (satellites) {
521
+ satellites.classList.remove('unfolded');
522
+ satellites.classList.add('collapsed');
523
+ this.areSatellitesUnfolded = false;
524
+ }
525
+ if (nodeSuperspaceWrapper) {
526
+ nodeSuperspaceWrapper.classList.remove('shooting-to-top-left');
527
+ }
528
+
529
+ this.onLaunchApp?.(space);
530
+ }, 1000);
531
+ }
532
+
533
+ private createSpace(type: 'code' | 'text'): AttachedSpace {
534
+ if (type === 'code') {
535
+ this.codeSpaceCounter++;
536
+ const id = `space-code-${this.codeSpaceCounter}`;
537
+ const space: AttachedSpace = {
538
+ id,
539
+ type: 'code',
540
+ name: `Code Space ${this.codeSpaceCounter}`,
541
+ shortLabel: `Code ${this.codeSpaceCounter}`,
542
+ icon: '&lt;/&gt;'
543
+ };
544
+ this.attachedSpaces.push(space);
545
+ this.appendSpaceToRail(space);
546
+ this.updateCosmosSettingsList();
547
+ return space;
548
+ } else {
549
+ this.textSpaceCounter++;
550
+ const id = `space-text-${this.textSpaceCounter}`;
551
+ const space: AttachedSpace = {
552
+ id,
553
+ type: 'text',
554
+ name: `Text Space ${this.textSpaceCounter}`,
555
+ shortLabel: `Text ${this.textSpaceCounter}`,
556
+ icon: '📝'
557
+ };
558
+ this.attachedSpaces.push(space);
559
+ this.appendSpaceToRail(space);
560
+ this.updateCosmosSettingsList();
561
+ return space;
562
+ }
563
+ }
564
+
565
+ private appendSpaceToRail(space: AttachedSpace): void {
566
+ const container = document.getElementById('activity-spaces-container');
567
+ if (!container) { return; }
568
+
569
+ const btn = document.createElement('button');
570
+ btn.className = 'activity-bar-btn activity-space-btn';
571
+ btn.id = `activity-btn-${space.id}`;
572
+ btn.type = 'button';
573
+ btn.setAttribute('data-space-id', space.id);
574
+ btn.title = space.name;
575
+ btn.innerHTML = `
576
+ <span class="activity-icon">${space.icon}</span>
577
+ <span class="activity-label">${space.shortLabel}</span>
578
+ `;
579
+ btn.addEventListener('click', () => {
580
+ this.switchToSpace(space.id);
581
+ });
582
+
583
+ container.appendChild(btn);
584
+ }
585
+
586
+ public switchToSpace(spaceId: string): void {
587
+ const space = this.attachedSpaces.find(s => s.id === spaceId);
588
+ if (!space) { return; }
589
+
590
+ this.activeSpaceId = spaceId;
591
+
592
+ // Activity Bar state
593
+ const actCosmos = document.getElementById('activity-btn-cosmos');
594
+ actCosmos?.classList.remove('active');
595
+
596
+ const allSpaceBtns = document.querySelectorAll('.activity-space-btn');
597
+ allSpaceBtns.forEach(btn => {
598
+ if (btn.getAttribute('data-space-id') === spaceId) {
599
+ btn.classList.add('active');
600
+ } else {
601
+ btn.classList.remove('active');
602
+ }
603
+ });
604
+
605
+ // Ensure panels are expanded
606
+ const activityBar = document.getElementById('activity-bar');
607
+ const leftPanel = document.getElementById('left-panel');
608
+ if (activityBar) {
609
+ activityBar.classList.remove('collapsed');
610
+ activityBar.classList.add('expanded');
611
+ }
612
+ if (leftPanel) {
613
+ leftPanel.classList.remove('collapsed');
614
+ leftPanel.classList.add('expanded');
615
+ }
616
+
617
+ // Left Panel Side Views
618
+ const leftCosmos = document.getElementById('left-panel-cosmos-view');
619
+ const leftCode = document.getElementById('left-panel-code-view');
620
+ const leftText = document.getElementById('left-panel-text-view');
621
+
622
+ if (leftCosmos) { leftCosmos.style.display = 'none'; }
623
+
624
+ if (space.type === 'code') {
625
+ if (leftCode) { leftCode.style.display = 'block'; }
626
+ if (leftText) { leftText.style.display = 'none'; }
627
+ const titleEl = document.getElementById('left-code-space-title');
628
+ if (titleEl) { titleEl.textContent = space.name; }
629
+ } else {
630
+ if (leftText) { leftText.style.display = 'block'; }
631
+ if (leftCode) { leftCode.style.display = 'none'; }
632
+ const titleEl = document.getElementById('left-text-space-title');
633
+ if (titleEl) { titleEl.textContent = space.name; }
634
+ }
635
+
636
+ // Center Views
637
+ const viewSpaces = document.getElementById('view-spaces');
638
+ const viewRepos = document.getElementById('view-repos');
639
+ const viewCodeOnboarding = document.getElementById('view-code-onboarding');
640
+ const viewTextOnboarding = document.getElementById('view-text-onboarding');
641
+
642
+ if (viewSpaces) { viewSpaces.style.display = 'none'; }
643
+ if (viewRepos) { viewRepos.style.display = 'none'; }
644
+
645
+ if (space.type === 'code') {
646
+ if (viewCodeOnboarding) { viewCodeOnboarding.style.display = 'flex'; }
647
+ if (viewTextOnboarding) { viewTextOnboarding.style.display = 'none'; }
648
+ } else {
649
+ if (viewTextOnboarding) { viewTextOnboarding.style.display = 'flex'; }
650
+ if (viewCodeOnboarding) { viewCodeOnboarding.style.display = 'none'; }
651
+ const textTitle = document.getElementById('text-onboarding-title');
652
+ if (textTitle) { textTitle.textContent = space.name; }
653
+ }
654
+ }
655
+
656
+ /**
657
+ * Injects Cosmos navigation component back into center panel,
658
+ * switches Left Panel to Cosmos Settings / Overview,
659
+ * and guarantees background stars are fully sparkling.
660
+ */
661
+ public returnToCosmos(): void {
662
+ this.activeSpaceId = null;
663
+
664
+ // Activity Bar state: Cosmos at top is active
665
+ const actCosmos = document.getElementById('activity-btn-cosmos');
666
+ actCosmos?.classList.add('active');
667
+
668
+ const allSpaceBtns = document.querySelectorAll('.activity-space-btn');
669
+ allSpaceBtns.forEach(btn => btn.classList.remove('active'));
670
+
671
+ // Left Panel: Cosmos Settings view
672
+ const leftCosmos = document.getElementById('left-panel-cosmos-view');
673
+ const leftCode = document.getElementById('left-panel-code-view');
674
+ const leftText = document.getElementById('left-panel-text-view');
675
+
676
+ if (leftCosmos) { leftCosmos.style.display = 'block'; }
677
+ if (leftCode) { leftCode.style.display = 'none'; }
678
+ if (leftText) { leftText.style.display = 'none'; }
679
+
680
+ this.updateCosmosSettingsList();
681
+
682
+ // Center Panel: Cosmos Spaces stage
683
+ const viewSpaces = document.getElementById('view-spaces');
684
+ const viewRepos = document.getElementById('view-repos');
685
+ const viewCodeOnboarding = document.getElementById('view-code-onboarding');
686
+ const viewTextOnboarding = document.getElementById('view-text-onboarding');
687
+
688
+ if (viewCodeOnboarding) { viewCodeOnboarding.style.display = 'none'; }
689
+ if (viewTextOnboarding) { viewTextOnboarding.style.display = 'none'; }
690
+ if (viewRepos) { viewRepos.style.display = 'none'; }
691
+ if (viewSpaces) { viewSpaces.style.display = 'flex'; }
692
+
693
+ // Reset header galaxy pulse
694
+ const headerBrandGalaxy = document.getElementById('header-brand-galaxy');
695
+ if (headerBrandGalaxy) {
696
+ headerBrandGalaxy.classList.remove('brand-galaxy-active');
697
+ }
698
+
699
+ // Reset stage elements if needed
700
+ const nodeSuperspaceWrapper = document.getElementById('node-superspace-wrapper');
701
+ if (nodeSuperspaceWrapper) {
702
+ nodeSuperspaceWrapper.classList.remove('shooting-to-top-left');
703
+ }
704
+
705
+ // Bulletproof stars guarantee
706
+ this.ensureStars();
707
+
708
+ this.onReturnToCosmos?.();
709
+ }
710
+
711
+ private updateCosmosSettingsList(): void {
712
+ const countEl = document.getElementById('cosmos-spaces-count');
713
+ const listEl = document.getElementById('cosmos-spaces-list');
714
+ if (countEl) { countEl.textContent = String(this.attachedSpaces.length); }
715
+
716
+ if (!listEl) { return; }
717
+
718
+ if (this.attachedSpaces.length === 0) {
719
+ listEl.innerHTML = `<p class="empty-list-note">No spaces added yet.<br>Click Code or Text in Cosmos to attach a space.</p>`;
720
+ return;
721
+ }
722
+
723
+ listEl.innerHTML = '';
724
+ for (const space of this.attachedSpaces) {
725
+ const item = document.createElement('div');
726
+ item.className = `cosmos-space-item ${this.activeSpaceId === space.id ? 'active' : ''}`;
727
+ item.setAttribute('data-space-id', space.id);
728
+ item.innerHTML = `
729
+ <span class="space-item-name">
730
+ <span class="space-item-icon">${space.icon}</span>
731
+ <span>${space.name}</span>
732
+ </span>
733
+ <span class="space-item-type">${space.type.toUpperCase()}</span>
734
+ `;
735
+ item.addEventListener('click', () => {
736
+ this.switchToSpace(space.id);
737
+ });
738
+ listEl.appendChild(item);
739
+ }
740
+ }
741
+
742
+ public handleAgentClick(): void {
743
+ if (this.isAgentDocked) return;
744
+ const nodeAgentWrapper = document.getElementById('node-agent-wrapper');
745
+ const agentFabContainer = document.getElementById('agent-fab-container');
746
+
747
+ if (nodeAgentWrapper) {
748
+ nodeAgentWrapper.classList.add('shooting-to-bottom-right');
749
+ }
750
+
751
+ setTimeout(() => {
752
+ this.isAgentDocked = true;
753
+ if (agentFabContainer) {
754
+ agentFabContainer.classList.remove('hidden');
755
+ agentFabContainer.classList.add('visible');
756
+ }
757
+ }, 600);
758
+ }
759
+
760
+ public resetToSingularity(): void {
761
+ this.attachedSpaces = [];
762
+ this.codeSpaceCounter = 0;
763
+ this.textSpaceCounter = 0;
764
+ this.activeSpaceId = null;
765
+
766
+ const spacesContainer = document.getElementById('activity-spaces-container');
767
+ if (spacesContainer) { spacesContainer.innerHTML = ''; }
768
+
769
+ const activityBar = document.getElementById('activity-bar');
770
+ const leftPanel = document.getElementById('left-panel');
771
+ if (activityBar) {
772
+ activityBar.classList.remove('expanded');
773
+ activityBar.classList.add('collapsed');
774
+ }
775
+ if (leftPanel) {
776
+ leftPanel.classList.remove('expanded');
777
+ leftPanel.classList.add('collapsed');
778
+ }
779
+
780
+ const singularityContainer = document.getElementById('cosmic-singularity-container');
781
+ const cluster = document.getElementById('cosmic-cluster');
782
+ const controls = document.getElementById('cosmic-controls');
783
+ const satellites = document.getElementById('superspace-satellites');
784
+ const nodeIdentityWrapper = document.getElementById('node-identity-wrapper');
785
+ const nodeAgentWrapper = document.getElementById('node-agent-wrapper');
786
+ const nodeSuperspaceWrapper = document.getElementById('node-superspace-wrapper');
787
+ const agentFabContainer = document.getElementById('agent-fab-container');
788
+ const identityHeaderContainer = document.getElementById('identity-header-container');
789
+ const headerBrandGalaxy = document.getElementById('header-brand-galaxy');
790
+ const btnCode = document.getElementById('btn-cosmic-code');
791
+ const btnNotes = document.getElementById('btn-cosmic-notes');
792
+
793
+ this.isClusterExpanded = false;
794
+ this.areSatellitesUnfolded = false;
795
+ this.isIdentityDocked = false;
796
+ this.isAgentDocked = false;
797
+
798
+ // Reset classes and animations
799
+ if (nodeIdentityWrapper) {
800
+ nodeIdentityWrapper.classList.remove('shooting-to-top-right');
801
+ nodeIdentityWrapper.style.animation = 'none';
802
+ }
803
+ if (nodeAgentWrapper) {
804
+ nodeAgentWrapper.classList.remove('shooting-to-bottom-right');
805
+ nodeAgentWrapper.style.animation = 'none';
806
+ }
807
+ if (nodeSuperspaceWrapper) {
808
+ nodeSuperspaceWrapper.classList.remove('shooting-to-top-left');
809
+ }
810
+ if (btnCode) {
811
+ btnCode.classList.remove('shooting-to-activity-code');
812
+ }
813
+ if (btnNotes) {
814
+ btnNotes.classList.remove('shooting-to-activity-text');
815
+ }
816
+ if (headerBrandGalaxy) {
817
+ headerBrandGalaxy.classList.remove('brand-galaxy-active');
818
+ }
819
+ if (identityHeaderContainer) {
820
+ identityHeaderContainer.classList.remove('identity-active-highlight');
821
+ }
822
+ if (agentFabContainer) {
823
+ agentFabContainer.classList.remove('visible');
824
+ agentFabContainer.classList.add('hidden');
825
+ }
826
+ if (satellites) {
827
+ satellites.classList.remove('unfolded');
828
+ satellites.classList.add('collapsed');
829
+ }
830
+ if (cluster) {
831
+ cluster.classList.remove('expanded');
832
+ cluster.classList.add('hidden');
833
+ }
834
+ if (controls) {
835
+ controls.classList.add('hidden');
836
+ }
837
+ if (singularityContainer) {
838
+ singularityContainer.classList.remove('collapsed');
839
+ }
840
+
841
+ // Return to Cosmos view in center
842
+ this.returnToCosmos();
843
+ }
844
+ }