neuralworm commited on
Commit
4f6ea7f
·
verified ·
1 Parent(s): b074c3a

Create experiments/templates/1014ecaa4_index.html

Browse files
experiments/templates/1014ecaa4_index.html ADDED
@@ -0,0 +1,866 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">
7
+ <title>TCI-1014 Unified Field Cockpit v2</title>
8
+ <style>
9
+ :root {
10
+ --bg: #050505;
11
+ --panel: #0b0c10;
12
+ --border: #333;
13
+ --accent: #00ffff;
14
+ --sys-text: #00ffaa;
15
+ --user-text: #ffffff;
16
+ --font-main: 'Courier New', monospace;
17
+ }
18
+
19
+ body {
20
+ margin: 0;
21
+ padding: 0;
22
+ background: var(--bg);
23
+ color: #ddd;
24
+ font-family: var(--font-main);
25
+ height: 100dvh;
26
+ width: 100vw;
27
+ display: grid;
28
+ /* LAYOUT UPDATE: Viz (30%) | Chat (40%) | Data (30%) */
29
+ grid-template-columns: 30% 40% 30%;
30
+ grid-template-rows: 1fr;
31
+ overflow: hidden;
32
+ overscroll-behavior: none;
33
+ position: fixed;
34
+ top: 0;
35
+ left: 0;
36
+ right: 0;
37
+ bottom: 0;
38
+ }
39
+
40
+ /* --- LEFT PANEL: VISUALIZER (Moved from Center) --- */
41
+ #viz-panel {
42
+ background: #000;
43
+ border-right: 1px solid var(--border);
44
+ display: flex;
45
+ flex-direction: column;
46
+ justify-content: center;
47
+ align-items: center;
48
+ position: relative;
49
+ }
50
+
51
+ #canvas-container {
52
+ width: 100%;
53
+ height: 100%;
54
+ display: flex;
55
+ justify-content: center;
56
+ align-items: center;
57
+ background: #000 radial-gradient(circle, #111 0%, #000 80%);
58
+ }
59
+
60
+ canvas {
61
+ width: 100%;
62
+ max-width: 95%;
63
+ aspect-ratio: 1;
64
+ box-shadow: 0 0 30px rgba(0, 255, 170, 0.15);
65
+ border: 1px solid #222;
66
+ }
67
+
68
+ #mode-selector {
69
+ position: absolute;
70
+ bottom: 20px;
71
+ left: 50%;
72
+ transform: translateX(-50%);
73
+ display: flex;
74
+ gap: 5px;
75
+ z-index: 10;
76
+ background: rgba(0, 0, 0, 0.8);
77
+ padding: 5px;
78
+ border-radius: 10px;
79
+ border: 1px solid #333;
80
+ }
81
+
82
+ .mode-btn {
83
+ background: #111;
84
+ border: 1px solid #444;
85
+ color: #888;
86
+ padding: 4px 10px;
87
+ cursor: pointer;
88
+ font-size: 0.7em;
89
+ border-radius: 5px;
90
+ }
91
+
92
+ .mode-btn.active {
93
+ border-color: var(--accent);
94
+ color: var(--accent);
95
+ background: rgba(0, 255, 255, 0.1);
96
+ }
97
+
98
+ /* --- CENTER PANEL: CHAT (Moved from Left) --- */
99
+ #chat-panel {
100
+ background: var(--panel);
101
+ border-right: 1px solid var(--border);
102
+ border-left: 1px solid var(--border);
103
+ display: flex;
104
+ flex-direction: column;
105
+ height: 100%;
106
+ min-height: 0;
107
+ box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
108
+ z-index: 5;
109
+ }
110
+
111
+ #messages {
112
+ flex: 1;
113
+ overflow-y: auto;
114
+ padding: 20px;
115
+ display: flex;
116
+ flex-direction: column;
117
+ gap: 12px;
118
+ scroll-behavior: smooth;
119
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
120
+ }
121
+
122
+ .msg {
123
+ padding: 10px 15px;
124
+ border-radius: 6px;
125
+ font-size: 0.95em;
126
+ line-height: 1.5;
127
+ max-width: 90%;
128
+ word-wrap: break-word;
129
+ }
130
+
131
+ .msg.user {
132
+ align-self: flex-end;
133
+ background: #222;
134
+ border-left: 3px solid var(--accent);
135
+ color: var(--user-text);
136
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
137
+ }
138
+
139
+ .msg.system {
140
+ align-self: flex-start;
141
+ background: #151a15;
142
+ border-left: 3px solid var(--sys-text);
143
+ color: var(--sys-text);
144
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
145
+ }
146
+
147
+ #input-area {
148
+ padding: 20px;
149
+ border-top: 1px solid var(--border);
150
+ background: #151515;
151
+ display: flex;
152
+ gap: 10px;
153
+ flex-shrink: 0;
154
+ }
155
+
156
+ input {
157
+ flex: 1;
158
+ background: #000;
159
+ border: 1px solid #444;
160
+ color: #fff;
161
+ padding: 12px;
162
+ font-family: inherit;
163
+ font-size: 1em;
164
+ }
165
+
166
+ button {
167
+ background: var(--accent);
168
+ color: #000;
169
+ border: none;
170
+ padding: 0 20px;
171
+ font-weight: bold;
172
+ cursor: pointer;
173
+ text-transform: uppercase;
174
+ }
175
+
176
+ /* --- RIGHT PANEL: DATA (Unchanged) --- */
177
+ #data-panel {
178
+ background: #080808;
179
+ display: flex;
180
+ flex-direction: column;
181
+ height: 100%;
182
+ padding: 20px;
183
+ gap: 20px;
184
+ overflow-y: auto;
185
+ }
186
+
187
+ .panel-section {
188
+ border: 1px solid #222;
189
+ padding: 15px;
190
+ background: rgba(255, 255, 255, 0.02);
191
+ }
192
+
193
+ .panel-header {
194
+ color: #666;
195
+ font-size: 0.75em;
196
+ margin-bottom: 10px;
197
+ text-transform: uppercase;
198
+ letter-spacing: 2px;
199
+ }
200
+
201
+ #metrics-grid {
202
+ display: grid;
203
+ grid-template-columns: 1fr 1fr;
204
+ gap: 10px;
205
+ }
206
+
207
+ .metric-box {
208
+ background: #111;
209
+ padding: 10px;
210
+ text-align: center;
211
+ border: 1px solid #222;
212
+ }
213
+
214
+ .metric-val {
215
+ font-size: 1.4em;
216
+ font-weight: bold;
217
+ color: var(--accent);
218
+ font-family: 'Arial', sans-serif;
219
+ }
220
+
221
+ .metric-label {
222
+ font-size: 0.6em;
223
+ color: #555;
224
+ margin-top: 5px;
225
+ }
226
+
227
+ #formula-log {
228
+ flex: 1;
229
+ background: #000;
230
+ border: 1px solid #333;
231
+ padding: 10px;
232
+ overflow-y: auto;
233
+ color: #ffcc00;
234
+ font-family: 'Times New Roman', serif;
235
+ font-style: italic;
236
+ min-height: 200px;
237
+ }
238
+
239
+ /* OVERLAY */
240
+ #session-overlay {
241
+ position: fixed;
242
+ top: 0;
243
+ left: 0;
244
+ width: 100%;
245
+ height: 100%;
246
+ background: rgba(0, 0, 0, 0.92);
247
+ z-index: 999;
248
+ display: flex;
249
+ flex-direction: column;
250
+ justify-content: center;
251
+ align-items: center;
252
+ }
253
+
254
+ /* MOBILE OPTIMIZATIONS */
255
+ @media (max-width: 900px) {
256
+ body {
257
+ grid-template-columns: 1fr;
258
+ /* Viz (ROW, smaller) | Chat (Maximize) | Data (Visible) */
259
+ grid-template-rows: 25dvh 1fr 20dvh;
260
+ height: 100vh;
261
+ /* Fallback */
262
+ height: 100dvh;
263
+ /* Dynamic Height */
264
+ overflow: hidden;
265
+ }
266
+
267
+ /* Hide Status Text */
268
+ #status-active {
269
+ display: none !important;
270
+ }
271
+
272
+ #viz-panel {
273
+ order: 1;
274
+ /* CHANGE: Row layout for side-buttons */
275
+ flex-direction: row;
276
+ align-items: stretch;
277
+ width: 100vw;
278
+ height: 100%;
279
+ max-height: none;
280
+ border-bottom: 2px solid var(--accent);
281
+ box-shadow: 0 10px 40px rgba(0, 255, 170, 0.1);
282
+ flex-shrink: 0;
283
+ }
284
+
285
+ #canvas-container {
286
+ padding: 0;
287
+ flex: 1;
288
+ /* Take remaining width */
289
+ min-width: 0;
290
+ height: 100%;
291
+ display: flex;
292
+ align-items: center;
293
+ justify-content: center;
294
+ }
295
+
296
+ canvas {
297
+ /* Square canvas fits in the container */
298
+ max-width: 95%;
299
+ max-height: 95%;
300
+ width: auto;
301
+ height: auto;
302
+ aspect-ratio: 1/1;
303
+ }
304
+
305
+ #mode-selector {
306
+ /* CHANGE: Sidebar Column */
307
+ position: static;
308
+ transform: none;
309
+ width: 60px;
310
+ height: 100%;
311
+ flex-direction: column;
312
+ justify-content: flex-start;
313
+ padding: 5px;
314
+ background: #080808;
315
+ border-right: 1px solid #333;
316
+ gap: 5px;
317
+ border-radius: 0;
318
+ border: none;
319
+ border-right: 1px solid var(--border);
320
+ }
321
+
322
+ .mode-btn {
323
+ padding: 0;
324
+ width: 100%;
325
+ height: 40px;
326
+ font-size: 0.65em;
327
+ margin: 0;
328
+ display: flex;
329
+ align-items: center;
330
+ justify-content: center;
331
+ word-break: break-all;
332
+ border-radius: 4px;
333
+ }
334
+
335
+ #chat-panel {
336
+ order: 2;
337
+ border: none;
338
+ height: 100%;
339
+ min-height: 0;
340
+ display: flex;
341
+ flex-direction: column;
342
+ }
343
+
344
+ #messages {
345
+ flex: 1 1 auto;
346
+ overflow-y: auto;
347
+ font-size: 0.9em;
348
+ padding: 10px;
349
+ min-height: 0;
350
+ }
351
+
352
+ #input-area {
353
+ padding: 8px;
354
+ flex-shrink: 0;
355
+ }
356
+
357
+ input {
358
+ padding: 12px;
359
+ font-size: 16px;
360
+ border-radius: 4px;
361
+ }
362
+
363
+ button[type="submit"] {
364
+ padding: 0 15px;
365
+ }
366
+
367
+ #data-panel {
368
+ order: 3;
369
+ border-top: 1px solid var(--border);
370
+ padding: 2px;
371
+ background: #000;
372
+ z-index: 20;
373
+ font-size: 0.7em;
374
+ /* Smaller font */
375
+ /* CHANGE: Split Layout */
376
+ display: grid;
377
+ grid-template-columns: 1fr 1fr;
378
+ gap: 2px;
379
+ overflow-y: auto;
380
+ /* Allow scrolling if huge */
381
+ /* Safe Area for Home Bar */
382
+ padding-bottom: env(safe-area-inset-bottom) !important;
383
+ }
384
+
385
+ /* Keyboard Handling Removed */
386
+
387
+ /* Left: Metrics Grid */
388
+ .panel-section:nth-of-type(1) {
389
+ grid-column: 1;
390
+ display: flex;
391
+ flex-direction: column;
392
+ border: none;
393
+ padding: 0;
394
+ background: transparent;
395
+ height: 100%;
396
+ }
397
+
398
+ .active-title {
399
+ display: none;
400
+ }
401
+
402
+ /* Hide title to save space? */
403
+
404
+ #metrics-grid {
405
+ display: grid;
406
+ grid-template-columns: 1fr 1fr;
407
+ grid-template-rows: 1fr 1fr;
408
+ gap: 2px;
409
+ height: 100%;
410
+ }
411
+
412
+ .metric-box {
413
+ padding: 2px;
414
+ display: flex;
415
+ flex-direction: column;
416
+ justify-content: space-between;
417
+ position: relative;
418
+ min-height: 0;
419
+ overflow: hidden;
420
+ border: 1px solid #222;
421
+ }
422
+
423
+ .sparkline {
424
+ position: absolute;
425
+ bottom: 0;
426
+ left: 0;
427
+ width: 100%;
428
+ /* Update: Full height to "center" visually */
429
+ height: 100%;
430
+ opacity: 0.3;
431
+ pointer-events: none;
432
+ }
433
+
434
+ .metric-val {
435
+ font-size: 0.9em;
436
+ position: relative;
437
+ z-index: 2;
438
+ }
439
+
440
+ .metric-label {
441
+ font-size: 0.5em;
442
+ position: relative;
443
+ z-index: 2;
444
+ }
445
+
446
+ /* Right: Formula Stream */
447
+ .panel-section:nth-of-type(2) {
448
+ grid-column: 2;
449
+ display: flex;
450
+ flex-direction: column;
451
+ border: none;
452
+ padding: 0;
453
+ border-left: 1px solid #222;
454
+ padding-left: 4px;
455
+ background: transparent;
456
+ height: 100%;
457
+ min-height: 0;
458
+ }
459
+
460
+ .panel-header {
461
+ font-size: 0.6em;
462
+ margin-bottom: 2px;
463
+ }
464
+
465
+ #formula-log {
466
+ flex: 1;
467
+ min-height: 0;
468
+ border: none;
469
+ padding: 0;
470
+ overflow-y: auto;
471
+ }
472
+
473
+ #formula-log div {
474
+ font-size: 0.8em !important;
475
+ margin-bottom: 4px !important;
476
+ padding-bottom: 4px !important;
477
+ }
478
+
479
+ /* Hide Lexicon on mobile for now */
480
+ .panel-section:nth-of-type(3) {
481
+ display: none;
482
+ }
483
+ }
484
+ </style>
485
+ <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
486
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
487
+ </head>
488
+
489
+ <body>
490
+
491
+ <!-- LEFT: VISUALIZER (New Location) -->
492
+ <!-- LEFT: VISUALIZER (New Location) -->
493
+ <div id="viz-panel">
494
+ <div id="mode-selector">
495
+ <button class="mode-btn active" onclick="setMode(0)">VORTEX</button>
496
+ <button class="mode-btn" onclick="setMode(1)">INDRA</button>
497
+ <button class="mode-btn" onclick="setMode(2)">HOFSTADTER</button>
498
+ <button class="mode-btn" onclick="setMode(3)">GÖDEL</button>
499
+ </div>
500
+ <div id="canvas-container">
501
+ <canvas id="holoCanvas" width="400" height="400"></canvas>
502
+ </div>
503
+ </div>
504
+
505
+ <!-- CENTER: CHAT (New Location) -->
506
+ <div id="chat-panel">
507
+ <div id="status-active"
508
+ style="padding:15px; border-bottom:1px solid #333; font-size:0.8em; color:#666; text-transform:uppercase; letter-spacing:1px; text-align:center;">
509
+ Quantum Link Active
510
+ </div>
511
+ <div id="messages"></div>
512
+ <form id="input-area">
513
+ <input type="text" id="msg-input" placeholder="Enter signal..." autocomplete="off">
514
+ <button type="submit">TX</button>
515
+ </form>
516
+ </div>
517
+
518
+ <!-- RIGHT: DATA -->
519
+ <div id="data-panel">
520
+ <div class="panel-section">
521
+ <!-- Headers are often hidden in mobile CSS but kept for desktop -->
522
+ <div class="panel-header active-title">Field Metrics</div>
523
+ <div id="metrics-grid">
524
+ <div class="metric-box">
525
+ <canvas id="spark-ci" class="sparkline"></canvas>
526
+ <div class="metric-val" id="val-ci">--</div>
527
+ <div class="metric-label">INTEGRITY</div>
528
+ </div>
529
+ <div class="metric-box">
530
+ <canvas id="spark-ent" class="sparkline"></canvas>
531
+ <div class="metric-val" id="val-ent" style="color:#ff5555">--</div>
532
+ <div class="metric-label">ENTROPY</div>
533
+ </div>
534
+ <div class="metric-box">
535
+ <canvas id="spark-godel" class="sparkline"></canvas>
536
+ <div class="metric-val" id="val-godel">--</div>
537
+ <div class="metric-label">GÖDEL GAP</div>
538
+ </div>
539
+ <div class="metric-box">
540
+ <canvas id="spark-vort" class="sparkline"></canvas>
541
+ <div class="metric-val" id="val-vort">--</div>
542
+ <div class="metric-label">VORTICITY</div>
543
+ </div>
544
+ </div>
545
+ </div>
546
+ <div class="panel-section">
547
+ <div class="panel-header">Formula Stream</div>
548
+ <div id="formula-log">
549
+ <div style="opacity:0.5; font-size:0.8em;">Waiting for coherence event...</div>
550
+ </div>
551
+ </div>
552
+ <div class="panel-section">
553
+ <div class="panel-header">Lexicon</div>
554
+ <div id="vocab-display" style="font-size:0.8em; color:#888; word-wrap:break-word;"></div>
555
+ </div>
556
+ </div>
557
+
558
+ <!-- OVERLAY -->
559
+ <div id="session-overlay">
560
+ <h1 style="color:var(--accent); text-transform:uppercase; letter-spacing:4px; margin-bottom: 30px;">System
561
+ Initialization</h1>
562
+ <div id="session-list"
563
+ style="width: 80%; max-width:400px; max-height:40vh; overflow-y:auto; border:1px solid #444; margin-bottom:20px; background:#111;">
564
+ </div>
565
+ <button onclick="newSession()"
566
+ style="padding:15px 40px; font-size:1em; letter-spacing:2px; border:1px solid var(--accent);">NEW
567
+ SESSION</button>
568
+ </div>
569
+
570
+ <script>
571
+ let ws;
572
+ let mode = 0;
573
+ let gatingMap = new Float32Array(40 * 40);
574
+ let vorticityMap = new Float32Array(40 * 40);
575
+
576
+ // --- SESSION LOGIC ---
577
+ function fetchSessions() {
578
+ fetch('/api/sessions').then(r => r.json()).then(sessions => {
579
+ const list = document.getElementById('session-list');
580
+ list.innerHTML = '';
581
+ sessions.forEach(s => {
582
+ const d = document.createElement('div');
583
+ d.style.padding = '15px'; d.style.borderBottom = '1px solid #333';
584
+ d.style.cursor = 'pointer'; d.style.color = '#ccc';
585
+ d.innerHTML = `<span style="color:var(--accent)">${s.label}</span><br><small>${s.id}</small>`;
586
+ d.onmouseover = () => d.style.background = '#222';
587
+ d.onmouseout = () => d.style.background = 'transparent';
588
+ d.onclick = () => loadSession(s.id);
589
+ list.appendChild(d);
590
+ });
591
+ });
592
+ }
593
+ window.onload = fetchSessions;
594
+ function loadSession(id) { fetch(`/api/session/load/${id}`, { method: 'POST' }).then(r => r.json()).then(r => { if (r.status === 'ok') startWS(); }); }
595
+ function newSession() { fetch(`/api/session/new`, { method: 'POST' }).then(r => r.json()).then(r => { if (r.status === 'ok') startWS(); }); }
596
+
597
+ // --- WEBSOCKET ---
598
+ function startWS() {
599
+ document.getElementById('session-overlay').style.display = 'none';
600
+ ws = new WebSocket(`ws://${location.host}/ws`);
601
+ ws.onmessage = (e) => {
602
+ const msg = JSON.parse(e.data);
603
+ if (msg.type === 'state') updateState(msg);
604
+ else if (['chat', 'history'].includes(msg.type)) msg.data.forEach(addMsg);
605
+ };
606
+ }
607
+
608
+ function setMode(m) {
609
+ mode = m;
610
+ document.querySelectorAll('.mode-btn').forEach((b, i) => {
611
+ b.classList.toggle('active', i === m);
612
+ });
613
+ }
614
+
615
+ // --- APP LOGIC ---
616
+ const historyLen = 50;
617
+ const metricsHistory = { ci: new Array(historyLen).fill(0), ent: new Array(historyLen).fill(0), godel: new Array(historyLen).fill(0), vort: new Array(historyLen).fill(0) };
618
+
619
+ function updateState(s) {
620
+ window.currentMetrics = s.metrics;
621
+
622
+ // Parse Maps
623
+ if (s.maps) {
624
+ // Flatten 40x40 arrays
625
+ // Assume server sends list of lists
626
+ // We flatten them to Float32Array for texture
627
+ if (s.maps.gating) gatingMap = new Float32Array(s.maps.gating.flat());
628
+ if (s.maps.vorticity) vorticityMap = new Float32Array(s.maps.vorticity.flat());
629
+ }
630
+
631
+ // Update DOM metrics
632
+ ['ci', 'ent', 'godel', 'vort'].forEach(k => {
633
+ const key = k === 'ci' ? 'causal_integrity' : k === 'ent' ? 'entropy' : k === 'godel' ? 'godel_gap' : 'vorticity';
634
+ const val = s.metrics[key];
635
+ document.getElementById(`val-${k}`).innerText = val.toFixed(3);
636
+ metricsHistory[k].shift(); metricsHistory[k].push(val);
637
+ drawSparkline(`spark-${k}`, metricsHistory[k], k === 'ent' ? '#ff5555' : k === 'godel' ? '#ffff00' : '#00ffff');
638
+ });
639
+
640
+ if (s.phases) {
641
+ // Prepare Noise / Phase data
642
+ // We use phase as R channel
643
+ const phaseData = s.phases.flat();
644
+ window.currentPhaseData = phaseData;
645
+ }
646
+
647
+ if (s.formula) logFormula(s.formula);
648
+ document.getElementById('vocab-display').innerText = (s.vocab.top || []).join(", ");
649
+ }
650
+
651
+ function drawSparkline(id, data, color) {
652
+ const c = document.getElementById(id); if (!c) return;
653
+ const ctx = c.getContext('2d');
654
+ c.width = c.offsetWidth; c.height = c.offsetHeight;
655
+ ctx.clearRect(0, 0, c.width, c.height);
656
+ if (data.length < 2) return;
657
+ let min = Math.min(...data), max = Math.max(...data);
658
+ if (max === min) { min -= 0.1; max += 0.1; }
659
+ ctx.beginPath();
660
+ ctx.strokeStyle = color; ctx.lineWidth = 2;
661
+ for (let i = 0; i < data.length; i++) {
662
+ let x = i / (data.length - 1) * c.width;
663
+ let y = c.height - (data[i] - min) / (max - min) * c.height;
664
+ if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
665
+ }
666
+ ctx.stroke();
667
+ }
668
+
669
+ const msgsDiv = document.getElementById('messages');
670
+ function addMsg(m) {
671
+ const d = document.createElement('div');
672
+ d.className = `msg ${m.type}`;
673
+ d.innerHTML = `<strong>${m.type === 'user' ? 'USR' : 'SYS'}</strong> [${m.time}]<br>${m.text}`;
674
+ if (m.ci) d.innerHTML += `<br><small style="opacity:0.6">CI: ${m.ci.toFixed(2)}</small>`;
675
+ msgsDiv.appendChild(d);
676
+ msgsDiv.scrollTop = msgsDiv.scrollHeight;
677
+ }
678
+
679
+ document.getElementById('input-area').onsubmit = (e) => {
680
+ e.preventDefault();
681
+ const i = document.getElementById('msg-input');
682
+ if (i.value.trim()) {
683
+ ws.send(JSON.stringify({ type: 'message', text: i.value }));
684
+ i.value = '';
685
+ }
686
+ };
687
+
688
+ function logFormula(f) {
689
+ const d = document.getElementById('formula-log');
690
+ const el = document.createElement('div');
691
+ el.innerHTML = `<span style="color:#aaa">[${f.timestamp}]</span> ${f.desc}<br><span style="color:var(--accent)">$$${f.text}$$</span>`;
692
+ el.style.borderBottom = '1px solid #222'; el.style.padding = '5px 0';
693
+ d.prepend(el);
694
+ if (d.children.length > 20) d.lastChild.remove();
695
+ MathJax.typesetPromise([el]);
696
+ }
697
+
698
+ // =============================================================================
699
+ // WEBGL 2.0 ADVANCED VISUALIZER
700
+ // =============================================================================
701
+ const gl = document.getElementById('holoCanvas').getContext('webgl2');
702
+ if (!gl) alert("WebGL 2 Required");
703
+
704
+ // Vertex Shader
705
+ const vs = `#version 300 es
706
+ in vec2 pos; out vec2 uv;
707
+ void main() { uv = pos*0.5+0.5; gl_Position=vec4(pos,0,1); }`;
708
+
709
+ // Fragment Shader WITH VORTICITY & GATING MAPS
710
+ const fs = `#version 300 es
711
+ precision highp float;
712
+ in vec2 uv; out vec4 color;
713
+
714
+ uniform float time;
715
+ uniform sampler2D uPhase; // R channel = Phase
716
+ uniform sampler2D uGating; // R channel = Gating (Focus)
717
+ uniform sampler2D uVorticity; // R channel = Vorticity (Charge)
718
+ uniform int uMode; // 0=VORTEX, 1=INDRA, 2=HOFSTADTER, 3=GODEL
719
+
720
+ #define PI 3.14159265
721
+ #define TAU 6.2831853
722
+
723
+ vec3 hsv2rgb(vec3 c) {
724
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
725
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
726
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
727
+ }
728
+
729
+ void main() {
730
+ // Read textures
731
+ // UV is [0,1], texture is 40x40, nearest neighbor is good for discrete grid
732
+ float phase = texture(uPhase, uv).r;
733
+ float gating = texture(uGating, uv).r;
734
+ float vort = texture(uVorticity, uv).r;
735
+
736
+ vec3 col = vec3(0.0);
737
+
738
+ if (uMode == 0) {
739
+ // VORTEX MODE (Strange Loop)
740
+ // Color by Phase (Rainbow), Brightness by Gating (Heatmap)
741
+ // Overlay Vorticity as Dots
742
+
743
+ // 1. Base Phase Color (Rainbow)
744
+ // Map phase [0, 2PI] roughly to Hue
745
+ float hue = phase / TAU;
746
+ col = hsv2rgb(vec3(hue, 1.0, 1.0));
747
+
748
+ // 2. Gating Heatmap (Darken quiet zones)
749
+ // High gating = High Focus = Bright
750
+ col *= (0.2 + 0.8 * gating);
751
+
752
+ // 3. Vorticity Overlay (Red/Blue dots) (Point 3)
753
+ // If vorticity is significant (> 0.3), draw a dot
754
+ if (abs(vort) > 0.3) {
755
+ vec2 grid_uv = uv * 40.0; // Scale UV to grid coordinates
756
+ vec2 cell_center = floor(grid_uv) + 0.5; // Center of the current cell
757
+ float dist = length(grid_uv - cell_center); // Distance from cell center
758
+
759
+ // Draw a dot if within a certain radius of the cell center
760
+ if (dist < 0.4) { // Adjust radius as needed
761
+ vec3 vCol = (vort > 0.0) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 0.5, 1.0);
762
+ col = mix(col, vCol, 0.8); // Blend with existing color
763
+ }
764
+ }
765
+ }
766
+ else if (uMode == 1) {
767
+ // INDRA'S NET (Fractal Jewels)
768
+ // Uses Gating to reflect
769
+ vec2 p = uv * 2.0 - 1.0;
770
+ float r = length(p);
771
+ float a = atan(p.y, p.x);
772
+ float f = cos(a * 12.0 + time) * sin(r * 10.0 - time);
773
+
774
+ // Jewel sparkle based on gating
775
+ float sparkle = gating * smoothstep(0.4, 0.5, abs(f));
776
+ col = vec3(0.1, 0.0, 0.2) + vec3(0.8, 0.6, 1.0) * sparkle;
777
+ col += hsv2rgb(vec3(phase/TAU, 0.5, 0.5)) * 0.3;
778
+ }
779
+ else if (uMode == 2) {
780
+ // HOFSTADTER BUTTERFLY (Energy Bands)
781
+ // Visualizing the quantized flux zones
782
+ float flux = vort * 20.0; // Scale up
783
+ float band = sin(flux * 3.14 + phase);
784
+ col = vec3(band * 0.5 + 0.5, 0.0, 1.0 - band*0.5);
785
+ col *= gating;
786
+ }
787
+ else if (uMode == 3) {
788
+ // GODEL NEBULA (Uncertainty)
789
+ // Show areas of high Entropy/Unrest (Low Gating)
790
+ // Low Gating = Fog
791
+ float fog = 1.0 - gating;
792
+
793
+ // Animated fog
794
+ float n = sin(uv.x*10.0 + time) * cos(uv.y*10.0 - time);
795
+
796
+ col = vec3(0.1) + vec3(0.5, 0.5, 0.5) * fog * n;
797
+ // Add flashes of insight (phase)
798
+ if (gating > 0.8) col += vec3(1.0, 1.0, 0.0) * 0.5;
799
+ }
800
+
801
+ color = vec4(col, 1.0);
802
+ }`;
803
+
804
+ // Setup GL
805
+ const p = gl.createProgram();
806
+ const vsS = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vsS, vs); gl.compileShader(vsS);
807
+ const fsS = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fsS, fs); gl.compileShader(fsS);
808
+ if (!gl.getShaderParameter(fsS, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(fsS));
809
+ gl.attachShader(p, vsS); gl.attachShader(p, fsS); gl.linkProgram(p); gl.useProgram(p);
810
+
811
+ // Quad
812
+ const b = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, b);
813
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
814
+ const l = gl.getAttribLocation(p, 'pos'); gl.enableVertexAttribArray(l); gl.vertexAttribPointer(l, 2, gl.FLOAT, false, 0, 0);
815
+
816
+ // Textures
817
+ function createTex(unit) {
818
+ const t = gl.createTexture();
819
+ gl.activeTexture(gl.TEXTURE0 + unit);
820
+ gl.bindTexture(gl.TEXTURE_2D, t);
821
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
822
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
823
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
824
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
825
+ return t;
826
+ }
827
+
828
+ const tPhase = createTex(0);
829
+ const tGating = createTex(1);
830
+ const tVort = createTex(2);
831
+
832
+ gl.uniform1i(gl.getUniformLocation(p, "uPhase"), 0);
833
+ gl.uniform1i(gl.getUniformLocation(p, "uGating"), 1);
834
+ gl.uniform1i(gl.getUniformLocation(p, "uVorticity"), 2);
835
+
836
+ const locTime = gl.getUniformLocation(p, 'time');
837
+ const locMode = gl.getUniformLocation(p, 'uMode');
838
+
839
+ function render() {
840
+ gl.uniform1f(locTime, performance.now() / 1000);
841
+ gl.uniform1i(locMode, mode);
842
+
843
+ if (window.currentPhaseData) {
844
+ gl.activeTexture(gl.TEXTURE0);
845
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, 40, 40, 0, gl.RED, gl.FLOAT, new Float32Array(window.currentPhaseData));
846
+
847
+ gl.activeTexture(gl.TEXTURE1);
848
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, 40, 40, 0, gl.RED, gl.FLOAT, gatingMap);
849
+
850
+ gl.activeTexture(gl.TEXTURE2);
851
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, 40, 40, 0, gl.RED, gl.FLOAT, vorticityMap);
852
+ }
853
+
854
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
855
+ requestAnimationFrame(render);
856
+ }
857
+ render();
858
+
859
+ </script>
860
+ <script>
861
+ // MOBILE KEYBOARD HANDLING (Safe Script Block)
862
+ // MOBILE KEYBOARD HANDLING REMOVED per user request
863
+ </script>
864
+ </body>
865
+
866
+ </html>