Skip to content

feat(architecture): refine motion systems#253

Open
Aditya948351 wants to merge 4 commits into
SamXop123:mainfrom
Aditya948351:refinemotion
Open

feat(architecture): refine motion systems#253
Aditya948351 wants to merge 4 commits into
SamXop123:mainfrom
Aditya948351:refinemotion

Conversation

@Aditya948351

@Aditya948351 Aditya948351 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Resolves #238

Summary by CodeRabbit

Release Notes

  • New Features

    • Multi-display visualizer overlay support
    • Per-display enable/disable controls in the tray menu
  • Improvements

    • Enhanced audio level smoothing responsiveness
    • Better handling of display configuration changes and device additions/removals

Copilot AI review requested due to automatic review settings June 18, 2026 10:28
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

@Aditya948351 is attempting to deploy a commit to the Dot_NotSam's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 384b434b-5239-4c66-abfd-702e147ac5c3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR replaces the single overlayWindow variable with an overlayWindows Map keyed by display ID, adds createOverlayForDisplay and syncOverlayWindows functions, broadcasts audio IPC to all active overlay windows, extends the tray menu with a per-display Displays submenu, and updates all screen/lifecycle event handlers to the multi-display model. In renderer.js, audio level smoothing is made frame-rate independent via delta-time scaling.

Changes

Multi-display overlay architecture and delta-time audio smoothing

Layer / File(s) Summary
overlayWindows Map and per-display creation
main.js
Replaces the single overlayWindow variable with an overlayWindows Map and introduces createOverlayForDisplay, which guards against duplicates and checks visualizerSettings.monitors[display.id].enabled before creating a window.
syncOverlayWindows, audio broadcast, and visualizer reload
main.js
Adds syncOverlayWindows to reconcile the Map against currently connected displays and enabled settings. Updates sendAudioLevel to iterate all non-destroyed overlay windows for IPC broadcast, and updates reloadVisualizer to call reloadIgnoringCache on every window in the Map.
Tray Displays submenu and lifecycle event wiring
main.js
Adds a "Displays" submenu to the tray context menu with per-display checkbox items that toggle monitors[display.id].enabled. Replaces single-overlay screen event handlers with calls to syncOverlayWindows and resizeAllOverlays, and updates activate/second-instance logic to check overlayWindows.size.
Delta-time audio smoothing
renderer.js
Computes deltaTime from lastFrameAt and a timeScale relative to a 16.6ms baseline; multiplies the smoothing increment by timeScale in updateAudioLevel so convergence speed is consistent across frame rates.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #199 — The changes directly implement the multi-monitor overlay manager architecture described in that issue: overlayWindows Map keyed by display ID, per-display overlay creation/synchronization, audio level broadcast to all overlay windows, and per-display enable/disable controls in the tray menu.
  • #238 — The delta-time-based smoothing added in renderer.js addresses the task of implementing delta-time-based smoothing for animations where it was missing, as listed in that issue's objectives.

Poem

🐇 Hoppity hop, one screen's not enough,
Each monitor now gets its own overlay fluff!
The Map holds them all, keyed snug by their id,
And smoothing scales time so no frame goes astray.
From tray menu checkboxes to sync on each event,
Multi-display magic is what this PR meant! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The multi-display overlay architecture changes in main.js extend beyond the motion systems refinement scope defined in issue #238, introducing new display management functionality. Review whether multi-display overlay refactoring belongs in this PR or should be deferred to a separate architectural change request aligned with issue #238 scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(architecture): refine motion systems' is directly related to the main change—transitioning to a multi-display overlay architecture and implementing delta-time based smoothing for animations.
Linked Issues check ✅ Passed The PR addresses issue #238 by implementing delta-time based smoothing in renderer.js and refactoring overlay architecture to improve frame pacing and animation consistency.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SamXop123 SamXop123 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This PR is unsafe to merge and will crash the application on startup, disable visualizer responses, and break settings persistence. Please address the following issues:

  1. ReferenceError in main.js: In createOverlayForDisplay(display), you updated the initialization to const win = new BrowserWindow({...}) but did not change the subsequent references (e.g. overlayWindow.setAlwaysOnTop, overlayWindow.loadFile, etc.) which still use the removed global overlayWindow variable.
  2. Missing resizeAllOverlays function: You call resizeAllOverlays() on display-metrics-changed and second-instance events, but the function is not defined anywhere in the codebase.
  3. Broken Settings / IPC Control:
    • sendVisualizerSettings() and sendFocusModeOpacity() still check and use the global overlayWindow, meaning settings and opacity changes will not be broadcast to the new overlayWindows Map.
    • showCustomContextMenu and the set-ignore-mouse-events IPC handler still check overlayWindow.
  4. Settings Sanitization in settingsStore.js: The new monitors settings configuration is missing from sanitizeSettings and DEFAULT_SETTINGS, meaning any changes saved via updateSettings are immediately stripped and discarded.
  5. Frozen Renderer Physics: In renderer.js (renderFrame), lastFrameAt = now; is executed before updateAudioLevel(now). Inside updateAudioLevel, now - lastFrameAt evaluates to 0, making timeScale = 0. As a result, the audio reactivity is frozen and won't respond to incoming levels.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
main.js (4)

399-408: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove stale reference to overlayWindow.

Line 407 references the old single-window variable after the loop already reloads all windows in overlayWindows. This line is both redundant and will cause a runtime error since overlayWindow no longer exists.

🐛 Proposed fix
 function reloadVisualizer() {
   for (const win of overlayWindows.values()) {
     if (!win.isDestroyed()) {
       win.webContents.reloadIgnoringCache();
     }
   }

   stopSimulatedAudioFallback();
-  overlayWindow.webContents.reloadIgnoringCache();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.js` around lines 399 - 408, In the reloadVisualizer function, remove the
stale reference to the overlayWindow variable on the last line that calls
win.webContents.reloadIgnoringCache(). This line is redundant because all
windows are already being reloaded in the for loop that iterates through
overlayWindows.values(), and overlayWindow no longer exists in the codebase,
which will cause a runtime error. Simply delete this line to resolve the issue.

1622-1643: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Update showCustomContextMenu to multi-display model.

This function still references overlayWindow in multiple places. For multi-display support, it should determine which overlay window contains the cursor and send the context menu command to that window.

🔧 Proposed fix
 function showCustomContextMenu() {
-  if (!overlayWindow || overlayWindow.isDestroyed()) {
+  if (overlayWindows.size === 0) {
     return;
   }
   const cursorPoint = screen.getCursorScreenPoint();
+  const targetDisplay = screen.getDisplayNearestPoint(cursorPoint);
+  const win = overlayWindows.get(targetDisplay.id);
+  
+  if (!win || win.isDestroyed()) {
+    return;
+  }

   // Force Windows to refresh the window's z-order relative to other topmost windows
   // (like the tray overflow panel) by toggling setAlwaysOnTop and calling moveTop()
-  overlayWindow.setAlwaysOnTop(false);
-  overlayWindow.setAlwaysOnTop(true, "screen-saver");
-  overlayWindow.moveTop();
+  win.setAlwaysOnTop(false);
+  win.setAlwaysOnTop(true, "screen-saver");
+  win.moveTop();

-  const primaryDisplay = screen.getPrimaryDisplay();
-  const localX = cursorPoint.x - primaryDisplay.bounds.x;
-  const localY = cursorPoint.y - primaryDisplay.bounds.y;
+  const localX = cursorPoint.x - targetDisplay.bounds.x;
+  const localY = cursorPoint.y - targetDisplay.bounds.y;

-  overlayWindow.webContents.send("show-context-menu", {
+  win.webContents.send("show-context-menu", {
     x: localX,
     y: localY
   });
-  overlayWindow.setIgnoreMouseEvents(false);
+  win.setIgnoreMouseEvents(false);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.js` around lines 1622 - 1643, The showCustomContextMenu function
currently assumes a single overlayWindow and sends the context menu to it
regardless of which display the cursor is on. To support multi-display, refactor
this function to determine which display contains the cursor using the
cursorPoint coordinates and screen.getAllDisplays(), then identify the
corresponding overlay window for that display. Instead of using the global
overlayWindow reference, find and use the correct overlay window for the display
containing the cursor before sending the show-context-menu message to
overlayWindow.webContents.send().

475-480: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Update sendFocusModeOpacity to multi-display model.

This function still references the old overlayWindow variable. It should iterate over overlayWindows like sendAudioLevel does.

🐛 Proposed fix
 function sendFocusModeOpacity(opacity) {
-  if (!overlayWindow || overlayWindow.isDestroyed()) {
-    return;
-  }
-  overlayWindow.webContents.send("focus-mode-opacity", { opacity });
+  for (const win of overlayWindows.values()) {
+    if (!win.isDestroyed()) {
+      win.webContents.send("focus-mode-opacity", { opacity });
+    }
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.js` around lines 475 - 480, The sendFocusModeOpacity function currently
operates on a single overlayWindow variable but needs to be updated to support
multiple displays. Refactor this function to iterate over the overlayWindows
collection (similar to how sendAudioLevel handles multiple windows) and send the
focus-mode-opacity message to each non-destroyed window in the collection,
removing the single overlayWindow check and replacing it with a loop that
validates each window before sending.

265-286: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: References to undefined overlayWindow instead of win.

The window is created as win on line 241, but lines 265-286 operate on overlayWindow which is the old single-window variable that no longer exists in this multi-display architecture. This will cause runtime errors—the new window is never configured, shown, or loaded.

Additionally, line 285 sets overlayWindow = null in the closed handler, which is incorrect for multi-display—the window should be removed from the Map instead.

🐛 Proposed fix
-  overlayWindow.setAlwaysOnTop(true, "screen-saver");
-  overlayWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
-  overlayWindow.setIgnoreMouseEvents(true, { forward: true });
-  overlayWindow.setBounds(bounds);
-  overlayWindow.showInactive();
-  overlayWindow.moveTop();
-  overlayWindow.loadFile("index.html");
+  win.setAlwaysOnTop(true, "screen-saver");
+  win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
+  win.setIgnoreMouseEvents(true, { forward: true });
+  win.setBounds(bounds);
+  win.showInactive();
+  win.moveTop();
+  win.loadFile("index.html");

-  overlayWindow.webContents.on("did-finish-load", () => {
+  win.webContents.on("did-finish-load", () => {
     setTimeout(() => {
       sendVisualizerSettings();
     }, 100);
   });

-  overlayWindow.on("close", () => {
+  win.on("close", () => {
     stopSimulatedAudioFallback();
   });

-  overlayWindow.on("closed", () => {
+  win.on("closed", () => {
     stopSimulatedAudioFallback();
-    overlayWindow = null;
+    overlayWindows.delete(id);
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.js` around lines 265 - 286, Replace all references to `overlayWindow`
with `win` throughout this code block since the window is created as `win` on
line 241. Additionally, in the `closed` event handler where the code currently
sets `overlayWindow = null`, this should instead remove the window from the Map
data structure that stores windows for the multi-display architecture (likely
using a key identifier like the display ID or window ID to locate and delete the
entry from the Map).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@renderer.js`:
- Around line 596-598: The smoothing factor calculation in the smoothedLevel
update line can exceed 1 during frame stalls, causing overshoot and jitter.
Bound the product of response and timeScale to a maximum of 1 by wrapping the
multiplication factor (response * timeScale) with Math.min to prevent
smoothedLevel from overshooting its normalized bounds and ensure stable
frame-rate independent smoothing even when frames are delayed.

---

Outside diff comments:
In `@main.js`:
- Around line 399-408: In the reloadVisualizer function, remove the stale
reference to the overlayWindow variable on the last line that calls
win.webContents.reloadIgnoringCache(). This line is redundant because all
windows are already being reloaded in the for loop that iterates through
overlayWindows.values(), and overlayWindow no longer exists in the codebase,
which will cause a runtime error. Simply delete this line to resolve the issue.
- Around line 1622-1643: The showCustomContextMenu function currently assumes a
single overlayWindow and sends the context menu to it regardless of which
display the cursor is on. To support multi-display, refactor this function to
determine which display contains the cursor using the cursorPoint coordinates
and screen.getAllDisplays(), then identify the corresponding overlay window for
that display. Instead of using the global overlayWindow reference, find and use
the correct overlay window for the display containing the cursor before sending
the show-context-menu message to overlayWindow.webContents.send().
- Around line 475-480: The sendFocusModeOpacity function currently operates on a
single overlayWindow variable but needs to be updated to support multiple
displays. Refactor this function to iterate over the overlayWindows collection
(similar to how sendAudioLevel handles multiple windows) and send the
focus-mode-opacity message to each non-destroyed window in the collection,
removing the single overlayWindow check and replacing it with a loop that
validates each window before sending.
- Around line 265-286: Replace all references to `overlayWindow` with `win`
throughout this code block since the window is created as `win` on line 241.
Additionally, in the `closed` event handler where the code currently sets
`overlayWindow = null`, this should instead remove the window from the Map data
structure that stores windows for the multi-display architecture (likely using a
key identifier like the display ID or window ID to locate and delete the entry
from the Map).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 08ffb67e-7825-489b-9bed-6501fd622e2e

📥 Commits

Reviewing files that changed from the base of the PR and between 944e15f and d8dff89.

📒 Files selected for processing (2)
  • main.js
  • renderer.js

Comment thread renderer.js Outdated
@Aditya948351
Aditya948351 requested a review from SamXop123 June 19, 2026 15:04
@Aditya948351

Copy link
Copy Markdown
Contributor Author

@SamXop123 Requesting your review again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Architecture] Refine Motion Systems

3 participants