FlameF0X commited on
Commit
918f706
·
verified ·
1 Parent(s): 43db06d

Delete src

Browse files
Files changed (8) hide show
  1. src/App.css +0 -38
  2. src/App.js +0 -619
  3. src/App.test.js +0 -8
  4. src/index.css +0 -13
  5. src/index.js +0 -17
  6. src/logo.svg +0 -1
  7. src/reportWebVitals.js +0 -13
  8. src/setupTests.js +0 -5
src/App.css DELETED
@@ -1,38 +0,0 @@
1
- .App {
2
- text-align: center;
3
- }
4
-
5
- .App-logo {
6
- height: 40vmin;
7
- pointer-events: none;
8
- }
9
-
10
- @media (prefers-reduced-motion: no-preference) {
11
- .App-logo {
12
- animation: App-logo-spin infinite 20s linear;
13
- }
14
- }
15
-
16
- .App-header {
17
- background-color: #282c34;
18
- min-height: 100vh;
19
- display: flex;
20
- flex-direction: column;
21
- align-items: center;
22
- justify-content: center;
23
- font-size: calc(10px + 2vmin);
24
- color: white;
25
- }
26
-
27
- .App-link {
28
- color: #61dafb;
29
- }
30
-
31
- @keyframes App-logo-spin {
32
- from {
33
- transform: rotate(0deg);
34
- }
35
- to {
36
- transform: rotate(360deg);
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/App.js DELETED
@@ -1,619 +0,0 @@
1
- import React, { useState, useEffect, useRef, useMemo } from 'react';
2
- import {
3
- Activity,
4
- Settings,
5
- Play,
6
- Square,
7
- Trash2,
8
- Layers,
9
- Cpu,
10
- Zap,
11
- Plus,
12
- Info,
13
- Database,
14
- Move,
15
- Maximize,
16
- Search,
17
- ZoomIn,
18
- ZoomOut
19
- } from 'lucide-react';
20
- import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
21
-
22
- // --- BLOCK DEFINITIONS ---
23
- const BLOCK_TYPES = {
24
- INPUT: {
25
- id: 'INPUT',
26
- label: 'Data In',
27
- category: 'IO',
28
- color: 'bg-emerald-500',
29
- outputs: 1,
30
- inputs: 0,
31
- config: { batchSize: 32, seqLen: 128, vocabSize: 5000 }
32
- },
33
- EMBED: {
34
- id: 'EMBED',
35
- label: 'Embedding',
36
- category: 'Core',
37
- color: 'bg-blue-500',
38
- outputs: 1,
39
- inputs: 1,
40
- config: { dim: 512 }
41
- },
42
- ATTN: {
43
- id: 'ATTN',
44
- label: 'Attention',
45
- category: 'Core',
46
- color: 'bg-indigo-600',
47
- outputs: 1,
48
- inputs: 1,
49
- config: { heads: 8, headDim: 64, dropout: 0.1 }
50
- },
51
- FFN: {
52
- id: 'FFN',
53
- label: 'Feed Forward',
54
- category: 'Core',
55
- color: 'bg-blue-600',
56
- outputs: 1,
57
- inputs: 1,
58
- config: { mult: 4, dropout: 0.1 }
59
- },
60
- NORM: {
61
- id: 'NORM',
62
- label: 'Layer Norm',
63
- category: 'Core',
64
- color: 'bg-slate-500',
65
- outputs: 1,
66
- inputs: 1,
67
- config: { eps: 1e-5 }
68
- },
69
- LSTM: {
70
- id: 'LSTM',
71
- label: 'LSTM',
72
- category: 'RNN',
73
- color: 'bg-amber-500',
74
- outputs: 1,
75
- inputs: 1,
76
- config: { hidden: 512, layers: 1 }
77
- },
78
- MAMBA: {
79
- id: 'MAMBA',
80
- label: 'Mamba (SSM)',
81
- category: 'Modern',
82
- color: 'bg-purple-600',
83
- outputs: 1,
84
- inputs: 1,
85
- config: { d_state: 16, d_conv: 4, expand: 2 }
86
- },
87
- RWKV: {
88
- id: 'RWKV',
89
- label: 'RWKV',
90
- category: 'Modern',
91
- color: 'bg-fuchsia-600',
92
- outputs: 1,
93
- inputs: 1,
94
- config: { mode: 'v5', head_size: 64 }
95
- },
96
- RESIDUAL: {
97
- id: 'RESIDUAL',
98
- label: 'Residual +',
99
- category: 'Utility',
100
- color: 'bg-cyan-500',
101
- outputs: 1,
102
- inputs: 2,
103
- config: {}
104
- },
105
- OUTPUT: {
106
- id: 'OUTPUT',
107
- label: 'Data Out',
108
- category: 'IO',
109
- color: 'bg-red-500',
110
- outputs: 0,
111
- inputs: 1,
112
- config: { loss: 'CrossEntropy' }
113
- }
114
- };
115
-
116
- const App = () => {
117
- // State for Blocks and Connections
118
- const [nodes, setNodes] = useState([
119
- { id: 'n1', type: 'INPUT', x: 50, y: 150, config: BLOCK_TYPES.INPUT.config },
120
- { id: 'n2', type: 'EMBED', x: 250, y: 150, config: BLOCK_TYPES.EMBED.config },
121
- { id: 'n3', type: 'OUTPUT', x: 450, y: 150, config: BLOCK_TYPES.OUTPUT.config },
122
- ]);
123
- const [connections, setConnections] = useState([
124
- { id: 'c1', from: 'n1', to: 'n2' },
125
- { id: 'c2', from: 'n2', to: 'n3' }
126
- ]);
127
-
128
- // UI & Viewport State
129
- const [viewOffset, setViewOffset] = useState({ x: 0, y: 0 });
130
- const [zoom, setZoom] = useState(1);
131
- const [isPanning, setIsPanning] = useState(false);
132
- const [panStart, setPanStart] = useState({ x: 0, y: 0 });
133
-
134
- const [selectedNodeId, setSelectedNodeId] = useState(null);
135
- const [isTraining, setIsTraining] = useState(false);
136
- const [trainingData, setTrainingData] = useState([]);
137
- const [learningRate, setLearningRate] = useState(0.001);
138
- const [isDraggingNode, setIsDraggingNode] = useState(null);
139
- const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
140
- const [connectingFrom, setConnectingFrom] = useState(null);
141
-
142
- const canvasRef = useRef(null);
143
-
144
- // --- SIMULATION ENGINE ---
145
- const runTrainingStep = (epoch) => {
146
- const hasInput = nodes.some(n => n.type === 'INPUT');
147
- const hasOutput = nodes.some(n => n.type === 'OUTPUT');
148
- if (!hasInput || !hasOutput) return null;
149
-
150
- let capacity = 0;
151
- let vanishingGradientRisk = 1.0;
152
-
153
- nodes.forEach(n => {
154
- if (n.type === 'EMBED') capacity += (n.config.dim || 512) * 0.1;
155
- if (n.type === 'ATTN') capacity += (n.config.heads * n.config.headDim) * 0.5;
156
- if (n.type === 'FFN') capacity += (n.config.mult * 512) * 0.3;
157
- if (n.type === 'LSTM') {
158
- capacity += (n.config.hidden || 512) * 0.4;
159
- vanishingGradientRisk *= 0.85;
160
- }
161
- if (n.type === 'NORM') vanishingGradientRisk = Math.min(1.0, vanishingGradientRisk + 0.2);
162
- if (n.type === 'RESIDUAL') vanishingGradientRisk = Math.min(1.0, vanishingGradientRisk + 0.3);
163
- });
164
-
165
- const trainability = Math.max(0.1, (capacity / 500) * vanishingGradientRisk);
166
- const noise = (Math.random() - 0.5) * 0.05;
167
- const lrFactor = learningRate > 0.01 ? (0.5 + Math.random()) : 1.0;
168
-
169
- const baseLoss = 8.0;
170
- const decay = 0.05 * trainability * (1 / lrFactor);
171
- const loss = baseLoss * Math.exp(-decay * epoch) + (0.2 / (epoch + 1)) + noise;
172
- const acc = Math.min(0.99, 1 - (loss / baseLoss) + (Math.random() * 0.02));
173
-
174
- return {
175
- epoch,
176
- loss: Math.max(0, loss).toFixed(4),
177
- accuracy: Math.max(0, acc).toFixed(4)
178
- };
179
- };
180
-
181
- useEffect(() => {
182
- let interval;
183
- if (isTraining) {
184
- interval = setInterval(() => {
185
- setTrainingData(prev => {
186
- const nextEpoch = prev.length;
187
- if (nextEpoch > 150) { setIsTraining(false); return prev; }
188
- const step = runTrainingStep(nextEpoch);
189
- return [...prev, step];
190
- });
191
- }, 150);
192
- }
193
- return () => clearInterval(interval);
194
- }, [isTraining, nodes, connections, learningRate]);
195
-
196
- // --- INTERACTION HANDLERS ---
197
- const handleWheel = (e) => {
198
- e.preventDefault();
199
- const zoomSpeed = 0.001;
200
- const newZoom = Math.min(Math.max(zoom - e.deltaY * zoomSpeed, 0.2), 2);
201
- setZoom(newZoom);
202
- };
203
-
204
- const addNode = (type) => {
205
- const newNode = {
206
- id: `n${Date.now()}`,
207
- type,
208
- // Place node relative to current view center and zoom
209
- x: (-viewOffset.x + 100) / zoom,
210
- y: (-viewOffset.y + 100) / zoom,
211
- config: { ...BLOCK_TYPES[type].config }
212
- };
213
- setNodes([...nodes, newNode]);
214
- };
215
-
216
- const deleteNode = (id) => {
217
- setNodes(nodes.filter(n => n.id !== id));
218
- setConnections(connections.filter(c => c.from !== id && c.to !== id));
219
- if (selectedNodeId === id) setSelectedNodeId(null);
220
- };
221
-
222
- const deleteConnection = (id) => {
223
- setConnections(connections.filter(c => c.id !== id));
224
- };
225
-
226
- const handleCanvasMouseDown = (e) => {
227
- if (e.target === canvasRef.current || e.target.tagName === 'svg' || e.target.id === 'grid-background') {
228
- setIsPanning(true);
229
- setPanStart({ x: e.clientX - viewOffset.x, y: e.clientY - viewOffset.y });
230
- setSelectedNodeId(null);
231
- }
232
- };
233
-
234
- const handleNodeMouseDown = (e, id) => {
235
- e.stopPropagation();
236
- if (connectingFrom) return;
237
- setIsDraggingNode(id);
238
- const node = nodes.find(n => n.id === id);
239
- // Dragging logic needs to account for zoom
240
- setDragOffset({ x: e.clientX / zoom - node.x, y: e.clientY / zoom - node.y });
241
- setSelectedNodeId(id);
242
- };
243
-
244
- const handleMouseMove = (e) => {
245
- if (isDraggingNode) {
246
- setNodes(nodes.map(n => n.id === isDraggingNode ? { ...n, x: e.clientX / zoom - dragOffset.x, y: e.clientY / zoom - dragOffset.y } : n));
247
- } else if (isPanning) {
248
- setViewOffset({
249
- x: e.clientX - panStart.x,
250
- y: e.clientY - panStart.y
251
- });
252
- }
253
- };
254
-
255
- const handleMouseUp = () => {
256
- setIsDraggingNode(null);
257
- setIsPanning(false);
258
- };
259
-
260
- const startConnection = (e, id) => {
261
- e.stopPropagation();
262
- setConnectingFrom(id);
263
- };
264
-
265
- const endConnection = (e, id) => {
266
- e.stopPropagation();
267
- if (connectingFrom && connectingFrom !== id) {
268
- if (!connections.some(c => c.from === connectingFrom && c.to === id)) {
269
- setConnections([...connections, { id: `c${Date.now()}`, from: connectingFrom, to: id }]);
270
- }
271
- }
272
- setConnectingFrom(null);
273
- };
274
-
275
- const updateConfig = (key, val) => {
276
- setNodes(nodes.map(n => n.id === selectedNodeId ? { ...n, config: { ...n.config, [key]: val } } : n));
277
- };
278
-
279
- const resetView = () => {
280
- setViewOffset({ x: 0, y: 0 });
281
- setZoom(1);
282
- };
283
-
284
- const selectedNode = nodes.find(n => n.id === selectedNodeId);
285
-
286
- // Calculated properties for infinite grid
287
- const gridSize = 24 * zoom;
288
- const gridOffsetX = viewOffset.x % gridSize;
289
- const gridOffsetY = viewOffset.y % gridSize;
290
-
291
- return (
292
- <div className="flex flex-col h-screen w-screen bg-slate-950 text-slate-100 overflow-hidden font-sans">
293
- {/* Header */}
294
- <header className="h-16 border-b border-slate-800 flex items-center justify-between px-6 bg-slate-900/50 backdrop-blur-md z-20">
295
- <div className="flex items-center gap-3">
296
- <div className="p-2 bg-indigo-500 rounded-lg">
297
- <Layers size={20} className="text-white" />
298
- </div>
299
- <h1 className="text-lg font-bold tracking-tight">Arch-Sim <span className="text-slate-500 font-normal">v1.2</span></h1>
300
- </div>
301
-
302
- <div className="flex items-center gap-4">
303
- <div className="flex items-center bg-slate-800 rounded-full px-4 py-1.5 gap-3 border border-slate-700">
304
- <span className="text-xs text-slate-400 uppercase font-semibold">LR</span>
305
- <input
306
- type="range"
307
- min="0.0001"
308
- max="0.05"
309
- step="0.0001"
310
- value={learningRate}
311
- onChange={(e) => setLearningRate(parseFloat(e.target.value))}
312
- className="w-24 accent-indigo-500"
313
- />
314
- <span className="text-xs font-mono w-12">{learningRate}</span>
315
- </div>
316
-
317
- <button
318
- onClick={() => {
319
- if (isTraining) setIsTraining(false);
320
- else {
321
- setTrainingData([]);
322
- setIsTraining(true);
323
- }
324
- }}
325
- className={`flex items-center gap-2 px-5 py-2 rounded-lg font-medium transition-all ${
326
- isTraining ? 'bg-red-500 hover:bg-red-600' : 'bg-emerald-500 hover:bg-emerald-600'
327
- }`}
328
- >
329
- {isTraining ? <><Square size={16} fill="currentColor" /> Stop</> : <><Play size={16} fill="currentColor" /> Start Training</>}
330
- </button>
331
- </div>
332
- </header>
333
-
334
- <main className="flex-1 flex overflow-hidden">
335
- {/* Sidebar: Blocks Palette */}
336
- <aside className="w-64 border-r border-slate-800 bg-slate-900/30 p-4 flex flex-col gap-6 overflow-y-auto z-10">
337
- <div>
338
- <h3 className="text-xs font-bold text-slate-500 uppercase tracking-widest mb-4">Components</h3>
339
- <div className="grid grid-cols-1 gap-2">
340
- {Object.entries(BLOCK_TYPES).map(([key, type]) => (
341
- <button
342
- key={key}
343
- onClick={() => addNode(key)}
344
- className="flex items-center gap-3 p-3 rounded-xl border border-slate-800 bg-slate-900/50 hover:border-indigo-500/50 hover:bg-slate-800/50 transition-all text-left group"
345
- >
346
- <div className={`w-8 h-8 rounded-lg ${type.color} flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform`}>
347
- <Cpu size={14} />
348
- </div>
349
- <div>
350
- <div className="text-sm font-semibold">{type.label}</div>
351
- <div className="text-[10px] text-slate-500 uppercase">{type.category}</div>
352
- </div>
353
- <Plus size={14} className="ml-auto text-slate-600 group-hover:text-indigo-400" />
354
- </button>
355
- ))}
356
- </div>
357
- </div>
358
- </aside>
359
-
360
- {/* Canvas Area */}
361
- <div
362
- className="flex-1 relative bg-slate-950 overflow-hidden cursor-grab active:cursor-grabbing outline-none"
363
- onMouseDown={handleCanvasMouseDown}
364
- onMouseMove={handleMouseMove}
365
- onMouseUp={handleMouseUp}
366
- onWheel={handleWheel}
367
- ref={canvasRef}
368
- >
369
- {/* Infinite Dot Grid Background */}
370
- <div
371
- id="grid-background"
372
- className="absolute inset-0 pointer-events-none"
373
- style={{
374
- backgroundImage: `radial-gradient(circle, #1e293b 1px, transparent 1px)`,
375
- backgroundSize: `${gridSize}px ${gridSize}px`,
376
- backgroundPosition: `${gridOffsetX}px ${gridOffsetY}px`
377
- }}
378
- />
379
-
380
- {/* Viewport Transform Container */}
381
- <div
382
- className="absolute inset-0 pointer-events-none"
383
- style={{
384
- transform: `translate(${viewOffset.x}px, ${viewOffset.y}px) scale(${zoom})`,
385
- transformOrigin: '0 0'
386
- }}
387
- >
388
- {/* Connections SVG */}
389
- <svg className="absolute inset-0 w-[10000px] h-[10000px] pointer-events-auto overflow-visible">
390
- <defs>
391
- <marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
392
- <path d="M 0 0 L 10 5 L 0 10 z" fill="#6366f1" />
393
- </marker>
394
- </defs>
395
- {connections.map(conn => {
396
- const fromNode = nodes.find(n => n.id === conn.from);
397
- const toNode = nodes.find(n => n.id === conn.to);
398
- if (!fromNode || !toNode) return null;
399
-
400
- const x1 = fromNode.x + 160;
401
- const y1 = fromNode.y + 40;
402
- const x2 = toNode.x;
403
- const y2 = toNode.y + 40;
404
- const dx = (x2 - x1) / 2;
405
-
406
- return (
407
- <g key={conn.id} className="group cursor-pointer">
408
- <path
409
- d={`M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`}
410
- stroke="transparent"
411
- strokeWidth={20 / zoom} // Adjust hit area based on zoom
412
- fill="none"
413
- onClick={(e) => { e.stopPropagation(); deleteConnection(conn.id); }}
414
- />
415
- <path
416
- d={`M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`}
417
- stroke="#6366f1"
418
- strokeWidth={3}
419
- strokeDasharray={isTraining ? "8 4" : "0"}
420
- className={`${isTraining ? "animate-[dash_1s_linear_infinite]" : ""} group-hover:stroke-red-500 transition-colors`}
421
- fill="none"
422
- markerEnd="url(#arrow)"
423
- opacity="0.6"
424
- />
425
- </g>
426
- );
427
- })}
428
- </svg>
429
-
430
- {/* Nodes */}
431
- {nodes.map(node => {
432
- const type = BLOCK_TYPES[node.type];
433
- const isSelected = selectedNodeId === node.id;
434
- return (
435
- <div
436
- key={node.id}
437
- style={{ left: node.x, top: node.y }}
438
- onMouseDown={(e) => handleNodeMouseDown(e, node.id)}
439
- className={`absolute w-40 p-4 rounded-xl border-2 transition-shadow cursor-move select-none pointer-events-auto ${
440
- isSelected ? 'border-indigo-500 bg-slate-800 shadow-[0_0_25px_rgba(99,102,241,0.2)]' : 'border-slate-800 bg-slate-900/90'
441
- }`}
442
- >
443
- <div className="flex justify-between items-start mb-2">
444
- <div className={`w-8 h-8 rounded-lg ${type.color} flex items-center justify-center shadow-lg mb-2`}>
445
- <Cpu size={14} />
446
- </div>
447
- {isSelected && (
448
- <button onClick={(e) => { e.stopPropagation(); deleteNode(node.id); }} className="text-slate-500 hover:text-red-400">
449
- <Trash2 size={14} />
450
- </button>
451
- )}
452
- </div>
453
-
454
- <h4 className="text-xs font-bold uppercase tracking-wide truncate">{type.label}</h4>
455
- <div className="text-[10px] text-slate-500 mb-4">{node.id}</div>
456
-
457
- {/* Input Port */}
458
- {type.inputs > 0 && (
459
- <div
460
- onMouseUp={(e) => endConnection(e, node.id)}
461
- className={`absolute -left-3 top-1/2 -translate-y-1/2 w-6 h-6 rounded-full bg-slate-800 border-2 ${connectingFrom ? 'border-yellow-400 animate-pulse' : 'border-indigo-500'} flex items-center justify-center hover:bg-indigo-500 cursor-pointer z-30`}
462
- >
463
- <div className="w-1.5 h-1.5 bg-white rounded-full" />
464
- </div>
465
- )}
466
- {/* Output Port */}
467
- {type.outputs > 0 && (
468
- <div
469
- onMouseDown={(e) => startConnection(e, node.id)}
470
- className="absolute -right-3 top-1/2 -translate-y-1/2 w-6 h-6 rounded-full bg-slate-800 border-2 border-indigo-500 flex items-center justify-center hover:bg-indigo-500 cursor-pointer z-30"
471
- >
472
- <div className="w-1.5 h-1.5 bg-white rounded-full" />
473
- </div>
474
- )}
475
- </div>
476
- );
477
- })}
478
- </div>
479
-
480
- {/* Navigation Controls Overlay */}
481
- <div className="absolute bottom-6 left-6 flex flex-col gap-2 z-20">
482
- <div className="flex gap-2">
483
- <button
484
- onClick={resetView}
485
- className="p-3 bg-slate-900 border border-slate-700 rounded-lg hover:bg-slate-800 transition-colors shadow-xl text-slate-400 flex items-center gap-2"
486
- title="Reset View"
487
- >
488
- <Maximize size={18} />
489
- <span className="text-[10px] font-bold uppercase tracking-widest">{Math.round(zoom * 100)}%</span>
490
- </button>
491
- <button
492
- onClick={() => setZoom(prev => Math.min(prev + 0.1, 2))}
493
- className="p-3 bg-slate-900 border border-slate-700 rounded-lg hover:bg-slate-800 transition-colors shadow-xl text-slate-400"
494
- >
495
- <ZoomIn size={18} />
496
- </button>
497
- <button
498
- onClick={() => setZoom(prev => Math.max(prev - 0.1, 0.2))}
499
- className="p-3 bg-slate-900 border border-slate-700 rounded-lg hover:bg-slate-800 transition-colors shadow-xl text-slate-400"
500
- >
501
- <ZoomOut size={18} />
502
- </button>
503
- </div>
504
- <div className="p-3 bg-slate-900/80 border border-slate-700 rounded-lg shadow-xl text-[10px] text-slate-400 flex items-center gap-2">
505
- <Search size={14} /> Scroll to zoom, Drag background to pan
506
- </div>
507
- </div>
508
- </div>
509
-
510
- {/* Right Sidebar: Config & Monitoring */}
511
- <aside className="w-80 border-l border-slate-800 bg-slate-900/50 flex flex-col z-10">
512
- <div className="h-1/2 p-6 flex flex-col border-b border-slate-800">
513
- <div className="flex items-center gap-2 mb-4 text-slate-400 uppercase text-xs font-bold tracking-widest">
514
- <Activity size={14} /> Training Metrics
515
- </div>
516
-
517
- <div className="flex-1 bg-slate-900 rounded-xl p-2 border border-slate-800 overflow-hidden">
518
- {trainingData.length > 0 ? (
519
- <ResponsiveContainer width="100%" height="100%">
520
- <LineChart data={trainingData}>
521
- <CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
522
- <XAxis dataKey="epoch" hide />
523
- <YAxis hide domain={[0, 'auto']} />
524
- <Tooltip
525
- contentStyle={{ backgroundColor: '#0f172a', border: '1px solid #1e293b', borderRadius: '8px' }}
526
- itemStyle={{ color: '#6366f1' }}
527
- />
528
- <Line type="monotone" dataKey="loss" stroke="#6366f1" strokeWidth={2} dot={false} isAnimationActive={false} />
529
- </LineChart>
530
- </ResponsiveContainer>
531
- ) : (
532
- <div className="h-full flex flex-col items-center justify-center text-slate-600 italic text-sm text-center">
533
- Simulation idle.
534
- </div>
535
- )}
536
- </div>
537
-
538
- <div className="mt-4 grid grid-cols-2 gap-4">
539
- <div className="p-3 bg-slate-900/50 rounded-lg border border-slate-800 text-center">
540
- <div className="text-[10px] uppercase text-slate-500 font-bold mb-1">Loss</div>
541
- <div className="text-lg font-mono text-indigo-400">
542
- {trainingData.length > 0 ? trainingData[trainingData.length-1].loss : '0.0000'}
543
- </div>
544
- </div>
545
- <div className="p-3 bg-slate-900/50 rounded-lg border border-slate-800 text-center">
546
- <div className="text-[10px] uppercase text-slate-500 font-bold mb-1">Accuracy</div>
547
- <div className="text-lg font-mono text-emerald-400">
548
- {trainingData.length > 0 ? `${(trainingData[trainingData.length-1].accuracy * 100).toFixed(1)}%` : '0.0%'}
549
- </div>
550
- </div>
551
- </div>
552
- </div>
553
-
554
- <div className="h-1/2 p-6 overflow-y-auto">
555
- <div className="flex items-center gap-2 mb-6 text-slate-400 uppercase text-xs font-bold tracking-widest">
556
- <Settings size={14} /> {selectedNode ? 'Block Config' : 'Project Info'}
557
- </div>
558
-
559
- {selectedNode ? (
560
- <div className="space-y-6">
561
- <div className="flex items-center gap-3 p-3 bg-indigo-500/10 rounded-xl border border-indigo-500/20">
562
- <div className={`w-8 h-8 rounded-lg ${BLOCK_TYPES[selectedNode.type].color} flex items-center justify-center`}>
563
- <Cpu size={14} />
564
- </div>
565
- <div>
566
- <div className="font-bold text-sm">{BLOCK_TYPES[selectedNode.type].label}</div>
567
- <div className="text-[10px] text-indigo-300 font-mono uppercase">{selectedNode.id}</div>
568
- </div>
569
- </div>
570
-
571
- <div className="space-y-4">
572
- {Object.entries(selectedNode.config).map(([key, val]) => (
573
- <div key={key} className="space-y-1.5">
574
- <label className="text-[11px] font-bold text-slate-500 uppercase flex justify-between">
575
- {key} <span>{val}</span>
576
- </label>
577
- <input
578
- type={typeof val === 'number' ? 'range' : 'text'}
579
- min={1}
580
- max={1024}
581
- value={val}
582
- onChange={(e) => updateConfig(key, typeof val === 'number' ? parseInt(e.target.value) : e.target.value)}
583
- className="w-full h-1.5 bg-slate-800 rounded-lg appearance-none cursor-pointer accent-indigo-500"
584
- />
585
- </div>
586
- ))}
587
- </div>
588
- </div>
589
- ) : (
590
- <div className="space-y-4">
591
- <div className="p-4 bg-slate-800/30 rounded-xl border border-slate-700/50 text-xs text-slate-400 space-y-3">
592
- <p><strong className="text-slate-300">Navigation:</strong> Click and drag the background to pan. <span className="text-indigo-400 font-bold">Use mouse wheel to zoom.</span></p>
593
- <p><strong className="text-slate-300">Infinite Grid:</strong> The canvas background scales and repeats automatically as you navigate.</p>
594
- </div>
595
- </div>
596
- )}
597
- </div>
598
- </aside>
599
- </main>
600
-
601
- <footer className="h-10 border-t border-slate-800 bg-slate-900/80 px-4 flex items-center justify-between text-[10px] text-slate-500 uppercase tracking-widest font-semibold">
602
- <div className="flex gap-4">
603
- <span>Blocks: {nodes.length}</span>
604
- <span>Links: {connections.length}</span>
605
- <span>Zoom: {(zoom * 100).toFixed(0)}%</span>
606
- </div>
607
- <div>Educational Arch-Sim Environment</div>
608
- </footer>
609
-
610
- <style>{`
611
- @keyframes dash {
612
- to { stroke-dashoffset: -12; }
613
- }
614
- `}</style>
615
- </div>
616
- );
617
- };
618
-
619
- export default App;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/App.test.js DELETED
@@ -1,8 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import App from './App';
3
-
4
- test('renders learn react link', () => {
5
- render(<App />);
6
- const linkElement = screen.getByText(/learn react/i);
7
- expect(linkElement).toBeInTheDocument();
8
- });
 
 
 
 
 
 
 
 
 
src/index.css DELETED
@@ -1,13 +0,0 @@
1
- body {
2
- margin: 0;
3
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5
- sans-serif;
6
- -webkit-font-smoothing: antialiased;
7
- -moz-osx-font-smoothing: grayscale;
8
- }
9
-
10
- code {
11
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12
- monospace;
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/index.js DELETED
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom/client';
3
- import './index.css';
4
- import App from './App';
5
- import reportWebVitals from './reportWebVitals';
6
-
7
- const root = ReactDOM.createRoot(document.getElementById('root'));
8
- root.render(
9
- <React.StrictMode>
10
- <App />
11
- </React.StrictMode>
12
- );
13
-
14
- // If you want to start measuring performance in your app, pass a function
15
- // to log results (for example: reportWebVitals(console.log))
16
- // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17
- reportWebVitals();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/logo.svg DELETED
src/reportWebVitals.js DELETED
@@ -1,13 +0,0 @@
1
- const reportWebVitals = onPerfEntry => {
2
- if (onPerfEntry && onPerfEntry instanceof Function) {
3
- import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4
- getCLS(onPerfEntry);
5
- getFID(onPerfEntry);
6
- getFCP(onPerfEntry);
7
- getLCP(onPerfEntry);
8
- getTTFB(onPerfEntry);
9
- });
10
- }
11
- };
12
-
13
- export default reportWebVitals;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/setupTests.js DELETED
@@ -1,5 +0,0 @@
1
- // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
- // allows you to do things like:
3
- // expect(element).toHaveTextContent(/react/i)
4
- // learn more: https://github.com/testing-library/jest-dom
5
- import '@testing-library/jest-dom';