Skip to content

perf: draw nodes as boxes on a renderer-owned canvas when zoomed out - #15031

Open
benjcooley wants to merge 10 commits into
benjcooley/vue-nodes-simple-keepalivefrom
benjcooley/vue-nodes-lod-boxes
Open

perf: draw nodes as boxes on a renderer-owned canvas when zoomed out#15031
benjcooley wants to merge 10 commits into
benjcooley/vue-nodes-simple-keepalivefrom
benjcooley/vue-nodes-lod-boxes

Conversation

@benjcooley

@benjcooley benjcooley commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Below the readable-text zoom threshold, Nodes 2.0 replaces ordinary Vue node DOM with renderer-owned canvas boxes, avoiding mass DOM activation during zoom-out.

Changes

  • What: Draw node bodies, titles, slots, and widgets from canonical graph geometry and data.
  • KeepAlive integration: Switch perf: retain offscreen Vue nodes with KeepAlive #15405 attached nodes to safety-pinned or explicitly protected nodes while in LOD; full node components return as the same instances above the threshold.
  • Interaction: Let LiteGraph select, drag, and resize visible boxes. Simplified slot and widget marks are visual only; detailed DOM hit targets remain disabled.
  • Reliability: Grow the canonical spatial index for workflows outside its initial bounds, fail open for invalid geometry, validate every canvas colour source, re-arm slot measurement after remount, redraw legacy widgets on reactivation, and keep active coachmark targets in the detailed renderer.
  • Setting: Expose the existing LiteGraph.Canvas.MinFontSizeForLOD setting to Vue Nodes; 0 disables LOD.
  • Architecture: ADR 0016 records the viewport-retention and LOD ownership boundary and rejected alternatives.

Review Focus

This is one LOD layer stacked directly on #15405. GraphCanvas derives the attached ID set and plain box data; threshold policy and drawing remain separate modules. Graph membership, geometry, serialization, and node sizes are unchanged.

The overlay is idle unless camera, layout, geometry, theme, DPR, panel size, or node content changes. Camera movement queries only visible IDs and reuses cached box, slot, and widget objects until their source versions change.

Validation

  • 83 focused stacked unit tests passed before the latest compatibility additions; 23 directly related tests pass on the current head.
  • The five renderer review regressions failed test-only in CI run 32196889262 before their implementation.
  • The legacy-widget regression failed test-only in CI run 32213804243 before its implementation; the current full unit run then passed all 16,354 tests.
  • The current-main onboarding remount regression passes against a local production cloud build.
  • Typecheck, production cloud build, lint, formatting, layer audit, and knip pass locally; GitHub checks are running on the rebased stack.

@benjcooley
benjcooley requested a review from a team as a code owner August 11, 2026 03:33
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 11, 2026
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: ASSERTIVE

Plan: Pro Plus

Run ID: 7fd27c63-5a39-44ae-a9ee-d53f05f0eab0

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

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.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
Posted by the CLA Assistant Lite bot.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/19/2026, 05:20:21 PM UTC

Links

🎭 Playwright: ✅ 1831 passed, 0 failed · 4 flaky

📊 Browser Reports
  • chromium: View Report (✅ 1810 / ❌ 0 / ⚠️ 4 / ⏭️ 5)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 18 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

📦 Bundle: 8.87 MB gzip

Details

Summary

  • Raw size: 37.4 MB
  • Gzip: 8.87 MB
  • Brotli: 6.2 MB
  • Bundles: 438 current • 438 added
    Baseline artifact not found; showing current bundle sizes only.

Category Glance
Vendor & Third-Party 16.8 MB · Other 14.2 MB · Data & Services 3.53 MB · Graph Workspace 1.39 MB · Panels & Settings 566 kB · Utilities & Hooks 549 kB · + 5 more

App Entry Points — 3.71 kB

Main entry bundles and manifests

File Size Gzip Brotli
assets/index-CzE0s-lp.js (new) 3.71 kB 1.86 kB 1.59 kB

Status: 1 added

Graph Workspace — 1.39 MB

Graph editor runtime, canvas, workflow orchestration

File Size Gzip Brotli
assets/GraphView-D8jMMR61.js (new) 1.38 MB 304 kB 228 kB
assets/WidgetCompositor-CM4dB6OA.js (new) 8.17 kB 2.76 kB 2.47 kB
assets/workflow-B3xkz5Kx.js (new) 1.01 kB 508 B 420 B

Status: 3 added

Views & Navigation — 124 kB

Top-level views, pages, and routed surfaces

File Size Gzip Brotli
assets/CloudSurveyView-DMruQVid.js (new) 25 kB 6.24 kB 5.51 kB
assets/CloudLayoutView-Yfv9vUBL.js (new) 21.8 kB 6.57 kB 5.73 kB
assets/OAuthConsentView-DhZODinp.js (new) 15.5 kB 4.26 kB 3.71 kB
assets/UserCheckView-C16K1fZW.js (new) 8.75 kB 2.19 kB 1.9 kB
assets/CloudLoginView-BjKiMeW6.js (new) 8.74 kB 2.56 kB 2.26 kB
assets/useCloudAuthPage-B9ccbXIT.js (new) 7.08 kB 2.52 kB 2.21 kB
assets/CloudSignupView-BhOjMkfg.js (new) 6.96 kB 2.28 kB 2 kB
assets/WidgetTextPreview-CUtkJ0DL.js (new) 6.07 kB 2.13 kB 1.89 kB
assets/CloudSubscriptionRedirectView-phARB5iy.js (new) 6.05 kB 2.25 kB 1.96 kB
assets/UserSelectView-BdctkXbi.js (new) 5.49 kB 1.96 kB 1.72 kB
assets/CloudForgotPasswordView-D8tF9QpO.js (new) 4.97 kB 1.73 kB 1.49 kB
assets/CloudAuthTimeoutView-BaMrrywH.js (new) 4.43 kB 1.54 kB 1.33 kB
assets/OAuthLayoutView--cVMJH5J.js (new) 1.31 kB 701 B 586 B
assets/CloudSorryContactSupportView-BIxhfxbl.js (new) 1.14 kB 579 B 501 B
assets/video-split-screen-CNFWB03A.js (new) 595 B 362 B 299 B
assets/layout-DXIsFXvh.js (new) 403 B 251 B 205 B
assets/WidgetTextPreview-CNhON6lB.js (new) 131 B 100 B 90 B

Status: 17 added

Panels & Settings — 566 kB

Configuration panels, inspectors, and settings screens

File Size Gzip Brotli
assets/KeybindingPanel-DyavSh3j.js (new) 49.4 kB 9.94 kB 8.8 kB
assets/settings-Du8MHruG.js (new) 39.6 kB 9.66 kB 7.93 kB
assets/settings-mkYpqm8E.js (new) 35.2 kB 8.6 kB 7.24 kB
assets/SecretsPanel-Dve6GqbU.js (new) 33.7 kB 7.87 kB 6.89 kB
assets/settings-C7eLoO4D.js (new) 33.4 kB 8.43 kB 6.89 kB
assets/settings-l9qo4SWq.js (new) 32.9 kB 8.46 kB 7.02 kB
assets/settings-D401de9y.js (new) 31.3 kB 8.71 kB 7.3 kB
assets/settings-h_rkpPt_.js (new) 30.7 kB 8.34 kB 7.28 kB
assets/settings-DYxqUlrV.js (new) 29.5 kB 8.01 kB 6.86 kB
assets/settings-CZVBM34C.js (new) 29.5 kB 8.25 kB 7.17 kB
assets/settings-DFOMjiGL.js (new) 29.4 kB 8.14 kB 7.15 kB
assets/settings-BG4gNbcb.js (new) 28.6 kB 7.93 kB 6.86 kB
assets/settings-x8-cO3Ea.js (new) 28.5 kB 8.38 kB 6.96 kB
assets/settings-BVHHvTsA.js (new) 27.5 kB 7.82 kB 6.5 kB
assets/settings-DCXleDrM.js (new) 25.1 kB 8.14 kB 6.55 kB
assets/settings-C_Ly-sWO.js (new) 24.5 kB 7.96 kB 6.2 kB
assets/CreditsPanel-DMOCoErV.js (new) 11.5 kB 3.21 kB 2.81 kB
assets/AboutPanel-ClayWqm0.js (new) 11.2 kB 3.03 kB 2.72 kB
assets/ExtensionPanel-Ce6Ylc9n.js (new) 9.19 kB 2.51 kB 2.22 kB
assets/settings-DPHAAZkV.js (new) 7.15 kB 1.89 kB 1.59 kB
assets/ServerConfigPanel-BpE5ZSsV.js (new) 6.09 kB 1.94 kB 1.73 kB
assets/UserPanel-CucGza0L.js (new) 5.73 kB 1.79 kB 1.55 kB
assets/refreshRemoteConfig-rhzshTLj.js (new) 4.24 kB 1.51 kB 1.34 kB
assets/remoteConfig-WIk1OS4i.js (new) 1.51 kB 698 B 584 B
assets/cloudRemoteConfig-DD2grRDE.js (new) 951 B 512 B 422 B
assets/refreshRemoteConfig-IpsQOKy-.js (new) 110 B 89 B 88 B

Status: 26 added

User & Accounts — 27.5 kB

Authentication, profile, and account management bundles

File Size Gzip Brotli
assets/SignUpForm-BLQoJMsK.js (new) 13.3 kB 4.53 kB 3.94 kB
assets/PasswordFields-CNalw1Aa.js (new) 4.93 kB 1.46 kB 1.28 kB
assets/auth-Cm-oUZcV.js (new) 3.48 kB 1.21 kB 1.01 kB
assets/UpdatePasswordContent-CkYF1hkY.js (new) 1.85 kB 846 B 731 B
assets/WorkspaceProfilePic-Cq8zj0ZT.js (new) 1.6 kB 831 B 752 B
assets/oauthState-DmjrcfWa.js (new) 1.17 kB 478 B 406 B
assets/authClasses-CGLCAoTJ.js (new) 679 B 422 B 334 B
assets/profiler-DTaQ-5S5.js (new) 178 B 141 B 128 B
assets/authStore-DPaINGLI.js (new) 128 B 107 B 101 B
assets/workspaceAuthStore-DieISK5H.js (new) 108 B 99 B 111 B
assets/auth-DhhMskJv.js (new) 105 B 96 B 85 B

Status: 11 added

Editors & Dialogs — 125 kB

Modals, dialogs, drawers, and in-app editors

File Size Gzip Brotli
assets/ComfyHubPublishDialog-BxrJBFxc.js (new) 90.1 kB 19.3 kB 16.5 kB
assets/useShareDialog-CPEjOhFL.js (new) 23.9 kB 5.7 kB 5.04 kB
assets/feedbackDialog-1h2BBPA1.js (new) 4.45 kB 1.87 kB 1.59 kB
assets/useRangeEditor-KpxAMS6n.js (new) 3.29 kB 1.14 kB 1.04 kB
assets/SubscriptionInactiveMemberDialog-DPV576_B.js (new) 2.48 kB 1 kB 854 B
assets/useLayerEditor-ZvTk5Tbd.js (new) 1.01 kB 490 B 406 B
assets/ComfyHubPublishDialog-x1t-aPWC.js (new) 143 B 105 B 90 B
assets/useSubscriptionDialog-CqDhl5Qr.js (new) 108 B 102 B 94 B

Status: 8 added

UI Components — 67.1 kB

Reusable component library chunks

File Size Gzip Brotli
assets/ComfyQueueButton-n9UTRaU-.js (new) 14.6 kB 3.97 kB 3.52 kB
assets/useTerminalTabs-Dtm9NQM2.js (new) 11.8 kB 3.69 kB 3.28 kB
assets/InviteMembersForm-BfifkiyO.js (new) 8.23 kB 2.74 kB 2.44 kB
assets/TopbarBadge-BiYfsATf.js (new) 7.65 kB 1.83 kB 1.62 kB
assets/ScrubableNumberInput-Bt9NKcKd.js (new) 6.49 kB 2.16 kB 1.91 kB
assets/WidgetInputNumberInput-D10itclY.js (new) 5.83 kB 2.08 kB 1.85 kB
assets/Button-OKQxEw6S.js (new) 4.64 kB 1.62 kB 1.43 kB
assets/SubscribeButton-B-sloKpH.js (new) 2.15 kB 971 B 851 B
assets/WidgetButton-CDJj2IHc.js (new) 1.93 kB 889 B 780 B
assets/Input-_LO9F0FD.js (new) 1.76 kB 875 B 760 B
assets/UserAvatar-DfF0iPQF.js (new) 1.24 kB 641 B 551 B
assets/cloudFeedbackTopbarButton-DtBCzsuW.js (new) 705 B 422 B 373 B
assets/ComfyQueueButton-BSjsLb-W.js (new) 128 B 99 B 89 B
assets/toggle-group-By3xvTWH.js (new) 40 B 60 B 44 B

Status: 14 added

Data & Services — 3.53 MB

Stores, services, APIs, and repositories

File Size Gzip Brotli
assets/settingStore-fKa4Bj22.js (new) 3.17 MB 743 kB 559 kB
assets/api-Bcs8juXT.js (new) 186 kB 39.8 kB 33.4 kB
assets/load3dService-BNY6A4AC.js (new) 132 kB 29.3 kB 24.7 kB
assets/workflowShareService-VkH2jV-S.js (new) 16.5 kB 4.91 kB 4.35 kB
assets/keybindingService-BCzu417a.js (new) 6.89 kB 1.73 kB 1.5 kB
assets/releaseStore-iPmTfo4B.js (new) 6.72 kB 2.03 kB 1.77 kB
assets/dialogStore-DVbAwd0N.js (new) 5.35 kB 1.64 kB 1.44 kB
assets/systemStatsStore-__-KlmdP.js (new) 4.93 kB 1.74 kB 1.47 kB
assets/userStore-BZ6jkHGs.js (new) 2.38 kB 900 B 798 B
assets/serverConfigStore-BEGF58Jh.js (new) 2.3 kB 778 B 680 B
assets/audioService-ucbcV8vI.js (new) 1.71 kB 832 B 733 B
assets/toastStore-jHx-CgVK.js (new) 841 B 396 B 349 B
assets/dialogService-CLqJfxfJ.js (new) 98 B 97 B 85 B
assets/releaseStore-B2IXnm7H.js (new) 95 B 86 B 88 B
assets/settingStore-BtaSsPeS.js (new) 95 B 86 B 84 B
assets/assetsStore-u2zfhvJq.js (new) 94 B 92 B 86 B
assets/api-UACfOUag.js (new) 62 B 74 B 66 B

Status: 17 added

Utilities & Hooks — 549 kB

Helpers, composables, and utility bundles

File Size Gzip Brotli
assets/useConflictDetection-f5kWnBEm.js (new) 236 kB 53.1 kB 43.2 kB
assets/useLayerEditorSession-ol7pdmAw.js (new) 158 kB 40.8 kB 34.3 kB
assets/useLoad3d-BqvQYyH-.js (new) 25.8 kB 5.8 kB 5.14 kB
assets/useLoad3dViewer-JGqJl02O.js (new) 21.2 kB 4.99 kB 4.37 kB
assets/useImageQuiet-2bHPWAN6.js (new) 19.1 kB 6.12 kB 5.27 kB
assets/formatUtil-CNG-Br4i.js (new) 16.2 kB 5.46 kB 4.81 kB
assets/useImageCrop-0r7Xs5kp.js (new) 14.9 kB 3.42 kB 2.98 kB
assets/useDowngradeToPersonal-BgxsAi7V.js (new) 10.9 kB 2.74 kB 2.36 kB
assets/useFeatureFlags-Ds03bQzR.js (new) 7.32 kB 2.06 kB 1.76 kB
assets/curveUtils-CMFtfKRr.js (new) 3.79 kB 1.26 kB 1.11 kB
assets/useTransformState-Yvskdhev.js (new) 3.54 kB 1.55 kB 1.28 kB
assets/useCompositorLayers-cIUK36V2.js (new) 2.94 kB 903 B 801 B
assets/useSurveyEligibility-ChuSEsDX.js (new) 2.89 kB 1.11 kB 919 B
assets/useExternalLink-bEHH0pQO.js (new) 2.85 kB 1.07 kB 923 B
assets/assetPreviewUtil-J0zE8PIc.js (new) 2.35 kB 969 B 846 B
assets/useFeatureUsageTracker-tQ9scF5C.js (new) 2.07 kB 912 B 771 B
assets/downloadUtil-CxnVuOZt.js (new) 2.04 kB 908 B 728 B
assets/useTypeformEmbed-DCSeFvhl.js (new) 2.02 kB 1.03 kB 848 B
assets/useUpstreamValue-C7c2otc2.js (new) 1.99 kB 761 B 676 B
assets/useWorkspaceTierLabel-Dd-O9xs1.js (new) 1.93 kB 814 B 693 B
assets/markdownRendererUtil-llRXLHTo.js (new) 1.53 kB 799 B 692 B
assets/useErrorHandling-CDhZEkTK.js (new) 1.49 kB 614 B 521 B
assets/hdrFormatUtil-CnRXb_Cj.js (new) 1.03 kB 485 B 390 B
assets/histogramUtil-nwm_kqcs.js (new) 921 B 539 B 457 B
assets/useModalLiftedZIndex-B9Cqq7lO.js (new) 908 B 555 B 465 B
assets/subscriptionCheckoutUtil-CkhZacsp.js (new) 877 B 525 B 435 B
assets/useTextFileContent-DzBkD12b.js (new) 841 B 428 B 374 B
assets/useClickDragGuard-C9dEHod_.js (new) 773 B 372 B 333 B
assets/useSessionCookie-BiE_G802.js (new) 652 B 337 B 313 B
assets/_plugin-vue_export-helper-DEKQMRQ4.js (new) 365 B 255 B 216 B
assets/envUtil-D9umgS8T.js (new) 333 B 213 B 178 B
assets/useLoad3d-Jc49-dIR.js (new) 311 B 165 B 148 B
assets/SkeletonUtils-uc7PBd52.js (new) 133 B 111 B 108 B
assets/useSessionCookie-DUULjuVC.js (new) 101 B 86 B 80 B
assets/useFeatureFlags-g3QAGVlO.js (new) 98 B 85 B 86 B
assets/useLoad3dViewer-DIRdT2S9.js (new) 98 B 85 B 85 B
assets/useCurrentUser-DC2n1fqW.js (new) 94 B 95 B 80 B

Status: 37 added

Vendor & Third-Party — 16.8 MB

External libraries and shared vendor chunks

File Size Gzip Brotli
assets/vendor-three-BNBNm62f.js (new) 7.09 MB 2.18 MB 1.02 MB
assets/vendor-other-CIG9dJHN.js (new) 2.23 MB 483 kB 380 kB
assets/vendor-primevue-6EECEpXQ.js (new) 1.69 MB 306 kB 184 kB
assets/vendor-firebase-DZ9gHliD.js (new) 1.15 MB 233 kB 186 kB
assets/vendor-tiptap-CRth4-B-.js (new) 747 kB 184 kB 148 kB
assets/vendor-reka-ui-ivfAsB1n.js (new) 563 kB 102 kB 77.4 kB
assets/vendor-ag-psd-iN-PK2Jv.js (new) 545 kB 113 kB 91.2 kB
assets/vendor-datadog-CR3rU1mS.js (new) 528 kB 126 kB 102 kB
assets/vendor-chart-hciqepb7.js (new) 412 kB 100 kB 83 kB
assets/vendor-xterm-tvYwlZkL.js (new) 380 kB 75.9 kB 61.2 kB
assets/vendor-vue-core-BA37GaAP.js (new) 349 kB 87.4 kB 73.5 kB
assets/vendor-yjs-CbNkqTUJ.js (new) 278 kB 60.9 kB 50.7 kB
assets/vendor-sentry-CwHvS6Tl.js (new) 239 kB 56.7 kB 47.5 kB
assets/vendor-vueuse-Czwo5f2i.js (new) 151 kB 37.8 kB 32.4 kB
assets/vendor-i18n-DceAZerK.js (new) 128 kB 29 kB 24.8 kB
assets/vendor-markdown-DQZfBP8x.js (new) 121 kB 30.3 kB 26.6 kB
assets/vendor-axios-I_gyl9iu.js (new) 119 kB 32 kB 27.4 kB
assets/vendor-zod-DMTwNxpJ.js (new) 106 kB 18.9 kB 16.1 kB

Status: 18 added

Other — 14.2 MB

Bundles that do not match a named category

File Size Gzip Brotli
assets/nodeDefs-DJncJqM3.js (new) 761 kB 127 kB 86.3 kB
assets/nodeDefs-CpkVJBoz.js (new) 700 kB 115 kB 80.1 kB
assets/nodeDefs-B6RvNLh0.js (new) 693 kB 118 kB 82.5 kB
assets/nodeDefs-BTcb6VPF.js (new) 636 kB 114 kB 79.4 kB
assets/nodeDefs-Cqvlii7j.js (new) 633 kB 109 kB 77.3 kB
assets/nodeDefs-ctNGELIv.js (new) 612 kB 112 kB 78.9 kB
assets/nodeDefs-COuQXeRc.js (new) 609 kB 111 kB 80.1 kB
assets/nodeDefs-cJbQgzfa.js (new) 602 kB 110 kB 80.5 kB
assets/nodeDefs-COqBgFtH.js (new) 600 kB 108 kB 78 kB
assets/nodeDefs-CyZzIjqk.js (new) 596 kB 106 kB 77.7 kB
assets/nodeDefs-CqlxyYBJ.js (new) 593 kB 106 kB 76.9 kB
assets/nodeDefs-CsUuOUpp.js (new) 567 kB 98.8 kB 72.3 kB
assets/nodeDefs-CyuI0uEL.js (new) 550 kB 110 kB 76.8 kB
assets/nodeDefs-CU3YafMu.js (new) 545 kB 108 kB 75.3 kB
assets/main-Ub70wlYB.js (new) 323 kB 79.8 kB 61.9 kB
assets/main-DrCz2UPc.js (new) 289 kB 72.3 kB 57.5 kB
assets/main-DjXGc5-u.js (new) 274 kB 71.6 kB 56.6 kB
assets/main-D2VI9Zum.js (new) 265 kB 70.9 kB 55.7 kB
assets/main-D0DYIY6J.js (new) 256 kB 68.6 kB 54.9 kB
assets/main-C4mQZFtQ.js (new) 241 kB 69.5 kB 57.4 kB
assets/main-DCNYc_Q8.js (new) 239 kB 68.4 kB 54.6 kB
assets/main-EfuGA8is.js (new) 233 kB 67.7 kB 55.8 kB
assets/main-QXmcpGfd.js (new) 230 kB 67.9 kB 56.3 kB
assets/main-jwnbHe2t.js (new) 228 kB 66.8 kB 55.6 kB
assets/main-BClbBnzH.js (new) 225 kB 65.7 kB 55.1 kB
assets/main-C2VbHNI1.js (new) 207 kB 60.1 kB 50.4 kB
assets/main-B3N4wc59.js (new) 203 kB 66.7 kB 52.7 kB
assets/main-pHRK9r-1.js (new) 200 kB 66.3 kB 52.4 kB
assets/core-CQKKGhL6.js (new) 114 kB 29.7 kB 25.1 kB
assets/OBJLoader2WorkerModule-DTMpvldF.js (new) 109 kB 27.1 kB 21.9 kB
assets/WidgetSelect-Q3u0eX-j.js (new) 88.8 kB 20.1 kB 17.2 kB
assets/SubscriptionPanelContentWorkspace-Cryq-odV.js (new) 81.2 kB 16.1 kB 13.9 kB
assets/Load3D-CSUPdS8b.js (new) 73.3 kB 12.1 kB 10.3 kB
assets/WidgetVideoEdit-bsU2lIPf.js (new) 67.5 kB 15.7 kB 13.9 kB
assets/SubscriptionTransitionPreviewWorkspace-DGYgZ1lf.js (new) 66.6 kB 13.5 kB 11.7 kB
assets/WorkspaceSettingsPanelContent-D1GwJr-i.js (new) 58.2 kB 12.4 kB 10.8 kB
assets/Preview3d-CBaF1Hc6.js (new) 50.9 kB 8.32 kB 7.24 kB
assets/main-CqHDnb2b.js (new) 45.4 kB 13.2 kB 11.5 kB
assets/SubscriptionRequiredDialogContentUnified-BLSlzx3Q.js (new) 42.7 kB 9.39 kB 8.19 kB
assets/LayerEditorContent-BXnwblrs.js (new) 42.5 kB 9.62 kB 8.41 kB
assets/nodeDefs-C1w7DDtA.js (new) 39.2 kB 10.1 kB 8.75 kB
assets/WidgetBoundingBoxes-Dd0JHUU5.js (new) 33.7 kB 9.16 kB 8.13 kB
assets/WidgetPainter-DYDTQmtt.js (new) 32.6 kB 7.88 kB 6.98 kB
assets/Load3dViewerContent-COTUP7S_.js (new) 30.8 kB 6.28 kB 5.45 kB
assets/HdrViewerContent-CxB9iAUS.js (new) 29.8 kB 8.25 kB 7.27 kB
assets/ColorPicker-Cm-eTnNO.js (new) 29.2 kB 7.59 kB 6.67 kB
assets/SubscriptionRequiredDialogContent-Cm0xU6lv.js (new) 26.9 kB 6.35 kB 5.61 kB
assets/SubscriptionRequiredDialogContentWorkspace-CjGTeZeU.js (new) 25.1 kB 5.81 kB 5.12 kB
assets/CreditsTile-CUIMGglq.js (new) 24.9 kB 6.65 kB 5.84 kB
assets/initHostTelemetry-C3rCdmQe.js (new) 24.5 kB 5.82 kB 4.83 kB
assets/load3d-DT1_SqBJ.js (new) 22.2 kB 5.41 kB 4.68 kB
assets/CurrentUserPopoverWorkspace-CEsEnrNh.js (new) 21.9 kB 4.99 kB 4.44 kB
assets/SignInContent-DEpkEbRs.js (new) 20.6 kB 5.18 kB 4.53 kB
assets/commands-BKN6fRVa.js (new) 18.6 kB 4 kB 3.09 kB
assets/DialogHeader-BuZ1oQfx.js (new) 17.5 kB 5.28 kB 4.6 kB
assets/commands-D2b4SpmW.js (new) 17.3 kB 3.69 kB 2.85 kB
assets/commands-gx4P-ybS.js (new) 17.3 kB 3.76 kB 2.96 kB
assets/commands-DrmQsqDP.js (new) 17.3 kB 3.59 kB 2.82 kB
assets/commands-lpkD8Jr0.js (new) 16.7 kB 3.79 kB 2.98 kB
assets/i18n-Bn2I8KUh.js (new) 16.7 kB 4.55 kB 3.82 kB
assets/WidgetRecordAudio-DLNDSeaR.js (new) 16.6 kB 4.6 kB 4.1 kB
assets/commands-CGE1NEkE.js (new) 16.4 kB 3.54 kB 2.92 kB
assets/commands-Bym53ZK-.js (new) 15.9 kB 3.5 kB 2.87 kB
assets/commands-D_uHBcHD.js (new) 15.9 kB 3.42 kB 2.78 kB
assets/commands-DYFW3wAz.js (new) 15.8 kB 3.39 kB 2.78 kB
assets/commands-XyP6YuDv.js (new) 15.7 kB 3.65 kB 2.84 kB
assets/commands-B3vhE5a3.js (new) 15.5 kB 3.25 kB 2.68 kB
assets/commands-DM9rmOop.js (new) 15.4 kB 3.18 kB 2.69 kB
assets/commands-4qWg2NAn.js (new) 15 kB 3.59 kB 2.71 kB
assets/commands-9uJVV2DI.js (new) 14.8 kB 3.53 kB 2.64 kB
assets/WidgetInputNumber-lUIlJL_w.js (new) 13.9 kB 3.63 kB 3.21 kB
assets/WidgetRange-C3UBrxbm.js (new) 13.7 kB 3.55 kB 3.13 kB
assets/WaveAudioPlayer-AwUITQ6H.js (new) 12.8 kB 3.46 kB 3.03 kB
assets/WidgetCurve-4UwVKpqz.js (new) 11.2 kB 3.47 kB 3.14 kB
assets/SelectValue-fnnzefUA.js (new) 10.6 kB 2.61 kB 2.32 kB
assets/AudioPreviewPlayer-C03EfRFQ.js (new) 10.6 kB 3.05 kB 2.72 kB
assets/meshy-C5eznzGL.js (new) 10.5 kB 4.72 kB 4.15 kB
assets/TeamWorkspacesDialogContent-B_YvchLb.js (new) 10.3 kB 2.97 kB 2.63 kB
assets/onboardingCloudRoutes-D6mx4MsW.js (new) 9.49 kB 2.85 kB 2.44 kB
assets/ideogram-CPAcI9VN.js (new) 9.21 kB 4.28 kB 3.67 kB
assets/types-Bk23msdr.js (new) 9.16 kB 2.9 kB 2.37 kB
assets/Load3DConfiguration-DSvubifr.js (new) 8.91 kB 2.61 kB 2.31 kB
assets/comfy-logo-BxADqrWH.js (new) 8.6 kB 3.84 kB 3.24 kB
assets/WidgetImageCrop-CU4YjgGF.js (new) 8.49 kB 2.65 kB 2.34 kB
assets/SetMemberCreditLimitDialogContent-D4-CQfuy.js (new) 8.47 kB 2.34 kB 2.06 kB
assets/nodeTemplates-BiP6-dbt.js (new) 8.32 kB 2.85 kB 2.5 kB
assets/WidgetImageCompare-BtuwHU2Y.js (new) 8.13 kB 2.3 kB 2.01 kB
assets/NightlySurveyController-DIpxT388.js (new) 7.5 kB 2.56 kB 2.25 kB
assets/Popover-DmA3BbAn.js (new) 7.48 kB 2.69 kB 2.36 kB
assets/CloudRunButtonWrapper-yljF1Rja.js (new) 7.29 kB 2.3 kB 2.02 kB
assets/gemini-DxvHIIpm.js (new) 6.76 kB 1.18 kB 986 B
assets/commands-C9_85oGd.js (new) 6.53 kB 1.54 kB 1.31 kB
assets/WidgetWithControl-CDpCaxEi.js (new) 6.51 kB 2.67 kB 2.36 kB
assets/missingModelMetadata-BH4NqpTD.js (new) 6.45 kB 2.2 kB 1.93 kB
assets/AnimationControls-piaxnmd-.js (new) 6.1 kB 1.86 kB 1.64 kB
assets/CancelSubscriptionDialogContent-Bnlsq7VT.js (new) 5.97 kB 1.98 kB 1.75 kB
assets/main-CEUpmmm4.js (new) 5.92 kB 1.91 kB 1.59 kB
assets/load3dPreviewExtensions-CrrUhoaB.js (new) 5.88 kB 1.81 kB 1.6 kB
assets/DowngradeRemoveMembersDialogContent-BKbl_KGu.js (new) 5.58 kB 1.89 kB 1.65 kB
assets/minimax-B3NM3ir2.js (new) 5.44 kB 2.48 kB 2.15 kB
assets/launchCancellationFlow-C9rhEiXl.js (new) 5.18 kB 1.78 kB 1.55 kB
assets/CreateWorkspaceDialogContent-B8DBRYkj.js (new) 5.12 kB 1.79 kB 1.55 kB
assets/CloudNotificationContent-DJT7or61.js (new) 5.05 kB 1.76 kB 1.51 kB
assets/ChangeMemberRoleDialogContent-BNJd1sEs.js (new) 4.97 kB 1.64 kB 1.42 kB
assets/InviteMemberDialogContent-CPPhgKDk.js (new) 4.96 kB 1.64 kB 1.44 kB
assets/EditWorkspaceDialogContent-CKhj3BUr.js (new) 4.93 kB 1.76 kB 1.53 kB
assets/PaletteSwatchRow-CJ-Ghq72.js (new) 4.86 kB 1.86 kB 1.65 kB
assets/WidgetTextarea-Dh8bTOWy.js (new) 4.83 kB 1.88 kB 1.64 kB
assets/grain-DpjNtV4-.js (new) 4.83 kB 1.32 kB 975 B
assets/saveMesh-B7VjB0jV.js (new) 4.76 kB 1.52 kB 1.34 kB
assets/WorkspacePanelContent-C3otswaO.js (new) 4.74 kB 1.63 kB 1.43 kB
assets/brightness-contrast-D4ZrSTJK.js (new) 4.61 kB 1.56 kB 1.39 kB
assets/ValueControlPopover-BtsGBiAw.js (new) 4.49 kB 1.55 kB 1.38 kB
assets/ToggleGroupItem-xn3wG_Kg.js (new) 4.14 kB 1.41 kB 1.24 kB
assets/ApiNodesSignInContent-Dv19bJAY.js (new) 4.08 kB 1.32 kB 1.16 kB
assets/reportError-gkwW-D2R.js (new) 4.02 kB 1.72 kB 1.46 kB
assets/Slider-DGiPEB6t.js (new) 3.91 kB 1.43 kB 1.24 kB
assets/DeleteWorkspaceDialogContent-Dltr8Inc.js (new) 3.84 kB 1.44 kB 1.23 kB
assets/WidgetBoundingBox-5ChaIh3e.js (new) 3.76 kB 1.03 kB 900 B
assets/RemoveMemberDialogContent-DatRsgcw.js (new) 3.76 kB 1.39 kB 1.2 kB
assets/WidgetGalleria-mYYvsMtB.js (new) 3.75 kB 1.45 kB 1.29 kB
assets/RevokeInviteDialogContent-Dkc0SfkX.js (new) 3.67 kB 1.39 kB 1.21 kB
assets/LeaveWorkspaceDialogContent-DaV9kMV4.js (new) 3.67 kB 1.39 kB 1.19 kB
assets/tencent-DcxX2XL4.js (new) 3.63 kB 1.69 kB 1.49 kB
assets/WidgetToggleSwitch-CFBaWD5s.js (new) 3.56 kB 1.3 kB 1.15 kB
assets/hitpaw-C0NOpgD2.js (new) 3.51 kB 1.75 kB 1.5 kB
assets/InviteMemberUpsellDialogContent-BUjW7tkB.js (new) 3.47 kB 1.24 kB 1.08 kB
assets/sora-CahMvg3l.js (new) 3.46 kB 1.81 kB 1.56 kB
assets/workspaceCheckoutTelemetry-DcqB0IQk.js (new) 3.4 kB 1.52 kB 1.32 kB
assets/GlobalToast-BKussUxK.js (new) 3.25 kB 1.3 kB 1.11 kB
assets/Media3DTop-CTc1XQBC.js (new) 3.21 kB 1.26 kB 1.1 kB
assets/openai-cmoqR7c6.js (new) 3.21 kB 1.55 kB 1.38 kB
assets/get-video-components-Ft-NLDFC.js (new) 3.09 kB 1.37 kB 1.21 kB
assets/pixverse-CHKZYPBx.js (new) 3.08 kB 1.48 kB 1.28 kB
assets/kling-2U9Sap30.js (new) 3.08 kB 1.14 kB 973 B
assets/image-invert-CvSik4TT.js (new) 3.07 kB 1.03 kB 853 B
assets/WidgetMarkdown-CuNQAjKi.js (new) 3.07 kB 1.26 kB 1.1 kB
assets/WidgetInputText-DVQSNz3L.js (new) 3.04 kB 1.27 kB 1.14 kB
assets/MediaVideoTop-C5_s44G_.js (new) 2.96 kB 1.2 kB 1.04 kB
assets/rodin-D99hR298.js (new) 2.93 kB 1.41 kB 1.23 kB
assets/load3dAdvanced-DerGFGsa.js (new) 2.82 kB 1.1 kB 953 B
assets/ErrorPanelSurveyCta-DlVa2acW.js (new) 2.64 kB 1.14 kB 1.01 kB
assets/wan-B-4QUtRI.js (new) 2.62 kB 1.28 kB 1.13 kB
assets/loadExternalScript-Bah6Al85.js (new) 2.59 kB 913 B 744 B
assets/Switch-BbUMssUS.js (new) 2.49 kB 1.09 kB 945 B
assets/image-outpainting-DPutOHdl.js (new) 2.47 kB 1.13 kB 978 B
assets/image-outpaint-CuZDQ-s9.js (new) 2.46 kB 1.12 kB 976 B
assets/SubscribeToRun-GNEIFlPN.js (new) 2.39 kB 1.04 kB 903 B
assets/tripo-BJxtNDyf.js (new) 2.38 kB 1.12 kB 989 B
assets/WidgetLayoutField-mOMC9P_R.js (new) 2.38 kB 1.03 kB 901 B
assets/WidgetChart-DDii0vX0.js (new) 2.36 kB 1 kB 866 B
assets/ltxv-CREe9jI1.js (new) 2.35 kB 1.2 kB 1.05 kB
assets/luma-CKtjQHSe.js (new) 2.32 kB 595 B 505 B
assets/image-inpaint-D-VnZoJS.js (new) 2.29 kB 1.07 kB 919 B
assets/vidu-DouVPJS-.js (new) 2.12 kB 1.02 kB 876 B
assets/rolldown-runtime-xtsTai4I.js (new) 2.07 kB 947 B 814 B
assets/TopBarHeader-BNNFKFky.js (new) 2.01 kB 845 B 732 B
assets/video-inpaint-B0ovAfX_.js (new) 1.99 kB 957 B 823 B
assets/moonvalley-marey-DKF4OIv2.js (new) 1.98 kB 870 B 777 B
assets/image-to-layers-DCdlgpAV.js (new) 1.95 kB 868 B 705 B
assets/MediaImageTop-DVKzPYH1.js (new) 1.95 kB 929 B 798 B
assets/claude-COhIiCXc.js (new) 1.85 kB 1.03 kB 895 B
assets/text-to-audio-DpKEmv6s.js (new) 1.84 kB 860 B 735 B
assets/TypeformEmbed-CV71ZpeI.js (new) 1.83 kB 811 B 707 B
assets/anthropic-BWmduUeu.js (new) 1.79 kB 1 kB 871 B
assets/wavespeed-Cf_Y-WE-.js (new) 1.78 kB 953 B 808 B
assets/MediaTextTop-CmOLjm8L.js (new) 1.77 kB 855 B 725 B
assets/pin-BBhiJ-Ro.js (new) 1.75 kB 981 B 849 B
assets/bria-01tswOT4.js (new) 1.74 kB 863 B 746 B
assets/auto-E0RPASnx.js (new) 1.7 kB 619 B 548 B
assets/video-interpolation-E1ZYZfjz.js (new) 1.7 kB 816 B 702 B
assets/WidgetColorPicker-CuzjI_lW.js (new) 1.69 kB 758 B 670 B
assets/voice-clone-CLECE4e1.js (new) 1.67 kB 878 B 709 B
assets/image-select-object-segmentation-pTwgE7RS.js (new) 1.66 kB 822 B 709 B
assets/Loader-C2HK2cqt.js (new) 1.64 kB 782 B 704 B
assets/WidgetColors-Bv6ImHVe.js (new) 1.63 kB 808 B 709 B
assets/MediaAudioTop-C316mzio.js (new) 1.62 kB 810 B 669 B
assets/veo-CGwt9Auf.js (new) 1.62 kB 843 B 751 B
assets/stability-ai-GsPHcQLg.js (new) 1.61 kB 819 B 709 B
assets/bytedance-BAE74qy_.js (new) 1.61 kB 852 B 745 B
assets/pose-to-image-BvUGgc9H.js (new) 1.58 kB 819 B 689 B
assets/Textarea-BcGUymgY.js (new) 1.56 kB 816 B 714 B
assets/image-collage-e-ttxsAp.js (new) 1.55 kB 613 B 493 B
assets/signInSchema-a9kXR0Zp.js (new) 1.55 kB 554 B 515 B
assets/webviewDetection-G_eepi8c.js (new) 1.52 kB 613 B 548 B
assets/image-to-3d-DZ2fsCrF.js (new) 1.52 kB 764 B 659 B
assets/pose-to-video-C6gVRnB7.js (new) 1.5 kB 785 B 667 B
assets/comfyCredits-QD6D3aQ0.js (new) 1.48 kB 530 B 462 B
assets/widgetPropFilter-C6CiCSHV.js (new) 1.47 kB 670 B 547 B
assets/VideoPlayOverlay-C3wXBTFH.js (new) 1.46 kB 728 B 645 B
assets/image-vectorize-BPJBhZHU.js (new) 1.42 kB 683 B 594 B
assets/reve-D4nsQmOA.js (new) 1.41 kB 736 B 571 B
assets/video-upscale-DHzmQ_zv.js (new) 1.4 kB 698 B 598 B
assets/comfy-c-rvqaaLz6.js (new) 1.4 kB 795 B 689 B
assets/image-edit-D9ce-d34.js (new) 1.34 kB 701 B 609 B
assets/grok-Bn_ZS4mR.js (new) 1.34 kB 794 B 666 B
assets/runway-dTJ-BZlC.js (new) 1.34 kB 748 B 645 B
assets/depth-to-image-CVaRR23Y.js (new) 1.33 kB 718 B 616 B
assets/image-ai-edit-Bmy-5CCv.js (new) 1.33 kB 622 B 531 B
assets/canny-to-image-DcTSZY12.js (new) 1.32 kB 687 B 593 B
assets/video-select-object-segmentation-BXcZZs7A.js (new) 1.31 kB 688 B 570 B
assets/image-depth-DkhlVZog.js (new) 1.28 kB 681 B 590 B
assets/image-to-image-BqSVcceo.js (new) 1.26 kB 638 B 551 B
assets/depth-to-video-i-UPkQlp.js (new) 1.25 kB 682 B 587 B
assets/text-to-3d-CP_26bwF.js (new) 1.24 kB 650 B 565 B
assets/ButtonGroup-DCYapn0W.js (new) 1.24 kB 643 B 563 B
assets/canny-to-video-Cn0VChNR.js (new) 1.24 kB 657 B 564 B
assets/ai-model-C8iGlxMz.js (new) 1.19 kB 575 B 501 B
assets/3d-decomp-RjA0gFmA.js (new) 1.19 kB 597 B 514 B
assets/DialogClose-DVTgm3xI.js (new) 1.18 kB 612 B 553 B
assets/image-to-video-jztf067S.js (new) 1.18 kB 621 B 529 B
assets/mask-cDEa-6-s.js (new) 1.16 kB 500 B 436 B
assets/batch-images-node-zQB_peEw.js (new) 1.13 kB 597 B 508 B
assets/image-canny-B3ZrILNA.js (new) 1.13 kB 604 B 515 B
assets/canny-J_xT5t3B.js (new) 1.11 kB 595 B 514 B
assets/image-batch-DMOK_HMA.js (new) 1.11 kB 591 B 501 B
assets/recraft-DZ2oKkMO.js (new) 1.1 kB 556 B 484 B
assets/image-upscale-nq0-_m-2.js (new) 1.05 kB 558 B 473 B
assets/video-edit-DoAUmDnG.js (new) 1.04 kB 593 B 503 B
assets/MediaOtherTop-C6tuqeqJ.js (new) 1.02 kB 575 B 472 B
assets/extensions-blocks-Dl5rqs4I.js (new) 1.02 kB 543 B 460 B
assets/glow-QcBFWyCA.js (new) 1.02 kB 468 B 402 B
assets/nodeTypes-Bwqk5SXD.js (new) 1.01 kB 447 B 381 B
assets/template-rnD0AK7u.js (new) 993 B 498 B 426 B
assets/video-trim-DqUDHzQc.js (new) 977 B 509 B 437 B
assets/image-remove-background-Cg3Xau6F.js (new) 975 B 525 B 445 B
assets/frames-to-video-CZ7-VxFj.js (new) 955 B 535 B 448 B
assets/file-output-CQ0ZWFnN.js (new) 943 B 545 B 468 B
assets/image-compare-DdB4fbII.js (new) 943 B 537 B 460 B
assets/open-ai-chat-node-BaQlo11G.js (new) 942 B 518 B 440 B
assets/dial-JJKuN71R.js (new) 941 B 474 B 407 B
assets/cloudSessionCookie-BDg6emmB.js (new) 933 B 433 B 379 B
assets/cloudBadges-DphCes5V.js (new) 922 B 518 B 435 B
assets/ComfyOrgHeader-yIsyGUzY.js (new) 906 B 496 B 432 B
assets/image-rotate-BZVAXcdZ.js (new) 899 B 499 B 431 B
assets/magnific-DyoOXzaM.js (new) 894 B 441 B 380 B
assets/image-captioning-DreocsxD.js (new) 891 B 489 B 416 B
assets/lora-loader-CqTfu1TX.js (new) 845 B 518 B 441 B
assets/load-3d-ChaXqnVx.js (new) 844 B 503 B 432 B
assets/save-3d-CYwbkXZ2.js (new) 838 B 499 B 427 B
assets/video-slice-RfomFSXB.js (new) 833 B 452 B 380 B
assets/load3dSerialize-BIPv2l0M.js (new) 832 B 393 B 336 B
assets/video-extract-frame-DpM1yIqF.js (new) 832 B 459 B 382 B
assets/channels-CWzr-AGk.js (new) 808 B 392 B 324 B
assets/text-to-image-CkeH6vgx.js (new) 763 B 468 B 389 B
assets/Load3DAdvanced-CG9CaTF4.js (new) 761 B 423 B 359 B
assets/bfl-D0kEkSSj.js (new) 745 B 454 B 384 B
assets/chromatic-aberration-AddZTK2j.js (new) 740 B 420 B 356 B
assets/image-blur-2EtiuWuI.js (new) 718 B 429 B 360 B
assets/quiver-DVpoQpQ5.js (new) 694 B 430 B 364 B
assets/image-shader-DWifxCrB.js (new) 685 B 398 B 336 B
assets/text-to-video-BecNw9zw.js (new) 685 B 436 B 365 B
assets/devFeatureFlagOverride-D9x6Noj0.js (new) 680 B 427 B 354 B
assets/video-enhance-BQCy6-3e.js (new) 671 B 412 B 344 B
assets/image-sharpen-BSWKHqeL.js (new) 662 B 414 B 351 B
assets/send-CCfAcvOS.js (new) 658 B 410 B 336 B
assets/video-captioning-DEya6ZKv.js (new) 628 B 390 B 329 B
assets/topaz-DRomf3uD.js (new) 618 B 389 B 337 B
assets/node-9_S0T5yn.js (new) 554 B 400 B 345 B
assets/subscriptionCancellationTelemetry-BF-Zq8Rx.js (new) 546 B 333 B 287 B
assets/load-video-CGUIEnct.js (new) 518 B 348 B 296 B
assets/widgetTypes-BLllNmrY.js (new) 514 B 283 B 272 B
assets/save-video-BJqLQPeC.js (new) 512 B 348 B 292 B
assets/vRekaZIndex-DiOTTFpE.js (new) 505 B 331 B 274 B
assets/telemetry-IkzvF0TI.js (new) 499 B 299 B 243 B
assets/text-prompt-enhance-Bmq8gDVO.js (new) 492 B 339 B 280 B
assets/load-audio-epQbRZsp.js (new) 460 B 320 B 268 B
assets/save-audio-DZVtSVp_.js (new) 454 B 319 B 265 B
assets/nightlyBadges-ClXTz91A.js (new) 411 B 272 B 266 B
assets/src-DLOcFdhc.js (new) 407 B 288 B 244 B
assets/elevenlabs-BVR3dQ8G.js (new) 388 B 286 B 232 B
assets/play-BFqV6tIE.js (new) 369 B 256 B 225 B
assets/cloud-subscription-DJ2DFeD9.js (new) 223 B 154 B 133 B
assets/comfy-logo-single-B7u6lN8V.js (new) 217 B 154 B 117 B
assets/Load3dViewerContent-U8KDUhR6.js (new) 137 B 103 B 110 B
assets/WidgetBoundingBox-CU8Q9BZb.js (new) 131 B 100 B 95 B
assets/missingModelMetadata-BF3qdEch.js (new) 125 B 103 B 105 B
assets/Load3DAdvanced-D-w05HV_.js (new) 122 B 97 B 87 B
assets/types-t0xJOOCt.js (new) 120 B 124 B 83 B
assets/WidgetLegacy-5gFH6P2m.js (new) 117 B 106 B 101 B
assets/workflowDraftStoreV2-CyySxjUj.js (new) 112 B 101 B 107 B
assets/Load3D-DQnPo_j_.js (new) 98 B 89 B 86 B
assets/i18n-6-AfCSq2.js (new) 97 B 92 B 101 B
assets/dist-Bp3Fn1Wt.js (new) 96 B 102 B 91 B
assets/startRecording-BOV6MsgY.js (new) 95 B 96 B 92 B
assets/changeTracker-BScJU2qj.js (new) 91 B 93 B 85 B

Status: 286 added

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 70.4 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.6 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 73.8 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.1 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 82.6 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 81.3 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 81.4 MB heap
legacy-node-drag: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 75.4 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 82.9 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 55.5 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.2 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.3 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 79.0 MB heap
vue-large-graph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 93.1 MB heap
vue-large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 97.8 MB heap
vue-zoom-culling: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 28ms TBT · 112.4 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.8 MB heap

ℹ️ No baseline found — significance unavailable.

Absolute values
Metric Value
canvas-idle: avg frame time 17ms
canvas-idle: p95 frame time 17ms
canvas-idle: layout duration 0ms
canvas-idle: style recalc duration 8ms
canvas-idle: layout count 0
canvas-idle: style recalc count 8
canvas-idle: task duration 565ms
canvas-idle: script duration 10ms
canvas-idle: TBT 0ms
canvas-idle: heap used 70.4 MB
canvas-idle: DOM nodes 16
canvas-idle: event listeners 6
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 3ms
canvas-mouse-sweep: style recalc duration 38ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 74
canvas-mouse-sweep: task duration 899ms
canvas-mouse-sweep: script duration 119ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 65.6 MB
canvas-mouse-sweep: DOM nodes 56
canvas-mouse-sweep: event listeners 5
canvas-zoom-sweep: avg frame time 17ms
canvas-zoom-sweep: p95 frame time 17ms
canvas-zoom-sweep: layout duration 1ms
canvas-zoom-sweep: style recalc duration 18ms
canvas-zoom-sweep: layout count 6
canvas-zoom-sweep: style recalc count 33
canvas-zoom-sweep: task duration 391ms
canvas-zoom-sweep: script duration 11ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 73.8 MB
canvas-zoom-sweep: DOM nodes 78
canvas-zoom-sweep: event listeners 19
dom-widget-clipping: avg frame time 17ms
dom-widget-clipping: p95 frame time 17ms
dom-widget-clipping: layout duration 0ms
dom-widget-clipping: style recalc duration 8ms
dom-widget-clipping: layout count 0
dom-widget-clipping: style recalc count 11
dom-widget-clipping: task duration 396ms
dom-widget-clipping: script duration 63ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 57.1 MB
dom-widget-clipping: DOM nodes 17
dom-widget-clipping: event listeners 1
large-graph-idle: avg frame time 17ms
large-graph-idle: p95 frame time 17ms
large-graph-idle: layout duration 0ms
large-graph-idle: style recalc duration 8ms
large-graph-idle: layout count 0
large-graph-idle: style recalc count 8
large-graph-idle: task duration 630ms
large-graph-idle: script duration 18ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 82.6 MB
large-graph-idle: DOM nodes 16
large-graph-idle: event listeners 5
large-graph-pan: avg frame time 17ms
large-graph-pan: p95 frame time 17ms
large-graph-pan: layout duration 0ms
large-graph-pan: style recalc duration 13ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 67
large-graph-pan: task duration 1232ms
large-graph-pan: script duration 364ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 81.3 MB
large-graph-pan: DOM nodes 11
large-graph-pan: event listeners 5
large-graph-zoom: avg frame time 17ms
large-graph-zoom: p95 frame time 17ms
large-graph-zoom: layout duration 7ms
large-graph-zoom: style recalc duration 14ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 65
large-graph-zoom: task duration 1351ms
large-graph-zoom: script duration 398ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 81.4 MB
large-graph-zoom: DOM nodes 11
large-graph-zoom: event listeners 8
legacy-node-drag: avg frame time 17ms
legacy-node-drag: p95 frame time 17ms
legacy-node-drag: layout duration 0ms
legacy-node-drag: style recalc duration 9ms
legacy-node-drag: layout count 0
legacy-node-drag: style recalc count 45
legacy-node-drag: task duration 1497ms
legacy-node-drag: script duration 475ms
legacy-node-drag: TBT 0ms
legacy-node-drag: heap used 75.4 MB
legacy-node-drag: DOM nodes 10
legacy-node-drag: event listeners 185
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 7ms
minimap-idle: layout count 0
minimap-idle: style recalc count 8
minimap-idle: task duration 543ms
minimap-idle: script duration 15ms
minimap-idle: TBT 0ms
minimap-idle: heap used 82.9 MB
minimap-idle: DOM nodes 15
minimap-idle: event listeners 5
subgraph-dom-widget-clipping: avg frame time 17ms
subgraph-dom-widget-clipping: p95 frame time 17ms
subgraph-dom-widget-clipping: layout duration 0ms
subgraph-dom-widget-clipping: style recalc duration 11ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 47
subgraph-dom-widget-clipping: task duration 416ms
subgraph-dom-widget-clipping: script duration 122ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 55.5 MB
subgraph-dom-widget-clipping: DOM nodes 19
subgraph-dom-widget-clipping: event listeners 8
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 9ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 10
subgraph-idle: task duration 497ms
subgraph-idle: script duration 9ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 71.2 MB
subgraph-idle: DOM nodes 20
subgraph-idle: event listeners 6
subgraph-mouse-sweep: avg frame time 17ms
subgraph-mouse-sweep: p95 frame time 17ms
subgraph-mouse-sweep: layout duration 5ms
subgraph-mouse-sweep: style recalc duration 38ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 75
subgraph-mouse-sweep: task duration 815ms
subgraph-mouse-sweep: script duration 94ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 62.3 MB
subgraph-mouse-sweep: DOM nodes 61
subgraph-mouse-sweep: event listeners 4
viewport-pan-sweep: avg frame time 17ms
viewport-pan-sweep: p95 frame time 17ms
viewport-pan-sweep: layout duration 0ms
viewport-pan-sweep: style recalc duration 36ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 250
viewport-pan-sweep: task duration 4122ms
viewport-pan-sweep: script duration 1064ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 79.0 MB
viewport-pan-sweep: DOM nodes -61
viewport-pan-sweep: event listeners -46
vue-large-graph-idle: avg frame time 17ms
vue-large-graph-idle: p95 frame time 17ms
vue-large-graph-idle: layout duration 0ms
vue-large-graph-idle: style recalc duration 0ms
vue-large-graph-idle: layout count 0
vue-large-graph-idle: style recalc count 0
vue-large-graph-idle: task duration 2791ms
vue-large-graph-idle: script duration 33ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 93.1 MB
vue-large-graph-idle: DOM nodes -1605
vue-large-graph-idle: event listeners -1784
vue-large-graph-pan: avg frame time 17ms
vue-large-graph-pan: p95 frame time 17ms
vue-large-graph-pan: layout duration 0ms
vue-large-graph-pan: style recalc duration 18ms
vue-large-graph-pan: layout count 3
vue-large-graph-pan: style recalc count 66
vue-large-graph-pan: task duration 3914ms
vue-large-graph-pan: script duration 574ms
vue-large-graph-pan: TBT 0ms
vue-large-graph-pan: heap used 97.8 MB
vue-large-graph-pan: DOM nodes -1783
vue-large-graph-pan: event listeners -1797
vue-zoom-culling: avg frame time 17ms
vue-zoom-culling: p95 frame time 17ms
vue-zoom-culling: layout duration 20ms
vue-zoom-culling: style recalc duration 43ms
vue-zoom-culling: layout count 42
vue-zoom-culling: style recalc count 45
vue-zoom-culling: task duration 1568ms
vue-zoom-culling: script duration 448ms
vue-zoom-culling: TBT 28ms
vue-zoom-culling: heap used 112.4 MB
vue-zoom-culling: DOM nodes 1638
vue-zoom-culling: event listeners 291
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 2ms
workflow-execution: style recalc duration 21ms
workflow-execution: layout count 4
workflow-execution: style recalc count 14
workflow-execution: task duration 106ms
workflow-execution: script duration 7ms
workflow-execution: TBT 0ms
workflow-execution: heap used 71.8 MB
workflow-execution: DOM nodes 144
workflow-execution: event listeners 74
Raw data
{
  "timestamp": "2026-08-19T17:31:11.563Z",
  "gitSha": "f6f6076c33546bd3bd4dd11596834ff5435d268e",
  "branch": "benjcooley/vue-nodes-lod-boxes",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2052.099999999996,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.893000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 631.919,
      "heapDeltaBytes": 2194712,
      "heapUsedBytes": 74241828,
      "domNodes": 16,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 11.180999999999997,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2034.6450000000686,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.100999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 497.47,
      "heapDeltaBytes": 1597212,
      "heapUsedBytes": 73456252,
      "domNodes": 16,
      "jsHeapTotalBytes": 16515072,
      "scriptDurationMs": 8.847000000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1830.5199999999786,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 36.609,
      "layouts": 12,
      "layoutDurationMs": 3.4410000000000003,
      "taskDurationMs": 909.411,
      "heapDeltaBytes": -3474748,
      "heapUsedBytes": 68617560,
      "domNodes": 55,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 120.34500000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1870.632999999998,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 38.523,
      "layouts": 12,
      "layoutDurationMs": 3.382,
      "taskDurationMs": 887.918,
      "heapDeltaBytes": -3068112,
      "heapUsedBytes": 69005956,
      "domNodes": 57,
      "jsHeapTotalBytes": 16777216,
      "scriptDurationMs": 118.566,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1720.3869999999597,
      "styleRecalcs": 33,
      "styleRecalcDurationMs": 16.691000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.5770000000000001,
      "taskDurationMs": 365.554,
      "heapDeltaBytes": 5497620,
      "heapUsedBytes": 77501656,
      "domNodes": 78,
      "jsHeapTotalBytes": 16515072,
      "scriptDurationMs": 8.948,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1753.8729999999987,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 18.678,
      "layouts": 6,
      "layoutDurationMs": 0.5529999999999999,
      "taskDurationMs": 417.12999999999994,
      "heapDeltaBytes": 5197012,
      "heapUsedBytes": 77194332,
      "domNodes": 78,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 12.158000000000001,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 582.3300000000131,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.723000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 388.622,
      "heapDeltaBytes": -14543968,
      "heapUsedBytes": 57391064,
      "domNodes": 18,
      "jsHeapTotalBytes": 18350080,
      "scriptDurationMs": 58.325,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 609.6089999999776,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.348999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 403.08299999999997,
      "heapDeltaBytes": -14359008,
      "heapUsedBytes": 62392156,
      "domNodes": 16,
      "jsHeapTotalBytes": 17932288,
      "scriptDurationMs": 68.223,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2034.4149999999672,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.288000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 596.792,
      "heapDeltaBytes": 20995668,
      "heapUsedBytes": 86284232,
      "domNodes": 16,
      "jsHeapTotalBytes": 2883584,
      "scriptDurationMs": 17.091999999999995,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2005.749000000037,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.851999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 664.027,
      "heapDeltaBytes": 20985692,
      "heapUsedBytes": 86895624,
      "domNodes": 16,
      "jsHeapTotalBytes": 2359296,
      "scriptDurationMs": 19.820999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2177.408000000014,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 13.808000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1177.266,
      "heapDeltaBytes": 19313000,
      "heapUsedBytes": 85314384,
      "domNodes": 14,
      "jsHeapTotalBytes": 3862528,
      "scriptDurationMs": 344.77200000000005,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2329.8039999999673,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 12.187999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1286.958,
      "heapDeltaBytes": 18540324,
      "heapUsedBytes": 85249836,
      "domNodes": 8,
      "jsHeapTotalBytes": 4386816,
      "scriptDurationMs": 383.047,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3131.7280000000096,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 14.247,
      "layouts": 60,
      "layoutDurationMs": 7.034000000000001,
      "taskDurationMs": 1357.006,
      "heapDeltaBytes": 19022248,
      "heapUsedBytes": 86875900,
      "domNodes": 12,
      "jsHeapTotalBytes": 3670016,
      "scriptDurationMs": 408.80300000000005,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3197.848000000022,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 14.089,
      "layouts": 60,
      "layoutDurationMs": 7.2490000000000006,
      "taskDurationMs": 1344.54,
      "heapDeltaBytes": 16979532,
      "heapUsedBytes": 83823816,
      "domNodes": 10,
      "jsHeapTotalBytes": 3407872,
      "scriptDurationMs": 387.61699999999996,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "legacy-node-drag",
      "durationMs": 2274.169000000029,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 9.366,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1418.1979999999999,
      "heapDeltaBytes": 10154060,
      "heapUsedBytes": 78175236,
      "domNodes": 12,
      "jsHeapTotalBytes": 4349952,
      "scriptDurationMs": 453.085,
      "eventListeners": 184,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "legacy-node-drag",
      "durationMs": 2736.0120000000734,
      "styleRecalcs": 44,
      "styleRecalcDurationMs": 8.713,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1575.741,
      "heapDeltaBytes": 11320740,
      "heapUsedBytes": 79866800,
      "domNodes": 8,
      "jsHeapTotalBytes": 6455296,
      "scriptDurationMs": 496.53000000000003,
      "eventListeners": 186,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 1993.5909999999808,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 6.752000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 535.582,
      "heapDeltaBytes": 21011468,
      "heapUsedBytes": 86476724,
      "domNodes": 16,
      "jsHeapTotalBytes": 2883584,
      "scriptDurationMs": 13.787,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2003.783999999996,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 6.541000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 549.519,
      "heapDeltaBytes": 20837232,
      "heapUsedBytes": 87349108,
      "domNodes": 14,
      "jsHeapTotalBytes": 3932160,
      "scriptDurationMs": 16.617,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 598.352000000034,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 10.047999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 404.39300000000003,
      "heapDeltaBytes": -14552060,
      "heapUsedBytes": 57506596,
      "domNodes": 18,
      "jsHeapTotalBytes": 18350080,
      "scriptDurationMs": 119.94599999999998,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 625.165999999922,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 11.577,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 428.421,
      "heapDeltaBytes": -13290404,
      "heapUsedBytes": 58793192,
      "domNodes": 20,
      "jsHeapTotalBytes": 16777216,
      "scriptDurationMs": 124.24799999999999,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2006.7650000000299,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.397999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 484.083,
      "heapDeltaBytes": 2591252,
      "heapUsedBytes": 74714932,
      "domNodes": 20,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 9.095,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2038.8719999999694,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.263,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 509.73100000000005,
      "heapDeltaBytes": 2391916,
      "heapUsedBytes": 74551048,
      "domNodes": 20,
      "jsHeapTotalBytes": 16515072,
      "scriptDurationMs": 8.734000000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1689.6229999999832,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 39.588,
      "layouts": 16,
      "layoutDurationMs": 4.994999999999999,
      "taskDurationMs": 807.903,
      "heapDeltaBytes": -6648332,
      "heapUsedBytes": 65456632,
      "domNodes": 61,
      "jsHeapTotalBytes": 18087936,
      "scriptDurationMs": 93.539,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1709.594999999922,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 36.725,
      "layouts": 16,
      "layoutDurationMs": 4.4190000000000005,
      "taskDurationMs": 822.278,
      "heapDeltaBytes": -6909068,
      "heapUsedBytes": 65152928,
      "domNodes": 61,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 95.273,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8341.731999999978,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 36.175,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4151.586,
      "heapDeltaBytes": 24950096,
      "heapUsedBytes": 90364960,
      "domNodes": 16,
      "jsHeapTotalBytes": 6221824,
      "scriptDurationMs": 1070.143,
      "eventListeners": 22,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8280.239000000052,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 36.687999999999995,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4091.8179999999998,
      "heapDeltaBytes": 9919688,
      "heapUsedBytes": 75352324,
      "domNodes": -138,
      "jsHeapTotalBytes": 2523136,
      "scriptDurationMs": 1058.574,
      "eventListeners": -114,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 4064.341000000013,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 2701.0170000000003,
      "heapDeltaBytes": -8996636,
      "heapUsedBytes": 97605140,
      "domNodes": -1605,
      "jsHeapTotalBytes": 8097792,
      "scriptDurationMs": 32.98699999999999,
      "eventListeners": -1784,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.80000000000109
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 4086.496000000011,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 2880.689,
      "heapDeltaBytes": -9409900,
      "heapUsedBytes": 97619652,
      "domNodes": -1605,
      "jsHeapTotalBytes": 8097792,
      "scriptDurationMs": 33.566999999999986,
      "eventListeners": -1784,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 5202.631999999994,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 17.953999999999997,
      "layouts": 3,
      "layoutDurationMs": 0.37000000000000227,
      "taskDurationMs": 3878.3880000000004,
      "heapDeltaBytes": -20844940,
      "heapUsedBytes": 89207720,
      "domNodes": -1941,
      "jsHeapTotalBytes": 2813952,
      "scriptDurationMs": 564.548,
      "eventListeners": -1814,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 5188.743999999929,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 17.986,
      "layouts": 3,
      "layoutDurationMs": 0.3759999999999944,
      "taskDurationMs": 3949.4630000000006,
      "heapDeltaBytes": 25212040,
      "heapUsedBytes": 115950388,
      "domNodes": -1625,
      "jsHeapTotalBytes": -327680,
      "scriptDurationMs": 583.233,
      "eventListeners": -1780,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-zoom-culling",
      "durationMs": 3437.621999999976,
      "styleRecalcs": 45,
      "styleRecalcDurationMs": 44.787000000000006,
      "layouts": 42,
      "layoutDurationMs": 20.594999999999995,
      "taskDurationMs": 1520.6139999999998,
      "heapDeltaBytes": 22973972,
      "heapUsedBytes": 118918728,
      "domNodes": 1644,
      "jsHeapTotalBytes": 3670016,
      "scriptDurationMs": 427.54400000000004,
      "eventListeners": 290,
      "totalBlockingTimeMs": 27,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-zoom-culling",
      "durationMs": 3560.2480000000014,
      "styleRecalcs": 44,
      "styleRecalcDurationMs": 40.69499999999999,
      "layouts": 41,
      "layoutDurationMs": 20.145999999999997,
      "taskDurationMs": 1614.4129999999998,
      "heapDeltaBytes": 23144744,
      "heapUsedBytes": 116888676,
      "domNodes": 1632,
      "jsHeapTotalBytes": 3670016,
      "scriptDurationMs": 469.07300000000004,
      "eventListeners": 292,
      "totalBlockingTimeMs": 29,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 125.18899999997757,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 19.165000000000003,
      "layouts": 4,
      "layoutDurationMs": 1.538,
      "taskDurationMs": 92.124,
      "heapDeltaBytes": 3337188,
      "heapUsedBytes": 74335404,
      "domNodes": 140,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 6.690000000000001,
      "eventListeners": 49,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 475.6560000000718,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 23.015999999999995,
      "layouts": 3,
      "layoutDurationMs": 1.5939999999999999,
      "taskDurationMs": 119.27300000000002,
      "heapDeltaBytes": 5288508,
      "heapUsedBytes": 76278204,
      "domNodes": 147,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 7.667,
      "eventListeners": 99,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@benjcooley

Copy link
Copy Markdown
Contributor Author

I have read and agree to the Contributor License Agreement

comfy-legal added a commit to Comfy-Org/comfy-cla that referenced this pull request Aug 11, 2026
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.74114% with 56 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/components/graph/GraphCanvas.vue 28.98% 49 Missing ⚠️
...nderer/extensions/vueNodes/utils/nodeStyleUtils.ts 0.00% 5 Missing ⚠️
.../extensions/vueNodes/components/NodeBoxOverlay.vue 95.65% 2 Missing ⚠️
@@                           Coverage Diff                           @@
##           benjcooley/vue-nodes-simple-keepalive   #15031    +/-   ##
=======================================================================
  Coverage                                  81.37%   81.38%            
=======================================================================
  Files                                       1886     1890     +4     
  Lines                                     115278   115601   +323     
  Branches                                   35771    35858    +87     
=======================================================================
+ Hits                                       93812    94080   +268     
- Misses                                     21008    21063    +55     
  Partials                                     458      458            
Flag Coverage Δ
unit 73.35% <84.74%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/lib/litegraph/src/LGraphCanvas.ts 69.59% <ø> (-0.05%) ⬇️
src/lib/litegraph/src/LGraphNode.ts 68.24% <ø> (-0.02%) ⬇️
src/lib/litegraph/src/LiteGraphGlobal.ts 48.55% <ø> (ø)
src/platform/settings/constants/coreSettings.ts 85.00% <ø> (ø)
src/renderer/core/canvas/nodeBoxRenderer.ts 100.00% <100.00%> (ø)
src/renderer/core/layout/store/layoutStore.ts 84.60% <100.00%> (+0.11%) ⬆️
src/renderer/core/spatial/SpatialIndex.ts 95.23% <100.00%> (+2.64%) ⬆️
.../extensions/firstRunTour/tour/canvasCoachTarget.ts 100.00% <100.00%> (ø)
...ons/vueNodes/composables/useLowQualityRendering.ts 100.00% <100.00%> (ø)
...sions/vueNodes/composables/useViewportKeepAlive.ts 100.00% <100.00%> (ø)
... and 6 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@christian-byrne christian-byrne left a comment

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.

This assumes node (or whatever gets torn down) unmount hooks serialize any state that wants to be persisted (which we want to be the case, but just noting for readers).

@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from 570eeb8 to e28d5f2 Compare August 11, 2026 03:55
@benjcooley benjcooley added the New Browser Test Expectations New browser test screenshot should be set by github action label Aug 11, 2026
@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from e28d5f2 to bc7e1ee Compare August 11, 2026 05:17
@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from bc7e1ee to c69cd94 Compare August 11, 2026 05:37
@benjcooley benjcooley added New Browser Test Expectations New browser test screenshot should be set by github action and removed New Browser Test Expectations New browser test screenshot should be set by github action labels Aug 11, 2026
@github-actions

Copy link
Copy Markdown

Updating Playwright Expectations

@github-actions github-actions Bot removed the New Browser Test Expectations New browser test screenshot should be set by github action label Aug 11, 2026
@benjcooley

Copy link
Copy Markdown
Contributor Author

@christian-byrne Right — and that assumption mostly holds because the persistent state doesn't live in the components: positions/sizes are in layoutStore, selection in canvasStore, z-index in layoutStore, execution/preview state in their stores, so unmount loses nothing there. The known exceptions are element-local DOM widget state (media playback position, IME composition, focus) which survives detach only partially, and the DOM-measured slot layouts, which are deleted on unmount by useSlotElementTracking — links then fall back to computed geometry. That last one is tracked as FE-1557 (preserve slot layouts across cull), which also removes the fallback's ~11% pan-time cost. Selected nodes are never culled, so an in-progress drag/resize can't be torn down mid-interaction.

@christian-byrne christian-byrne added the preview-cpu Creates a preview ephemeral environment for this PR (CPU only) label Aug 12, 2026
@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch 5 times, most recently from f5d3c2a to 34a2db0 Compare August 18, 2026 16:17
@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from 34a2db0 to 31f27d9 Compare August 18, 2026 18:52
@benjcooley
benjcooley changed the base branch from benjcooley/vue-nodes-viewport-culling to benjcooley/vue-nodes-simple-keepalive August 18, 2026 18:52
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Aug 18, 2026
@github-actions

Copy link
Copy Markdown

🔗 Website Preview

Website Preview: https://comfy-website-preview-pr-15031.vercel.app

This commit: https://website-frontend-2zcotd9o6-comfyui.vercel.app

Last updated: 2026-08-18T18:54:21Z for 31f27d9

@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from 31f27d9 to 0391723 Compare August 18, 2026 18:59
@christian-byrne

Copy link
Copy Markdown
Contributor

Thanks for adding this, and it is a good ADR. The Decision section is precise, and recording that a second spatial index and mount scheduler were rejected is exactly the thing DrJKL's review was asking for.

I checked it against the Slack thread specifically for what a future maintainer or agent would need and cannot get from the code. Nine items came up: four partly covered, five absent. One of them I would fix before merge because it is not a gap but a wrong impression.

The one that is actively misleading

Evidence says KeepAlive and destructive unmounting were "in the same performance tier" across Chromium, Firefox and WebKit. The thread is more specific than that: KeepAlive is slower on Chrome and close on the others. That matters twice over, because Chrome is where nearly all users are, and because most of the team dailies non-Chrome browsers, so our dogfooding is biased away from the exact case where this design is weakest. As written, a reader concludes the retention strategy is free everywhere.

Something I found while checking, which is worse than a documentation gap

The 158-line docs/architecture/vue-nodes-large-graph-performance.md and the whole of scripts/perf/ exist on no branch any more: not main, not this one, not #15405, not the abandoned #15030. Those took two review rounds to get committed and re-runnable, and they are the only thing that made the numbers checkable.

That leaves this ADR's Evidence section, including the 8.3 versus 8.6 ms/frame comparison, with no committed source behind it. Either restore them or point Evidence at the @perf suite in browser_tests/tests/performance.spec.ts with browser_tests/fixtures/utils/perfReporter.ts, which is committed and does run.

Placement

The ADR is only on this branch, but items 1 through 6 below are about the KeepAlive decision, which is #15405. #15031 is stacked on #15405, so if the base lands alone, which is the likely order, the decision ships and its rationale does not. I would move the file and its README index row down to #15405 unchanged, keep it as one ADR covering both halves, and add a line to Status noting which PR delivers which half.

The nine items

Verdicts: item 1 partial, 2 missing, 3 partial and misleading, 4 partial, 5 missing, 6 missing, 7 missing, 8 missing, 9 missing.

Drafted below in the ADR's own voice and section structure so it is paste-ready. Take or leave any of it; the wording is not the point, the content is.


All of the following is wrapped to the ADR's existing column width, uses the
repo's backtick-and-markdown-link conventions, and contains no emdashes.

Item 1. Replace the "Destroy offscreen components" alternative

Replace the whole subsection body:

### Destroy offscreen components

Rejected as the default. Interaction performance landed in the same tier as
`KeepAlive`, so maintainability decided this and not speed. Unmounting fires
`mounted` and `unmounted` on every viewport crossing, which node components and
extensions already treat as create and destroy, and it discards
component-local state. `KeepAlive` fires `activated` and `deactivated` instead,
a separate lifecycle that existing code does not overload, and the instance
keeps its state across the transition.

Item 2. New alternative, insert after "Keep every Vue node attached"

### Virtualize the node list and mount only visible nodes

Built, reviewed, and abandoned as
[#15030](https://github.com/Comfy-Org/ComfyUI_frontend/pull/15030), roughly
2700 lines added. Virtualization was going to be the default, and the default
was deliberately reversed once `KeepAlive` measured the same and turned out to
be the smaller lifecycle change. The implementation was then removed rather
than kept behind a setting, so there is one attachment path to reason about
instead of two. The approach works and is not disqualified; it was dropped
because it costs more machinery than the current activation threshold
justifies. Anyone revisiting it should start from that PR rather than rebuild
it.

Note the wording: this rejects the implementation, not the virtualization
model. The model survives in the Decision section and in Notes below, so do
not write "virtualization was dropped" without that qualifier.

Item 3. Replace the first Evidence paragraph

Replace from "On the 245-node workflow" through "primary gain.":

On the 245-node workflow used for the original performance investigation,
removing offscreen DOM improved scripted interactions on Chromium, Firefox, and
WebKit. Between the two retention strategies, `KeepAlive` is slower than
destructive unmounting on Chrome specifically and close to it on the other
browsers, so active DOM size and not the retention strategy is the primary
gain. Chrome is both where this design is weakest and where nearly all users
are, while most of the team dailies non-Chrome browsers. Dogfooding is
therefore biased away from the worst case, and Chrome needs explicit attention
in any follow-up measurement.

Item 3, second half. Add to Consequences / Negative

- `KeepAlive` is slower than unmounting on Chrome, which is where almost all
  users are and where the team dogfoods least.

Item 4. Replace the first Negative bullet

- `KeepAlive` retains component memory for detached nodes. The cost grows with
  graph size and has not been measured, so the magnitude is unknown.

Item 5. Append to the Evidence paragraph that quotes 8.3 vs 8.6 ms/frame

Read that comparison narrowly. Nodes 2.0 is now close to LiteGraph on these
workflows rather than ahead of it, and some of this work also made LiteGraph
faster, so a before and after against an older `main` overstates the gain
attributable to viewport retention. Compare Nodes 2.0 against LiteGraph on the
same build.

Item 9. Append to Evidence, after the behavioral coverage paragraph

The cross-browser comparison behind these statements came from a generated
benchmark report the team chose not to publish, so no numbers from it are
quoted here. The committed and re-runnable source is the `@perf` suite in
`browser_tests/tests/performance.spec.ts` with
`browser_tests/fixtures/utils/perfReporter.ts`. Anything this ADR asserts about
performance should be reproducible from that suite; if it is not, treat it as
unsourced.

Items 6, 7, 8. New Notes section, appended at the end of the ADR

The house template puts a ## Notes section last and 0013 and 0015 both use it
for direction and follow-ups, so this is where the forward-looking material
belongs.

## Notes

Agreed direction for follow-up performance work: keep this virtualization
model and fix where it breaks down rather than reverting to attaching every
node. The available tools are overscan, hysteresis on membership transitions,
buffered visibility regions, and retained rendering. Prefer a buffered
visibility region owned by the renderer over a per-node `isInViewport` flag; a
per-node predicate puts a reactive boundary on every node and scatters the
overscan and hysteresis tuning that a single region keeps in one place.

Viewport retention and the low-quality box layer interact. Render-on-pan lag is
more noticeable when the level-of-detail change is not also present, so the two
are best evaluated together. They may land as separate PRs, and if retention
ships first then panning will feel worse than the measurements here suggest.

A risk to watch: profiling does not always survive contact with real users,
real workflows, and real hardware. Treat the scripted measurements as a
starting point and monitor real-world experience reports after release rather
than closing this out on the numbers alone.

@christian-byrne christian-byrne left a comment

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.

Verified all 18 threads against the code at head rather than against the replies. 10 confirmed, 4 partial, 1 not fixed, 3 no longer applicable. I have resolved the confirmed ones and replied in place on the rest naming exactly what is left, so the threads should tell you what to do without re-reading this.

The one I owe you an apology on is now closed correctly. The double title-height offset was my error, and the fix is right: I derived it end to end and the box span matches the node span exactly, with widgets on the body-relative rect and slots on absolute getSlotPosition, all three in register.

One reply does not hold up and I have left that thread open. On the culling-index fail-open, the reply says layoutStore owns that handling. It does not: grep -rn unpositioned src/ is empty, SpatialIndexManager.insert discards QuadTree.insert's boolean, and the root is still the fixed +/-10000 box. So a node outside it is absent from every query, attached by the keepalive fail-open and never drawn as a box, i.e. invisible below the threshold. Your own #15254 is the root cause; this PR needs either to depend on that fix or reinstate a fail-open list on the read path.

Three threads are now moot for a reason worth its own attention: the measurement doc and all of scripts/perf/ are gone from every branch, including the abandoned one. I raised that on the ADR comment because it leaves the ADR's own numbers unsourced.

One new finding inline, on the same line as a thread I just closed.

@christian-byrne christian-byrne left a comment

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.

Re-review after the rebase onto #15405, head 0391723f78. Status on the five open threads, plus one new blocking finding the rebase introduced.

The rebase reverted the SpatialIndexManager hardening

This is the important one, and it is a regression rather than a pre-existing gap.

On #15030 you closed DrJKL's "second QuadTree" blocker by deleting nodeCullingIndex.ts and hardening the canonical index. That branch's SpatialIndex.ts has unindexableEntries, an isIndexable() check, if (!indexed) this.rebuild(), and batched-growth handling — verified at origin/benjcooley/vue-nodes-viewport-culling:src/renderer/core/spatial/SpatialIndex.ts:37-98.

None of it is on this branch. SpatialIndex.ts is untouched relative to #15405, and insert() is back to:

insert(nodeId: TId, bounds: Bounds): void {
  this.quadTree.insert(String(nodeId), bounds, nodeId)
  this.invalidateCache()
}

QuadTree.insert returns false when !this.contains(item.bounds) (QuadTree.ts:52-54), the index is constructed with no explicit bounds (layoutStore.ts:230) so it uses DEFAULT_BOUNDS = ±10000, and that boolean is discarded.

This matters more here than it did on #15030. Below the LOD threshold Vue nodes are detached, so getNodeBoxes is the only thing drawing a node — and it draws exactly what queryNodesInBounds returns. A node beyond ±10000 fails insert silently, is absent from the query, and is therefore invisible when zoomed out: not mounted, not drawn. ±10000 is reachable in a real workflow.

This also re-opens thread 3 in substance. I left it open saying "no fail-open list exists anywhere in the tree"; the reply pointed at layoutStore. On #15030 that reply became true. On this branch it is false again, and the relocation to queryNodesInBounds means the two-readers-disagree framing no longer applies — now there is one reader and it silently omits.

Cheapest correct fix is to bring SpatialIndex.ts forward from the #15030 branch. It is self-contained and already reviewed.

Thread status

Thread State
nodeCullingIndex.queryEntries omits unpositioned Superseded, hazard live — file deleted, but see above. Suggest re-scoping this thread to the SpatialIndex regression rather than closing it.
useLowQualityRendering header vs HYSTERESIS Unchanged. Lines 5-6 still say both renderers "simplify at exactly the same zoom and the same setting controls both"; HYSTERESIS = 0.15 at :28 is still applied at :75. Still no composable-level DPR test.
nodeBoxRenderer colour batching Unchanged, and the second half is now confirmed — see inline.
getBoxes allocation / O(all) Half closed. queryNodesInBounds + viewport expansion landed; O(visible) is right and the title offset is correctly applied once via includeNodeTitleInBounds. Allocation half still open, non-blocking.
Cold-start re-arm Not re-verified this round; leaving as-is.

Direction remains right and the LOD work itself is clean. The blocking item is purely the lost SpatialIndex hardening — a rebase artifact, not a design choice.

Comment thread src/components/graph/GraphCanvas.vue Outdated
Comment thread src/renderer/core/canvas/nodeBoxRenderer.ts Outdated
Comment thread src/components/graph/GraphCanvas.vue Outdated
Comment thread src/renderer/extensions/vueNodes/composables/useLowQualityRendering.ts Outdated
@benjcooley
benjcooley force-pushed the benjcooley/vue-nodes-lod-boxes branch from 0391723 to c8aa094 Compare August 18, 2026 20:40

@christian-byrne christian-byrne left a comment

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.

Approving. All threads resolved, CI 35 pass / 0 fail at 1c303b03d6. Verified each fix at head.

The blocking one — the SpatialIndexManager hardening lost in the rebase — is fully restored: unindexableEntries (:37), the isIndexable branch (:54-58), if (!indexed) this.rebuild() (:67), the batched rebuildRequired path (:83-105), and query concatenating unindexable entries so it fails open (:140-141). SpatialIndex.test.ts:6-17 inserts at x: 50_000, outside the original ±10000 root, and asserts the query returns it. That test is the part that matters — it's what stops this being lost to a rebase a third time.

The setFill fix is better than the read-back I proposed. Assigning the known-good fallback before attempting the desired value means a rejected colour degrades to the default rather than inheriting the previous box's, and reading currentColor back off ctx.fillStyle makes cache/context divergence structurally impossible instead of merely unlikely. It also closed the slot-colour input for free, since those now route through the same fallback.

Also verified: nodeBoxCache removes the per-frame NodeLayout + slot/widget materialisation on the moving path; the file header now describes the shared threshold plus the deliberate Vue-only hysteresis instead of claiming identical transition zooms; and the cold-start re-arm case is unreachable now that the re-arm is gated on wasLow && !low, so the immediate: true run at cold start can't trigger it.

One condition, carried from #15405

Land these together, or this one immediately behind #15405. #15405 alone has no bound on the activation set at low zoom; this PR is what supplies it, by switching the template off activeNodeIds below the LOD threshold. I accepted the decline to add a redundant cap in #15405 on that basis, so the sequencing is load-bearing.

ADR 0016 lives only on this PR, which is the second reason the two shouldn't separate — merging #15405 first puts the KeepAlive architecture in main undocumented. The six Slack items the ADR is still missing are listed on #15405; they apply to this file since it's where the ADR lives.

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

Labels

area:nodes area:vue-migration perf:speed preview-cpu Creates a preview ephemeral environment for this PR (CPU only) retain-preview Keep the ephemeral preview environment from being torn down for inactivity risk:R3 PR risk grade (advisory shadow check; grader-owned) size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants