Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- index.html +510 -744
index.html
CHANGED
|
@@ -1,760 +1,526 @@
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
|
|
|
| 3 |
<head>
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
.glitch-text::before, .glitch-text::after {
|
| 58 |
-
content: attr(data-text);
|
| 59 |
-
position: absolute;
|
| 60 |
-
top: 0; left: 0; width: 100%; height: 100%;
|
| 61 |
-
background: var(--bg-void);
|
| 62 |
-
}
|
| 63 |
-
.glitch-text::before {
|
| 64 |
-
left: 2px; text-shadow: -1px 0 var(--accent-magenta);
|
| 65 |
-
clip: rect(24px, 550px, 90px, 0); animation: glitch-anim-2 3s infinite linear alternate-reverse;
|
| 66 |
-
}
|
| 67 |
-
.glitch-text::after {
|
| 68 |
-
left: -2px; text-shadow: -1px 0 var(--accent-cyan);
|
| 69 |
-
clip: rect(85px, 550px, 140px, 0); animation: glitch-anim 2.5s infinite linear alternate-reverse;
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
@keyframes glitch-anim {
|
| 73 |
-
0% { clip: rect(14px, 9999px, 127px, 0); }
|
| 74 |
-
20% { clip: rect(80px, 9999px, 95px, 0); }
|
| 75 |
-
40% { clip: rect(10px, 9999px, 50px, 0); }
|
| 76 |
-
60% { clip: rect(60px, 9999px, 120px, 0); }
|
| 77 |
-
80% { clip: rect(20px, 9999px, 80px, 0); }
|
| 78 |
-
100% { clip: rect(100px, 9999px, 110px, 0); }
|
| 79 |
-
}
|
| 80 |
-
@keyframes glitch-anim-2 {
|
| 81 |
-
0% { clip: rect(65px, 9999px, 100px, 0); }
|
| 82 |
-
20% { clip: rect(10px, 9999px, 40px, 0); }
|
| 83 |
-
40% { clip: rect(90px, 9999px, 130px, 0); }
|
| 84 |
-
60% { clip: rect(30px, 9999px, 80px, 0); }
|
| 85 |
-
80% { clip: rect(70px, 9999px, 110px, 0); }
|
| 86 |
-
100% { clip: rect(50px, 9999px, 90px, 0); }
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
/* Scrollbars */
|
| 90 |
-
::-webkit-scrollbar { width: 6px; height: 6px; }
|
| 91 |
-
::-webkit-scrollbar-track { background: var(--bg-void); }
|
| 92 |
-
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
| 93 |
-
::-webkit-scrollbar-thumb:hover { background: var(--accent-cyan); }
|
| 94 |
-
|
| 95 |
-
/* Custom Inputs */
|
| 96 |
-
input[type=range] {
|
| 97 |
-
-webkit-appearance: none; width: 100%; background: transparent;
|
| 98 |
-
}
|
| 99 |
-
input[type=range]::-webkit-slider-thumb {
|
| 100 |
-
-webkit-appearance: none; height: 14px; width: 14px; border-radius: 50%;
|
| 101 |
-
background: var(--text); cursor: pointer; margin-top: -5px;
|
| 102 |
-
box-shadow: 0 0 5px var(--accent-cyan);
|
| 103 |
-
}
|
| 104 |
-
input[type=range]::-webkit-slider-runnable-track {
|
| 105 |
-
width: 100%; height: 4px; cursor: pointer; background: var(--border); border-radius: 2px;
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
.glass-panel {
|
| 109 |
-
background: rgba(10, 10, 15, 0.85);
|
| 110 |
-
backdrop-filter: blur(10px);
|
| 111 |
-
border: 1px solid rgba(255,255,255,0.08);
|
| 112 |
-
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
.neon-box {
|
| 116 |
-
border: 1px solid var(--border);
|
| 117 |
-
transition: all 0.2s;
|
| 118 |
-
}
|
| 119 |
-
.neon-box:hover { box-shadow: 0 0 15px rgba(0, 240, 255, 0.2); border-color: var(--accent-cyan); }
|
| 120 |
-
.neon-box.active { box-shadow: 0 0 20px var(--accent-cyan); border-color: var(--accent-cyan); }
|
| 121 |
-
|
| 122 |
-
.fx-card {
|
| 123 |
-
background: rgba(18, 18, 26, 0.9);
|
| 124 |
-
border-left: 3px solid var(--border);
|
| 125 |
-
transition: all 0.3s;
|
| 126 |
-
}
|
| 127 |
-
.fx-card:hover { background: rgba(25, 25, 35, 0.95); }
|
| 128 |
-
.fx-card.active { border-left-color: var(--accent-lime); background: rgba(0, 50, 30, 0.2); box-shadow: inset 0 0 20px rgba(0, 255, 100, 0.1); }
|
| 129 |
-
|
| 130 |
-
/* 3D Canvas Container */
|
| 131 |
-
#viewport-3d {
|
| 132 |
-
background: radial-gradient(circle at center, #1a1a24 0%, #000000 100%);
|
| 133 |
-
}
|
| 134 |
-
</style>
|
| 135 |
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 136 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 137 |
-
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
|
| 138 |
</head>
|
|
|
|
| 139 |
<body class="flex flex-col h-screen">
|
| 140 |
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
</div>
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
<button id="btn-export" class="flex items-center gap-2 px-4 py-2 rounded bg-gradient-to-r from-cyan-600 to-blue-700 hover:from-cyan-500 hover:to-blue-600 text-white shadow-[0_0_15px_rgba(0,240,255,0.4)] transition-all hover:shadow-[0_0_25px_rgba(0,240,255,0.6)] font-mono text-xs uppercase tracking-wider font-bold">
|
| 161 |
-
<i class="fa-solid fa-download"></i> Export Project
|
| 162 |
-
</button>
|
| 163 |
</div>
|
| 164 |
-
|
| 165 |
|
| 166 |
-
|
| 167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
|
| 169 |
-
<
|
| 170 |
-
|
| 171 |
-
<
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
</div>
|
| 186 |
-
</div>
|
| 187 |
-
|
| 188 |
-
<div id="fx-list" class="flex-1 overflow-y-auto p-3 space-y-2 custom-scrollbar">
|
| 189 |
-
<!-- FX Items Injected Here -->
|
| 190 |
-
</div>
|
| 191 |
-
|
| 192 |
-
<div class="p-4 border-t border-[#1a1a2e] bg-[#050508]">
|
| 193 |
-
<h3 class="text-[10px] uppercase text-gray-500 mb-2 font-bold tracking-wider">Media Input</h3>
|
| 194 |
-
<div class="grid grid-cols-2 gap-2">
|
| 195 |
-
<label class="cursor-pointer flex flex-col items-center justify-center p-3 rounded border border-[#1a1a2e] hover:border-cyan-500/50 hover:bg-cyan-900/10 transition group">
|
| 196 |
-
<i class="fa-solid fa-video text-cyan-500 mb-1 group-hover:text-cyan-300 transition"></i>
|
| 197 |
-
<span class="text-[10px] text-cyan-200 group-hover:text-white">Load Video</span>
|
| 198 |
-
<input type="file" id="inp-video" accept="video/*" class="hidden">
|
| 199 |
-
</label>
|
| 200 |
-
<label class="cursor-pointer flex flex-col items-center justify-center p-3 rounded border border-[#1a1a2e] hover:border-magenta-500/50 hover:bg-magenta-900/10 transition group">
|
| 201 |
-
<i class="fa-solid fa-music text-magenta-500 mb-1 group-hover:text-magenta-300 transition"></i>
|
| 202 |
-
<span class="text-[10px] text-cyan-200 group-hover:text-white">Load Audio</span>
|
| 203 |
-
<input type="file" id="inp-audio" accept="audio/*" class="hidden">
|
| 204 |
-
</label>
|
| 205 |
-
</div>
|
| 206 |
-
</div>
|
| 207 |
-
</aside>
|
| 208 |
-
|
| 209 |
-
<!-- CENTER: VIEWPORT -->
|
| 210 |
-
<section class="flex-1 relative flex flex-col items-center justify-center bg-[#030306] overflow-hidden">
|
| 211 |
-
|
| 212 |
-
<!-- 3D Canvas -->
|
| 213 |
-
<div id="viewport-3d" class="absolute inset-0 w-full h-full z-0">
|
| 214 |
-
<canvas id="glCanvas" class="w-full h-full object-contain"></canvas>
|
| 215 |
-
</div>
|
| 216 |
-
|
| 217 |
-
<!-- Overlay Info -->
|
| 218 |
-
<div class="absolute top-4 left-4 z-10 flex flex-col gap-2 pointer-events-none">
|
| 219 |
-
<div class="glass-panel px-3 py-2 rounded border-l-4 border-cyan-500">
|
| 220 |
-
<div class="text-[10px] text-cyan-300 uppercase font-bold">Current Engine</div>
|
| 221 |
-
<div class="text-xs font-mono text-white" id="engine-status">WebGL 2.0 // Three.js Core</div>
|
| 222 |
-
</div>
|
| 223 |
-
<div class="glass-panel px-3 py-2 rounded border-l-4 border-magenta-500 w-48">
|
| 224 |
-
<div class="text-[10px] text-magenta-300 uppercase font-bold">Audio Reactivity</div>
|
| 225 |
-
<div class="flex items-center gap-2 mt-1">
|
| 226 |
-
<div class="flex-1 h-1 bg-gray-800 rounded overflow-hidden">
|
| 227 |
-
<div id="audio-bar" class="h-full bg-magenta-500 w-0 transition-all duration-75"></div>
|
| 228 |
-
</div>
|
| 229 |
-
<span id="audio-val" class="text-[9px] font-mono text-magenta-300">0%</span>
|
| 230 |
-
</div>
|
| 231 |
-
</div>
|
| 232 |
-
</div>
|
| 233 |
-
|
| 234 |
-
<!-- Bottom Controls -->
|
| 235 |
-
<div class="absolute bottom-6 z-20 flex items-center gap-4 bg-[#00000080] backdrop-blur-md px-6 py-3 rounded-full border border-[#1a1a2e] shadow-[0_0_30px_rgba(0,0,0,0.8)]">
|
| 236 |
-
<button id="btn-play" class="w-10 h-10 rounded-full bg-white text-black hover:bg-cyan-400 transition flex items-center justify-center">
|
| 237 |
-
<i class="fa-solid fa-play text-sm ml-0.5"></i>
|
| 238 |
-
</button>
|
| 239 |
-
<div class="flex flex-col">
|
| 240 |
-
<span class="text-[9px] text-gray-400 uppercase tracking-widest">Time</span>
|
| 241 |
-
<span id="time-display" class="font-mono text-sm text-cyan-400">00:00:00</span>
|
| 242 |
-
</div>
|
| 243 |
-
<button id="btn-screenshot" class="px-3 py-1 rounded text-[10px] text-gray-300 hover:text-white hover:bg-white/10 transition border border-transparent hover:border-white/20">
|
| 244 |
-
<i class="fa-solid fa-camera mr-1"></i> Snapshot
|
| 245 |
-
</button>
|
| 246 |
-
</div>
|
| 247 |
-
</section>
|
| 248 |
-
|
| 249 |
-
<!-- RIGHT PANEL: STACK & SETTINGS -->
|
| 250 |
-
<aside class="w-80 bg-[#0a0a0f] border-l border-[#1a1a2e] flex flex-col overflow-hidden z-10">
|
| 251 |
-
|
| 252 |
-
<!-- Active Stack -->
|
| 253 |
-
<div class="p-4 border-b border-[#1a1a2e] bg-[#050508]">
|
| 254 |
-
<div class="flex items-center justify-between">
|
| 255 |
-
<h2 class="font-display text-sm text-cyan-400 tracking-widest">EFFECT STACK</h2>
|
| 256 |
-
<span id="stack-count" class="text-[10px] bg-cyan-900/30 text-cyan-300 px-2 py-0.5 rounded border border-cyan-900/50">0 / 12</span>
|
| 257 |
-
</div>
|
| 258 |
-
<div class="text-[9px] text-gray-500 mt-1">Drag to reorder • Click to adjust</div>
|
| 259 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
/
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
categories.forEach(cat => {
|
| 475 |
-
const header = document.createElement('div');
|
| 476 |
-
header.className = "text-[9px] text-gray-500 uppercase font-bold mt-4 mb-2 pl-2 tracking-widest border-b border-[#1a1a2e]";
|
| 477 |
-
header.innerText = cat;
|
| 478 |
-
list.appendChild(header);
|
| 479 |
-
|
| 480 |
-
FX_LIBRARY.filter(s => s.category === cat).forEach(shader => {
|
| 481 |
-
const el = document.createElement('div');
|
| 482 |
-
el.className = "fx-card p-3 rounded transition-all group cursor-pointer border-l-4 border-[#1a1a2e]";
|
| 483 |
-
el.innerHTML = `
|
| 484 |
-
<div class="flex justify-between items-start mb-1">
|
| 485 |
-
<span class="font-bold text-cyan-300 text-sm group-hover:text-white transition">${shader.name}</span>
|
| 486 |
-
<i class="fa-solid fa-plus-circle text-[10px] text-gray-500 group-hover:text-cyan-400 transition"></i>
|
| 487 |
-
</div>
|
| 488 |
-
<div class="text-[9px] text-gray-400 line-clamp-2">${shader.desc}</div>
|
| 489 |
-
`;
|
| 490 |
-
|
| 491 |
-
// Drag Start
|
| 492 |
-
el.draggable = true;
|
| 493 |
-
el.addEventListener('dragstart', (e) => {
|
| 494 |
-
e.dataTransfer.setData('text/plain', shader.id);
|
| 495 |
-
e.dataTransfer.setData('name', shader.name);
|
| 496 |
-
e.dataTransfer.setData('glsl', shader.glsl);
|
| 497 |
-
});
|
| 498 |
-
|
| 499 |
-
list.appendChild(el);
|
| 500 |
-
});
|
| 501 |
-
});
|
| 502 |
-
|
| 503 |
-
// Drop Zone (Stack List)
|
| 504 |
-
const stackList = document.getElementById('stack-list');
|
| 505 |
-
stackList.addEventListener('dragover', (e) => e.preventDefault());
|
| 506 |
-
stackList.addEventListener('drop', (e) => {
|
| 507 |
-
e.preventDefault();
|
| 508 |
-
const id = e.dataTransfer.getData('text/plain');
|
| 509 |
-
const name = e.dataTransfer.getData('name');
|
| 510 |
-
const glsl = e.dataTransfer.getData('glsl');
|
| 511 |
-
|
| 512 |
-
if (NexusOS.stack.length < NexusOS.maxEffects) {
|
| 513 |
-
NexusOS.addEffect(id, name, glsl);
|
| 514 |
-
} else {
|
| 515 |
-
alert("Effect Stack Full (Max 12)");
|
| 516 |
-
}
|
| 517 |
-
});
|
| 518 |
-
|
| 519 |
-
// Search
|
| 520 |
-
document.getElementById('search-fx').addEventListener('input', (e) => {
|
| 521 |
-
const term = e.target.value.toLowerCase();
|
| 522 |
-
const cards = document.querySelectorAll('.fx-card');
|
| 523 |
-
cards.forEach(card => {
|
| 524 |
-
const text = card.innerText.toLowerCase();
|
| 525 |
-
card.style.display = text.includes(term) ? 'block' : 'none';
|
| 526 |
-
});
|
| 527 |
-
});
|
| 528 |
-
|
| 529 |
-
// Global Settings
|
| 530 |
-
document.getElementById('global-res').addEventListener('input', (e) => {
|
| 531 |
-
document.getElementById('res-val').innerText = e.target.value + 'p';
|
| 532 |
-
// Logic to resize canvas would go here
|
| 533 |
-
});
|
| 534 |
-
document.getElementById('global-fps').addEventListener('input', (e) => {
|
| 535 |
-
document.getElementById('fps-val').innerText = parseFloat(e.target.value).toFixed(3);
|
| 536 |
-
});
|
| 537 |
-
|
| 538 |
-
// Play/Pause
|
| 539 |
-
document.getElementById('btn-play').addEventListener('click', () => {
|
| 540 |
-
if (NexusOS.video.paused) {
|
| 541 |
-
NexusOS.video.play();
|
| 542 |
-
document.getElementById('audio-src').play();
|
| 543 |
-
NexusOS.isPlaying = true;
|
| 544 |
-
document.getElementById('btn-play').innerHTML = '<i class="fa-solid fa-pause text-sm ml-0.5"></i>';
|
| 545 |
-
} else {
|
| 546 |
-
NexusOS.video.pause();
|
| 547 |
-
document.getElementById('audio-src').pause();
|
| 548 |
-
NexusOS.isPlaying = false;
|
| 549 |
-
document.getElementById('btn-play').innerHTML = '<i class="fa-solid fa-play text-sm ml-0.5"></i>';
|
| 550 |
-
}
|
| 551 |
-
});
|
| 552 |
-
|
| 553 |
-
// Randomize
|
| 554 |
-
document.getElementById('btn-randomize').addEventListener('click', () => {
|
| 555 |
-
// Clear stack
|
| 556 |
-
NexusOS.stack.forEach(() => NexusOS.removeEffect(NexusOS.stack[0].uid));
|
| 557 |
-
|
| 558 |
-
// Add random
|
| 559 |
-
const count = Math.floor(Math.random() * 5) + 2;
|
| 560 |
-
for(let i=0; i<count; i++) {
|
| 561 |
-
const rnd = FX_LIBRARY[Math.floor(Math.random() * FX_LIBRARY.length)];
|
| 562 |
-
NexusOS.addEffect(rnd.id, rnd.name, rnd.glsl);
|
| 563 |
-
}
|
| 564 |
-
});
|
| 565 |
-
|
| 566 |
-
// Export
|
| 567 |
-
document.getElementById('btn-export').addEventListener('click', () => {
|
| 568 |
-
alert("Project exported to local storage as JSON config.");
|
| 569 |
-
const config = {
|
| 570 |
-
effects: NexusOS.stack.map(p => ({ id: p.def.id, amount: p.uniforms.amount.value })),
|
| 571 |
-
resolution: document.getElementById('global-res').value,
|
| 572 |
-
fps: document.getElementById('global-fps').value
|
| 573 |
-
};
|
| 574 |
-
const blob = new Blob([JSON.stringify(config)], {type: 'application/json'});
|
| 575 |
-
const a = document.createElement('a');
|
| 576 |
-
a.href = URL.createObjectURL(blob);
|
| 577 |
-
a.download = 'nexus_project_config.json';
|
| 578 |
-
a.click();
|
| 579 |
-
});
|
| 580 |
-
|
| 581 |
-
// APK Builder
|
| 582 |
-
document.getElementById('btn-build-apk').addEventListener('click', () => {
|
| 583 |
-
NexusOS.buildAndroidProject();
|
| 584 |
-
});
|
| 585 |
-
},
|
| 586 |
-
|
| 587 |
-
setupAudio: () => {
|
| 588 |
-
NexusOS.video = document.getElementById('video-src');
|
| 589 |
-
if(!NexusOS.video) {
|
| 590 |
-
// Create placeholder if not loaded
|
| 591 |
-
NexusOS.video = document.createElement('video');
|
| 592 |
-
NexusOS.video.id = 'video-src';
|
| 593 |
-
NexusOS.video.playsInline = true;
|
| 594 |
-
NexusOS.video.loop = true;
|
| 595 |
-
NexusOS.video.src = "https://media.w3.org/2010/05/sintel/trailer_hd.mp4"; // Fallback
|
| 596 |
-
document.body.appendChild(NexusOS.video);
|
| 597 |
-
}
|
| 598 |
-
|
| 599 |
-
// Load Audio
|
| 600 |
-
const audioEl = document.getElementById('audio-src');
|
| 601 |
-
if(!audioEl) {
|
| 602 |
-
const audio = document.createElement('audio');
|
| 603 |
-
audio.id = 'audio-src';
|
| 604 |
-
audio.crossOrigin = "anonymous";
|
| 605 |
-
document.body.appendChild(audio);
|
| 606 |
-
}
|
| 607 |
-
|
| 608 |
-
// File Inputs
|
| 609 |
-
document.getElementById('inp-video').addEventListener('change', (e) => {
|
| 610 |
-
const file = e.target.files[0];
|
| 611 |
-
if (file) {
|
| 612 |
-
const url = URL.createObjectURL(file);
|
| 613 |
-
NexusOS.video.src = url;
|
| 614 |
-
NexusOS.video.load();
|
| 615 |
-
NexusOS.video.play().then(() => {
|
| 616 |
-
NexusOS.isPlaying = true;
|
| 617 |
-
document.getElementById('btn-play').innerHTML = '<i class="fa-solid fa-pause text-sm ml-0.5"></i>';
|
| 618 |
-
});
|
| 619 |
-
}
|
| 620 |
-
});
|
| 621 |
-
|
| 622 |
-
document.getElementById('inp-audio').addEventListener('change', (e) => {
|
| 623 |
-
const file = e.target.files[0];
|
| 624 |
-
if (file) {
|
| 625 |
-
const url = URL.createObjectURL(file);
|
| 626 |
-
const audioEl = document.getElementById('audio-src');
|
| 627 |
-
audioEl.src = url;
|
| 628 |
-
|
| 629 |
-
if (!NexusOS.audioCtx) {
|
| 630 |
-
NexusOS.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
| 631 |
-
const src = NexusOS.audioCtx.createMediaElementSource(audioEl);
|
| 632 |
-
NexusOS.analyser = NexusOS.audioCtx.createAnalyser();
|
| 633 |
-
NexusOS.analyser.fftSize = 256;
|
| 634 |
-
src.connect(NexusOS.analyser);
|
| 635 |
-
NexusOS.analyser.connect(NexusOS.audioCtx.destination);
|
| 636 |
-
NexusOS.dataArray = new Uint8Array(NexusOS.analyser.frequencyBinCount);
|
| 637 |
-
}
|
| 638 |
-
audioEl.play();
|
| 639 |
-
}
|
| 640 |
-
});
|
| 641 |
-
},
|
| 642 |
-
|
| 643 |
-
addEffect: (id, name, glslCode) => {
|
| 644 |
-
const def = FX_LIBRARY.find(s => s.id === id);
|
| 645 |
-
if (!def) return;
|
| 646 |
-
|
| 647 |
-
const myUniforms = {
|
| 648 |
-
"tDiffuse": { value: null },
|
| 649 |
-
"amount": { value: 0.5 },
|
| 650 |
-
"time": { value: 0.0 },
|
| 651 |
-
"resolution": { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
|
| 652 |
-
"uAudio": { value: 0.0 }
|
| 653 |
-
};
|
| 654 |
-
|
| 655 |
-
const myShader = {
|
| 656 |
-
uniforms: myUniforms,
|
| 657 |
-
vertexShader: `
|
| 658 |
-
varying vec2 vUv;
|
| 659 |
-
void main() {
|
| 660 |
-
vUv = uv;
|
| 661 |
-
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
| 662 |
-
}`,
|
| 663 |
-
fragmentShader: glslCode
|
| 664 |
-
};
|
| 665 |
-
|
| 666 |
-
const pass = new ShaderPass(myShader);
|
| 667 |
-
pass.uid = Date.now() + Math.random();
|
| 668 |
-
pass.def = def;
|
| 669 |
-
|
| 670 |
-
// Insert at top
|
| 671 |
-
NexusOS.composer.insertPass(pass, 1);
|
| 672 |
-
NexusOS.stack.unshift(pass);
|
| 673 |
-
NexusOS.renderStackUI();
|
| 674 |
-
},
|
| 675 |
-
|
| 676 |
-
removeEffect: (uid) => {
|
| 677 |
-
const idx = NexusOS.stack.findIndex(p => p.uid === uid);
|
| 678 |
-
if (idx > -1) {
|
| 679 |
-
NexusOS.composer.removePass(NexusOS.stack[idx]);
|
| 680 |
-
NexusOS.stack.splice(idx, 1);
|
| 681 |
-
NexusOS.renderStackUI();
|
| 682 |
-
}
|
| 683 |
-
},
|
| 684 |
-
|
| 685 |
-
renderStackUI: () => {
|
| 686 |
-
const container = document.getElementById('stack-list');
|
| 687 |
-
document.getElementById('stack-count').innerText = `${NexusOS.stack.length} / ${NexusOS.maxEffects}`;
|
| 688 |
-
|
| 689 |
-
if (NexusOS.stack.length === 0) {
|
| 690 |
-
container.innerHTML = '<div class="text-center py-10 text-gray-600 text-sm border-2 border-dashed border-gray-800 rounded"><i class="fa-solid fa-layer-group text-2xl mb-2 opacity-50"></i>No effects active. Drag from library.</div>';
|
| 691 |
-
return;
|
| 692 |
-
}
|
| 693 |
-
|
| 694 |
-
container.innerHTML = '';
|
| 695 |
-
NexusOS.stack.forEach((pass, i) => {
|
| 696 |
-
const el = document.createElement('div');
|
| 697 |
-
el.className = "neon-box active p-3 rounded mb-2";
|
| 698 |
-
el.innerHTML = `
|
| 699 |
-
<div class="flex justify-between items-center mb-2">
|
| 700 |
-
<div class="flex items-center gap-2">
|
| 701 |
-
<span class="text-[9px] bg-cyan-900 text-cyan-300 px-1 rounded">${i+1}</span>
|
| 702 |
-
<span class="text-sm font-bold text-cyan-300">${pass.def.name}</span>
|
| 703 |
-
</div>
|
| 704 |
-
<button class="text-red-500 hover:text-white transition" onclick="NexusOS.removeEffect(${pass.uid})">
|
| 705 |
-
<i class="fa-solid fa-trash"></i>
|
| 706 |
-
</button>
|
| 707 |
-
</div>
|
| 708 |
-
<div class="flex items-center gap-2">
|
| 709 |
-
<span class="text-[9px] text-gray-500">INTENSITY</span>
|
| 710 |
-
<input type="range" class="w-full h-1 bg-gray-800 rounded appearance-none cursor-pointer"
|
| 711 |
-
min="0" max="1" step="0.01" value="${pass.uniforms.amount.value}"
|
| 712 |
-
oninput="NexusOS.updateEffect(${pass.uid}, this.value)">
|
| 713 |
-
</div>
|
| 714 |
-
`;
|
| 715 |
-
container.appendChild(el);
|
| 716 |
-
});
|
| 717 |
-
},
|
| 718 |
-
|
| 719 |
-
updateEffect: (uid, val) => {
|
| 720 |
-
const pass = NexusOS.stack.find(p => p.uid === uid);
|
| 721 |
-
if (pass) pass.uniforms.amount.value = parseFloat(val);
|
| 722 |
-
},
|
| 723 |
-
|
| 724 |
-
buildAndroidProject: () => {
|
| 725 |
-
const appName = document.getElementById('app-name').value || "NexusApp";
|
| 726 |
-
const appId = document.getElementById('app-id').value || "com.nexus.app";
|
| 727 |
-
|
| 728 |
-
if(!appId.includes('.')) {
|
| 729 |
-
alert("Invalid Bundle ID format. Use com.company.app");
|
| 730 |
-
return;
|
| 731 |
-
}
|
| 732 |
-
|
| 733 |
-
const zip = new JSZip();
|
| 734 |
-
const assets = {};
|
| 735 |
-
|
| 736 |
-
// Generate a simple HTML file for the app
|
| 737 |
-
const htmlContent = `
|
| 738 |
-
<!DOCTYPE html>
|
| 739 |
-
<html>
|
| 740 |
-
<head>
|
| 741 |
-
<title>${appName}</title>
|
| 742 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 743 |
-
<style>
|
| 744 |
-
body { margin:0; background:#000; overflow:hidden; }
|
| 745 |
-
canvas { display:block; width:100%; height:100%; }
|
| 746 |
-
.anycoder { position:fixed; bottom:5px; right:5px; font-size:10px; color:#555; z-index:9999; }
|
| 747 |
-
</style>
|
| 748 |
-
</head>
|
| 749 |
-
<body>
|
| 750 |
-
<canvas id="glCanvas"></canvas>
|
| 751 |
-
<div class="anycoder">Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Nexus FX Forge</a></div>
|
| 752 |
-
<script>
|
| 753 |
-
// Simplified logic for WebView
|
| 754 |
-
const canvas = document.getElementById('glCanvas');
|
| 755 |
-
const gl = canvas.getContext('webgl');
|
| 756 |
-
// ... (WebGL init code would go here, simplified for demo)
|
| 757 |
-
canvas.width = window.innerWidth; canvas.height = window.innerHeight;
|
| 758 |
-
<\/script>
|
| 759 |
-
</body>
|
| 760 |
-
</html>
|
|
|
|
| 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.0">
|
| 7 |
+
<title>NEXUS FX OS | AI Sci-Fi Studio + VisionFX Pro</title>
|
| 8 |
+
|
| 9 |
+
<!-- Libraries -->
|
| 10 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 11 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"></script>
|
| 12 |
+
<script src="https://cdn.jsdelivr.net/npm/mathjs@11.8.0/lib/browser/math.min.js"></script>
|
| 13 |
+
<script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
|
| 14 |
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script>
|
| 15 |
+
|
| 16 |
+
<!-- Three.js Import Map -->
|
| 17 |
+
<script type="importmap">
|
| 18 |
+
{
|
| 19 |
+
"imports": {
|
| 20 |
+
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
|
| 21 |
+
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
</script>
|
| 25 |
+
|
| 26 |
+
<style>
|
| 27 |
+
:root {
|
| 28 |
+
--bg-void: #030306;
|
| 29 |
+
--bg-panel: #0a0a0f;
|
| 30 |
+
--bg-card: #12121a;
|
| 31 |
+
--border: #1a1a2e;
|
| 32 |
+
--accent-cyan: #00f0ff;
|
| 33 |
+
--accent-magenta: #ff00aa;
|
| 34 |
+
--accent-lime: #00ff66;
|
| 35 |
+
--accent-red: #ff2244;
|
| 36 |
+
--text: #e8e8f0;
|
| 37 |
+
--text-dim: #6a6a7a;
|
| 38 |
+
--math-bg: #000000;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
* { box-sizing: border-box; margin: 0; padding: 0; outline: none; }
|
| 42 |
+
|
| 43 |
+
body {
|
| 44 |
+
font-family: 'JetBrains Mono', monospace;
|
| 45 |
+
background: var(--bg-void);
|
| 46 |
+
color: var(--text);
|
| 47 |
+
overflow: hidden;
|
| 48 |
+
height: 100vh;
|
| 49 |
+
background-image:
|
| 50 |
+
radial-gradient(circle at 10% 20%, rgba(0, 240, 255, 0.1) 0%, transparent 20%),
|
| 51 |
+
radial-gradient(circle at 90% 80%, rgba(255, 0, 170, 0.1) 0%, transparent 20%);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.font-display { font-family: 'Orbitron', sans-serif; }
|
| 55 |
+
|
| 56 |
+
/* Glitch Text Animation */
|
| 57 |
+
.glitch-text {
|
| 58 |
+
position: relative;
|
| 59 |
+
z-index: 1;
|
| 60 |
+
}
|
| 61 |
+
.glitch-text::before, .glitch-text::after {
|
| 62 |
+
content: attr(data-text);
|
| 63 |
+
position: absolute;
|
| 64 |
+
top: 0; left: 0; width: 100%; height: 100%;
|
| 65 |
+
background: var(--bg-void); z-index: -1;
|
| 66 |
+
}
|
| 67 |
+
.glitch-text::before {
|
| 68 |
+
left: 2px; text-shadow: -1px 0 var(--accent-magenta);
|
| 69 |
+
clip: rect(24px, 550px, 90px, 0);
|
| 70 |
+
animation: glitch-anim-2 3s infinite linear alternate-reverse;
|
| 71 |
+
}
|
| 72 |
+
.glitch-text::after {
|
| 73 |
+
left: -2px; text-shadow: -1px 0 var(--accent-cyan);
|
| 74 |
+
clip: rect(85px, 550px, 140px, 0);
|
| 75 |
+
animation: glitch-anim 2.5s infinite linear alternate-reverse;
|
| 76 |
+
}
|
| 77 |
+
@keyframes glitch-anim { /* ... (Same as original) ... */
|
| 78 |
+
0% { clip: rect(14px, 9999px, 127px, 0); } 20% { clip: rect(80px, 9999px, 95px, 0); }
|
| 79 |
+
40% { clip: rect(10px, 9999px, 50px, 0); } 60% { clip: rect(60px, 9999px, 120px, 0); }
|
| 80 |
+
80% { clip: rect(20px, 9999px, 80px, 0); } 100% { clip: rect(100px, 9999px, 110px, 0); }
|
| 81 |
+
}
|
| 82 |
+
@keyframes glitch-anim-2 { /* ... (Same as original) ... */
|
| 83 |
+
0% { clip: rect(65px, 9999px, 100px, 0); } 20% { clip: rect(10px, 9999px, 40px, 0); }
|
| 84 |
+
40% { clip: rect(90px, 9999px, 130px, 0); } 60% { clip: rect(30px, 9999px, 80px, 0); }
|
| 85 |
+
80% { clip: rect(70px, 9999px, 110px, 0); } 100% { clip: rect(50px, 9999px, 90px, 0); }
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
/* Scrollbars & Inputs */
|
| 89 |
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
| 90 |
+
::-webkit-scrollbar-track { background: var(--bg-void); }
|
| 91 |
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
| 92 |
+
::-webkit-scrollbar-thumb:hover { background: var(--accent-cyan); }
|
| 93 |
|
| 94 |
+
input[type=range] {
|
| 95 |
+
-webkit-appearance: none; width: 100%; background: transparent;
|
| 96 |
+
cursor: grab; transition: all 0.2s;
|
| 97 |
+
}
|
| 98 |
+
input[type=range]:active { cursor: grabbing; }
|
| 99 |
+
input[type=range]::-webkit-slider-thumb {
|
| 100 |
+
-webkit-appearance: none; height: 14px; width: 14px; border-radius: 50%;
|
| 101 |
+
background: var(--text); cursor: pointer; margin-top: -5px;
|
| 102 |
+
box-shadow: 0 0 5px var(--accent-cyan);
|
| 103 |
+
}
|
| 104 |
+
input[type=range]::-webkit-slider-runnable-track {
|
| 105 |
+
width: 100%; height: 4px; cursor: pointer; background: var(--border); border-radius: 2px;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
/* Glassmorphism & Neon */
|
| 109 |
+
.glass-panel {
|
| 110 |
+
background: rgba(10, 10, 15, 0.85); backdrop-filter: blur(10px);
|
| 111 |
+
border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
|
| 112 |
+
}
|
| 113 |
+
.neon-box { border: 1px solid var(--border); transition: all 0.2s; }
|
| 114 |
+
.neon-box:hover { box-shadow: 0 0 15px rgba(0, 240, 255, 0.2); border-color: var(--accent-cyan); }
|
| 115 |
+
.neon-box.active { box-shadow: 0 0 20px var(--accent-cyan); border-color: var(--accent-cyan); }
|
| 116 |
|
| 117 |
+
.fx-card { background: rgba(18, 18, 26, 0.9); border-left: 3px solid var(--border); transition: all 0.3s; }
|
| 118 |
+
.fx-card:hover { background: rgba(25, 25, 35, 0.95); }
|
| 119 |
+
|
| 120 |
+
/* Math Engine UI */
|
| 121 |
+
.math-container { position: relative; }
|
| 122 |
+
.math-input {
|
| 123 |
+
width: 100%; background: var(--math-bg); border: 1px solid var(--border);
|
| 124 |
+
color: var(--accent-cyan); font-family: 'Courier New', monospace; padding: 8px;
|
| 125 |
+
min-height: 40px; resize: vertical; font-size: 14px; transition: border 0.3s;
|
| 126 |
+
}
|
| 127 |
+
.math-input:focus { border-color: var(--accent-lime); outline: none; }
|
| 128 |
+
.math-btn { background: #222; border: 1px solid #444; color: #aaa; cursor: pointer; padding: 4px 8px; font-size: 10px; }
|
| 129 |
+
.math-btn:hover { background: var(--accent-cyan); color: #000; }
|
| 130 |
+
|
| 131 |
+
.math-popup {
|
| 132 |
+
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
| 133 |
+
background: var(--bg-panel); border: 1px solid var(--accent-cyan); padding: 20px;
|
| 134 |
+
z-index: 5000; box-shadow: 0 0 50px rgba(0, 240, 255, 0.2); width: 90%; max-width: 500px;
|
| 135 |
+
display: none; animation: popIn 0.3s ease;
|
| 136 |
+
}
|
| 137 |
+
@keyframes popIn { from { opacity: 0; transform: translate(-50%, -45%); } to { opacity: 1; transform: translate(-50%, -50%); } }
|
| 138 |
+
|
| 139 |
+
/* Split View Controls */
|
| 140 |
+
.split-view-handle {
|
| 141 |
+
width: 10px; background: #000; cursor: col-resize; border-left: 1px solid var(--border); border-right: 1px solid var(--border);
|
| 142 |
+
}
|
| 143 |
+
.split-view-handle:hover { background: var(--accent-cyan); }
|
| 144 |
+
|
| 145 |
+
/* 3D Canvas Container */
|
| 146 |
+
#viewport-3d { background: radial-gradient(circle at center, #1a1a24 0%, #000000 100%); }
|
| 147 |
+
|
| 148 |
+
/* Mobile Responsive Tweaks */
|
| 149 |
+
@media (max-width: 768px) {
|
| 150 |
+
.split-view-container { flex-direction: column; }
|
| 151 |
+
.split-view-handle { width: 100%; height: 10px; cursor: row-resize; border-left: none; border-right: none; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
| 152 |
+
.panel-left, .panel-right { flex: 1; }
|
| 153 |
+
}
|
| 154 |
+
</style>
|
| 155 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 156 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 157 |
+
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
</head>
|
| 159 |
+
|
| 160 |
<body class="flex flex-col h-screen">
|
| 161 |
|
| 162 |
+
<!-- HEADER -->
|
| 163 |
+
<header class="h-16 bg-[#050508] border-b border-[#1a1a2e] flex items-center justify-between px-6 z-50 shadow-[0_5px_20px_rgba(0,0,0,0.8)]">
|
| 164 |
+
<div class="flex items-center gap-4">
|
| 165 |
+
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-cyan-500 to-magenta-600 flex items-center justify-center shadow-[0_0_15px_rgba(0,240,255,0.5)]">
|
| 166 |
+
<i class="fa-solid fa-cube text-white text-xl"></i>
|
| 167 |
+
</div>
|
| 168 |
+
<div>
|
| 169 |
+
<h1 class="font-display text-xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-magenta-400 glitch-text" data-text="NEXUS FX OS">
|
| 170 |
+
NEXUS FX OS
|
| 171 |
+
</h1>
|
| 172 |
+
<div class="text-xs text-cyan-500/70 font-mono tracking-widest">INTELLIGENT MEDIA ENGINE // V.3.0.0</div>
|
| 173 |
+
</div>
|
| 174 |
+
</div>
|
| 175 |
+
<div class="flex items-center gap-3">
|
| 176 |
+
<button id="btn-randomize" class="hidden md:flex items-center gap-2 px-4 py-2 rounded bg-[#1a1a2e] hover:bg-[#2a2a4e] text-cyan-400 border border-[#1a1a2e] transition-all hover:border-cyan-500/50 hover:shadow-[0_0_10px_rgba(0,240,255,0.3)] font-mono text-xs uppercase tracking-wider">
|
| 177 |
+
<i class="fa-solid fa-shuffle"></i> Randomize
|
| 178 |
+
</button>
|
| 179 |
+
<button id="btn-export" class="flex items-center gap-2 px-4 py-2 rounded bg-gradient-to-r from-cyan-600 to-blue-700 hover:from-cyan-500 hover:to-blue-600 text-white shadow-[0_0_15px_rgba(0,240,255,0.4)] transition-all hover:shadow-[0_0_25px_rgba(0,240,255,0.6)] font-mono text-xs uppercase tracking-wider font-bold">
|
| 180 |
+
<i class="fa-solid fa-download"></i> Export
|
| 181 |
+
</button>
|
| 182 |
+
</div>
|
| 183 |
+
</header>
|
| 184 |
+
|
| 185 |
+
<!-- MAIN LAYOUT -->
|
| 186 |
+
<main class="flex-1 flex overflow-hidden split-view-container">
|
| 187 |
+
|
| 188 |
+
<!-- LEFT PANEL: FX LIBRARY & MATH ENGINE -->
|
| 189 |
+
<aside class="w-96 bg-[#0a0a0f] border-r border-[#1a1a2e] flex flex-col overflow-hidden relative">
|
| 190 |
+
|
| 191 |
+
<!-- FX Library Section -->
|
| 192 |
+
<div class="p-4 border-b border-[#1a1a2e] bg-[#050508]">
|
| 193 |
+
<div class="flex items-center justify-between mb-3">
|
| 194 |
+
<h2 class="font-display text-sm text-cyan-400 tracking-widest">FX LIBRARY <span class="text-[10px] bg-cyan-900/30 px-2 py-0.5 rounded ml-2">100+ MODULES</span></h2>
|
| 195 |
+
<div class="relative">
|
| 196 |
+
<i class="fa-solid fa-search absolute left-3 top-2.5 text-cyan-500/50 text-xs"></i>
|
| 197 |
+
<input type="text" id="search-fx" placeholder="Search shaders..." class="w-full pl-8 pr-3 py-1.5 bg-[#12121a] border border-[#1a1a2e] rounded text-[10px] text-cyan-200 focus:border-cyan-500 focus:outline-none transition-colors">
|
| 198 |
+
</div>
|
| 199 |
</div>
|
| 200 |
+
<div class="flex gap-2 overflow-x-auto pb-2">
|
| 201 |
+
<span class="px-2 py-1 rounded text-[9px] bg-[#1a1a2e] text-cyan-300 border border-[#1a1a2e] cursor-pointer hover:bg-cyan-900/30 transition">ALL</span>
|
| 202 |
+
<span class="px-2 py-1 rounded text-[9px] bg-[#1a1a2e] text-purple-300 border border-[#1a1a2e] cursor-pointer hover:bg-purple-900/30 transition">COLOR</span>
|
| 203 |
+
<span class="px-2 py-1 rounded text-[9px] bg-[#1a1a2e] text-red-300 border border-[#1a1a2e] cursor-pointer hover:bg-red-900/30 transition">GLITCH</span>
|
| 204 |
+
<span class="px-2 py-1 rounded text-[9px] bg-[#1a1a2e] text-green-300 border border-[#1a1a2e] cursor-pointer hover:bg-green-900/30 transition">GEOMETRY</span>
|
| 205 |
+
<span class="px-2 py-1 rounded text-[9px] bg-[#1a1a2e] text-yellow-300 border border-[#1a1a2e] cursor-pointer hover:bg-yellow-900/30 transition">AUDIO</span>
|
|
|
|
|
|
|
|
|
|
| 206 |
</div>
|
| 207 |
+
</div>
|
| 208 |
|
| 209 |
+
<div id="fx-list" class="flex-1 overflow-y-auto p-3 space-y-2 custom-scrollbar relative z-10">
|
| 210 |
+
<!-- FX Items Injected Here -->
|
| 211 |
+
<div class="text-center py-10 text-gray-600 text-sm">
|
| 212 |
+
<i class="fa-solid fa-list text-2xl mb-2 opacity-50"></i> Drag effects or use Math Engine below
|
| 213 |
+
</div>
|
| 214 |
+
</div>
|
| 215 |
+
|
| 216 |
+
<!-- Math Engine Section (Bottom of Left Panel) -->
|
| 217 |
+
<div class="p-4 border-t border-[#1a1a2e] bg-[#050508] z-20">
|
| 218 |
+
<div class="flex items-center justify-between mb-2">
|
| 219 |
+
<h3 class="font-display text-sm text-magenta-400 tracking-widest">MATH ENGINE // V.3</h3>
|
| 220 |
+
<button id="btn-spread" class="text-[10px] bg-magenta-900/20 text-magenta-300 px-2 py-0.5 rounded border border-magenta-900/50 hover:bg-magenta-900/50 transition flex items-center gap-1">
|
| 221 |
+
<i class="fa-solid fa-expand"></i> Split View
|
| 222 |
+
</button>
|
| 223 |
+
</div>
|
| 224 |
|
| 225 |
+
<div class="space-y-2">
|
| 226 |
+
<div class="flex items-center gap-2">
|
| 227 |
+
<button id="btn-start-stop" class="flex-1 py-2 rounded bg-[#1a1a2e] hover:bg-[#2a2a4e] text-xs text-cyan-300 border border-[#1a1a2e] transition flex items-center justify-center gap-2">
|
| 228 |
+
<i class="fa-solid fa-play" id="play-icon"></i> <span id="play-text">Start Flow</span>
|
| 229 |
+
</button>
|
| 230 |
+
<button id="btn-clear" class="px-2 py-2 rounded bg-red-900/20 text-red-400 hover:bg-red-900/40 transition">
|
| 231 |
+
<i class="fa-solid fa-trash"></i>
|
| 232 |
+
</button>
|
| 233 |
+
</div>
|
| 234 |
+
|
| 235 |
+
<div class="math-container">
|
| 236 |
+
<textarea id="math-input" class="math-input" placeholder="Enter Formula (e.g., sin(x) * cos(y) + 0.5 * time)..." spellcheck="false"></textarea>
|
| 237 |
+
<div class="absolute top-2 right-2 flex gap-1">
|
| 238 |
+
<button class="math-btn" id="btn-history"><i class="fa-solid fa-history"></i> H</button>
|
| 239 |
+
<button class="math-btn" id="btn-calc"><i class="fa-solid fa-calculator"></i> C</button>
|
| 240 |
+
<button class="math-btn" id="btn-apply"><i class="fa-solid fa-check"></i></button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
</div>
|
| 242 |
+
</div>
|
| 243 |
+
|
| 244 |
+
<div id="math-output" class="text-[9px] text-gray-400 font-mono min-h-[16px]">
|
| 245 |
+
Waiting for input...
|
| 246 |
+
</div>
|
| 247 |
+
|
| 248 |
+
<div id="generated-sliders" class="space-y-3 pt-2">
|
| 249 |
+
<!-- Dynamic Sliders appear here -->
|
| 250 |
+
</div>
|
| 251 |
+
</div>
|
| 252 |
|
| 253 |
+
<div class="mt-4 pt-3 border-t border-[#1a1a2e]">
|
| 254 |
+
<h4 class="text-[10px] text-gray-500 uppercase font-bold mb-2">Pattern Extractor</h4>
|
| 255 |
+
<textarea id="pattern-input" class="w-full h-24 bg-[#000] border border-[#1a1a2e] rounded p-2 text-[9px] text-cyan-200 font-mono mb-2" placeholder="Paste code to extract patterns (URLs, Functions, Comments)..."></textarea>
|
| 256 |
+
<div class="flex gap-2">
|
| 257 |
+
<select id="pattern-select" class="flex-1 bg-[#12121a] border border-[#1a1a2e] rounded p-1 text-[9px] text-cyan-200">
|
| 258 |
+
<option value="urls">Download Files (pdf, zip...)</option>
|
| 259 |
+
<option value="functions">Function Definitions</option>
|
| 260 |
+
<option value="comments">Comments (JS/Java)</option>
|
| 261 |
+
<option value="cyber">🧷 Cyber Patterns</option>
|
| 262 |
+
</select>
|
| 263 |
+
<button id="btn-extract" class="px-3 py-1 rounded bg-[#1a1a2e] hover:bg-[#2a2a4e] text-[9px] text-cyan-300 border border-[#1a1a2e]">Extract</button>
|
| 264 |
+
</div>
|
| 265 |
+
<div id="pattern-output" class="mt-2 text-[8px] text-gray-500 font-mono h-20 overflow-y-auto border border-[#1a1a2e] bg-black/50 p-2 rounded"></div>
|
| 266 |
+
</div>
|
| 267 |
+
</div>
|
| 268 |
+
</aside>
|
| 269 |
+
|
| 270 |
+
<!-- CENTER: VIEWPORT -->
|
| 271 |
+
<section class="flex-1 relative flex flex-col items-center justify-center bg-[#030306] overflow-hidden">
|
| 272 |
+
|
| 273 |
+
<!-- 3D Canvas -->
|
| 274 |
+
<div id="viewport-3d" class="absolute inset-0 w-full h-full z-0">
|
| 275 |
+
<canvas id="glCanvas" class="w-full h-full object-contain"></canvas>
|
| 276 |
+
</div>
|
| 277 |
+
|
| 278 |
+
<!-- Overlay Info -->
|
| 279 |
+
<div class="absolute top-4 left-4 z-10 flex flex-col gap-2 pointer-events-none">
|
| 280 |
+
<div class="glass-panel px-3 py-2 rounded border-l-4 border-cyan-500">
|
| 281 |
+
<div class="text-[10px] text-cyan-300 uppercase font-bold">Current Engine</div>
|
| 282 |
+
<div class="text-xs font-mono text-white" id="engine-status">WebGL 2.0 // Three.js Core</div>
|
| 283 |
+
</div>
|
| 284 |
+
<div class="glass-panel px-3 py-2 rounded border-l-4 border-magenta-500 w-48">
|
| 285 |
+
<div class="text-[10px] text-magenta-300 uppercase font-bold">Audio Reactivity</div>
|
| 286 |
+
<div class="flex items-center gap-2 mt-1">
|
| 287 |
+
<div class="flex-1 h-1 bg-gray-800 rounded overflow-hidden">
|
| 288 |
+
<div id="audio-bar" class="h-full bg-magenta-500 w-0 transition-all duration-75"></div>
|
| 289 |
</div>
|
| 290 |
+
<span id="audio-val" class="text-[9px] font-mono text-magenta-300">0%</span>
|
| 291 |
+
</div>
|
| 292 |
+
</div>
|
| 293 |
+
</div>
|
| 294 |
+
|
| 295 |
+
<!-- Bottom Controls -->
|
| 296 |
+
<div class="absolute bottom-6 z-20 flex items-center gap-4 bg-[#00000080] backdrop-blur-md px-6 py-3 rounded-full border border-[#1a1a2e] shadow-[0_0_30px_rgba(0,0,0,0.8)]">
|
| 297 |
+
<button id="btn-play" class="w-10 h-10 rounded-full bg-white text-black hover:bg-cyan-400 transition flex items-center justify-center">
|
| 298 |
+
<i class="fa-solid fa-play text-sm ml-0.5"></i>
|
| 299 |
+
</button>
|
| 300 |
+
<div class="flex flex-col">
|
| 301 |
+
<span class="text-[9px] text-gray-400 uppercase tracking-widest">Time</span>
|
| 302 |
+
<span id="time-display" class="font-mono text-sm text-cyan-400">00:00:00</span>
|
| 303 |
+
</div>
|
| 304 |
+
<button id="btn-screenshot" class="px-3 py-1 rounded text-[10px] text-gray-300 hover:text-white hover:bg-white/10 transition border border-transparent hover:border-white/20">
|
| 305 |
+
<i class="fa-solid fa-camera mr-1"></i> Snapshot
|
| 306 |
+
</button>
|
| 307 |
+
</div>
|
| 308 |
+
</section>
|
| 309 |
+
|
| 310 |
+
<!-- RIGHT PANEL: STACK & SETTINGS -->
|
| 311 |
+
<aside class="w-80 bg-[#0a0a0f] border-l border-[#1a1a2e] flex flex-col overflow-hidden z-10">
|
| 312 |
+
|
| 313 |
+
<!-- Active Stack -->
|
| 314 |
+
<div class="p-4 border-b border-[#1a1a2e] bg-[#050508]">
|
| 315 |
+
<div class="flex items-center justify-between">
|
| 316 |
+
<h2 class="font-display text-sm text-cyan-400 tracking-widest">EFFECT STACK</h2>
|
| 317 |
+
<span id="stack-count" class="text-[10px] bg-cyan-900/30 text-cyan-300 px-2 py-0.5 rounded border border-cyan-900/50">0 / 12</span>
|
| 318 |
+
</div>
|
| 319 |
+
<div class="text-[9px] text-gray-500 mt-1">Drag to reorder • Click to adjust</div>
|
| 320 |
+
</div>
|
| 321 |
|
| 322 |
+
<div id="stack-list" class="flex-1 overflow-y-auto p-4 space-y-3 bg-[#08080c]">
|
| 323 |
+
<div class="text-center py-10 text-gray-600 text-sm border-2 border-dashed border-gray-800 rounded">
|
| 324 |
+
<i class="fa-solid fa-layer-group text-2xl mb-2 opacity-50"></i>
|
| 325 |
+
No effects active. Drag from library.
|
| 326 |
+
</div>
|
| 327 |
+
</div>
|
| 328 |
+
|
| 329 |
+
<!-- Quick Settings -->
|
| 330 |
+
<div class="p-4 border-t border-[#1a1a2e] bg-[#050508] space-y-4">
|
| 331 |
+
<div>
|
| 332 |
+
<div class="flex justify-between mb-1">
|
| 333 |
+
<label class="text-[10px] text-cyan-400 uppercase font-bold tracking-wider">Global Resolution</label>
|
| 334 |
+
<span id="res-val" class="text-[9px] text-gray-400 font-mono">1080p</span>
|
| 335 |
+
</div>
|
| 336 |
+
<input type="range" id="global-res" min="360" max="2160" step="72" value="1080" class="w-full">
|
| 337 |
+
</div>
|
| 338 |
+
<div>
|
| 339 |
+
<div class="flex justify-between mb-1">
|
| 340 |
+
<label class="text-[10px] text-magenta-400 uppercase font-bold tracking-wider">Frame Rate (FPS)</label>
|
| 341 |
+
<span id="fps-val" class="text-[9px] text-gray-400 font-mono">60.000</span>
|
| 342 |
+
</div>
|
| 343 |
+
<input type="range" id="global-fps" min="15" max="240" step="0.1" value="60" class="w-full">
|
| 344 |
+
</div>
|
| 345 |
+
<div class="pt-2 border-t border-[#1a1a2e]">
|
| 346 |
+
<h3 class="text-[10px] text-gray-500 uppercase font-bold mb-2">APK Converter</h3>
|
| 347 |
+
<div class="flex items-center justify-between text-[9px] text-gray-400 mb-2 bg-[#000] p-2 rounded border border-[#1a1a2e]">
|
| 348 |
+
<span>Web to Android Builder</span>
|
| 349 |
+
<i class="fa-solid fa-mobile-screen text-cyan-500"></i>
|
| 350 |
+
</div>
|
| 351 |
+
<div class="grid grid-cols-2 gap-2">
|
| 352 |
+
<input type="text" id="app-name" placeholder="App Name" class="bg-[#12121a] border border-[#1a1a2e] rounded px-2 py-1 text-[9px] text-cyan-200 focus:border-cyan-500">
|
| 353 |
+
<input type="text" id="app-id" placeholder="Bundle ID" class="bg-[#12121a] border border-[#1a1a2e] rounded px-2 py-1 text-[9px] text-cyan-200 focus:border-cyan-500" value="com.nexus.app">
|
| 354 |
+
</div>
|
| 355 |
+
<button id="btn-build-apk" class="w-full mt-2 py-1.5 rounded bg-[#1a1a2e] hover:bg-[#2a2a4e] text-[10px] text-cyan-300 border border-[#1a1a2e] transition flex items-center justify-center gap-2">
|
| 356 |
+
<i class="fa-solid fa-code-commit"></i> Generate Android Project
|
| 357 |
+
</button>
|
| 358 |
+
</div>
|
| 359 |
+
<div class="pt-2 border-t border-[#1a1a2e]">
|
| 360 |
+
<h3 class="text-[10px] text-gray-500 uppercase font-bold mb-2">Database Stats</h3>
|
| 361 |
+
<div class="grid grid-cols-2 gap-2 text-[9px] text-gray-400 font-mono">
|
| 362 |
+
<div class="bg-[#000] p-2 rounded border border-[#1a1a2e]">Presets: <span id="stat-presets" class="text-cyan-400">0</span></div>
|
| 363 |
+
<div class="bg-[#000] p-2 rounded border border-[#1a1a2e]">History: <span id="stat-history" class="text-magenta-400">0</span></div>
|
| 364 |
+
</div>
|
| 365 |
+
</div>
|
| 366 |
+
</div>
|
| 367 |
+
</aside>
|
| 368 |
+
</main>
|
| 369 |
+
|
| 370 |
+
<!-- MATH POPUP MODAL -->
|
| 371 |
+
<div id="math-popup" class="math-popup">
|
| 372 |
+
<div class="flex justify-between items-center mb-4 border-b border-gray-700 pb-2">
|
| 373 |
+
<h3 class="text-lg font-bold text-cyan-400">Math Correction Assistant</h3>
|
| 374 |
+
<button id="popup-close" class="text-gray-400 hover:text-white text-xl">×</button>
|
| 375 |
+
</div>
|
| 376 |
+
<p class="text-sm text-gray-300 mb-2">We detected a syntax issue in your formula. Here is the corrected version:</p>
|
| 377 |
+
<textarea id="popup-correction" class="w-full h-32 bg-[#000] border border-cyan-500/50 text-cyan-200 p-2 font-mono text-sm mb-4"></textarea>
|
| 378 |
+
<div class="flex justify-between items-center">
|
| 379 |
+
<span class="text-xs text-yellow-500">Auto-fix applied in 0.003s</span>
|
| 380 |
+
<button id="popup-apply" class="px-4 py-2 bg-cyan-600 hover:bg-cyan-500 text-white rounded text-sm font-bold transition">Accept & Apply</button>
|
| 381 |
+
</div>
|
| 382 |
+
</div>
|
| 383 |
+
|
| 384 |
+
<!-- SCRIPTS -->
|
| 385 |
+
<script type="module">
|
| 386 |
+
import * as THREE from 'three';
|
| 387 |
+
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
| 388 |
+
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
| 389 |
+
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
|
| 390 |
+
|
| 391 |
+
// --- 1. FX LIBRARY DEFINITION (Merged & Expanded) ---
|
| 392 |
+
const FX_LIBRARY = [
|
| 393 |
+
{ id: 'bw', name: 'Monochrome', category: 'Color', desc: 'Converts video to black and white with contrast control.', glsl: `uniform float amount; void main() { vec4 color = texture2D(tDiffuse, vUv); float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); gl_FragColor = vec4(vec3(gray * amount), color.a); }` },
|
| 394 |
+
{ id: 'rgb_shift', name: 'Chromatic Aberration', category: 'Glitch', desc: 'Separates RGB channels for sci-fi distortion.', glsl: `uniform float amount; uniform float uAudio; void main() { float offset = amount * 0.05 * (1.0 + uAudio); vec2 rUv = vUv + vec2(offset, 0.0); vec2 gUv = vUv; vec2 bUv = vUv - vec2(offset, 0.0); vec4 r = texture2D(tDiffuse, rUv); vec4 g = texture2D(tDiffuse, gUv); vec4 b = texture2D(tDiffuse, bUv); gl_FragColor = vec4(r.r, g.g, b.b, 1.0); }` },
|
| 395 |
+
{ id: 'noise', name: 'Digital Noise', category: 'Glitch', desc: 'Static noise overlay with audio sensitivity.', glsl: `uniform float amount; uniform float time; float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } void main() { vec4 color = texture2D(tDiffuse, vUv); float diff = (rand(vUv + time) - 0.5) * amount; gl_FragColor = vec4(color.rgb + diff, color.a); }` },
|
| 396 |
+
{ id: 'scanlines', name: 'CRT Scanlines', category: 'Visual', desc: 'Retro television scanline effect.', glsl: `uniform float amount; uniform vec2 resolution; void main() { vec4 color = texture2D(tDiffuse, vUv); float scanline = sin(vUv.y * resolution.y * 0.5) * 0.1 * amount; gl_FragColor = vec4(color.rgb - scanline, color.a); }` },
|
| 397 |
+
{ id: 'vignette', name: 'Neon Vignette', category: 'Art', desc: 'Darken edges with neon color bleed.', glsl: `uniform float amount; uniform vec2 resolution; void main() { vec4 color = texture2D(tDiffuse, vUv); vec2 uv = vUv - 0.5; float dist = length(uv); float aspect = resolution.x / resolution.y; uv.x *= aspect; float curve = smoothstep(0.8, 0.1, length(uv)); gl_FragColor = vec4(color.rgb * curve, color.a); }` },
|
| 398 |
+
{ id: 'shockwave', name: 'Sonic Shockwave', category: 'Audio', desc: 'Expands based on bass frequencies.', glsl: `uniform float amount; uniform float uAudio; uniform vec2 resolution; void main() { vec2 uv = vUv - 0.5; float aspect = resolution.x / resolution.y; uv.x *= aspect; float radius = length(uv); float angle = atan(uv.y, uv.x); float distortion = sin(angle * 10.0 + radius * 20.0 * uAudio + uAudio * 5.0) * amount * 0.1; vec2 newUv = vUv + distortion * vec2(cos(angle), sin(angle)); gl_FragColor = texture2D(tDiffuse, newUv); }` },
|
| 399 |
+
{ id: 'pixelate', name: 'Mosaic Glitch', category: 'Glitch', desc: 'Blocky pixelation based on mid frequencies.', glsl: `uniform float amount; uniform vec2 resolution; void main() { float d = 1.0 / (amount * 100.0 + 10.0); vec2 coord = d * floor(vUv / d); gl_FragColor = texture2D(tDiffuse, coord); }` },
|
| 400 |
+
{ id: 'invert', name: 'Cyber Invert', category: 'Color', desc: 'High contrast negative effect.', glsl: `uniform float amount; void main() { vec4 color = texture2D(tDiffuse, vUv); gl_FragColor = vec4(mix(color.rgb, 1.0 - color.rgb, amount), color.a); }` },
|
| 401 |
+
// VisionFX Pro Additions
|
| 402 |
+
{ id: 'toxic', name: 'Toxic Fallout', category: 'Color', desc: 'Green channel amplification with noise.', glsl: `uniform float amount; uniform float time; void main() { vec4 color = texture2D(tDiffuse, vUv); float noise = (fract(sin(dot(vUv, vec2(12.9898,78.233))) * 43758.5453) - 0.5) * amount * 0.2; gl_FragColor = vec4(color.r, color.g * (1.0 + amount), color.b, color.a) + noise; }` },
|
| 403 |
+
{ id: 'luma_rush', name: 'Luma Rush', category: 'Logic', desc: 'Speed control based on brightness.', glsl: `uniform float amount; uniform float uAudio; void main() { vec4 color = texture2D(tDiffuse, vUv); float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); float speed = 1.0 + (gray * amount * 2.0) + uAudio; gl_FragColor = texture2D(tDiffuse, vUv * speed); }` }
|
| 404 |
+
];
|
| 405 |
+
|
| 406 |
+
// --- 2. APP CORE (Nexus OS + Vision FX Integration) ---
|
| 407 |
+
const NexusOS = {
|
| 408 |
+
scene: null, camera: null, renderer: null, composer: null,
|
| 409 |
+
video: null, videoTex: null, audioCtx: null, analyser: null, dataArray: null,
|
| 410 |
+
stack: [], maxEffects: 12, isPlaying: false, animationId: null,
|
| 411 |
+
mathState: { isRunning: false, autoCorrect: true },
|
| 412 |
+
mathHistory: [],
|
| 413 |
+
|
| 414 |
+
init: () => {
|
| 415 |
+
NexusOS.setup3D();
|
| 416 |
+
NexusOS.setupUI();
|
| 417 |
+
NexusOS.setupAudio();
|
| 418 |
+
NexusOS.animate();
|
| 419 |
+
NexusOS.loadStats();
|
| 420 |
+
},
|
| 421 |
+
|
| 422 |
+
setup3D: () => {
|
| 423 |
+
const container = document.getElementById('viewport-3d');
|
| 424 |
+
const width = container.clientWidth;
|
| 425 |
+
const height = container.clientHeight;
|
| 426 |
+
|
| 427 |
+
NexusOS.scene = new THREE.Scene();
|
| 428 |
+
NexusOS.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
| 429 |
+
|
| 430 |
+
NexusOS.renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('glCanvas'), antialias: true, preserveDrawingBuffer: true });
|
| 431 |
+
NexusOS.renderer.setSize(width, height);
|
| 432 |
+
NexusOS.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
| 433 |
+
|
| 434 |
+
NexusOS.composer = new EffectComposer(NexusOS.renderer);
|
| 435 |
+
const renderPass = new RenderPass(NexusOS.scene, NexusOS.camera);
|
| 436 |
+
NexusOS.composer.addPass(renderPass);
|
| 437 |
+
|
| 438 |
+
const geometry = new THREE.PlaneGeometry(2, 2);
|
| 439 |
+
const material = new THREE.MeshBasicMaterial({ color: 0x000000 });
|
| 440 |
+
const quad = new THREE.Mesh(geometry, material);
|
| 441 |
+
NexusOS.scene.add(quad);
|
| 442 |
+
NexusOS.quad = quad;
|
| 443 |
+
|
| 444 |
+
window.addEventListener('resize', () => {
|
| 445 |
+
const w = container.clientWidth; const h = container.clientHeight;
|
| 446 |
+
NexusOS.renderer.setSize(w, h); NexusOS.composer.setSize(w, h);
|
| 447 |
+
NexusOS.stack.forEach(pass => { if(pass.uniforms.resolution) pass.uniforms.resolution.value.set(w, h); });
|
| 448 |
+
});
|
| 449 |
+
},
|
| 450 |
+
|
| 451 |
+
setupUI: () => {
|
| 452 |
+
const list = document.getElementById('fx-list');
|
| 453 |
+
const categories = [...new Set(FX_LIBRARY.map(s => s.category))];
|
| 454 |
+
|
| 455 |
+
categories.forEach(cat => {
|
| 456 |
+
const header = document.createElement('div');
|
| 457 |
+
header.className = "text-[9px] text-gray-500 uppercase font-bold mt-4 mb-2 pl-2 tracking-widest border-b border-[#1a1a2e]";
|
| 458 |
+
header.innerText = cat; list.appendChild(header);
|
| 459 |
+
|
| 460 |
+
FX_LIBRARY.filter(s => s.category === cat).forEach(shader => {
|
| 461 |
+
const el = document.createElement('div');
|
| 462 |
+
el.className = "fx-card p-3 rounded transition-all group cursor-pointer border-l-4 border-[#1a1a2e]";
|
| 463 |
+
el.innerHTML = `
|
| 464 |
+
<div class="flex justify-between items-start mb-1">
|
| 465 |
+
<span class="font-bold text-cyan-300 text-sm group-hover:text-white transition">${shader.name}</span>
|
| 466 |
+
<i class="fa-solid fa-plus-circle text-[10px] text-gray-500 group-hover:text-cyan-400 transition"></i>
|
| 467 |
+
</div>
|
| 468 |
+
<div class="text-[9px] text-gray-400 line-clamp-2">${shader.desc}</div>
|
| 469 |
+
`;
|
| 470 |
+
el.draggable = true;
|
| 471 |
+
el.addEventListener('dragstart', (e) => {
|
| 472 |
+
e.dataTransfer.setData('text/plain', shader.id);
|
| 473 |
+
e.dataTransfer.setData('name', shader.name);
|
| 474 |
+
e.dataTransfer.setData('glsl', shader.glsl);
|
| 475 |
+
});
|
| 476 |
+
list.appendChild(el);
|
| 477 |
+
});
|
| 478 |
+
});
|
| 479 |
+
|
| 480 |
+
const stackList = document.getElementById('stack-list');
|
| 481 |
+
stackList.addEventListener('dragover', (e) => e.preventDefault());
|
| 482 |
+
stackList.addEventListener('drop', (e) => {
|
| 483 |
+
e.preventDefault();
|
| 484 |
+
const id = e.dataTransfer.getData('text/plain');
|
| 485 |
+
if (NexusOS.stack.length < NexusOS.maxEffects) NexusOS.addEffect(id, e.dataTransfer.getData('name'), e.dataTransfer.getData('glsl'));
|
| 486 |
+
else alert("Effect Stack Full (Max 12)");
|
| 487 |
+
});
|
| 488 |
+
|
| 489 |
+
document.getElementById('search-fx').addEventListener('input', (e) => {
|
| 490 |
+
const term = e.target.value.toLowerCase();
|
| 491 |
+
document.querySelectorAll('.fx-card').forEach(card => {
|
| 492 |
+
card.style.display = card.innerText.toLowerCase().includes(term) ? 'block' : 'none';
|
| 493 |
+
});
|
| 494 |
+
});
|
| 495 |
+
|
| 496 |
+
// Global Settings
|
| 497 |
+
document.getElementById('global-res').addEventListener('input', (e) => document.getElementById('res-val').innerText = e.target.value + 'p');
|
| 498 |
+
document.getElementById('global-fps').addEventListener('input', (e) => document.getElementById('fps-val').innerText = parseFloat(e.target.value).toFixed(3));
|
| 499 |
+
|
| 500 |
+
// Play/Pause
|
| 501 |
+
document.getElementById('btn-play').addEventListener('click', () => {
|
| 502 |
+
if (NexusOS.video.paused) {
|
| 503 |
+
NexusOS.video.play(); document.getElementById('audio-src').play();
|
| 504 |
+
NexusOS.isPlaying = true;
|
| 505 |
+
document.getElementById('btn-play').innerHTML = '<i class="fa-solid fa-pause text-sm ml-0.5"></i>';
|
| 506 |
+
} else {
|
| 507 |
+
NexusOS.video.pause(); document.getElementById('audio-src').pause();
|
| 508 |
+
NexusOS.isPlaying = false;
|
| 509 |
+
document.getElementById('btn-play').innerHTML = '<i class="fa-solid fa-play text-sm ml-0.5"></i>';
|
| 510 |
+
}
|
| 511 |
+
});
|
| 512 |
+
|
| 513 |
+
// Randomize
|
| 514 |
+
document.getElementById('btn-randomize').addEventListener('click', () => {
|
| 515 |
+
NexusOS.stack.forEach(() => NexusOS.removeEffect(NexusOS.stack[0].uid));
|
| 516 |
+
const count = Math.floor(Math.random() * 5) + 2;
|
| 517 |
+
for(let i=0; i<count; i++) {
|
| 518 |
+
const rnd = FX_LIBRARY[Math.floor(Math.random() * FX_LIBRARY.length)];
|
| 519 |
+
NexusOS.addEffect(rnd.id, rnd.name, rnd.glsl);
|
| 520 |
+
}
|
| 521 |
+
});
|
| 522 |
+
|
| 523 |
+
// Export
|
| 524 |
+
document.getElementById('btn-export').addEventListener('click', () => {
|
| 525 |
+
const config = { effects: NexusOS.stack.map(p => ({ id: p.def.id, amount: p.uniforms.amount.value })), resolution: document.getElementById('global-res').value };
|
| 526 |
+
const blob = new Blob([JSON.stringify(config)], {type: 'application/json'});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|