diff --git a/benchmark.cjs b/benchmark.cjs new file mode 100644 index 0000000..0714c2b --- /dev/null +++ b/benchmark.cjs @@ -0,0 +1,25 @@ +const count = 10000; +const media = Array.from({ length: count }, (_, i) => ({ + id: `id-${i}`, + kind: 'image', + url: `url-${i}`, + fileName: `file-${i}`, + mimeType: 'image/png' +})); + +const searchId = `id-${count - 1}`; + +console.log(`Benchmarking with ${count} items...`); + +console.time('Array.find'); +for (let i = 0; i < 10000; i++) { + media.find(m => m.id === searchId); +} +console.timeEnd('Array.find'); + +const mediaMap = new Map(media.map(m => [m.id, m])); +console.time('Map.get'); +for (let i = 0; i < 10000; i++) { + mediaMap.get(searchId); +} +console.timeEnd('Map.get'); diff --git a/components/MediaPanel.tsx b/components/MediaPanel.tsx index b8afee1..27a6b8f 100644 --- a/components/MediaPanel.tsx +++ b/components/MediaPanel.tsx @@ -1,73 +1,74 @@ -import React, { useState } from 'react'; -import type { MediaItem } from '../types'; - -interface MediaPanelProps { - media: MediaItem[]; - activeMediaId?: string; - onSelect: (id?: string) => void; - onRemove: (id: string) => void; -} - -export const MediaPanel: React.FC = ({ media, activeMediaId, onSelect, onRemove }) => { - const [focusedId, setFocusedId] = useState(activeMediaId || null); - - const handleOpen = (id: string) => { - setFocusedId(id); - onSelect(id); - }; - - const handleClose = () => { - setFocusedId(null); - onSelect(undefined); - }; - - return ( -
-

Media

- {media.length === 0 ? ( -
No media added yet.
- ) : ( -
- {media.map(item => ( -
- {item.kind === 'video' ? ( -
- ))} -
- )} - - {focusedId && ( -
-
e.stopPropagation()}> -
- -
-
- {(() => { - const item = media.find(m => m.id === focusedId); - if (!item) return null; - if (item.kind === 'video') { - return ( -
-
-
- )} -
- ); -}; - +import React, { useState, useMemo } from 'react'; +import type { MediaItem } from '../types'; + +interface MediaPanelProps { + media: MediaItem[]; + activeMediaId?: string; + onSelect: (id?: string) => void; + onRemove: (id: string) => void; +} + +export const MediaPanel: React.FC = ({ media, activeMediaId, onSelect, onRemove }) => { + const [focusedId, setFocusedId] = useState(activeMediaId || null); + + const mediaMap = useMemo(() => new Map(media.map(item => [item.id, item])), [media]); + + const handleOpen = (id: string) => { + setFocusedId(id); + onSelect(id); + }; + + const handleClose = () => { + setFocusedId(null); + onSelect(undefined); + }; + + return ( +
+

Media

+ {media.length === 0 ? ( +
No media added yet.
+ ) : ( +
+ {media.map(item => ( +
+ {item.kind === 'video' ? ( +
+ ))} +
+ )} + + {focusedId && ( +
+
e.stopPropagation()}> +
+ +
+
+ {(() => { + const item = mediaMap.get(focusedId); + if (!item) return null; + if (item.kind === 'video') { + return ( +
+
+
+ )} +
+ ); +}; diff --git a/hooks/useWebGPURender.ts b/hooks/useWebGPURender.ts index f64cca3..e024669 100644 --- a/hooks/useWebGPURender.ts +++ b/hooks/useWebGPURender.ts @@ -370,16 +370,12 @@ export function useWebGPURender( useEffect(() => { const device = deviceRef.current; if (!device || !gpuReady) return; + const p = renderParamsRef.current; console.log(`[PatternDisplay] Updating cells buffer: matrix=${matrix ? 'yes' : 'null'}, rows=${matrix?.numRows}, channels=${matrix?.numChannels}`); if (cellsBufferRef.current) cellsBufferRef.current.destroy(); const isHighPrec = shaderFile.includes('v0.36') || shaderFile.includes('v0.37') || shaderFile.includes('v0.38') || shaderFile.includes('v0.39') || shaderFile.includes('v0.40') || shaderFile.includes('v0.42') || shaderFile.includes('v0.43') || shaderFile.includes('v0.44') || shaderFile.includes('v0.45') || shaderFile.includes('v0.46') || shaderFile.includes('v0.47') || shaderFile.includes('v0.48') || shaderFile.includes('v0.49') || shaderFile.includes('v0.50'); const packFunc = isHighPrec ? packPatternMatrixHighPrecision : packPatternMatrix; const { packedData, noteCount } = packFunc(p.matrix, p.padTopChannel); - let noteCount = 0; - for (let i = 0; i < packedData.length; i += 2) { - const note = ((packedData[i] ?? 0) >> 24) & 0xFF; - if (note > 0) noteCount++; - } console.log(`[PatternDisplay] Packed data contains ${noteCount} notes in ${packedData.length / 2} cells`); cellsBufferRef.current = createBufferWithData(device, packedData, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST); if (layoutTypeRef.current === 'extended') {