Skip to content

refactor: [Option A] inline node footer layout with core _footerHeight/_collapsedHeight#10711

Closed
jaeone94 wants to merge 9 commits intomainfrom
refactor/node-footer-inline-layout
Closed

refactor: [Option A] inline node footer layout with core _footerHeight/_collapsedHeight#10711
jaeone94 wants to merge 9 commits intomainfrom
refactor/node-footer-inline-layout

Conversation

@jaeone94
Copy link
Copy Markdown
Collaborator

@jaeone94 jaeone94 commented Mar 29, 2026

Summary

Fix selection bounding box not encompassing node footer, and refactor footer from absolute overlay to inline flow layout. Option A uses _footerHeight and _collapsedHeight properties on LGraphNode with vueNodesMode guard in measure().

See also: Option B#10712 (uses onBounding callback with vueBoundsOverrides Map instead of core changes)

Background

The node footer (Enter Subgraph, Advanced, Error buttons) was previously rendered as an absolute overlay (absolute top-full) outside the node body. This caused the selection bounding box, resize handles, and border/outline overlays to not account for the footer height, requiring multiple hardcoded pixel offsets (32px, 34px) to compensate.

Changes

Footer inline layout

  • Replace absolute overlay footer with inline flow layout using z-index layering (body z-5 > footer z-0/z-2)
  • Footer buttons use negative margin (-mt-5) to slide behind the body's rounded bottom edge
  • Enter/Advanced buttons tuck behind Error button with -ml-5 overlap
  • Shape-aware radius classes for all footer button combinations

Border/outline unification

  • Remove two separate overlay divs (selection border + root border)
  • Move border directly to root element (border border-solid border-component-node-border)
  • Selection/execution indicator uses outline on root (no layout shift)
  • Error state hides root border (border-transparent) since ring-4 covers it

Resize handles

  • Split SE/SW handles: body handles hide when footer exists, footer-level handles render after NodeFooter
  • Use body element (node-inner-wrapper) for resize start size to exclude footer height
  • Add z-10 to resize handles so they appear above footer buttons

Accurate bounding rect (Option A approach)

  • Measure body (node-inner-wrapper) via offsetHeight for node.size to exclude footer, preventing size accumulation on Vue/legacy mode switching
  • Store footer height separately (_footerHeight) on LGraphNode for measure() to extend boundingRect
  • Store collapsed width/height from DOM in ResizeObserver
  • Skip _collapsed_width text measurement in Vue nodes mode since measure() ctx overwrites ResizeObserver values
  • selectionBorder.ts unchanged — uses createBounds as before, no per-frame DOM queries

Limitations of Option A

  • Adds _footerHeight and _collapsed_height properties to LGraphNode.ts (core change, Vue-specific fields)
  • measure() has vueNodesMode branch (core knows about rendering mode)

Tests

  • 8 parameterized E2E tests for selection bounding box (subgraph/regular x expanded/collapsed x bottom-left/bottom-right)
  • Shared test helpers: repositionNodes (decomposed into getSerializedGraph + applyNodePositions + loadGraph), NodeReference.setCollapsed, measureSelectionBounds

Review Focus

  • The _footerHeight / _collapsed_height approach vs onBounding callback (see Option B PR)
  • offsetHeight usage instead of borderBoxSize in ResizeObserver (needed because contain-layout excludes footer from getBoundingClientRect)
  • Border/outline unification removes 2 overlay divs and selectionShapeClass computed

┆Issue is synchronized with this Notion page by Unito

- Replace absolute overlay footer with inline flow layout
- Use z-index layering: body(z-5) > footer(z-0/z-2) to keep footer
  behind body while maintaining hover interactivity
- Move resize handles inside body to avoid footer overlap
- Use border-2 with negative inset for root border overlay to render
  outside body bounds, preventing slot dot occlusion (z-0)
- Shape-aware radius classes for error/enter/footer buttons
- Remove hasFooter computed and all footer offset classes
- Move border from overlay div to root element directly
- Replace separate selection/execution overlay with outline on root
- Remove overlay div, selectionShapeClass computed, and hasFooter
- Inline all footer sizing constants
- Add ring-inset border for Enter/Advanced buttons in error state
- Hide root border in error state (transparent) since ring-4 covers it
- Remove isCollapsed prop from NodeFooter (no longer needed)
- Split SE/SW handles: body handles hide when footer exists,
  footer-level handles render after NodeFooter
- Use body element (node-inner-wrapper) for resize start size
  instead of root element to exclude footer height
- Add z-10 to resize handles so they appear above footer buttons
- Restore hasFooter computed for handle visibility control
- Measure body (node-inner-wrapper) for node.size to exclude footer
  height, preventing size accumulation on Vue/legacy mode switching
- Store footer height separately (_footerHeight) for boundingRect
- Store collapsed width/height from DOM in ResizeObserver instead of
  relying on canvas text measurement
- Skip _collapsed_width text measurement in Vue nodes mode since
  measure() ctx overwrites ResizeObserver values
- Restore selectionBorder.ts to use createBounds (no per-frame DOM)
- Rename loadWithPositions to repositionNodes, decompose into
  getSerializedGraph + applyNodePositions (pure) + loadGraph
- Extract measureSelectionBounds to shared boundsUtils helper
- Add JSDoc to setCollapsed
- Move test helpers out of spec file into fixture utils
@jaeone94 jaeone94 requested a review from a team March 29, 2026 18:01
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Mar 29, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/30/2026, 08:46:46 AM UTC

Links

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

🎭 Playwright: ❌ 792 passed, 26 failed · 4 flaky

❌ Failed Tests

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7f59a1ea-eab8-4854-bd7a-62d46887ca79

📥 Commits

Reviewing files that changed from the base of the PR and between 7b39902 and 920f8ab.

📒 Files selected for processing (1)
  • src/renderer/extensions/vueNodes/components/LGraphNode.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/extensions/vueNodes/components/LGraphNode.vue

📝 Walkthrough

Walkthrough

Adds selection-bounds measurement helpers and Playwright tests; introduces graph fixture and node operations helpers; updates Vue node rendering, footer sizing, and resize-tracking to include footer/collapsed dimensions; adjusts LiteGraph node measurement to account for footer and cached collapsed height.

Changes

Cohort / File(s) Summary
Test assets & helpers
browser_tests/assets/selection/subgraph-with-regular-node.json, browser_tests/fixtures/helpers/NodeOperationsHelper.ts, browser_tests/fixtures/utils/boundsUtils.ts, browser_tests/fixtures/utils/litegraphUtils.ts, browser_tests/tests/selectionBoundingBox.spec.ts
Adds graph fixture, graph serialize/load/reposition and collapse helpers, selection-bounds measurement utility, and a Playwright suite exercising selection bounding-box behavior across subgraph/regular nodes, collapsed states, and positions.
LiteGraph node sizing
src/lib/litegraph/src/LGraphNode.ts
Adds _collapsed_height and _footerHeight fields; updates measure() to include footer height in collapsed/expanded height and to avoid recomputing collapsed width in Vue nodes mode.
Vue node UI & footer
src/renderer/extensions/vueNodes/components/LGraphNode.vue, src/renderer/extensions/vueNodes/components/NodeFooter.vue
Consolidates outline rendering to a root outlineClass, reorganizes border/radius classes, moves top resize handles, and refactors footer templates and tab/button sizing/radius logic.
Resize measurement & tracking
src/renderer/extensions/vueNodes/composables/useVueNodeResizeTracking.ts, src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.ts
Switches measurements to use node-inner-wrapper element (fallback to node), synchronizes collapsed width/height and footer extra height from DOM, and updates resize tracking to use DOM-derived sizes.
Tests & mocks updated
src/renderer/extensions/vueNodes/components/LGraphNode.test.ts, src/renderer/extensions/vueNodes/composables/useVueNodeResizeTracking.test.ts
Removes assertions for layered overlay outline, updates mocks to provide offsetWidth/offsetHeight for resize measurements.

Sequence Diagram(s)

sequenceDiagram
    participant TestRunner as Test Runner
    participant App as Canvas App
    participant DOM as Browser DOM
    participant BoundsUtil as Bounds Utility
    participant Assert as Assertions

    TestRunner->>App: loadGraphData(fixture)
    TestRunner->>App: repositionNodes / setCollapsed(nodeId, state)
    TestRunner->>App: select all (Ctrl+A)
    App-->>TestRunner: selected items confirm (2 nodes)
    TestRunner->>BoundsUtil: measureSelectionBounds([targetId, refId])
    activate BoundsUtil
    BoundsUtil->>DOM: read canvas.selectedItems and canvas.ds (scale, offset)
    DOM-->>BoundsUtil: selected items + transform
    BoundsUtil->>DOM: query node elements by data-node-id, getBoundingClientRect(), footer extents
    DOM-->>BoundsUtil: node rects and footer measurements
    BoundsUtil->>BoundsUtil: convert DOM coords -> canvas/world coords using scale & offset
    BoundsUtil-->>TestRunner: return { selectionBounds, nodeVisualBounds }
    deactivate BoundsUtil
    TestRunner->>Assert: verify selectionBounds non-null and encloses target node bounds
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • AustinMroz
  • DrJKL

Poem

🐰 I hopped through nodes both big and small,
Measured footers, collapsed ones, and all.
With pixels aligned and boxes snug,
Selection wraps tight like a cozy hug.
Hooray — tests passed with a joyful thump!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Adr Compliance For Entity/Litegraph Changes ⚠️ Warning PR violates ADR 0008 and ADR 0003 by adding Vue-specific properties (_footerHeight, _collapsed_height) to core LGraphNode and imperatively mutating them without command pattern compliance. Implement Option B's onBounding callback with vueBoundsOverrides to externalize Vue measurements from LGraphNode, or create a separate measurement component keeping core entity free of Vue-specific responsibilities.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main refactoring work: moving footer layout inline and adjusting node measurement via _footerHeight/_collapsedHeight properties.
Description check ✅ Passed The description comprehensively covers summary, detailed changes across multiple areas, design rationale, test additions, review focus points, and acknowledges limitations and alternatives.
End-To-End Regression Coverage For Fixes ✅ Passed PR uses 'refactor' language (not bug-fix) and changes multiple browser_tests/ files including new test suite selectionBoundingBox.spec.ts with 92 lines of parametrized E2E tests.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/node-footer-inline-layout

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

❤️ Share

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

📦 Bundle: 5.1 MB gzip 🔴 +219 B

Details

Summary

  • Raw size: 23.5 MB baseline 23.5 MB — 🔴 +2.22 kB
  • Gzip: 5.1 MB baseline 5.1 MB — 🔴 +219 B
  • Brotli: 3.95 MB baseline 3.95 MB — 🔴 +62 B
  • Bundles: 250 current • 250 baseline • 114 added / 114 removed

Category Glance
Graph Workspace 🔴 +1.87 kB (1.17 MB) · Data & Services 🔴 +350 B (2.96 MB) · Vendor & Third-Party ⚪ 0 B (9.8 MB) · Other ⚪ 0 B (8.44 MB) · Panels & Settings ⚪ 0 B (484 kB) · Utilities & Hooks ⚪ 0 B (338 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-B6dFwhYY.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +7.95 kB 🔴 +6.82 kB
assets/index-CpeszDFF.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -7.96 kB 🟢 -6.83 kB

Status: 1 added / 1 removed

Graph Workspace — 1.17 MB (baseline 1.17 MB) • 🔴 +1.87 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-Z4bWy2Wy.js (new) 1.17 MB 🔴 +1.17 MB 🔴 +251 kB 🔴 +190 kB
assets/GraphView-DY27Hvqz.js (removed) 1.17 MB 🟢 -1.17 MB 🟢 -251 kB 🟢 -190 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-B0ZX6Nw0.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.4 kB 🟢 -2.9 kB
assets/CloudSurveyView-EiRxnfAH.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.4 kB 🔴 +2.9 kB
assets/CloudLoginView-BgxBgrks.js (new) 12 kB 🔴 +12 kB 🔴 +3.35 kB 🔴 +2.97 kB
assets/CloudLoginView-DQA-14F9.js (removed) 12 kB 🟢 -12 kB 🟢 -3.36 kB 🟢 -2.97 kB
assets/CloudSignupView-BRaQQ4Dn.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.85 kB 🟢 -2.5 kB
assets/CloudSignupView-CX2kfv8S.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.85 kB 🔴 +2.51 kB
assets/UserCheckView-DN99N_ID.js (new) 9.04 kB 🔴 +9.04 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/UserCheckView-DT-sUaUK.js (removed) 9.04 kB 🟢 -9.04 kB 🟢 -2.33 kB 🟢 -2.04 kB
assets/CloudLayoutView-CEKotnDe.js (new) 7.54 kB 🔴 +7.54 kB 🔴 +2.36 kB 🔴 +2.05 kB
assets/CloudLayoutView-vXlBNb1N.js (removed) 7.54 kB 🟢 -7.54 kB 🟢 -2.36 kB 🟢 -2.05 kB
assets/CloudForgotPasswordView-BDsOMUBu.js (removed) 5.94 kB 🟢 -5.94 kB 🟢 -2.1 kB 🟢 -1.85 kB
assets/CloudForgotPasswordView-PkFGMqnW.js (new) 5.94 kB 🔴 +5.94 kB 🔴 +2.09 kB 🔴 +1.86 kB
assets/CloudAuthTimeoutView-DGyYgcMn.js (removed) 5.31 kB 🟢 -5.31 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/CloudAuthTimeoutView-gtSO0rD3.js (new) 5.31 kB 🔴 +5.31 kB 🔴 +1.93 kB 🔴 +1.7 kB
assets/CloudSubscriptionRedirectView-BCu56MRZ.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.91 kB 🟢 -1.69 kB
assets/CloudSubscriptionRedirectView-BfiNzk_X.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.91 kB 🔴 +1.69 kB
assets/UserSelectView-BKD0kfRM.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.74 kB 🔴 +1.54 kB
assets/UserSelectView-CNU7fIxn.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.74 kB 🟢 -1.54 kB

Status: 9 added / 9 removed / 2 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-By7QLiX5.js (new) 46.6 kB 🔴 +46.6 kB 🔴 +9.52 kB 🔴 +8.46 kB
assets/KeybindingPanel-CT7f_nRV.js (removed) 46.6 kB 🟢 -46.6 kB 🟢 -9.52 kB 🟢 -8.47 kB
assets/SecretsPanel-D5Tnt1dP.js (removed) 22.4 kB 🟢 -22.4 kB 🟢 -5.42 kB 🟢 -4.76 kB
assets/SecretsPanel-DE4TF2Km.js (new) 22.4 kB 🔴 +22.4 kB 🔴 +5.42 kB 🔴 +4.76 kB
assets/LegacyCreditsPanel-IelrUo22.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.81 kB 🔴 +5.13 kB
assets/LegacyCreditsPanel-p16jqtJa.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.81 kB 🟢 -5.13 kB
assets/SubscriptionPanel-5m2TD8h-.js (removed) 19.7 kB 🟢 -19.7 kB 🟢 -5.01 kB 🟢 -4.4 kB
assets/SubscriptionPanel-BfzXZdAs.js (new) 19.7 kB 🔴 +19.7 kB 🔴 +5.01 kB 🔴 +4.41 kB
assets/AboutPanel-B190VBh8.js (removed) 12 kB 🟢 -12 kB 🟢 -3.33 kB 🟢 -2.98 kB
assets/AboutPanel-BZw3wmIz.js (new) 12 kB 🔴 +12 kB 🔴 +3.32 kB 🔴 +2.98 kB
assets/ExtensionPanel-_ZLZWgTU.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.82 kB 🔴 +2.51 kB
assets/ExtensionPanel-DhugtJOU.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.82 kB 🟢 -2.51 kB
assets/ServerConfigPanel-Bx4EuJY_.js (new) 6.85 kB 🔴 +6.85 kB 🔴 +2.27 kB 🔴 +2.03 kB
assets/ServerConfigPanel-oX60M4Fa.js (removed) 6.85 kB 🟢 -6.85 kB 🟢 -2.27 kB 🟢 -2.04 kB
assets/UserPanel-C46bKKrH.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.15 kB 🟢 -1.9 kB
assets/UserPanel-CrgW3E9j.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.15 kB 🔴 +1.9 kB
assets/cloudRemoteConfig-B1VOC9TV.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -904 B 🟢 -791 B
assets/cloudRemoteConfig-CkM99Y7g.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +901 B 🔴 +796 B
assets/refreshRemoteConfig-BYQV_Jbg.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -649 B 🟢 -550 B
assets/refreshRemoteConfig-CdnelsVH.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +648 B 🔴 +554 B

Status: 10 added / 10 removed / 12 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-F3v3KhPE.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/auth-jwgluJhM.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.26 kB 🔴 +1.07 kB
assets/SignUpForm-DUpI8CD_.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -1.29 kB 🟢 -1.14 kB
assets/SignUpForm-DZQy3JU3.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +1.28 kB 🔴 +1.14 kB
assets/UpdatePasswordContent-BV0G7qpk.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.19 kB 🔴 +1.06 kB
assets/UpdatePasswordContent-DEFTJxTG.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.19 kB 🟢 -1.06 kB
assets/authStore-D1Sd7V5a.js (new) 989 B 🔴 +989 B 🔴 +481 B 🔴 +424 B
assets/authStore-DTnytIOm.js (removed) 989 B 🟢 -989 B 🟢 -482 B 🟢 -427 B
assets/auth-DH8s7L0b.js (removed) 348 B 🟢 -348 B 🟢 -217 B 🟢 -207 B
assets/auth-ewK7iVBz.js (new) 348 B 🔴 +348 B 🔴 +216 B 🔴 +205 B

Status: 5 added / 5 removed / 2 unchanged

Editors & Dialogs — 109 kB (baseline 109 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useShareDialog-BTsmWEJP.js (new) 108 kB 🔴 +108 kB 🔴 +22.4 kB 🔴 +18.9 kB
assets/useShareDialog-fAjgSyV7.js (removed) 108 kB 🟢 -108 kB 🟢 -22.4 kB 🟢 -18.9 kB
assets/useSubscriptionDialog-CMji_2Li.js (new) 969 B 🔴 +969 B 🔴 +474 B 🔴 +414 B
assets/useSubscriptionDialog-oTC44evn.js (removed) 969 B 🟢 -969 B 🟢 -475 B 🟢 -417 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-aYWNU9om.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.79 kB 🔴 +3.37 kB
assets/ComfyQueueButton-DcRCwC2O.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.79 kB 🟢 -3.38 kB
assets/useTerminalTabs-C0PQUvN5.js (new) 10.7 kB 🔴 +10.7 kB 🔴 +3.6 kB 🔴 +3.16 kB
assets/useTerminalTabs-Dv4MJiJV.js (removed) 10.7 kB 🟢 -10.7 kB 🟢 -3.6 kB 🟢 -3.17 kB
assets/SubscribeButton-C8wrHQ2h.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.05 kB 🔴 +918 B
assets/SubscribeButton-CqddZjQK.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.05 kB 🟢 -916 B
assets/cloudFeedbackTopbarButton-CtqJN3V0.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -844 B 🟢 -760 B
assets/cloudFeedbackTopbarButton-RXg6fMOQ.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +844 B 🔴 +743 B
assets/ComfyQueueButton-DIX0R8ll.js (removed) 1.03 kB 🟢 -1.03 kB 🟢 -490 B 🟢 -441 B
assets/ComfyQueueButton-g-sFHYK2.js (new) 1.03 kB 🔴 +1.03 kB 🔴 +489 B 🔴 +440 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 2.96 MB (baseline 2.96 MB) • 🔴 +350 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-BfXmGT78.js (new) 1.92 MB 🔴 +1.92 MB 🔴 +444 kB 🔴 +336 kB
assets/dialogService-u7biW6L6.js (removed) 1.92 MB 🟢 -1.92 MB 🟢 -444 kB 🟢 -336 kB
assets/api-D9HwMSip.js (new) 886 kB 🔴 +886 kB 🔴 +212 kB 🔴 +167 kB
assets/api-TFHElRie.js (removed) 885 kB 🟢 -885 kB 🟢 -211 kB 🟢 -167 kB
assets/load3dService-CPkmS1Wo.js (new) 92.5 kB 🔴 +92.5 kB 🔴 +19.7 kB 🔴 +17 kB
assets/load3dService-HFOu7qLt.js (removed) 92.5 kB 🟢 -92.5 kB 🟢 -19.7 kB 🟢 -16.9 kB
assets/workflowShareService-AMtjXbCX.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.88 kB 🟢 -4.32 kB
assets/workflowShareService-BnDImJnL.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.88 kB 🔴 +4.32 kB
assets/keybindingService-Cd4fbUlr.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.66 kB 🟢 -3.21 kB
assets/keybindingService-krU3gpwY.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.21 kB
assets/releaseStore-CCQEBSSd.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.28 kB 🔴 +2 kB
assets/releaseStore-DGFb3PGZ.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.28 kB 🟢 -2 kB
assets/userStore-BrerNEqG.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -867 B 🟢 -766 B
assets/userStore-CHFvBGqa.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +869 B 🔴 +769 B
assets/audioService-3PJVG95K.js (removed) 1.8 kB 🟢 -1.8 kB 🟢 -880 B 🟢 -763 B
assets/audioService-CsbalUAt.js (new) 1.8 kB 🔴 +1.8 kB 🔴 +875 B 🔴 +757 B
assets/releaseStore-Bc_5mmMH.js (new) 993 B 🔴 +993 B 🔴 +478 B 🔴 +423 B
assets/releaseStore-swmowNeF.js (removed) 993 B 🟢 -993 B 🟢 -481 B 🟢 -427 B
assets/workflowDraftStore-_2UfQdnc.js (new) 969 B 🔴 +969 B 🔴 +473 B 🔴 +417 B
assets/workflowDraftStore-mz46UBGV.js (removed) 969 B 🟢 -969 B 🟢 -475 B 🟢 -424 B
assets/dialogService-BrBf0AFT.js (new) 958 B 🔴 +958 B 🔴 +467 B 🔴 +413 B
assets/dialogService-C-o5zS_0.js (removed) 958 B 🟢 -958 B 🟢 -467 B 🟢 -418 B
assets/settingStore-2cuu9RHc.js (new) 956 B 🔴 +956 B 🔴 +469 B 🔴 +413 B
assets/settingStore-BGMnlXl7.js (removed) 956 B 🟢 -956 B 🟢 -470 B 🟢 -414 B
assets/assetsStore-BLINPcU8.js (removed) 955 B 🟢 -955 B 🟢 -470 B 🟢 -418 B
assets/assetsStore-BVQJagka.js (new) 955 B 🔴 +955 B 🔴 +468 B 🔴 +413 B

Status: 13 added / 13 removed / 4 unchanged

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-CG4GnDPH.js (new) 232 kB 🔴 +232 kB 🔴 +51.3 kB 🔴 +41.8 kB
assets/useConflictDetection-eI2r5zIF.js (removed) 232 kB 🟢 -232 kB 🟢 -51.3 kB 🟢 -41.7 kB
assets/useLoad3dViewer-bHHquv0j.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.44 kB 🟢 -3.87 kB
assets/useLoad3dViewer-BYBztWoL.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.44 kB 🔴 +3.87 kB
assets/useLoad3d-8Nd6pXwD.js (new) 15 kB 🔴 +15 kB 🔴 +3.79 kB 🔴 +3.36 kB
assets/useLoad3d-CdMKXe69.js (removed) 15 kB 🟢 -15 kB 🟢 -3.79 kB 🟢 -3.36 kB
assets/useFeatureFlags-BoNVpQYz.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.75 kB 🟢 -1.48 kB
assets/useFeatureFlags-OSJOpEqF.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.75 kB 🔴 +1.48 kB
assets/useCopyToClipboard-BDI_ZFlU.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/useCopyToClipboard-DfnnpsNs.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/useWorkspaceUI-B2uO4HBP.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +981 B 🔴 +813 B
assets/useWorkspaceUI-D8Mj7I9K.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -982 B 🟢 -810 B
assets/subscriptionCheckoutUtil-BSzVtEh2.js (new) 2.97 kB 🔴 +2.97 kB 🔴 +1.31 kB 🔴 +1.14 kB
assets/subscriptionCheckoutUtil-D8kP4F50.js (removed) 2.97 kB 🟢 -2.97 kB 🟢 -1.31 kB 🟢 -1.14 kB
assets/assetPreviewUtil-BD9PS-bn.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +959 B 🔴 +834 B
assets/assetPreviewUtil-DzvrYiBc.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -957 B 🟢 -834 B
assets/useUpstreamValue-C3nEW2kw.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -805 B 🟢 -713 B
assets/useUpstreamValue-DPT4Jxbt.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +805 B 🔴 +714 B
assets/useLoad3d-C1COPK33.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -538 B 🟢 -482 B
assets/useLoad3d-CxrNG6ob.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +538 B 🔴 +474 B
assets/useLoad3dViewer-aE6X6U3v.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +504 B 🔴 +452 B
assets/useLoad3dViewer-CYYbLGAS.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -506 B 🟢 -456 B
assets/useCurrentUser-D3G8Enjp.js (removed) 955 B 🟢 -955 B 🟢 -471 B 🟢 -416 B
assets/useCurrentUser-DsyQnHJ-.js (new) 955 B 🔴 +955 B 🔴 +469 B 🔴 +413 B
assets/useWorkspaceSwitch-BtUVM0B2.js (removed) 747 B 🟢 -747 B 🟢 -385 B 🟢 -336 B
assets/useWorkspaceSwitch-CN7EKmIi.js (new) 747 B 🔴 +747 B 🔴 +387 B 🔴 +334 B

Status: 13 added / 13 removed / 13 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 8.44 MB (baseline 8.44 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-C8tvj6Px.js (removed) 76.8 kB 🟢 -76.8 kB 🟢 -19.9 kB 🟢 -16.9 kB
assets/core-CJnViYPC.js (new) 76.8 kB 🔴 +76.8 kB 🔴 +19.9 kB 🔴 +16.9 kB
assets/groupNode-BNsivjV2.js (new) 74 kB 🔴 +74 kB 🔴 +18.5 kB 🔴 +16.3 kB
assets/groupNode-CZpkX845.js (removed) 74 kB 🟢 -74 kB 🟢 -18.5 kB 🟢 -16.3 kB
assets/WidgetSelect-BDAtGZF-.js (new) 64.6 kB 🔴 +64.6 kB 🔴 +14.1 kB 🔴 +12.1 kB
assets/WidgetSelect-DBrrSLP-.js (removed) 64.6 kB 🟢 -64.6 kB 🟢 -14.1 kB 🟢 -12.2 kB
assets/SubscriptionRequiredDialogContentWorkspace-DBPfjRel.js (new) 48.9 kB 🔴 +48.9 kB 🔴 +9.29 kB 🔴 +7.92 kB
assets/SubscriptionRequiredDialogContentWorkspace-DgY_9_Na.js (removed) 48.9 kB 🟢 -48.9 kB 🟢 -9.29 kB 🟢 -7.97 kB
assets/WidgetPainter-Bn9D17e8.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -8.11 kB 🟢 -7.2 kB
assets/WidgetPainter-BS9dqqQJ.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +8.12 kB 🔴 +7.2 kB
assets/Load3DControls-B4ZB1lO_.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -5.47 kB 🟢 -4.76 kB
assets/Load3DControls-COOu2OvU.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +5.47 kB 🔴 +4.75 kB
assets/WorkspacePanelContent-Dj6xAJSj.js (new) 29.9 kB 🔴 +29.9 kB 🔴 +6.33 kB 🔴 +5.57 kB
assets/WorkspacePanelContent-DRDrYvDr.js (removed) 29.9 kB 🟢 -29.9 kB 🟢 -6.33 kB 🟢 -5.56 kB
assets/SubscriptionRequiredDialogContent-C_eWfPDM.js (new) 28.2 kB 🔴 +28.2 kB 🔴 +7.17 kB 🔴 +6.31 kB
assets/SubscriptionRequiredDialogContent-DjLw33Pi.js (removed) 28.2 kB 🟢 -28.2 kB 🟢 -7.17 kB 🟢 -6.3 kB
assets/Load3dViewerContent-C7t2nnoR.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -5.32 kB 🟢 -4.63 kB
assets/Load3dViewerContent-oDUiaF6R.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +5.32 kB 🔴 +4.63 kB
assets/WidgetImageCrop-CaeegJUw.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.83 kB 🟢 -5.14 kB
assets/WidgetImageCrop-P24DMOVT.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.83 kB 🔴 +5.14 kB
assets/SubscriptionPanelContentWorkspace-Dp7gFhyB.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.18 kB 🟢 -4.55 kB
assets/SubscriptionPanelContentWorkspace-hSfTD0OE.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.55 kB
assets/SignInContent-CQ13ksjG.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.29 kB 🔴 +4.63 kB
assets/SignInContent-Dzce8g9S.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.29 kB 🟢 -4.64 kB
assets/CurrentUserPopoverWorkspace-6QZONaMr.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -4.83 kB 🟢 -4.32 kB
assets/CurrentUserPopoverWorkspace-Bv86iypb.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +4.83 kB 🔴 +4.33 kB
assets/WidgetInputNumber-BnXd3NEf.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.84 kB 🟢 -4.3 kB
assets/WidgetInputNumber-Ds6WOGVb.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.3 kB
assets/WidgetRecordAudio-D8f78vXD.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +5.18 kB 🔴 +4.64 kB
assets/WidgetRecordAudio-lT_fd94Z.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -5.18 kB 🟢 -4.64 kB
assets/Load3D-CRdmaEhe.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.11 kB 🔴 +3.58 kB
assets/Load3D-DRbNWiDS.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.11 kB 🟢 -3.59 kB
assets/load3d-jPViyVZQ.js (removed) 15 kB 🟢 -15 kB 🟢 -4.32 kB 🟢 -3.74 kB
assets/load3d-RWaLy-ix.js (new) 15 kB 🔴 +15 kB 🔴 +4.32 kB 🔴 +3.73 kB
assets/WaveAudioPlayer-L-z3P6nl.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.68 kB 🔴 +3.22 kB
assets/WaveAudioPlayer-XpqHOFAU.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.69 kB 🟢 -3.22 kB
assets/WidgetCurve-BbiK3U3v.js (new) 12 kB 🔴 +12 kB 🔴 +3.85 kB 🔴 +3.48 kB
assets/WidgetCurve-vlDmdm93.js (removed) 12 kB 🟢 -12 kB 🟢 -3.85 kB 🟢 -3.48 kB
assets/TeamWorkspacesDialogContent-BDNNNTRF.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +3.34 kB 🔴 +2.96 kB
assets/TeamWorkspacesDialogContent-DbuMQomK.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -3.33 kB 🟢 -2.96 kB
assets/nodeTemplates-C7bpzn6q.js (new) 9.58 kB 🔴 +9.58 kB 🔴 +3.37 kB 🔴 +2.97 kB
assets/nodeTemplates-Do56Ph9w.js (removed) 9.58 kB 🟢 -9.58 kB 🟢 -3.38 kB 🟢 -2.97 kB
assets/InviteMemberDialogContent-BbKcdqhu.js (new) 7.77 kB 🔴 +7.77 kB 🔴 +2.45 kB 🔴 +2.15 kB
assets/InviteMemberDialogContent-SGxAc6O6.js (removed) 7.77 kB 🟢 -7.77 kB 🟢 -2.45 kB 🟢 -2.14 kB
assets/Load3DConfiguration-CRZhBCoG.js (new) 6.6 kB 🔴 +6.6 kB 🔴 +2.04 kB 🔴 +1.78 kB
assets/Load3DConfiguration-Z2eYwWdb.js (removed) 6.6 kB 🟢 -6.6 kB 🟢 -2.04 kB 🟢 -1.78 kB
assets/onboardingCloudRoutes-CnjojtFO.js (new) 6.53 kB 🔴 +6.53 kB 🔴 +2.04 kB 🔴 +1.76 kB
assets/onboardingCloudRoutes-CSfsTDBJ.js (removed) 6.53 kB 🟢 -6.53 kB 🟢 -2.04 kB 🟢 -1.75 kB
assets/WidgetWithControl-Cyoc1DcE.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.38 kB 🔴 +2.12 kB
assets/WidgetWithControl-WubSuwvs.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.38 kB 🟢 -2.11 kB
assets/CreateWorkspaceDialogContent-afuTnRbD.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +2.15 kB 🔴 +1.88 kB
assets/CreateWorkspaceDialogContent-AHJLRglI.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -2.15 kB 🟢 -1.87 kB
assets/FreeTierDialogContent-Bv3JdptN.js (new) 5.82 kB 🔴 +5.82 kB 🔴 +2.05 kB 🔴 +1.8 kB
assets/FreeTierDialogContent-CZGjzCkR.js (removed) 5.82 kB 🟢 -5.82 kB 🟢 -2.05 kB 🟢 -1.8 kB
assets/EditWorkspaceDialogContent-Dide1kJ2.js (removed) 5.75 kB 🟢 -5.75 kB 🟢 -2.11 kB 🟢 -1.84 kB
assets/EditWorkspaceDialogContent-pB--EAMn.js (new) 5.75 kB 🔴 +5.75 kB 🔴 +2.11 kB 🔴 +1.84 kB
assets/WidgetTextarea-CSTVJw00.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +2.17 kB 🔴 +1.93 kB
assets/WidgetTextarea-rAJK-EnC.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -2.17 kB 🟢 -1.91 kB
assets/Preview3d-BLR1B8mh.js (removed) 5.36 kB 🟢 -5.36 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/Preview3d-leFfP1WJ.js (new) 5.36 kB 🔴 +5.36 kB 🔴 +1.79 kB 🔴 +1.56 kB
assets/ValueControlPopover-BeBrcEn4.js (removed) 5.33 kB 🟢 -5.33 kB 🟢 -1.93 kB 🟢 -1.73 kB
assets/ValueControlPopover-qu-9y5-r.js (new) 5.33 kB 🔴 +5.33 kB 🔴 +1.93 kB 🔴 +1.72 kB
assets/CancelSubscriptionDialogContent-C-pJtoN7.js (new) 5.22 kB 🔴 +5.22 kB 🔴 +1.95 kB 🔴 +1.7 kB
assets/CancelSubscriptionDialogContent-CjHM5qwl.js (removed) 5.22 kB 🟢 -5.22 kB 🟢 -1.95 kB 🟢 -1.71 kB
assets/DeleteWorkspaceDialogContent-DKQbjtnj.js (removed) 4.65 kB 🟢 -4.65 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/DeleteWorkspaceDialogContent-gI6-3LXL.js (new) 4.65 kB 🔴 +4.65 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/LeaveWorkspaceDialogContent-CDMDzH1J.js (removed) 4.48 kB 🟢 -4.48 kB 🟢 -1.74 kB 🟢 -1.51 kB
assets/LeaveWorkspaceDialogContent-wBD8j6SX.js (new) 4.48 kB 🔴 +4.48 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/RemoveMemberDialogContent-B_80cOEE.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.69 kB 🟢 -1.47 kB
assets/RemoveMemberDialogContent-C6lfYdJ8.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.69 kB 🔴 +1.47 kB
assets/tierBenefits-CwymHnfM.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.57 kB 🔴 +1.36 kB
assets/tierBenefits-DjgEkZ1-.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.58 kB 🟢 -1.36 kB
assets/RevokeInviteDialogContent-BVQzGrpq.js (removed) 4.37 kB 🟢 -4.37 kB 🟢 -1.7 kB 🟢 -1.49 kB
assets/RevokeInviteDialogContent-BwuShvsr.js (new) 4.37 kB 🔴 +4.37 kB 🔴 +1.7 kB 🔴 +1.49 kB
assets/InviteMemberUpsellDialogContent-C_hk-wXT.js (new) 4.27 kB 🔴 +4.27 kB 🔴 +1.56 kB 🔴 +1.36 kB
assets/InviteMemberUpsellDialogContent-DpcRj1KR.js (removed) 4.27 kB 🟢 -4.27 kB 🟢 -1.56 kB 🟢 -1.36 kB
assets/cloudSessionCookie-7WthrIGk.js (removed) 4.12 kB 🟢 -4.12 kB 🟢 -1.49 kB 🟢 -1.29 kB
assets/cloudSessionCookie-DkqoIQsW.js (new) 4.12 kB 🔴 +4.12 kB 🔴 +1.49 kB 🔴 +1.29 kB
assets/saveMesh-BEWgNNrM.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.68 kB 🔴 +1.48 kB
assets/saveMesh-CH6pJuqe.js (removed) 3.92 kB 🟢 -3.92 kB 🟢 -1.68 kB 🟢 -1.48 kB
assets/Media3DTop-D080LOol.js (new) 3.85 kB 🔴 +3.85 kB 🔴 +1.62 kB 🔴 +1.43 kB
assets/Media3DTop-DqeX9Hlz.js (removed) 3.85 kB 🟢 -3.85 kB 🟢 -1.62 kB 🟢 -1.43 kB
assets/GlobalToast-DC96TkDC.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.07 kB
assets/GlobalToast-xHIFxRQT.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/SubscribeToRun-Dhi4D7qc.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -982 B 🟢 -869 B
assets/SubscribeToRun-gSMi53cQ.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +982 B 🔴 +867 B
assets/MediaAudioTop-Be2VMzo1.js (removed) 2.02 kB 🟢 -2.02 kB 🟢 -982 B 🟢 -831 B
assets/MediaAudioTop-zBB9mExS.js (new) 2.02 kB 🔴 +2.02 kB 🔴 +981 B 🔴 +832 B
assets/CloudRunButtonWrapper-DfKaCF-8.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -912 B 🟢 -807 B
assets/CloudRunButtonWrapper-ye2Hu9x8.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +913 B 🔴 +802 B
assets/graphHasMissingNodes-ClMuCUus.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -858 B 🟢 -756 B
assets/graphHasMissingNodes-Cno6ffg_.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +859 B 🔴 +752 B
assets/cloudBadges-BRhtl1_l.js (removed) 1.77 kB 🟢 -1.77 kB 🟢 -890 B 🟢 -770 B
assets/cloudBadges-CLEJmm0s.js (new) 1.77 kB 🔴 +1.77 kB 🔴 +890 B 🔴 +770 B
assets/cloudSubscription-BGzYuaAl.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -813 B 🟢 -700 B
assets/cloudSubscription-Budff_vL.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +813 B 🔴 +699 B
assets/previousFullPath-BqQTzwiM.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +696 B 🔴 +602 B
assets/previousFullPath-BXkm4b8a.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -695 B 🟢 -618 B
assets/Load3D-ByZ83iES.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +613 B 🔴 +547 B
assets/Load3D-Cfm2t_Kx.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -611 B 🟢 -543 B
assets/nightlyBadges-BPk8UYdt.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +657 B 🔴 +583 B
assets/nightlyBadges-CeOHriGL.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -658 B 🟢 -575 B
assets/Load3dViewerContent-BweU9nCL.js (new) 1.23 kB 🔴 +1.23 kB 🔴 +564 B 🔴 +501 B
assets/Load3dViewerContent-ZlnxRUDT.js (removed) 1.23 kB 🟢 -1.23 kB 🟢 -565 B 🟢 -498 B
assets/SubscriptionPanelContentWorkspace-B8vhw9nS.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -536 B 🟢 -468 B
assets/SubscriptionPanelContentWorkspace-Dyf_CPfd.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +537 B 🔴 +467 B
assets/WidgetLegacy--4ohidH1.js (removed) 978 B 🟢 -978 B 🟢 -482 B 🟢 -423 B
assets/WidgetLegacy-BCzs-DlG.js (new) 978 B 🔴 +978 B 🔴 +481 B 🔴 +421 B
assets/changeTracker-BI6x-uFx.js (removed) 952 B 🟢 -952 B 🟢 -470 B 🟢 -414 B
assets/changeTracker-DhvzLXL1.js (new) 952 B 🔴 +952 B 🔴 +469 B 🔴 +410 B

Status: 55 added / 55 removed / 79 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.2 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.9 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.3 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.1 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.3 MB heap
large-graph-pan: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.6 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.9 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.2 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 46.9 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.1 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.4 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 73.9 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 154.7 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 154.2 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 46.2 MB heap

⚠️ 5 regressions detected

Metric Baseline PR (median) Δ Sig
canvas-idle: script duration 31ms 31ms -0% ⚠️ z=2.4
canvas-mouse-sweep: layout duration 4ms 4ms +12% ⚠️ z=2.7
minimap-idle: task duration 680ms 633ms -7% ⚠️ z=2.2
subgraph-idle: style recalc duration 11ms 13ms +20% ⚠️ z=3.8
subgraph-mouse-sweep: task duration 977ms 974ms -0% ⚠️ z=3.0
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.9
canvas-idle: p95 frame time 17ms 17ms +0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 11ms 10ms -7% z=-0.8
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 11 11 +0% z=-0.3
canvas-idle: task duration 450ms 420ms -7% z=0.8
canvas-idle: script duration 31ms 31ms -0% ⚠️ z=2.4
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 60.2 MB 60.2 MB +0%
canvas-idle: DOM nodes 22 22 +0% z=-0.5
canvas-idle: event listeners 6 6 +0% z=-1.2
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +1%
canvas-mouse-sweep: layout duration 4ms 4ms +12% ⚠️ z=2.7
canvas-mouse-sweep: style recalc duration 45ms 42ms -6% z=-0.2
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 81 77 -5% z=-0.7
canvas-mouse-sweep: task duration 993ms 833ms -16% z=-0.6
canvas-mouse-sweep: script duration 140ms 130ms -7% z=-0.8
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 56.7 MB 56.9 MB +0%
canvas-mouse-sweep: DOM nodes 66 61 -8% z=-0.5
canvas-mouse-sweep: event listeners 6 4 -33% z=-1.1
canvas-zoom-sweep: avg frame time 17ms 17ms +0% z=0.5
canvas-zoom-sweep: p95 frame time 17ms 17ms +0%
canvas-zoom-sweep: layout duration 1ms 1ms +8% z=1.9
canvas-zoom-sweep: style recalc duration 20ms 19ms -5% z=-0.3
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 31 +0% z=-0.6
canvas-zoom-sweep: task duration 348ms 353ms +1% z=1.1
canvas-zoom-sweep: script duration 34ms 32ms -5% z=1.7
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 64.1 MB 64.3 MB +0%
canvas-zoom-sweep: DOM nodes 78 78 +0% z=-1.6
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
dom-widget-clipping: p95 frame time 17ms 17ms +0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 9ms 10ms +3% z=-0.3
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 13 13 +0% z=-0.2
dom-widget-clipping: task duration 380ms 361ms -5% z=-0.2
dom-widget-clipping: script duration 73ms 63ms -14% z=-1.4
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 47.0 MB 47.1 MB +0%
dom-widget-clipping: DOM nodes 22 22 +0% z=-0.1
dom-widget-clipping: event listeners 2 2 +0% variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=-0.2
large-graph-idle: p95 frame time 17ms 17ms +0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 10ms 10ms -3% z=-2.2
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 10 11 +10% z=-1.9
large-graph-idle: task duration 630ms 625ms -1% z=1.5
large-graph-idle: script duration 124ms 102ms -18% z=-0.1
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 53.2 MB 52.3 MB -2%
large-graph-idle: DOM nodes -257 -258 +0% z=-312.8
large-graph-idle: event listeners -127 -125 -2% z=-24.8
large-graph-pan: avg frame time 17ms 17ms -0% z=-0.8
large-graph-pan: p95 frame time 17ms 17ms -1%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 18ms 16ms -12% z=-2.2
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 70 68 -3% z=-2.4
large-graph-pan: task duration 1188ms 1165ms -2% z=1.9
large-graph-pan: script duration 426ms 386ms -9% z=-1.1
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 67.4 MB 65.6 MB -3%
large-graph-pan: DOM nodes -258 -262 +2% z=-170.3
large-graph-pan: event listeners -127 -125 -2% z=-156.9
large-graph-zoom: avg frame time 17ms 17ms +0%
large-graph-zoom: p95 frame time 17ms 17ms -1%
large-graph-zoom: layout duration 8ms 8ms +6%
large-graph-zoom: style recalc duration 17ms 18ms +4%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 66 66 +0%
large-graph-zoom: task duration 1408ms 1391ms -1%
large-graph-zoom: script duration 513ms 489ms -5%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 58.8 MB 58.9 MB +0%
large-graph-zoom: DOM nodes -263 -263 +0%
large-graph-zoom: event listeners -123 -123 +0%
minimap-idle: avg frame time 17ms 17ms +0% z=-0.9
minimap-idle: p95 frame time 17ms 17ms +0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 11ms 10ms -9% z=0.2
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 10 10 +0% z=0.6
minimap-idle: task duration 680ms 633ms -7% ⚠️ z=2.2
minimap-idle: script duration 124ms 102ms -17% z=0.4
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 54.5 MB 54.2 MB -1%
minimap-idle: DOM nodes -259 -258 -0% z=-202.6
minimap-idle: event listeners -127 -125 -2% z=-196.2
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 12ms 13ms +10% z=0.7
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 47 49 +4% z=1.8
subgraph-dom-widget-clipping: task duration 378ms 387ms +2% z=0.5
subgraph-dom-widget-clipping: script duration 130ms 125ms -3% z=-0.5
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 47.3 MB 46.9 MB -1%
subgraph-dom-widget-clipping: DOM nodes 20 23 +15% z=0.7
subgraph-dom-widget-clipping: event listeners 8 8 +0% z=-1.4
subgraph-idle: avg frame time 17ms 17ms +0% z=0.4
subgraph-idle: p95 frame time 17ms 17ms -1%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 11ms 13ms +20% ⚠️ z=3.8
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 11 12 +9% z=1.7
subgraph-idle: task duration 426ms 412ms -3% z=1.3
subgraph-idle: script duration 26ms 25ms -3% z=1.9
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 60.3 MB 60.1 MB -0%
subgraph-idle: DOM nodes 22 23 +5% z=0.8
subgraph-idle: event listeners 6 6 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms +0% z=1.2
subgraph-mouse-sweep: p95 frame time 17ms 17ms +1%
subgraph-mouse-sweep: layout duration 5ms 5ms +7% z=0.5
subgraph-mouse-sweep: style recalc duration 48ms 49ms +3% z=2.0
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 83 85 +2% z=2.5
subgraph-mouse-sweep: task duration 977ms 974ms -0% ⚠️ z=3.0
subgraph-mouse-sweep: script duration 112ms 98ms -12% z=-0.4
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 52.4 MB 52.4 MB -0%
subgraph-mouse-sweep: DOM nodes 72 73 +1% z=2.7
subgraph-mouse-sweep: event listeners 6 6 +0% variance too high
viewport-pan-sweep: avg frame time 17ms 17ms -0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 46ms 47ms +1%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 251 251 +0%
viewport-pan-sweep: task duration 3885ms 4083ms +5%
viewport-pan-sweep: script duration 1277ms 1329ms +4%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 75.3 MB 73.9 MB -2%
viewport-pan-sweep: DOM nodes -255 -256 +0%
viewport-pan-sweep: event listeners -111 -111 +0%
vue-large-graph-idle: avg frame time 17ms 17ms +0%
vue-large-graph-idle: p95 frame time 17ms 17ms -1%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 13107ms 10788ms -18%
vue-large-graph-idle: script duration 641ms 581ms -9%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 157.6 MB 154.7 MB -2%
vue-large-graph-idle: DOM nodes -8331 -8331 +0%
vue-large-graph-idle: event listeners -16464 -16468 +0%
vue-large-graph-pan: avg frame time 18ms 17ms -3%
vue-large-graph-pan: p95 frame time 17ms 17ms +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 16ms 15ms -3%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 68 65 -4%
vue-large-graph-pan: task duration 14794ms 12737ms -14%
vue-large-graph-pan: script duration 910ms 846ms -7%
vue-large-graph-pan: TBT 0ms 0ms +0%
vue-large-graph-pan: heap used 164.5 MB 154.2 MB -6%
vue-large-graph-pan: DOM nodes -8331 -8332 +0%
vue-large-graph-pan: event listeners -16461 -16464 +0%
workflow-execution: avg frame time 17ms 17ms +0% z=0.6
workflow-execution: p95 frame time 17ms 17ms +0%
workflow-execution: layout duration 1ms 2ms +12% z=0.6
workflow-execution: style recalc duration 26ms 24ms -5% z=0.0
workflow-execution: layout count 5 5 +0% z=0.1
workflow-execution: style recalc count 17 18 +6% z=0.1
workflow-execution: task duration 132ms 132ms -0% z=0.8
workflow-execution: script duration 31ms 31ms -1% z=0.6
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 46.4 MB 46.2 MB -0%
workflow-execution: DOM nodes 156 158 +1% z=-0.4
workflow-execution: event listeners 71 71 +0% z=4.4
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-03-30T08:56:54.664Z",
  "gitSha": "9c8c08b5354eae3602b6c2f507414e36c3f8327b",
  "branch": "refactor/node-footer-inline-layout",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2024.6319999999969,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.323000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 465.24899999999997,
      "heapDeltaBytes": 20337880,
      "heapUsedBytes": 63063240,
      "domNodes": 22,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 31.797,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2048.004999999989,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.145000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 419.74999999999994,
      "heapDeltaBytes": 20891404,
      "heapUsedBytes": 64809700,
      "domNodes": 22,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 24.380000000000006,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2037.3749999999973,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.073,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 420.12899999999996,
      "heapDeltaBytes": 20376024,
      "heapUsedBytes": 63109408,
      "domNodes": 22,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 30.523000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1960.5140000000176,
      "styleRecalcs": 79,
      "styleRecalcDurationMs": 54.187000000000005,
      "layouts": 12,
      "layoutDurationMs": 4.689,
      "taskDurationMs": 930.087,
      "heapDeltaBytes": 16653852,
      "heapUsedBytes": 60778504,
      "domNodes": 64,
      "jsHeapTotalBytes": 23855104,
      "scriptDurationMs": 151.76700000000002,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1862.0270000000119,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 42.013000000000005,
      "layouts": 12,
      "layoutDurationMs": 4.132000000000001,
      "taskDurationMs": 832.615,
      "heapDeltaBytes": 6934000,
      "heapUsedBytes": 59624552,
      "domNodes": 61,
      "jsHeapTotalBytes": 25952256,
      "scriptDurationMs": 130.154,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1797.099000000003,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 37.331,
      "layouts": 12,
      "layoutDurationMs": 3.488,
      "taskDurationMs": 819.863,
      "heapDeltaBytes": 15786128,
      "heapUsedBytes": 59643376,
      "domNodes": 58,
      "jsHeapTotalBytes": 23592960,
      "scriptDurationMs": 126.94,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1732.3080000000175,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 18.617999999999995,
      "layouts": 6,
      "layoutDurationMs": 0.7299999999999998,
      "taskDurationMs": 352.785,
      "heapDeltaBytes": 24703464,
      "heapUsedBytes": 67395824,
      "domNodes": 77,
      "jsHeapTotalBytes": 20447232,
      "scriptDurationMs": 32.073,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1743.9489999999864,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 18.528999999999996,
      "layouts": 6,
      "layoutDurationMs": 0.7559999999999999,
      "taskDurationMs": 353.086,
      "heapDeltaBytes": 24660884,
      "heapUsedBytes": 67423304,
      "domNodes": 79,
      "jsHeapTotalBytes": 20709376,
      "scriptDurationMs": 32.571,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1746.1849999999686,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 19.206,
      "layouts": 6,
      "layoutDurationMs": 0.7160000000000001,
      "taskDurationMs": 352.73299999999995,
      "heapDeltaBytes": 24672376,
      "heapUsedBytes": 67386104,
      "domNodes": 78,
      "jsHeapTotalBytes": 20971520,
      "scriptDurationMs": 29.184,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 571.1009999999987,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 10.199,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 358.00399999999996,
      "heapDeltaBytes": 6047748,
      "heapUsedBytes": 48985256,
      "domNodes": 22,
      "jsHeapTotalBytes": 13631488,
      "scriptDurationMs": 61.155,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.669999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 581.3499999999863,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 9.454999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 368.366,
      "heapDeltaBytes": 6701988,
      "heapUsedBytes": 50498236,
      "domNodes": 21,
      "jsHeapTotalBytes": 13631488,
      "scriptDurationMs": 63.120999999999995,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 559.6700000000965,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 9.644000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 361.439,
      "heapDeltaBytes": 6837116,
      "heapUsedBytes": 49375824,
      "domNodes": 22,
      "jsHeapTotalBytes": 12582912,
      "scriptDurationMs": 63.154,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2036.151999999987,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.881999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 636.8929999999999,
      "heapDeltaBytes": 2548860,
      "heapUsedBytes": 53392636,
      "domNodes": -256,
      "jsHeapTotalBytes": 14876672,
      "scriptDurationMs": 101.724,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2029.1189999999801,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.8790000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 582.7869999999999,
      "heapDeltaBytes": 2643380,
      "heapUsedBytes": 54876468,
      "domNodes": -261,
      "jsHeapTotalBytes": 15925248,
      "scriptDurationMs": 90.72800000000001,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2038.0930000000035,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.662999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 624.952,
      "heapDeltaBytes": 4858644,
      "heapUsedBytes": 55869880,
      "domNodes": -258,
      "jsHeapTotalBytes": 16449536,
      "scriptDurationMs": 102.113,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2180.2749999999946,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 17.038,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1209.875,
      "heapDeltaBytes": 18242656,
      "heapUsedBytes": 71167816,
      "domNodes": -260,
      "jsHeapTotalBytes": 17702912,
      "scriptDurationMs": 406.826,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2125.684999999976,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 13.724,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1165.4940000000001,
      "heapDeltaBytes": 15254568,
      "heapUsedBytes": 68741360,
      "domNodes": -270,
      "jsHeapTotalBytes": 18227200,
      "scriptDurationMs": 386.247,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2140.423999999939,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 15.537000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1122.889,
      "heapDeltaBytes": 15174096,
      "heapUsedBytes": 68571068,
      "domNodes": -262,
      "jsHeapTotalBytes": 18489344,
      "scriptDurationMs": 380.85,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3265.7299999999905,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 19.616000000000003,
      "layouts": 60,
      "layoutDurationMs": 8.418,
      "taskDurationMs": 1439.873,
      "heapDeltaBytes": 8501740,
      "heapUsedBytes": 64286516,
      "domNodes": -261,
      "jsHeapTotalBytes": 17555456,
      "scriptDurationMs": 500.757,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3201.233000000002,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 16.047,
      "layouts": 60,
      "layoutDurationMs": 8.103000000000002,
      "taskDurationMs": 1387.0090000000002,
      "heapDeltaBytes": 4113064,
      "heapUsedBytes": 58830812,
      "domNodes": -265,
      "jsHeapTotalBytes": 17235968,
      "scriptDurationMs": 474.31499999999994,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3211.3460000000487,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 18.017,
      "layouts": 60,
      "layoutDurationMs": 8.213,
      "taskDurationMs": 1390.8039999999999,
      "heapDeltaBytes": 7456020,
      "heapUsedBytes": 61780528,
      "domNodes": -263,
      "jsHeapTotalBytes": 18022400,
      "scriptDurationMs": 488.633,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2051.296999999977,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.764000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 632.6700000000001,
      "heapDeltaBytes": 4689080,
      "heapUsedBytes": 57516944,
      "domNodes": -259,
      "jsHeapTotalBytes": 16187392,
      "scriptDurationMs": 102.40900000000002,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2040.0070000000028,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 9.423999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 633.345,
      "heapDeltaBytes": 4636836,
      "heapUsedBytes": 56815968,
      "domNodes": -258,
      "jsHeapTotalBytes": 15663104,
      "scriptDurationMs": 101.096,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "minimap-idle",
      "durationMs": 2036.514000000011,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 12.275,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 606.8690000000001,
      "heapDeltaBytes": 3030380,
      "heapUsedBytes": 55252808,
      "domNodes": -256,
      "jsHeapTotalBytes": 15663104,
      "scriptDurationMs": 102.45199999999998,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 572.8289999999845,
      "styleRecalcs": 49,
      "styleRecalcDurationMs": 13.655000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 383.783,
      "heapDeltaBytes": 6448664,
      "heapUsedBytes": 49209304,
      "domNodes": 23,
      "jsHeapTotalBytes": 12845056,
      "scriptDurationMs": 125.29499999999999,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 573.8289999999893,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 11.65,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 393.043,
      "heapDeltaBytes": 6512008,
      "heapUsedBytes": 49540724,
      "domNodes": 20,
      "jsHeapTotalBytes": 13369344,
      "scriptDurationMs": 128.47,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 601.5129999999544,
      "styleRecalcs": 49,
      "styleRecalcDurationMs": 13.331000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 386.774,
      "heapDeltaBytes": 6217780,
      "heapUsedBytes": 49202056,
      "domNodes": 24,
      "jsHeapTotalBytes": 14155776,
      "scriptDurationMs": 125.336,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2050.0749999999925,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 13.403999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 422.86400000000003,
      "heapDeltaBytes": 20169868,
      "heapUsedBytes": 63233192,
      "domNodes": 20,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 27.373999999999995,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2020.7139999999981,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 11.584000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 411.974,
      "heapDeltaBytes": 20008000,
      "heapUsedBytes": 62980012,
      "domNodes": 23,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 25.123,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2031.3190000000532,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 13.519000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 406.58099999999996,
      "heapDeltaBytes": 19981580,
      "heapUsedBytes": 62650724,
      "domNodes": 23,
      "jsHeapTotalBytes": 22282240,
      "scriptDurationMs": 25.169999999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1998.061999999976,
      "styleRecalcs": 85,
      "styleRecalcDurationMs": 49.020999999999994,
      "layouts": 16,
      "layoutDurationMs": 4.869,
      "taskDurationMs": 973.7040000000002,
      "heapDeltaBytes": 11846708,
      "heapUsedBytes": 54536796,
      "domNodes": 73,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 106.9,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1696.7089999999985,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 40.498,
      "layouts": 16,
      "layoutDurationMs": 5.157,
      "taskDurationMs": 740.518,
      "heapDeltaBytes": 12264240,
      "heapUsedBytes": 56483920,
      "domNodes": 63,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 98.482,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1994.9430000000348,
      "styleRecalcs": 85,
      "styleRecalcDurationMs": 50.263000000000005,
      "layouts": 16,
      "layoutDurationMs": 4.722,
      "taskDurationMs": 973.623,
      "heapDeltaBytes": 11917520,
      "heapUsedBytes": 54907992,
      "domNodes": 73,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 98.36200000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8174.977999999982,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 47.023999999999994,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4345.768999999999,
      "heapDeltaBytes": 32059232,
      "heapUsedBytes": 82619684,
      "domNodes": -256,
      "jsHeapTotalBytes": 25829376,
      "scriptDurationMs": 1459.339,
      "eventListeners": -105,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8182.164999999997,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 46.002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4082.739,
      "heapDeltaBytes": 17263732,
      "heapUsedBytes": 68556056,
      "domNodes": -256,
      "jsHeapTotalBytes": 20062208,
      "scriptDurationMs": 1290.166,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8200.67599999993,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 46.517,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4078.15,
      "heapDeltaBytes": 27025504,
      "heapUsedBytes": 77484108,
      "domNodes": -257,
      "jsHeapTotalBytes": 20848640,
      "scriptDurationMs": 1329.478,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10831.99400000001,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10809.262999999999,
      "heapDeltaBytes": -25672212,
      "heapUsedBytes": 184909300,
      "domNodes": -8331,
      "jsHeapTotalBytes": 28139520,
      "scriptDurationMs": 580.533,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10807.684999999992,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10787.543,
      "heapDeltaBytes": -37306104,
      "heapUsedBytes": 162245740,
      "domNodes": -8331,
      "jsHeapTotalBytes": 24207360,
      "scriptDurationMs": 585.1650000000001,
      "eventListeners": -16470,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10591.646000000082,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10569.860999999999,
      "heapDeltaBytes": -53100396,
      "heapUsedBytes": 150045724,
      "domNodes": -8332,
      "jsHeapTotalBytes": 18440192,
      "scriptDurationMs": 559.542,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12756.272000000024,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 15.241000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12736.87,
      "heapDeltaBytes": -53615088,
      "heapUsedBytes": 161655144,
      "domNodes": -8331,
      "jsHeapTotalBytes": 23420928,
      "scriptDurationMs": 893.665,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12810.810000000003,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 15.159000000000006,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12789.967999999999,
      "heapDeltaBytes": -24979648,
      "heapUsedBytes": 172976948,
      "domNodes": -8332,
      "jsHeapTotalBytes": 24645632,
      "scriptDurationMs": 846.063,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12737.915999999928,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 14.903000000000027,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12719.152999999998,
      "heapDeltaBytes": -38798048,
      "heapUsedBytes": 159151148,
      "domNodes": -8333,
      "jsHeapTotalBytes": -3842048,
      "scriptDurationMs": 833.121,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.216666666666665,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 460.2199999999925,
      "styleRecalcs": 20,
      "styleRecalcDurationMs": 29.438,
      "layouts": 5,
      "layoutDurationMs": 1.981,
      "taskDurationMs": 147.297,
      "heapDeltaBytes": 4759432,
      "heapUsedBytes": 48729004,
      "domNodes": 169,
      "jsHeapTotalBytes": 262144,
      "scriptDurationMs": 30.9,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "workflow-execution",
      "durationMs": 449.18300000006184,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 22.8,
      "layouts": 5,
      "layoutDurationMs": 1.636,
      "taskDurationMs": 129.64600000000002,
      "heapDeltaBytes": 4528548,
      "heapUsedBytes": 48468664,
      "domNodes": 154,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 27.721999999999998,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 449.79000000000724,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 24.275,
      "layouts": 5,
      "layoutDurationMs": 1.4220000000000002,
      "taskDurationMs": 131.818,
      "heapDeltaBytes": 4515140,
      "heapUsedBytes": 48065100,
      "domNodes": 158,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 30.886999999999997,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    }
  ]
}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
browser_tests/fixtures/utils/boundsUtils.ts (1)

18-21: Consider moving to fixtures/helpers/ since this has a Page dependency.

Per the coding guidelines, fixtures/utils/ is for "pure utility functions with no Page dependency", while fixtures/helpers/ is for "focused helper classes for domain-specific actions". This file accepts a Page parameter, making it a Page-dependent helper rather than a pure utility.

This is a minor organizational concern that could be addressed in a follow-up. As per coding guidelines: "Place pure utility functions with no Page dependency in fixtures/utils/ for stateless helpers usable anywhere".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@browser_tests/fixtures/utils/boundsUtils.ts` around lines 18 - 21, The
function measureSelectionBounds accepts a Playwright Page and therefore belongs
in the Page-dependent helpers folder; move the file from fixtures/utils/ to
fixtures/helpers/, update any import paths referencing measureSelectionBounds,
and ensure the module export remains the same (measureSelectionBounds) so
callers (tests/fixtures) continue to work; also run/adjust any tests or lints to
confirm there are no remaining imports pointing to the old fixtures/utils path.
src/renderer/extensions/vueNodes/composables/useVueNodeResizeTracking.ts (1)

161-180: Vue-specific fields on LGraphNode noted as Option A limitation.

This adds _footerHeight to LGraphNode instances, which is a Vue-rendering-specific field. Per ADR guidance, this grows the LGraphNode "God-object" with Vue-specific concerns.

This is explicitly acknowledged in the PR objectives as a limitation of Option A: "core changes add Vue-specific fields (_footerHeight, _collapsed_height) to LGraphNode". The alternative Option B is noted as pending.

The implementation itself is correct - measuring the body element for node.size while tracking footer contribution separately ensures accurate bounding rect calculation.

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

Inline comments:
In `@browser_tests/fixtures/utils/litegraphUtils.ts`:
- Line 335: Update the docstring for the deterministic setter to correctly
describe that LGraphNode.collapse() is a toggle: state is toggled by
node.collapse(), but this setter enforces deterministic behavior by guarding the
call (so it only calls node.collapse() when the desired state differs from the
current state). Mention LGraphNode.collapse() and the deterministic guard in the
comment for clarity.

In `@src/lib/litegraph/src/LGraphNode.ts`:
- Around line 425-434: The patch adds renderer-specific fields to the core
LGraphNode (_collapsed_height and _footerHeight), coupling graph state to Vue
DOM measurement; instead, remove these properties from LGraphNode and move the
measurement state into a Vue-side store/composable keyed by node id (or maintain
a Map<string, {collapsedHeight:number, footerHeight:number}>), update any code
that reads/writes _collapsed_height/_footerHeight to instead call the new
composable/store API, and ensure any functions that relied on those fields
(e.g., measure() callers) retrieve measurement values through the store keyed by
node.id rather than from LGraphNode.
- Line 2103: measure() currently uses Vue-only cached fields _footerHeight and
_collapsed_height unconditionally; update measure() so it only consumes those
cached values when the node is actually in Vue rendering mode. In practice:
inside LGraphNode.measure(), replace direct uses of this._footerHeight and
this._collapsed_height with conditional expressions that use the cached value
only when a Vue-mode flag (e.g. this._isVueMode / this._vueMode / whatever
existing boolean indicates Vue rendering in this class) is true, otherwise
default to 0 (or the legacy calculation). Apply the same guard at both sites
that reference _footerHeight and _collapsed_height so legacy rendering cannot
pick up stale Vue-populated heights.

---

Nitpick comments:
In `@browser_tests/fixtures/utils/boundsUtils.ts`:
- Around line 18-21: The function measureSelectionBounds accepts a Playwright
Page and therefore belongs in the Page-dependent helpers folder; move the file
from fixtures/utils/ to fixtures/helpers/, update any import paths referencing
measureSelectionBounds, and ensure the module export remains the same
(measureSelectionBounds) so callers (tests/fixtures) continue to work; also
run/adjust any tests or lints to confirm there are no remaining imports pointing
to the old fixtures/utils path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96707eed-e152-4374-8055-d3d2c9d130d5

📥 Commits

Reviewing files that changed from the base of the PR and between af0f7cb and 5b8d21b.

📒 Files selected for processing (10)
  • browser_tests/assets/selection/subgraph-with-regular-node.json
  • browser_tests/fixtures/helpers/NodeOperationsHelper.ts
  • browser_tests/fixtures/utils/boundsUtils.ts
  • browser_tests/fixtures/utils/litegraphUtils.ts
  • browser_tests/tests/selectionBoundingBox.spec.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/renderer/extensions/vueNodes/components/LGraphNode.vue
  • src/renderer/extensions/vueNodes/components/NodeFooter.vue
  • src/renderer/extensions/vueNodes/composables/useVueNodeResizeTracking.ts
  • src/renderer/extensions/vueNodes/interactions/resize/useNodeResize.ts

async isCollapsed() {
return !!(await this.getFlags()).collapsed
}
/** Deterministic setter using node.collapse() API (not a toggle). */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Correct the collapse() semantics in the docstring.

Line 335 says collapse() is “not a toggle”, but LGraphNode.collapse() toggles state. This setter is deterministic because of the guard on Line 341.

✏️ Proposed wording fix
-  /** Deterministic setter using node.collapse() API (not a toggle). */
+  /** Deterministic collapsed-state setter using guard + node.collapse() toggle API. */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@browser_tests/fixtures/utils/litegraphUtils.ts` at line 335, Update the
docstring for the deterministic setter to correctly describe that
LGraphNode.collapse() is a toggle: state is toggled by node.collapse(), but this
setter enforces deterministic behavior by guarding the call (so it only calls
node.collapse() when the desired state differs from the current state). Mention
LGraphNode.collapse() and the deterministic guard in the comment for clarity.

Comment on lines +425 to +434
/**
* The height of the node when collapsed (including footer).
* Set by ResizeObserver in Vue nodes mode.
*/
_collapsed_height?: number
/**
* The footer height in Vue nodes mode.
* Set by ResizeObserver, used by measure() to extend boundingRect.
*/
_footerHeight?: number
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid expanding LGraphNode with renderer-specific fields.

Adding _collapsed_height and _footerHeight to core LGraphNode couples LiteGraph entity state to Vue DOM measurement concerns. Prefer storing this UI measurement state in Vue-side store/composable structures keyed by node id.

Based on learnings: Applies to {src/lib/litegraph/**,src/ecs/**}/*.{ts,tsx,js} : ADR compliance for entity/litegraph changes: Flag new methods/properties added to LGraphNode, LGraphCanvas, LGraph, or Subgraph that add responsibilities rather than extracting/migrating existing ones (God-object growth).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/litegraph/src/LGraphNode.ts` around lines 425 - 434, The patch adds
renderer-specific fields to the core LGraphNode (_collapsed_height and
_footerHeight), coupling graph state to Vue DOM measurement; instead, remove
these properties from LGraphNode and move the measurement state into a Vue-side
store/composable keyed by node id (or maintain a Map<string,
{collapsedHeight:number, footerHeight:number}>), update any code that
reads/writes _collapsed_height/_footerHeight to instead call the new
composable/store API, and ensure any functions that relied on those fields
(e.g., measure() callers) retrieve measurement values through the store keyed by
node.id rather than from LGraphNode.

if (!this.flags?.collapsed) {
out[2] = this.size[0]
out[3] = this.size[1] + titleHeight
out[3] = this.size[1] + titleHeight + (this._footerHeight ?? 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Gate Vue-only cached heights to Vue mode to prevent stale bounds in legacy rendering.

Line 2103 and Line 2114 consume _footerHeight / _collapsed_height unconditionally. If values were populated in Vue mode and then rendering switches to legacy mode, node bounds/hitboxes can remain inflated.

🩹 Proposed guard in measure()
-      out[3] = this.size[1] + titleHeight + (this._footerHeight ?? 0)
+      const footerHeight = LiteGraph.vueNodesMode
+        ? (this._footerHeight ?? 0)
+        : 0
+      out[3] = this.size[1] + titleHeight + footerHeight
...
-      out[3] = this._collapsed_height || LiteGraph.NODE_TITLE_HEIGHT
+      out[3] = LiteGraph.vueNodesMode
+        ? (this._collapsed_height ?? LiteGraph.NODE_TITLE_HEIGHT)
+        : LiteGraph.NODE_TITLE_HEIGHT

Also applies to: 2114-2114

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/litegraph/src/LGraphNode.ts` at line 2103, measure() currently uses
Vue-only cached fields _footerHeight and _collapsed_height unconditionally;
update measure() so it only consumes those cached values when the node is
actually in Vue rendering mode. In practice: inside LGraphNode.measure(),
replace direct uses of this._footerHeight and this._collapsed_height with
conditional expressions that use the cached value only when a Vue-mode flag
(e.g. this._isVueMode / this._vueMode / whatever existing boolean indicates Vue
rendering in this class) is true, otherwise default to 0 (or the legacy
calculation). Apply the same guard at both sites that reference _footerHeight
and _collapsed_height so legacy rendering cannot pick up stale Vue-populated
heights.

- Remove overlay div assertions (node-state-outline-overlay removed)
- Add createSharedComposable to @vueuse/core mock
- Add offsetWidth/offsetHeight to ResizeObserver test elements
@jaeone94 jaeone94 added the New Browser Test Expectations New browser test screenshot should be set by github action label Mar 30, 2026
@github-actions
Copy link
Copy Markdown

Updating Playwright Expectations

@jaeone94 jaeone94 removed the New Browser Test Expectations New browser test screenshot should be set by github action label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/renderer/extensions/vueNodes/components/LGraphNode.vue`:
- Around line 13-16: The class list currently applies outlineClass after
rootBorderShapeClass which causes outlineClass's rounded-* to override the
larger error radius; update outlineClass so it does not hardcode rounded-* but
instead derives its radius from the same source as rootBorderShapeClass (i.e.,
reuse or compute the same value used to build rootBorderShapeClass) so the outer
error radius is defined in one place; locate where outlineClass and
rootBorderShapeClass are composed in LGraphNode.vue and remove/replace any
hardcoded rounded-* in outlineClass with the shared radius value or a reference
to rootBorderShapeClass.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b580d4be-c763-4d5b-9bc2-2ad4f2a660ff

📥 Commits

Reviewing files that changed from the base of the PR and between d74cfe1 and 7b39902.

📒 Files selected for processing (1)
  • src/renderer/extensions/vueNodes/components/LGraphNode.vue

Comment on lines +13 to +16
'group/node lg-node absolute isolate box-border flex flex-col border border-solid text-sm contain-layout contain-style',
hasAnyError ? 'border-transparent' : 'border-component-node-border',
rootBorderShapeClass,
outlineClass,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep the outer error radius defined in one place.

Because Line 16 applies outlineClass after rootBorderShapeClass, the rounded-* classes in Lines 598-604 override the larger error-state radius from Lines 658-663. That means selected/executing error nodes drop back to the smaller 16px corners in exactly the state where the 21px outer radius is supposed to preserve the ring/outline alignment.

🛠️ Minimal fix
 const outlineClass = computed(() => {
   const color = isSelected.value
     ? 'outline-node-component-outline'
     : executing.value
       ? 'outline-node-stroke-executing'
       : null
   if (!color) return ''

   if (!hasAnyError.value) return cn('outline-3', color)

-  const errorRadius =
-    nodeData.shape === RenderShape.BOX
-      ? ''
-      : nodeData.shape === RenderShape.CARD
-        ? 'rounded-tl-[16px] rounded-br-[16px]'
-        : 'rounded-[16px]'
-  return cn('outline-4 outline-offset-[3px]', errorRadius, color)
+  return cn('outline-4 outline-offset-[3px]', color)
 })

If you still need an explicit outline radius here, derive it from the same source as rootBorderShapeClass instead of hardcoding a second set of values.

Based on learnings, the cn utility with tailwind-merge keeps the last conflicting Tailwind class, so later rounded-* entries override earlier ones.

Also applies to: 588-605, 652-663

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/extensions/vueNodes/components/LGraphNode.vue` around lines 13 -
16, The class list currently applies outlineClass after rootBorderShapeClass
which causes outlineClass's rounded-* to override the larger error radius;
update outlineClass so it does not hardcode rounded-* but instead derives its
radius from the same source as rootBorderShapeClass (i.e., reuse or compute the
same value used to build rootBorderShapeClass) so the outer error radius is
defined in one place; locate where outlineClass and rootBorderShapeClass are
composed in LGraphNode.vue and remove/replace any hardcoded rounded-* in
outlineClass with the shared radius value or a reference to
rootBorderShapeClass.

@jaeone94
Copy link
Copy Markdown
Collaborator Author

Due to too many design changes, I will resubmit the PR with a new approach.

@jaeone94 jaeone94 closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants