Monorepo for Aesthetic.Computer aesthetic.computer
at main 387 lines 11 kB view raw
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 <!-- CSP will be injected by extension, or use permissive one for local dev --> 7 <meta http-equiv="Content-Security-Policy" content="{{CSP}}"> 8 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> 9 <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script> 10 <style> 11 * { margin: 0; padding: 0; box-sizing: border-box; } 12 13 /* Dark theme (default) */ 14 body { 15 background: #181318; 16 color: #fff; 17 font-family: monospace; 18 overflow: hidden; 19 height: 100vh; 20 } 21 body[data-theme="light"] { 22 background: #fcf7c5; 23 color: #281e5a; 24 } 25 26 #canvas { position: absolute; top: 0; left: 0; z-index: 1; } 27 28 /* ====== HEADER BAR ====== */ 29 .header-bar { 30 position: fixed; 31 top: 0; 32 left: 0; 33 right: 0; 34 height: 44px; 35 display: flex; 36 align-items: center; 37 justify-content: space-between; 38 padding: 0 16px; 39 background: linear-gradient(to bottom, rgba(24, 19, 24, 0.9) 0%, rgba(24, 19, 24, 0) 100%); 40 z-index: 100; 41 pointer-events: none; 42 } 43 body[data-theme="light"] .header-bar { 44 background: linear-gradient(to bottom, rgba(252, 247, 197, 0.9) 0%, rgba(252, 247, 197, 0) 100%); 45 } 46 47 .header-left { 48 display: flex; 49 align-items: center; 50 gap: 12px; 51 } 52 53 .title { 54 font-size: 13px; 55 display: flex; 56 align-items: center; 57 gap: 8px; 58 } 59 .title .dot { color: #ff69b4; } 60 body[data-theme="light"] .title .dot { color: #006400; } 61 62 .status-dot { 63 width: 6px; 64 height: 6px; 65 border-radius: 50%; 66 background: #ff69b4; 67 flex-shrink: 0; 68 } 69 body[data-theme="light"] .status-dot { background: #387adf; } 70 .status-dot.online { background: #0f0; } 71 body[data-theme="light"] .status-dot.online { background: #006400; } 72 73 .header-center { 74 display: flex; 75 align-items: center; 76 gap: 16px; 77 font-size: 11px; 78 color: #666; 79 } 80 body[data-theme="light"] .header-center { color: #806060; } 81 .header-center .stat { display: flex; align-items: center; gap: 4px; } 82 .header-center .val { color: #fff; font-weight: bold; } 83 body[data-theme="light"] .header-center .val { color: #281e5a; } 84 85 .header-right { 86 display: flex; 87 align-items: center; 88 gap: 8px; 89 pointer-events: auto; 90 } 91 92 .header-btn { 93 background: rgba(255, 255, 255, 0.08); 94 border: 1px solid rgba(255, 255, 255, 0.15); 95 color: #fff; 96 padding: 5px 10px; 97 border-radius: 4px; 98 font-size: 11px; 99 font-family: monospace; 100 cursor: pointer; 101 transition: all 0.15s ease; 102 } 103 body[data-theme="light"] .header-btn { 104 background: rgba(0, 0, 0, 0.08); 105 border: 1px solid rgba(0, 0, 0, 0.15); 106 color: #281e5a; 107 } 108 .header-btn:hover { 109 background: rgba(255, 255, 255, 0.15); 110 border-color: #ff69b4; 111 } 112 body[data-theme="light"] .header-btn:hover { 113 background: rgba(0, 0, 0, 0.12); 114 border-color: #006400; 115 } 116 117 /* ====== CENTER PANEL (process count + actions) ====== */ 118 .center-panel { 119 position: fixed; 120 bottom: 60px; 121 left: 50%; 122 transform: translateX(-50%); 123 text-align: center; 124 z-index: 100; 125 pointer-events: none; 126 padding: 12px 20px; 127 background: rgba(24, 19, 24, 0.7); 128 border-radius: 12px; 129 border: 1px solid rgba(255, 255, 255, 0.08); 130 backdrop-filter: blur(8px); 131 -webkit-backdrop-filter: blur(8px); 132 } 133 body[data-theme="light"] .center-panel { 134 background: rgba(252, 247, 197, 0.8); 135 border: 1px solid rgba(0, 0, 0, 0.1); 136 } 137 138 .process-counter { 139 display: flex; 140 align-items: baseline; 141 justify-content: center; 142 gap: 6px; 143 margin-bottom: 10px; 144 } 145 .process-counter .count { 146 font-size: 32px; 147 font-weight: bold; 148 color: #fff; 149 line-height: 1; 150 } 151 body[data-theme="light"] .process-counter .count { color: #281e5a; } 152 .process-counter .label { 153 font-size: 11px; 154 color: #666; 155 text-transform: uppercase; 156 letter-spacing: 1px; 157 } 158 body[data-theme="light"] .process-counter .label { color: #806060; } 159 160 .actions { 161 pointer-events: auto; 162 display: flex; 163 gap: 8px; 164 justify-content: center; 165 } 166 .action-btn { 167 background: rgba(255,255,255,0.1); 168 border: 1px solid rgba(255,255,255,0.2); 169 border-radius: 6px; 170 padding: 8px 14px; 171 font-size: 12px; 172 color: #fff; 173 cursor: pointer; 174 transition: all 0.15s ease; 175 font-family: inherit; 176 } 177 body[data-theme="light"] .action-btn { 178 background: rgba(0,0,0,0.08); 179 border: 1px solid rgba(0,0,0,0.15); 180 color: #281e5a; 181 } 182 .action-btn:hover { 183 background: rgba(255,255,255,0.18); 184 border-color: #ff69b4; 185 } 186 body[data-theme="light"] .action-btn:hover { 187 background: rgba(0,0,0,0.12); 188 border-color: #006400; 189 } 190 .action-btn.primary { 191 background: #ff69b4; 192 border-color: #ff69b4; 193 color: #000; 194 } 195 body[data-theme="light"] .action-btn.primary { 196 background: #006400; 197 border-color: #006400; 198 color: #fff; 199 } 200 .action-btn.primary:hover { 201 background: #ff8ab3; 202 } 203 body[data-theme="light"] .action-btn.primary:hover { 204 background: #008000; 205 } 206 207 /* ====== STATUS BAR (bottom) ====== */ 208 .status-bar { 209 position: fixed; 210 bottom: 0; 211 left: 0; 212 right: 0; 213 height: 36px; 214 display: flex; 215 align-items: center; 216 justify-content: space-between; 217 padding: 0 16px; 218 background: linear-gradient(to top, rgba(24, 19, 24, 0.9) 0%, rgba(24, 19, 24, 0) 100%); 219 z-index: 100; 220 pointer-events: none; 221 font-size: 11px; 222 color: #666; 223 } 224 body[data-theme="light"] .status-bar { 225 background: linear-gradient(to top, rgba(252, 247, 197, 0.9) 0%, rgba(252, 247, 197, 0) 100%); 226 color: #806060; 227 } 228 229 .status-left { 230 display: flex; 231 align-items: center; 232 gap: 16px; 233 } 234 235 .status-right { 236 display: flex; 237 align-items: center; 238 gap: 16px; 239 } 240 241 /* ====== STATS GRAPH (bottom-right) ====== */ 242 .stats-graph-container { 243 position: fixed; 244 bottom: 50px; 245 right: 16px; 246 width: 200px; 247 height: 80px; 248 z-index: 100; 249 pointer-events: none; 250 background: rgba(24, 19, 24, 0.5); 251 border-radius: 8px; 252 border: 1px solid rgba(255, 255, 255, 0.08); 253 backdrop-filter: blur(4px); 254 -webkit-backdrop-filter: blur(4px); 255 padding: 8px; 256 } 257 body[data-theme="light"] .stats-graph-container { 258 background: rgba(252, 247, 197, 0.6); 259 border: 1px solid rgba(0, 0, 0, 0.1); 260 } 261 .stats-graph-header { 262 display: flex; 263 justify-content: space-between; 264 font-size: 9px; 265 margin-bottom: 4px; 266 color: #888; 267 } 268 body[data-theme="light"] .stats-graph-header { color: #806060; } 269 .stats-graph-header .cpu-label { color: #50fa7b; } 270 .stats-graph-header .mem-label { color: #ff79c6; } 271 body[data-theme="light"] .stats-graph-header .cpu-label { color: #006400; } 272 body[data-theme="light"] .stats-graph-header .mem-label { color: #c71585; } 273 .stats-graph-canvas { 274 width: 100%; 275 height: 50px; 276 border-radius: 4px; 277 background: rgba(0, 0, 0, 0.2); 278 } 279 body[data-theme="light"] .stats-graph-canvas { 280 background: rgba(0, 0, 0, 0.05); 281 } 282 283 .dev-badge { 284 background: #ff69b4; 285 color: #000; 286 padding: 3px 8px; 287 border-radius: 3px; 288 font-size: 9px; 289 font-weight: bold; 290 text-transform: uppercase; 291 letter-spacing: 0.5px; 292 } 293 body[data-theme="light"] .dev-badge { 294 background: #006400; 295 color: #fff; 296 } 297 298 .mem-display { 299 font-family: monospace; 300 } 301 302 /* ====== LABELS CONTAINER ====== */ 303 .label-container { 304 position: absolute; 305 top: 44px; /* below header */ 306 left: 0; 307 width: 100%; 308 height: calc(100% - 44px - 36px); /* minus header and status bar */ 309 pointer-events: none; 310 z-index: 50; 311 overflow: hidden; 312 } 313 .proc-label { 314 position: absolute; 315 text-align: center; 316 transform: translate(-50%, -100%); 317 white-space: nowrap; 318 text-shadow: 0 0 6px #000, 0 0 10px #000, 0 0 14px #000; 319 pointer-events: none; 320 padding: 2px 4px; 321 border-radius: 4px; 322 background: transparent; 323 } 324 body[data-theme="light"] .proc-label { 325 text-shadow: 0 0 6px #fcf7c5, 0 0 10px #fcf7c5, 0 0 14px #fcf7c5; 326 background: transparent; 327 } 328 .proc-label .icon { font-size: 16px; display: block; line-height: 1.2; } 329 .proc-label .name { font-size: 10px; margin-top: 2px; font-weight: bold; letter-spacing: 0.3px; } 330 .proc-label .info { font-size: 8px; color: #aaa; margin-top: 1px; } 331 body[data-theme="light"] .proc-label .info { color: #806060; } 332 </style> 333</head> 334<body data-theme="dark"> 335 <canvas id="canvas"></canvas> 336 337 <!-- HEADER BAR --> 338 <div class="header-bar"> 339 <div class="header-left"> 340 <div class="status-dot" id="status-dot"></div> 341 <div class="title"> 342 <span>Aesthetic<span class="dot">.</span>Computer</span> 343 </div> 344 </div> 345 <div class="header-center"> 346 <div class="stat"><span class="val" id="uptime"></span></div> 347 <div class="stat"><span class="val" id="cpus"></span> cpus</div> 348 </div> 349 <div class="header-right"> 350 <button class="header-btn" onclick="window.ProcessTreeViz?.toggleTheme()">🌓</button> 351 </div> 352 </div> 353 354 <!-- CENTER PANEL --> 355 <div class="center-panel"> 356 <div class="process-counter"> 357 <span class="count" id="process-count">0</span> 358 <span class="label">processes</span> 359 </div> 360 <div class="actions"> 361 <button class="action-btn primary" id="btn-kidlisp">🎨 KidLisp</button> 362 <button class="action-btn" id="btn-pane">💻 AC Pane</button> 363 </div> 364 </div> 365 366 <!-- STATUS BAR --> 367 <div class="status-bar"> 368 <div class="status-left" id="status-left"></div> 369 <div class="status-right"> 370 <span class="mem-display"><span id="mem-text">— / —</span> MB</span> 371 </div> 372 </div> 373 374 <!-- STATS GRAPH (bottom-right) --> 375 <div class="stats-graph-container" id="stats-graph-container"> 376 <div class="stats-graph-header"> 377 <span class="cpu-label">CPU: <span id="cpu-pct">0</span>%</span> 378 <span class="mem-label">MEM: <span id="mem-pct">0</span>%</span> 379 </div> 380 <canvas class="stats-graph-canvas" id="stats-graph-canvas"></canvas> 381 </div> 382 383 <div id="labels" class="label-container"></div> 384 385 <script src="process-tree.js"></script> 386</body> 387</html>