Skip to content

Prevent duplicate canvas event listener registration#618

Open
tracygardner wants to merge 1 commit intomainfrom
claude/fix-memory-leak-X7KoW
Open

Prevent duplicate canvas event listener registration#618
tracygardner wants to merge 1 commit intomainfrom
claude/fix-memory-leak-X7KoW

Conversation

@tracygardner
Copy link
Copy Markdown
Contributor

@tracygardner tracygardner commented May 8, 2026

Summary

Wrapped all canvas and window event listener registrations in a guard condition to prevent duplicate listener attachment when the initialization function is called multiple times.

Key Changes

  • Added flock._canvasListenersRegistered flag to track whether listeners have already been registered
  • Wrapped all event listener attachments (touchend, keydown, keyup, blur, pointerup) in a conditional block that only executes once
  • This prevents memory leaks and duplicate event handling that could occur if the initialization code runs more than once

Implementation Details

The change uses a simple boolean flag (flock._canvasListenersRegistered) to ensure that the event listener registration block only executes on the first initialization. This is a common pattern for preventing duplicate listener registration in scenarios where initialization functions may be called multiple times during the application lifecycle.

https://claude.ai/code/session_01QYFwXKPZrjm2RxVFKcKNvA

Summary by CodeRabbit

  • Bug Fixes
    • Resolved an issue where input event listeners were being registered multiple times during initialization, preventing potential performance issues and input handling anomalies.

createEngine() is called on every code run (engine is disposed to null
between runs), causing touchend, keydown, keyup, blur, and pointerup
handlers to stack up indefinitely with no way to remove them. Guard
registration with a one-time flag; the handlers are safe to reuse across
runs since they access flock.scene lazily at call time.

https://claude.ai/code/session_01QYFwXKPZrjm2RxVFKcKNvA
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The initialize() function now guards canvas and window input event listener registration with a flock._canvasListenersRegistered flag. All listener attachments—touchend, keydown, keyup, blur, and pointerup—are wrapped in a single conditional block that executes only once, preventing duplicate listener registration on repeated initialization calls.

Changes

Event Listener Registration Guard

Layer / File(s) Summary
Single-use listener registration
flock.js
Canvas event listeners (touchend, keydown, keyup) and window hard-reset handlers (blur, pointerup) are now guarded by a _canvasListenersRegistered flag to prevent duplicate attachment on repeated initialize() calls.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A guard so bright, a flag so true,
Listeners register just once, not two!
No duplicate echoes in the night,
Flock's events flow clean and light. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: preventing duplicate canvas event listener registration, which matches the core objective of guarding listener registration with a boolean flag.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fix-memory-leak-X7KoW

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@flock.js`:
- Around line 1283-1292: The touchend handler currently dereferences flock.scene
and flock.scene.activeCamera directly which can be null during dispose/re-init;
update the handler to guard against a missing scene before accessing
activeCamera and its inputs (e.g., check flock && flock.scene &&
flock.scene.activeCamera first), then continue with the existing logic that
reads inputs and calls flock._hardResetCameraControls; ensure the same
null-check pattern surrounds the input retrieval and subsequent use of
flock._hardResetCameraControls to avoid runtime exceptions.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 34734cb1-5a39-4c18-b13f-9f81d2ad028d

📥 Commits

Reviewing files that changed from the base of the PR and between e96964b and 42bd388.

📒 Files selected for processing (1)
  • flock.js

Comment thread flock.js
Comment on lines +1283 to +1292
const input = flock.scene.activeCamera.inputs?.attached?.pointers;
// Add null check for input itself
if (
input &&
(input._pointA !== null ||
input._pointB !== null ||
input._isMultiTouch === true)
) {
flock._hardResetCameraControls(flock.scene.activeCamera, {
reattachDelayMs: 100,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard flock.scene before dereferencing in touchend handler.

flock.scene.activeCamera is accessed directly; during dispose/re-init windows flock.scene can be null, causing a runtime exception in the event handler.

Proposed fix
-            const input = flock.scene.activeCamera.inputs?.attached?.pointers;
+            const activeCamera = flock.scene?.activeCamera;
+            const input = activeCamera?.inputs?.attached?.pointers;
             // Add null check for input itself
             if (
               input &&
               (input._pointA !== null ||
                 input._pointB !== null ||
                 input._isMultiTouch === true)
             ) {
-              flock._hardResetCameraControls(flock.scene.activeCamera, {
+              flock._hardResetCameraControls(activeCamera, {
                 reattachDelayMs: 100,
                 noPreventDefault: true,
               });
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const input = flock.scene.activeCamera.inputs?.attached?.pointers;
// Add null check for input itself
if (
input &&
(input._pointA !== null ||
input._pointB !== null ||
input._isMultiTouch === true)
) {
flock._hardResetCameraControls(flock.scene.activeCamera, {
reattachDelayMs: 100,
const activeCamera = flock.scene?.activeCamera;
const input = activeCamera?.inputs?.attached?.pointers;
// Add null check for input itself
if (
input &&
(input._pointA !== null ||
input._pointB !== null ||
input._isMultiTouch === true)
) {
flock._hardResetCameraControls(activeCamera, {
reattachDelayMs: 100,
🧰 Tools
🪛 GitHub Actions: Prettier / prettier

[warning] Prettier reported formatting issues.

🤖 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 `@flock.js` around lines 1283 - 1292, The touchend handler currently
dereferences flock.scene and flock.scene.activeCamera directly which can be null
during dispose/re-init; update the handler to guard against a missing scene
before accessing activeCamera and its inputs (e.g., check flock && flock.scene
&& flock.scene.activeCamera first), then continue with the existing logic that
reads inputs and calls flock._hardResetCameraControls; ensure the same
null-check pattern surrounds the input retrieval and subsequent use of
flock._hardResetCameraControls to avoid runtime exceptions.

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.

2 participants