diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10f..c9e5b63e 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,3 +61,7 @@ ## 2026-07-13 - Array.from mapping optimization **Learning:** Using `Array.from({ length: N }).map(...)` creates an intermediate array of `undefined` values which requires memory allocation and garbage collection, adding O(N) unnecessary overhead in frequently re-rendered UI components. **Action:** Use `Array.from({ length: N }, (_, index) => ...)` to map elements directly during array creation, avoiding intermediate allocations. + +## 2026-07-14 - O(N) iteration with reduced function overhead for finding maximum values +**Learning:** Using `Array.prototype.reduce()` coupled with `Math.max()` to find the maximum value in a large array (like transcription notes) introduces significant function call overhead, allocating intermediate closures for each item. +**Action:** Prefer standard `for` loops with simple reassignment over `.reduce()` for finding extreme values in performance-critical paths, especially for arrays that can grow very large. diff --git a/apps/desktop/src/features/workspace/GrooveMap.tsx b/apps/desktop/src/features/workspace/GrooveMap.tsx index 2745d4d7..2defcdd0 100644 --- a/apps/desktop/src/features/workspace/GrooveMap.tsx +++ b/apps/desktop/src/features/workspace/GrooveMap.tsx @@ -17,7 +17,14 @@ function GrooveMapComponent({ notes, isLoading }: GrooveMapProps) { // Find max offset to determine timeline width const maxTime = useMemo(() => { - return renderedNotes.reduce((max, n) => Math.max(max, n.offset), 10); + // Performance: Avoid function call overhead of .reduce() and Math.max for large arrays + let max = 10; + for (let i = 0; i < renderedNotes.length; i++) { + if (renderedNotes[i].offset > max) { + max = renderedNotes[i].offset; + } + } + return max; }, [renderedNotes]); // Unique pitches to determine vertical lanes (avoiding 88-key piano roll)