Skip to content

fix: cache canvas cursor style to avoid redundant DOM writes#9171

Merged
christian-byrne merged 3 commits intomainfrom
perf/fix-cursor-cache
Mar 4, 2026
Merged

fix: cache canvas cursor style to avoid redundant DOM writes#9171
christian-byrne merged 3 commits intomainfrom
perf/fix-cursor-cache

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Feb 24, 2026

Summary

Cache canvas.style.cursor to avoid redundant DOM writes that dirty Firefox's style tree.

Changes

  • What: Add _lastCursor field to LGraphCanvas._updateCursorStyle() — only writes canvas.style.cursor when the value changes. Eliminates ~347 redundant style mutations per profiling session.

Review Focus

  • The fix is 2 lines (cache field + comparison). The unit test validates the caching pattern without requiring full LGraphCanvas instantiation.
  • This is one of several contributors to Firefox's cascading style recalculation freeze. Each canvas.style.cursor write dirties the style tree, which is flushed during the next paint in the canvas render loop.

Stack

2 of 4 in Firefox perf fix stack. Depends on #9170.

┆Issue is synchronized with this Notion page by Unito

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 02/27/2026, 02:59:53 AM UTC

Links

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🎭 Playwright: ✅ 541 passed, 0 failed · 8 flaky

📊 Browser Reports
  • chromium: View Report (✅ 528 / ❌ 0 / ⚠️ 8 / ⏭️ 10)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 10 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21c47f9 and ec1e291.

📒 Files selected for processing (3)
  • src/lib/litegraph/src/LGraphCanvas.ts
  • src/lib/litegraph/src/cursorCache.test.ts
  • src/lib/litegraph/src/cursorCache.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/litegraph/src/LGraphCanvas.ts
  • src/lib/litegraph/src/cursorCache.ts
  • src/lib/litegraph/src/cursorCache.test.ts

📝 Walkthrough

Walkthrough

Adds a cursor-caching utility and integrates it into LGraphCanvas so cursor updates route through a cached setter that only writes to the DOM when the cursor value changes; includes unit tests for the cache.

Changes

Cohort / File(s) Summary
Canvas integration
src/lib/litegraph/src/LGraphCanvas.ts
Introduces a private _setCursor member initialized via createCursorCache(element) and replaces direct element.style.cursor assignments with _setCursor(...) calls in cursor update and resize-direction logic.
Cursor cache implementation
src/lib/litegraph/src/cursorCache.ts
New export function createCursorCache(element: HTMLElement) that returns a setCursor(cursor: string) closure which caches the last cursor and updates element.style.cursor only when the value changes.
Cursor cache tests
src/lib/litegraph/src/cursorCache.test.ts
New tests using a mock element to verify: deduplication of consecutive identical cursor writes, writing when value differs, and skipping redundant writes interspersed with changes.
Manifest
package.json
Minor manifest lines changed (small metadata edit recorded in diff).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Canvas as LGraphCanvas
participant Cache as createCursorCache()
participant DOM as HTMLElement.style
rect rgba(200,230,255,0.5)
Canvas->>Cache: initialize with element
end
rect rgba(200,255,200,0.5)
Canvas->>Cache: request setCursor("pointer")
Cache->>Cache: compare with lastCursor
alt different
Cache->>DOM: write "pointer" to style.cursor
else same
Cache-->>DOM: no write
end

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰
I hop the canvas, soft and spry,
Caching each twitch so DOM won't cry.
One gentle write when the cursor must change,
Then quiet fields where updates stay strange.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing cursor caching to eliminate redundant DOM writes, which is the core purpose of this PR.
Description check ✅ Passed The description covers the summary, main changes, review focus, and context about the performance impact and dependency stack, matching the template structure.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf/fix-cursor-cache

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

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

⚡ Performance Report

Metric Baseline PR Δ
canvas-idle: style recalcs 121 122 +1% ⚪
canvas-idle: layouts 0 0 +0% ⚪
canvas-idle: task duration 395ms 406ms +3% ⚪
canvas-mouse-sweep: style recalcs 189 187 -1% ⚪
canvas-mouse-sweep: layouts 12 12 +0% ⚪
canvas-mouse-sweep: task duration 1123ms 965ms -14% 🟢
dom-widget-clipping: style recalcs 50 42 -16% 🟢
dom-widget-clipping: layouts 1 0 -100% 🟢
dom-widget-clipping: task duration 442ms 379ms -14% 🟢
Raw data
{
  "timestamp": "2026-02-27T03:01:34.473Z",
  "gitSha": "eed317a184f9b0596a9a3fab341f2c4f1271b06a",
  "branch": "perf/fix-cursor-cache",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2005.7799999999588,
      "styleRecalcs": 122,
      "styleRecalcDurationMs": 23.925,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 405.733,
      "heapDeltaBytes": -3183896
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2050.46399999992,
      "styleRecalcs": 187,
      "styleRecalcDurationMs": 70.30600000000001,
      "layouts": 12,
      "layoutDurationMs": 4.425,
      "taskDurationMs": 965.042,
      "heapDeltaBytes": -3424536
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 580.889999999954,
      "styleRecalcs": 42,
      "styleRecalcDurationMs": 13.850999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 378.611,
      "heapDeltaBytes": 7577304
    }
  ]
}

@christian-byrne christian-byrne force-pushed the perf/fix-cursor-cache branch 4 times, most recently from 120f85d to 9ba9c78 Compare February 26, 2026 03:29
Base automatically changed from perf/testing-infrastructure to main February 26, 2026 04:10
@christian-byrne christian-byrne marked this pull request as ready for review February 26, 2026 04:12
@christian-byrne christian-byrne requested a review from a team as a code owner February 26, 2026 04:12
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Feb 26, 2026
@github-actions
Copy link

github-actions bot commented Feb 26, 2026

📦 Bundle: 4.44 MB gzip 🟢 -39 B

Details

Summary

  • Raw size: 20.8 MB baseline 20.8 MB — 🔴 +237 B
  • Gzip: 4.44 MB baseline 4.44 MB — 🟢 -39 B
  • Brotli: 3.43 MB baseline 3.43 MB — 🔴 +106 B
  • Bundles: 228 current • 228 baseline • 108 added / 108 removed

Category Glance
Data & Services 🔴 +237 B (2.55 MB) · Vendor & Third-Party ⚪ 0 B (8.84 MB) · Other ⚪ 0 B (7.77 MB) · Graph Workspace ⚪ 0 B (1.02 MB) · Panels & Settings ⚪ 0 B (435 kB) · Views & Navigation ⚪ 0 B (72.1 kB) · + 5 more

App Entry Points — 17.9 kB (baseline 17.9 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-D3uw89sc.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -6.34 kB 🟢 -5.52 kB
assets/index-Js1u093w.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +6.35 kB 🔴 +5.52 kB

Status: 1 added / 1 removed

Graph Workspace — 1.02 MB (baseline 1.02 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-C7WMW5Sl.js (new) 1.02 MB 🔴 +1.02 MB 🔴 +218 kB 🔴 +164 kB
assets/GraphView-TkTrmRYi.js (removed) 1.02 MB 🟢 -1.02 MB 🟢 -218 kB 🟢 -164 kB

Status: 1 added / 1 removed

Views & Navigation — 72.1 kB (baseline 72.1 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-B4pKC8A2.js (new) 15.5 kB 🔴 +15.5 kB 🔴 +3.32 kB 🔴 +2.81 kB
assets/CloudSurveyView-tp2D6_WM.js (removed) 15.5 kB 🟢 -15.5 kB 🟢 -3.32 kB 🟢 -2.82 kB
assets/CloudLoginView-BevH5zSb.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.19 kB 🟢 -2.82 kB
assets/CloudLoginView-YyVWDu8F.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.19 kB 🔴 +2.82 kB
assets/CloudSignupView-DGykF5ub.js (removed) 9.37 kB 🟢 -9.37 kB 🟢 -2.7 kB 🟢 -2.36 kB
assets/CloudSignupView-z2psk6lM.js (new) 9.37 kB 🔴 +9.37 kB 🔴 +2.7 kB 🔴 +2.35 kB
assets/UserCheckView-BFJJ4dZL.js (removed) 8.41 kB 🟢 -8.41 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/UserCheckView-DSajWk64.js (new) 8.41 kB 🔴 +8.41 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/CloudLayoutView-B2XMaMtk.js (removed) 6.43 kB 🟢 -6.43 kB 🟢 -2.1 kB 🟢 -1.82 kB
assets/CloudLayoutView-DlrJEVIo.js (new) 6.43 kB 🔴 +6.43 kB 🔴 +2.1 kB 🔴 +1.82 kB
assets/CloudForgotPasswordView-Bvsfsf2r.js (removed) 5.56 kB 🟢 -5.56 kB 🟢 -1.93 kB 🟢 -1.71 kB
assets/CloudForgotPasswordView-DmYL-RAJ.js (new) 5.56 kB 🔴 +5.56 kB 🔴 +1.93 kB 🔴 +1.7 kB
assets/CloudAuthTimeoutView-s2F7JGPJ.js (removed) 4.91 kB 🟢 -4.91 kB 🟢 -1.77 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-YtSccPQl.js (new) 4.91 kB 🔴 +4.91 kB 🔴 +1.76 kB 🔴 +1.54 kB
assets/CloudSubscriptionRedirectView-Cj9jmB4J.js (new) 4.75 kB 🔴 +4.75 kB 🔴 +1.79 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-QkMgqRSJ.js (removed) 4.75 kB 🟢 -4.75 kB 🟢 -1.78 kB 🟢 -1.57 kB
assets/UserSelectView-B4OHgJDX.js (new) 4.5 kB 🔴 +4.5 kB 🔴 +1.64 kB 🔴 +1.46 kB
assets/UserSelectView-BZtCx_xg.js (removed) 4.5 kB 🟢 -4.5 kB 🟢 -1.64 kB 🟢 -1.47 kB
assets/CloudSorryContactSupportView-Bypca0av.js 1.02 kB 1.02 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-CI4MZk1L.js 296 B 296 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 9 added / 9 removed

Panels & Settings — 435 kB (baseline 435 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SecretsPanel-CWwcEzfQ.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.31 kB 🟢 -4.66 kB
assets/SecretsPanel-DW-k3oMq.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.31 kB 🔴 +4.66 kB
assets/LegacyCreditsPanel-CzqVQSGS.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +5.56 kB 🔴 +4.89 kB
assets/LegacyCreditsPanel-W5zlLljm.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -5.56 kB 🟢 -4.9 kB
assets/SubscriptionPanel-B72WNyEj.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.66 kB 🟢 -4.11 kB
assets/SubscriptionPanel-BMAVKFbi.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.65 kB 🔴 +4.09 kB
assets/KeybindingPanel-C_Ce_pxt.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -3.52 kB 🟢 -3.11 kB
assets/KeybindingPanel-GC5gF_Bc.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +3.51 kB 🔴 +3.11 kB
assets/AboutPanel-D54nAG9I.js (new) 9.79 kB 🔴 +9.79 kB 🔴 +2.73 kB 🔴 +2.45 kB
assets/AboutPanel-DGKmduyT.js (removed) 9.79 kB 🟢 -9.79 kB 🟢 -2.73 kB 🟢 -2.45 kB
assets/ExtensionPanel-CYJ8B2lv.js (removed) 9.38 kB 🟢 -9.38 kB 🟢 -2.65 kB 🟢 -2.36 kB
assets/ExtensionPanel-iHHuF7bR.js (new) 9.38 kB 🔴 +9.38 kB 🔴 +2.65 kB 🔴 +2.36 kB
assets/ServerConfigPanel-1fEabEu4.js (new) 6.44 kB 🔴 +6.44 kB 🔴 +2.12 kB 🔴 +1.9 kB
assets/ServerConfigPanel-C0TRP1Ex.js (removed) 6.44 kB 🟢 -6.44 kB 🟢 -2.12 kB 🟢 -1.89 kB
assets/UserPanel-D1CWSD_y.js (removed) 6.16 kB 🟢 -6.16 kB 🟢 -1.99 kB 🟢 -1.75 kB
assets/UserPanel-D9o1DUkV.js (new) 6.16 kB 🔴 +6.16 kB 🔴 +1.99 kB 🔴 +1.75 kB
assets/cloudRemoteConfig-Ddj8hQZI.js (removed) 1.44 kB 🟢 -1.44 kB 🟢 -703 B 🟢 -609 B
assets/cloudRemoteConfig-Doi1XrE3.js (new) 1.44 kB 🔴 +1.44 kB 🔴 +704 B 🔴 +616 B
assets/refreshRemoteConfig-BQR3O7wT.js (new) 1.14 kB 🔴 +1.14 kB 🔴 +521 B 🔴 +458 B
assets/refreshRemoteConfig-CEnssXwC.js (removed) 1.14 kB 🟢 -1.14 kB 🟢 -520 B 🟢 -458 B
assets/config-CGn5JFmU.js 996 B 996 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B5oF6TeI.js 29.9 kB 29.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BVYOg4dh.js 24.5 kB 24.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CBEvSL1z.js 38.5 kB 38.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CGx1t8IZ.js 27.8 kB 27.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CNcb_4nC.js 30.5 kB 30.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Cx1dZM6H.js 23.9 kB 23.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Dw-QS6Nb.js 27.9 kB 27.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DXxgnCSn.js 32.4 kB 32.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-GRFn4guL.js 34.2 kB 34.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-mgwKIVQ2.js 28.8 kB 28.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-s83B801I.js 28.7 kB 28.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 10 added / 10 removed

User & Accounts — 16 kB (baseline 16 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-A6aOk8qX.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.18 kB 🟢 -985 B
assets/auth-BVgvtGUx.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.18 kB 🔴 +988 B
assets/SignUpForm-DyYH62tn.js (new) 3.01 kB 🔴 +3.01 kB 🔴 +1.23 kB 🔴 +1.09 kB
assets/SignUpForm-IPCd3lOf.js (removed) 3.01 kB 🟢 -3.01 kB 🟢 -1.23 kB 🟢 -1.09 kB
assets/UpdatePasswordContent-DOWRP1hr.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.07 kB 🟢 -941 B
assets/UpdatePasswordContent-DrXLBibM.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.07 kB 🔴 +942 B
assets/firebaseAuthStore-CQMiq6A7.js (new) 788 B 🔴 +788 B 🔴 +384 B 🔴 +375 B
assets/firebaseAuthStore-vrvmEmmj.js (removed) 788 B 🟢 -788 B 🟢 -390 B 🟢 -347 B
assets/auth-bdTbaYr6.js (removed) 357 B 🟢 -357 B 🟢 -227 B 🟢 -193 B
assets/auth-DeQbVhkr.js (new) 357 B 🔴 +357 B 🔴 +226 B 🔴 +191 B
assets/PasswordFields-DLbVLg8O.js 4.51 kB 4.51 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WorkspaceProfilePic-D6ioir1T.js 1.57 kB 1.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Editors & Dialogs — 736 B (baseline 736 B) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-D4LpfE7b.js (new) 736 B 🔴 +736 B 🔴 +378 B 🔴 +349 B
assets/useSubscriptionDialog-pyivOuVL.js (removed) 736 B 🟢 -736 B 🟢 -381 B 🟢 -350 B

Status: 1 added / 1 removed

UI Components — 47.1 kB (baseline 47.1 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useTerminalTabs-CxtOSgey.js (new) 9.84 kB 🔴 +9.84 kB 🔴 +3.39 kB 🔴 +3 kB
assets/useTerminalTabs-hLuNZQu3.js (removed) 9.84 kB 🟢 -9.84 kB 🟢 -3.4 kB 🟢 -3 kB
assets/ComfyQueueButton-B2_Dj06P.js (removed) 8.02 kB 🟢 -8.02 kB 🟢 -2.49 kB 🟢 -2.23 kB
assets/ComfyQueueButton-BvHeYC9g.js (new) 8.02 kB 🔴 +8.02 kB 🔴 +2.48 kB 🔴 +2.23 kB
assets/SubscribeButton-kNHSgOaw.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -1.07 kB 🟢 -941 B
assets/SubscribeButton-MrYhsH6r.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +1.07 kB 🔴 +945 B
assets/cloudFeedbackTopbarButton-BXJSs1Xt.js (new) 1.59 kB 🔴 +1.59 kB 🔴 +851 B 🔴 +765 B
assets/cloudFeedbackTopbarButton-gRxVplVc.js (removed) 1.59 kB 🟢 -1.59 kB 🟢 -852 B 🟢 -758 B
assets/ComfyQueueButton-B5h4IXir.js (removed) 793 B 🟢 -793 B 🟢 -391 B 🟢 -349 B
assets/ComfyQueueButton-HR9dPE5e.js (new) 793 B 🔴 +793 B 🔴 +392 B 🔴 +349 B
assets/Button-D1z3poyI.js 2.98 kB 2.98 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-BEnZAylJ.js 1.24 kB 1.24 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/FormSearchInput-Bg4LklDe.js 3.73 kB 3.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ScrubableNumberInput-DecBFGbM.js 5.94 kB 5.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-CJNpTEnW.js 7.44 kB 7.44 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-CnQQLXB-.js 1.17 kB 1.17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-sg8Jj4MY.js 1.84 kB 1.84 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Data & Services — 2.55 MB (baseline 2.55 MB) • 🔴 +237 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-BaeTIl3M.js (new) 1.75 MB 🔴 +1.75 MB 🔴 +393 kB 🔴 +296 kB
assets/dialogService-BfTcc-ND.js (removed) 1.75 MB 🟢 -1.75 MB 🟢 -393 kB 🟢 -296 kB
assets/api-DOig6q4Q.js (new) 679 kB 🔴 +679 kB 🔴 +154 kB 🔴 +122 kB
assets/api-RqllEVak.js (removed) 678 kB 🟢 -678 kB 🟢 -153 kB 🟢 -122 kB
assets/load3dService-BCBJbpZz.js (removed) 91 kB 🟢 -91 kB 🟢 -19.1 kB 🟢 -16.4 kB
assets/load3dService-DMBHlyt_.js (new) 91 kB 🔴 +91 kB 🔴 +19.1 kB 🔴 +16.4 kB
assets/extensionStore-CbtD3l7K.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +4.21 kB 🔴 +3.7 kB
assets/extensionStore-DCkvMazm.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -4.21 kB 🟢 -3.69 kB
assets/releaseStore-DGkqKpfB.js (removed) 7.96 kB 🟢 -7.96 kB 🟢 -2.22 kB 🟢 -1.95 kB
assets/releaseStore-Z01nAtXD.js (new) 7.96 kB 🔴 +7.96 kB 🔴 +2.22 kB 🔴 +1.96 kB
assets/keybindingService-BKBJb-Mt.js (new) 6.52 kB 🔴 +6.52 kB 🔴 +1.71 kB 🔴 +1.47 kB
assets/keybindingService-TCfeDVIT.js (removed) 6.52 kB 🟢 -6.52 kB 🟢 -1.71 kB 🟢 -1.47 kB
assets/bootstrapStore-BPe07mav.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -875 B 🟢 -784 B
assets/bootstrapStore-DN44dd_W.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +875 B 🔴 +785 B
assets/userStore-BtA_Qp94.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +721 B 🔴 +678 B
assets/userStore-DOOhmxK8.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -720 B 🟢 -631 B
assets/audioService-CAxIq9qd.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +850 B 🔴 +726 B
assets/audioService-W2TdI9Z1.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -849 B 🟢 -724 B
assets/releaseStore-C_GdZ9QL.js (removed) 760 B 🟢 -760 B 🟢 -385 B 🟢 -337 B
assets/releaseStore-q_hs709Y.js (new) 760 B 🔴 +760 B 🔴 +384 B 🔴 +340 B
assets/settingStore-B7RcFUWW.js (removed) 744 B 🟢 -744 B 🟢 -387 B 🟢 -365 B
assets/settingStore-BYc_NAW7.js (new) 744 B 🔴 +744 B 🔴 +382 B 🔴 +372 B
assets/workflowDraftStore-CBB6xal9.js (new) 736 B 🔴 +736 B 🔴 +375 B 🔴 +335 B
assets/workflowDraftStore-G4cfd76B.js (removed) 736 B 🟢 -736 B 🟢 -381 B 🟢 -332 B
assets/dialogService-CBbiokgh.js (removed) 725 B 🟢 -725 B 🟢 -367 B 🟢 -325 B
assets/dialogService-NaZomsEe.js (new) 725 B 🔴 +725 B 🔴 +366 B 🔴 +340 B
assets/serverConfigStore-EPk4OtIK.js 2.32 kB 2.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 13 added / 13 removed

Utilities & Hooks — 55.5 kB (baseline 55.5 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useLoad3d-D-ynFjpr.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.63 kB 🔴 +3.21 kB
assets/useLoad3d-RuiihLO1.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.63 kB 🟢 -3.2 kB
assets/useLoad3dViewer-D09ahe0M.js (new) 14.1 kB 🔴 +14.1 kB 🔴 +3.15 kB 🔴 +2.8 kB
assets/useLoad3dViewer-hLNlYAow.js (removed) 14.1 kB 🟢 -14.1 kB 🟢 -3.15 kB 🟢 -2.79 kB
assets/useFeatureFlags-CVZ6kZJ5.js (removed) 4.14 kB 🟢 -4.14 kB 🟢 -1.24 kB 🟢 -1.06 kB
assets/useFeatureFlags-DDYpcYu9.js (new) 4.14 kB 🔴 +4.14 kB 🔴 +1.24 kB 🔴 +1.06 kB
assets/useWorkspaceUI-CLiX9-T1.js (new) 3 kB 🔴 +3 kB 🔴 +821 B 🔴 +702 B
assets/useWorkspaceUI-DwwOZk2W.js (removed) 3 kB 🟢 -3 kB 🟢 -822 B 🟢 -699 B
assets/subscriptionCheckoutUtil-Bq2PoHC9.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +1.06 kB 🔴 +946 B
assets/subscriptionCheckoutUtil-DiIKGDj9.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.06 kB 🟢 -946 B
assets/useErrorHandling-p_KEFjUh.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -628 B 🟢 -533 B
assets/useErrorHandling-xGPRmdH1.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +632 B 🔴 +533 B
assets/useWorkspaceSwitch-BARcFwFn.js (removed) 1.25 kB 🟢 -1.25 kB 🟢 -544 B 🟢 -483 B
assets/useWorkspaceSwitch-CoJ5Vk8H.js (new) 1.25 kB 🔴 +1.25 kB 🔴 +545 B 🔴 +483 B
assets/useLoad3d-CBhmFSZR.js (removed) 859 B 🟢 -859 B 🟢 -425 B 🟢 -375 B
assets/useLoad3d-ePgXLyBf.js (new) 859 B 🔴 +859 B 🔴 +421 B 🔴 +382 B
assets/audioUtils-CVxjqAo3.js (new) 858 B 🔴 +858 B 🔴 +500 B 🔴 +402 B
assets/audioUtils-p3iHgBSB.js (removed) 858 B 🟢 -858 B 🟢 -498 B 🟢 -410 B
assets/useLoad3dViewer-C5gwnJiY.js (removed) 838 B 🟢 -838 B 🟢 -411 B 🟢 -365 B
assets/useLoad3dViewer-Cb8GlMsK.js (new) 838 B 🔴 +838 B 🔴 +407 B 🔴 +370 B
assets/useCurrentUser-DBazHyyB.js (new) 722 B 🔴 +722 B 🔴 +370 B 🔴 +344 B
assets/useCurrentUser-wWuEQkIE.js (removed) 722 B 🟢 -722 B 🟢 -372 B 🟢 -349 B
assets/_plugin-vue_export-helper-ralzwvFM.js 315 B 315 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-CY7QMUhQ.js 7 kB 7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/envUtil-Clzmwvt4.js 466 B 466 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-Cddas8Zl.js 1.56 kB 1.56 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SkeletonUtils-BputJAFn.js 133 B 133 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useExternalLink-DzcPdi1l.js 1.66 kB 1.66 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 11 added / 11 removed

Vendor & Third-Party — 8.84 MB (baseline 8.84 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-axios-Cp6hch1I.js 70.7 kB 70.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-chart-BxkFiWzp.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-firebase-BvMr43CG.js 836 kB 836 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-i18n-DNX73mqE.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-markdown-D5S6AC80.js 103 kB 103 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DrYd4O-6.js 1.52 MB 1.52 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-BnCPTL0g.js 1.73 MB 1.73 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-DVmi2O2Z.js 388 kB 388 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-sentry-SQwstEKc.js 182 kB 182 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-LBLOE6BD.js 1.8 MB 1.8 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BnYkbQDM.js 634 kB 634 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-core-DtiQ1dr9.js 311 kB 311 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vueuse-D2jVNnmE.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-MKpa1ZAW.js 374 kB 374 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-yjs-CP_4YO8u.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-zod-DcCUUPIi.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.77 MB (baseline 7.77 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-acXtCu1m.js (removed) 73.4 kB 🟢 -73.4 kB 🟢 -18.9 kB 🟢 -16.2 kB
assets/core-DQ6rMLCr.js (new) 73.4 kB 🔴 +73.4 kB 🔴 +18.9 kB 🔴 +16.2 kB
assets/groupNode-B2M1s51q.js (new) 71.8 kB 🔴 +71.8 kB 🔴 +17.7 kB 🔴 +15.6 kB
assets/groupNode-D3_6rAak.js (removed) 71.8 kB 🟢 -71.8 kB 🟢 -17.7 kB 🟢 -15.6 kB
assets/WidgetSelect-BwaTfEuW.js (removed) 58.1 kB 🟢 -58.1 kB 🟢 -12.4 kB 🟢 -10.7 kB
assets/WidgetSelect-CO6NdD0k.js (new) 58.1 kB 🔴 +58.1 kB 🔴 +12.4 kB 🔴 +10.7 kB
assets/SubscriptionRequiredDialogContentWorkspace-B39kNVZn.js (new) 46.3 kB 🔴 +46.3 kB 🔴 +8.65 kB 🔴 +7.49 kB
assets/SubscriptionRequiredDialogContentWorkspace-UBswvrxl.js (removed) 46.3 kB 🟢 -46.3 kB 🟢 -8.65 kB 🟢 -7.5 kB
assets/WidgetPainter-CwfoA3kZ.js (removed) 32.5 kB 🟢 -32.5 kB 🟢 -7.96 kB 🟢 -7.07 kB
assets/WidgetPainter-DxC1OVrm.js (new) 32.5 kB 🔴 +32.5 kB 🔴 +7.96 kB 🔴 +7.07 kB
assets/Load3DControls-6_F7ivXG.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +5.34 kB 🔴 +4.65 kB
assets/Load3DControls-BIiicqOB.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -5.34 kB 🟢 -4.64 kB
assets/WorkspacePanelContent-BDRX5xPG.js (new) 29.3 kB 🔴 +29.3 kB 🔴 +6.14 kB 🔴 +5.39 kB
assets/WorkspacePanelContent-C9r8TZdE.js (removed) 29.3 kB 🟢 -29.3 kB 🟢 -6.14 kB 🟢 -5.39 kB
assets/SubscriptionRequiredDialogContent-BEDS6J4R.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -6.57 kB 🟢 -5.77 kB
assets/SubscriptionRequiredDialogContent-ztyRjxy-.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +6.57 kB 🔴 +5.79 kB
assets/Load3dViewerContent-CNXZ8rU5.js (new) 23 kB 🔴 +23 kB 🔴 +5.18 kB 🔴 +4.49 kB
assets/Load3dViewerContent-DnDkiLVx.js (removed) 23 kB 🟢 -23 kB 🟢 -5.18 kB 🟢 -4.5 kB
assets/WidgetImageCrop-BlXjlEZt.js (removed) 22.1 kB 🟢 -22.1 kB 🟢 -5.5 kB 🟢 -4.85 kB
assets/WidgetImageCrop-TmPwSVrs.js (new) 22.1 kB 🔴 +22.1 kB 🔴 +5.5 kB 🔴 +4.85 kB
assets/SubscriptionPanelContentWorkspace-DaC85suE.js (removed) 21.6 kB 🟢 -21.6 kB 🟢 -5.05 kB 🟢 -4.45 kB
assets/SubscriptionPanelContentWorkspace-Dlc-_q4z.js (new) 21.6 kB 🔴 +21.6 kB 🔴 +5.05 kB 🔴 +4.46 kB
assets/CurrentUserPopoverWorkspace-B3kDw4Tg.js (removed) 19.9 kB 🟢 -19.9 kB 🟢 -4.88 kB 🟢 -4.34 kB
assets/CurrentUserPopoverWorkspace-B4l4dY9t.js (new) 19.9 kB 🔴 +19.9 kB 🔴 +4.88 kB 🔴 +4.34 kB
assets/SignInContent-8AEyUPhX.js (new) 18.9 kB 🔴 +18.9 kB 🔴 +4.76 kB 🔴 +4.17 kB
assets/SignInContent-d5YB4RXY.js (removed) 18.9 kB 🟢 -18.9 kB 🟢 -4.76 kB 🟢 -4.16 kB
assets/WidgetInputNumber-CALBcUAJ.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.75 kB 🔴 +4.22 kB
assets/WidgetInputNumber-DdVVB6-I.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.75 kB 🟢 -4.22 kB
assets/WidgetRecordAudio-BLdb403E.js (removed) 17.3 kB 🟢 -17.3 kB 🟢 -4.94 kB 🟢 -4.42 kB
assets/WidgetRecordAudio-Cn3Dpz2t.js (new) 17.3 kB 🔴 +17.3 kB 🔴 +4.94 kB 🔴 +4.42 kB
assets/Load3D-C9IXLDz6.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.03 kB 🟢 -3.51 kB
assets/Load3D-DXAocf6t.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.03 kB 🔴 +3.51 kB
assets/load3d-CuviKZCF.js (new) 14.7 kB 🔴 +14.7 kB 🔴 +4.19 kB 🔴 +3.63 kB
assets/load3d-DQV_GAok.js (removed) 14.7 kB 🟢 -14.7 kB 🟢 -4.18 kB 🟢 -3.63 kB
assets/AudioPreviewPlayer-Pu16kmv0.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -3.19 kB 🟢 -2.86 kB
assets/AudioPreviewPlayer-wAarm5Q9.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +3.19 kB 🔴 +2.86 kB
assets/changeTracker-C6j69JEF.js (new) 9.38 kB 🔴 +9.38 kB 🔴 +2.9 kB 🔴 +2.55 kB
assets/changeTracker-DiEvuTE7.js (removed) 9.38 kB 🟢 -9.38 kB 🟢 -2.89 kB 🟢 -2.55 kB
assets/nodeTemplates-BxpTSuiW.js (new) 9.29 kB 🔴 +9.29 kB 🔴 +3.25 kB 🔴 +2.86 kB
assets/nodeTemplates-C2KJkHba.js (removed) 9.29 kB 🟢 -9.29 kB 🟢 -3.25 kB 🟢 -2.86 kB
assets/InviteMemberDialogContent-DjuCxcZO.js (new) 7.38 kB 🔴 +7.38 kB 🔴 +2.29 kB 🔴 +2 kB
assets/InviteMemberDialogContent-TPIaM7RK.js (removed) 7.38 kB 🟢 -7.38 kB 🟢 -2.29 kB 🟢 -2 kB
assets/Load3DConfiguration-B6VoaSwy.js (removed) 6.27 kB 🟢 -6.27 kB 🟢 -1.91 kB 🟢 -1.68 kB
assets/Load3DConfiguration-gWAhJQ_e.js (new) 6.27 kB 🔴 +6.27 kB 🔴 +1.92 kB 🔴 +1.68 kB
assets/CreateWorkspaceDialogContent-BanilMm8.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +1.99 kB 🔴 +1.73 kB
assets/CreateWorkspaceDialogContent-CqHTrb0O.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -1.99 kB 🟢 -1.74 kB
assets/onboardingCloudRoutes-CjFMbNad.js (new) 5.41 kB 🔴 +5.41 kB 🔴 +1.84 kB 🔴 +1.61 kB
assets/onboardingCloudRoutes-D1qWOztf.js (removed) 5.41 kB 🟢 -5.41 kB 🟢 -1.84 kB 🟢 -1.6 kB
assets/FreeTierDialogContent-4HlHCkRg.js (new) 5.39 kB 🔴 +5.39 kB 🔴 +1.89 kB 🔴 +1.67 kB
assets/FreeTierDialogContent-BON2nlt1.js (removed) 5.39 kB 🟢 -5.39 kB 🟢 -1.89 kB 🟢 -1.67 kB
assets/EditWorkspaceDialogContent-D3HeJ11N.js (removed) 5.33 kB 🟢 -5.33 kB 🟢 -1.94 kB 🟢 -1.7 kB
assets/EditWorkspaceDialogContent-MSpOXxOY.js (new) 5.33 kB 🔴 +5.33 kB 🔴 +1.94 kB 🔴 +1.7 kB
assets/ValueControlPopover-BlafgSYw.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.76 kB 🟢 -1.57 kB
assets/ValueControlPopover-DgMwS5Z3.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/Preview3d-CSmupvWw.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.56 kB 🔴 +1.36 kB
assets/Preview3d-Dz9gOXvO.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.57 kB 🟢 -1.36 kB
assets/CancelSubscriptionDialogContent-CGQMQ-wk.js (removed) 4.79 kB 🟢 -4.79 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/CancelSubscriptionDialogContent-Ck_hBKWk.js (new) 4.79 kB 🔴 +4.79 kB 🔴 +1.78 kB 🔴 +1.56 kB
assets/DeleteWorkspaceDialogContent-BpuvNEPZ.js (new) 4.23 kB 🔴 +4.23 kB 🔴 +1.63 kB 🔴 +1.42 kB
assets/DeleteWorkspaceDialogContent-RH_aF6h9.js (removed) 4.23 kB 🟢 -4.23 kB 🟢 -1.63 kB 🟢 -1.42 kB
assets/WidgetWithControl-BOxrzL9X.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.77 kB 🟢 -1.58 kB
assets/WidgetWithControl-FmYmdkm0.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.77 kB 🔴 +1.59 kB
assets/LeaveWorkspaceDialogContent-5JVK_RYT.js (removed) 4.06 kB 🟢 -4.06 kB 🟢 -1.57 kB 🟢 -1.37 kB
assets/LeaveWorkspaceDialogContent-CV2ur5Db.js (new) 4.06 kB 🔴 +4.06 kB 🔴 +1.57 kB 🔴 +1.37 kB
assets/RemoveMemberDialogContent-Be-1VjYV.js (removed) 4.04 kB 🟢 -4.04 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/RemoveMemberDialogContent-ZzRKsfNQ.js (new) 4.04 kB 🔴 +4.04 kB 🔴 +1.52 kB 🔴 +1.33 kB
assets/RevokeInviteDialogContent-BtnfBBz7.js (removed) 3.95 kB 🟢 -3.95 kB 🟢 -1.54 kB 🟢 -1.35 kB
assets/RevokeInviteDialogContent-D1DODs-V.js (new) 3.95 kB 🔴 +3.95 kB 🔴 +1.54 kB 🔴 +1.35 kB
assets/InviteMemberUpsellDialogContent-Bu2kyYmS.js (removed) 3.82 kB 🟢 -3.82 kB 🟢 -1.4 kB 🟢 -1.22 kB
assets/InviteMemberUpsellDialogContent-CYUCUpTv.js (new) 3.82 kB 🔴 +3.82 kB 🔴 +1.4 kB 🔴 +1.23 kB
assets/tierBenefits-B-FbV4zK.js (removed) 3.66 kB 🟢 -3.66 kB 🟢 -1.3 kB 🟢 -1.17 kB
assets/tierBenefits-D5oQa4wX.js (new) 3.66 kB 🔴 +3.66 kB 🔴 +1.3 kB 🔴 +1.17 kB
assets/saveMesh-CmMLlVTz.js (removed) 3.38 kB 🟢 -3.38 kB 🟢 -1.45 kB 🟢 -1.29 kB
assets/saveMesh-hoNnSdb4.js (new) 3.38 kB 🔴 +3.38 kB 🔴 +1.45 kB 🔴 +1.29 kB
assets/cloudSessionCookie-BQIHYmRo.js (new) 3.1 kB 🔴 +3.1 kB 🔴 +1.08 kB 🔴 +984 B
assets/cloudSessionCookie-CKLohnB-.js (removed) 3.1 kB 🟢 -3.1 kB 🟢 -1.08 kB 🟢 -941 B
assets/GlobalToast-ctE62tUI.js (removed) 2.91 kB 🟢 -2.91 kB 🟢 -1.21 kB 🟢 -1.03 kB
assets/GlobalToast-DyPh3pd4.js (new) 2.91 kB 🔴 +2.91 kB 🔴 +1.21 kB 🔴 +1.07 kB
assets/SubscribeToRun-BHSAvOd8.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +1.01 kB 🔴 +881 B
assets/SubscribeToRun-DZOftgTJ.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -1.01 kB 🟢 -867 B
assets/CloudRunButtonWrapper-Dep1fVWF.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -786 B 🟢 -704 B
assets/CloudRunButtonWrapper-eowsYmpi.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +782 B 🔴 +701 B
assets/previousFullPath-BENWpbJb.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +648 B 🔴 +574 B
assets/previousFullPath-Dnx2g6xk.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -651 B 🟢 -579 B
assets/cloudBadges-1MkkkwBy.js (removed) 1.37 kB 🟢 -1.37 kB 🟢 -700 B 🟢 -607 B
assets/cloudBadges-NcAejGpa.js (new) 1.37 kB 🔴 +1.37 kB 🔴 +699 B 🔴 +612 B
assets/cloudSubscription-D5IPEopo.js (removed) 1.33 kB 🟢 -1.33 kB 🟢 -653 B 🟢 -566 B
assets/cloudSubscription-DkpZzHqh.js (new) 1.33 kB 🔴 +1.33 kB 🔴 +651 B 🔴 +567 B
assets/Load3D-BKBdE9TP.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -498 B 🟢 -442 B
assets/Load3D-CFEcxQRn.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +496 B 🔴 +441 B
assets/nightlyBadges-BrYu6A8H.js (removed) 1 kB 🟢 -1 kB 🟢 -530 B 🟢 -467 B
assets/nightlyBadges-CD8-2DKK.js (new) 1 kB 🔴 +1 kB 🔴 +529 B 🔴 +471 B
assets/Load3dViewerContent-BashFeY9.js (new) 993 B 🔴 +993 B 🔴 +464 B 🔴 +415 B
assets/Load3dViewerContent-Cy4pODpg.js (removed) 993 B 🟢 -993 B 🟢 -468 B 🟢 -414 B
assets/SubscriptionPanelContentWorkspace-BX9zPzRM.js (new) 920 B 🔴 +920 B 🔴 +436 B 🔴 +378 B
assets/SubscriptionPanelContentWorkspace-C9OvaAxb.js (removed) 920 B 🟢 -920 B 🟢 -438 B 🟢 -374 B
assets/graphHasMissingNodes-byLH6wZ_.js (removed) 761 B 🟢 -761 B 🟢 -375 B 🟢 -332 B
assets/graphHasMissingNodes-PJvqAaTw.js (new) 761 B 🔴 +761 B 🔴 +375 B 🔴 +318 B
assets/changeTracker-C0iKYAVF.js (new) 757 B 🔴 +757 B 🔴 +384 B 🔴 +356 B
assets/changeTracker-D1Bbl-pJ.js (removed) 757 B 🟢 -757 B 🟢 -385 B 🟢 -335 B
assets/WidgetLegacy-CGKYUNVw.js (removed) 745 B 🟢 -745 B 🟢 -385 B 🟢 -359 B
assets/WidgetLegacy-DcJ0d690.js (new) 745 B 🔴 +745 B 🔴 +380 B 🔴 +354 B
assets/WidgetInputNumber-BMwmm4XI.js (new) 469 B 🔴 +469 B 🔴 +266 B 🔴 +229 B
assets/WidgetInputNumber-BRfHTpPD.js (removed) 469 B 🟢 -469 B 🟢 -264 B 🟢 -227 B
assets/AnimationControls-e1OB6oJR.js 4.61 kB 4.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ApiNodesSignInContent-Bzv_bB5d.js 2.69 kB 2.69 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auto-BTnZwrs2.js 1.7 kB 1.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/BaseViewTemplate-DQKI7wOs.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/comfy-logo-single-D9MrYETV.js 198 B 198 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyOrgHeader-CuEodz4y.js 910 B 910 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-B-AdR9IA.js 17.5 kB 17.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CbkxT8K8.js 16.1 kB 16.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CJGmjcIS.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CMaLgTTb.js 16.7 kB 16.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Cw07MMbJ.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D7EtdE6o.js 16.9 kB 16.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DknEFpK3.js 15.2 kB 15.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ds6WuXnw.js 16.1 kB 16.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Dvq-F-mb.js 17.5 kB 17.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-pUOay9Eo.js 15.1 kB 15.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-u2AZ8xU4.js 16.1 kB 16.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/constants-htt0vt7m.js 579 B 579 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-DKWcz8Zh.js 527 kB 527 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-J0aEQYXk.js 199 B 199 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-0eBOvZE-.js 147 kB 147 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2sg68b4.js 169 kB 169 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BonGln7m.js 183 kB 183 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bwaiyhg6.js 130 kB 130 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CgPRGKFQ.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-COpUCFH6.js 154 kB 154 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D5fk3t1K.js 176 kB 176 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DQn-D-q9.js 151 kB 151 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DRFXRCEv.js 205 kB 205 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-e5nfEcC2.js 146 kB 146 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-MEdUGbq0.js 149 kB 149 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-Dqa2c7nZ.js 1.82 kB 1.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-DLiWNcHw.js 1.43 kB 1.43 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-BLQErkwF.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaOtherTop-NQGNpa4H.js 1.02 kB 1.02 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaTextTop-0crUoXWV.js 1.01 kB 1.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-sJMrm9jB.js 2.77 kB 2.77 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BmbASBY9.js 409 kB 409 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BPIx0d5-.js 393 kB 393 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BWj_hhU9.js 393 kB 393 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-C7at0SVC.js 385 kB 385 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D00E-J_2.js 390 kB 390 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DRodGSrf.js 362 kB 362 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ezyqmmhm.js 443 kB 443 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-GaT9kQvQ.js 483 kB 483 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-hnjb8NXS.js 397 kB 397 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ITpXEN3V.js 442 kB 442 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ZK3OUxU7.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Popover-BIYdg9E5.js 3.65 kB 3.65 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-DLICfi3-.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SelectValue-C_7cycpB.js 8.94 kB 8.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/signInSchema-CIXWGcS0.js 1.53 kB 1.53 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-DVkw5nPu.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/src-CbNGuSYA.js 251 B 251 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionBenefits-DVSfLULk.js 2.01 kB 2.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/telemetry-zZf2dHJ2.js 226 B 226 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/types-DT3N7am7.js 204 B 204 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/VideoPlayOverlay-D-ZhKuWc.js 1.35 kB 1.35 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-NeEr3XWN.js 586 B 586 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-BYbwNME9.js 283 B 283 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-GzA4D-L-.js 3.19 kB 3.19 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-BtoXUSiF.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-DCbDfd19.js 2.9 kB 2.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetCurve-CIcV8pqy.js 9.36 kB 9.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-DZSYhGzO.js 3.61 kB 3.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-oYMwrOjF.js 7 kB 7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-0CncUIzA.js 1.86 kB 1.86 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-TvCt3ARa.js 1.98 kB 1.98 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-Cqdttdn1.js 2.93 kB 2.93 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-DN03zIgB.js 1.1 kB 1.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-B7IIifV6.js 3.96 kB 3.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-CTquGMvp.js 6.8 kB 6.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-Br_tbhcL.js 393 B 393 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 52 added / 52 removed

Copy link
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/litegraph/src/cursorCache.test.ts`:
- Around line 4-14: The test currently validates the standalone helper
createCursorCache() instead of exercising the production path; update the test
to instantiate a minimal LGraphCanvas (or a partial/mock instance) and call
LGraphCanvas._updateCursorStyle(), injecting a mocked canvas element whose
style.cursor setter captures assignments, then assert the setter was called only
when the cursor changes. Locate the existing test assertions around
createCursorCache and replace them with calls to LGraphCanvas._updateCursorStyle
(or a small harness that forwards to it), ensuring you reference the mocked
canvas.style.cursor setter to observe changes and keep the same change/no-change
assertions.

In `@src/lib/litegraph/src/LGraphCanvas.ts`:
- Around line 391-394: The cache _lastCursor can get out of sync because some
code writes this.canvas.style.cursor directly (e.g., the direct write found near
the code that bypasses _updateCursorStyle()); fix by centralizing cursor
updates: replace direct assignments to this.canvas.style.cursor with a single
helper (or call) that sets both this._lastCursor and this.canvas.style.cursor
(or ensure any direct write also updates this._lastCursor before changing
style); update callers that currently write the cursor directly to use the
helper or set _lastCursor so _updateCursorStyle() behavior remains correct.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e215b3 and 680aee2.

📒 Files selected for processing (2)
  • src/lib/litegraph/src/LGraphCanvas.ts
  • src/lib/litegraph/src/cursorCache.test.ts

Add a _lastCursor field to LGraphCanvas._updateCursorStyle() that
tracks the last cursor value written to the DOM. Only writes
canvas.style.cursor when the value has actually changed.

Eliminates ~347 redundant style mutations per profiling session that
were dirtying Firefox's style tree and contributing to the cascading
style recalculation freeze.

Includes unit test validating the caching behavior.

Amp-Thread-ID: https://ampcode.com/threads/T-019c8ed0-59ad-720b-bc4f-6f52dc452844
@christian-byrne christian-byrne merged commit bcc4706 into main Mar 4, 2026
32 checks passed
@christian-byrne christian-byrne deleted the perf/fix-cursor-cache branch March 4, 2026 22:06
Myestery pushed a commit that referenced this pull request Mar 5, 2026
## Summary

Cache `canvas.style.cursor` to avoid redundant DOM writes that dirty
Firefox's style tree.

## Changes

- **What**: Add `_lastCursor` field to
`LGraphCanvas._updateCursorStyle()` — only writes `canvas.style.cursor`
when the value changes. Eliminates ~347 redundant style mutations per
profiling session.

## Review Focus

- The fix is 2 lines (cache field + comparison). The unit test validates
the caching pattern without requiring full LGraphCanvas instantiation.
- This is one of several contributors to Firefox's cascading style
recalculation freeze. Each `canvas.style.cursor` write dirties the style
tree, which is flushed during the next paint in the canvas render loop.

## Stack

2 of 4 in Firefox perf fix stack. Depends on #9170.

<!-- Fixes #ISSUE_NUMBER -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9171-fix-cache-canvas-cursor-style-to-avoid-redundant-DOM-writes-3116d73d36508139827fe1d644fa1bd0)
by [Unito](https://www.unito.io)
@christian-byrne christian-byrne added core/1.40 Backport PRs for core 1.40 needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch labels Mar 8, 2026
github-actions bot pushed a commit that referenced this pull request Mar 8, 2026
## Summary

Cache `canvas.style.cursor` to avoid redundant DOM writes that dirty
Firefox's style tree.

## Changes

- **What**: Add `_lastCursor` field to
`LGraphCanvas._updateCursorStyle()` — only writes `canvas.style.cursor`
when the value changes. Eliminates ~347 redundant style mutations per
profiling session.

## Review Focus

- The fix is 2 lines (cache field + comparison). The unit test validates
the caching pattern without requiring full LGraphCanvas instantiation.
- This is one of several contributors to Firefox's cascading style
recalculation freeze. Each `canvas.style.cursor` write dirties the style
tree, which is flushed during the next paint in the canvas render loop.

## Stack

2 of 4 in Firefox perf fix stack. Depends on #9170.

<!-- Fixes #ISSUE_NUMBER -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9171-fix-cache-canvas-cursor-style-to-avoid-redundant-DOM-writes-3116d73d36508139827fe1d644fa1bd0)
by [Unito](https://www.unito.io)
@comfy-pr-bot
Copy link
Member

@christian-byrne Successfully backported to #9604

@github-actions github-actions bot removed the needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch label Mar 8, 2026
christian-byrne added a commit that referenced this pull request Mar 8, 2026
…t DOM writes (#9604)

Backport of #9171 to `core/1.40`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9604-backport-core-1-40-fix-cache-canvas-cursor-style-to-avoid-redundant-DOM-writes-31d6d73d36508107ad71fc0ced9541e7)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core/1.40 Backport PRs for core 1.40 perf:speed size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants