Skip to content

perf: add gpu hint and transform settle to prevent rasterizing while zooming (scale transform)#7417

Merged
christian-byrne merged 4 commits intomainfrom
vue-node/restore-transform-settle-gpu-delayer
Dec 12, 2025
Merged

perf: add gpu hint and transform settle to prevent rasterizing while zooming (scale transform)#7417
christian-byrne merged 4 commits intomainfrom
vue-node/restore-transform-settle-gpu-delayer

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Dec 12, 2025

Summary

Ensures the nodes get their own compositing layers during scale transform (tracked via mouse wheel events), which prevents rasterization during transform. Adds forced reflow at end of transform to ensure layers are always at correct resolution (fixes blurriness and some readability issues).

Videos show testing this branch first then testing main - doing layer visualization, paint (include paint operations calculations and actual raster) visualizations, and cpu usage monitoring.

VID_20251212_042140430.mp4
VID_20251212_035211733.mp4

@christian-byrne christian-byrne requested a review from a team as a code owner December 12, 2025 14:10
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Dec 12, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

📝 Walkthrough

Walkthrough

This PR introduces a new useTransformSettling composable to track canvas zoom transform state during interactions, applies dynamic CSS classes to optimize performance by disabling transitions and enabling transform hints, and includes comprehensive test coverage for the new functionality.

Changes

Cohort / File(s) Summary
CSS Performance Optimizations
packages/design-system/src/css/style.css
Adds rules to disable transitions on .lg-node descendants and enable will-change: transform hints during .transform-pane--interacting state for rendering performance.
Transform Pane Component
src/renderer/core/layout/transform/TransformPane.vue
src/renderer/core/layout/__tests__/TransformPane.test.ts
Replaces static class binding with dynamic transform-pane--interacting toggle driven by useTransformSettling hook; adds computed canvasElement reference and scoped style rule; updates tests to reflect CSS class rename and verify event listener lifecycle.
Transform Settling Composable
src/renderer/core/layout/transform/useTransformSettling.ts
tests-ui/tests/composables/graph/useTransformSettling.test.ts
Introduces new composable tracking wheel-based transform changes with configurable debounce settling (256 ms default); exposes isTransforming reactive state; comprehensive test suite validates wheel event tracking, settle timer behavior, event capture, passive listeners, and cleanup.

Sequence Diagram

sequenceDiagram
    participant User
    participant Canvas as Canvas Element
    participant useTS as useTransformSettling
    participant TP as TransformPane Component
    participant CSS as CSS Engine

    User->>Canvas: wheel event
    Canvas->>useTS: dispatch wheel event (capture phase)
    activate useTS
    useTS->>useTS: set isTransforming = true
    useTS->>useTS: reset settle timer
    useTS->>TP: reactive update: isTransforming = true
    deactivate useTS
    
    activate TP
    TP->>TP: compute dynamic class<br/>"transform-pane--interacting"
    TP->>CSS: apply class
    deactivate TP
    
    activate CSS
    CSS->>CSS: disable transitions on .lg-node
    CSS->>CSS: enable will-change: transform
    CSS->>CSS: render optimized transform
    deactivate CSS
    
    Note over User,CSS: User continues wheel interactions...
    
    User->>Canvas: (no more wheel events)
    activate useTS
    useTS->>useTS: settle timer fires after 256ms
    useTS->>useTS: set isTransforming = false
    useTS->>TP: reactive update: isTransforming = false
    deactivate useTS
    
    activate TP
    TP->>TP: compute dynamic class<br/>"" (empty)
    TP->>CSS: remove class
    deactivate TP
    
    activate CSS
    CSS->>CSS: re-enable transitions
    CSS->>CSS: disable will-change
    CSS->>CSS: render normal
    deactivate CSS
Loading

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch vue-node/restore-transform-settle-gpu-delayer

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

@github-actions
Copy link

github-actions bot commented Dec 12, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 12/12/2025, 02:20:27 PM UTC

📈 Summary

  • Total Tests: 502
  • Passed: 492 ✅
  • Failed: 0
  • Flaky: 1 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 483 / ❌ 0 / ⚠️ 1 / ⏭️ 9
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Dec 12, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/12/2025, 02:12:10 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

Bundle Size Report

Summary

  • Raw size: 17.1 MB baseline 17.1 MB — 🔴 +1.17 kB
  • Gzip: 3.39 MB baseline 3.39 MB — 🔴 +238 B
  • Brotli: 2.6 MB baseline 2.6 MB — 🔴 +385 B
  • Bundles: 97 current • 97 baseline • 39 added / 39 removed

Category Glance
Graph Workspace 🔴 +1.17 kB (984 kB) · Vendor & Third-Party ⚪ 0 B (8.56 MB) · Other ⚪ 0 B (3.81 MB) · App Entry Points ⚪ 0 B (3.24 MB) · Panels & Settings ⚪ 0 B (298 kB) · UI Components ⚪ 0 B (178 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.24 MB (baseline 3.24 MB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-C6QsO8Vo.js (new) 3.01 MB 🔴 +3.01 MB 🔴 +626 kB 🔴 +476 kB
assets/index-Dk7G_39R.js (removed) 3.01 MB 🟢 -3.01 MB 🟢 -626 kB 🟢 -476 kB
assets/index-BeCbW1th.js (new) 227 kB 🔴 +227 kB 🔴 +48.6 kB 🔴 +39.9 kB
assets/index-BIwd08Ne.js (removed) 227 kB 🟢 -227 kB 🟢 -48.6 kB 🟢 -39.9 kB
assets/index-Dgf7sZnQ.js (new) 345 B 🔴 +345 B 🔴 +244 B 🔴 +234 B
assets/index-gN8YPTre.js (removed) 345 B 🟢 -345 B 🟢 -247 B 🟢 -200 B

Status: 3 added / 3 removed

Graph Workspace — 984 kB (baseline 983 kB) • 🔴 +1.17 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DCZlX8xz.js (new) 984 kB 🔴 +984 kB 🔴 +191 kB 🔴 +146 kB
assets/GraphView-Cuj9eAYC.js (removed) 983 kB 🟢 -983 kB 🟢 -190 kB 🟢 -145 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-D9DGmgfj.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.89 kB
assets/UserSelectView-iQimhRV9.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.13 kB 🔴 +1.89 kB

Status: 1 added / 1 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-Bn98hxmK.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/LegacyCreditsPanel-DYSLqrId.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/KeybindingPanel-De0Pdbjd.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/KeybindingPanel-DfFSK3-w.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/ExtensionPanel-CIZYmrS1.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.57 kB 🔴 +2.26 kB
assets/ExtensionPanel-DNn2mlZD.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.26 kB
assets/AboutPanel-DSXAN5wq.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-Z5ix-Bqs.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-CfMwgBNW.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/ServerConfigPanel-KXNXLSiP.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/UserPanel-6JBUcK4w.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.5 kB
assets/UserPanel-dvpJmH0r.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.5 kB
assets/settings-B_sqawkt.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BlDXT7wp.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Bz8HAvJu.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C2vW8UNv.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9vsDM17.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DWD49kQp.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DZE27_Iz.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-OXaZPcZF.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-RbkKsnDG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-CG1_MsSN.js (new) 53.7 kB 🔴 +53.7 kB 🔴 +8.48 kB 🔴 +7.29 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-knB3kSmS.js (removed) 53.7 kB 🟢 -53.7 kB 🟢 -8.48 kB 🟢 -7.29 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-ClEol73J.js (new) 48.1 kB 🔴 +48.1 kB 🔴 +10.4 kB 🔴 +8.99 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-Dng75nHz.js (removed) 48.1 kB 🟢 -48.1 kB 🟢 -10.4 kB 🟢 -8.99 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-C1ZhsCym.js (new) 48 kB 🔴 +48 kB 🔴 +10.6 kB 🔴 +9.32 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-oweXBCtf.js (removed) 48 kB 🟢 -48 kB 🟢 -10.6 kB 🟢 -9.32 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BXpCjZAf.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.96 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-DjdaHnDJ.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.97 kB
assets/ComfyQueueButton-BJfQkJ1y.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.22 kB
assets/ComfyQueueButton-BnTmgcU6.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.48 kB 🟢 -2.21 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BlvRl_a-.js (new) 2.15 kB 🔴 +2.15 kB 🔴 +893 B 🔴 +770 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-DqB2QZqG.js (removed) 2.15 kB 🟢 -2.15 kB 🟢 -897 B 🟢 -767 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CJVDB9XP.js (removed) 897 B 🟢 -897 B 🟢 -502 B 🟢 -439 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-paZWS0m4.js (new) 897 B 🔴 +897 B 🔴 +500 B 🔴 +466 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-HWlLovsu.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-CMNwFzv0.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-B-dJs90L.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.84 kB 🔴 +1.58 kB
assets/keybindingService-CO6Uu-Zl.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.84 kB 🟢 -1.58 kB
assets/audioService-BiPIYVJT.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +961 B 🔴 +825 B
assets/audioService-DYHYzoP8.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -962 B 🟢 -820 B
assets/serverConfigStore-bHPLOH2-.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-CxBJkeib.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +581 B
assets/audioUtils-zIuHqLb8.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -653 B 🟢 -547 B
assets/mathUtil-CD4DsosH.js 1.32 kB 1.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-VUOgEeCi.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-Deurr33o.js 3.98 MB 3.98 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-DO99B366.js 1.96 MB 1.96 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-jlp9Zr6M.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-DQYuPKbl.js 160 kB 160 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-3gi-GwUV.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.23 kB 🔴 +4.62 kB
assets/WidgetRecordAudio-CoF_3Zdq.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.23 kB 🟢 -4.63 kB
assets/AudioPreviewPlayer-Be0M34-w.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.37 kB 🔴 +3.01 kB
assets/AudioPreviewPlayer-Siymur4N.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.37 kB 🟢 -3.01 kB
assets/WidgetGalleria-BsojVXwA.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.3 kB
assets/WidgetGalleria-CjBDfJ51.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.44 kB 🔴 +1.31 kB
assets/WidgetColorPicker-D2Yw0mJ6.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetColorPicker-pgsx3WG-.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetTextarea-DceCOkL8.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.21 kB 🟢 -1.07 kB
assets/WidgetTextarea-DZ2u5xvm.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.21 kB 🔴 +1.07 kB
assets/WidgetMarkdown-D4PxJWeS.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetMarkdown-DBkoNJCU.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetAudioUI-C39bZjAC.js (new) 2.86 kB 🔴 +2.86 kB 🔴 +1.16 kB 🔴 +1.05 kB
assets/WidgetAudioUI-CuX7C-NO.js (removed) 2.86 kB 🟢 -2.86 kB 🟢 -1.17 kB 🟢 -1.05 kB
assets/WidgetInputText-B_5jZycT.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +917 B 🔴 +848 B
assets/WidgetInputText-DjVzkxgk.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -921 B 🟢 -829 B
assets/WidgetToggleSwitch-7pkTvxMB.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +831 B 🔴 +733 B
assets/WidgetToggleSwitch-BB2ozCn1.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -835 B 🟢 -735 B
assets/MediaImageBottom-BA8DNqKc.js (new) 1.55 kB 🔴 +1.55 kB 🔴 +736 B 🔴 +640 B
assets/MediaImageBottom-BIhLopSK.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -736 B 🟢 -642 B
assets/MediaAudioBottom-Bzi772jc.js (removed) 1.51 kB 🟢 -1.51 kB 🟢 -735 B 🟢 -651 B
assets/MediaAudioBottom-CH5LKZWG.js (new) 1.51 kB 🔴 +1.51 kB 🔴 +735 B 🔴 +644 B
assets/Media3DBottom-BepXG4n9.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +730 B 🔴 +646 B
assets/Media3DBottom-E1N2W3IX.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -732 B 🟢 -651 B
assets/MediaVideoBottom-BPENdOpx.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +729 B 🔴 +643 B
assets/MediaVideoBottom-u22j2Vrl.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -645 B
assets/Media3DTop-BYAhYTFm.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +762 B 🔴 +649 B
assets/Media3DTop-DMmZh_zM.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -761 B 🟢 -643 B
assets/WidgetSelect-Bj9dNzia.js (new) 655 B 🔴 +655 B 🔴 +340 B 🔴 +287 B
assets/WidgetSelect-D1HPJDJb.js (removed) 655 B 🟢 -655 B 🟢 -343 B 🟢 -286 B
assets/WidgetInputNumber-D-PnM1Zv.js (removed) 595 B 🟢 -595 B 🟢 -327 B 🟢 -271 B
assets/WidgetInputNumber-DHKuQyYf.js (new) 595 B 🔴 +595 B 🔴 +327 B 🔴 +272 B
assets/Load3D-BtypHsN7.js (new) 424 B 🔴 +424 B 🔴 +265 B 🔴 +223 B
assets/Load3D-rvIgh7B1.js (removed) 424 B 🟢 -424 B 🟢 -263 B 🟢 -222 B
assets/WidgetLegacy-8dDqHz9b.js (new) 364 B 🔴 +364 B 🔴 +235 B 🔴 +195 B
assets/WidgetLegacy-D-2YkYuv.js (removed) 364 B 🟢 -364 B 🟢 -234 B 🟢 -193 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BMi-Aksj.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CqR8skJT.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DcRHAFEy.js 81.7 kB 81.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DdFdLxku.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DJAtuVu5.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DK8I9Rk3.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-gP_ssnMb.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-nxXY9vGp.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Ycd3gqkA.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-D1WKsNUf.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-B2BN_vpA.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-B8jmaGRE.js 2.65 kB 2.65 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BC3OlaIn.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BsqN8-W1.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK2saYDx.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cm5kR4Hi.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CMrh-uxB.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DlUIOit1.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DNu_xoP2.js 282 kB 282 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DpcvlpZe.js 303 kB 303 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-IyjOYIl-.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-BH0eLeWx.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-mYznCAm6.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 18 added / 18 removed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b1bd4b and 7e14980.

📒 Files selected for processing (5)
  • packages/design-system/src/css/style.css (1 hunks)
  • src/renderer/core/layout/__tests__/TransformPane.test.ts (2 hunks)
  • src/renderer/core/layout/transform/TransformPane.vue (4 hunks)
  • src/renderer/core/layout/transform/useTransformSettling.ts (1 hunks)
  • tests-ui/tests/composables/graph/useTransformSettling.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/component test files must be named **/*.test.ts or in tests-ui/ directory
Do not write change detector tests that just assert default values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing; do not write redundant tests; see composable tests approach
Follow 'Don't Mock What You Don't Own' principle - avoid mocking external dependencies
Do not write tests that just test the mocks; ensure tests fail when code behaves unexpectedly
Leverage Vitest's mocking utilities where possible for test mocking
Keep module mocks contained in test files; do not use global mutable state within test files; use vi.hoisted() if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/renderer/core/layout/transform/TransformPane.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/renderer/core/layout/transform/TransformPane.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Minimize the surface area (exported values) of each module and composable

Files:

  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
🧠 Learnings (33)
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Be parsimonious in testing; do not write redundant tests; see composable tests approach

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Test user workflows in browser tests

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Test across multiple viewports

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Prefer specific selectors in browser tests

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Leverage Vitest's mocking utilities where possible for test mocking

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • tests-ui/tests/composables/graph/useTransformSettling.test.ts
  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
  • src/renderer/core/layout/__tests__/TransformPane.test.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use setup() function in Vue 3 Composition API

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Vue components must use `<script setup lang="ts">` for component logic

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement computed() for derived state in Vue 3 Composition API

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use VueUse functions for performance-enhancing styles

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
  • src/renderer/core/layout/transform/useTransformSettling.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use `ref` for reactive state in Vue Composition API components

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/renderer/core/layout/transform/TransformPane.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices described in the official documentation for E2E tests

Applied to files:

  • src/renderer/core/layout/__tests__/TransformPane.test.ts
🧬 Code graph analysis (2)
tests-ui/tests/composables/graph/useTransformSettling.test.ts (1)
src/renderer/core/layout/transform/useTransformSettling.ts (1)
  • useTransformSettling (45-84)
packages/design-system/src/css/style.css (1)
src/lib/litegraph/src/LGraph.ts (1)
  • change (1261-1264)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: setup
🔇 Additional comments (1)
src/renderer/core/layout/transform/TransformPane.vue (1)

4-9: Use Tailwind will-change-* utilities instead of <style> blocks; remove scoped CSS.

The repo guideline requires using Tailwind utilities for styling and avoiding <style> blocks in Vue components. Tailwind 4 provides the exact utilities needed here:

  • Replace will-change-auto with the will-change-auto utility
  • Add will-change-transform to the interacting state

Remove the <style scoped> block entirely and apply the utility class conditionally via cn() when interacting. Also verify the import path for LGraphCanvas matches the module export structure.

Comment on lines +1331 to +1338
/* Performance optimization during canvas interaction */
.transform-pane--interacting .lg-node * {
transition: none !important;
}

.transform-pane--interacting .lg-node {
will-change: transform;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Over-broad * { transition: none !important; } risks unintended UI regressions; prefer targeting known transitioning elements.

Right now this disables all descendant transitions under nodes during zoom, not just the LiteGraph node transition surfaces. Given you already define transitions on .lg-node .lg-slot / .lg-node .lg-widget (Line 1324-1329), consider scoping the override to those instead of *.

 /* Performance optimization during canvas interaction */
-.transform-pane--interacting .lg-node * {
-  transition: none !important;
-}
+.transform-pane--interacting .lg-node .lg-slot,
+.transform-pane--interacting .lg-node .lg-widget {
+  transition: none !important;
+}
 
 .transform-pane--interacting .lg-node {
   will-change: transform;
 }
🤖 Prompt for AI Agents
In packages/design-system/src/css/style.css around lines 1331 to 1338, the rule
using the universal selector to disable transitions is too broad and can cause
regressions; narrow the selector to only the known transition targets (e.g.,
.lg-node .lg-slot and .lg-node .lg-widget or any other specific transitioning
descendants) so that during .transform-pane--interacting only those elements
receive transition: none !important, leaving unrelated descendants unaffected.

Comment on lines +120 to +185
describe('canvas event listeners', () => {
it('should add event listeners to canvas on mount', async () => {
const mockCanvas = createMockCanvas()
mount(TransformPane, {
props: {
canvas: mockCanvas
}
})

await nextTick()

expect(mockCanvas.canvas.addEventListener).toHaveBeenCalledWith(
'wheel',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
'pointerdown',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
'pointerup',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
'pointercancel',
expect.any(Function),
expect.any(Object)
)
})

it('should remove event listeners on unmount', async () => {
const mockCanvas = createMockCanvas()
const wrapper = mount(TransformPane, {
props: {
canvas: mockCanvas
}
})

await nextTick()
wrapper.unmount()

expect(mockCanvas.canvas.removeEventListener).toHaveBeenCalledWith(
'wheel',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
'pointerdown',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
'pointerup',
expect.any(Function),
expect.any(Object)
)
expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
'pointercancel',
expect.any(Function),
expect.any(Object)
)
})
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Event-listener tests should assert handler identity (and avoid brittle “no pointer listeners” assertions).

removeEventListener requires the same function reference and compatible options; expect.any(Function) can pass even if the component leaks the real handler. Also, “not called with pointer*” will break if pointer listeners are legitimately added later.

Consider tightening to “wheel is registered with capture/passive” and “wheel is removed with the same handler”:

 it('should add event listeners to canvas on mount', async () => {
   const mockCanvas = createMockCanvas()
   mount(TransformPane, {
     props: {
       canvas: mockCanvas
     }
   })
 
   await nextTick()
 
-  expect(mockCanvas.canvas.addEventListener).toHaveBeenCalledWith(
-    'wheel',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
-    'pointerdown',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
-    'pointerup',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith(
-    'pointercancel',
-    expect.any(Function),
-    expect.any(Object)
-  )
+  const [type, handler, options] =
+    (mockCanvas.canvas.addEventListener as unknown as { mock: { calls: unknown[][] } })
+      .mock.calls[0]
+
+  expect(type).toBe('wheel')
+  expect(handler).toEqual(expect.any(Function))
+  expect(options).toEqual(expect.objectContaining({ capture: true }))
 })
 
 it('should remove event listeners on unmount', async () => {
   const mockCanvas = createMockCanvas()
   const wrapper = mount(TransformPane, {
     props: {
       canvas: mockCanvas
     }
   })
 
   await nextTick()
+  const [, handler, options] =
+    (mockCanvas.canvas.addEventListener as unknown as { mock: { calls: unknown[][] } })
+      .mock.calls[0]
   wrapper.unmount()
 
-  expect(mockCanvas.canvas.removeEventListener).toHaveBeenCalledWith(
-    'wheel',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
-    'pointerdown',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
-    'pointerup',
-    expect.any(Function),
-    expect.any(Object)
-  )
-  expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith(
-    'pointercancel',
-    expect.any(Function),
-    expect.any(Object)
-  )
+  expect(mockCanvas.canvas.removeEventListener).toHaveBeenCalledWith(
+    'wheel',
+    handler as EventListener,
+    options as AddEventListenerOptions
+  )
 })

(If you’d rather avoid mocking intricacies altogether, consider using a real HTMLCanvasElement and vi.spyOn(canvasEl, 'addEventListener').)
Based on learnings, prefer assertions that reflect behavior over internal wiring where possible.

🤖 Prompt for AI Agents
In src/renderer/core/layout/__tests__/TransformPane.test.ts around lines 120 to
185, the tests currently assert add/remove calls using expect.any(Function) and
negative assertions for pointer listeners which is brittle; update the tests to
(1) capture the actual handler reference returned/attached when addEventListener
is spied or when using a real HTMLCanvasElement so you can assert the same
function is used in removeEventListener, (2) assert the wheel listener was
registered with the expected options (e.g. passive/capture) rather than broadly
checking any function, and (3) remove the
“not.toHaveBeenCalledWith('pointer...')” negative assertions or replace them
with behavior-based assertions; alternatively switch to a real canvas element
and use vi.spyOn(canvasEl, 'addEventListener') so you can compare handler
identity and options precisely and then assert removeEventListener was called
with that exact handler and matching options.

Comment on lines +201 to +203
expect(transformPane.classes()).not.toContain(
'transform-pane--interacting'
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Interaction class test only asserts the initial state; consider validating the “interacting” state is reachable.

Right now it only checks the class is absent initially. If feasible, dispatch a wheel event on a real canvas element (and advance fake timers) to assert transform-pane--interacting toggles on/off.

🤖 Prompt for AI Agents
In src/renderer/core/layout/__tests__/TransformPane.test.ts around lines 201 to
203, the test only asserts the initial absence of the
'transform-pane--interacting' class; extend it to actually trigger and verify
the interacting state by dispatching a real 'wheel' event on the canvas element
and advancing fake timers to observe the class toggle. Specifically, get the
actual canvas DOM element from the mounted wrapper, dispatch a WheelEvent with a
non-zero delta (e.g., deltaY), assert the wrapper now contains
'transform-pane--interacting', then advance timers by the interaction timeout
duration and assert the class is removed; ensure
jest.useFakeTimers/jest.advanceTimersByTime (or equivalent) are used and timers
are restored/cleared after the test.

Comment on lines +5 to +16
interface TransformSettlingOptions {
/**
* Delay in ms before transform is considered "settled" after last interaction
* @default 200
*/
settleDelay?: number
/**
* Whether to use passive event listeners (better performance but can't preventDefault)
* @default true
*/
passive?: boolean
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/renderer/core/layout/transform/useTransformSettling.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2905


🌐 Web query:

VueUse useEventListener return type documentation

💡 Result:

The VueUse docs show the TypeScript declarations for useEventListener (including its return type). In short: useEventListener returns a cleanup function you can call to unregister the listener, and the library also exports a type alias UseEventListenerReturn = ReturnType. See the Type Declarations in the docs for details and overloads. [1][2]

Sources:
[1] VueUse useEventListener (Type declarations). https://vueuse.org/core/useeventlistener/
[2] VueUse docs (versioned/type alias showing UseEventListenerReturn = ReturnType). https://v7-7-1.vueuse.org/core/useeventlistener/


🏁 Script executed:

rg "useTransformSettling" --type ts --type vue -A 3 -B 1

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 97


🏁 Script executed:

rg "useTransformSettling" -A 3 -B 1

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 5818


🏁 Script executed:

cat -n tests-ui/tests/composables/graph/useTransformSettling.test.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 6338


Fix documentation mismatch for default settleDelay value.

The JSDoc @default 200 at line 8 disagrees with the actual implementation at line 49 which uses settleDelay = 256. Please align the documentation to match the actual default value of 256.

Additionally, consider whether returning the stop() function from useEventListener would improve API flexibility. While the composable currently works correctly via automatic cleanup in component setup contexts (as verified by the test suite), exposing the stop function would allow explicit cleanup if the composable is ever used outside a Vue effect scope.

🤖 Prompt for AI Agents
In src/renderer/core/layout/transform/useTransformSettling.ts around lines 5 to
16, update the JSDoc for TransformSettlingOptions to state the correct default
settleDelay of 256 (replace @default 200 with @default 256) so docs match the
implementation, and modify the composable to expose the stop() cleanup function
returned by useEventListener (either return stop from useTransformSettling or
include it in the composable's returned object) so callers can explicitly
teardown listeners when used outside a Vue effect scope.

Comment on lines +105 to +130
it('should use capture phase for events', async () => {
const captureHandler = vi.fn()
const bubbleHandler = vi.fn()

// Add handlers to verify capture phase
element.addEventListener('wheel', captureHandler, true)
element.addEventListener('wheel', bubbleHandler, false)

const { isTransforming } = useTransformSettling(element)

// Create child element
const child = document.createElement('div')
element.appendChild(child)

// Dispatch event on child
child.dispatchEvent(new WheelEvent('wheel', { bubbles: true }))
await nextTick()

// Capture handler should be called before bubble handler
expect(captureHandler).toHaveBeenCalled()
expect(isTransforming.value).toBe(true)

element.removeEventListener('wheel', captureHandler, true)
element.removeEventListener('wheel', bubbleHandler, false)
})

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Strengthen or drop implementation-detail tests (capture/passive) to avoid false confidence.

  • The “capture phase” test doesn’t validate that useTransformSettling registered with { capture: true }; it only shows a capture listener existed.
  • If you want this as a contract, it’s clearer to vi.spyOn(element, 'addEventListener') and assert the options passed include { capture: true, passive: true } (similar to the passive test), or remove the capture test and rely on the options assertion alone.

Also applies to: 157-170

@christian-byrne christian-byrne merged commit 0646bb3 into main Dec 12, 2025
42 checks passed
@christian-byrne christian-byrne deleted the vue-node/restore-transform-settle-gpu-delayer branch December 12, 2025 22:41
Enferlain pushed a commit to Enferlain/ComfyUI_frontend that referenced this pull request Dec 18, 2025
…zooming (scale transform) (Comfy-Org#7417)

## Summary

Ensures the nodes get their own compositing layers during scale
transform (tracked via mouse wheel events), which prevents rasterization
during transform. Adds forced reflow at end of transform to ensure
layers are always at correct resolution (fixes blurriness and some
readability issues).

Videos show testing this branch first then testing main - doing layer
visualization, paint (include paint operations calculations and actual
raster) visualizations, and cpu usage monitoring.


https://github.com/user-attachments/assets/c5fab219-0b32-4822-9238-c4572f0d6a44



https://github.com/user-attachments/assets/7e172e8d-cc5b-4dcd-aa07-1dfc3eb65bac
Yourz pushed a commit that referenced this pull request Dec 24, 2025
…zooming (scale transform) (#7417)

## Summary

Ensures the nodes get their own compositing layers during scale
transform (tracked via mouse wheel events), which prevents rasterization
during transform. Adds forced reflow at end of transform to ensure
layers are always at correct resolution (fixes blurriness and some
readability issues).

Videos show testing this branch first then testing main - doing layer
visualization, paint (include paint operations calculations and actual
raster) visualizations, and cpu usage monitoring.


https://github.com/user-attachments/assets/c5fab219-0b32-4822-9238-c4572f0d6a44



https://github.com/user-attachments/assets/7e172e8d-cc5b-4dcd-aa07-1dfc3eb65bac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:vue-migration perf:speed size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants