Skip to content

Refactor monitor#171

Merged
streamer45 merged 14 commits intomainfrom
refactor-monitor
Mar 17, 2026
Merged

Refactor monitor#171
streamer45 merged 14 commits intomainfrom
refactor-monitor

Conversation

@streamer45
Copy link
Owner

@streamer45 streamer45 commented Mar 16, 2026

Summary

Trying to improve perf of the compositor UI which is pretty terrible atm.


Staging: Open in Devin

@streamer45 streamer45 self-assigned this Mar 16, 2026
Copy link
Contributor

@staging-devin-ai-integration staging-devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 potential issues.

View 4 additional findings in Devin Review.

Staging: Open in Devin
Debug

Playground

Comment on lines +19 to +20
*/
export const PARAM_THROTTLE_MS = 33;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 PARAM_THROTTLE_MS changed from 100ms to 33ms affects all slider controls

The default throttle for parameter updates was changed from 100ms to 33ms (~30 updates/sec) via the new PARAM_THROTTLE_MS constant. This affects both the compositor layer updates (useCompositorLayers.ts:125) and all generic numeric sliders (useNumericSlider.ts:77). While the constant is well-documented as balancing responsiveness vs network load, the 3x increase in update frequency could increase WebSocket traffic and server load, especially with multiple concurrent slider interactions. The perf-baselines.json shows dramatically improved render counts (22→2), suggesting the zero-render optimization compensates for the higher frequency on the client side. However, the server-side impact should be validated under load.

Staging: Open in Devin

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

staging-devin-ai-integration[bot]

This comment was marked as resolved.

staging-devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Contributor

@staging-devin-ai-integration staging-devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 new potential issues.

View 8 additional findings in Devin Review.

Staging: Open in Devin
Debug

Playground

Copy link
Contributor

@staging-devin-ai-integration staging-devin-ai-integration bot Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 commitLayerAppearance overwrites concurrent React state changes made during slider drag

When sliderActiveRef is true during a zero-render opacity/rotation drag, the layersRef sync from React state is skipped (useCompositorLayers.ts:168). If any concurrent operation calls setLayers() during this window — such as arrow-key nudges (compositorKeyboard.ts:108-111), visibility toggles (compositorOverlays.ts:204), mirror toggles (compositorOverlays.ts:245), or reorder (compositorOverlays.ts:499) — those changes update React state but not layersRef. When the slider is released, commitLayerAppearance() calls setLayers([...layersRef.current]) with a direct value (not a functional updater), overwriting the concurrent changes.

Reproduction steps
  1. Select a compositor layer (wrapper gets keyboard focus)
  2. Start dragging the opacity slider (sliderActiveRef = true)
  3. While holding the mouse on the slider, press an arrow key to nudge
  4. The nudge calls setLayers(prev => ...), updating React state
  5. But layersRef is NOT synced (guarded by sliderActiveRef)
  6. Release the slider → commitLayerAppearance sets layers from stale layersRef
  7. The arrow-key position change is lost
Staging: Open in Devin

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

"opacity-slider-20-ticks": {
"name": "opacity-slider-20-ticks",
"meanRenderCount": 22,
"meanRenderCount": 2,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Perf baselines show dramatic render count reduction (22→2) — verify test correctness

The perf-baselines.json changes show meanRenderCount dropping from 22 to 2 for opacity, rotation, and mixed slider tests. This 11x improvement is consistent with the zero-render optimization (skipping setLayers during drags means the measured component doesn't re-render). However, a count of 2 for 20 slider ticks means the component renders only on initial mount + final commit, not during the drag at all. If the perf test's measureRenders is counting the component under test (not the slider), this validates that the memoization barriers are working. Worth confirming the test still exercises the same code path and that the dramatic improvement isn't from accidentally skipping the interaction.

Staging: Open in Devin

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

Copy link
Contributor

@staging-devin-ai-integration staging-devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

View 8 additional findings in Devin Review.

Staging: Open in Devin
Debug

Playground

Comment on lines +107 to +127
function layerArrayGeometryEqual(a: readonly LayerState[], b: readonly LayerState[]): boolean {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
const la = a[i];
const lb = b[i];
if (
la.id !== lb.id ||
la.x !== lb.x ||
la.y !== lb.y ||
la.width !== lb.width ||
la.height !== lb.height ||
la.zIndex !== lb.zIndex ||
la.visible !== lb.visible ||
la.mirrorHorizontal !== lb.mirrorHorizontal ||
la.mirrorVertical !== lb.mirrorVertical
) {
return false;
}
}
return true;
}
Copy link
Contributor

@staging-devin-ai-integration staging-devin-ai-integration bot Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 areCanvasPropsEqual intentionally skips opacity/rotation but this affects server-pushed updates too

The custom memo comparator areCanvasPropsEqual (CompositorCanvas.tsx:72-100) and layerArrayGeometryEqual (CompositorCanvas.tsx:107-127) intentionally skip opacity and rotationDegrees for video layers to avoid re-renders during slider drags. This is correct for the local slider path (DOM is already updated directly). However, it also prevents re-rendering when the server pushes opacity/rotation changes via mapServerLayers in compositorServerSync.ts:33-73. If the server independently modifies these values (e.g., a multi-client scenario or server-side automation), the canvas would display stale opacity/rotation until the next geometry change triggers a re-render. In the typical single-client case, echo-backs carry the same values the client sent, so this is unlikely to be visible. Worth considering whether a rare server-push edge case justifies adding these fields back to the comparator.

Staging: Open in Devin

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

staging-devin-ai-integration[bot]

This comment was marked as resolved.

staging-devin-ai-integration[bot]

This comment was marked as resolved.

staging-devin-ai-integration[bot]

This comment was marked as resolved.

staging-devin-ai-integration[bot]

This comment was marked as resolved.

@streamer45 streamer45 merged commit 3a98c2d into main Mar 17, 2026
15 checks passed
@streamer45 streamer45 deleted the refactor-monitor branch March 17, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant