Download src/store/index.ts from TechAvenger/kernel-convolution-visualizer: direct link, hf CLI and curl.
- Browser
- Download file 14.4 kB
-
https://huggingface.co/spaces/TechAvenger/kernel-convolution-visualizer/resolve/main/src/store/index.ts
- Command line
-
hf download hf://spaces/TechAvenger/kernel-convolution-visualizer/src/store/index.ts
-
curl -L -o index.ts https://huggingface.co/spaces/TechAvenger/kernel-convolution-visualizer/resolve/main/src/store/index.ts
14.4 kB
| import { create } from 'zustand' | |
| import { subscribeWithSelector } from 'zustand/middleware' | |
| import { useShallow } from 'zustand/react/shallow' | |
| import type { | |
| Kernel, | |
| ConvolutionState, | |
| AppSettings, | |
| ComparisonState, | |
| KernelComparisonResult, | |
| PaddingMode, | |
| } from '@/types' | |
| type ConvolutionStoreState = ConvolutionState & { | |
| startConvolution: () => void | |
| pauseConvolution: () => void | |
| resumeConvolution: () => void | |
| stopConvolution: () => void | |
| updateConvolutionStep: (step: ConvolutionState['currentStep']) => void | |
| updateConvolutionProgress: (progress: number, processedPixels: number, elapsedTime: number) => void | |
| completeConvolution: (outputImageData: ImageData) => void | |
| setConvolutionError: (error: string) => void | |
| resetConvolution: () => void | |
| } | |
| type SettingsStoreState = AppSettings & { | |
| setAnimationSpeed: (speed: number) => void | |
| toggleOverlay: (key: keyof AppSettings['showOverlay']) => void | |
| setPadding: (padding: PaddingMode) => void | |
| setZoomLevel: (zoom: number) => void | |
| setPanOffset: (offset: { x: number; y: number }) => void | |
| setComparisonMode: (mode: AppSettings['comparisonMode']) => void | |
| setStepMode: (enabled: boolean) => void | |
| } | |
| type KernelStoreState = { | |
| selectedKernel: Kernel | null | |
| customKernelMatrix: number[][] | |
| customKernelSize: number | |
| customKernelNormalize: boolean | |
| setSelectedKernel: (kernel: Kernel | null) => void | |
| setCustomKernel: (matrix: number[][], size: number, normalize: boolean) => void | |
| updateCustomKernelCell: (row: number, col: number, value: number) => void | |
| setCustomKernelSize: (size: number) => void | |
| setCustomKernelNormalize: (normalize: boolean) => void | |
| } | |
| type ImageStoreState = { | |
| originalImage: HTMLImageElement | null | |
| originalImageData: ImageData | null | |
| processedImageData: ImageData | null | |
| setOriginalImage: (image: HTMLImageElement, imageData: ImageData) => void | |
| } | |
| type ComparisonStoreState = ComparisonState & { | |
| setComparisonViewMode: (mode: ComparisonState['mode']) => void | |
| setSplitPosition: (position: number) => void | |
| toggleSynchronizedZoom: () => void | |
| toggleSynchronizedPan: () => void | |
| addComparisonResult: (result: KernelComparisonResult) => void | |
| clearComparisonResults: () => void | |
| setActiveComparisonTab: (kernelId: string) => void | |
| } | |
| type UIStoreState = { | |
| isLoading: boolean | |
| error: string | null | |
| showHelp: boolean | |
| showSettings: boolean | |
| setLoading: (loading: boolean) => void | |
| setError: (error: string | null) => void | |
| toggleHelp: () => void | |
| toggleSettings: () => void | |
| } | |
| interface AppStore { | |
| // Image state | |
| originalImage: HTMLImageElement | null | |
| originalImageData: ImageData | null | |
| processedImageData: ImageData | null | |
| // Kernel state | |
| selectedKernel: Kernel | null | |
| customKernelMatrix: number[][] | |
| customKernelSize: number | |
| customKernelNormalize: boolean | |
| // Convolution state | |
| convolution: ConvolutionState | |
| // Settings | |
| settings: AppSettings | |
| // Comparison | |
| comparison: ComparisonState | |
| comparisonResults: KernelComparisonResult[] | |
| // UI state | |
| isLoading: boolean | |
| error: string | null | |
| showHelp: boolean | |
| showSettings: boolean | |
| // Actions | |
| setOriginalImage: (image: HTMLImageElement, imageData: ImageData) => void | |
| setSelectedKernel: (kernel: Kernel | null) => void | |
| setCustomKernel: (matrix: number[][], size: number, normalize: boolean) => void | |
| updateCustomKernelCell: (row: number, col: number, value: number) => void | |
| setCustomKernelSize: (size: number) => void | |
| setCustomKernelNormalize: (normalize: boolean) => void | |
| // Convolution actions | |
| startConvolution: () => void | |
| pauseConvolution: () => void | |
| resumeConvolution: () => void | |
| stopConvolution: () => void | |
| updateConvolutionStep: (step: ConvolutionState['currentStep']) => void | |
| updateConvolutionProgress: (progress: number, processedPixels: number, elapsedTime: number) => void | |
| completeConvolution: (outputImageData: ImageData) => void | |
| setConvolutionError: (error: string) => void | |
| resetConvolution: () => void | |
| // Settings actions | |
| updateSettings: (settings: Partial<AppSettings>) => void | |
| setAnimationSpeed: (speed: number) => void | |
| toggleOverlay: (key: keyof AppSettings['showOverlay']) => void | |
| setPadding: (padding: PaddingMode) => void | |
| setZoomLevel: (zoomLevel: number) => void | |
| setPanOffset: (panOffset: { x: number; y: number }) => void | |
| setComparisonMode: (comparisonMode: AppSettings['comparisonMode']) => void | |
| setStepMode: (stepMode: boolean) => void | |
| // Comparison actions | |
| setComparisonViewMode: (mode: ComparisonState['mode']) => void | |
| setSplitPosition: (splitPosition: number) => void | |
| toggleSynchronizedZoom: () => void | |
| toggleSynchronizedPan: () => void | |
| addComparisonResult: (result: KernelComparisonResult) => void | |
| clearComparisonResults: () => void | |
| setActiveComparisonTab: (activeTab: string) => void | |
| // UI actions | |
| setLoading: (isLoading: boolean) => void | |
| setError: (error: string | null) => void | |
| toggleHelp: () => void | |
| toggleSettings: () => void | |
| } | |
| const defaultSettings: AppSettings = { | |
| animationSpeed: 1, | |
| showOverlay: { | |
| kernelBoundary: true, | |
| pixelValues: true, | |
| multiplications: true, | |
| summation: true, | |
| }, | |
| padding: 'zero', | |
| zoomLevel: 1, | |
| panOffset: { x: 0, y: 0 }, | |
| comparisonMode: 'split', | |
| stepMode: false, | |
| } | |
| const defaultConvolutionState: ConvolutionState = { | |
| status: 'idle', | |
| currentStep: null, | |
| progress: 0, | |
| startTime: 0, | |
| elapsedTime: 0, | |
| processedPixels: 0, | |
| totalPixels: 0, | |
| outputImageData: null, | |
| error: null, | |
| } | |
| const defaultComparisonState: ComparisonState = { | |
| mode: 'split', | |
| splitPosition: 0.5, | |
| synchronizedZoom: true, | |
| synchronizedPan: true, | |
| activeTab: '', | |
| } | |
| export const useAppStore = create<AppStore>()( | |
| subscribeWithSelector((set) => ({ | |
| originalImage: null, | |
| originalImageData: null, | |
| processedImageData: null, | |
| selectedKernel: null, | |
| customKernelMatrix: Array(3) | |
| .fill(0) | |
| .map(() => Array(3).fill(0)), | |
| customKernelSize: 3, | |
| customKernelNormalize: true, | |
| convolution: defaultConvolutionState, | |
| settings: defaultSettings, | |
| comparison: defaultComparisonState, | |
| comparisonResults: [], | |
| isLoading: false, | |
| error: null, | |
| showHelp: false, | |
| showSettings: false, | |
| setOriginalImage: (image, imageData) => | |
| set({ originalImage: image, originalImageData: imageData, processedImageData: null }), | |
| setSelectedKernel: (kernel) => set({ selectedKernel: kernel }), | |
| setCustomKernel: (matrix, size, normalize) => | |
| set({ customKernelMatrix: matrix, customKernelSize: size, customKernelNormalize: normalize }), | |
| updateCustomKernelCell: (row, col, value) => | |
| set((state) => { | |
| const newMatrix = state.customKernelMatrix.map((r, i) => | |
| i === row ? r.map((v, j) => (j === col ? value : v)) : r | |
| ) | |
| return { customKernelMatrix: newMatrix } | |
| }), | |
| setCustomKernelSize: (size) => | |
| set((state) => { | |
| const newMatrix = Array(size) | |
| .fill(0) | |
| .map(() => Array(size).fill(0)) | |
| return { customKernelSize: size, customKernelMatrix: newMatrix } | |
| }), | |
| setCustomKernelNormalize: (normalize) => set({ customKernelNormalize: normalize }), | |
| startConvolution: () => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'running', | |
| startTime: Date.now(), | |
| progress: 0, | |
| processedPixels: 0, | |
| error: null, | |
| }, | |
| })), | |
| pauseConvolution: () => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'paused', | |
| elapsedTime: Date.now() - state.convolution.startTime, | |
| }, | |
| })), | |
| resumeConvolution: () => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'running', | |
| }, | |
| })), | |
| stopConvolution: () => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'idle', | |
| currentStep: null, | |
| progress: 0, | |
| }, | |
| })), | |
| updateConvolutionStep: (step) => | |
| set((state) => { | |
| const newState = { | |
| convolution: { | |
| ...state.convolution, | |
| currentStep: step, | |
| }, | |
| } | |
| // If this step has a partial output image, update the processed image data | |
| if (step && step.isPartialOutput && step.partialOutputImageData) { | |
| return { | |
| ...newState, | |
| processedImageData: step.partialOutputImageData, | |
| } | |
| } | |
| return newState | |
| }), | |
| updateConvolutionProgress: (progress, processedPixels, elapsedTime) => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| progress, | |
| processedPixels, | |
| elapsedTime, | |
| }, | |
| })), | |
| completeConvolution: (outputImageData) => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'completed', | |
| progress: 1, | |
| outputImageData, | |
| elapsedTime: Date.now() - state.convolution.startTime, | |
| }, | |
| processedImageData: outputImageData, | |
| })), | |
| setConvolutionError: (error) => | |
| set((state) => ({ | |
| convolution: { | |
| ...state.convolution, | |
| status: 'error', | |
| error, | |
| }, | |
| })), | |
| resetConvolution: () => | |
| set({ | |
| convolution: defaultConvolutionState, | |
| processedImageData: null, | |
| }), | |
| updateSettings: (newSettings) => | |
| set((state) => ({ | |
| settings: { ...state.settings, ...newSettings }, | |
| })), | |
| setAnimationSpeed: (speed) => | |
| set((state) => ({ | |
| settings: { ...state.settings, animationSpeed: speed }, | |
| })), | |
| toggleOverlay: (key) => | |
| set((state) => ({ | |
| settings: { | |
| ...state.settings, | |
| showOverlay: { ...state.settings.showOverlay, [key]: !state.settings.showOverlay[key] }, | |
| }, | |
| })), | |
| setPadding: (padding) => | |
| set((state) => ({ | |
| settings: { ...state.settings, padding }, | |
| })), | |
| setZoomLevel: (zoomLevel) => | |
| set((state) => ({ | |
| settings: { ...state.settings, zoomLevel }, | |
| })), | |
| setPanOffset: (panOffset) => | |
| set((state) => ({ | |
| settings: { ...state.settings, panOffset }, | |
| })), | |
| setComparisonMode: (comparisonMode) => | |
| set((state) => ({ | |
| settings: { ...state.settings, comparisonMode }, | |
| })), | |
| setStepMode: (stepMode) => | |
| set((state) => ({ | |
| settings: { ...state.settings, stepMode }, | |
| })), | |
| // Comparison actions | |
| setComparisonViewMode: (mode: ComparisonState['mode']) => | |
| set((state) => ({ | |
| comparison: { ...state.comparison, mode }, | |
| })), | |
| setSplitPosition: (splitPosition: number) => | |
| set((state) => ({ | |
| comparison: { ...state.comparison, splitPosition }, | |
| })), | |
| toggleSynchronizedZoom: () => | |
| set((state) => ({ | |
| comparison: { ...state.comparison, synchronizedZoom: !state.comparison.synchronizedZoom }, | |
| })), | |
| toggleSynchronizedPan: () => | |
| set((state) => ({ | |
| comparison: { ...state.comparison, synchronizedPan: !state.comparison.synchronizedPan }, | |
| })), | |
| addComparisonResult: (result) => | |
| set((state) => ({ | |
| comparisonResults: [...state.comparisonResults, result], | |
| })), | |
| clearComparisonResults: () => set({ comparisonResults: [] }), | |
| setActiveComparisonTab: (activeTab: string) => | |
| set((state) => ({ | |
| comparison: { ...state.comparison, activeTab }, | |
| })), | |
| setLoading: (isLoading) => set({ isLoading }), | |
| setError: (error) => set({ error }), | |
| toggleHelp: () => set((state) => ({ showHelp: !state.showHelp })), | |
| toggleSettings: () => set((state) => ({ showSettings: !state.showSettings })), | |
| })) | |
| ) | |
| // Selector hooks that include both state and actions | |
| export const useConvolutionStore = () => useAppStore(useShallow((state): ConvolutionStoreState => ({ | |
| ...state.convolution, | |
| startConvolution: state.startConvolution, | |
| pauseConvolution: state.pauseConvolution, | |
| resumeConvolution: state.resumeConvolution, | |
| stopConvolution: state.stopConvolution, | |
| updateConvolutionStep: state.updateConvolutionStep, | |
| updateConvolutionProgress: state.updateConvolutionProgress, | |
| completeConvolution: state.completeConvolution, | |
| setConvolutionError: state.setConvolutionError, | |
| resetConvolution: state.resetConvolution, | |
| }))) | |
| export const useSettingsStore = () => useAppStore(useShallow((state): SettingsStoreState => ({ | |
| ...state.settings, | |
| setAnimationSpeed: state.setAnimationSpeed, | |
| toggleOverlay: state.toggleOverlay, | |
| setPadding: state.setPadding, | |
| setZoomLevel: state.setZoomLevel, | |
| setPanOffset: state.setPanOffset, | |
| setComparisonMode: state.setComparisonMode, | |
| setStepMode: state.setStepMode, | |
| }))) | |
| export const useKernelStore = () => useAppStore(useShallow((state): KernelStoreState => ({ | |
| selectedKernel: state.selectedKernel, | |
| customKernelMatrix: state.customKernelMatrix, | |
| customKernelSize: state.customKernelSize, | |
| customKernelNormalize: state.customKernelNormalize, | |
| setSelectedKernel: state.setSelectedKernel, | |
| setCustomKernel: state.setCustomKernel, | |
| updateCustomKernelCell: state.updateCustomKernelCell, | |
| setCustomKernelSize: state.setCustomKernelSize, | |
| setCustomKernelNormalize: state.setCustomKernelNormalize, | |
| }))) | |
| export const useImageStore = () => useAppStore(useShallow((state): ImageStoreState => ({ | |
| originalImage: state.originalImage, | |
| originalImageData: state.originalImageData, | |
| processedImageData: state.processedImageData, | |
| setOriginalImage: state.setOriginalImage, | |
| }))) | |
| export const useComparisonStore = () => useAppStore(useShallow((state): ComparisonStoreState => ({ | |
| ...state.comparison, | |
| setComparisonViewMode: state.setComparisonViewMode, | |
| setSplitPosition: state.setSplitPosition, | |
| toggleSynchronizedZoom: state.toggleSynchronizedZoom, | |
| toggleSynchronizedPan: state.toggleSynchronizedPan, | |
| addComparisonResult: state.addComparisonResult, | |
| clearComparisonResults: state.clearComparisonResults, | |
| setActiveComparisonTab: state.setActiveComparisonTab, | |
| }))) | |
| export const useUIStore = () => useAppStore(useShallow((state): UIStoreState => ({ | |
| isLoading: state.isLoading, | |
| error: state.error, | |
| showHelp: state.showHelp, | |
| showSettings: state.showSettings, | |
| setLoading: state.setLoading, | |
| setError: state.setError, | |
| toggleHelp: state.toggleHelp, | |
| toggleSettings: state.toggleSettings, | |
| }))) |