HI7RAI commited on
Commit
381b048
·
verified ·
1 Parent(s): 171f087

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +811 -19
index.html CHANGED
@@ -1,19 +1,811 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.0">
6
+ <title>CSS Gen-Algo & 3D Experimental Lab</title>
7
+ <!-- Import Icons -->
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <!-- Three.js -->
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
11
+
12
+ <style>
13
+ :root {
14
+ --bg-color: #050505;
15
+ --panel-bg: rgba(20, 20, 25, 0.75);
16
+ --accent-primary: #00f3ff;
17
+ --accent-secondary: #bd00ff;
18
+ --text-main: #ffffff;
19
+ --text-muted: #888888;
20
+ --border-color: rgba(255, 255, 255, 0.1);
21
+ --card-ratio-w: 4;
22
+ --card-ratio-h: 5;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ margin: 0;
28
+ padding: 0;
29
+ font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
30
+ }
31
+
32
+ body {
33
+ background-color: var(--bg-color);
34
+ color: var(--text-main);
35
+ overflow: hidden; /* App-like feel */
36
+ height: 100vh;
37
+ width: 100vw;
38
+ }
39
+
40
+ /* --- 3D Background Canvas --- */
41
+ #bg-canvas {
42
+ position: fixed;
43
+ top: 0;
44
+ left: 0;
45
+ width: 100%;
46
+ height: 100%;
47
+ z-index: -1;
48
+ pointer-events: none; /* Let clicks pass through */
49
+ }
50
+
51
+ /* --- Header --- */
52
+ header {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ padding: 1rem 2rem;
57
+ background: rgba(0, 0, 0, 0.8);
58
+ backdrop-filter: blur(10px);
59
+ border-bottom: 1px solid var(--border-color);
60
+ z-index: 100;
61
+ }
62
+
63
+ .brand {
64
+ font-size: 1.2rem;
65
+ font-weight: 700;
66
+ letter-spacing: 2px;
67
+ text-transform: uppercase;
68
+ background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
69
+ -webkit-background-clip: text;
70
+ -webkit-text-fill-color: transparent;
71
+ }
72
+
73
+ .anycoder-link {
74
+ font-size: 0.8rem;
75
+ color: var(--text-muted);
76
+ text-decoration: none;
77
+ transition: color 0.3s;
78
+ }
79
+ .anycoder-link:hover { color: var(--accent-primary); }
80
+
81
+ /* --- Main Layout --- */
82
+ main {
83
+ display: grid;
84
+ grid-template-columns: 350px 1fr;
85
+ height: calc(100vh - 70px);
86
+ position: relative;
87
+ }
88
+
89
+ /* --- Sidebar / Controls --- */
90
+ aside {
91
+ background: var(--panel-bg);
92
+ backdrop-filter: blur(15px);
93
+ border-right: 1px solid var(--border-color);
94
+ padding: 1.5rem;
95
+ overflow-y: auto;
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: 1.5rem;
99
+ }
100
+
101
+ h2 {
102
+ font-size: 0.9rem;
103
+ text-transform: uppercase;
104
+ color: var(--accent-primary);
105
+ margin-bottom: 0.8rem;
106
+ border-bottom: 1px solid var(--border-color);
107
+ padding-bottom: 0.3rem;
108
+ }
109
+
110
+ .control-group {
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: 0.5rem;
114
+ }
115
+
116
+ label {
117
+ font-size: 0.8rem;
118
+ color: var(--text-muted);
119
+ }
120
+
121
+ textarea {
122
+ background: rgba(0, 0, 0, 0.5);
123
+ border: 1px solid var(--border-color);
124
+ color: #00ff00;
125
+ font-family: 'Courier New', monospace;
126
+ font-size: 0.75rem;
127
+ padding: 0.5rem;
128
+ border-radius: 4px;
129
+ resize: vertical;
130
+ min-height: 80px;
131
+ }
132
+ textarea:focus { outline: 1px solid var(--accent-primary); }
133
+
134
+ button {
135
+ background: linear-gradient(45deg, var(--accent-secondary), #8000ff);
136
+ border: none;
137
+ color: white;
138
+ padding: 0.8rem;
139
+ border-radius: 4px;
140
+ cursor: pointer;
141
+ font-weight: 600;
142
+ text-transform: uppercase;
143
+ font-size: 0.8rem;
144
+ transition: transform 0.2s, box-shadow 0.2s;
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ gap: 0.5rem;
149
+ }
150
+
151
+ button:hover {
152
+ transform: translateY(-2px);
153
+ box-shadow: 0 4px 15px rgba(189, 0, 255, 0.4);
154
+ }
155
+
156
+ button.secondary {
157
+ background: transparent;
158
+ border: 1px solid var(--accent-primary);
159
+ color: var(--accent-primary);
160
+ }
161
+ button.secondary:hover {
162
+ background: rgba(0, 243, 255, 0.1);
163
+ box-shadow: 0 0 10px rgba(0, 243, 255, 0.2);
164
+ }
165
+
166
+ /* --- 3D Scanner Preview --- */
167
+ #scanner-preview {
168
+ width: 100%;
169
+ height: 150px;
170
+ background: #000;
171
+ border: 1px solid var(--border-color);
172
+ border-radius: 4px;
173
+ position: relative;
174
+ overflow: hidden;
175
+ }
176
+ #scanner-preview canvas {
177
+ width: 100%;
178
+ height: 100%;
179
+ }
180
+
181
+ /* --- Performance Curve --- */
182
+ #chart-canvas {
183
+ width: 100%;
184
+ height: 100px;
185
+ background: rgba(0,0,0,0.3);
186
+ border: 1px solid var(--border-color);
187
+ border-radius: 4px;
188
+ }
189
+
190
+ /* --- Gallery / Workspace --- */
191
+ #workspace {
192
+ padding: 2rem;
193
+ overflow: hidden;
194
+ display: flex;
195
+ flex-direction: column;
196
+ }
197
+
198
+ .toolbar {
199
+ display: flex;
200
+ justify-content: space-between;
201
+ align-items: center;
202
+ margin-bottom: 1rem;
203
+ }
204
+
205
+ .zoom-control {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 10px;
209
+ }
210
+ input[type="range"] {
211
+ accent-color: var(--accent-primary);
212
+ }
213
+
214
+ /* --- Gallery Grid --- */
215
+ #gallery-grid {
216
+ display: grid;
217
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
218
+ gap: 1.5rem;
219
+ overflow-y: auto;
220
+ flex-grow: 1;
221
+ padding-right: 10px;
222
+ padding-bottom: 20px;
223
+ align-content: start;
224
+ }
225
+
226
+ /* Custom Scrollbar */
227
+ #gallery-grid::-webkit-scrollbar {
228
+ width: 8px;
229
+ }
230
+ #gallery-grid::-webkit-scrollbar-track {
231
+ background: rgba(255,255,255,0.05);
232
+ }
233
+ #gallery-grid::-webkit-scrollbar-thumb {
234
+ background: var(--border-color);
235
+ border-radius: 4px;
236
+ }
237
+
238
+ /* --- The Card (4:5) --- */
239
+ .card {
240
+ aspect-ratio: 4 / 5;
241
+ background: rgba(20,20,20,0.8);
242
+ border: 1px solid var(--border-color);
243
+ border-radius: 8px;
244
+ position: relative;
245
+ display: flex;
246
+ flex-direction: column;
247
+ overflow: hidden;
248
+ transition: all 0.3s ease;
249
+ cursor: pointer;
250
+ box-shadow: 0 4px 6px rgba(0,0,0,0.3);
251
+ }
252
+
253
+ .card:hover {
254
+ transform: translateY(-5px) scale(1.02);
255
+ z-index: 10;
256
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
257
+ }
258
+
259
+ /* Card Visuals (Generated CSS applies here) */
260
+ .card-visual {
261
+ flex-grow: 1;
262
+ position: relative;
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: center;
266
+ overflow: hidden;
267
+ }
268
+
269
+ /* The "Shrunk" 3D Model representation in card */
270
+ .card-model-placeholder {
271
+ width: 60%;
272
+ height: 60%;
273
+ background: rgba(255,255,255,0.05);
274
+ border-radius: 50%;
275
+ display: flex;
276
+ align-items: center;
277
+ justify-content: center;
278
+ font-size: 2rem;
279
+ color: rgba(255,255,255,0.2);
280
+ transition: all 0.5s;
281
+ }
282
+
283
+ .card:hover .card-model-placeholder {
284
+ transform: rotate(45deg) scale(1.1);
285
+ color: var(--accent-primary);
286
+ }
287
+
288
+ .card-info {
289
+ padding: 1rem;
290
+ background: rgba(0,0,0,0.9);
291
+ border-top: 1px solid var(--border-color);
292
+ }
293
+
294
+ .card-title {
295
+ font-size: 0.8rem;
296
+ font-weight: bold;
297
+ margin-bottom: 0.3rem;
298
+ white-space: nowrap;
299
+ overflow: hidden;
300
+ text-overflow: ellipsis;
301
+ }
302
+
303
+ .card-meta {
304
+ font-size: 0.6rem;
305
+ color: var(--text-muted);
306
+ display: flex;
307
+ justify-content: space-between;
308
+ }
309
+
310
+ .save-btn {
311
+ position: absolute;
312
+ top: 10px;
313
+ right: 10px;
314
+ background: rgba(0,0,0,0.6);
315
+ border: 1px solid var(--text-muted);
316
+ color: white;
317
+ width: 30px;
318
+ height: 30px;
319
+ border-radius: 50%;
320
+ display: flex;
321
+ align-items: center;
322
+ justify-content: center;
323
+ cursor: pointer;
324
+ opacity: 0;
325
+ transition: opacity 0.2s;
326
+ }
327
+ .card:hover .save-btn { opacity: 1; }
328
+ .save-btn:hover { background: var(--accent-primary); border-color: var(--accent-primary); color: black; }
329
+
330
+ /* --- Toast Notification --- */
331
+ #toast-container {
332
+ position: fixed;
333
+ bottom: 20px;
334
+ right: 20px;
335
+ z-index: 1000;
336
+ display: flex;
337
+ flex-direction: column;
338
+ gap: 10px;
339
+ }
340
+ .toast {
341
+ background: rgba(10, 10, 15, 0.95);
342
+ border-left: 4px solid var(--accent-primary);
343
+ color: white;
344
+ padding: 1rem 1.5rem;
345
+ border-radius: 4px;
346
+ box-shadow: 0 5px 15px rgba(0,0,0,0.5);
347
+ animation: slideIn 0.3s ease-out;
348
+ font-size: 0.9rem;
349
+ display: flex;
350
+ align-items: center;
351
+ gap: 10px;
352
+ }
353
+ @keyframes slideIn {
354
+ from { transform: translateX(100%); opacity: 0; }
355
+ to { transform: translateX(0); opacity: 1; }
356
+ }
357
+
358
+ /* Responsive */
359
+ @media (max-width: 900px) {
360
+ main { grid-template-columns: 1fr; grid-template-rows: auto 1fr; overflow-y: auto; height: auto;}
361
+ aside { height: auto; max-height: 300px; border-right: none; border-bottom: 1px solid var(--border-color); }
362
+ #workspace { height: 600px; }
363
+ }
364
+ </style>
365
+ </head>
366
+ <body>
367
+
368
+ <!-- 3D Background -->
369
+ <canvas id="bg-canvas"></canvas>
370
+
371
+ <!-- Header -->
372
+ <header>
373
+ <div class="brand"><i class="fa-solid fa-dna"></i> CSS GEN-ALGO LAB</div>
374
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
375
+ Built with anycoder <i class="fa-solid fa-external-link-alt"></i>
376
+ </a>
377
+ </header>
378
+
379
+ <main>
380
+ <!-- Sidebar Controls -->
381
+ <aside>
382
+ <!-- CSS Models Mixer -->
383
+ <section>
384
+ <h2><i class="fa-solid fa-code"></i> CSS Models (Import)</h2>
385
+ <div class="control-group">
386
+ <label>Model A (Base)</label>
387
+ <textarea id="css-model-a" spellcheck="false">
388
+ .card-visual {
389
+ background: radial-gradient(circle, #2a2a2a, #000);
390
+ border: 2px solid #00f3ff;
391
+ }
392
+ .card-model-placeholder {
393
+ box-shadow: 0 0 15px #00f3ff;
394
+ border: 1px dashed #00f3ff;
395
+ border-radius: 10px;
396
+ }</textarea>
397
+ </div>
398
+ <div class="control-group">
399
+ <label>Model B (Variant)</label>
400
+ <textarea id="css-model-b" spellcheck="false">
401
+ .card-visual {
402
+ background: linear-gradient(135deg, #1a001a, #000);
403
+ border: 1px solid #bd00ff;
404
+ }
405
+ .card-model-placeholder {
406
+ box-shadow: 0 0 20px #bd00ff;
407
+ border-radius: 50%;
408
+ background: rgba(189, 0, 255, 0.1);
409
+ }</textarea>
410
+ </div>
411
+ <button id="btn-mix" style="margin-top: 10px;">
412
+ <i class="fa-solid fa-shuffle"></i> Mix & Regenerate
413
+ </button>
414
+ </section>
415
+
416
+ <!-- 3D Scanner / Source Code -->
417
+ <section>
418
+ <h2><i class="fa-solid fa-cube"></i> 3D Source Scanner</h2>
419
+ <div class="control-group">
420
+ <label>Source Code / URL / ID</label>
421
+ <textarea id="source-input" placeholder="Paste code, URL (.obj/.gltf), or ID here..."></textarea>
422
+ </div>
423
+ <button id="btn-scan" class="secondary">
424
+ <i class="fa-solid fa-radar"></i> Scan & Extract
425
+ </button>
426
+ <div id="scanner-preview">
427
+ <!-- Mini 3D Viewport -->
428
+ </div>
429
+ </section>
430
+
431
+ <!-- Performance Curve -->
432
+ <section>
433
+ <h2><i class="fa-solid fa-chart-line"></i> Performance</h2>
434
+ <canvas id="chart-canvas"></canvas>
435
+ </section>
436
+ </aside>
437
+
438
+ <!-- Gallery Workspace -->
439
+ <section id="workspace">
440
+ <div class="toolbar">
441
+ <h3>Generated Gallery (4:5)</h3>
442
+ <div class="zoom-control">
443
+ <i class="fa-solid fa-magnifying-glass-minus"></i>
444
+ <input type="range" id="zoom-slider" min="0.5" max="1.5" step="0.1" value="1">
445
+ <i class="fa-solid fa-magnifying-glass-plus"></i>
446
+ </div>
447
+ </div>
448
+
449
+ <div id="gallery-grid">
450
+ <!-- Cards will be injected here via JS -->
451
+ </div>
452
+ </section>
453
+ </main>
454
+
455
+ <!-- Toast Container -->
456
+ <div id="toast-container"></div>
457
+
458
+ <script>
459
+ // --- 1. GLOBAL STATE & CONFIG ---
460
+ const state = {
461
+ cards: [],
462
+ zoom: 1,
463
+ mixedCSS: '',
464
+ scannedModelType: 'cube' // cube, sphere, complex
465
+ };
466
+
467
+ const galleryGrid = document.getElementById('gallery-grid');
468
+ const zoomSlider = document.getElementById('zoom-slider');
469
+
470
+ // --- 2. UTILITIES ---
471
+ function showToast(message, type = 'info') {
472
+ const container = document.getElementById('toast-container');
473
+ const toast = document.createElement('div');
474
+ toast.className = 'toast';
475
+ toast.innerHTML = `<i class="fa-solid ${type === 'success' ? 'fa-check-circle' : 'fa-info-circle'}"></i> ${message}`;
476
+ container.appendChild(toast);
477
+ setTimeout(() => {
478
+ toast.style.opacity = '0';
479
+ setTimeout(() => toast.remove(), 300);
480
+ }, 3000);
481
+ }
482
+
483
+ function randomId() {
484
+ return Math.random().toString(36).substr(2, 9);
485
+ }
486
+
487
+ // --- 3. CSS GENETIC ALGORITHM (MIXER) ---
488
+ function mixCSSModels(cssA, cssB) {
489
+ // Split into blocks (separated by })
490
+ const blocksA = cssA.split('}').filter(b => b.trim() !== '');
491
+ const blocksB = cssB.split('}').filter(b => b.trim() !== '');
492
+
493
+ const mixedBlocks = [];
494
+
495
+ // Heuristic: Mix lines/blocks randomly
496
+ const maxLen = Math.max(blocksA.length, blocksB.length);
497
+
498
+ for(let i=0; i < maxLen; i++) {
499
+ const pickA = Math.random() > 0.5;
500
+ let block = '';
501
+
502
+ if(pickA && blocksA[i]) {
503
+ block = blocksA[i] + '}';
504
+ } else if (!pickA && blocksB[i]) {
505
+ block = blocksB[i] + '}';
506
+ } else if (blocksA[i]) {
507
+ block = blocksA[i] + '}';
508
+ } else if (blocksB[i]) {
509
+ block = blocksB[i] + '}';
510
+ }
511
+
512
+ // Randomly mutate a property value (Simulation)
513
+ if(block.includes('px') || block.includes('deg')) {
514
+ block = block.replace(/(\d+(\.\d+)?)/g, (match) => {
515
+ if(Math.random() > 0.8) return parseFloat(match) * (0.8 + Math.random() * 0.4);
516
+ return match;
517
+ });
518
+ }
519
+ mixedBlocks.push(block);
520
+ }
521
+ return mixedBlocks.join('\n');
522
+ }
523
+
524
+ // --- 4. CARD GENERATION ---
525
+ function createCard(styleString, index) {
526
+ const card = document.createElement('div');
527
+ card.className = 'card';
528
+ // Apply zoom via CSS variable or inline style handled by container,
529
+ // but specific mix styles need a scope.
530
+ // We will use a unique ID for the style tag to scope it to just this card or use inline styles.
531
+ // For simplicity and "mixing lines" demo, we'll create a scoped style element or inject classes.
532
+ // Better: Inject a style block specifically for this card's ID.
533
+
534
+ const cardId = `card-${randomId()}`;
535
+ card.id = cardId;
536
+
537
+ // Extract relevant parts or wrap the mixed CSS
538
+ // Assuming the mixed CSS targets .card-visual or .card-model-placeholder
539
+ const scopedStyle = styleString.replace(/\.card-visual/g, `#${cardId} .card-visual`)
540
+ .replace(/\.card-model-placeholder/g, `#${cardId} .card-model-placeholder`);
541
+
542
+ const styleEl = document.createElement('style');
543
+ styleEl.innerHTML = scopedStyle;
544
+ card.appendChild(styleEl);
545
+
546
+ // Content
547
+ const visual = document.createElement('div');
548
+ visual.className = 'card-visual';
549
+
550
+ // 3D Placeholder (Shrunk model)
551
+ const placeholder = document.createElement('div');
552
+ placeholder.className = 'card-model-placeholder';
553
+ // Icon based on scanned type
554
+ let iconClass = 'fa-cube';
555
+ if(state.scannedModelType === 'sphere') iconClass = 'fa-globe';
556
+ if(state.scannedModelType === 'complex') iconClass = 'fa-shapes';
557
+ placeholder.innerHTML = `<i class="fa-solid ${iconClass}"></i>`;
558
+
559
+ visual.appendChild(placeholder);
560
+
561
+ const info = document.createElement('div');
562
+ info.className = 'card-info';
563
+ info.innerHTML = `
564
+ <div class="card-title">Product #${index.toString().padStart(4, '0')}</div>
565
+ <div class="card-meta">
566
+ <span>Mix v${Math.floor(Math.random()*10)}</span>
567
+ <span style="color:var(--accent-primary)">Active</span>
568
+ </div>
569
+ `;
570
+
571
+ const saveBtn = document.createElement('div');
572
+ saveBtn.className = 'save-btn';
573
+ saveBtn.innerHTML = '<i class="fa-solid fa-floppy-disk"></i>';
574
+ saveBtn.onclick = (e) => {
575
+ e.stopPropagation();
576
+ showToast(`Design ${index} saved to library!`, 'success');
577
+ };
578
+
579
+ card.appendChild(saveBtn);
580
+ card.appendChild(visual);
581
+ card.appendChild(info);
582
+
583
+ return card;
584
+ }
585
+
586
+ function generateGallery() {
587
+ const cssA = document.getElementById('css-model-a').value;
588
+ const cssB = document.getElementById('css-model-b').value;
589
+
590
+ // Mix
591
+ const mixed = mixCSSModels(cssA, cssB);
592
+ state.mixedCSS = mixed;
593
+
594
+ // Clear current but keep some for effect? No, regenerate usually means new batch.
595
+ galleryGrid.innerHTML = '';
596
+
597
+ // Generate 8 cards
598
+ for(let i=0; i<8; i++) {
599
+ // Slight variation for each card
600
+ const variedMixed = mixCSSModels(mixed, cssB); // Mix again slightly
601
+ const card = createCard(variedMixed, i+1);
602
+ galleryGrid.appendChild(card);
603
+ }
604
+
605
+ // Update Chart
606
+ drawPerformanceChart();
607
+ showToast('Gallery Regenerated with Mixed CSS');
608
+ }
609
+
610
+ // --- 5. CHARTING (Performance Curve) ---
611
+ function drawPerformanceChart() {
612
+ const canvas = document.getElementById('chart-canvas');
613
+ const ctx = canvas.getContext('2d');
614
+ const w = canvas.width = canvas.offsetWidth;
615
+ const h = canvas.height = canvas.offsetHeight;
616
+
617
+ ctx.clearRect(0, 0, w, h);
618
+
619
+ // Grid
620
+ ctx.strokeStyle = 'rgba(255,255,255,0.1)';
621
+ ctx.beginPath();
622
+ for(let i=0; i<w; i+=20) { ctx.moveTo(i,0); ctx.lineTo(i,h); }
623
+ ctx.stroke();
624
+
625
+ // Random Curve
626
+ ctx.strokeStyle = '#00f3ff';
627
+ ctx.lineWidth = 2;
628
+ ctx.beginPath();
629
+
630
+ let points = [];
631
+ for(let i=0; i<=10; i++) {
632
+ points.push({
633
+ x: (w / 10) * i,
634
+ y: h - (Math.random() * h * 0.8 + h * 0.1)
635
+ });
636
+ }
637
+
638
+ ctx.moveTo(points[0].x, points[0].y);
639
+
640
+ // Catmull-Rom or simple Bezier smoothing
641
+ for (let i = 0; i < points.length - 1; i ++) {
642
+ const x_mid = (points[i].x + points[i + 1].x) / 2;
643
+ const y_mid = (points[i].y + points[i + 1].y) / 2;
644
+ const cp_x1 = (x_mid + points[i].x) / 2;
645
+ const cp_x2 = (x_mid + points[i + 1].x) / 2;
646
+ ctx.quadraticCurveTo(points[i].x, points[i].y, x_mid, y_mid);
647
+ }
648
+ ctx.lineTo(points[points.length-1].x, points[points.length-1].y);
649
+ ctx.stroke();
650
+
651
+ // Fill
652
+ ctx.lineTo(w, h);
653
+ ctx.lineTo(0, h);
654
+ ctx.fillStyle = 'linear-gradient(to top, rgba(0, 243, 255, 0.2), transparent)';
655
+ ctx.fill();
656
+ }
657
+
658
+ // --- 6. 3D LOGIC (Background & Scanner) ---
659
+
660
+ // -- A. Background Graph --
661
+ function initBackground3D() {
662
+ const canvas = document.getElementById('bg-canvas');
663
+ const renderer = new THREE.WebGLRenderer({ canvas: canvas, alpha: true, antialias: true });
664
+ renderer.setSize(window.innerWidth, window.innerHeight);
665
+ renderer.setPixelRatio(window.devicePixelRatio);
666
+
667
+ const scene = new THREE.Scene();
668
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
669
+ camera.position.z = 30;
670
+
671
+ // Particles
672
+ const geometry = new THREE.BufferGeometry();
673
+ const count = 500;
674
+ const positions = new Float32Array(count * 3);
675
+ for(let i=0; i<count*3; i++) {
676
+ positions[i] = (Math.random() - 0.5) * 60;
677
+ }
678
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
679
+
680
+ const material = new THREE.PointsMaterial({ color: 0x444444, size: 0.2 });
681
+ const particles = new THREE.Points(geometry, material);
682
+ scene.add(particles);
683
+
684
+ // Connecting Lines (Network)
685
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x222222, transparent: true, opacity: 0.3 });
686
+ const lineGeometry = new THREE.BufferGeometry();
687
+ // We'll update lines in animation loop or just use a wireframe object
688
+ const wireGeo = new THREE.IcosahedronGeometry(15, 1);
689
+ const wireframe = new THREE.LineSegments(new THREE.WireframeGeometry(wireGeo), lineMaterial);
690
+ scene.add(wireframe);
691
+
692
+ function animate() {
693
+ requestAnimationFrame(animate);
694
+ wireframe.rotation.x += 0.001;
695
+ wireframe.rotation.y += 0.001;
696
+ particles.rotation.y -= 0.0005;
697
+ renderer.render(scene, camera);
698
+ }
699
+ animate();
700
+
701
+ window.addEventListener('resize', () => {
702
+ camera.aspect = window.innerWidth / window.innerHeight;
703
+ camera.updateProjectionMatrix();
704
+ renderer.setSize(window.innerWidth, window.innerHeight);
705
+ });
706
+ }
707
+
708
+ // -- B. Scanner 3D Viewer --
709
+ let scannerRenderer, scannerScene, scannerCamera, scannerMesh;
710
+
711
+ function initScanner3D() {
712
+ const container = document.getElementById('scanner-preview');
713
+ const w = container.offsetWidth;
714
+ const h = container.offsetHeight;
715
+
716
+ scannerRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
717
+ scannerRenderer.setSize(w, h);
718
+ container.appendChild(scannerRenderer.domElement);
719
+
720
+ scannerScene = new THREE.Scene();
721
+ scannerCamera = new THREE.PerspectiveCamera(50, w / h, 0.1, 100);
722
+ scannerCamera.position.z = 4;
723
+
724
+ // Lights
725
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
726
+ scannerScene.add(ambientLight);
727
+ const pointLight = new THREE.PointLight(0xffffff, 1);
728
+ pointLight.position.set(2, 2, 2);
729
+ scannerScene.add(pointLight);
730
+
731
+ // Default Mesh
732
+ updateScannerMesh('cube');
733
+
734
+ function animateScanner() {
735
+ requestAnimationFrame(animateScanner);
736
+ if(scannerMesh) {
737
+ scannerMesh.rotation.x += 0.01;
738
+ scannerMesh.rotation.y += 0.01;
739
+ }
740
+ scannerRenderer.render(scannerScene, scannerCamera);
741
+ }
742
+ animateScanner();
743
+ }
744
+
745
+ function updateScannerMesh(type) {
746
+ if(scannerMesh) scannerScene.remove(scannerMesh);
747
+
748
+ let geometry;
749
+ state.scannedModelType = type;
750
+
751
+ if(type === 'sphere') geometry = new THREE.SphereGeometry(1, 32, 32);
752
+ else if(type === 'complex') geometry = new THREE.TorusKnotGeometry(0.7, 0.2, 100, 16);
753
+ else geometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);
754
+
755
+ // "Raytracing" look via Physical Material
756
+ const material = new THREE.MeshPhysicalMaterial({
757
+ color: 0x222222,
758
+ metalness: 0.9,
759
+ roughness: 0.1,
760
+ clearcoat: 1.0,
761
+ clearcoatRoughness: 0.1,
762
+ emissive: 0x000000
763
+ });
764
+
765
+ scannerMesh = new THREE.Mesh(geometry, material);
766
+ scannerScene.add(scannerMesh);
767
+ }
768
+
769
+ // --- 7. EVENT LISTENERS & LOGIC ---
770
+
771
+ // Zoom
772
+ zoomSlider.addEventListener('input', (e) => {
773
+ const val = e.target.value;
774
+ // We scale the grid items via transform
775
+ const cards = document.querySelectorAll('.card');
776
+ cards.forEach(card => {
777
+ card.style.transform = `scale(${val})`;
778
+ });
779
+ });
780
+
781
+ // Mix & Regenerate
782
+ document.getElementById('btn-mix').addEventListener('click', generateGallery);
783
+
784
+ // Scan Source Code
785
+ document.getElementById('btn-scan').addEventListener('click', () => {
786
+ const input = document.getElementById('source-input').value.toLowerCase();
787
+
788
+ // Intelligent Recognition Simulation
789
+ let detected = 'cube';
790
+ if(input.includes('sphere') || input.includes('round') || input.includes('ball')) detected = 'sphere';
791
+ if(input.includes('complex') || input.includes('torus') || input.includes('knot') || input.includes('advanced')) detected = 'complex';
792
+ if(input.includes('http') && input.includes('.obj')) detected = 'complex'; // Assume complex if URL
793
+
794
+ updateScannerMesh(detected);
795
+ showToast(`Source Analyzed: Detected ${detected.toUpperCase()} geometry`, 'success');
796
+
797
+ // Also regenerate gallery to apply new model type to cards
798
+ generateGallery();
799
+ });
800
+
801
+ // --- 8. INITIALIZATION ---
802
+ window.addEventListener('load', () => {
803
+ initBackground3D();
804
+ initScanner3D();
805
+ drawPerformanceChart();
806
+ generateGallery(); // Initial batch
807
+ });
808
+
809
+ </script>
810
+ </body>
811
+ </html>