11import React , { useState , useMemo , useRef , useCallback , useEffect } from 'react' ;
22import {
33 Play , Pause , Microscope ,
4- ArrowRight , Eraser , ChevronRight , Activity , Grid , MousePointer2 ,
5- Edit3 , Hash , Upload , Image as ImageIcon , Maximize ,
6- Calculator , TrendingUp , Type
4+ ArrowRight , Eraser , Activity , Grid , MousePointer2 ,
5+ Hash , Upload , Image as ImageIcon , Sun , Moon ,
6+ Calculator
77} from 'lucide-react' ;
88
99// --- MATH & LOGIC ENGINE ---
@@ -69,6 +69,9 @@ const ACTIVATIONS = {
6969export default function DeepLabCNN ( ) {
7070 // --- STATE ---
7171
72+ // Theme State (Default to 'dark')
73+ const [ theme , setTheme ] = useState ( 'dark' ) ;
74+
7275 // Dimensions
7376 const [ gridSize , setGridSize ] = useState ( 14 ) ;
7477 const [ kernelSize , setKernelSize ] = useState ( 3 ) ;
@@ -79,7 +82,7 @@ export default function DeepLabCNN() {
7982
8083 // Model Parameters
8184 const [ stride , setStride ] = useState ( 1 ) ;
82- const [ padding , setPadding ] = useState ( 0 ) ;
85+ const [ padding , setPadding ] = useState ( 0 ) ; // Always 0 (Valid)
8386 const [ activation , setActivation ] = useState ( 'relu' ) ;
8487
8588 // Filter State
@@ -322,16 +325,21 @@ export default function DeepLabCNN() {
322325 // Adjusted pixel size: 20 for interactive (bigger)
323326 const pixelSize = isInteractive ? 20 : 22 ;
324327
328+ const lightThemeGridBg = 'bg-slate-200' ;
329+ const darkThemeGridBg = 'bg-black' ;
330+ const gridBg = theme === 'light' ? lightThemeGridBg : darkThemeGridBg ;
331+ const gridBorder = theme === 'light' ? 'border-slate-400' : 'border-slate-700' ;
332+
325333 return (
326334 < div className = "flex flex-col items-center gap-2 relative group/grid" >
327335 < div className = "relative p-px" style = { {
328336 padding : usePadding > 0 ? `${ ( usePadding / dim ) * 100 } %` : '0' ,
329- border : usePadding > 0 ? '1px dashed #475569 ' : 'none'
337+ border : usePadding > 0 ? '1px dashed var(--color-border) ' : 'none'
330338 } } >
331339 { usePadding > 0 && < div className = "absolute -top-4 left-0 text-[8px] text-slate-500" > Padding: { usePadding } px</ div > }
332340
333341 < div
334- className = " relative bg-black border border-slate-700 shadow-lg select-none overflow-hidden"
342+ className = { ` relative ${ gridBg } ${ gridBorder } border shadow-lg select-none overflow-hidden` }
335343 style = { {
336344 width : dim * pixelSize + 'px' ,
337345 height : dim * pixelSize + 'px' ,
@@ -401,21 +409,38 @@ export default function DeepLabCNN() {
401409 } ;
402410
403411 const mathInfo = getMathDetails ( ) ;
412+
413+ const themeClasses = {
414+ dark : 'bg-slate-950 text-slate-200 border-slate-800' ,
415+ light : 'bg-white text-slate-900 border-slate-200' ,
416+ } ;
417+ const cardClasses = theme === 'dark' ? 'bg-slate-900 border-slate-800' : 'bg-slate-50 border-slate-200' ;
418+ const topBarClasses = theme === 'dark' ? 'bg-slate-900' : 'bg-slate-100' ;
419+
404420
405421 return (
406- < div className = " min-h-screen bg-slate-950 text-slate-200 font-sans selection:bg-blue-500 selection:text-white" >
422+ < div className = { ` min-h-screen font-sans selection:bg-blue-500 selection:text-white ${ themeClasses [ theme ] } ` } >
407423
408424 { /* Top Bar */ }
409- < div className = " h-20 border-b border-slate-800 flex items-center px-6 bg-slate-900 sticky top-0 z-20 overflow-x-auto" >
425+ < div className = { ` h-20 border-b ${ theme === 'dark' ? ' border-slate-800' : 'border-slate-300' } flex items-center px-6 ${ topBarClasses } sticky top-0 z-20 overflow-x-auto` } >
410426 < div className = "flex items-center gap-3 mr-8 shrink-0" >
411427 < div className = "bg-blue-600 p-1.5 rounded-lg" >
412428 < Microscope className = "w-5 h-5 text-white" />
413429 </ div >
414- < h1 className = "font-bold text-lg tracking-tight" > DeepLab CNN < span className = "font-normal text-slate-500" > v1.0</ span > </ h1 >
430+ < h1 className = "font-bold text-lg tracking-tight" > DeepLab < span className = "font-normal text-slate-500" > v1.0</ span > </ h1 >
415431 </ div >
416432
417433 < div className = "flex-1 flex items-center justify-end gap-6 text-sm shrink-0" >
418-
434+
435+ { /* Theme Toggle */ }
436+ < button
437+ onClick = { ( ) => setTheme ( theme === 'dark' ? 'light' : 'dark' ) }
438+ className = { `flex items-center px-3 py-1.5 rounded-full border text-xs transition-all ${ theme === 'dark' ? 'bg-slate-800 border-slate-700 text-yellow-400' : 'bg-slate-200 border-slate-300 text-indigo-600' } ` }
439+ title = "Toggle Theme"
440+ >
441+ { theme === 'dark' ? < Sun className = "w-4 h-4" /> : < Moon className = "w-4 h-4" /> }
442+ </ button >
443+
419444 { /* Values Toggle */ }
420445 < button
421446 onClick = { ( ) => setShowValues ( ! showValues ) }
@@ -460,13 +485,13 @@ export default function DeepLabCNN() {
460485 </ div >
461486
462487 { /* Activation & Graph */ }
463- < div className = " flex items-center gap-3 bg-slate-800/50 p-1.5 rounded-lg border border-slate-800" >
488+ < div className = { ` flex items-center gap-3 p-1.5 rounded-lg border ${ theme === 'dark' ? 'bg-slate-800/50 border-slate-800' : 'bg-slate-200 border-slate-300' } ` } >
464489 < div className = "flex flex-col" >
465490 < span className = "text-[10px] text-slate-500 uppercase font-bold mb-1" > Activation</ span >
466491 < select
467492 value = { activation }
468493 onChange = { ( e ) => setActivation ( e . target . value ) }
469- className = " bg-slate-900 border border-slate-700 text-xs rounded py-1 px-1 outline-none text-slate-300 w-20"
494+ className = { `border ${ theme === 'dark' ? ' bg-slate-900 border-slate-700 text-slate-300' : 'bg-white border-slate-300 text-slate-800' } text- xs rounded py-1 px-1 outline-none w-20` }
470495 >
471496 < option value = "relu" > ReLU</ option >
472497 < option value = "sigmoid" > Sigmoid</ option >
@@ -483,12 +508,12 @@ export default function DeepLabCNN() {
483508 < div className = "flex flex-col lg:flex-row h-[calc(100vh-80px)]" >
484509
485510 { /* LEFT COLUMN: INPUT & MATH */ }
486- < div className = " w-full lg:w-1/3 border-r border-slate-800 flex flex-col bg-slate-900 overflow-y-auto" >
511+ < div className = { ` w-full lg:w-1/3 border-r ${ theme === 'dark' ? ' border-slate-800 bg-slate-900' : 'border-slate-300 bg-slate-100' } flex flex-col overflow-y-auto` } >
487512
488513 { /* Drawing Area */ }
489- < div className = " p-6 border-b border-slate-800" >
514+ < div className = { ` p-6 border-b ${ theme === 'dark' ? ' border-slate-800' : 'border-slate-300' } ` } >
490515 < div className = "flex justify-between items-center mb-4" >
491- < h2 className = "text-slate-100 font-semibold flex items-center gap-2" >
516+ < h2 className = { ` font-semibold flex items-center gap-2 ${ theme === 'dark' ? 'text-slate-100' : 'text-slate-800' } ` } >
492517 < ImageIcon className = "w-4 h-4 text-blue-500" /> Input Layer
493518 </ h2 >
494519 < div className = "flex gap-2 items-center" >
@@ -520,11 +545,11 @@ export default function DeepLabCNN() {
520545 highlightRegion = { getInputHighlight ( ) }
521546 isInteractive = { true }
522547 showNums = { showValues }
523- usePadding = { padding === 1 ? Math . floor ( kernelSize / 2 ) * 20 : 0 } // Visual Padding Size
548+ usePadding = { 0 }
524549 />
525550 < div className = "absolute inset-0 flex items-center justify-center pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-500" >
526551 { ! inputGrid . some ( x => x > 0 ) && ! isDrawing && (
527- < div className = " flex flex-col items-center text-slate-500 bg-slate-900/90 px-4 py-2 rounded-xl backdrop-blur border border-slate-800" >
552+ < div className = { ` flex flex-col items-center ${ theme === 'dark' ? ' text-slate-500 bg-slate-900/90 border-slate-800' : 'text-slate-600 bg-slate-200/90 border-slate-300' } px-4 py-2 rounded-xl backdrop-blur border` } >
528553 < MousePointer2 className = "w-5 h-5 mb-1" />
529554 < span className = "font-mono text-xs" > Draw Here</ span >
530555 </ div >
@@ -535,37 +560,37 @@ export default function DeepLabCNN() {
535560 </ div >
536561
537562 { /* Math Explainer Panel */ }
538- < div className = " flex-1 p-6 bg-slate-900/50 overflow-y-auto" >
539- < h2 className = "text-slate-100 font-semibold flex items-center gap-2 mb-4" >
563+ < div className = { ` flex-1 p-6 ${ theme === 'dark' ? ' bg-slate-900/50' : 'bg-slate-100/50' } overflow-y-auto` } >
564+ < h2 className = { ` font-semibold flex items-center gap-2 mb-4 ${ theme === 'dark' ? 'text-slate-100' : 'text-slate-800' } ` } >
540565 < Calculator className = "w-4 h-4 text-amber-500" /> Convolution Math
541566 </ h2 >
542567
543568 { mathInfo ? (
544569 < div className = "space-y-4 animate-in fade-in duration-300" >
545- < div className = " text-xs text-slate-400 bg-slate-800 p-2 rounded border border-slate-700" >
570+ < div className = { ` text-xs p-2 rounded border ${ theme === 'dark' ? ' text-slate-400 bg-slate-800 border-slate-700' : 'text-slate-600 bg-slate-200 border-slate-300' } ` } >
546571 Analyzing: < span className = "text-amber-400 font-bold" > { mathInfo . filterName } </ span > at ({ hoveredPixel . x } , { hoveredPixel . y } )
547572 </ div >
548573
549574 < div className = "space-y-1" >
550575 { mathInfo . calculations . slice ( 0 , 9 ) . map ( ( calc , i ) => (
551576 < div key = { i } className = "flex items-center text-xs font-mono" >
552577 < span className = "text-slate-500 w-4" > ({ i } )</ span >
553- < span className = { `w-12 text-right ${ calc . isPadding ? 'text-slate-600 italic' : ' text-blue-400'} ` } >
578+ < span className = { `w-12 text-right ${ calc . isPadding ? 'text-slate-600 italic' : ( theme === 'dark' ? ' text-blue-400' : 'text-blue-700' ) } ` } >
554579 { calc . isPadding ? '0 (pad)' : calc . val . toFixed ( 2 ) }
555580 </ span >
556581 < span className = "px-2 text-slate-600" > ×</ span >
557- < span className = " w-8 text-right text-emerald-400" > { calc . weight } </ span >
582+ < span className = { ` w-8 text-right ${ theme === 'dark' ? ' text-emerald-400' : 'text-emerald-700' } ` } > { calc . weight } </ span >
558583 < span className = "px-2 text-slate-600" > =</ span >
559- < span className = " text-white" > { calc . product . toFixed ( 2 ) } </ span >
584+ < span className = { ` ${ theme === 'dark' ? ' text-white' : 'text-slate-900' } ` } > { calc . product . toFixed ( 2 ) } </ span >
560585 </ div >
561586 ) ) }
562587 { mathInfo . calculations . length > 9 && < div className = "text-xs text-slate-600 pl-4" > ...and { mathInfo . calculations . length - 9 } more</ div > }
563588 </ div >
564589
565- < div className = " border-t border-slate-700 pt-2 mt-2" >
590+ < div className = { ` border-t ${ theme === 'dark' ? ' border-slate-700' : 'border-slate-300' } pt-2 mt-2` } >
566591 < div className = "flex justify-between text-sm" >
567592 < span className = "text-slate-400" > Sum:</ span >
568- < span className = " font-mono text-white" > { mathInfo . total . toFixed ( 2 ) } </ span >
593+ < span className = { ` font-mono ${ theme === 'dark' ? ' text-white' : 'text-slate-800' } ` } > { mathInfo . total . toFixed ( 2 ) } </ span >
569594 </ div >
570595 < div className = "flex justify-between text-sm font-bold text-amber-400 mt-1" >
571596 < span > { activation . toUpperCase ( ) } (Sum):</ span >
@@ -574,7 +599,7 @@ export default function DeepLabCNN() {
574599 </ div >
575600 </ div >
576601 ) : (
577- < div className = " flex flex-col items-center justify-center h-32 text-slate-500 text- xs text-center border-2 border-dashed border-slate-800 rounded-xl" >
602+ < div className = { ` flex flex-col items-center justify-center h-32 text-xs text-center border-2 border-dashed rounded-xl ${ theme === 'dark' ? 'text-slate-500 border-slate-800' : 'text-slate-400 border-slate-400' } ` } >
578603 < MousePointer2 className = "w-6 h-6 mb-2 opacity-20" />
579604 Hover over a feature map pixel< br /> to see the math.
580605 </ div >
@@ -584,7 +609,7 @@ export default function DeepLabCNN() {
584609 </ div >
585610
586611 { /* RIGHT COLUMN: PIPELINE */ }
587- < div className = " flex-1 overflow-y-auto bg-slate-950 p-6" >
612+ < div className = { ` flex-1 overflow-y-auto ${ theme === 'dark' ? ' bg-slate-950' : 'bg-slate-200' } p-6` } >
588613
589614 { /* STEP 1: CONVOLUTION */ }
590615 < section className = "mb-10" >
@@ -593,7 +618,7 @@ export default function DeepLabCNN() {
593618 < Activity className = "w-5 h-5 text-emerald-500" />
594619 </ div >
595620 < div >
596- < h2 className = " text-lg font-medium text-slate-200" > Convolution Layer</ h2 >
621+ < h2 className = { ` text-lg font-medium ${ theme === 'dark' ? ' text-slate-200' : 'text-slate-800' } ` } > Convolution Layer</ h2 >
597622 < p className = "text-xs text-slate-500 font-mono" >
598623 Kernel: { kernelSize } x{ kernelSize } | Stride: { stride } | Pad: { padding }
599624 </ p >
@@ -607,15 +632,15 @@ export default function DeepLabCNN() {
607632 < div
608633 key = { idx }
609634 onMouseEnter = { ( ) => setSelectedFilterIdx ( idx ) }
610- className = { `bg-slate-900 border rounded-xl p-4 flex flex-col items-center transition-colors group cursor-crosshair ${ hoveredPixel ?. layer === 'conv' && hoveredPixel . filterIndex === idx ? 'border-blue-500 ring-1 ring-blue-500 bg-blue-900/10' : 'border-slate-800 hover:border-slate-600 ' } ` }
635+ className = { `border rounded-xl p-4 flex flex-col items-center transition-colors group cursor-crosshair ${ theme === 'dark' ? 'bg-slate-900 border-slate-800 hover:border-slate-600' : 'bg-white border-slate-200 hover:border-slate-400' } ${ hoveredPixel ?. layer === 'conv' && hoveredPixel . filterIndex === idx ? 'border-blue-500 ring-1 ring-blue-500 bg-blue-900/10' : '' } ` }
611636 >
612637 < div className = "flex justify-between items-center w-full mb-3" >
613638 < h3 className = "text-xs font-semibold uppercase tracking-wider text-slate-400" > { filter . name } </ h3 >
614639 { /* Kernel Preview Mini */ }
615- < div className = " bg-slate-800 border border -slate-700 p-1 rounded shadow-sm group-hover:border-slate-500 transition-colors" title = "Kernel Weights" >
616- < div className = { `grid gap-px bg-slate-600 border border-slate-600 ` } style = { { gridTemplateColumns : `repeat(${ filter . kernel . length } , 1fr)` } } >
640+ < div className = { `border p-1 rounded shadow-sm transition-colors ${ theme === 'dark' ? ' bg-slate-800 border-slate-700 group-hover:border-slate-500' : 'bg-slate-200 border-slate-300 group-hover:border-slate-500' } ` } title = "Kernel Weights" >
641+ < div className = { `grid gap-px ${ theme === 'dark' ? ' bg-slate-600 border-slate-600' : 'bg-slate-400 border-slate-400' } ` } style = { { gridTemplateColumns : `repeat(${ filter . kernel . length } , 1fr)` } } >
617642 { filter . kernel . flat ( ) . map ( ( k , i ) => (
618- < div key = { i } className = { `w-2 h-2 ${ k > 0 ? 'bg-white' : k < 0 ? 'bg-black' : ' bg-slate-400'} ` } />
643+ < div key = { i } className = { `w-2 h-2 ${ k > 0 ? 'bg-white' : k < 0 ? 'bg-black' : ( theme === 'dark' ? ' bg-slate-400' : 'bg-slate-600' ) } ` } />
619644 ) ) }
620645 </ div >
621646 </ div >
0 commit comments