Rahul-Samedavar's picture
added frontend drafts
b96b3a8
import React, { useEffect, useState } from 'react';
import PanelContainer from '../ui/PanelContainer';
import GlowingBox from '../ui/GlowingBox';
import FeatureMap from '../ui/FeatureMap';
import { ScanSearch, MoveRight } from 'lucide-react';
const ConvolutionPanel: React.FC = () => {
const [kernelPosition, setKernelPosition] = useState({ x: 0, y: 0 });
const [isAnimating, setIsAnimating] = useState(true);
// Simple edge detection kernel
const kernel = [
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]
];
// Animation for sliding kernel
useEffect(() => {
if (!isAnimating) return;
const maxPos = 5; // 8x8 input - 3x3 kernel + 1
const interval = setInterval(() => {
setKernelPosition(prev => {
const newX = prev.x + 1 > maxPos ? 0 : prev.x + 1;
const newY = newX === 0 ? (prev.y + 1 > maxPos ? 0 : prev.y + 1) : prev.y;
return { x: newX, y: newY };
});
}, 800);
return () => clearInterval(interval);
}, [isAnimating]);
return (
<PanelContainer
title="Convolution Operation"
description="The convolution operation slides a filter (kernel) across the input image to detect features like edges, textures, or patterns."
panelNumber={2}
>
<div className="flex flex-col lg:flex-row gap-8 items-center">
<div className="flex-1 flex flex-col items-center">
<h3 className="text-xl font-semibold text-gray-100 mb-4">Kernel Sliding</h3>
<div className="relative">
{/* Input image with overlay */}
<div className="grid grid-cols-8 grid-rows-8 w-full max-w-[280px] gap-[1px]">
{Array(64).fill(0).map((_, index) => {
const x = index % 8;
const y = Math.floor(index / 8);
// Determine if cell is within the current kernel position
const isInKernel = x >= kernelPosition.x && x < kernelPosition.x + 3 &&
y >= kernelPosition.y && y < kernelPosition.y + 3;
return (
<div
key={index}
className={`
aspect-square flex items-center justify-center
${isInKernel
? 'bg-purple-600/30 border border-purple-400'
: 'bg-gray-800 border border-gray-700'}
`}
></div>
);
})}
</div>
{/* Animated kernel */}
<div
className="absolute w-[calc(37.5%)] h-[calc(37.5%)] border-2 border-cyan-400 rounded-md shadow-lg shadow-cyan-500/50 transition-all duration-300 pointer-events-none"
style={{
top: `${kernelPosition.y * 12.5}%`,
left: `${kernelPosition.x * 12.5}%`
}}
>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-cyan-400">
<ScanSearch size={24} />
</div>
</div>
</div>
<button
className="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md text-sm"
onClick={() => setIsAnimating(!isAnimating)}
>
{isAnimating ? 'Pause Animation' : 'Resume Animation'}
</button>
</div>
<div className="hidden lg:flex items-center justify-center">
<MoveRight size={40} className="text-gray-500" />
</div>
<div className="flex-1 flex flex-col items-center">
<div className="flex gap-8 items-start">
<div>
<h3 className="text-xl font-semibold text-gray-100 mb-4">Kernel/Filter</h3>
<GlowingBox color="from-purple-500 to-blue-500" className="max-w-[150px]">
<div className="grid grid-cols-3 gap-1">
{kernel.flat().map((value, i) => (
<div
key={i}
className="aspect-square flex items-center justify-center bg-gray-900 text-sm font-mono"
>
{value}
</div>
))}
</div>
</GlowingBox>
<p className="mt-2 text-sm text-gray-400 max-w-[150px]">Edge detection filter</p>
</div>
<div>
<h3 className="text-xl font-semibold text-gray-100 mb-4">Feature Map</h3>
<GlowingBox color="from-blue-500 to-teal-500" className="max-w-[200px]">
<FeatureMap
size={6}
highlightPosition={kernelPosition.x < 6 && kernelPosition.y < 6 ?
{ x: kernelPosition.x, y: kernelPosition.y } : null}
/>
</GlowingBox>
<p className="mt-2 text-sm text-gray-400 max-w-[200px]">
Resulting feature map from convolution operation
</p>
</div>
</div>
</div>
</div>
</PanelContainer>
);
};
export default ConvolutionPanel;