Skip to content

feat: add Painter Node#8521

Open
jtydhr88 wants to merge 1 commit intomainfrom
feat/painter-node
Open

feat: add Painter Node#8521
jtydhr88 wants to merge 1 commit intomainfrom
feat/painter-node

Conversation

@jtydhr88
Copy link
Collaborator

@jtydhr88 jtydhr88 commented Feb 1, 2026

Summary

Add PainterNode widget for freehand mask drawing directly on the canvas, with brush/eraser tools, opacity, hardness, and background color controls.

need BE changes Comfy-Org/ComfyUI#12294

Screenshots (if applicable)

2026-01-31.22-17-31.mp4

┆Issue is synchronized with this Notion page by Unito

@jtydhr88 jtydhr88 requested review from a team as code owners February 1, 2026 03:05
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Feb 1, 2026
@github-actions
Copy link

github-actions bot commented Feb 1, 2026

🎭 Playwright Tests: ⚠️ Passed with flaky tests

Results: 507 passed, 0 failed, 2 flaky, 8 skipped (Total: 517)

❌ Failed Tests

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

@github-actions
Copy link

github-actions bot commented Feb 1, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 02/06/2026, 03:56:17 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Adds a new painter feature: a Vue SFC painter widget and usePainter composable, painter widget type/registry and constructor, core extension enforcing Painter node size, localization strings, and widget registration in ComfyWidgets.

Changes

Cohort / File(s) Summary
Painter UI & Composable
src/components/painter/WidgetPainter.vue, src/composables/painter/usePainter.ts
New Vue component and composable implementing a full canvas painter: input-image support, pointer-driven drawing, brush/eraser tools and parameters (size/color/opacity/hardness), soft/hard rendering, off-screen canvases, resize/clear, serialization and upload of masks, and widget-state persistence.
Widget Types & Registry
src/lib/litegraph/src/types/widgets.ts, src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts, src/renderer/extensions/vueNodes/widgets/composables/usePainterWidget.ts
Adds IPainterWidget type to widget union, async WidgetPainter component registration under type painter, includes painter in expanding types, and provides usePainterWidget constructor for attaching painter widgets.
Widget Integration
src/scripts/widgets.ts
Registers PAINTER entry in ComfyWidgets via transform of the v2→v1 painter widget constructor.
Core Extension
src/extensions/core/painter.ts, src/extensions/core/index.ts
Adds Comfy.Painter extension and imports it into core extensions; on node creation enforces minimum Painter node size (at least 450×550).
Localization
src/locales/en/main.json
Adds painter localization keys: tool, brush, eraser, size, color, hardness, width, height, background, clear, uploadError.

Sequence Diagram

sequenceDiagram
    actor User
    participant WidgetPainter as "WidgetPainter\n(renders UI)"
    participant usePainter as "usePainter\n(state + draw)"
    participant Canvas as "Canvas\n(offscreen/main)"
    participant Server as "Server\n(mask upload)"

    User->>WidgetPainter: open / interact UI (controls, pointer)
    WidgetPainter->>usePainter: handlePointerDown/Move/Up, control updates
    usePainter->>Canvas: convert coords, render stroke preview onto offscreen
    Canvas->>usePainter: composite stroke into main canvas
    User->>WidgetPainter: clear / save
    WidgetPainter->>usePainter: clear() / serialize()
    usePainter->>Server: upload serialized mask
    Server-->>usePainter: upload result (URL/status)
    usePainter-->>WidgetPainter: update modelValue / widget state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I'm a rabbit with a paint-splattered hat,
I hopped in to add a colorful spat.
Brushes hum softly, erasers go snap,
Strokes stitch a story on canvas and map.
🐇🎨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the summary and screenshots but is missing the required Changes section with What, Breaking, and Dependencies details. Add a Changes section detailing what core functionality was added/modified, any breaking changes, and new dependencies introduced by this feature.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main addition: a new Painter Node widget for the application.

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

✨ 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 feat/painter-node

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

github-actions bot commented Feb 1, 2026

Bundle Size Report

Summary

  • Raw size: 20.2 MB baseline 20.2 MB — 🔴 +31.8 kB
  • Gzip: 4.33 MB baseline 4.32 MB — 🔴 +7.65 kB
  • Brotli: 3.35 MB baseline 3.34 MB — 🔴 +6.96 kB
  • Bundles: 234 current • 233 baseline • 188 added / 187 removed

Category Glance
Other 🔴 +31.1 kB (7.13 MB) · Data & Services 🔴 +710 B (2.1 MB) · Graph Workspace 🔴 +3 B (840 kB) · Vendor & Third-Party ⚪ 0 B (9.37 MB) · Panels & Settings ⚪ 0 B (410 kB) · Utilities & Hooks ⚪ 0 B (234 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.5 kB (baseline 22.5 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-Dj4QzKF0.js (removed) 22.5 kB 🟢 -22.5 kB 🟢 -7.18 kB 🟢 -6.24 kB
assets/index-YKpF2XVO.js (new) 22.5 kB 🔴 +22.5 kB 🔴 +7.19 kB 🔴 +6.26 kB

Status: 1 added / 1 removed

Graph Workspace — 840 kB (baseline 840 kB) • 🔴 +3 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BTSJq5JF.js (new) 840 kB 🔴 +840 kB 🔴 +180 kB 🔴 +137 kB
assets/GraphView-BoT0juUT.js (removed) 840 kB 🟢 -840 kB 🟢 -180 kB 🟢 -137 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CdvBA3Nl.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.46 kB 🟢 -2.95 kB
assets/CloudSurveyView-CwFt3KrB.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.46 kB 🔴 +2.95 kB
assets/CloudLoginView-BhpiMzXT.js (new) 10 kB 🔴 +10 kB 🔴 +2.93 kB 🔴 +2.58 kB
assets/CloudLoginView-CJBh090I.js (removed) 10 kB 🟢 -10 kB 🟢 -2.93 kB 🟢 -2.57 kB
assets/UserCheckView-C8YCutAz.js (new) 8.39 kB 🔴 +8.39 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/UserCheckView-Cx7E6AFj.js (removed) 8.39 kB 🟢 -8.39 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/CloudSignupView-B4E6X-eP.js (new) 7.38 kB 🔴 +7.38 kB 🔴 +2.31 kB 🔴 +2.01 kB
assets/CloudSignupView-lOHQ-z6C.js (removed) 7.38 kB 🟢 -7.38 kB 🟢 -2.31 kB 🟢 -2.02 kB
assets/CloudLayoutView-C2e08tqG.js (removed) 6.43 kB 🟢 -6.43 kB 🟢 -2.12 kB 🟢 -1.83 kB
assets/CloudLayoutView-KY6tl54e.js (new) 6.43 kB 🔴 +6.43 kB 🔴 +2.12 kB 🔴 +1.83 kB
assets/CloudForgotPasswordView-Cg-UGqAM.js (removed) 5.56 kB 🟢 -5.56 kB 🟢 -1.94 kB 🟢 -1.72 kB
assets/CloudForgotPasswordView-CrQSJMw3.js (new) 5.56 kB 🔴 +5.56 kB 🔴 +1.94 kB 🔴 +1.74 kB
assets/CloudAuthTimeoutView-7y7lUQdG.js (new) 4.91 kB 🔴 +4.91 kB 🔴 +1.77 kB 🔴 +1.55 kB
assets/CloudAuthTimeoutView-BLck4lp7.js (removed) 4.91 kB 🟢 -4.91 kB 🟢 -1.77 kB 🟢 -1.55 kB
assets/CloudSubscriptionRedirectView-CMN4Syn4.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.77 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-T8B_rKuq.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.77 kB 🟢 -1.57 kB
assets/UserSelectView-MhD-sNyK.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.64 kB 🔴 +1.46 kB
assets/UserSelectView-RGdfDzzz.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.64 kB 🟢 -1.46 kB
assets/CloudSorryContactSupportView-BGk_kmuy.js (new) 1.02 kB 🔴 +1.02 kB 🔴 +538 B 🔴 +461 B
assets/CloudSorryContactSupportView-BPXBOTez.js (removed) 1.02 kB 🟢 -1.02 kB 🟢 -539 B 🟢 -464 B
assets/layout-BA5GtZ7P.js (new) 296 B 🔴 +296 B 🔴 +224 B 🔴 +191 B
assets/layout-ncetNFDR.js (removed) 296 B 🟢 -296 B 🟢 -222 B 🟢 -186 B

Status: 11 added / 11 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settings-BmEXiKRV.js (removed) 32 kB 🟢 -32 kB 🟢 -8.08 kB 🟢 -6.63 kB
assets/settings-DhiOd5RJ.js (new) 32 kB 🔴 +32 kB 🔴 +8.08 kB 🔴 +6.63 kB
assets/settings-CKCscONF.js (removed) 28.1 kB 🟢 -28.1 kB 🟢 -7.15 kB 🟢 -6.03 kB
assets/settings-CODNY0jQ.js (new) 28.1 kB 🔴 +28.1 kB 🔴 +7.15 kB 🔴 +6.02 kB
assets/WorkspacePanel-EC7DJYGe.js (removed) 26.9 kB 🟢 -26.9 kB 🟢 -5.66 kB 🟢 -4.96 kB
assets/WorkspacePanel-YlUZwk3K.js (new) 26.9 kB 🔴 +26.9 kB 🔴 +5.66 kB 🔴 +4.99 kB
assets/settings-D95NIw0v.js (removed) 26.8 kB 🟢 -26.8 kB 🟢 -7 kB 🟢 -5.67 kB
assets/settings-or3Z5VB2.js (new) 26.8 kB 🔴 +26.8 kB 🔴 +7 kB 🔴 +5.67 kB
assets/settings-Dn-91ECq.js (new) 25.7 kB 🔴 +25.7 kB 🔴 +7.28 kB 🔴 +6.1 kB
assets/settings-DQe4OZm2.js (removed) 25.7 kB 🟢 -25.7 kB 🟢 -7.28 kB 🟢 -6.1 kB
assets/settings-BfPS1ep1.js (new) 25 kB 🔴 +25 kB 🔴 +6.99 kB 🔴 +6.11 kB
assets/settings-BgcR6REE.js (removed) 25 kB 🟢 -25 kB 🟢 -6.99 kB 🟢 -6.11 kB
assets/settings-DmYc-PH9.js (removed) 24.2 kB 🟢 -24.2 kB 🟢 -6.75 kB 🟢 -5.74 kB
assets/settings-ihHLHLTG.js (new) 24.2 kB 🔴 +24.2 kB 🔴 +6.75 kB 🔴 +5.75 kB
assets/settings-BNs5rnMt.js (removed) 24.1 kB 🟢 -24.1 kB 🟢 -6.88 kB 🟢 -6.02 kB
assets/settings-BzHHkkP7.js (new) 24.1 kB 🔴 +24.1 kB 🔴 +6.88 kB 🔴 +6.02 kB
assets/settings-C5jqELHS.js (removed) 23.6 kB 🟢 -23.6 kB 🟢 -6.64 kB 🟢 -5.8 kB
assets/settings-j1bEePMm.js (new) 23.6 kB 🔴 +23.6 kB 🔴 +6.64 kB 🔴 +5.8 kB
assets/settings-f2yAwEpW.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -7 kB 🟢 -5.81 kB
assets/settings-ymEyMAEd.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +7 kB 🔴 +5.81 kB
assets/SecretsPanel-BsK9Pr-7.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.31 kB 🔴 +4.65 kB
assets/SecretsPanel-C0Ccjtcq.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.31 kB 🟢 -4.65 kB
assets/settings-CzcL_U24.js (removed) 20.8 kB 🟢 -20.8 kB 🟢 -6.85 kB 🟢 -5.49 kB
assets/settings-Dm3Qx17Q.js (new) 20.8 kB 🔴 +20.8 kB 🔴 +6.85 kB 🔴 +5.49 kB
assets/LegacyCreditsPanel-DDxlFGbE.js (new) 20.8 kB 🔴 +20.8 kB 🔴 +5.62 kB 🔴 +4.93 kB
assets/LegacyCreditsPanel-e4I_EcQB.js (removed) 20.8 kB 🟢 -20.8 kB 🟢 -5.62 kB 🟢 -4.93 kB
assets/settings-DHh_y6Nd.js (new) 20.3 kB 🔴 +20.3 kB 🔴 +6.62 kB 🔴 +5.16 kB
assets/settings-Dxocpd_-.js (removed) 20.3 kB 🟢 -20.3 kB 🟢 -6.62 kB 🟢 -5.16 kB
assets/SubscriptionPanel-DGXud9NC.js (removed) 18.8 kB 🟢 -18.8 kB 🟢 -4.77 kB 🟢 -4.21 kB
assets/SubscriptionPanel-Du_321wS.js (new) 18.8 kB 🔴 +18.8 kB 🔴 +4.77 kB 🔴 +4.2 kB
assets/KeybindingPanel-CFRnolTC.js (removed) 12.6 kB 🟢 -12.6 kB 🟢 -3.63 kB 🟢 -3.2 kB
assets/KeybindingPanel-CYTfP2Ke.js (new) 12.6 kB 🔴 +12.6 kB 🔴 +3.62 kB 🔴 +3.21 kB
assets/ExtensionPanel-CESqONXU.js (new) 9.49 kB 🔴 +9.49 kB 🔴 +2.69 kB 🔴 +2.39 kB
assets/ExtensionPanel-DSY9As5h.js (removed) 9.49 kB 🟢 -9.49 kB 🟢 -2.69 kB 🟢 -2.39 kB
assets/AboutPanel-BKBsvTOo.js (new) 8.62 kB 🔴 +8.62 kB 🔴 +2.45 kB 🔴 +2.21 kB
assets/AboutPanel-Btv4aEbD.js (removed) 8.62 kB 🟢 -8.62 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-DDW0HSo0.js (removed) 6.64 kB 🟢 -6.64 kB 🟢 -2.15 kB 🟢 -1.95 kB
assets/ServerConfigPanel-yLTwa6XZ.js (new) 6.64 kB 🔴 +6.64 kB 🔴 +2.15 kB 🔴 +1.95 kB
assets/UserPanel-CKguqUDu.js (new) 6.28 kB 🔴 +6.28 kB 🔴 +2.02 kB 🔴 +1.77 kB
assets/UserPanel-CQgjaEdm.js (removed) 6.28 kB 🟢 -6.28 kB 🟢 -2.02 kB 🟢 -1.77 kB
assets/cloudRemoteConfig-3RjIrMkK.js (removed) 1.44 kB 🟢 -1.44 kB 🟢 -700 B 🟢 -609 B
assets/cloudRemoteConfig-DcOqo4QD.js (new) 1.44 kB 🔴 +1.44 kB 🔴 +700 B 🔴 +605 B
assets/refreshRemoteConfig-BgyiXDuv.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -514 B 🟢 -448 B
assets/refreshRemoteConfig-ybwQYTGq.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +513 B 🔴 +447 B
assets/config-CO8TaJRX.js (new) 1.01 kB 🔴 +1.01 kB 🔴 +549 B 🔴 +445 B
assets/config-HAvaVehF.js (removed) 1.01 kB 🟢 -1.01 kB 🟢 -549 B 🟢 -445 B
assets/refreshRemoteConfig-BJfLptcT.js (new) 345 B 🔴 +345 B 🔴 +207 B 🔴 +204 B
assets/refreshRemoteConfig-DPKKOPo3.js (removed) 345 B 🟢 -345 B 🟢 -201 B 🟢 -204 B
assets/remoteConfig-CUBB_j_I.js 581 B 581 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 24 added / 24 removed

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-AZSyrcCZ.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.18 kB 🔴 +995 B
assets/auth-B4tEzJ7G.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.18 kB 🟢 -995 B
assets/SignUpForm-BSpae2Cf.js (removed) 3.01 kB 🟢 -3.01 kB 🟢 -1.23 kB 🟢 -1.09 kB
assets/SignUpForm-CQqK5kQ-.js (new) 3.01 kB 🔴 +3.01 kB 🔴 +1.23 kB 🔴 +1.1 kB
assets/UpdatePasswordContent-C4RMfSLH.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.07 kB 🔴 +942 B
assets/UpdatePasswordContent-L0JzGx5w.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.07 kB 🟢 -946 B
assets/firebaseAuthStore-B_KfgpBe.js (new) 790 B 🔴 +790 B 🔴 +391 B 🔴 +347 B
assets/firebaseAuthStore-mq59gNxh.js (removed) 790 B 🟢 -790 B 🟢 -390 B 🟢 -345 B
assets/auth-BuF-hVAb.js (new) 347 B 🔴 +347 B 🔴 +222 B 🔴 +191 B
assets/auth-Dcy-z73C.js (removed) 347 B 🟢 -347 B 🟢 -221 B 🟢 -211 B
assets/PasswordFields-BAi3GPM-.js 4.51 kB 4.51 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WorkspaceProfilePic-B0BztYjc.js 1.57 kB 1.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-Pm320iRZ.js (removed) 2.68 kB 🟢 -2.68 kB 🟢 -1.32 kB 🟢 -1.18 kB
assets/useSubscriptionDialog-pmhDKFLl.js (new) 2.68 kB 🔴 +2.68 kB 🔴 +1.32 kB 🔴 +1.19 kB
assets/useSubscriptionDialog-2bX69i-X.js (new) 783 B 🔴 +783 B 🔴 +386 B 🔴 +342 B
assets/useSubscriptionDialog-D-WmTKxp.js (removed) 783 B 🟢 -783 B 🟢 -389 B 🟢 -343 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useTerminalTabs-BkQJHR3C.js (removed) 9.9 kB 🟢 -9.9 kB 🟢 -3.41 kB 🟢 -3 kB
assets/useTerminalTabs-DbBBnUWr.js (new) 9.9 kB 🔴 +9.9 kB 🔴 +3.4 kB 🔴 +2.99 kB
assets/TopbarBadge-BsZTG314.js (removed) 7.52 kB 🟢 -7.52 kB 🟢 -1.82 kB 🟢 -1.6 kB
assets/TopbarBadge-DAhlTQxW.js (new) 7.52 kB 🔴 +7.52 kB 🔴 +1.82 kB 🔴 +1.6 kB
assets/ComfyQueueButton-BCot3PGl.js (removed) 7.13 kB 🟢 -7.13 kB 🟢 -2.31 kB 🟢 -2.06 kB
assets/ComfyQueueButton-DsqP0i3X.js (new) 7.13 kB 🔴 +7.13 kB 🔴 +2.31 kB 🔴 +2.06 kB
assets/SubscribeButton-B_AJMPuh.js (new) 3.68 kB 🔴 +3.68 kB 🔴 +1.38 kB 🔴 +1.24 kB
assets/SubscribeButton-DcXjUYdv.js (removed) 3.68 kB 🟢 -3.68 kB 🟢 -1.38 kB 🟢 -1.25 kB
assets/WidgetButton-DVfWCi_V.js (removed) 1.84 kB 🟢 -1.84 kB 🟢 -877 B 🟢 -776 B
assets/WidgetButton-Lg0M1Jvg.js (new) 1.84 kB 🔴 +1.84 kB 🔴 +879 B 🔴 +768 B
assets/cloudFeedbackTopbarButton-9IF1fkAL.js (new) 1.6 kB 🔴 +1.6 kB 🔴 +856 B 🔴 +758 B
assets/cloudFeedbackTopbarButton-DQlwc7nC.js (removed) 1.6 kB 🟢 -1.6 kB 🟢 -857 B 🟢 -735 B
assets/CloudBadge-Jsl50D-2.js (new) 1.2 kB 🔴 +1.2 kB 🔴 +593 B 🔴 +510 B
assets/CloudBadge-nZ5YFAbJ.js (removed) 1.2 kB 🟢 -1.2 kB 🟢 -595 B 🟢 -512 B
assets/ComfyQueueButton-Cc_ETLEH.js (new) 795 B 🔴 +795 B 🔴 +393 B 🔴 +354 B
assets/ComfyQueueButton-DlZg_exB.js (removed) 795 B 🟢 -795 B 🟢 -394 B 🟢 -352 B
assets/Button-ChqYCdrL.js 3 kB 3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-Dtdiv1Hu.js 1.17 kB 1.17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 8 added / 8 removed

Data & Services — 2.1 MB (baseline 2.1 MB) • 🔴 +710 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-BpBp8tzL.js (new) 1.3 MB 🔴 +1.3 MB 🔴 +298 kB 🔴 +232 kB
assets/dialogService-9SmI0wfa.js (removed) 1.3 MB 🟢 -1.3 MB 🟢 -298 kB 🟢 -232 kB
assets/api-3tJfoD2n.js (new) 641 kB 🔴 +641 kB 🔴 +144 kB 🔴 +116 kB
assets/api-7EHTuGQP.js (removed) 641 kB 🟢 -641 kB 🟢 -144 kB 🟢 -115 kB
assets/load3dService-CQbDlxIr.js (removed) 91.1 kB 🟢 -91.1 kB 🟢 -19.1 kB 🟢 -16.4 kB
assets/load3dService-fJk4Uw67.js (new) 91.1 kB 🔴 +91.1 kB 🔴 +19.1 kB 🔴 +16.4 kB
assets/teamWorkspaceStore-BORj7bCr.js (new) 27.1 kB 🔴 +27.1 kB 🔴 +6.12 kB 🔴 +5.42 kB
assets/teamWorkspaceStore-u-xjun7f.js (removed) 27.1 kB 🟢 -27.1 kB 🟢 -6.12 kB 🟢 -5.41 kB
assets/systemStatsStore-7Xhr35Gr.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +4.29 kB 🔴 +3.77 kB
assets/systemStatsStore-DpwWWYi1.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -4.29 kB 🟢 -3.77 kB
assets/releaseStore-D9FH0PSY.js (new) 8.14 kB 🔴 +8.14 kB 🔴 +2.24 kB 🔴 +1.97 kB
assets/releaseStore-DWAS8XnF.js (removed) 8.14 kB 🟢 -8.14 kB 🟢 -2.24 kB 🟢 -1.97 kB
assets/keybindingService-BQd5oOiq.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.71 kB 🔴 +1.47 kB
assets/keybindingService-oR8W5ZJk.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.72 kB 🟢 -1.48 kB
assets/serverConfigStore-3Fx4b3JX.js (new) 2.32 kB 🔴 +2.32 kB 🔴 +791 B 🔴 +691 B
assets/serverConfigStore-DB58Z5s2.js (removed) 2.32 kB 🟢 -2.32 kB 🟢 -791 B 🟢 -690 B
assets/bootstrapStore-2bm4ztpc.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +881 B 🔴 +812 B
assets/bootstrapStore-BddSu94k.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -880 B 🟢 -814 B
assets/userStore-D-p_SVm_.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -721 B 🟢 -676 B
assets/userStore-DQnPQAO_.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +719 B 🔴 +633 B
assets/audioService-BouFc6he.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -846 B 🟢 -729 B
assets/audioService-V8BCs9C8.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +846 B 🔴 +731 B
assets/releaseStore-FtDZWDtW.js (removed) 762 B 🟢 -762 B 🟢 -388 B 🟢 -334 B
assets/releaseStore-vs7_6VY4.js (new) 762 B 🔴 +762 B 🔴 +385 B 🔴 +334 B
assets/dialogStore-D2gUGUn6.js 4.1 kB 4.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 12 added / 12 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-BCejprch.js (new) 177 kB 🔴 +177 kB 🔴 +38.9 kB 🔴 +32.4 kB
assets/useConflictDetection-Cyk81ZLv.js (removed) 177 kB 🟢 -177 kB 🟢 -38.9 kB 🟢 -32.4 kB
assets/useLoad3d--JLfQ151.js (removed) 14.4 kB 🟢 -14.4 kB 🟢 -3.56 kB 🟢 -3.14 kB
assets/useLoad3d-Db25YVhl.js (new) 14.4 kB 🔴 +14.4 kB 🔴 +3.56 kB 🔴 +3.14 kB
assets/useLoad3dViewer-C57FwCTr.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.16 kB 🔴 +2.8 kB
assets/useLoad3dViewer-DLGsls-S.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.16 kB 🟢 -2.8 kB
assets/useErrorHandling-B-3BGL76.js (removed) 4.26 kB 🟢 -4.26 kB 🟢 -1.35 kB 🟢 -1.18 kB
assets/useErrorHandling-CFgA8qSy.js (new) 4.26 kB 🔴 +4.26 kB 🔴 +1.34 kB 🔴 +1.18 kB
assets/useWorkspaceUI-BUhmX7Yy.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +883 B 🔴 +765 B
assets/useWorkspaceUI-CTUia8rM.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -881 B 🟢 -761 B
assets/useSubscriptionActions-Cc97tziM.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -754 B 🟢 -653 B
assets/useSubscriptionActions-D4gaysgN.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +755 B 🔴 +682 B
assets/subscriptionCheckoutUtil-BgUAc3ct.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +781 B 🔴 +687 B
assets/subscriptionCheckoutUtil-D--An4VW.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -784 B 🟢 -683 B
assets/useExternalLink-BmIleWA2.js (new) 1.63 kB 🔴 +1.63 kB 🔴 +755 B 🔴 +669 B
assets/useExternalLink-DWs-fjHA.js (removed) 1.63 kB 🟢 -1.63 kB 🟢 -756 B 🟢 -671 B
assets/useCopyToClipboard-BCOSf9ef.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -669 B 🟢 -564 B
assets/useCopyToClipboard-BSqdN5jG.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +668 B 🔴 +562 B
assets/useSubscriptionCredits-08m0FdFr.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -499 B 🟢 -430 B
assets/useSubscriptionCredits-EEbu4hLQ.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +501 B 🔴 +457 B
assets/useLoad3d-DBYxb3XE.js (new) 861 B 🔴 +861 B 🔴 +427 B 🔴 +380 B
assets/useLoad3d-Dn8tD2IX.js (removed) 861 B 🟢 -861 B 🟢 -427 B 🟢 -381 B
assets/audioUtils-8ftIr8xG.js (removed) 858 B 🟢 -858 B 🟢 -498 B 🟢 -404 B
assets/audioUtils-DzS3ifaV.js (new) 858 B 🔴 +858 B 🔴 +497 B 🔴 +401 B
assets/useLoad3dViewer-DXJ_mziW.js (removed) 840 B 🟢 -840 B 🟢 -410 B 🟢 -373 B
assets/useLoad3dViewer-ztGzAJG-.js (new) 840 B 🔴 +840 B 🔴 +411 B 🔴 +368 B
assets/useCurrentUser-BGbQUrcJ.js (removed) 724 B 🟢 -724 B 🟢 -372 B 🟢 -327 B
assets/useCurrentUser-CFTy2iNw.js (new) 724 B 🔴 +724 B 🔴 +376 B 🔴 +328 B
assets/_plugin-vue_export-helper-CAbbkOlw.js 315 B 315 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-FW_Ghng2.js 7 kB 7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/envUtil-Djb4sHrV.js 524 B 524 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-Cc2LFa5s.js 1.56 kB 1.56 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/networkUtil-Du2a_n7V.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SkeletonUtils-DwBAnKr-.js 133 B 133 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 14 added / 14 removed

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-xterm-3PfzLF46.js (new) 398 kB 🔴 +398 kB 🔴 +79.3 kB 🔴 +63.6 kB
assets/vendor-xterm-DOEEpxXk.js (removed) 398 kB 🟢 -398 kB 🟢 -79.3 kB 🟢 -63.5 kB
assets/vendor-axios-D0w6WYH0.js 71.6 kB 71.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-chart-CIdI9Yl4.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-firebase-CLEC0CcJ.js 842 kB 842 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-i18n-C6_f776o.js 132 kB 132 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-markdown-BkVHYrKV.js 102 kB 102 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DPcKX1Hx.js 2.16 MB 2.16 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-Dw8RivU1.js 1.74 MB 1.74 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-CPrt7lw0.js 240 kB 240 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-sentry-BVA5kbUC.js 183 kB 183 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-CJhOuqDg.js 1.8 MB 1.8 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CvX7mojg.js 632 kB 632 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-core-BBP9kkTE.js 312 kB 312 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vueuse-CS5mlw4Q.js 111 kB 111 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-yjs-BtrvIr1x.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-zod-gAWmQIF-.js 110 kB 110 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Other — 7.13 MB (baseline 7.1 MB) • 🔴 +31.1 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/i18n-CFhiAM2s.js (new) 480 kB 🔴 +480 kB 🔴 +91.8 kB 🔴 +71.5 kB
assets/i18n-0PstQIzB.js (removed) 480 kB 🟢 -480 kB 🟢 -91.7 kB 🟢 -71.5 kB
assets/nodeDefs-Bjx0mgI7.js (removed) 442 kB 🟢 -442 kB 🟢 -67.1 kB 🟢 -46.4 kB
assets/nodeDefs-OJaEsj0Y.js (new) 442 kB 🔴 +442 kB 🔴 +67.1 kB 🔴 +46.4 kB
assets/nodeDefs-BaOl03VS.js (new) 406 kB 🔴 +406 kB 🔴 +61 kB 🔴 +42.9 kB
assets/nodeDefs-fPFi65f3.js (removed) 406 kB 🟢 -406 kB 🟢 -61 kB 🟢 -42.9 kB
assets/nodeDefs-DDR1mCTO.js (removed) 405 kB 🟢 -405 kB 🟢 -63.1 kB 🟢 -44.5 kB
assets/nodeDefs-WXDPBjW6.js (new) 405 kB 🔴 +405 kB 🔴 +63.1 kB 🔴 +44.5 kB
assets/nodeDefs-B3gfi4ez.js (new) 375 kB 🔴 +375 kB 🔴 +61.1 kB 🔴 +42.7 kB
assets/nodeDefs-Ch6ZXz-h.js (removed) 375 kB 🟢 -375 kB 🟢 -61.1 kB 🟢 -42.7 kB
assets/nodeDefs-BCF6YMp3.js (removed) 365 kB 🟢 -365 kB 🟢 -59.9 kB 🟢 -42.5 kB
assets/nodeDefs-DJwr7gA_.js (new) 365 kB 🔴 +365 kB 🔴 +59.9 kB 🔴 +42.5 kB
assets/nodeDefs-4ZA9-QzB.js (removed) 361 kB 🟢 -361 kB 🟢 -58.6 kB 🟢 -42.8 kB
assets/nodeDefs-BGDE4Bfq.js (new) 361 kB 🔴 +361 kB 🔴 +58.6 kB 🔴 +42.8 kB
assets/nodeDefs-Dq3oYs6j.js (new) 361 kB 🔴 +361 kB 🔴 +60 kB 🔴 +43.6 kB
assets/nodeDefs-DyA4_B3a.js (removed) 361 kB 🟢 -361 kB 🟢 -59.9 kB 🟢 -43.6 kB
assets/nodeDefs-4hvYRxdj.js (new) 358 kB 🔴 +358 kB 🔴 +57.4 kB 🔴 +41.9 kB
assets/nodeDefs-D18zvGhR.js (removed) 358 kB 🟢 -358 kB 🟢 -57.4 kB 🟢 -41.9 kB
assets/nodeDefs-D-Q-rY5U.js (new) 354 kB 🔴 +354 kB 🔴 +56.5 kB 🔴 +41.3 kB
assets/nodeDefs-DT6NpDBI.js (removed) 354 kB 🟢 -354 kB 🟢 -56.5 kB 🟢 -41.3 kB
assets/nodeDefs-_IXEWmm8.js (removed) 332 kB 🟢 -332 kB 🟢 -58.5 kB 🟢 -41.2 kB
assets/nodeDefs-XVX3qm7r.js (new) 332 kB 🔴 +332 kB 🔴 +58.5 kB 🔴 +41.2 kB
assets/nodeDefs-BS6wnxse.js (removed) 329 kB 🟢 -329 kB 🟢 -57.5 kB 🟢 -40 kB
assets/nodeDefs-DUgFcSCz.js (new) 329 kB 🔴 +329 kB 🔴 +57.5 kB 🔴 +40 kB
assets/main-CN7pSufO.js (removed) 180 kB 🟢 -180 kB 🟢 -47.6 kB 🟢 -38 kB
assets/main-DMX4rm1H.js (new) 180 kB 🔴 +180 kB 🔴 +47.6 kB 🔴 +38 kB
assets/main-Dt6bQoC3.js (removed) 161 kB 🟢 -161 kB 🟢 -42.9 kB 🟢 -35 kB
assets/main-DYZ26Qq7.js (new) 161 kB 🔴 +161 kB 🔴 +42.9 kB 🔴 +35 kB
assets/main-5vUvgJMx.js (removed) 155 kB 🟢 -155 kB 🟢 -42.8 kB 🟢 -34.6 kB
assets/main-Cd2_rR09.js (new) 155 kB 🔴 +155 kB 🔴 +42.8 kB 🔴 +34.6 kB
assets/main-B_En4SpT.js (removed) 148 kB 🟢 -148 kB 🟢 -42.6 kB 🟢 -34.4 kB
assets/main-hI9XKjOm.js (new) 148 kB 🔴 +148 kB 🔴 +42.6 kB 🔴 +34.4 kB
assets/main-BYoy9XSQ.js (removed) 136 kB 🟢 -136 kB 🟢 -41.3 kB 🟢 -35 kB
assets/main-DMSoONgu.js (new) 136 kB 🔴 +136 kB 🔴 +41.3 kB 🔴 +34.9 kB
assets/main-2HxSpwOp.js (removed) 133 kB 🟢 -133 kB 🟢 -40.8 kB 🟢 -33.4 kB
assets/main-Dr9_Hkeg.js (new) 133 kB 🔴 +133 kB 🔴 +40.8 kB 🔴 +33.4 kB
assets/main-CiTAARZa.js (new) 131 kB 🔴 +131 kB 🔴 +40.3 kB 🔴 +33.9 kB
assets/main-Dn8ME7jP.js (removed) 131 kB 🟢 -131 kB 🟢 -40.4 kB 🟢 -34 kB
assets/main-BuWOig7p.js (removed) 129 kB 🟢 -129 kB 🟢 -40.2 kB 🟢 -34 kB
assets/main-CRYUSY-1.js (new) 129 kB 🔴 +129 kB 🔴 +40.2 kB 🔴 +34 kB
assets/main-Ceb-3q1b.js (new) 128 kB 🔴 +128 kB 🔴 +39.6 kB 🔴 +33.6 kB
assets/main-dc7AuxCr.js (removed) 128 kB 🟢 -128 kB 🟢 -39.6 kB 🟢 -33.6 kB
assets/main-BenE6Oix.js (new) 114 kB 🔴 +114 kB 🔴 +39.4 kB 🔴 +31.8 kB
assets/main-CKN_4E4Z.js (removed) 114 kB 🟢 -114 kB 🟢 -39.4 kB 🟢 -31.7 kB
assets/main-BpnmNj1n.js (removed) 113 kB 🟢 -113 kB 🟢 -39.4 kB 🟢 -31.5 kB
assets/main-D_v_zmb1.js (new) 113 kB 🔴 +113 kB 🔴 +39.4 kB 🔴 +31.5 kB
assets/core-DJKU3FX-.js (new) 71.7 kB 🔴 +71.7 kB 🔴 +18.4 kB 🔴 +15.8 kB
assets/core-BM-D68wz.js (removed) 71.4 kB 🟢 -71.4 kB 🟢 -18.4 kB 🟢 -15.8 kB
assets/groupNode-2TOOM5zm.js (new) 70.9 kB 🔴 +70.9 kB 🔴 +17.5 kB 🔴 +15.4 kB
assets/groupNode-C8t7IizW.js (removed) 70.9 kB 🟢 -70.9 kB 🟢 -17.5 kB 🟢 -15.4 kB
assets/WidgetSelect-BFq6nEhU.js (new) 56.6 kB 🔴 +56.6 kB 🔴 +12 kB 🔴 +10.4 kB
assets/WidgetSelect-Dgd1FI-v.js (removed) 56.6 kB 🟢 -56.6 kB 🟢 -12 kB 🟢 -10.4 kB
assets/SettingDialogContent-C5AIIz5H.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +8 kB 🔴 +7.05 kB
assets/SettingDialogContent-DEezyb5k.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -8 kB 🟢 -7.05 kB
assets/Load3DControls-BUbKM3pY.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -5.33 kB 🟢 -4.63 kB
assets/Load3DControls-W_DoilRJ.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +5.33 kB 🔴 +4.63 kB
assets/WidgetPainter-CpiAHxqP.js (new) 30.5 kB 🔴 +30.5 kB 🔴 +7.4 kB 🔴 +6.52 kB
assets/SubscriptionRequiredDialogContent-DkD0XxhY.js (removed) 25.4 kB 🟢 -25.4 kB 🟢 -6.36 kB 🟢 -5.58 kB
assets/SubscriptionRequiredDialogContent-DqVdfUZ9.js (new) 25.4 kB 🔴 +25.4 kB 🔴 +6.36 kB 🔴 +5.58 kB
assets/Load3dViewerContent-DrfrPW9b.js (removed) 23.2 kB 🟢 -23.2 kB 🟢 -5.24 kB 🟢 -4.54 kB
assets/Load3dViewerContent-SgITUyGL.js (new) 23.2 kB 🔴 +23.2 kB 🔴 +5.24 kB 🔴 +4.54 kB
assets/WidgetImageCrop-BcfD197m.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.51 kB 🔴 +4.84 kB
assets/WidgetImageCrop-fw5biYXq.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.51 kB 🟢 -4.85 kB
assets/FormItem-BnAJeA_N.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -4.87 kB 🟢 -4.24 kB
assets/FormItem-Cr1iWoiZ.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +4.87 kB 🔴 +4.25 kB
assets/CurrentUserPopoverWorkspace-CVCM-FaM.js (new) 19.7 kB 🔴 +19.7 kB 🔴 +4.74 kB 🔴 +4.22 kB
assets/CurrentUserPopoverWorkspace-DF9LGjXS.js (removed) 19.7 kB 🟢 -19.7 kB 🟢 -4.74 kB 🟢 -4.22 kB
assets/SignInContent-B35MPKl1.js (removed) 19 kB 🟢 -19 kB 🟢 -4.8 kB 🟢 -4.21 kB
assets/SignInContent-TBmPTExb.js (new) 19 kB 🔴 +19 kB 🔴 +4.8 kB 🔴 +4.19 kB
assets/commands-D7Ez6YeH.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -3.84 kB 🟢 -3 kB
assets/commands-LfAehxTw.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +3.84 kB 🔴 +2.99 kB
assets/WidgetRecordAudio-BMRt3gQd.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -4.93 kB 🟢 -4.41 kB
assets/WidgetRecordAudio-iOiBCcPG.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +4.92 kB 🔴 +4.41 kB
assets/TopUpCreditsDialogContent-NJD8PYJQ.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.8 kB 🔴 +4.25 kB
assets/TopUpCreditsDialogContent-pyD71Pkl.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.8 kB 🟢 -4.25 kB
assets/commands-bneKLdja.js (new) 16.7 kB 🔴 +16.7 kB 🔴 +3.54 kB 🔴 +2.75 kB
assets/commands-DuYqNMWX.js (removed) 16.7 kB 🟢 -16.7 kB 🟢 -3.54 kB 🟢 -2.75 kB
assets/commands-CVZhWS_N.js (new) 16.7 kB 🔴 +16.7 kB 🔴 +3.57 kB 🔴 +2.84 kB
assets/commands-Ds7u8tBA.js (removed) 16.7 kB 🟢 -16.7 kB 🟢 -3.57 kB 🟢 -2.84 kB
assets/commands-BamWPikz.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +3.63 kB 🔴 +2.89 kB
assets/commands-ovF76AYH.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -3.64 kB 🟢 -2.89 kB
assets/Load3D-Chtuan7V.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.03 kB 🔴 +3.5 kB
assets/Load3D-DHbJQGmW.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.03 kB 🟢 -3.5 kB
assets/MissingModelsWarning-BCIwifWU.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -4.4 kB 🟢 -3.92 kB
assets/MissingModelsWarning-hefplIOM.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +4.4 kB 🔴 +3.91 kB
assets/commands-b4ZVTa0J.js (new) 15.9 kB 🔴 +15.9 kB 🔴 +3.39 kB 🔴 +2.84 kB
assets/commands-BTIhwSf_.js (removed) 15.9 kB 🟢 -15.9 kB 🟢 -3.39 kB 🟢 -2.84 kB
assets/SubscriptionPanelContentWorkspace-Bh_La5tZ.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -4.03 kB 🟢 -3.54 kB
assets/SubscriptionPanelContentWorkspace-Nuk0W3IC.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +4.04 kB 🔴 +3.55 kB
assets/WidgetInputNumber-BV76V31i.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +4.26 kB 🔴 +3.8 kB
assets/WidgetInputNumber-tToPLxp8.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -4.26 kB 🟢 -3.8 kB
assets/commands-Bvsmp41f.js (new) 15.4 kB 🔴 +15.4 kB 🔴 +3.37 kB 🔴 +2.83 kB
assets/commands-DFfk2Km5.js (removed) 15.4 kB 🟢 -15.4 kB 🟢 -3.37 kB 🟢 -2.83 kB
assets/commands-Ct4jSbcT.js (new) 15.4 kB 🔴 +15.4 kB 🔴 +3.28 kB 🔴 +2.67 kB
assets/commands-tMQq9SrH.js (removed) 15.4 kB 🟢 -15.4 kB 🟢 -3.28 kB 🟢 -2.67 kB
assets/commands-BCSmRi2Z.js (new) 15.3 kB 🔴 +15.3 kB 🔴 +3.23 kB 🔴 +2.68 kB
assets/commands-BYGUQRX1.js (removed) 15.3 kB 🟢 -15.3 kB 🟢 -3.23 kB 🟢 -2.67 kB
assets/commands-B6iGMTjt.js (new) 15.2 kB 🔴 +15.2 kB 🔴 +3.5 kB 🔴 +2.75 kB
assets/commands-CtxsvHdf.js (removed) 15.2 kB 🟢 -15.2 kB 🟢 -3.5 kB 🟢 -2.75 kB
assets/load3d-a1oc6-Hh.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -4.18 kB 🟢 -3.65 kB
assets/load3d-B8xcWbAs.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +4.18 kB 🔴 +3.65 kB
assets/commands-BqbXSiOi.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.42 kB 🔴 +2.56 kB
assets/commands-BxiMWv9a.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.42 kB 🟢 -2.56 kB
assets/commands-BfntAh7V.js (new) 14.4 kB 🔴 +14.4 kB 🔴 +3.41 kB 🔴 +2.5 kB
assets/commands-D4xkLWYG.js (removed) 14.4 kB 🟢 -14.4 kB 🟢 -3.41 kB 🟢 -2.5 kB
assets/LazyImage-Bir4uhOp.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -3.8 kB 🟢 -3.34 kB
assets/LazyImage-OWUjy-uU.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +3.8 kB 🔴 +3.33 kB
assets/AudioPreviewPlayer-CCaWnOVy.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -3.2 kB 🟢 -2.86 kB
assets/AudioPreviewPlayer-SaNVJ9jJ.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +3.2 kB 🔴 +2.86 kB
assets/NodeConflictDialogContent-pRvuOb4U.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.37 kB 🟢 -2.08 kB
assets/NodeConflictDialogContent-tzac1Ct9.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.36 kB 🔴 +2.06 kB
assets/nodeTemplates-B9Ukv3GY.js (new) 9.33 kB 🔴 +9.33 kB 🔴 +3.27 kB 🔴 +2.89 kB
assets/nodeTemplates-Dx8Vn6YL.js (removed) 9.33 kB 🟢 -9.33 kB 🟢 -3.27 kB 🟢 -2.88 kB
assets/InviteMemberDialogContent-C4Ylx13J.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.56 kB 🔴 +2.24 kB
assets/InviteMemberDialogContent-Dh_qcQkX.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.57 kB 🟢 -2.22 kB
assets/WidgetWithControl-_HbqmUtr.js (removed) 6.97 kB 🟢 -6.97 kB 🟢 -2.59 kB 🟢 -2.32 kB
assets/WidgetWithControl-C6JtfuLa.js (new) 6.97 kB 🔴 +6.97 kB 🔴 +2.59 kB 🔴 +2.32 kB
assets/Load3DConfiguration-D7iBFAe5.js (removed) 6.36 kB 🟢 -6.36 kB 🟢 -1.92 kB 🟢 -1.69 kB
assets/Load3DConfiguration-DpEeqMVM.js (new) 6.36 kB 🔴 +6.36 kB 🔴 +1.92 kB 🔴 +1.69 kB
assets/MissingNodesContent-C7X5SzHK.js (removed) 6.14 kB 🟢 -6.14 kB 🟢 -2.09 kB 🟢 -1.87 kB
assets/MissingNodesContent-D0lzOalL.js (new) 6.14 kB 🔴 +6.14 kB 🔴 +2.08 kB 🔴 +1.85 kB
assets/CreateWorkspaceDialogContent-BBI63ZTB.js (new) 5.58 kB 🔴 +5.58 kB 🔴 +2 kB 🔴 +1.74 kB
assets/CreateWorkspaceDialogContent-snzMBivf.js (removed) 5.58 kB 🟢 -5.58 kB 🟢 -2 kB 🟢 -1.74 kB
assets/EditWorkspaceDialogContent-Bk-kiAJs.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.96 kB 🔴 +1.7 kB
assets/EditWorkspaceDialogContent-BKBEkZsx.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.96 kB 🟢 -1.71 kB
assets/ValueControlPopover-BFj7wcD8.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.78 kB 🟢 -1.58 kB
assets/ValueControlPopover-DU0Y3Tgp.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.78 kB 🔴 +1.58 kB
assets/Preview3d-BrC06JlD.js (removed) 4.82 kB 🟢 -4.82 kB 🟢 -1.57 kB 🟢 -1.36 kB
assets/Preview3d-CCWbL2O5.js (new) 4.82 kB 🔴 +4.82 kB 🔴 +1.57 kB 🔴 +1.36 kB
assets/MissingNodesFooter-BQyX8Zb-.js (new) 4.8 kB 🔴 +4.8 kB 🔴 +1.78 kB 🔴 +1.58 kB
assets/MissingNodesFooter-INS5FJaH.js (removed) 4.8 kB 🟢 -4.8 kB 🟢 -1.78 kB 🟢 -1.58 kB
assets/DeleteWorkspaceDialogContent-_OkqUp95.js (removed) 4.28 kB 🟢 -4.28 kB 🟢 -1.65 kB 🟢 -1.43 kB
assets/DeleteWorkspaceDialogContent--u7s2le9.js (new) 4.28 kB 🔴 +4.28 kB 🔴 +1.64 kB 🔴 +1.43 kB
assets/LeaveWorkspaceDialogContent-BwYLn7bK.js (removed) 4.11 kB 🟢 -4.11 kB 🟢 -1.59 kB 🟢 -1.38 kB
assets/LeaveWorkspaceDialogContent-Ddf_YGAL.js (new) 4.11 kB 🔴 +4.11 kB 🔴 +1.59 kB 🔴 +1.38 kB
assets/RemoveMemberDialogContent-8Tq55Y_d.js (removed) 4.09 kB 🟢 -4.09 kB 🟢 -1.54 kB 🟢 -1.34 kB
assets/RemoveMemberDialogContent-B-kNIlB6.js (new) 4.09 kB 🔴 +4.09 kB 🔴 +1.54 kB 🔴 +1.34 kB
assets/RevokeInviteDialogContent-BGC99qW6.js (removed) 4 kB 🟢 -4 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/RevokeInviteDialogContent-MhwfGZSW.js (new) 4 kB 🔴 +4 kB 🔴 +1.55 kB 🔴 +1.36 kB
assets/WidgetGalleria-C8ikSQqn.js (removed) 3.61 kB 🟢 -3.61 kB 🟢 -1.39 kB 🟢 -1.25 kB
assets/WidgetGalleria-vzNjD_An.js (new) 3.61 kB 🔴 +3.61 kB 🔴 +1.39 kB 🔴 +1.25 kB
assets/saveMesh-BGVzMHF6.js (removed) 3.38 kB 🟢 -3.38 kB 🟢 -1.45 kB 🟢 -1.29 kB
assets/saveMesh-Bj2_tcfC.js (new) 3.38 kB 🔴 +3.38 kB 🔴 +1.45 kB 🔴 +1.29 kB
assets/WidgetTextarea-D07MktMK.js (removed) 3.14 kB 🟢 -3.14 kB 🟢 -1.3 kB 🟢 -1.14 kB
assets/WidgetTextarea-DbegG7pw.js (new) 3.14 kB 🔴 +3.14 kB 🔴 +1.3 kB 🔴 +1.14 kB
assets/WidgetImageCompare-B1RSu0_k.js (removed) 3.1 kB 🟢 -3.1 kB 🟢 -1.15 kB 🟢 -1.02 kB
assets/WidgetImageCompare-CXXuUi79.js (new) 3.1 kB 🔴 +3.1 kB 🔴 +1.15 kB 🔴 +1.02 kB
assets/cloudSessionCookie-CNQUUN8P.js (new) 3.07 kB 🔴 +3.07 kB 🔴 +1.08 kB 🔴 +961 B
assets/cloudSessionCookie-m6dX4uAQ.js (removed) 3.07 kB 🟢 -3.07 kB 🟢 -1.08 kB 🟢 -957 B
assets/WidgetColorPicker-CBOK-9Qi.js (new) 2.9 kB 🔴 +2.9 kB 🔴 +1.23 kB 🔴 +1.11 kB
assets/WidgetColorPicker-jDbRm4n6.js (removed) 2.9 kB 🟢 -2.9 kB 🟢 -1.23 kB 🟢 -1.11 kB
assets/WidgetMarkdown-BYrCy83F.js (new) 2.88 kB 🔴 +2.88 kB 🔴 +1.22 kB 🔴 +1.05 kB
assets/WidgetMarkdown-wePHc2fh.js (removed) 2.88 kB 🟢 -2.88 kB 🟢 -1.22 kB 🟢 -1.07 kB
assets/ApiNodesSignInContent-D9D7DYbz.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.05 kB 🔴 +919 B
assets/ApiNodesSignInContent-SdEmJCMH.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.05 kB 🟢 -919 B
assets/WidgetToggleSwitch-CgpZMcLN.js (new) 2.5 kB 🔴 +2.5 kB 🔴 +1.09 kB 🔴 +995 B
assets/WidgetToggleSwitch-CoKD027B.js (removed) 2.5 kB 🟢 -2.5 kB 🟢 -1.09 kB 🟢 -990 B
assets/ImportFailedNodeContent-CFc03Tip.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +972 B 🔴 +828 B
assets/ImportFailedNodeContent-VPjQzi79.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -974 B 🟢 -828 B
assets/NodeConflictFooter-Dh-VROp2.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.03 kB 🟢 -899 B
assets/NodeConflictFooter-DYgsoeF4.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.03 kB 🔴 +898 B
assets/GlobalToast-BeqkcP-w.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -962 B 🟢 -800 B
assets/GlobalToast-CwWDSIWP.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +962 B 🔴 +806 B
assets/MediaVideoTop-CKmQms8p.js (new) 2.23 kB 🔴 +2.23 kB 🔴 +937 B 🔴 +800 B
assets/MediaVideoTop-CQw3f2T6.js (removed) 2.23 kB 🟢 -2.23 kB 🟢 -937 B 🟢 -800 B
assets/WidgetChart-BZvs6tsT.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +948 B 🔴 +822 B
assets/WidgetChart-Dsp6bf_j.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -948 B 🟢 -821 B
assets/SubscribeToRun-BADQN46h.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +989 B 🔴 +851 B
assets/SubscribeToRun-P00x3VuU.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -990 B 🟢 -870 B
assets/WidgetLayoutField-3oUQVRUT.js (new) 1.95 kB 🔴 +1.95 kB 🔴 +879 B 🔴 +760 B
assets/WidgetLayoutField-BcUSnWUK.js (removed) 1.95 kB 🟢 -1.95 kB 🟢 -879 B 🟢 -763 B
assets/ImportFailedNodeFooter-CN88Otlf.js (new) 1.88 kB 🔴 +1.88 kB 🔴 +867 B 🔴 +755 B
assets/ImportFailedNodeFooter-D_BxHHK1.js (removed) 1.88 kB 🟢 -1.88 kB 🟢 -866 B 🟢 -752 B
assets/WidgetInputText-8sROHU7_.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +874 B 🔴 +808 B
assets/WidgetInputText-MXN3EUoN.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -872 B 🟢 -795 B
assets/Media3DTop-B0hjzWGd.js (new) 1.82 kB 🔴 +1.82 kB 🔴 +897 B 🔴 +764 B
assets/Media3DTop-DTYkrVtB.js (removed) 1.82 kB 🟢 -1.82 kB 🟢 -897 B 🟢 -767 B
assets/BaseViewTemplate-BhBVWOWE.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +910 B 🔴 +815 B
assets/BaseViewTemplate-BnXUotno.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -910 B 🟢 -799 B
assets/MediaImageTop-ATOoJCQr.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -879 B 🟢 -750 B
assets/MediaImageTop-BaVMScBp.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +877 B 🔴 +751 B
assets/CloudRunButtonWrapper-Ar_KfN43.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +782 B 🔴 +701 B
assets/CloudRunButtonWrapper-H5A44p3r.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -781 B 🟢 -707 B
assets/signInSchema-DmfohtOF.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -562 B 🟢 -518 B
assets/signInSchema-TMhBa2K2.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +562 B 🔴 +514 B
assets/MediaAudioTop-AFmsiWi3.js (removed) 1.43 kB 🟢 -1.43 kB 🟢 -759 B 🟢 -632 B
assets/MediaAudioTop-DAlaM_mk.js (new) 1.43 kB 🔴 +1.43 kB 🔴 +758 B 🔴 +633 B
assets/cloudBadges-CWO9dEw-.js (removed) 1.37 kB 🟢 -1.37 kB 🟢 -701 B 🟢 -612 B
assets/cloudBadges-Dup6iP9T.js (new) 1.37 kB 🔴 +1.37 kB 🔴 +701 B 🔴 +617 B
assets/cloudSubscription-CHi_cgM3.js (new) 1.32 kB 🔴 +1.32 kB 🔴 +652 B 🔴 +567 B
assets/cloudSubscription-i7pEWEr0.js (removed) 1.32 kB 🟢 -1.32 kB 🟢 -652 B 🟢 -562 B
assets/widgetPropFilter-CYRkKG06.js (new) 1.1 kB 🔴 +1.1 kB 🔴 +511 B 🔴 +453 B
assets/widgetPropFilter-DyQHILEf.js (removed) 1.1 kB 🟢 -1.1 kB 🟢 -509 B 🟢 -448 B
assets/NodeConflictHeader-DRxQs5TH.js (removed) 1.09 kB 🟢 -1.09 kB 🟢 -565 B 🟢 -478 B
assets/NodeConflictHeader-Dzr-2wLT.js (new) 1.09 kB 🔴 +1.09 kB 🔴 +564 B 🔴 +477 B
assets/ImportFailedNodeHeader-AFugOvJc.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +551 B 🔴 +469 B
assets/ImportFailedNodeHeader-DUns4_x2.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -550 B 🟢 -471 B
assets/SubscriptionPanelContentWorkspace-DMZ3tPiu.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -479 B 🟢 -418 B
assets/SubscriptionPanelContentWorkspace-N396uR83.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +481 B 🔴 +416 B
assets/Load3D-CfmnqYsV.js (new) 1.04 kB 🔴 +1.04 kB 🔴 +486 B 🔴 +430 B
assets/Load3D-DRRU1QUy.js (removed) 1.04 kB 🟢 -1.04 kB 🟢 -485 B 🟢 -431 B
assets/nightlyBadges-Dh5IplQO.js (new) 1 kB 🔴 +1 kB 🔴 +536 B 🔴 +471 B
assets/nightlyBadges-DmY3YJpU.js (removed) 1 kB 🟢 -1 kB 🟢 -537 B 🟢 -475 B
assets/Load3dViewerContent-B-PGladc.js (removed) 961 B 🟢 -961 B 🟢 -457 B 🟢 -410 B
assets/Load3dViewerContent-DxQagSDA.js (new) 961 B 🔴 +961 B 🔴 +456 B 🔴 +403 B
assets/SettingDialogContent-CDodO9RO.js (removed) 917 B 🟢 -917 B 🟢 -442 B 🟢 -389 B
assets/SettingDialogContent-Dhf8KEOf.js (new) 917 B 🔴 +917 B 🔴 +441 B 🔴 +388 B
assets/graphHasMissingNodes-9uCB0A88.js (new) 761 B 🔴 +761 B 🔴 +373 B 🔴 +324 B
assets/graphHasMissingNodes-CIUysw1W.js (removed) 761 B 🟢 -761 B 🟢 -376 B 🟢 -328 B
assets/WidgetLegacy-CIidAuhL.js (new) 747 B 🔴 +747 B 🔴 +386 B 🔴 +364 B
assets/WidgetLegacy-t9yZZZku.js (removed) 747 B 🟢 -747 B 🟢 -387 B 🟢 -338 B
assets/previousFullPath-BwqJAUKa.js (new) 665 B 🔴 +665 B 🔴 +366 B 🔴 +318 B
assets/previousFullPath-DsBk66MD.js (removed) 665 B 🟢 -665 B 🟢 -368 B 🟢 -321 B
assets/WidgetInputNumber-CO_w5jTi.js (new) 392 B 🔴 +392 B 🔴 +232 B 🔴 +215 B
assets/WidgetInputNumber-DwJ042Vx.js (removed) 392 B 🟢 -392 B 🟢 -229 B 🟢 -194 B
assets/i18n-BHeCxExo.js (removed) 199 B 🟢 -199 B 🟢 -161 B 🟢 -139 B
assets/i18n-D8UtIzqx.js (new) 199 B 🔴 +199 B 🔴 +161 B 🔴 +139 B
assets/AnimationControls-bPyINTJI.js 4.61 kB 4.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auto-DjoqfnTX.js 1.7 kB 1.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/comfy-logo-single-DCVL1uOL.js 198 B 198 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyOrgHeader-32ZIoIYN.js 909 B 909 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingNodesHeader-BOlbqJ0O.js 1.09 kB 1.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-Dq6XmUX_.js 92 B 92 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/PanelTemplate-C1h0RxBM.js 1.2 kB 1.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-Ca2S-reV.js 1.87 kB 1.87 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SelectValue-1KJOqzqF.js 8.94 kB 8.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-BHt-6Ao_.js 1.62 kB 1.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-D5wathvf.js 244 B 244 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-Bh_ZdHn9.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/src-DAMctjF_.js 251 B 251 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/types-VDank0gz.js 318 B 318 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-RLUqfB5N.js 445 B 445 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-2w5BjjHm.js 3.94 kB 3.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-Djm16aYN.js 131 B 131 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-BCsKJASV.js 393 B 393 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 109 added / 108 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: 6

🤖 Fix all issues with AI agents
In `@src/components/painter/WidgetPainter.vue`:
- Around line 71-99: The toolbar uses raw <button> elements for the brush/eraser
toggles; replace them with the project's shared button components (e.g.,
TextButton or IconTextButton) to keep consistent styling and behavior: import
the desired component(s) from the button components, register them in the
component, and swap each <button> (the ones bound to tool and PAINTER_TOOLS and
the clear action at the other mentioned lines) for the shared component while
preserving the existing :class binding, `@click` handlers (e.g., `@click`="tool =
PAINTER_TOOLS.BRUSH"/ERASER), and translated label slots ({{ $t('painter.brush')
}} / {{ $t('painter.eraser') }}); if the shared component exposes props for
variant/active state or class forwarding, use those instead of duplicating
styles so the active state uses the component's selected variant.
- Around line 275-309: You’re using a props object (const props =
defineProps<...>()) instead of Vue 3.5-style destructuring; replace it with
destructured props like const { nodeId } = defineProps<{ nodeId: string }>() (or
use const { nodeId } = toRefs(defineProps(...)) if you need reactivity) and then
pass nodeId directly into usePainter (replace usePainter(props.nodeId, {
canvasEl, modelValue }) with usePainter(nodeId, { canvasEl, modelValue })); also
update any other references to props.nodeId to use the new nodeId binding.
- Around line 129-136: Replace the PrimeVue ColorPicker usage in
WidgetPainter.vue (instances bound to brushColorDisplay at the template around
the ColorPicker components and the :pt prop) with a native <input type="color">,
remove the :pt prop and any Tailwind classes using the `!` prefix, and delete
the PrimeVue import/registration for ColorPicker; ensure the new <input
type="color"> is v-model bound to brushColorDisplay (or the same reactive
prop/computed used by the current ColorPicker), apply equivalent Tailwind 4
classes (without `!`) to match sizing/rounded/border styles (e.g., use h-4 w-8
rounded-full border-none or wrapper styling), and update the other occurrence
(the block around lines 238–242) similarly so both uses are consistent and no
`!` overrides remain.
- Around line 266-268: The file directly imports PrimeVue's ColorPicker (import
ColorPicker from 'primevue/colorpicker') which violates the guideline; replace
this raw import and any direct usage of ColorPicker in WidgetPainter.vue with
your project’s approved wrapper component (e.g., FormColorPicker or
ColorCustomizationSelector): remove the ColorPicker import, import the chosen
wrapper instead, update template bindings/props/events to match the wrapper's
API, and keep existing related symbols (useElementSize, computed,
useTemplateRef) unchanged so layout and reactivity continue to work; ensure prop
names and v-model/event names are adapted to the wrapper’s contract.

In `@src/composables/painter/usePainter.ts`:
- Around line 509-545: Wrap the upload and JSON parsing in serializeValue() in a
try/catch around the api.fetchApi(...) call and the subsequent resp.json() so
network failures and invalid JSON are caught; on error set isDirty.value
appropriately, show a localized toast via
useToastStore().addAlert(t('painter.uploadErrorGeneric')) and rethrow or return
modelValue.value as appropriate. Also handle non-200 statuses inside the try by
using t('painter.uploadError', { status: resp.status, statusText:
resp.statusText }) for the toast instead of the hardcoded string, and only set
modelValue.value/isDirty.value after successful parsing; import useI18n() at the
top of the file and call const { t } = useI18n() inside the module, and add the
suggested keys painter.uploadError and painter.uploadErrorGeneric to
src/locales/en/main.json.

In `@src/renderer/extensions/vueNodes/widgets/composables/usePainterWidget.ts`:
- Around line 6-16: Convert the exported const to a function declaration named
usePainterWidget that returns ComfyWidgetConstructorV2; inside the returned
constructor function (the function that receives node: LGraphNode and inputSpec:
InputSpecV2) add a runtime type guard for inputSpec.default so you only pass a
string to node.addWidget (e.g. check typeof inputSpec.default === 'string' and
fall back to '' when undefined or of the wrong type) instead of casting (remove
the direct cast (inputSpec.default as string)); keep the widget options ({
serialize: true, canvasOnly: false }) and return the created widget from
node.addWidget.

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

🤖 Fix all issues with AI agents
In `@src/composables/painter/usePainter.ts`:
- Around line 18-23: Export the PainterTool type and let TypeScript infer
literal types for PAINTER_TOOLS by removing the explicit Record<string,
PainterTool> annotation; specifically, change the declaration so PainterTool is
exported (export type PainterTool = 'brush' | 'eraser') and declare
PAINTER_TOOLS as an exported const with the object and trailing as const (export
const PAINTER_TOOLS = { BRUSH: 'brush', ERASER: 'eraser' } as const) so external
usage like tool.value in WidgetPainter.vue can use the exported PainterTool type
and the correct literal types are preserved.
- Around line 576-581: In the restoreCanvas code path (the block that draws the
loaded image into the canvas, e.g., in restoreCanvas within usePainter.ts)
change isDirty.value from true to false so the canvas is marked clean after
restoration; leave hasStrokes as-is if stroke state should reflect content. This
ensures the subsequent serialization/upload logic (the branch that only skips
upload when isDirty is false) correctly treats a restored canvas as not needing
an upload.

In `@src/extensions/core/painter.ts`:
- Around line 6-11: The nodeCreated callback is unnecessarily declared async
even though it contains no await; remove the async keyword from the nodeCreated
method (the one checking node.constructor.comfyClass === 'PainterNode' and
calling node.setSize) so it no longer returns an implicit Promise and remains a
plain synchronous function.

@asagi4
Copy link

asagi4 commented Feb 1, 2026

Would it be difficult to add a "mask only" brush mode (could be a toggle in the color picker to keep the interface uncluttered)? I can see it being useful to add bits to the mask output without actually necessarily painting over the image.

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

🤖 Fix all issues with AI agents
In `@src/components/painter/WidgetPainter.vue`:
- Around line 148-167: The numeric opacity input in WidgetPainter.vue currently
uses `@click.prevent` which stops default click behavior and blocks caret
placement; change the listener to `@click.stop` (or remove it entirely) so the
click doesn't bubble to parents but still allows cursor placement, keeping the
existing `@change` handler that updates brushOpacityPercent and the input value
intact.
- Around line 64-69: The label elements for the painter controls are
inconsistently hidden in compact mode — keep layout consistent by either adding
the same v-if="!compact" guard to every label div that renders translation keys
(e.g. the divs showing $t('painter.tool'), $t('painter.size'),
$t('painter.color'), $t('painter.hardness') and other label divs between lines
105–192) or replace them with a small shared Label component/slot that
encapsulates the compact check (e.g. <Label :compact="compact">...</Label>) and
use that everywhere so the compact-mode visibility logic is centralized.

In `@src/composables/painter/usePainter.ts`:
- Around line 403-421: The resizeCanvas function currently captures prevData and
restores it with getCtx()?.putImageData, which silently clips content when
canvasWidth or canvasHeight shrink; update resizeCanvas to either (A) add a
clear inline comment above the prevData/putImageData block explaining that
silent clipping on shrink is intentional and acceptable for this app (mention
canvasWidth, canvasHeight, prevData, putImageData, getCtx, hasBaseSnapshot), or
(B) implement proportional scaling: create an offscreen/temp canvas, draw the
prevData into it, then use drawImage to scale the temp canvas into the new
el.width/el.height before replacing the main canvas (use getCtx/getCtx of temp,
drawImage instead of putImageData, and preserve strokeCanvas/baseCanvas state),
ensuring hasBaseSnapshot, strokeCtx and baseCtx handling remains consistent;
choose A for minimal change or B if you need to preserve painted content on
resize.
🧹 Nitpick comments (5)
src/components/painter/WidgetPainter.vue (1)

338-350: Use string instead of unknown for color setter parameter types.

Both brushColorDisplay and backgroundColorDisplay setters accept unknown, but the native <input type="color"> always produces a string. Using unknown here bypasses type safety unnecessarily.

♻️ Proposed fix
 const brushColorDisplay = computed({
   get: () => toHexFromFormat(brushColor.value, 'hex'),
-  set: (val: unknown) => {
+  set: (val: string) => {
     brushColor.value = toHexFromFormat(val, 'hex')
   }
 })

 const backgroundColorDisplay = computed({
   get: () => toHexFromFormat(backgroundColor.value, 'hex'),
-  set: (val: unknown) => {
+  set: (val: string) => {
     backgroundColor.value = toHexFromFormat(val, 'hex')
   }
 })
src/composables/painter/usePainter.ts (4)

499-510: isCanvasEmpty scans every pixel — expensive at large canvas sizes.

At the maximum canvas size of 4096×4096, this iterates over ~67 million alpha values before every serializeValue call. Consider an early-out approach: track whether any strokes have been made (you already have hasStrokes) and only fall back to the pixel scan when necessary, or sample a subset of pixels for a fast-path check.

Currently, hasStrokes already short-circuits on Line 500, which helps for the no-stroke case. However, after handleClear (Line 429: hasStrokes = false), this is already handled. The remaining concern is the full-canvas-cleared case where strokes existed but were entirely erased — requiring the full scan. This is a minor performance concern since it only fires on serialization.


78-95: Unsafe type assertions on node.properties values.

Lines 83–94 cast property values with as PainterTool, as number, as string without runtime validation. If the serialized properties contain unexpected types (e.g., from a corrupted workflow or schema migration), these casts silently produce incorrect state.

Consider adding lightweight runtime guards:

♻️ Proposed fix (example for one property)
-    if (props.painterTool != null) tool.value = props.painterTool as PainterTool
+    if (props.painterTool === 'brush' || props.painterTool === 'eraser')
+      tool.value = props.painterTool

617-621: Deep watchers on large store objects may cause performance overhead.

Lines 617–620 watch nodeOutputStore.nodeOutputs and nodeOutputStore.nodePreviewImages with { deep: true }. If these stores hold outputs for many nodes, every output change in the graph triggers the watcher. Consider narrowing the watch to only the relevant node's outputs, or using a computed that extracts the specific node's data.

♻️ Example
-  watch(() => nodeOutputStore.nodeOutputs, updateInputImageUrl, { deep: true })
-  watch(() => nodeOutputStore.nodePreviewImages, updateInputImageUrl, {
-    deep: true
-  })
+  const relevantOutputs = computed(() => {
+    const node = litegraphNode.value
+    const inputNode = node?.getInputNode(0)
+    if (!inputNode) return undefined
+    return nodeOutputStore.getNodeImageUrls(inputNode)
+  })
+  watch(relevantOutputs, updateInputImageUrl)

32-36: Accept MaybeRef<string> for nodeId to handle reactive updates.

While nodeId currently arrives as a plain string, the litegraphNode computed (line 60) closes over it and won't update if the prop changes. Other composables in the codebase (e.g., useNodePreviewState) use MaybeRefOrGetter<string> with toValue() for this pattern. Consider aligning usePainter with that approach for consistency and to guard against future component reuse scenarios.

Comment on lines +64 to +69
<div
v-if="!compact"
class="flex w-28 items-center truncate text-sm text-muted-foreground"
>
{{ $t('painter.tool') }}
</div>
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

Inconsistent compact-mode label visibility.

The "Tool" (Line 65) and "Size" (Line 106) labels are hidden in compact mode via v-if="!compact", but the "Color" (Line 129), "Hardness" (Line 171), and similar labels below lack this guard. In compact mode with grid-cols-1, these labels will still render as standalone full-width rows, making the layout inconsistent.

Either apply v-if="!compact" to all label divs, or wrap the labels in a shared template/component to centralize the compact logic.

Also applies to: 105-109, 127-192

🤖 Prompt for AI Agents
In `@src/components/painter/WidgetPainter.vue` around lines 64 - 69, The label
elements for the painter controls are inconsistently hidden in compact mode —
keep layout consistent by either adding the same v-if="!compact" guard to every
label div that renders translation keys (e.g. the divs showing
$t('painter.tool'), $t('painter.size'), $t('painter.color'),
$t('painter.hardness') and other label divs between lines 105–192) or replace
them with a small shared Label component/slot that encapsulates the compact
check (e.g. <Label :compact="compact">...</Label>) and use that everywhere so
the compact-mode visibility logic is centralized.

Comment on lines +148 to +167
<input
type="number"
:value="brushOpacityPercent"
min="0"
max="100"
step="1"
class="w-7 appearance-none border-0 bg-transparent text-right text-xs text-node-text-muted outline-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [-moz-appearance:textfield]"
@click.prevent
@change="
(e) => {
const val = Math.min(
100,
Math.max(0, Number((e.target as HTMLInputElement).value))
)
brushOpacityPercent = val
;(e.target as HTMLInputElement).value = String(val)
}
"
/>%</span
>
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

Opacity number input @click.prevent blocks caret placement.

Line 155: @click.prevent on the opacity <input type="number"> prevents the default click behavior, which means users cannot click to position the text cursor inside the field. This degrades the editing experience. If the intent is to prevent the parent from receiving the click, .stop is more appropriate.

♻️ Proposed fix
-              `@click.prevent`
+              `@click.stop`
🤖 Prompt for AI Agents
In `@src/components/painter/WidgetPainter.vue` around lines 148 - 167, The numeric
opacity input in WidgetPainter.vue currently uses `@click.prevent` which stops
default click behavior and blocks caret placement; change the listener to
`@click.stop` (or remove it entirely) so the click doesn't bubble to parents but
still allows cursor placement, keeping the existing `@change` handler that updates
brushOpacityPercent and the input value intact.

Comment on lines +403 to +421
function resizeCanvas() {
const el = canvasEl.value
if (!el) return
const prevData =
el.width > 0 && el.height > 0
? getCtx()?.getImageData(0, 0, el.width, el.height)
: null
el.width = canvasWidth.value
el.height = canvasHeight.value
if (prevData) {
getCtx()?.putImageData(prevData, 0, 0)
}

strokeCanvas = null
strokeCtx = null
baseCanvas = null
baseCtx = null
hasBaseSnapshot = 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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check canvas-related patterns in the codebase
rg -n "putImageData|drawImage" src/composables/ -C 3

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 49980


🏁 Script executed:

#!/bin/bash
# Check the overall usePainter.ts file structure and resizeCanvas usage
wc -l src/composables/painter/usePainter.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 111


🏁 Script executed:

#!/bin/bash
# Look for resizeCanvas calls and surrounding context
rg -n "resizeCanvas" src/ -C 5

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 3540


🏁 Script executed:

#!/bin/bash
# Check if there's any canvas size validation or warning logic elsewhere
rg -n "getImageData|canvasWidth|canvasHeight" src/composables/painter/usePainter.ts -C 2 | head -80

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2492


Add a clarifying comment on the silent content clipping behavior during canvas resize.

The resizeCanvas function preserves image data when dimensions change, but putImageData silently clips content that falls outside the new bounds. Since canvasWidth and canvasHeight are reactive refs that can shrink (from widget changes or image reloads), users could lose painted content unexpectedly. Either add a comment explaining why this clipping is acceptable, or implement scaling logic to preserve the painted area proportionally within the new dimensions.

🤖 Prompt for AI Agents
In `@src/composables/painter/usePainter.ts` around lines 403 - 421, The
resizeCanvas function currently captures prevData and restores it with
getCtx()?.putImageData, which silently clips content when canvasWidth or
canvasHeight shrink; update resizeCanvas to either (A) add a clear inline
comment above the prevData/putImageData block explaining that silent clipping on
shrink is intentional and acceptable for this app (mention canvasWidth,
canvasHeight, prevData, putImageData, getCtx, hasBaseSnapshot), or (B) implement
proportional scaling: create an offscreen/temp canvas, draw the prevData into
it, then use drawImage to scale the temp canvas into the new el.width/el.height
before replacing the main canvas (use getCtx/getCtx of temp, drawImage instead
of putImageData, and preserve strokeCanvas/baseCanvas state), ensuring
hasBaseSnapshot, strokeCtx and baseCtx handling remains consistent; choose A for
minimal change or B if you need to preserve painted content on resize.

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

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants