fredmo commited on
Commit
f435976
·
verified ·
1 Parent(s): 7dca660

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +499 -19
index.html CHANGED
@@ -1,19 +1,499 @@
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
+ <link rel="preconnect" href="https://fonts.googleapis.com">
7
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8
+ <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Audiowide&display=swap" rel="stylesheet">
9
+ <title>GPU Memory Visualizer (Synthwave Edition)</title>
10
+ <link rel="stylesheet" href="style.css">
11
+
12
+ <script>
13
+ document.addEventListener('DOMContentLoaded', () => {
14
+ // --- Canvas & Control Elements ---
15
+ const canvas = document.getElementById('gpuCanvas'); const ctx = canvas.getContext('2d');
16
+ const gpuContainer = document.querySelector('.gpu-container');
17
+ const gpuSelect = document.getElementById('gpu-select');
18
+ const modelSelect = document.getElementById('model-select');
19
+ const promptButtons = document.querySelectorAll('.prompt-button');
20
+ const resetButton = document.getElementById('reset-button');
21
+ const statusMessage = document.getElementById('status-message');
22
+ const workdayButton = document.getElementById('workday-pattern');
23
+ const batchButton = document.getElementById('batch-pattern');
24
+ const burstHellButton = document.getElementById('burst-hell-pattern'); // ++ Get New Button ++
25
+ // ++ Add new button to control list ++
26
+ const controlsToDisableOnError = [resetButton, workdayButton, batchButton, burstHellButton, ...promptButtons];
27
+ const simulationButtons = [workdayButton, batchButton, burstHellButton]; // ++ Group sim buttons ++
28
+
29
+ // --- Configuration --- (Keep existing)
30
+ const BLOCK_SIZE = 15; const PADDING = 1; const COLS = Math.floor(parseInt(canvas.width) / (BLOCK_SIZE + PADDING));
31
+ const BASE_CANVAS_HEIGHT = 200; const GPU_HEIGHT_MULTIPLIERS = { 'L4': 1, 'A100': 2, 'H100': 4 };
32
+ const GPU_GB = { 'L4': 24, 'A100': 40, 'H100': 80 }; const MODEL_GB = { 'gemma-1b': 2, 'gemma-4b': 8, 'gemma-12b': 24, 'gemma-27b': 54 };
33
+ let ROWS; let TOTAL_BLOCKS; let modelBlockSizes = {}; let MAIN_GPU_AREA_START_INDEX; const TOKENS_TO_GENERATE = 3;
34
+
35
+ // --- SYNTHWAVE Colors --- (Keep existing)
36
+ const COLOR_FREE = '#1a1a2e'; const COLOR_MODEL = '#4d4dff'; const COLOR_PROMPT_SMALL = '#ff00ff'; const COLOR_PROMPT_MID = '#00ffff'; const COLOR_PROMPT_LONG = '#fff000'; const COLOR_PROCESSING = '#9d00ff'; const COLOR_GENERATED = '#ff1f1f';
37
+
38
+ // --- State Variables --- (Keep existing)
39
+ let gpuType = gpuSelect.value; let baseBlockProcessingTimeMs;
40
+ let memory = []; let processingQueue = []; let visuallyPlacedPrompts = []; let currentTask = null; let nextPromptId = 0; let isSimulationRunning = false; let simulationTimeoutIds = [];
41
+
42
+ // --- Helper Functions to Disable/Enable Controls --- (Modify enableControls)
43
+ function disableControlsOnError() { controlsToDisableOnError.forEach(control => control.disabled = true); gpuSelect.disabled = false; modelSelect.disabled = false; gpuContainer.style.opacity = '0.7'; console.log("Controls Disabled (Except GPU & Model Select)"); }
44
+ function enableControls() {
45
+ // Enable non-simulation controls first
46
+ [gpuSelect, modelSelect, resetButton, ...promptButtons].forEach(control => control.disabled = false);
47
+ // Enable simulation buttons ONLY if a simulation isn't running
48
+ simulationButtons.forEach(button => button.disabled = isSimulationRunning);
49
+ gpuContainer.style.opacity = '1';
50
+ console.log("Controls Enabled/Status Updated");
51
+ }
52
+ function disableSimButtons() {
53
+ simulationButtons.forEach(button => button.disabled = true);
54
+ }
55
+
56
+ // --- Update Canvas Size & Calculate Model Block Sizes --- (Keep existing)
57
+ function updateCanvasSizeAndRecalculateGrid() { const selectedGpu = gpuSelect.value || 'L4'; const multiplier = GPU_HEIGHT_MULTIPLIERS[selectedGpu] || 1; const newHeight = Math.floor(BASE_CANVAS_HEIGHT * multiplier); canvas.height = newHeight; gpuContainer.style.height = `${newHeight + 4}px`; ROWS = Math.floor(newHeight / (BLOCK_SIZE + PADDING)); TOTAL_BLOCKS = COLS * ROWS; const l4Height = BASE_CANVAS_HEIGHT; const l4Rows = Math.floor(l4Height / (BLOCK_SIZE + PADDING)); const totalBlocksForL4 = COLS * l4Rows; const blocksPerGbScale = totalBlocksForL4 / GPU_GB['L4']; modelBlockSizes = {}; for (const modelKey in MODEL_GB) { const modelGb = MODEL_GB[modelKey]; modelBlockSizes[modelKey] = Math.round(blocksPerGbScale * modelGb); } console.log(`Set canvas height: ${newHeight}px | Grid: ${COLS}x${ROWS}=${TOTAL_BLOCKS} | Model Sizes:`, modelBlockSizes); }
58
+
59
+ // --- Initialization --- (Keep existing)
60
+ function initializeMemory() { console.log("--- Initializing Grid ---"); isSimulationRunning = false; simulationTimeoutIds.forEach(clearTimeout); simulationTimeoutIds = []; if(currentTask && currentTask.timeoutId) clearTimeout(currentTask.timeoutId); const selectedModel = modelSelect.value; const currentModelWeightsBlocks = modelBlockSizes[selectedModel] || modelBlockSizes['gemma-1b']; MAIN_GPU_AREA_START_INDEX = currentModelWeightsBlocks; console.log(`Model: ${selectedModel}, W: ${currentModelWeightsBlocks}, Total: ${TOTAL_BLOCKS}, Start: ${MAIN_GPU_AREA_START_INDEX}`); memory = new Array(TOTAL_BLOCKS).fill(COLOR_FREE); processingQueue = []; visuallyPlacedPrompts = []; currentTask = null; nextPromptId = 0; updateProcessingSpeed(); if (currentModelWeightsBlocks >= TOTAL_BLOCKS) { console.error(`Model (${currentModelWeightsBlocks}) >= total (${TOTAL_BLOCKS}) for ${gpuSelect.value}.`); statusMessage.textContent = "ERROR: MODEL TOO LARGE FOR GRID!"; statusMessage.classList.add('error'); disableControlsOnError(); } else { statusMessage.classList.remove('error'); statusMessage.textContent = 'SYSTEM IDLE.'; enableControls(); for (let i = 0; i < currentModelWeightsBlocks; i++) { memory[i] = COLOR_MODEL; } const freeSpace = TOTAL_BLOCKS - currentModelWeightsBlocks; if (freeSpace < 100) { console.warn(`Low free space (${freeSpace}).`); } } drawAll(); }
61
+
62
+ // --- Drawing Functions --- (Keep existing)
63
+ function getCoords(index) { const row = Math.floor(index / COLS); const col = index % COLS; const x = col * (BLOCK_SIZE + PADDING); const y = row * (BLOCK_SIZE + PADDING); return { x, y }; }
64
+ function drawBlock(index, color) { if (index >= memory.length || index < 0) return; const { x, y } = getCoords(index); ctx.fillStyle = color; ctx.fillRect(x, y, BLOCK_SIZE, BLOCK_SIZE); }
65
+ function drawAll() { ctx.fillStyle = COLOR_FREE; ctx.fillRect(0, 0, canvas.width, canvas.height); for (let i = 0; i < memory.length; i++) { if (memory[i] !== COLOR_FREE) { drawBlock(i, memory[i]); } } }
66
+
67
+ // --- Logic Functions --- (Keep existing)
68
+ function getPromptColor(size) { if (size <= 3) return COLOR_PROMPT_SMALL; if (size <= 5) return COLOR_PROMPT_MID; return COLOR_PROMPT_LONG; }
69
+ function updateProcessingSpeed() { gpuType = gpuSelect.value || 'L4'; if (gpuType === 'A100') { baseBlockProcessingTimeMs = 150; } else if (gpuType === 'H100') { baseBlockProcessingTimeMs = 50; } else { baseBlockProcessingTimeMs = 250; } console.log(`GPU set to ${gpuType}, base speed ${baseBlockProcessingTimeMs}ms/block`); }
70
+ function findFreeSpaceInMainGPU(size) { let c=0; for(let i=MAIN_GPU_AREA_START_INDEX;i<TOTAL_BLOCKS;i++){ if(memory[i]===COLOR_FREE){c++;if(c===size){return i-size+1;}}else{c=0;}} return -1;}
71
+ function findOldestGeneratedBlock() { for (let i=MAIN_GPU_AREA_START_INDEX; i<TOTAL_BLOCKS; i++) { if (memory[i] === COLOR_GENERATED) return i; } return -1; }
72
+ function tryPlaceWaitingPrompts() { let p=false; for(let i=processingQueue.length-1;i>=0;i--){const q=processingQueue[i];const idx=findFreeSpaceInMainGPU(q.size); if(idx!==-1){processingQueue.splice(i,1);const pl={...q,startIndex:idx};visuallyPlacedPrompts.push(pl); for(let j=0;j<q.size;j++){if(idx+j<memory.length)memory[idx+j]=q.color;} p=true;}} if(p){drawAll();} updateStatusMessage(); }
73
+ function processNextBlock() { if (!currentTask) return; const { prompt:p, startIndex:s, processedCount:pc, generatedCount:gc, generatedIndices:gi}=currentTask; let bC=false; const ept=baseBlockProcessingTimeMs; if (pc<p.size){const bI=s+pc; if (bI<TOTAL_BLOCKS&&memory[bI]===p.color){memory[bI]=COLOR_PROCESSING; currentTask.processedCount++; drawBlock(bI,COLOR_PROCESSING); bC=true; const rBI=findOldestGeneratedBlock(); if(rBI!==-1){memory[rBI]=COLOR_FREE; drawBlock(rBI,COLOR_FREE);}}else if(bI<TOTAL_BLOCKS&&memory[bI]===COLOR_PROCESSING){currentTask.processedCount++;}else{console.error(`Block ${bI} unexpected: ${memory[bI]}. Skip.`); currentTask.processedCount++;}}else if(gc<TOKENS_TO_GENERATE){const fGB=findFreeSpaceInMainGPU(1); if(fGB!==-1){memory[fGB]=COLOR_GENERATED; currentTask.generatedCount++; gi.push(fGB); drawBlock(fGB,COLOR_GENERATED); bC=true;}else{currentTask.generatedCount=TOKENS_TO_GENERATE; bC=true;}} if(pc>=p.size&&gc>=TOKENS_TO_GENERATE){statusMessage.textContent='TASK COMPLETE.';let cC=0;for(let i=0;i<p.size;i++){const idx=s+i;if(idx<TOTAL_BLOCKS&&memory[idx]===COLOR_PROCESSING){memory[idx]=COLOR_FREE; cC++;}} const tId=currentTask.timeoutId; currentTask=null; drawAll(); setTimeout(()=>{tryPlaceWaitingPrompts();checkAndStartProcessing();},50); return;} if(currentTask){currentTask.timeoutId=setTimeout(processNextBlock,ept);}}
74
+ function checkAndStartProcessing() { if (currentTask) return; if (visuallyPlacedPrompts.length > 0) { visuallyPlacedPrompts.sort((a,b)=>a.startIndex-b.startIndex); const nPI=visuallyPlacedPrompts[0]; statusMessage.textContent='PROCESSING...'; statusMessage.classList.remove('error'); visuallyPlacedPrompts.shift(); currentTask={prompt:{id:nPI.id,size:nPI.size,color:nPI.color},startIndex:nPI.startIndex,processedCount:0,generatedCount:0,generatedIndices:[],timeoutId:null}; currentTask.timeoutId=setTimeout(processNextBlock,baseBlockProcessingTimeMs); return;} updateStatusMessage();}
75
+ function updateStatusMessage() { if(statusMessage.classList.contains('error')) return; if(currentTask){const prg=currentTask.prompt.size>0?Math.round((currentTask.processedCount/currentTask.prompt.size)*100):100; statusMessage.textContent=`PROCESSING TX ${currentTask.prompt.id} [${prg}%]|KV GEN ${currentTask.generatedCount}/${TOKENS_TO_GENERATE}`;}else if(isSimulationRunning){statusMessage.textContent='SIMULATION ACTIVE...';}else if(processingQueue.length>0){statusMessage.textContent=`${processingQueue.length} TX QUEUED//WAITING GRID...`;}else if(visuallyPlacedPrompts.length>0){statusMessage.textContent=`${visuallyPlacedPrompts.length} TX ON GRID//AWAITING...`;}else{let fB=0,gB=0; for(let i=MAIN_GPU_AREA_START_INDEX;i<TOTAL_BLOCKS;i++){if(memory[i]===COLOR_FREE)fB++;else if(memory[i]===COLOR_GENERATED)gB++;} const tFB=TOTAL_BLOCKS-(MAIN_GPU_AREA_START_INDEX||0)-gB-visuallyPlacedPrompts.reduce((a,p)=>a+p.size,0); statusMessage.textContent=`SYSTEM IDLE.//${Math.max(0,tFB)} FREE//${gB} KV`;}}
76
+
77
+ // --- Simulation Functions ---
78
+ function clickPromptButton(size) { if (gpuSelect.disabled) return; /* Prevent clicks if controls disabled */ const color = getPromptColor(size); const newPrompt = { id: nextPromptId++, size: size, color: color }; processingQueue.push(newPrompt); tryPlaceWaitingPrompts(); checkAndStartProcessing(); updateStatusMessage(); }
79
+
80
+ function simulateWorkday() { if (isSimulationRunning || workdayButton.disabled) return; console.log("Starting Workday Simulation..."); isSimulationRunning = true; disableSimButtons(); simulationTimeoutIds = []; let currentTime = 0; const schedule = (delay, func) => { simulationTimeoutIds.push(setTimeout(func, currentTime + delay)); }; for (let i = 0; i < 15; i++) { schedule(i * 400, () => clickPromptButton(Math.random() < 0.7 ? 3 : 5)); } currentTime += 15 * 400 + 2000; for (let i = 0; i < 10; i++) { let size = 3; const rand = Math.random(); if (rand > 0.8) size = 15; else if (rand > 0.4) size = 5; schedule(i * 800, () => clickPromptButton(size)); } currentTime += 10 * 800 + 3000; for (let i = 0; i < 12; i++) { schedule(i * 500, () => clickPromptButton(Math.random() < 0.6 ? 3 : 5)); } currentTime += 12 * 500 + 1000; schedule(500, () => { console.log("Workday Simulation Finished."); isSimulationRunning = false; enableControls(); updateStatusMessage(); }); updateStatusMessage(); }
81
+
82
+ function simulateBatch() { if (isSimulationRunning || batchButton.disabled) return; console.log("Starting Batch Simulation..."); isSimulationRunning = true; disableSimButtons(); simulationTimeoutIds = []; let currentTime = 0; const schedule = (delay, func) => { simulationTimeoutIds.push(setTimeout(func, currentTime + delay)); }; for (let i = 0; i < 8; i++) { let size = Math.random() < 0.6 ? 15 : 5; schedule(i * 3000, () => clickPromptButton(size)); } currentTime += 8 * 3000; schedule(1000, () => clickPromptButton(3)); schedule(1500, () => clickPromptButton(5)); currentTime += 2000; schedule(500, () => { console.log("Batch Simulation Finished."); isSimulationRunning = false; enableControls(); updateStatusMessage(); }); updateStatusMessage(); }
83
+
84
+ // ++ Burst Hell Simulation ++
85
+ function simulateBurstHell() {
86
+ if (isSimulationRunning || burstHellButton.disabled) return;
87
+ console.log("Starting BURST HELL Simulation...");
88
+ isSimulationRunning = true;
89
+ disableSimButtons(); // Disable all sim buttons
90
+ simulationTimeoutIds = [];
91
+ let currentTime = 0;
92
+ const schedule = (delay, func) => {
93
+ simulationTimeoutIds.push(setTimeout(func, currentTime + delay));
94
+ };
95
+
96
+ // Morning burst x5 (more density)
97
+ const morningCount = 15 * 5;
98
+ for (let i = 0; i < morningCount; i++) {
99
+ schedule(i * 80, () => clickPromptButton(Math.random() < 0.7 ? 3 : 5)); // Faster interval
100
+ }
101
+ currentTime += morningCount * 80 + 1500; // Shorter pause
102
+
103
+ // Mid-day x5 (more density)
104
+ const middayCount = 10 * 5;
105
+ for (let i = 0; i < middayCount; i++) {
106
+ let size = 3;
107
+ const rand = Math.random();
108
+ if (rand > 0.9) size = 15; // Fewer long prompts maybe?
109
+ else if (rand > 0.3) size = 5;
110
+ schedule(i * 120, () => clickPromptButton(size)); // Faster interval
111
+ }
112
+ currentTime += middayCount * 120 + 2000; // Shorter pause
113
+
114
+ // Afternoon burst x5 (more density)
115
+ const afternoonCount = 12 * 5;
116
+ for (let i = 0; i < afternoonCount; i++) {
117
+ schedule(i * 100, () => clickPromptButton(Math.random() < 0.6 ? 3 : 5)); // Faster interval
118
+ }
119
+ currentTime += afternoonCount * 100 + 1000;
120
+
121
+ // End simulation
122
+ schedule(500, () => {
123
+ console.log("BURST HELL Simulation Finished.");
124
+ isSimulationRunning = false;
125
+ enableControls(); // Re-enable controls (including sim buttons)
126
+ updateStatusMessage();
127
+ });
128
+ updateStatusMessage();
129
+ }
130
+ // ++ End Burst Hell ++
131
+
132
+
133
+ // --- Event Listeners ---
134
+ gpuSelect.addEventListener('change', () => { console.log("GPU Changed"); updateCanvasSizeAndRecalculateGrid(); initializeMemory(); });
135
+ modelSelect.addEventListener('change', () => { console.log("Model Changed"); initializeMemory(); });
136
+ promptButtons.forEach(button => { button.addEventListener('click', () => { if (button.disabled || isSimulationRunning) return; const size = parseInt(button.getAttribute('data-size')); const color = getPromptColor(size); const newPrompt = { id: nextPromptId++, size: size, color: color }; processingQueue.push(newPrompt); tryPlaceWaitingPrompts(); checkAndStartProcessing(); updateStatusMessage(); }); });
137
+ resetButton.addEventListener('click', () => { if (resetButton.disabled) return; console.log("Reset Clicked"); updateCanvasSizeAndRecalculateGrid(); initializeMemory(); } );
138
+ workdayButton.addEventListener('click', simulateWorkday);
139
+ batchButton.addEventListener('click', simulateBatch);
140
+ burstHellButton.addEventListener('click', simulateBurstHell); // ++ Add Listener ++
141
+
142
+ // --- Initial Setup ---
143
+ updateCanvasSizeAndRecalculateGrid(); initializeMemory();
144
+ setInterval(() => { updateStatusMessage(); if (!gpuSelect.disabled) { if (!currentTask && !isSimulationRunning && visuallyPlacedPrompts.length > 0) { checkAndStartProcessing(); } if (!currentTask && !isSimulationRunning && processingQueue.length > 0) { tryPlaceWaitingPrompts(); } } }, 1000);
145
+
146
+ });
147
+ </script>
148
+
149
+ <style>
150
+ /* Import Google Fonts (already in HTML, but good practice) */
151
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Audiowide&display=swap');
152
+
153
+ :root {
154
+ /* Synthwave Color Palette */
155
+ --color-background: #1a1a2e; /* Deep dark blue/purple */
156
+ --color-background-light: #2a2a4e;
157
+ --color-grid-lines: #3a3a5e; /* For potential future grid lines */
158
+ --color-text: #ffffff;
159
+ --color-neon-pink: #ff00ff;
160
+ --color-neon-cyan: #00ffff;
161
+ --color-neon-purple: #9d00ff; /* Electric purple */
162
+ --color-neon-orange: #ff8c00; /* Neon orange */
163
+ --color-neon-red: #ff1f1f; /* Brighter neon red */
164
+ --color-neon-yellow: #fff000; /* Bright neon yellow */
165
+ --color-model-blue: #4d4dff; /* A slightly brighter dark blue */
166
+
167
+ /* Fonts */
168
+ --font-heading: 'Orbitron', sans-serif;
169
+ --font-body: 'Audiowide', sans-serif; /* Using Audiowide for more elements */
170
+ }
171
+
172
+ body {
173
+ font-family: var(--font-body);
174
+ background: linear-gradient(to bottom, #0f0c29, #302b63, #24243e); /* Dark Gradient */
175
+ color: var(--color-text);
176
+ display: flex;
177
+ flex-direction: column;
178
+ align-items: center;
179
+ min-height: 100vh;
180
+ margin: 0;
181
+ padding-top: 20px; /* Add some space at the top */
182
+ }
183
+
184
+ h1 {
185
+ font-family: var(--font-heading);
186
+ font-weight: 700;
187
+ color: var(--color-neon-cyan);
188
+ text-shadow: 0 0 5px var(--color-neon-cyan),
189
+ 0 0 10px var(--color-neon-cyan),
190
+ 0 0 15px var(--color-neon-pink); /* Pink/Cyan glow */
191
+ margin-bottom: 25px;
192
+ letter-spacing: 2px;
193
+ }
194
+
195
+ h3 {
196
+ font-family: var(--font-heading);
197
+ color: var(--color-neon-orange);
198
+ text-shadow: 0 0 5px var(--color-neon-orange);
199
+ margin-bottom: 10px;
200
+ font-weight: 400;
201
+ letter-spacing: 1px;
202
+ }
203
+
204
+ .controls, .prompt-controls, .simulation-controls {
205
+ margin: 10px;
206
+ padding: 15px 20px; /* More padding */
207
+ background-color: rgba(0, 0, 0, 0.3); /* Translucent dark background */
208
+ border: 1px solid var(--color-neon-purple);
209
+ box-shadow: 0 0 10px var(--color-neon-purple); /* Purple glow */
210
+ border-radius: 5px;
211
+ display: flex;
212
+ flex-wrap: wrap;
213
+ gap: 15px; /* More gap */
214
+ align-items: center;
215
+ justify-content: center;
216
+ width: 80%; /* Limit width */
217
+ max-width: 850px;
218
+ }
219
+
220
+ label {
221
+ color: var(--color-neon-cyan);
222
+ text-shadow: 0 0 3px var(--color-neon-cyan);
223
+ font-weight: bold;
224
+ }
225
+
226
+ select, input /* Style select boxes similarly */ {
227
+ background-color: var(--color-background-light);
228
+ color: var(--color-text);
229
+ border: 1px solid var(--color-neon-pink);
230
+ padding: 5px 8px;
231
+ border-radius: 3px;
232
+ font-family: var(--font-body);
233
+ box-shadow: inset 0 0 5px rgba(255, 0, 255, 0.5); /* Inner pink glow */
234
+ }
235
+
236
+ select option {
237
+ background-color: var(--color-background);
238
+ color: var(--color-text);
239
+ }
240
+
241
+
242
+ .gpu-container {
243
+ border: 2px solid var(--color-neon-cyan); /* Cyan border */
244
+ margin-top: 20px;
245
+ margin-bottom: 20px;
246
+ background-color: var(--color-background); /* Use dark bg for canvas container */
247
+ width: 800px;
248
+ height: 400px;
249
+ overflow: hidden;
250
+ box-shadow: 0 0 15px var(--color-neon-cyan), /* Outer glow */
251
+ inset 0 0 10px rgba(0, 0, 0, 0.5); /* Inner shadow */
252
+ padding: 2px; /* Small padding so border doesn't overlap blocks */
253
+ }
254
+
255
+ #gpuCanvas {
256
+ display: block;
257
+ background-color: var(--color-background); /* Match container */
258
+ }
259
+
260
+ /* --- Button Styling --- */
261
+ .prompt-button, .simulation-button, #reset-button {
262
+ padding: 10px 18px; /* Larger buttons */
263
+ border: none; /* Remove default border */
264
+ border-bottom: 2px solid; /* Add bottom border for 3D effect */
265
+ cursor: pointer;
266
+ border-radius: 4px;
267
+ font-weight: bold;
268
+ font-family: var(--font-body);
269
+ background-color: var(--color-background-light);
270
+ color: var(--color-text);
271
+ transition: all 0.2s ease;
272
+ text-shadow: 0 0 4px; /* Apply base text shadow */
273
+ box-shadow: 0 0 5px, inset 0 0 3px rgba(0,0,0,0.4); /* Apply base box shadow */
274
+ }
275
+
276
+ .prompt-button:hover, .simulation-button:hover, #reset-button:hover {
277
+ opacity: 0.9;
278
+ transform: translateY(-1px); /* Slight lift on hover */
279
+ }
280
+
281
+ .prompt-button:active, .simulation-button:active, #reset-button:active {
282
+ transform: translateY(1px); /* Push down on click */
283
+ box-shadow: 0 0 2px, inset 0 0 5px rgba(0,0,0,0.6);
284
+ }
285
+
286
+ /* Specific Button Colors & Glows */
287
+ #reset-button {
288
+ border-color: var(--color-neon-red);
289
+ color: var(--color-neon-red);
290
+ text-shadow: 0 0 4px var(--color-neon-red);
291
+ box-shadow: 0 0 5px var(--color-neon-red), inset 0 0 3px rgba(0,0,0,0.4);
292
+ }
293
+ #reset-button:hover { box-shadow: 0 0 8px var(--color-neon-red), inset 0 0 3px rgba(0,0,0,0.4); }
294
+
295
+ .prompt-button[data-size="3"] { /* Short -> Pink */
296
+ border-color: var(--color-neon-pink);
297
+ color: var(--color-neon-pink);
298
+ text-shadow: 0 0 4px var(--color-neon-pink);
299
+ box-shadow: 0 0 5px var(--color-neon-pink), inset 0 0 3px rgba(0,0,0,0.4);
300
+ }
301
+ .prompt-button[data-size="3"]:hover { box-shadow: 0 0 8px var(--color-neon-pink), inset 0 0 3px rgba(0,0,0,0.4); }
302
+
303
+
304
+ .prompt-button[data-size="5"] { /* Mid -> Cyan */
305
+ border-color: var(--color-neon-cyan);
306
+ color: var(--color-neon-cyan);
307
+ text-shadow: 0 0 4px var(--color-neon-cyan);
308
+ box-shadow: 0 0 5px var(--color-neon-cyan), inset 0 0 3px rgba(0,0,0,0.4);
309
+ }
310
+ .prompt-button[data-size="5"]:hover { box-shadow: 0 0 8px var(--color-neon-cyan), inset 0 0 3px rgba(0,0,0,0.4); }
311
+
312
+
313
+ .prompt-button[data-size="15"] { /* Long -> Yellow */
314
+ border-color: var(--color-neon-yellow);
315
+ color: var(--color-neon-yellow);
316
+ text-shadow: 0 0 4px var(--color-neon-yellow);
317
+ box-shadow: 0 0 5px var(--color-neon-yellow), inset 0 0 3px rgba(0,0,0,0.4);
318
+ }
319
+ .prompt-button[data-size="15"]:hover { box-shadow: 0 0 8px var(--color-neon-yellow), inset 0 0 3px rgba(0,0,0,0.4); }
320
+
321
+
322
+ .simulation-button { /* Simulation -> Orange */
323
+ border-color: var(--color-neon-orange);
324
+ color: var(--color-neon-orange);
325
+ text-shadow: 0 0 4px var(--color-neon-orange);
326
+ box-shadow: 0 0 5px var(--color-neon-orange), inset 0 0 3px rgba(0,0,0,0.4);
327
+ }
328
+ .simulation-button:hover { box-shadow: 0 0 8px var(--color-neon-orange), inset 0 0 3px rgba(0,0,0,0.4); }
329
+
330
+ .simulation-button:disabled {
331
+ border-color: #555;
332
+ color: #777;
333
+ text-shadow: none;
334
+ box-shadow: inset 0 0 5px rgba(0,0,0,0.6);
335
+ cursor: not-allowed;
336
+ opacity: 0.6;
337
+ transform: translateY(0);
338
+ }
339
+
340
+ #status-message {
341
+ font-weight: bold;
342
+ color: var(--color-text); /* White status text */
343
+ text-shadow: 0 0 3px var(--color-neon-purple); /* Purple glow */
344
+ min-width: 150px;
345
+ text-align: center;
346
+ flex-basis: 100%;
347
+ margin-top: 10px; /* More space for status */
348
+ letter-spacing: 1px;
349
+ }
350
+ #status-message {
351
+ font-weight: bold;
352
+ color: var(--color-text); /* Default white */
353
+ text-shadow: 0 0 3px var(--color-neon-purple); /* Default purple glow */
354
+ min-width: 150px;
355
+ text-align: center;
356
+ flex-basis: 100%;
357
+ margin-top: 10px;
358
+ letter-spacing: 1px;
359
+ transition: color 0.3s ease, text-shadow 0.3s ease; /* Smooth transition for color change */
360
+ }
361
+
362
+ /* ++ New Style for Error Status ++ */
363
+ #status-message.error {
364
+ color: var(--color-neon-red); /* Use neon red for errors */
365
+ text-shadow: 0 0 5px var(--color-neon-red), /* Stronger red glow */
366
+ 0 0 8px #ff0000;
367
+ }
368
+
369
+ #status-message {
370
+ font-weight: bold;
371
+ color: var(--color-text);
372
+ text-shadow: 0 0 3px var(--color-neon-purple);
373
+ min-width: 150px;
374
+ text-align: center;
375
+ flex-basis: 100%;
376
+ margin-top: 10px;
377
+ letter-spacing: 1px;
378
+ transition: color 0.3s ease, text-shadow 0.3s ease; /* Smooth transition */
379
+ }
380
+
381
+ /* ++ Style for Error Message ++ */
382
+ #status-message.error {
383
+ color: var(--color-neon-red);
384
+ text-shadow: 0 0 5px var(--color-neon-red);
385
+ }
386
+ /* --- Legend Styling --- */
387
+ .legend {
388
+ margin-top: 25px; /* Space above the legend */
389
+ padding: 15px 20px;
390
+ background-color: rgba(0, 0, 0, 0.3);
391
+ border: 1px solid var(--color-neon-purple);
392
+ box-shadow: 0 0 10px var(--color-neon-purple);
393
+ border-radius: 5px;
394
+ width: 80%;
395
+ max-width: 500px; /* Make legend less wide */
396
+ text-align: center;
397
+ }
398
+
399
+ .legend h3 {
400
+ margin-top: 0; /* Remove extra top margin from heading */
401
+ margin-bottom: 15px;
402
+ color: var(--color-neon-orange); /* Match other headings */
403
+ text-shadow: 0 0 5px var(--color-neon-orange);
404
+ }
405
+
406
+ .legend-item {
407
+ display: flex; /* Align color swatch and text */
408
+ align-items: center;
409
+ justify-content: center; /* Center items within the flex line */
410
+ margin-bottom: 8px; /* Space between legend items */
411
+ font-size: 0.9em; /* Slightly smaller text */
412
+ color: var(--color-text);
413
+ }
414
+
415
+ .legend-color {
416
+ display: inline-block;
417
+ width: 15px; /* Size of the color swatch */
418
+ height: 15px;
419
+ margin-right: 10px; /* Space between swatch and text */
420
+ border-radius: 3px; /* Slightly rounded corners */
421
+ vertical-align: middle; /* Align with text */
422
+ box-shadow: inset 0 0 3px rgba(0,0,0,0.5); /* Subtle inner shadow */
423
+ }
424
+ </style>
425
+
426
+ </head>
427
+ <body>
428
+ <h1>GPU Inference Pulse (SLM Edition)</h1>
429
+
430
+ <div class="controls">
431
+ <label for="gpu-select">SYSTEM:</label>
432
+ <select id="gpu-select">
433
+ <option value="L4" selected>L4 24GB (Standard)</option>
434
+ <option value="A100">A100 40GB (High)</option>
435
+ <option value="H100">H100 80GB (Mega)</option>
436
+ </select>
437
+
438
+ <label for="model-select">MODEL:</label>
439
+ <select id="model-select">
440
+ <option value="gemma-1b" selected>Gemma 3 1B</option>
441
+ <option value="gemma-4b">Gemma 3 4B</option>
442
+ <option value="gemma-12b">Gemma 3 12B</option>
443
+ <option value="gemma-27b">Gemma 3 27B</option>
444
+ </select>
445
+
446
+ <button id="reset-button">RESET GRID</button>
447
+ <span id="status-message">SYSTEM IDLE.</span>
448
+ </div>
449
+
450
+ <div class="gpu-container">
451
+ <canvas id="gpuCanvas" width="800"></canvas>
452
+ </div>
453
+
454
+ <div class="prompt-controls">
455
+ <h3>INITIATE PROMPT:</h3>
456
+ <button class="prompt-button" data-size="3">SHORT (3)</button>
457
+ <button class="prompt-button" data-size="5">MEDIUM (5)</button>
458
+ <button class="prompt-button" data-size="15">LONG (15)</button>
459
+ </div>
460
+
461
+ <div class="simulation-controls">
462
+ <h3>SIMULATE LOAD:</h3>
463
+ <button class="simulation-button" id="workday-pattern">WORKDAY</button>
464
+ <button class="simulation-button" id="batch-pattern">BATCH RUN</button>
465
+ <!-- ++ Add Burst Hell Button ++ -->
466
+ <button class="simulation-button" id="burst-hell-pattern">BURST HELL</button>
467
+ <!-- ++ End Add ++ -->
468
+ </div>
469
+ <script src="script.js"></script> <!-- Keep your script tag -->
470
+
471
+ <!-- Color Legend Section -->
472
+ <div class="legend">
473
+ <h3>LEGEND:</h3>
474
+ <div class="legend-item">
475
+ <span class="legend-color" style="background-color: #4d4dff;"></span> Model Weights Memory Footprint
476
+ </div>
477
+ <div class="legend-item">
478
+ <span class="legend-color" style="background-color: #ff00ff;"></span> Short Prompt Input Tokens
479
+ </div>
480
+ <div class="legend-item">
481
+ <span class="legend-color" style="background-color: #00ffff;"></span> Medium Prompt Input Tokens
482
+ </div>
483
+ <div class="legend-item">
484
+ <span class="legend-color" style="background-color: #fff000;"></span> Long Prompt Input Tokens
485
+ </div>
486
+ <div class="legend-item">
487
+ <span class="legend-color" style="background-color: #9d00ff;"></span> Processing Input Tokens
488
+ </div>
489
+ <div class="legend-item">
490
+ <span class="legend-color" style="background-color: #ff1f1f;"></span> Generated Tokens (Output)
491
+ </div>
492
+ <div class="legend-item">
493
+ <span class="legend-color" style="background-color: #1a1a2e; border: 1px solid #555;"></span> Free Memory
494
+ </div>
495
+ </div>
496
+ <!-- End Color Legend Section -->
497
+ <h2>fredmo</h2>
498
+ </body>
499
+ </html>