Skip to content

feat: add WaveAudioPlayer with waveform visualization and authenticated audio fetch#10158

Open
viva-jinyi wants to merge 8 commits intomainfrom
feature/new-wave-audio
Open

feat: add WaveAudioPlayer with waveform visualization and authenticated audio fetch#10158
viva-jinyi wants to merge 8 commits intomainfrom
feature/new-wave-audio

Conversation

@viva-jinyi
Copy link
Member

@viva-jinyi viva-jinyi commented Mar 17, 2026

Summary

Add a waveform-based audio player component (WaveAudioPlayer) replacing the native <audio> element, with authenticated API fetch for cloud audio playback.

Changes

  • What:
    • Add useWaveAudioPlayer composable with waveform visualization from audio data (Web Audio API decodeAudioData), playback controls, and seek support
    • Add WaveAudioPlayer.vue component with compact (inline waveform + time) and expanded (full transport controls) variants
    • Replace native <audio> in MediaAudioTop.vue and ResultAudio.vue with WaveAudioPlayer
    • Use api.fetchApi() instead of bare fetch() to include Firebase JWT auth headers, fixing 401 errors in cloud environments
    • Add Storybook stories and unit tests

Review Focus

  • The audio URL is fetched via api.fetchApi() with auth headers, converted to a Blob URL, then passed to the native <audio> element. This avoids 401 Unauthorized in cloud environments where /api/view requires authentication.
  • URL-to-route extraction logic (url.includes(apiBase)) handles both full API URLs and relative paths.
screen-capture.webm

┆Issue is synchronized with this Notion page by Unito

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Mar 17, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: faa7940f-bd05-4bd3-bd87-facd227e476f

📥 Commits

Reviewing files that changed from the base of the PR and between da3abe9 and b6568a6.

📒 Files selected for processing (2)
  • src/composables/useWaveAudioPlayer.test.ts
  • src/composables/useWaveAudioPlayer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/composables/useWaveAudioPlayer.test.ts

📝 Walkthrough

Walkthrough

Adds a WaveAudioPlayer Vue component with compact/expanded views, a composable useWaveAudioPlayer (plus formatTime), Storybook stories, unit tests, replaces native audio elements in two components with the new player, centralizes time formatting, and adds four English i18n keys.

Changes

Cohort / File(s) Summary
Component
src/components/common/WaveAudioPlayer.vue
New Vue component providing compact and expanded waveform UI, play/seek/volume controls, and a hidden audio element bound to the composable.
Composable
src/composables/useWaveAudioPlayer.ts
New composable handling fetch/decode of audio, generating waveform bars, playback controls (play/pause/seek/volume), time/progress refs, and cleanup. Exports useWaveAudioPlayer and formatTime.
Stories
src/components/common/WaveAudioPlayer.stories.ts
New Storybook file with Default, BottomAligned, Expanded stories and decorators demonstrating variants and layout wrappers.
Integrations
src/components/sidebar/tabs/queue/ResultAudio.vue, src/platform/assets/components/MediaAudioTop.vue
Replaced native <audio> usage with WaveAudioPlayer (props: src, bar-count, height, align); removed previous computed/html-type logic.
Tests
src/composables/useWaveAudioPlayer.test.ts
New unit tests mocking fetch/AudioContext and asserting bar generation, initial states, decode flow, and src-change behavior.
Utilities
packages/shared-frontend-utils/src/formatUtil.ts
Added exported formatTime(seconds: number): string helper (centralized time formatting).
Re-exports
src/renderer/extensions/vueNodes/widgets/utils/audioUtils.ts
Removed local formatTime implementation and re-exported formatTime from the centralized util.
Localization
src/locales/en/main.json
Added i18n keys: g.play, g.pause, g.skipToStart, g.skipToEnd.

Sequence Diagram

sequenceDiagram
    participant User
    participant WaveAudioPlayer
    participant useWaveAudioPlayer
    participant FetchAPI as Fetch API
    participant AudioContext
    participant HTMLAudio as HTMLAudioElement

    User->>WaveAudioPlayer: mount with `src` prop
    WaveAudioPlayer->>useWaveAudioPlayer: init(src, barCount)
    useWaveAudioPlayer->>FetchAPI: fetch(src)
    FetchAPI-->>useWaveAudioPlayer: audio blob
    useWaveAudioPlayer->>useWaveAudioPlayer: create blob URL
    useWaveAudioPlayer->>HTMLAudio: set src (blob URL)
    useWaveAudioPlayer->>AudioContext: decode audio buffer
    AudioContext-->>useWaveAudioPlayer: decoded buffer
    useWaveAudioPlayer->>useWaveAudioPlayer: generate waveform bars
    useWaveAudioPlayer-->>WaveAudioPlayer: update bars & state
    User->>WaveAudioPlayer: click play/pause or waveform
    WaveAudioPlayer->>useWaveAudioPlayer: togglePlayPause / handleWaveformClick
    useWaveAudioPlayer->>HTMLAudio: play/pause or set currentTime
    HTMLAudio-->>useWaveAudioPlayer: playback updates
    useWaveAudioPlayer-->>WaveAudioPlayer: update playedBarIndex & progress
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I twitch my whiskers, bars arise,
A waveform hop beneath bright skies,
Click to play — the meadow sings,
Tiny beats like carrot rings,
I bound — the audio takes flight!


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore (reviewers only)

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❌ Error PR contains a bug-fix commit (fix: add race condition guard...) but lacks end-to-end regression tests under browser_tests/ and provides no concrete explanation in the PR description for why such tests are unnecessary. Add a Playwright regression test under browser_tests/ for the race condition fix, or provide a concrete explanation in the PR description for why end-to-end testing is impractical.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: introducing WaveAudioPlayer component with waveform visualization and authenticated audio fetch capability.
Description check ✅ Passed The description follows the template structure with Summary, Changes (What, Breaking if applicable), and Review Focus sections; all critical information is provided.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/new-wave-audio
📝 Coding Plan
  • Generate coding plan for human review comments

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 Mar 17, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/18/2026, 04:12:23 AM UTC

Links

@github-actions
Copy link

github-actions bot commented Mar 17, 2026

🎭 Playwright: ✅ 632 passed, 0 failed · 5 flaky

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

@viva-jinyi viva-jinyi changed the title fix: use authenticated API fetch for audio playback in cloud environment feat: add WaveAudioPlayer with waveform visualization and authenticated audio fetch Mar 17, 2026
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

🧹 Nitpick comments (1)
src/composables/useWaveAudioPlayer.test.ts (1)

91-102: Restore globalThis.AudioContext after the test.

Line 98 permanently overrides a global. This can create cross-test coupling/flakiness.

💡 Proposed fix
-import { describe, expect, it, vi } from 'vitest'
+import { afterEach, describe, expect, it, vi } from 'vitest'
@@
 const mockFetchApi = vi.fn()
+const originalAudioContext = globalThis.AudioContext
+
+afterEach(() => {
+  globalThis.AudioContext = originalAudioContext
+  mockFetchApi.mockReset()
+})
As per coding guidelines "For mocking in Vitest, leverage Vitest's utilities where possible; keep module mocks contained without global mutable state".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/composables/useWaveAudioPlayer.test.ts` around lines 91 - 102, The test
overrides the globalThis.AudioContext (in the "fetches and decodes audio when
src changes" test) which can leak into other tests; save the original
AudioContext before mocking (e.g., const originalAudioContext =
globalThis.AudioContext) and restore it after the test using a finally block or
an afterEach hook (set globalThis.AudioContext = originalAudioContext), ensuring
any mockClose or decodeAudioData mocks are cleaned up (or use
vi.restoreAllMocks()) so globals are returned to their prior state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/common/WaveAudioPlayer.vue`:
- Around line 3-9: The container div that currently uses `@pointerdown.stop` (the
compact variant div with :class="cn('flex w-full gap-2', align === 'center' ?
'items-center' : 'items-end')") still allows click events to bubble up; update
that element to also stop click propagation (add `@click.stop`) and apply the same
change to the other occurrence near the waveform/progress (the element using
`@pointerdown.stop` around the progress/waveform controls) so clicks on the player
do not trigger parent clickable card actions.

In `@src/composables/useWaveAudioPlayer.ts`:
- Around line 43-60: The generateBarsFromBuffer function can compute
samplesPerBar = 0 for very short or empty AudioBuffers causing NaN heights;
guard against that by checking channelData.length and samplesPerBar before the
inner loop and early-returning or filling bars.value with a safe default (e.g.,
barCount entries with height 8) when samplesPerBar <= 0 or channelData.length
=== 0; otherwise clamp index access (i * samplesPerBar + j) to be inside
channelData.length and compute averages as currently done, then proceed to
compute peak and set bars.value as before. Ensure you reference
generateBarsFromBuffer, samplesPerBar, channelData, barCount, and bars.value
when making the change.
- Around line 62-87: In decodeAudioSource, validate the fetch response and
ensure AudioContext and blob URLs are cleaned up: check response.ok and that
response.headers.get('content-type') exists (or matches audio/*) before creating
the Blob and setting blobUrl.value; move new AudioContext() creation to a scope
so it exists before the try and always call ctx.close() in a finally block to
avoid leaking the AudioContext; when creating a new blobUrl revoke any previous
blobUrl.value first and if decoding fails revoke the newly created blobUrl.value
in the catch before setting bars.value = generatePlaceholderBars(); keep
generateBarsFromBuffer and generatePlaceholderBars usage unchanged but only call
decodeAudioData when response validation passes.

---

Nitpick comments:
In `@src/composables/useWaveAudioPlayer.test.ts`:
- Around line 91-102: The test overrides the globalThis.AudioContext (in the
"fetches and decodes audio when src changes" test) which can leak into other
tests; save the original AudioContext before mocking (e.g., const
originalAudioContext = globalThis.AudioContext) and restore it after the test
using a finally block or an afterEach hook (set globalThis.AudioContext =
originalAudioContext), ensuring any mockClose or decodeAudioData mocks are
cleaned up (or use vi.restoreAllMocks()) so globals are returned to their prior
state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 277a5dd3-48ce-466d-b99f-f8b1eb312512

📥 Commits

Reviewing files that changed from the base of the PR and between d6c1dd2 and 834e24a.

📒 Files selected for processing (7)
  • src/components/common/WaveAudioPlayer.stories.ts
  • src/components/common/WaveAudioPlayer.vue
  • src/components/sidebar/tabs/queue/ResultAudio.vue
  • src/composables/useWaveAudioPlayer.test.ts
  • src/composables/useWaveAudioPlayer.ts
  • src/locales/en/main.json
  • src/platform/assets/components/MediaAudioTop.vue

@viva-jinyi viva-jinyi requested a review from a team March 18, 2026 03:37
@github-actions
Copy link

github-actions bot commented Mar 18, 2026

📦 Bundle: 5.01 MB gzip 🔴 +8.75 kB

Details

Summary

  • Raw size: 23.1 MB baseline 23.1 MB — 🔴 +27.5 kB
  • Gzip: 5.01 MB baseline 5 MB — 🔴 +8.75 kB
  • Brotli: 3.88 MB baseline 3.87 MB — 🔴 +7.14 kB
  • Bundles: 245 current • 244 baseline • 227 added / 226 removed

Category Glance
Other 🔴 +15 kB (8.25 MB) · Vendor & Third-Party 🔴 +10.8 kB (9.8 MB) · Utilities & Hooks 🔴 +830 B (322 kB) · Panels & Settings 🔴 +341 B (461 kB) · Views & Navigation 🔴 +240 B (76.1 kB) · Data & Services 🟢 -150 B (2.91 MB) · + 5 more

App Entry Points — 22.8 kB (baseline 22.7 kB) • 🔴 +75 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-CUBs3DTi.js (new) 22.8 kB 🔴 +22.8 kB 🔴 +8.07 kB 🔴 +6.95 kB
assets/index-Dlrv1i6y.js (removed) 22.7 kB 🟢 -22.7 kB 🟢 -8.03 kB 🟢 -6.89 kB

Status: 1 added / 1 removed

Graph Workspace — 1.1 MB (baseline 1.1 MB) • 🔴 +62 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-D8KODvmA.js (new) 1.1 MB 🔴 +1.1 MB 🔴 +234 kB 🔴 +177 kB
assets/GraphView-DyiKz5FQ.js (removed) 1.1 MB 🟢 -1.1 MB 🟢 -234 kB 🟢 -177 kB

Status: 1 added / 1 removed

Views & Navigation — 76.1 kB (baseline 75.9 kB) • 🔴 +240 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-BUQJKF73.js (new) 15.6 kB 🔴 +15.6 kB 🔴 +3.39 kB 🔴 +2.89 kB
assets/CloudSurveyView-DihXY67h.js (removed) 15.6 kB 🟢 -15.6 kB 🟢 -3.38 kB 🟢 -2.88 kB
assets/CloudLoginView-Cor3TRZW.js (new) 11.9 kB 🔴 +11.9 kB 🔴 +3.34 kB 🔴 +2.95 kB
assets/CloudLoginView-CDnLzCvo.js (removed) 11.9 kB 🟢 -11.9 kB 🟢 -3.31 kB 🟢 -2.92 kB
assets/CloudSignupView-8QJ336tl.js (new) 9.68 kB 🔴 +9.68 kB 🔴 +2.83 kB 🔴 +2.48 kB
assets/CloudSignupView-BX6Wp6sE.js (removed) 9.64 kB 🟢 -9.64 kB 🟢 -2.8 kB 🟢 -2.44 kB
assets/UserCheckView-CJI2x8cK.js (removed) 9.01 kB 🟢 -9.01 kB 🟢 -2.31 kB 🟢 -2 kB
assets/UserCheckView-cYxr_5A7.js (new) 9.01 kB 🔴 +9.01 kB 🔴 +2.32 kB 🔴 +2.02 kB
assets/CloudLayoutView-CGKYY9-0.js (new) 7.46 kB 🔴 +7.46 kB 🔴 +2.33 kB 🔴 +2.04 kB
assets/CloudLayoutView-DjDLbQvy.js (removed) 7.42 kB 🟢 -7.42 kB 🟢 -2.3 kB 🟢 -2.01 kB
assets/CloudForgotPasswordView-BNmgrDz1.js (new) 5.89 kB 🔴 +5.89 kB 🔴 +2.07 kB 🔴 +1.82 kB
assets/CloudForgotPasswordView-Bn7J4qa8.js (removed) 5.85 kB 🟢 -5.85 kB 🟢 -2.04 kB 🟢 -1.79 kB
assets/CloudAuthTimeoutView-Uwwb5nZ5.js (new) 5.25 kB 🔴 +5.25 kB 🔴 +1.91 kB 🔴 +1.68 kB
assets/CloudAuthTimeoutView-F0ceJ9eo.js (removed) 5.21 kB 🟢 -5.21 kB 🟢 -1.88 kB 🟢 -1.64 kB
assets/CloudSubscriptionRedirectView-BB_9kiLs.js (new) 5.02 kB 🔴 +5.02 kB 🔴 +1.88 kB 🔴 +1.66 kB
assets/CloudSubscriptionRedirectView-CVwabfyT.js (removed) 4.98 kB 🟢 -4.98 kB 🟢 -1.86 kB 🟢 -1.64 kB
assets/UserSelectView-ClGlH9L4.js (new) 4.67 kB 🔴 +4.67 kB 🔴 +1.73 kB 🔴 +1.53 kB
assets/UserSelectView-DBH3dNP5.js (removed) 4.67 kB 🟢 -4.67 kB 🟢 -1.72 kB 🟢 -1.53 kB
assets/CloudSorryContactSupportView-CvHMqxDy.js (new) 1.21 kB 🔴 +1.21 kB 🔴 +607 B 🔴 +529 B
assets/CloudSorryContactSupportView-D39Tgqec.js (removed) 1.21 kB 🟢 -1.21 kB 🟢 -606 B 🟢 -529 B
assets/layout-BHDgL9g2.js (new) 385 B 🔴 +385 B 🔴 +269 B 🔴 +222 B
assets/layout-BIsc3PeX.js (removed) 385 B 🟢 -385 B 🟢 -267 B 🟢 -218 B

Status: 11 added / 11 removed

Panels & Settings — 461 kB (baseline 461 kB) • 🔴 +341 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settings-D3I2ADsr.js (new) 38.8 kB 🔴 +38.8 kB 🔴 +9.45 kB 🔴 +7.78 kB
assets/settings-DV7Oma6k.js (removed) 38.8 kB 🟢 -38.8 kB 🟢 -9.45 kB 🟢 -7.77 kB
assets/settings-DW074sak.js (new) 34.4 kB 🔴 +34.4 kB 🔴 +8.43 kB 🔴 +7.1 kB
assets/settings-DWve2Khy.js (removed) 34.4 kB 🟢 -34.4 kB 🟢 -8.43 kB 🟢 -7.1 kB
assets/settings-CnaANeGF.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -8.24 kB 🟢 -6.72 kB
assets/settings-yjwQD_7o.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +8.24 kB 🔴 +6.73 kB
assets/settings-DOj524JM.js (new) 30.7 kB 🔴 +30.7 kB 🔴 +8.55 kB 🔴 +7.16 kB
assets/settings-tPYveYQf.js (removed) 30.7 kB 🟢 -30.7 kB 🟢 -8.55 kB 🟢 -7.16 kB
assets/settings-BWS_NBz5.js (removed) 30.1 kB 🟢 -30.1 kB 🟢 -8.19 kB 🟢 -7.17 kB
assets/settings-DBjnzWpq.js (new) 30.1 kB 🔴 +30.1 kB 🔴 +8.19 kB 🔴 +7.17 kB
assets/KeybindingPanel-CHPhzDQg.js (new) 29 kB 🔴 +29 kB 🔴 +6.22 kB 🔴 +5.52 kB
assets/KeybindingPanel-zUA-40wN.js (removed) 28.9 kB 🟢 -28.9 kB 🟢 -6.19 kB 🟢 -5.49 kB
assets/settings-DyYQyOee.js (removed) 28.9 kB 🟢 -28.9 kB 🟢 -7.88 kB 🟢 -6.74 kB
assets/settings-DzuR7fTy.js (new) 28.9 kB 🔴 +28.9 kB 🔴 +7.88 kB 🔴 +6.71 kB
assets/settings-BKWCl63J.js (removed) 28.9 kB 🟢 -28.9 kB 🟢 -8.1 kB 🟢 -7.08 kB
assets/settings-CfT7pOxT.js (new) 28.9 kB 🔴 +28.9 kB 🔴 +8.1 kB 🔴 +7.08 kB
assets/settings-BIGUxb3F.js (removed) 28 kB 🟢 -28 kB 🟢 -7.8 kB 🟢 -6.77 kB
assets/settings-rWycUhC1.js (new) 28 kB 🔴 +28 kB 🔴 +7.8 kB 🔴 +6.77 kB
assets/settings-Ci4TA0QT.js (removed) 27.9 kB 🟢 -27.9 kB 🟢 -8.23 kB 🟢 -6.85 kB
assets/settings-D-iiI6b8.js (new) 27.9 kB 🔴 +27.9 kB 🔴 +8.23 kB 🔴 +6.86 kB
assets/settings-B4tFWxBO.js (new) 24.6 kB 🔴 +24.6 kB 🔴 +7.99 kB 🔴 +6.44 kB
assets/settings-XAoGbibE.js (removed) 24.6 kB 🟢 -24.6 kB 🟢 -8 kB 🟢 -6.45 kB
assets/settings-BAN7nkAf.js (removed) 24 kB 🟢 -24 kB 🟢 -7.76 kB 🟢 -6.05 kB
assets/settings-CI5QXY0m.js (new) 24 kB 🔴 +24 kB 🔴 +7.77 kB 🔴 +6.05 kB
assets/SecretsPanel-Df1NlAvi.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.42 kB 🔴 +4.77 kB
assets/SecretsPanel-DRAsbsxN.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.41 kB 🟢 -4.75 kB
assets/LegacyCreditsPanel-D5QiA2bx.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.74 kB 🔴 +5.06 kB
assets/LegacyCreditsPanel-C0PRUy1z.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.71 kB 🟢 -5.03 kB
assets/SubscriptionPanel-BP1EFLZX.js (new) 19.4 kB 🔴 +19.4 kB 🔴 +4.95 kB 🔴 +4.34 kB
assets/SubscriptionPanel-BffEqxgt.js (removed) 19.3 kB 🟢 -19.3 kB 🟢 -4.89 kB 🟢 -4.3 kB
assets/AboutPanel-CXEs554F.js (removed) 12 kB 🟢 -12 kB 🟢 -3.31 kB 🟢 -2.97 kB
assets/AboutPanel-DYRJrF7g.js (new) 12 kB 🔴 +12 kB 🔴 +3.32 kB 🔴 +2.97 kB
assets/ExtensionPanel-Cpju7_RX.js (new) 9.7 kB 🔴 +9.7 kB 🔴 +2.8 kB 🔴 +2.47 kB
assets/ExtensionPanel-D4u_i4mL.js (removed) 9.66 kB 🟢 -9.66 kB 🟢 -2.76 kB 🟢 -2.44 kB
assets/ServerConfigPanel-CFZ6AEDe.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +2.26 kB 🔴 +2.01 kB
assets/ServerConfigPanel-CEMLsR4F.js (removed) 6.74 kB 🟢 -6.74 kB 🟢 -2.23 kB 🟢 -2.04 kB
assets/UserPanel-BfM4q-Rq.js (new) 6.48 kB 🔴 +6.48 kB 🔴 +2.12 kB 🔴 +1.87 kB
assets/UserPanel-Dza4sQHu.js (removed) 6.44 kB 🟢 -6.44 kB 🟢 -2.1 kB 🟢 -1.83 kB
assets/config-CGUaDOR_.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -865 B 🟢 -713 B
assets/config-Dm-Sai3b.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +864 B 🔴 +683 B
assets/cloudRemoteConfig-GP-wTVLB.js (new) 1.77 kB 🔴 +1.77 kB 🔴 +877 B 🔴 +760 B
assets/cloudRemoteConfig-BlLc15wb.js (removed) 1.74 kB 🟢 -1.74 kB 🟢 -850 B 🟢 -740 B
assets/refreshRemoteConfig-D1Xp_e2V.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -647 B 🟢 -554 B
assets/refreshRemoteConfig-D8ZbK9dm.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +650 B 🔴 +552 B

Status: 22 added / 22 removed

User & Accounts — 17 kB (baseline 16.9 kB) • 🔴 +81 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/PasswordFields-CFdyppYX.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.42 kB 🔴 +1.25 kB
assets/PasswordFields-DNnYzMSv.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.42 kB 🟢 -1.26 kB
assets/auth-ClrC5oNQ.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.26 kB 🟢 -1.07 kB
assets/auth-DlOPQ53f.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/SignUpForm-ByHTFqCj.js (new) 3.18 kB 🔴 +3.18 kB 🔴 +1.3 kB 🔴 +1.16 kB
assets/SignUpForm-kReYsg8j.js (removed) 3.18 kB 🟢 -3.18 kB 🟢 -1.29 kB 🟢 -1.15 kB
assets/UpdatePasswordContent-k_Bm1Pup.js (new) 2.6 kB 🔴 +2.6 kB 🔴 +1.17 kB 🔴 +1.03 kB
assets/UpdatePasswordContent-Hm5sAykx.js (removed) 2.56 kB 🟢 -2.56 kB 🟢 -1.14 kB 🟢 -1.01 kB
assets/WorkspaceProfilePic-BOeNWN4H.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +861 B 🔴 +786 B
assets/WorkspaceProfilePic-BqC5mARc.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -860 B 🟢 -780 B
assets/firebaseAuthStore-CC1eT6iY.js (new) 947 B 🔴 +947 B 🔴 +458 B 🔴 +402 B
assets/firebaseAuthStore-C-I-HWtj.js (removed) 907 B 🟢 -907 B 🟢 -435 B 🟢 -385 B
assets/auth-Buz7GrRk.js (removed) 313 B 🟢 -313 B 🟢 -196 B 🟢 -183 B
assets/auth-D4yQ7UAO.js (new) 313 B 🔴 +313 B 🔴 +201 B 🔴 +175 B

Status: 7 added / 7 removed

Editors & Dialogs — 82.1 kB (baseline 82 kB) • 🔴 +80 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useShareDialog-5DJRtmtB.js (new) 81.2 kB 🔴 +81.2 kB 🔴 +17 kB 🔴 +14.5 kB
assets/useShareDialog-gSzXjwsO.js (removed) 81.2 kB 🟢 -81.2 kB 🟢 -16.9 kB 🟢 -14.5 kB
assets/useSubscriptionDialog-Da1Y-DGT.js (new) 895 B 🔴 +895 B 🔴 +449 B 🔴 +384 B
assets/useSubscriptionDialog-Dju8SSRu.js (removed) 855 B 🟢 -855 B 🟢 -425 B 🟢 -368 B

Status: 2 added / 2 removed

UI Components — 59.5 kB (baseline 59.4 kB) • 🔴 +120 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BOnokyON.js (new) 14.3 kB 🔴 +14.3 kB 🔴 +4.01 kB 🔴 +3.58 kB
assets/ComfyQueueButton-wLL5AP1V.js (removed) 14.3 kB 🟢 -14.3 kB 🟢 -4 kB 🟢 -3.58 kB
assets/useTerminalTabs-itP6FMZN.js (new) 10.6 kB 🔴 +10.6 kB 🔴 +3.58 kB 🔴 +3.13 kB
assets/useTerminalTabs-2aBYpErN.js (removed) 10.6 kB 🟢 -10.6 kB 🟢 -3.55 kB 🟢 -3.11 kB
assets/TopbarBadge-CF48hXFc.js (new) 7.52 kB 🔴 +7.52 kB 🔴 +1.85 kB 🔴 +1.62 kB
assets/TopbarBadge-DsvBeuYg.js (removed) 7.52 kB 🟢 -7.52 kB 🟢 -1.85 kB 🟢 -1.62 kB
assets/ScrubableNumberInput-CR36GIvQ.js (new) 6.27 kB 🔴 +6.27 kB 🔴 +2.13 kB 🔴 +1.89 kB
assets/ScrubableNumberInput-DCgMmTmd.js (removed) 6.27 kB 🟢 -6.27 kB 🟢 -2.13 kB 🟢 -1.89 kB
assets/toggle-group-BOQC4eRv.js (new) 4.03 kB 🔴 +4.03 kB 🔴 +1.42 kB 🔴 +1.25 kB
assets/toggle-group-D8Aj2fgN.js (removed) 4.03 kB 🟢 -4.03 kB 🟢 -1.42 kB 🟢 -1.25 kB
assets/FormSearchInput-DzIiJgiC.js (new) 3.94 kB 🔴 +3.94 kB 🔴 +1.64 kB 🔴 +1.43 kB
assets/FormSearchInput-SzYwVz2X.js (removed) 3.94 kB 🟢 -3.94 kB 🟢 -1.64 kB 🟢 -1.43 kB
assets/Button-BUAzEQH2.js (new) 3.44 kB 🔴 +3.44 kB 🔴 +1.35 kB 🔴 +1.19 kB
assets/Button-Bz6Bnept.js (removed) 3.44 kB 🟢 -3.44 kB 🟢 -1.34 kB 🟢 -1.18 kB
assets/SubscribeButton-B1sLQ8iH.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +914 B
assets/SubscribeButton-BxY5F9bs.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -913 B
assets/WidgetButton-DSXMJ7Tj.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +952 B 🔴 +863 B
assets/WidgetButton-DvOLQdOL.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -949 B 🟢 -858 B
assets/cloudFeedbackTopbarButton-Bnir82L-.js (new) 1.59 kB 🔴 +1.59 kB 🔴 +815 B 🔴 +734 B
assets/cloudFeedbackTopbarButton-oLB8bHgk.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -791 B 🟢 -703 B
assets/UserAvatar-BEhBHQwT.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -650 B 🟢 -558 B
assets/UserAvatar-D1T4j9sh.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +651 B 🔴 +558 B
assets/CloudBadge-Bj9LLRnS.js (removed) 1.17 kB 🟢 -1.17 kB 🟢 -592 B 🟢 -522 B
assets/CloudBadge-D8dUvVup.js (new) 1.17 kB 🔴 +1.17 kB 🔴 +593 B 🔴 +523 B
assets/ComfyQueueButton-DQsl4Xqa.js (new) 952 B 🔴 +952 B 🔴 +461 B 🔴 +409 B
assets/ComfyQueueButton-BULmM6Wt.js (removed) 912 B 🟢 -912 B 🟢 -439 B 🟢 -389 B

Status: 13 added / 13 removed

Data & Services — 2.91 MB (baseline 2.91 MB) • 🟢 -150 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-avHYLLzp.js (new) 1.91 MB 🔴 +1.91 MB 🔴 +439 kB 🔴 +333 kB
assets/dialogService-DXJKFi0J.js (removed) 1.91 MB 🟢 -1.91 MB 🟢 -439 kB 🟢 -333 kB
assets/api-D_-w8rBH.js (new) 864 kB 🔴 +864 kB 🔴 +206 kB 🔴 +163 kB
assets/api-Cnv1pcmI.js (removed) 864 kB 🟢 -864 kB 🟢 -206 kB 🟢 -163 kB
assets/load3dService-BwZCYC_i.js (new) 92.4 kB 🔴 +92.4 kB 🔴 +19.7 kB 🔴 +16.9 kB
assets/load3dService-Cfb_fiiw.js (removed) 92.3 kB 🟢 -92.3 kB 🟢 -19.6 kB 🟢 -16.9 kB
assets/workflowShareService-CzU5MGBG.js (removed) 14.1 kB 🟢 -14.1 kB 🟢 -4.32 kB 🟢 -3.8 kB
assets/workflowShareService-D2kH75Of.js (new) 14.1 kB 🔴 +14.1 kB 🔴 +4.32 kB 🔴 +3.8 kB
assets/releaseStore-7ytEkWW1.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.27 kB 🔴 +2 kB
assets/releaseStore-Dy5zNAvY.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.27 kB 🟢 -1.99 kB
assets/keybindingService-Bk3KeCZr.js (removed) 7.03 kB 🟢 -7.03 kB 🟢 -1.75 kB 🟢 -1.5 kB
assets/keybindingService-Bw2-Bxrd.js (new) 7.03 kB 🔴 +7.03 kB 🔴 +1.75 kB 🔴 +1.5 kB
assets/systemStatsStore-Bx_WbbCw.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.67 kB 🟢 -1.44 kB
assets/systemStatsStore-DTTQSIVb.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.67 kB 🔴 +1.45 kB
assets/dialogStore-B_fgsde8.js (new) 4.83 kB 🔴 +4.83 kB 🔴 +1.59 kB 🔴 +1.36 kB
assets/dialogStore-Dl8v4tkS.js (removed) 4.83 kB 🟢 -4.83 kB 🟢 -1.59 kB 🟢 -1.36 kB
assets/serverConfigStore-BLyAz-AI.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -809 B 🟢 -707 B
assets/serverConfigStore-fPFvFY_w.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +810 B 🔴 +707 B
assets/userStore-DbJR_wO5.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -869 B 🟢 -761 B
assets/userStore-oHXagxgp.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +868 B 🔴 +761 B
assets/electronDownloadStore-CvjYGarU.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +734 B 🔴 +655 B
assets/electronDownloadStore-DaA8BzaM.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -734 B 🟢 -711 B
assets/audioService-C55ilBf1.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +866 B 🔴 +746 B
assets/audioService-Ci9yTdGO.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -864 B 🟢 -745 B
assets/releaseStore-DbEYfVae.js (new) 919 B 🔴 +919 B 🔴 +453 B 🔴 +395 B
assets/workflowDraftStore-EsDjqAeP.js (new) 895 B 🔴 +895 B 🔴 +449 B 🔴 +387 B
assets/dialogService-CW2k5Emr.js (new) 884 B 🔴 +884 B 🔴 +441 B 🔴 +383 B
assets/settingStore-D1O0pG1r.js (new) 882 B 🔴 +882 B 🔴 +444 B 🔴 +382 B
assets/assetsStore-D0rkynj-.js (new) 881 B 🔴 +881 B 🔴 +444 B 🔴 +383 B
assets/releaseStore--bfc2H5Y.js (removed) 879 B 🟢 -879 B 🟢 -430 B 🟢 -370 B
assets/workflowDraftStore-DLiluusN.js (removed) 855 B 🟢 -855 B 🟢 -426 B 🟢 -372 B
assets/dialogService-CwBydaYS2.js (removed) 844 B 🟢 -844 B 🟢 -418 B 🟢 -365 B
assets/settingStore-BTEn6qdF.js (removed) 842 B 🟢 -842 B 🟢 -421 B 🟢 -365 B
assets/assetsStore-CHH583-q.js (removed) 841 B 🟢 -841 B 🟢 -421 B 🟢 -366 B
assets/useWorkspaceSwitch-2E6VApi-.js (removed) 747 B 🟢 -747 B 🟢 -386 B 🟢 -331 B

Status: 17 added / 18 removed

Utilities & Hooks — 322 kB (baseline 321 kB) • 🔴 +830 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-D7V6uPKa.js (removed) 231 kB 🟢 -231 kB 🟢 -51.2 kB 🟢 -41.7 kB
assets/useConflictDetection-Dk0bV-vd.js (new) 231 kB 🔴 +231 kB 🔴 +51.3 kB 🔴 +41.8 kB
assets/useLoad3dViewer-Dp50TDs9.js (removed) 18.6 kB 🟢 -18.6 kB 🟢 -4.42 kB 🟢 -3.88 kB
assets/useLoad3dViewer-TSPYDy7F.js (new) 18.6 kB 🔴 +18.6 kB 🔴 +4.43 kB 🔴 +3.89 kB
assets/formatUtil-DzGivJa_.js (new) 15.3 kB 🔴 +15.3 kB 🔴 +5.31 kB 🔴 +4.65 kB
assets/formatUtil-f5qiufgt.js (removed) 15.1 kB 🟢 -15.1 kB 🟢 -5.25 kB 🟢 -4.59 kB
assets/useLoad3d-C1_yAOra.js (new) 15 kB 🔴 +15 kB 🔴 +3.78 kB 🔴 +3.35 kB
assets/useLoad3d-DNt4v_IE.js (removed) 15 kB 🟢 -15 kB 🟢 -3.78 kB 🟢 -3.37 kB
assets/colorUtil-BipJb-N5.js (removed) 8.89 kB 🟢 -8.89 kB 🟢 -2.64 kB 🟢 -2.33 kB
assets/colorUtil-DMqtjvUZ.js (new) 8.89 kB 🔴 +8.89 kB 🔴 +2.64 kB 🔴 +2.33 kB
assets/useFeatureFlags-CIFEXT2y.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.75 kB 🔴 +1.48 kB
assets/useFeatureFlags-DrslGP1G.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.75 kB 🟢 -1.48 kB
assets/useWorkspaceUI-CcafB9rk.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +980 B 🔴 +811 B
assets/useWorkspaceUI-gkDpesGk.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -980 B 🟢 -808 B
assets/useExternalLink-BZrVMlfF.js (new) 3.04 kB 🔴 +3.04 kB 🔴 +1.17 kB 🔴 +1.04 kB
assets/useExternalLink-CgRVt4RS.js (removed) 3.04 kB 🟢 -3.04 kB 🟢 -1.17 kB 🟢 -1.03 kB
assets/subscriptionCheckoutUtil-BasS10mG.js (new) 3.04 kB 🔴 +3.04 kB 🔴 +1.32 kB 🔴 +1.15 kB
assets/subscriptionCheckoutUtil-DwBlMMgP.js (removed) 3.04 kB 🟢 -3.04 kB 🟢 -1.31 kB 🟢 -1.15 kB
assets/assetPreviewUtil-CxhIAM5j.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +958 B 🔴 +833 B
assets/assetPreviewUtil-DJbNgLcn.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -958 B 🟢 -833 B
assets/useUpstreamValue-Cb6amBJ5.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -805 B 🟢 -721 B
assets/useUpstreamValue-Dqjl1KCp.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +806 B 🔴 +712 B
assets/markdownRendererUtil-B_09GTaM.js (removed) 1.59 kB 🟢 -1.59 kB 🟢 -830 B 🟢 -722 B
assets/markdownRendererUtil-BELnS8BY.js (new) 1.59 kB 🔴 +1.59 kB 🔴 +830 B 🔴 +723 B
assets/useErrorHandling-TOD06dSN.js (removed) 1.54 kB 🟢 -1.54 kB 🟢 -650 B 🟢 -553 B
assets/useErrorHandling-uXLZJQVk.js (new) 1.54 kB 🔴 +1.54 kB 🔴 +650 B 🔴 +551 B
assets/useLoad3d-C2ufGMek.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +510 B 🔴 +454 B
assets/useLoad3d-XYs9EbC_.js (removed) 1.02 kB 🟢 -1.02 kB 🟢 -487 B 🟢 -435 B
assets/useLoad3dViewer-DeCmoMTF.js (new) 997 B 🔴 +997 B 🔴 +477 B 🔴 +426 B
assets/audioUtils-BJejcyru.js (removed) 958 B 🟢 -958 B 🟢 -563 B 🟢 -465 B
assets/useLoad3dViewer-H3LjBmoI.js (removed) 957 B 🟢 -957 B 🟢 -453 B 🟢 -402 B
assets/useCurrentUser-CKJP-vde.js (new) 881 B 🔴 +881 B 🔴 +444 B 🔴 +382 B
assets/useCurrentUser-UUMikLzx.js (removed) 841 B 🟢 -841 B 🟢 -422 B 🟢 -365 B
assets/useWorkspaceSwitch-CV7KKReU.js (new) 747 B 🔴 +747 B 🔴 +382 B 🔴 +332 B
assets/audioUtils-CPv2EEqb.js (new) 723 B 🔴 +723 B 🔴 +454 B 🔴 +364 B
assets/envUtil-6bVzeCCY.js (removed) 489 B 🟢 -489 B 🟢 -309 B 🟢 -244 B
assets/envUtil-B2IAFYnC.js (new) 489 B 🔴 +489 B 🔴 +311 B 🔴 +245 B
assets/SkeletonUtils-bHcGO-EQ.js (new) 133 B 🔴 +133 B 🔴 +114 B 🔴 +112 B
assets/SkeletonUtils-CfZ2EYHr.js (removed) 133 B 🟢 -133 B 🟢 -114 B 🟢 -106 B

Status: 20 added / 19 removed / 2 unchanged

Vendor & Third-Party — 9.8 MB (baseline 9.78 MB) • 🔴 +10.8 kB

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-three-BUCymQYQ.js (new) 1.83 MB 🔴 +1.83 MB 🔴 +394 kB 🔴 +287 kB
assets/vendor-three-Bx5-M0Cu.js (removed) 1.83 MB 🟢 -1.83 MB 🟢 -394 kB 🟢 -287 kB
assets/vendor-other-BkQWdXxb.js (new) 1.76 MB 🔴 +1.76 MB 🔴 +361 kB 🔴 +287 kB
assets/vendor-other-CYcyfS3G.js (removed) 1.76 MB 🟢 -1.76 MB 🟢 -361 kB 🟢 -287 kB
assets/vendor-primevue-CtiNg45q.js (removed) 1.75 MB 🟢 -1.75 MB 🟢 -315 kB 🟢 -191 kB
assets/vendor-primevue-CWE5QTEk.js (new) 1.75 MB 🔴 +1.75 MB 🔴 +315 kB 🔴 +191 kB
assets/vendor-chart-DbY9buOt.js (new) 411 kB 🔴 +411 kB 🔴 +99.9 kB 🔴 +82.8 kB
assets/vendor-chart-DPxJtbLv.js (removed) 411 kB 🟢 -411 kB 🟢 -99.9 kB 🟢 -82.9 kB
assets/vendor-xterm-p00yikmz.js (new) 374 kB 🔴 +374 kB 🔴 +75.6 kB 🔴 +61.1 kB
assets/vendor-xterm-VUry4wfH.js (removed) 374 kB 🟢 -374 kB 🟢 -75.6 kB 🟢 -61.1 kB
assets/vendor-vueuse-D8k5irwM.js (new) 147 kB 🔴 +147 kB 🔴 +36.8 kB 🔴 +31.5 kB
assets/vendor-vueuse-CvkGidGM.js (removed) 136 kB 🟢 -136 kB 🟢 -34.1 kB 🟢 -29.3 kB

Status: 6 added / 6 removed / 10 unchanged

Other — 8.25 MB (baseline 8.24 MB) • 🔴 +15 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/i18n-tLZJZ1Q7.js (new) 554 kB 🔴 +554 kB 🔴 +108 kB 🔴 +85 kB
assets/i18n-hi-0QyJU.js (removed) 553 kB 🟢 -553 kB 🟢 -108 kB 🟢 -85 kB
assets/nodeDefs-xAWAoDOM.js (new) 500 kB 🔴 +500 kB 🔴 +76.2 kB 🔴 +52.5 kB
assets/nodeDefs-xFXXWvtQ.js (removed) 500 kB 🟢 -500 kB 🟢 -76.2 kB 🟢 -52.5 kB
assets/nodeDefs-BvbhXr8n.js (new) 459 kB 🔴 +459 kB 🔴 +71.1 kB 🔴 +50.2 kB
assets/nodeDefs-BvPFTQbw.js (removed) 459 kB 🟢 -459 kB 🟢 -71.1 kB 🟢 -50.2 kB
assets/nodeDefs-CMgigGDq.js (removed) 458 kB 🟢 -458 kB 🟢 -68.8 kB 🟢 -48.4 kB
assets/nodeDefs-CN_ASPRv.js (new) 458 kB 🔴 +458 kB 🔴 +68.8 kB 🔴 +48.4 kB
assets/nodeDefs-B8bSPLVu.js (removed) 423 kB 🟢 -423 kB 🟢 -69.3 kB 🟢 -48.4 kB
assets/nodeDefs-CGu3rMUv.js (new) 423 kB 🔴 +423 kB 🔴 +69.3 kB 🔴 +48.4 kB
assets/nodeDefs-CiEsoOEe.js (removed) 411 kB 🟢 -411 kB 🟢 -67.7 kB 🟢 -48 kB
assets/nodeDefs-LOSek_u2.js (new) 411 kB 🔴 +411 kB 🔴 +67.7 kB 🔴 +47.9 kB
assets/nodeDefs-2J7WMjAQ.js (new) 407 kB 🔴 +407 kB 🔴 +66.3 kB 🔴 +48.5 kB
assets/nodeDefs-DLV_dpNY.js (removed) 407 kB 🟢 -407 kB 🟢 -66.3 kB 🟢 -48.5 kB
assets/nodeDefs-BjyZoomx.js (new) 406 kB 🔴 +406 kB 🔴 +67.7 kB 🔴 +49.1 kB
assets/nodeDefs-COxfTSLM.js (removed) 406 kB 🟢 -406 kB 🟢 -67.7 kB 🟢 -49.1 kB
assets/nodeDefs-C4HthWzE.js (removed) 403 kB 🟢 -403 kB 🟢 -64.8 kB 🟢 -47.3 kB
assets/nodeDefs-DbgqmE7a.js (new) 403 kB 🔴 +403 kB 🔴 +64.8 kB 🔴 +47.3 kB
assets/nodeDefs-CbftlIur.js (new) 398 kB 🔴 +398 kB 🔴 +63.8 kB 🔴 +46.7 kB
assets/nodeDefs-nUHNzy58.js (removed) 398 kB 🟢 -398 kB 🟢 -63.8 kB 🟢 -46.6 kB
assets/nodeDefs-C25At3xU.js (removed) 373 kB 🟢 -373 kB 🟢 -66.3 kB 🟢 -46.4 kB
assets/nodeDefs-CjS6C3Nu.js (new) 373 kB 🔴 +373 kB 🔴 +66.3 kB 🔴 +46.4 kB
assets/nodeDefs-B50iPTQ0.js (new) 369 kB 🔴 +369 kB 🔴 +65.4 kB 🔴 +45.3 kB
assets/nodeDefs-BEnxPjQL.js (removed) 369 kB 🟢 -369 kB 🟢 -65.4 kB 🟢 -45.3 kB
assets/main-COiOt8ZE.js (new) 230 kB 🔴 +230 kB 🔴 +59.3 kB 🔴 +46.8 kB
assets/main-N-yssEEP.js (removed) 230 kB 🟢 -230 kB 🟢 -59.3 kB 🟢 -46.8 kB
assets/main-B3PYmqDx.js (new) 206 kB 🔴 +206 kB 🔴 +53.6 kB 🔴 +43.3 kB
assets/main-Cg268kJ1.js (removed) 206 kB 🟢 -206 kB 🟢 -53.6 kB 🟢 -43.2 kB
assets/main-Bv2ScD_D.js (new) 197 kB 🔴 +197 kB 🔴 +53.4 kB 🔴 +42.6 kB
assets/main-DNPLYwoa.js (removed) 197 kB 🟢 -197 kB 🟢 -53.4 kB 🟢 -42.6 kB
assets/main-gUw44kUq.js (removed) 188 kB 🟢 -188 kB 🟢 -53 kB 🟢 -42.3 kB
assets/main-PhIuayEn.js (new) 188 kB 🔴 +188 kB 🔴 +53 kB 🔴 +42.2 kB
assets/main-Cccj6VV6.js (new) 172 kB 🔴 +172 kB 🔴 +51.6 kB 🔴 +43.2 kB
assets/main-CS3VoDuf.js (removed) 172 kB 🟢 -172 kB 🟢 -51.5 kB 🟢 -43.2 kB
assets/main-CUpVE_k8.js (new) 169 kB 🔴 +169 kB 🔴 +50.9 kB 🔴 +41.1 kB
assets/main-m1zakQq2.js (removed) 169 kB 🟢 -169 kB 🟢 -50.9 kB 🟢 -41.1 kB
assets/main-BFlVJ_wN.js (removed) 166 kB 🟢 -166 kB 🟢 -50.4 kB 🟢 -41.9 kB
assets/main-BvWqNJyl.js (new) 166 kB 🔴 +166 kB 🔴 +50.4 kB 🔴 +41.9 kB
assets/main-BtHDQw4D.js (removed) 164 kB 🟢 -164 kB 🟢 -50.7 kB 🟢 -42.6 kB
assets/main-BvW1lEhD.js (new) 164 kB 🔴 +164 kB 🔴 +50.7 kB 🔴 +42.5 kB
assets/main-BItu4fVV.js (new) 163 kB 🔴 +163 kB 🔴 +49.9 kB 🔴 +42 kB
assets/main-lETVFVpd.js (removed) 163 kB 🟢 -163 kB 🟢 -49.9 kB 🟢 -42 kB
assets/main-B-IzDJ6B.js (removed) 145 kB 🟢 -145 kB 🟢 -49.7 kB 🟢 -39.8 kB
assets/main-DCwVfYnr.js (new) 145 kB 🔴 +145 kB 🔴 +49.7 kB 🔴 +39.8 kB
assets/main-DbeGrqNi.js (removed) 144 kB 🟢 -144 kB 🟢 -49.6 kB 🟢 -39.5 kB
assets/main-uXjtxSld.js (new) 144 kB 🔴 +144 kB 🔴 +49.6 kB 🔴 +39.5 kB
assets/core-CYafS_Cl.js (new) 76.3 kB 🔴 +76.3 kB 🔴 +19.7 kB 🔴 +16.8 kB
assets/core-DdmwJMgx.js (removed) 76.2 kB 🟢 -76.2 kB 🟢 -19.7 kB 🟢 -16.8 kB
assets/groupNode-9XkUMNa3.js (removed) 73.9 kB 🟢 -73.9 kB 🟢 -18.5 kB 🟢 -16.3 kB
assets/groupNode-B9x5ybUr.js (new) 73.9 kB 🔴 +73.9 kB 🔴 +18.5 kB 🔴 +16.3 kB
assets/WidgetSelect-BXpwgGRu.js (new) 63.3 kB 🔴 +63.3 kB 🔴 +13.8 kB 🔴 +11.9 kB
assets/WidgetSelect-BAGK9U_d.js (removed) 63.3 kB 🟢 -63.3 kB 🟢 -13.8 kB 🟢 -11.9 kB
assets/SubscriptionRequiredDialogContentWorkspace-GW93h7_Q.js (new) 47.2 kB 🔴 +47.2 kB 🔴 +8.83 kB 🔴 +7.62 kB
assets/SubscriptionRequiredDialogContentWorkspace-BRKkSjgu.js (removed) 47.2 kB 🟢 -47.2 kB 🟢 -8.8 kB 🟢 -7.63 kB
assets/WidgetPainter-CThELuMB.js (new) 33.2 kB 🔴 +33.2 kB 🔴 +8.09 kB 🔴 +7.17 kB
assets/WidgetPainter-BGnoOXmS.js (removed) 33.2 kB 🟢 -33.2 kB 🟢 -8.05 kB 🟢 -7.15 kB
assets/Load3DControls-C6waeA1h.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -5.47 kB 🟢 -4.75 kB
assets/Load3DControls-DNfrSTyc.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +5.47 kB 🔴 +4.75 kB
assets/WorkspacePanelContent-D2bdlkwX.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +6.3 kB 🔴 +5.54 kB
assets/WorkspacePanelContent-ChTmZ8Cb.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -6.27 kB 🟢 -5.51 kB
assets/SubscriptionRequiredDialogContent-CaWKBI1g.js (new) 26.3 kB 🔴 +26.3 kB 🔴 +6.7 kB 🔴 +5.93 kB
assets/SubscriptionRequiredDialogContent-ZiE73RED.js (removed) 26.2 kB 🟢 -26.2 kB 🟢 -6.68 kB 🟢 -5.9 kB
assets/Load3dViewerContent-BqDUZM8W.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -5.32 kB 🟢 -4.63 kB
assets/Load3dViewerContent-DuXk_hBp.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +5.33 kB 🔴 +4.65 kB
assets/WidgetImageCrop-Li9Hdlry.js (new) 23.2 kB 🔴 +23.2 kB 🔴 +5.8 kB 🔴 +5.1 kB
assets/WidgetImageCrop-Cw_DyTF7.js (removed) 23.2 kB 🟢 -23.2 kB 🟢 -5.77 kB 🟢 -5.08 kB
assets/SubscriptionPanelContentWorkspace-CnpG7-Aq.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.56 kB
assets/SubscriptionPanelContentWorkspace-D4-kDvTq.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.17 kB 🟢 -4.57 kB
assets/CurrentUserPopoverWorkspace-avlRXtS6.js (new) 21 kB 🔴 +21 kB 🔴 +5.07 kB 🔴 +4.53 kB
assets/CurrentUserPopoverWorkspace-Bl-ZOnIO.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.04 kB 🟢 -4.5 kB
assets/SignInContent-DgJdAeIS.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +5.24 kB 🔴 +4.55 kB
assets/SignInContent-eFCTbOuw.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -5.21 kB 🟢 -4.54 kB
assets/WidgetInputNumber-DD_Qksqg.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.84 kB 🟢 -4.3 kB
assets/WidgetInputNumber-DgLEqyv6.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.3 kB
assets/commands-CdUHA_QB.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.1 kB 🟢 -3.2 kB
assets/commands-CjLw9G0O.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.11 kB 🔴 +3.2 kB
assets/WidgetRecordAudio-CzOx6gdt.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +5.17 kB 🔴 +4.63 kB
assets/WidgetRecordAudio-COcM0rEu.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -5.15 kB 🟢 -4.61 kB
assets/commands-COeF-sIa.js (new) 17.8 kB 🔴 +17.8 kB 🔴 +3.78 kB 🔴 +2.93 kB
assets/commands-QyjAgSOE.js (removed) 17.8 kB 🟢 -17.8 kB 🟢 -3.78 kB 🟢 -2.93 kB
assets/commands-BeOklgQ5.js (new) 17.8 kB 🔴 +17.8 kB 🔴 +3.85 kB 🔴 +3.03 kB
assets/commands-BI-kTfmu.js (removed) 17.8 kB 🟢 -17.8 kB 🟢 -3.85 kB 🟢 -3.02 kB
assets/commands-CaWIjgGj.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +3.88 kB 🔴 +3.05 kB
assets/commands-DfsP7qL5.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -3.88 kB 🟢 -3.05 kB
assets/commands-_slQ_VBR.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +3.61 kB 🔴 +3 kB
assets/commands-C64uBcN5.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -3.62 kB 🟢 -3.02 kB
assets/Load3D-C-eUvxFp.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.11 kB 🔴 +3.58 kB
assets/Load3D-D_Sfxfhc.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.11 kB 🟢 -3.58 kB
assets/commands-B9Tk7h0X.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.61 kB 🔴 +2.97 kB
assets/commands-RWwMIt_u.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.6 kB 🟢 -2.96 kB
assets/commands-BDqhaVEH.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.5 kB 🟢 -2.86 kB
assets/commands-CUZ9Dvwd.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.5 kB 🔴 +2.87 kB
assets/commands-0Jqq-zHN.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.47 kB 🟢 -2.88 kB
assets/commands-eJxT0QLe.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.47 kB 🔴 +2.88 kB
assets/WidgetColorPicker-BbjH1qvT.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -3.99 kB 🟢 -3.55 kB
assets/WidgetColorPicker-DQp4AuWh.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +3.99 kB 🔴 +3.54 kB
assets/commands-DMCK5Ua0.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +3.74 kB 🔴 +2.92 kB
assets/commands-rUyDORRt.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -3.74 kB 🟢 -2.92 kB
assets/commands-BjpwZWNC.js (new) 15.4 kB 🔴 +15.4 kB 🔴 +3.67 kB 🔴 +2.76 kB
assets/commands-CA9PyC2Q.js (removed) 15.4 kB 🟢 -15.4 kB 🟢 -3.67 kB 🟢 -2.77 kB
assets/commands-BfDAp58b.js (new) 15.3 kB 🔴 +15.3 kB 🔴 +3.63 kB 🔴 +2.71 kB
assets/commands-PcYAqSyB.js (removed) 15.3 kB 🟢 -15.3 kB 🟢 -3.63 kB 🟢 -2.71 kB
assets/WidgetCurve-B_KQLWJF.js (new) 15.2 kB 🔴 +15.2 kB 🔴 +4.7 kB 🔴 +4.21 kB
assets/WidgetCurve-QKdrP7Sv.js (removed) 15.1 kB 🟢 -15.1 kB 🟢 -4.67 kB 🟢 -4.19 kB
assets/load3d-Dj1RwhWP.js (new) 15 kB 🔴 +15 kB 🔴 +4.3 kB 🔴 +3.71 kB
assets/load3d-DsdFawN3.js (removed) 14.9 kB 🟢 -14.9 kB 🟢 -4.27 kB 🟢 -3.69 kB
assets/WaveAudioPlayer-D6n6nrVJ.js (new) 13.2 kB 🔴 +13.2 kB 🔴 +3.64 kB 🔴 +3.2 kB
assets/AudioPreviewPlayer-5MANz_8z.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.37 kB 🔴 +3.03 kB
assets/AudioPreviewPlayer-BtT1mbxM.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.35 kB 🟢 -2.99 kB
assets/SelectValue-BKaJpsvf.js (removed) 9.8 kB 🟢 -9.8 kB 🟢 -2.45 kB 🟢 -2.16 kB
assets/SelectValue-DICNpN-K.js (new) 9.8 kB 🔴 +9.8 kB 🔴 +2.45 kB 🔴 +2.16 kB
assets/nodeTemplates-DfjCryJY.js (new) 9.49 kB 🔴 +9.49 kB 🔴 +3.36 kB 🔴 +2.95 kB
assets/nodeTemplates-DPm7dZKm.js (removed) 9.45 kB 🟢 -9.45 kB 🟢 -3.33 kB 🟢 -2.93 kB
assets/NightlySurveyController-Bv0Qpqnl.js (removed) 7.89 kB 🟢 -7.89 kB 🟢 -2.62 kB 🟢 -2.31 kB
assets/NightlySurveyController-pU1Gle8r.js (new) 7.89 kB 🔴 +7.89 kB 🔴 +2.62 kB 🔴 +2.3 kB
assets/WidgetImageCompare-Dd-JMO88.js (new) 7.78 kB 🔴 +7.78 kB 🔴 +2.27 kB 🔴 +1.98 kB
assets/WidgetImageCompare-E21YPdrV.js (removed) 7.78 kB 🟢 -7.78 kB 🟢 -2.27 kB 🟢 -1.98 kB
assets/InviteMemberDialogContent-DJSYSOzi.js (new) 7.7 kB 🔴 +7.7 kB 🔴 +2.43 kB 🔴 +2.11 kB
assets/InviteMemberDialogContent-B38z90Nz.js (removed) 7.66 kB 🟢 -7.66 kB 🟢 -2.4 kB 🟢 -2.1 kB
assets/Load3DConfiguration-07GAdhlK.js (removed) 6.55 kB 🟢 -6.55 kB 🟢 -2.03 kB 🟢 -1.77 kB
assets/Load3DConfiguration-Bpaioyky.js (new) 6.55 kB 🔴 +6.55 kB 🔴 +2.03 kB 🔴 +1.77 kB
assets/onboardingCloudRoutes-BwDNzWVk.js (new) 6.42 kB 🔴 +6.42 kB 🔴 +2.01 kB 🔴 +1.72 kB
assets/onboardingCloudRoutes-BVNwwAgO.js (removed) 6.31 kB 🟢 -6.31 kB 🟢 -1.96 kB 🟢 -1.69 kB
assets/WidgetWithControl-BGeZCFcc.js (new) 5.93 kB 🔴 +5.93 kB 🔴 +2.35 kB 🔴 +2.1 kB
assets/CreateWorkspaceDialogContent-Bm61at0F.js (new) 5.88 kB 🔴 +5.88 kB 🔴 +2.12 kB 🔴 +1.83 kB
assets/WidgetWithControl-wk95e6qN.js (removed) 5.87 kB 🟢 -5.87 kB 🟢 -2.31 kB 🟢 -2.06 kB
assets/CreateWorkspaceDialogContent-ogaJR5cR.js (removed) 5.84 kB 🟢 -5.84 kB 🟢 -2.09 kB 🟢 -1.82 kB
assets/FreeTierDialogContent-CczZB0Et.js (new) 5.74 kB 🔴 +5.74 kB 🔴 +2.02 kB 🔴 +1.79 kB
assets/FreeTierDialogContent-WEv-pwSm.js (removed) 5.7 kB 🟢 -5.7 kB 🟢 -1.99 kB 🟢 -1.75 kB
assets/EditWorkspaceDialogContent-Bw56dSL8.js (new) 5.67 kB 🔴 +5.67 kB 🔴 +2.08 kB 🔴 +1.82 kB
assets/EditWorkspaceDialogContent-DjMlGhoJ.js (removed) 5.63 kB 🟢 -5.63 kB 🟢 -2.05 kB 🟢 -1.79 kB
assets/Preview3d-B2PIKAPc.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.53 kB
assets/ValueControlPopover-BPJHiFjP.js (new) 5.26 kB 🔴 +5.26 kB 🔴 +1.9 kB 🔴 +1.69 kB
assets/Preview3d-BhgG_bHU.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.74 kB 🟢 -1.51 kB
assets/ValueControlPopover-B0Z1pRzO.js (removed) 5.22 kB 🟢 -5.22 kB 🟢 -1.88 kB 🟢 -1.67 kB
assets/WidgetTextarea-CEkiiQck.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +2.04 kB 🔴 +1.8 kB
assets/WidgetTextarea-CDGq98Ds.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -2.02 kB 🟢 -1.79 kB
assets/CancelSubscriptionDialogContent-DeJktAx6.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.92 kB 🔴 +1.67 kB
assets/CancelSubscriptionDialogContent-DCViH0bb.js (removed) 5.11 kB 🟢 -5.11 kB 🟢 -1.89 kB 🟢 -1.65 kB
assets/CloudNotificationContent-DiWweo5w.js (removed) 4.96 kB 🟢 -4.96 kB 🟢 -1.76 kB 🟢 -1.51 kB
assets/CloudNotificationContent-DP8WdPiV.js (new) 4.96 kB 🔴 +4.96 kB 🔴 +1.77 kB 🔴 +1.52 kB
assets/AnimationControls-1kPkkCLQ.js (removed) 4.78 kB 🟢 -4.78 kB 🟢 -1.66 kB 🟢 -1.47 kB
assets/AnimationControls-BWLQsb5x.js (new) 4.78 kB 🔴 +4.78 kB 🔴 +1.66 kB 🔴 +1.47 kB
assets/DeleteWorkspaceDialogContent-CtrmOUOF.js (new) 4.58 kB 🔴 +4.58 kB 🔴 +1.76 kB 🔴 +1.53 kB
assets/DeleteWorkspaceDialogContent-8JqnbWvR.js (removed) 4.54 kB 🟢 -4.54 kB 🟢 -1.73 kB 🟢 -1.5 kB
assets/missingModelDownload-GmBCtXZG.js (removed) 4.5 kB 🟢 -4.5 kB 🟢 -1.76 kB 🟢 -1.54 kB
assets/tierBenefits-DBEL-Zw9.js (removed) 4.47 kB 🟢 -4.47 kB 🟢 -1.58 kB 🟢 -1.36 kB
assets/tierBenefits-DjhM-bvZ.js (new) 4.47 kB 🔴 +4.47 kB 🔴 +1.58 kB 🔴 +1.36 kB
assets/LeaveWorkspaceDialogContent-C97Cmu6M.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.71 kB 🔴 +1.48 kB
assets/RemoveMemberDialogContent-Cas6NsV4.js (new) 4.39 kB 🔴 +4.39 kB 🔴 +1.66 kB 🔴 +1.45 kB
assets/LeaveWorkspaceDialogContent-DFoeg_x7.js (removed) 4.37 kB 🟢 -4.37 kB 🟢 -1.68 kB 🟢 -1.45 kB
assets/RemoveMemberDialogContent-DU0YxKtE.js (removed) 4.35 kB 🟢 -4.35 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/RevokeInviteDialogContent-OAIDBFU0.js (new) 4.3 kB 🔴 +4.3 kB 🔴 +1.67 kB 🔴 +1.46 kB
assets/RevokeInviteDialogContent-L4a7Inu0.js (removed) 4.26 kB 🟢 -4.26 kB 🟢 -1.64 kB 🟢 -1.44 kB
assets/InviteMemberUpsellDialogContent-fmWgqgZF.js (new) 4.2 kB 🔴 +4.2 kB 🔴 +1.53 kB 🔴 +1.34 kB
assets/InviteMemberUpsellDialogContent-BtHZNAwr.js (removed) 4.16 kB 🟢 -4.16 kB 🟢 -1.51 kB 🟢 -1.32 kB
assets/cloudSessionCookie-DXleJbGp.js (new) 4.06 kB 🔴 +4.06 kB 🔴 +1.46 kB 🔴 +1.27 kB
assets/missingModelDownload-B7H7Mbhx.js (new) 4.05 kB 🔴 +4.05 kB 🔴 +1.59 kB 🔴 +1.39 kB
assets/cloudSessionCookie-DEiwnm1B.js (removed) 4.02 kB 🟢 -4.02 kB 🟢 -1.43 kB 🟢 -1.23 kB
assets/saveMesh-CbQuzn-6.js (new) 3.84 kB 🔴 +3.84 kB 🔴 +1.65 kB 🔴 +1.46 kB
assets/saveMesh-ByTJvE71.js (removed) 3.8 kB 🟢 -3.8 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/WidgetGalleria-BoSxJdOZ.js (removed) 3.8 kB 🟢 -3.8 kB 🟢 -1.47 kB 🟢 -1.31 kB
assets/WidgetGalleria-UfEmFqXm.js (new) 3.8 kB 🔴 +3.8 kB 🔴 +1.48 kB 🔴 +1.31 kB
assets/Media3DTop-aLxa2A_X.js (new) 3.77 kB 🔴 +3.77 kB 🔴 +1.6 kB 🔴 +1.4 kB
assets/Popover-D0bYK8uk.js (removed) 3.77 kB 🟢 -3.77 kB 🟢 -1.49 kB 🟢 -1.32 kB
assets/Popover-zgdN5yOQ.js (new) 3.77 kB 🔴 +3.77 kB 🔴 +1.49 kB 🔴 +1.32 kB
assets/WidgetToggleSwitch-actlL4Ib.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.43 kB 🔴 +1.27 kB
assets/WidgetToggleSwitch-DC9WTarB.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.43 kB 🟢 -1.26 kB
assets/Media3DTop-Dsh2uqK1.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.57 kB 🟢 -1.38 kB
assets/WidgetBoundingBox-Cm1T1-zm.js (removed) 3.62 kB 🟢 -3.62 kB 🟢 -1.01 kB 🟢 -884 B
assets/WidgetBoundingBox-CXmDPZNt.js (new) 3.62 kB 🔴 +3.62 kB 🔴 +1.02 kB 🔴 +885 B
assets/Slider-Bpy6XtPB.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.38 kB 🔴 +1.2 kB
assets/Slider-DimxYSES.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.38 kB 🟢 -1.2 kB
assets/WidgetMarkdown-CzGe86Ty.js (new) 3.13 kB 🔴 +3.13 kB 🔴 +1.3 kB 🔴 +1.14 kB
assets/WidgetMarkdown-QIcnY9t5.js (removed) 3.13 kB 🟢 -3.13 kB 🟢 -1.3 kB 🟢 -1.14 kB
assets/WidgetInputText-CuuG5xrD.js (removed) 3.09 kB 🟢 -3.09 kB 🟢 -1.31 kB 🟢 -1.19 kB
assets/WidgetInputText-i7lzK9Cs.js (new) 3.09 kB 🔴 +3.09 kB 🔴 +1.32 kB 🔴 +1.18 kB
assets/GlobalToast-_Q9LAQ54.js (new) 3.04 kB 🔴 +3.04 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/GlobalToast-BYpQ7-pL.js (removed) 3.04 kB 🟢 -3.04 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/MediaVideoTop-37ayWmvD.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +1.2 kB 🔴 +1.07 kB
assets/MediaVideoTop-eLK4GBpk.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -1.2 kB 🟢 -1.05 kB
assets/ApiNodesSignInContent-Bbai3qp4.js (removed) 2.86 kB 🟢 -2.86 kB 🟢 -1.1 kB 🟢 -969 B
assets/ApiNodesSignInContent-DQd237fv.js (new) 2.86 kB 🔴 +2.86 kB 🔴 +1.11 kB 🔴 +976 B
assets/WidgetChart-C8VjAutl.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.03 kB 🔴 +885 B
assets/WidgetChart-D7tWs-eE.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1.02 kB 🟢 -885 B
assets/WidgetLayoutField-DAZ5_1GC.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.04 kB 🔴 +910 B
assets/WidgetLayoutField-DBOb9ip3.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.03 kB 🟢 -916 B
assets/SubscribeToRun-BuSnt4y9.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -980 B 🟢 -855 B
assets/SubscribeToRun-w8H4hryb.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +982 B 🔴 +858 B
assets/SubscriptionBenefits-BjcOI_DV.js (removed) 2.07 kB 🟢 -2.07 kB 🟢 -709 B 🟢 -605 B
assets/SubscriptionBenefits-DgHfQUz4.js (new) 2.07 kB 🔴 +2.07 kB 🔴 +709 B 🔴 +610 B
assets/MediaImageTop-C4Hl0e8O.js (removed) 2.02 kB 🟢 -2.02 kB 🟢 -982 B 🟢 -851 B
assets/MediaImageTop-DwAVRn52.js (new) 2.02 kB 🔴 +2.02 kB 🔴 +982 B 🔴 +865 B
assets/MediaAudioTop-DM7MuB9-.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +968 B 🔴 +820 B
assets/BaseViewTemplate-DDCsKdJq.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -979 B 🟢 -874 B
assets/BaseViewTemplate-DxoQqcAP.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +980 B 🔴 +873 B
assets/CloudRunButtonWrapper-BnfJHMFY.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +881 B 🔴 +779 B
assets/CloudRunButtonWrapper-CT2xvrGA.js (removed) 1.88 kB 🟢 -1.88 kB 🟢 -861 B 🟢 -758 B
assets/auto-_VZiwxFM.js (removed) 1.7 kB 🟢 -1.7 kB 🟢 -619 B 🟢 -545 B
assets/auto-RTJwH0yl.js (new) 1.7 kB 🔴 +1.7 kB 🔴 +621 B 🔴 +574 B
assets/cloudBadges-DAuRRFes.js (new) 1.69 kB 🔴 +1.69 kB 🔴 +862 B 🔴 +754 B
assets/cloudBadges-zO5nrdDK.js (removed) 1.65 kB 🟢 -1.65 kB 🟢 -837 B 🟢 -736 B
assets/cloudSubscription-DNr5SDRQ.js (new) 1.6 kB 🔴 +1.6 kB 🔴 +784 B 🔴 +671 B
assets/MediaAudioTop-DrzZkE5s.js (removed) 1.59 kB 🟢 -1.59 kB 🟢 -824 B 🟢 -685 B
assets/surveyRegistry-C9f9xcoT.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +743 B 🔴 +629 B
assets/surveyRegistry-FZy5gaD9.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -743 B 🟢 -630 B
assets/cloudSubscription-DComJaSk.js (removed) 1.56 kB 🟢 -1.56 kB 🟢 -758 B 🟢 -646 B
assets/signInSchema-CGXgewvH.js (new) 1.56 kB 🔴 +1.56 kB 🔴 +579 B 🔴 +544 B
assets/signInSchema-sxqrJJiq.js (removed) 1.56 kB 🟢 -1.56 kB 🟢 -577 B 🟢 -508 B
assets/previousFullPath---pnDg3M.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -693 B 🟢 -624 B
assets/previousFullPath-B7HWwSxI.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +696 B 🔴 +604 B
assets/widgetPropFilter-CrFbjsmY.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +703 B 🔴 +574 B
assets/widgetPropFilter-D7OjNvSa.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -704 B 🟢 -572 B
assets/VideoPlayOverlay-C8xyaG-_.js (removed) 1.51 kB 🟢 -1.51 kB 🟢 -762 B 🟢 -670 B
assets/VideoPlayOverlay-DVudiwLV.js (new) 1.51 kB 🔴 +1.51 kB 🔴 +763 B 🔴 +672 B
assets/Textarea-BfX2rdD1.js (removed) 1.42 kB 🟢 -1.42 kB 🟢 -742 B 🟢 -648 B
assets/Textarea-BWWabzbj.js (new) 1.42 kB 🔴 +1.42 kB 🔴 +744 B 🔴 +649 B
assets/Load3D-Cj8cxMP6.js (new) 1.27 kB 🔴 +1.27 kB 🔴 +583 B 🔴 +515 B
assets/Loader-Btvb7Cr1.js (new) 1.26 kB 🔴 +1.26 kB 🔴 +685 B 🔴 +594 B
assets/Loader-D0rCug03.js (removed) 1.26 kB 🟢 -1.26 kB 🟢 -684 B 🟢 -603 B
assets/Load3D-DO_8H4Lf.js (removed) 1.23 kB 🟢 -1.23 kB 🟢 -563 B 🟢 -495 B
assets/nightlyBadges-Cld-pYem.js (new) 1.22 kB 🔴 +1.22 kB 🔴 +630 B 🔴 +553 B
assets/nightlyBadges-C2VZGp2Y.js (removed) 1.18 kB 🟢 -1.18 kB 🟢 -604 B 🟢 -535 B
assets/Load3dViewerContent-3ZTGe03c.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +537 B 🔴 +473 B
assets/Load3dViewerContent-BbtdWLAJ.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -514 B 🟢 -451 B
assets/SubscriptionPanelContentWorkspace-5jOSJ4Aj.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +506 B 🔴 +438 B
assets/MediaOtherTop-B4_NVsA5.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -602 B 🟢 -493 B
assets/MediaOtherTop-lGNKEmfR.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +602 B 🔴 +500 B
assets/MediaTextTop-U33Ag7do.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -598 B 🟢 -498 B
assets/MediaTextTop-ZHz6G2M_.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +599 B 🔴 +492 B
assets/SubscriptionPanelContentWorkspace-DCC85bw8.js (removed) 1.04 kB 🟢 -1.04 kB 🟢 -482 B 🟢 -417 B
assets/ComfyOrgHeader-3Hu3A8Hh.js (new) 960 B 🔴 +960 B 🔴 +527 B 🔴 +464 B
assets/ComfyOrgHeader-BbOkh2BZ.js (removed) 960 B 🟢 -960 B 🟢 -527 B 🟢 -461 B
assets/WidgetLegacy-DngL86k-.js (new) 904 B 🔴 +904 B 🔴 +454 B 🔴 +391 B
assets/changeTracker-BCc6EULV.js (new) 879 B 🔴 +879 B 🔴 +444 B 🔴 +383 B
assets/WidgetLegacy-DoPmX-Zb.js (removed) 864 B 🟢 -864 B 🟢 -432 B 🟢 -373 B
assets/changeTracker-Ce_wIclC.js (removed) 839 B 🟢 -839 B 🟢 -422 B 🟢 -363 B
assets/graphHasMissingNodes-CZb34gXP.js (new) 822 B 🔴 +822 B 🔴 +415 B 🔴 +348 B
assets/graphHasMissingNodes-vvK5NVnu.js (removed) 822 B 🟢 -822 B 🟢 -414 B 🟢 -346 B
assets/constants-Cg0GcyXq.js (new) 766 B 🔴 +766 B 🔴 +375 B 🔴 +304 B
assets/constants-D_Ccd14m.js (removed) 766 B 🟢 -766 B 🟢 -375 B 🟢 -305 B
assets/src-DBt913Cu.js (removed) 290 B 🟢 -290 B 🟢 -239 B 🟢 -233 B
assets/src-DuZpIXCH.js (new) 290 B 🔴 +290 B 🔴 +239 B 🔴 +230 B
assets/WidgetBoundingBox-C7WYHat9.js (new) 283 B 🔴 +283 B 🔴 +186 B 🔴 +166 B
assets/WidgetBoundingBox-DF335aNG.js (removed) 283 B 🟢 -283 B 🟢 -183 B 🟢 -163 B
assets/cloud-subscription-ClCIQsCh.js (new) 279 B 🔴 +279 B 🔴 +184 B 🔴 +147 B
assets/cloud-subscription-lV7_7grb.js (removed) 279 B 🟢 -279 B 🟢 -183 B 🟢 -149 B
assets/comfy-logo-single-6rWyl_L-.js (new) 272 B 🔴 +272 B 🔴 +184 B 🔴 +147 B
assets/comfy-logo-single-DFR2W4gO.js (removed) 272 B 🟢 -272 B 🟢 -186 B 🟢 -150 B
assets/missingModelDownload-Dp6OhW0O.js (new) 267 B 🔴 +267 B 🔴 +185 B 🔴 +180 B
assets/missingModelDownload-mHR3Xmdz.js (removed) 267 B 🟢 -267 B 🟢 -184 B 🟢 -179 B
assets/i18n-Cx8VmPQ_.js (removed) 137 B 🟢 -137 B 🟢 -122 B 🟢 -108 B
assets/i18n-zb23SKYO.js (new) 137 B 🔴 +137 B 🔴 +122 B 🔴 +108 B

Status: 127 added / 126 removed / 6 unchanged

⚡ Performance Report

⚠️ 3 regressions detected

Metric Baseline PR (n=3) Δ Sig
workflow-execution: style recalcs 18 22 +23% ⚠️ z=3.3
workflow-execution: DOM nodes 169 177 +5% ⚠️ z=2.6
workflow-execution: event listeners 54 71 +31% ⚠️ z=4.6
All metrics
Metric Baseline PR (n=3) Δ Sig
canvas-idle: style recalcs 11 11 +6% z=0.5
canvas-idle: layouts 0 0 +0%
canvas-idle: task duration 358ms 359ms +0% z=-1.1
canvas-idle: DOM nodes 22 22 +0% z=0.0
canvas-idle: script duration 20ms 22ms +8% z=-1.5
canvas-idle: event listeners 14 6 -57% z=-1.1
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: frame duration 17ms 17ms +0% z=-0.1
canvas-mouse-sweep: style recalcs 77 76 -1% z=-1.3
canvas-mouse-sweep: layouts 12 12 +0%
canvas-mouse-sweep: task duration 778ms 769ms -1% z=-1.7
canvas-mouse-sweep: DOM nodes 60 60 -1% z=-1.0
canvas-mouse-sweep: script duration 126ms 133ms +6% z=-0.5
canvas-mouse-sweep: event listeners 7 13 +73% z=0.8
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: frame duration 17ms 17ms +0% z=-0.3
canvas-zoom-sweep: style recalcs 32 31 -3% z=-1.5
canvas-zoom-sweep: layouts 6 6 +0%
canvas-zoom-sweep: task duration 293ms 298ms +2% z=-1.4
canvas-zoom-sweep: DOM nodes 80 79 -1% z=-0.8
canvas-zoom-sweep: script duration 23ms 25ms +9% z=-0.8
canvas-zoom-sweep: event listeners 28 20 -28% z=-0.7
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: frame duration 17ms 17ms +0% z=1.2
dom-widget-clipping: style recalcs 13 14 +8% z=1.9
dom-widget-clipping: layouts 0 0 +0%
dom-widget-clipping: task duration 348ms 360ms +3% z=-0.5
dom-widget-clipping: DOM nodes 23 25 +7% z=1.8
dom-widget-clipping: script duration 66ms 73ms +11% z=1.3
dom-widget-clipping: event listeners 10 26 +160% variance too high
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: frame duration 17ms 17ms +0% z=-0.9
large-graph-idle: style recalcs 12 11 -6% z=-1.8
large-graph-idle: layouts 0 0 +0%
large-graph-idle: task duration 479ms 506ms +6% z=-0.8
large-graph-idle: DOM nodes 26 23 -9% z=-1.4
large-graph-idle: script duration 90ms 98ms +9% z=-0.5
large-graph-idle: event listeners 30 21 -31% z=-0.6
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: frame duration 17ms 17ms +0% z=0.1
large-graph-pan: style recalcs 70 69 -1% z=-0.3
large-graph-pan: layouts 0 0 +0%
large-graph-pan: task duration 1009ms 1031ms +2% z=-1.1
large-graph-pan: DOM nodes 20 19 -7% z=-0.0
large-graph-pan: script duration 394ms 393ms -0% z=-0.5
large-graph-pan: event listeners 6 6 +0% z=1.5
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: frame duration 17ms 17ms -0% z=0.3
minimap-idle: style recalcs 10 11 +7% z=1.8
minimap-idle: layouts 0 0 +0%
minimap-idle: task duration 473ms 472ms -0% z=-1.2
minimap-idle: DOM nodes 20 21 +7% z=1.8
minimap-idle: script duration 94ms 90ms -5% z=-0.8
minimap-idle: event listeners 5 5 +0% z=1.0
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: frame duration 17ms 17ms -0% z=0.1
subgraph-dom-widget-clipping: style recalcs 48 49 +1% z=1.2
subgraph-dom-widget-clipping: layouts 0 0 +0%
subgraph-dom-widget-clipping: task duration 362ms 364ms +1% z=-0.8
subgraph-dom-widget-clipping: DOM nodes 21 23 +9% z=1.0
subgraph-dom-widget-clipping: script duration 128ms 125ms -3% z=-0.6
subgraph-dom-widget-clipping: event listeners 8 16 +100% z=-0.1
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: frame duration 17ms 17ms -0% z=0.2
subgraph-idle: style recalcs 12 12 +0% z=0.9
subgraph-idle: layouts 0 0 +0%
subgraph-idle: task duration 338ms 346ms +2% z=-0.9
subgraph-idle: DOM nodes 23 25 +6% z=1.6
subgraph-idle: script duration 17ms 18ms +2% z=-1.2
subgraph-idle: event listeners 14 22 +57% variance too high
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: frame duration 17ms 17ms -0% z=0.5
subgraph-mouse-sweep: style recalcs 81 81 +0% z=0.1
subgraph-mouse-sweep: layouts 16 16 +0%
subgraph-mouse-sweep: task duration 719ms 748ms +4% z=-0.5
subgraph-mouse-sweep: DOM nodes 68 68 +0% z=0.3
subgraph-mouse-sweep: script duration 91ms 95ms +5% z=-0.8
subgraph-mouse-sweep: event listeners 13 13 +0% variance too high
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: frame duration 17ms 17ms +0% z=1.0
vue-large-graph-idle: style recalcs 0 1
vue-large-graph-idle: layouts 0 1
vue-large-graph-idle: task duration 11566ms 12553ms +9%
vue-large-graph-idle: DOM nodes -3334 -2226 -33%
vue-large-graph-idle: script duration 579ms 610ms +5%
vue-large-graph-idle: event listeners -16487 -9813 -40%
vue-large-graph-idle: TBT 0ms 290ms
vue-large-graph-idle: frame duration 18ms 18ms -3%
vue-large-graph-pan: style recalcs 65 66 +1%
vue-large-graph-pan: layouts 0 0 +0%
vue-large-graph-pan: task duration 13857ms 14163ms +2%
vue-large-graph-pan: DOM nodes -5193 -3338 -36%
vue-large-graph-pan: script duration 849ms 868ms +2%
vue-large-graph-pan: event listeners -16484 -16483 -0%
vue-large-graph-pan: TBT 20ms 9ms -54%
vue-large-graph-pan: frame duration 18ms 18ms +0%
workflow-execution: style recalcs 18 22 +23% ⚠️ z=3.3
workflow-execution: layouts 5 5 +14% z=1.6
workflow-execution: task duration 107ms 125ms +17% z=0.1
workflow-execution: DOM nodes 169 177 +5% ⚠️ z=2.6
workflow-execution: script duration 23ms 28ms +24% z=-0.3
workflow-execution: event listeners 54 71 +31% ⚠️ z=4.6
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: frame duration 17ms 17ms +0% z=1.6
Historical variance (last 10 runs)
Metric μ σ CV
canvas-idle: style recalcs 11 1 4.9%
canvas-idle: layouts 0 0 0.0%
canvas-idle: task duration 397ms 35ms 8.7%
canvas-idle: DOM nodes 22 1 5.9%
canvas-idle: script duration 26ms 2ms 8.9%
canvas-idle: event listeners 10 4 38.6%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: frame duration 17ms 0ms 0.0%
canvas-mouse-sweep: style recalcs 79 2 2.8%
canvas-mouse-sweep: layouts 12 0 0.0%
canvas-mouse-sweep: task duration 866ms 58ms 6.7%
canvas-mouse-sweep: DOM nodes 62 2 3.6%
canvas-mouse-sweep: script duration 136ms 7ms 5.5%
canvas-mouse-sweep: event listeners 9 4 46.3%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: frame duration 17ms 0ms 0.0%
canvas-zoom-sweep: style recalcs 31 0 1.5%
canvas-zoom-sweep: layouts 6 0 0.0%
canvas-zoom-sweep: task duration 330ms 23ms 7.1%
canvas-zoom-sweep: DOM nodes 79 1 0.8%
canvas-zoom-sweep: script duration 28ms 3ms 11.4%
canvas-zoom-sweep: event listeners 23 4 18.4%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: frame duration 17ms 0ms 0.0%
dom-widget-clipping: style recalcs 13 1 4.1%
dom-widget-clipping: layouts 0 0 0.0%
dom-widget-clipping: task duration 368ms 18ms 4.8%
dom-widget-clipping: DOM nodes 22 2 7.1%
dom-widget-clipping: script duration 68ms 4ms 5.6%
dom-widget-clipping: event listeners 8 8 99.9%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: frame duration 17ms 0ms 0.0%
large-graph-idle: style recalcs 12 0 2.7%
large-graph-idle: layouts 0 0 0.0%
large-graph-idle: task duration 554ms 59ms 10.6%
large-graph-idle: DOM nodes 24 1 3.3%
large-graph-idle: script duration 104ms 12ms 11.7%
large-graph-idle: event listeners 25 7 28.2%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: frame duration 17ms 0ms 0.0%
large-graph-pan: style recalcs 70 1 0.9%
large-graph-pan: layouts 0 0 0.0%
large-graph-pan: task duration 1084ms 50ms 4.7%
large-graph-pan: DOM nodes 19 2 9.7%
large-graph-pan: script duration 405ms 23ms 5.7%
large-graph-pan: event listeners 5 1 15.9%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: frame duration 17ms 0ms 0.0%
minimap-idle: style recalcs 9 1 6.9%
minimap-idle: layouts 0 0 0.0%
minimap-idle: task duration 535ms 51ms 9.5%
minimap-idle: DOM nodes 19 1 6.9%
minimap-idle: script duration 99ms 11ms 11.1%
minimap-idle: event listeners 5 1 15.9%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: frame duration 17ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalcs 48 1 1.4%
subgraph-dom-widget-clipping: layouts 0 0 0.0%
subgraph-dom-widget-clipping: task duration 380ms 21ms 5.5%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.7%
subgraph-dom-widget-clipping: script duration 129ms 8ms 5.8%
subgraph-dom-widget-clipping: event listeners 17 7 41.7%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: frame duration 17ms 0ms 0.0%
subgraph-idle: style recalcs 11 1 6.9%
subgraph-idle: layouts 0 0 0.0%
subgraph-idle: task duration 375ms 31ms 8.3%
subgraph-idle: DOM nodes 22 2 7.8%
subgraph-idle: script duration 21ms 3ms 12.7%
subgraph-idle: event listeners 12 8 63.4%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: frame duration 17ms 0ms 0.0%
subgraph-mouse-sweep: style recalcs 80 2 2.2%
subgraph-mouse-sweep: layouts 16 0 0.0%
subgraph-mouse-sweep: task duration 784ms 70ms 9.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.1%
subgraph-mouse-sweep: script duration 102ms 7ms 7.3%
subgraph-mouse-sweep: event listeners 8 4 51.6%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: frame duration 17ms 0ms 0.0%
workflow-execution: style recalcs 18 1 6.8%
workflow-execution: layouts 5 0 5.6%
workflow-execution: task duration 124ms 12ms 9.5%
workflow-execution: DOM nodes 161 6 3.8%
workflow-execution: script duration 30ms 4ms 11.8%
workflow-execution: event listeners 52 4 7.9%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: frame duration 17ms 0ms 0.0%
Trend (last 10 commits on main)
Metric Trend Dir Latest
canvas-idle: style recalcs █▅▁▃▁▃▆█▆█ ➡️ 12
canvas-idle: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: task duration ▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: DOM nodes █▄▁▂▂▅▆▆▇▇ ➡️ 24
canvas-idle: script duration ▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: event listeners █▂▁▂▇██▂█▆ 📈 11
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: frame duration ▁▆█▆▆▃▁▁▃▁ ➡️ 17ms
canvas-mouse-sweep: style recalcs ▂▁▄▄▆▇▆▃█▅ ➡️ 79
canvas-mouse-sweep: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: task duration ▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: DOM nodes ▁▁▄▂▅█▇▃▆▆ ➡️ 64
canvas-mouse-sweep: script duration ▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: event listeners ▁▇▁▁▁██▇▁█ 📈 13
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: frame duration ▄▁██▁▅██▅▄ ➡️ 17ms
canvas-zoom-sweep: style recalcs ▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: task duration ▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: DOM nodes ▁▄█▅▆▆▄▃▅▄ ➡️ 79
canvas-zoom-sweep: script duration ▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: event listeners ▂▂█▁██▇▁█▁ ➡️ 19
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: frame duration ▁▁▁█▁▁███▁ ➡️ 17ms
dom-widget-clipping: style recalcs ▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: task duration ▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: DOM nodes ▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: script duration ▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: event listeners ▅██▁▁▁▁█▁▁ 📉 2
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: frame duration ▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
large-graph-idle: style recalcs ▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: task duration ▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: DOM nodes ▃▁▂▃▆▆▇▂█▆ ➡️ 25
large-graph-idle: script duration ▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: event listeners █▄▁▄▇▇█▂█▇ 📈 29
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: frame duration ▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-pan: style recalcs ▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: task duration ▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: DOM nodes ▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: script duration ▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: event listeners ▆▁▁▃▆▁▃██▃ ➡️ 5
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: frame duration ▃▁█▆▆▆▆█▁▆ ➡️ 17ms
minimap-idle: style recalcs ▄█▁▂▇▂▁▇█▄ ➡️ 9
minimap-idle: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: task duration ▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: DOM nodes ▄█▁▂▇▂▁▇█▄ ➡️ 19
minimap-idle: script duration ▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: event listeners ▁▃▁▁▆▁▃█▆▁ ➡️ 4
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: frame duration ▁█▆▆▃▃▆█▆█ ➡️ 17ms
subgraph-dom-widget-clipping: style recalcs ▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: task duration ▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: DOM nodes ▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: script duration ▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: event listeners ▁▅██▁▁█▅█▅ 📈 16
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: frame duration ▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-idle: style recalcs ▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: task duration ▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: DOM nodes ▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: script duration ▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: event listeners ▁▁▁▁▅▄▁███ 📈 21
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: frame duration ▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-mouse-sweep: style recalcs ▄▂▄█▅▆▃▁▃▄ ➡️ 81
subgraph-mouse-sweep: layouts ▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: task duration ▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: DOM nodes ▃▂▃█▄▅▃▁▄▃ ➡️ 66
subgraph-mouse-sweep: script duration ▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: event listeners ▁▁▁█▇▂▁▇▇▁ ➡️ 5
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: frame duration ▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
workflow-execution: style recalcs ▃▆█▇▆▆▇▃▄▁ ➡️ 15
workflow-execution: layouts ▆▆▁▆▆█▆▃▆▃ ➡️ 5
workflow-execution: task duration ▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: DOM nodes ▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: script duration ▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: event listeners ▄███▁██▄█▄ ➡️ 49
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: frame duration ▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
Raw data
{
  "timestamp": "2026-03-18T04:28:45.983Z",
  "gitSha": "1a6d3cad6fce3bf4397bc076244540bc436313d6",
  "branch": "feature/new-wave-audio",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2026.8389999999954,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 10.595,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 362.25700000000006,
      "heapDeltaBytes": 1685400,
      "domNodes": 23,
      "jsHeapTotalBytes": 14942208,
      "scriptDurationMs": 20.85,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-idle",
      "durationMs": 2036.3189999999918,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.74,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 362.80199999999996,
      "heapDeltaBytes": 1137308,
      "domNodes": 22,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 24.779000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-idle",
      "durationMs": 2026.6879999999219,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.740000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 351.51899999999995,
      "heapDeltaBytes": 1392244,
      "domNodes": 22,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 20.566000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1918.5559999999953,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 44.774,
      "layouts": 12,
      "layoutDurationMs": 4.13,
      "taskDurationMs": 820.336,
      "heapDeltaBytes": -2048516,
      "domNodes": 65,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 135.02599999999998,
      "eventListeners": 30,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1801.3449999999693,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 34.54500000000001,
      "layouts": 12,
      "layoutDurationMs": 3.2489999999999997,
      "taskDurationMs": 750.6870000000001,
      "heapDeltaBytes": -2555512,
      "domNodes": 57,
      "jsHeapTotalBytes": 17563648,
      "scriptDurationMs": 133.38,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1793.7789999999723,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 35.017999999999994,
      "layouts": 12,
      "layoutDurationMs": 3.384,
      "taskDurationMs": 735.253,
      "heapDeltaBytes": -2673956,
      "domNodes": 58,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 130.525,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1748.5130000000026,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 17.311,
      "layouts": 6,
      "layoutDurationMs": 0.704,
      "taskDurationMs": 301.29200000000003,
      "heapDeltaBytes": 5881440,
      "domNodes": 79,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 25.961000000000002,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1750.4190000000222,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 17.250999999999998,
      "layouts": 6,
      "layoutDurationMs": 0.7499999999999998,
      "taskDurationMs": 296.506,
      "heapDeltaBytes": 5876588,
      "domNodes": 78,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 25.465999999999994,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1752.5819999999612,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 16.491,
      "layouts": 6,
      "layoutDurationMs": 0.562,
      "taskDurationMs": 295.049,
      "heapDeltaBytes": 5861056,
      "domNodes": 79,
      "jsHeapTotalBytes": 17039360,
      "scriptDurationMs": 23.659,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 607.0099999999741,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 11.043000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 390.24399999999997,
      "heapDeltaBytes": 18891168,
      "domNodes": 24,
      "jsHeapTotalBytes": 18612224,
      "scriptDurationMs": 89.643,
      "eventListeners": 26,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 551.2729999999806,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 10.982000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 339.923,
      "heapDeltaBytes": 13785524,
      "domNodes": 25,
      "jsHeapTotalBytes": 12582912,
      "scriptDurationMs": 64.965,
      "eventListeners": 26,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 575.0500000000329,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 11.313,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 349.577,
      "heapDeltaBytes": 13541468,
      "domNodes": 25,
      "jsHeapTotalBytes": 13369344,
      "scriptDurationMs": 65.08500000000001,
      "eventListeners": 26,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2025.2319999999884,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 11.141000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 521.577,
      "heapDeltaBytes": -9619556,
      "domNodes": 23,
      "jsHeapTotalBytes": 8531968,
      "scriptDurationMs": 101.14500000000001,
      "eventListeners": 28,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "large-graph-idle",
      "durationMs": 1999.3390000000204,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.425,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 477.944,
      "heapDeltaBytes": -10055220,
      "domNodes": 22,
      "jsHeapTotalBytes": 9318400,
      "scriptDurationMs": 90.06900000000002,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-idle",
      "durationMs": 1994.2920000000868,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 13.308,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 519.0839999999998,
      "heapDeltaBytes": -10559708,
      "domNodes": 25,
      "jsHeapTotalBytes": 6934528,
      "scriptDurationMs": 102.498,
      "eventListeners": 30,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2107.568999999984,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 16.187,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1022.2600000000002,
      "heapDeltaBytes": 5429280,
      "domNodes": 20,
      "jsHeapTotalBytes": 15790080,
      "scriptDurationMs": 385.41200000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2109.3140000000403,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 16.634,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1051.719,
      "heapDeltaBytes": 6381692,
      "domNodes": 20,
      "jsHeapTotalBytes": 9236480,
      "scriptDurationMs": 405.80899999999997,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2106.273999999985,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 15.441,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1018.4150000000001,
      "heapDeltaBytes": 4483960,
      "domNodes": 16,
      "jsHeapTotalBytes": 8450048,
      "scriptDurationMs": 388.077,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 2017.0119999999656,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 9.641,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 473.71700000000004,
      "heapDeltaBytes": 13558472,
      "domNodes": 20,
      "jsHeapTotalBytes": 14561280,
      "scriptDurationMs": 94.136,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "minimap-idle",
      "durationMs": 2003.5520000000133,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.839999999999996,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 471.60999999999996,
      "heapDeltaBytes": -10783068,
      "domNodes": 22,
      "jsHeapTotalBytes": 8769536,
      "scriptDurationMs": 87.188,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "minimap-idle",
      "durationMs": 1990.1820000000043,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.304,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 470.82099999999997,
      "heapDeltaBytes": -10805280,
      "domNodes": 22,
      "jsHeapTotalBytes": 8269824,
      "scriptDurationMs": 88.76100000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 580.1829999999768,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 11.452,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 355.9,
      "heapDeltaBytes": 12989840,
      "domNodes": 22,
      "jsHeapTotalBytes": 14942208,
      "scriptDurationMs": 123.74600000000001,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 571.1069999999836,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 12.418,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 354.539,
      "heapDeltaBytes": 13032132,
      "domNodes": 22,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 121.36300000000001,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.65999999999999
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 595.6180000000586,
      "styleRecalcs": 50,
      "styleRecalcDurationMs": 13.924,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 382.82199999999995,
      "heapDeltaBytes": 12677156,
      "domNodes": 26,
      "jsHeapTotalBytes": 16252928,
      "scriptDurationMs": 128.67199999999997,
      "eventListeners": 32,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1992.7529999999933,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.12,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 339.71799999999996,
      "heapDeltaBytes": 799952,
      "domNodes": 22,
      "jsHeapTotalBytes": 17563648,
      "scriptDurationMs": 17.386,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999947
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1997.5979999999822,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 11.850000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 348.271,
      "heapDeltaBytes": 1003000,
      "domNodes": 25,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 18.005000000000003,
      "eventListeners": 30,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2002.2429999999076,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 12.095,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 350.188,
      "heapDeltaBytes": 1732332,
      "domNodes": 27,
      "jsHeapTotalBytes": 17825792,
      "scriptDurationMs": 17.167,
      "eventListeners": 30,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1979.343,
      "styleRecalcs": 87,
      "styleRecalcDurationMs": 44.745,
      "layouts": 16,
      "layoutDurationMs": 4.375,
      "taskDurationMs": 910.6020000000001,
      "heapDeltaBytes": -7141808,
      "domNodes": 74,
      "jsHeapTotalBytes": 17563648,
      "scriptDurationMs": 97.86500000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1715.4439999999909,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 39.778999999999996,
      "layouts": 16,
      "layoutDurationMs": 6.9430000000000005,
      "taskDurationMs": 680.237,
      "heapDeltaBytes": -6457480,
      "domNodes": 64,
      "jsHeapTotalBytes": 17563648,
      "scriptDurationMs": 94.271,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.680000000000017
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1690.2689999999438,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 38.419000000000004,
      "layouts": 16,
      "layoutDurationMs": 4.56,
      "taskDurationMs": 651.664,
      "heapDeltaBytes": -7090760,
      "domNodes": 66,
      "jsHeapTotalBytes": 18087936,
      "scriptDurationMs": 94.24499999999999,
      "eventListeners": 28,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000036
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13300.543000000005,
      "styleRecalcs": 2,
      "styleRecalcDurationMs": 26.943999999999996,
      "layouts": 2,
      "layoutDurationMs": 9.235999999999994,
      "taskDurationMs": 13285.117000000002,
      "heapDeltaBytes": 3957808,
      "domNodes": -1,
      "jsHeapTotalBytes": 36438016,
      "scriptDurationMs": 621.46,
      "eventListeners": 3534,
      "totalBlockingTimeMs": 871,
      "frameDurationMs": 18.33000000000029
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12139.696000000014,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12127.838,
      "heapDeltaBytes": -28808216,
      "domNodes": -3338,
      "jsHeapTotalBytes": 21757952,
      "scriptDurationMs": 596.596,
      "eventListeners": -16486,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000073
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12265.201999999932,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12245.646,
      "heapDeltaBytes": -13647808,
      "domNodes": -3340,
      "jsHeapTotalBytes": 18350080,
      "scriptDurationMs": 610.649,
      "eventListeners": -16486,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.33000000000029
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14183.144000000028,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 12.513999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14164.026,
      "heapDeltaBytes": -36840988,
      "domNodes": -3338,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 877.213,
      "eventListeners": -16482,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.339999999999783
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14206.833000000017,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 14.746999999999982,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14187.756,
      "heapDeltaBytes": -4025876,
      "domNodes": -3336,
      "jsHeapTotalBytes": 15380480,
      "scriptDurationMs": 860.265,
      "eventListeners": -16484,
      "totalBlockingTimeMs": 26,
      "frameDurationMs": 18.340000000000146
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14156.072999999993,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 12.619999999999992,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14136.394000000002,
      "heapDeltaBytes": -10700876,
      "domNodes": -3340,
      "jsHeapTotalBytes": 16691200,
      "scriptDurationMs": 866.0989999999999,
      "eventListeners": -16482,
      "totalBlockingTimeMs": 2,
      "frameDurationMs": 18.339999999999783
    },
    {
      "name": "workflow-execution",
      "durationMs": 459.0170000000171,
      "styleRecalcs": 22,
      "styleRecalcDurationMs": 23.624,
      "layouts": 6,
      "layoutDurationMs": 1.588,
      "taskDurationMs": 123.586,
      "heapDeltaBytes": 4795492,
      "domNodes": 192,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 27.088999999999995,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "workflow-execution",
      "durationMs": 458.1100000000333,
      "styleRecalcs": 24,
      "styleRecalcDurationMs": 24.702,
      "layouts": 5,
      "layoutDurationMs": 1.5999999999999999,
      "taskDurationMs": 120.40899999999999,
      "heapDeltaBytes": 4532096,
      "domNodes": 181,
      "jsHeapTotalBytes": 4456448,
      "scriptDurationMs": 24.990999999999993,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000027
    },
    {
      "name": "workflow-execution",
      "durationMs": 448.9019999999755,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 26.163,
      "layouts": 5,
      "layoutDurationMs": 1.436,
      "taskDurationMs": 131.24699999999999,
      "heapDeltaBytes": 4513228,
      "domNodes": 157,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 33.242000000000004,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998
    }
  ]
}

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

♻️ Duplicate comments (1)
src/composables/useWaveAudioPlayer.ts (1)

71-99: ⚠️ Potential issue | 🟠 Major

Failed loads can leave stale blobUrl, causing wrong audio playback and URL leaks.

When decode/fetch fails, blobUrl is not cleared/revoked in catch. Since audioSrc prefers blobUrl (Line 36), the player can keep using an old track after src changes.

💡 Proposed cleanup fix
 async function decodeAudioSource(url: string) {
   loading.value = true
   let ctx: AudioContext | undefined
+  let nextBlobUrl: string | undefined
   try {
@@
-    const blob = new Blob([arrayBuffer.slice(0)], {
+    const blob = new Blob([arrayBuffer], {
       type: response.headers.get('content-type') ?? 'audio/wav'
     })
-    if (blobUrl.value) URL.revokeObjectURL(blobUrl.value)
-    blobUrl.value = URL.createObjectURL(blob)
+    nextBlobUrl = URL.createObjectURL(blob)

     ctx = new AudioContext()
     const audioBuffer = await ctx.decodeAudioData(arrayBuffer)
+    if (blobUrl.value) URL.revokeObjectURL(blobUrl.value)
+    blobUrl.value = nextBlobUrl
+    nextBlobUrl = undefined
     generateBarsFromBuffer(audioBuffer)
-  } catch {
+  } catch {
+    if (nextBlobUrl) URL.revokeObjectURL(nextBlobUrl)
+    if (blobUrl.value) {
+      URL.revokeObjectURL(blobUrl.value)
+      blobUrl.value = undefined
+    }
     bars.value = generatePlaceholderBars()
   } finally {
-    await ctx?.close()
+    await ctx?.close().catch(() => undefined)
     loading.value = false
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/composables/useWaveAudioPlayer.ts` around lines 71 - 99,
decodeAudioSource can leave a stale blobUrl when fetch/decode fails because the
catch block only sets placeholder bars; update the catch block to revoke and
clear any existing blobUrl (check blobUrl.value, call URL.revokeObjectURL and
set blobUrl.value = undefined) so audioSrc (which prefers blobUrl) won't
continue to point at an old track, then set bars to generatePlaceholderBars();
keep the finally behavior (ctx?.close() and loading.value = false) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/composables/useWaveAudioPlayer.test.ts`:
- Around line 72-98: The test's mocked fetch response is missing success
indicators so the composable may take the error path without decodeAudioData
running; update the mockFetchApi resolved value to include ok: true (and
optionally status: 200) so the response is treated as successful, then assert
that the AudioContext.decodeAudioData mock (or decodeAudioData on the created
AudioContext) was called with the ArrayBuffer to ensure decoding actually
happened; locate this in the test around useWaveAudioPlayer, mockFetchApi,
globalThis.AudioContext, decodeAudioData, src and bars.

In `@src/composables/useWaveAudioPlayer.ts`:
- Around line 71-100: decodeAudioSource is vulnerable to race conditions because
multiple async decodes can complete out of order and overwrite bars/blobUrl; add
a per-invocation request token and only commit state when the token matches the
latest. Concretely: introduce a module-scoped incrementing counter (e.g.,
decodeRequestCounter) and inside decodeAudioSource capture const requestId =
++decodeRequestCounter; after each await (before mutating blobUrl, calling
URL.revokeObjectURL, setting bars, loading, or calling
generateBarsFromBuffer/generatePlaceholderBars) check that requestId ===
decodeRequestCounter and skip updates if not; keep ctx local and still close it
in finally but avoid revoking/setting blobUrl or updating bars unless the token
matches. Apply the same request-token guard pattern to the similar async decode
block referenced at 149-159.
- Around line 94-96: The empty catch in useWaveAudioPlayer swallows errors;
update the catch to capture the thrown error and surface it via a dedicated
error ref (e.g., audioError or playbackError) instead of silently discarding
it—set bars.value = generatePlaceholderBars() for UI fallback and assign
audioError.value = { message: 'Failed to generate audio bars', cause: err } (or
similar), and ensure the hook returns that error ref so callers/UI can react;
alternatively, if callers should handle it, rethrow the captured error from the
catch after setting the placeholder.

---

Duplicate comments:
In `@src/composables/useWaveAudioPlayer.ts`:
- Around line 71-99: decodeAudioSource can leave a stale blobUrl when
fetch/decode fails because the catch block only sets placeholder bars; update
the catch block to revoke and clear any existing blobUrl (check blobUrl.value,
call URL.revokeObjectURL and set blobUrl.value = undefined) so audioSrc (which
prefers blobUrl) won't continue to point at an old track, then set bars to
generatePlaceholderBars(); keep the finally behavior (ctx?.close() and
loading.value = false) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c7a3a430-37ee-4ad6-89c9-c89c9b9fe687

📥 Commits

Reviewing files that changed from the base of the PR and between 6c72039 and 5b7a38e.

📒 Files selected for processing (3)
  • src/components/common/WaveAudioPlayer.vue
  • src/composables/useWaveAudioPlayer.test.ts
  • src/composables/useWaveAudioPlayer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/common/WaveAudioPlayer.vue

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 18, 2026
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: 1

♻️ Duplicate comments (1)
src/composables/useWaveAudioPlayer.ts (1)

24-25: ⚠️ Potential issue | 🟠 Major

Invalidate pending decode work on unmount to avoid object-URL leaks.

A request that resolves after unmount can still create a new blob URL. The
current unmount cleanup won’t revoke URLs created afterward.

💡 Suggested fix
 onUnmounted(() => {
+  decodeRequestId += 1
   audioRef.value?.pause()
-  if (blobUrl.value) URL.revokeObjectURL(blobUrl.value)
+  if (blobUrl.value) {
+    URL.revokeObjectURL(blobUrl.value)
+    blobUrl.value = undefined
+  }
 })

Also applies to: 172-175

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

In `@src/composables/useWaveAudioPlayer.ts` around lines 24 - 25, The decode flow
can create blob URLs after the component unmounts causing leaks; update the
decode logic that uses decodeRequestId (and any handler that generates blob URLs
for bars) so you increment decodeRequestId before each decode, capture the
current id in the async task, and when the task resolves compare the captured id
against the latest decodeRequestId and skip creating/replacing blob URLs or
updating bars if they differ; also ensure the unmount cleanup
increments/invalidates decodeRequestId (or sets a cancelled flag) and revokes
any existing object URLs stored in bars (and revokes newly created URLs
immediately if the component is already unmounted) to prevent leaks.
🧹 Nitpick comments (1)
src/composables/useWaveAudioPlayer.test.ts (1)

72-102: Add regression tests for source-switch failure and empty-src cleanup.

Given the new request-token logic, it would help to lock in behavior when a new
source fails to decode (and when src becomes empty), so stale audio URLs
cannot regress silently.

As per coding guidelines "Do not write tests that just test the mocks; ensure tests fail when code behaves unexpectedly."

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

In `@src/composables/useWaveAudioPlayer.test.ts` around lines 72 - 102, Add two
regression tests in useWaveAudioPlayer.test.ts to cover (1) when src switches to
a new URL whose fetch decodes fail: simulate mockFetchApi resolving for the new
URL and mockDecodeAudioData rejecting, then assert that the previous decoded
data/bars remain unchanged (no silent replacement) and loading resolves
appropriately; and (2) when src becomes empty: set src.value = '' and assert the
player cleans up by calling AudioContext.close (mockClose), clearing bars and
stopping any loading state. Use the existing test helpers/mocks (mockFetchApi,
mockDecodeAudioData, mockClose) and the same useWaveAudioPlayer invocation to
locate relevant logic in useWaveAudioPlayer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/composables/useWaveAudioPlayer.ts`:
- Line 38: audioSrc currently prefers blobUrl over src which can keep a previous
blob playing when src becomes empty or a decode fails; change the computed
audioSrc to return an empty/explicit src when src.value is falsy (e.g.,
computed(() => src.value ? (blobUrl.value ?? src.value) : src.value)) so a
cleared src wins over an existing blob, and ensure any decode error paths that
previously left blobUrl set (the function that creates/assigns blobUrl after
decoding) explicitly clear blobUrl on failure so no stale blob remains.

---

Duplicate comments:
In `@src/composables/useWaveAudioPlayer.ts`:
- Around line 24-25: The decode flow can create blob URLs after the component
unmounts causing leaks; update the decode logic that uses decodeRequestId (and
any handler that generates blob URLs for bars) so you increment decodeRequestId
before each decode, capture the current id in the async task, and when the task
resolves compare the captured id against the latest decodeRequestId and skip
creating/replacing blob URLs or updating bars if they differ; also ensure the
unmount cleanup increments/invalidates decodeRequestId (or sets a cancelled
flag) and revokes any existing object URLs stored in bars (and revokes newly
created URLs immediately if the component is already unmounted) to prevent
leaks.

---

Nitpick comments:
In `@src/composables/useWaveAudioPlayer.test.ts`:
- Around line 72-102: Add two regression tests in useWaveAudioPlayer.test.ts to
cover (1) when src switches to a new URL whose fetch decodes fail: simulate
mockFetchApi resolving for the new URL and mockDecodeAudioData rejecting, then
assert that the previous decoded data/bars remain unchanged (no silent
replacement) and loading resolves appropriately; and (2) when src becomes empty:
set src.value = '' and assert the player cleans up by calling AudioContext.close
(mockClose), clearing bars and stopping any loading state. Use the existing test
helpers/mocks (mockFetchApi, mockDecodeAudioData, mockClose) and the same
useWaveAudioPlayer invocation to locate relevant logic in useWaveAudioPlayer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5377abfe-767e-4c7c-a54c-d94f3e976405

📥 Commits

Reviewing files that changed from the base of the PR and between da3abe9 and b6568a6.

📒 Files selected for processing (2)
  • src/composables/useWaveAudioPlayer.test.ts
  • src/composables/useWaveAudioPlayer.ts

const formattedCurrentTime = computed(() => formatTime(currentTime.value))
const formattedDuration = computed(() => formatTime(duration.value))

const audioSrc = computed(() => blobUrl.value ?? src.value)
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

Prevent stale audio playback when decode fails or src becomes empty.

Because audioSrc prefers blobUrl, the previous blob can stay active after a
failed decode or an empty src, so users may hear the old clip unexpectedly.

💡 Suggested fix
 watch(
   src,
   (url) => {
+    if (blobUrl.value) {
+      URL.revokeObjectURL(blobUrl.value)
+      blobUrl.value = undefined
+    }
     if (url) {
       playing.value = false
       currentTime.value = 0
       void decodeAudioSource(url)
+    } else {
+      bars.value = generatePlaceholderBars()
     }
   },
   { immediate: true }
 )
@@
-    } catch {
+    } catch {
       if (requestId === decodeRequestId) {
+        if (blobUrl.value) {
+          URL.revokeObjectURL(blobUrl.value)
+          blobUrl.value = undefined
+        }
         bars.value = generatePlaceholderBars()
       }
     } finally {

Also applies to: 101-104, 160-170

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

In `@src/composables/useWaveAudioPlayer.ts` at line 38, audioSrc currently prefers
blobUrl over src which can keep a previous blob playing when src becomes empty
or a decode fails; change the computed audioSrc to return an empty/explicit src
when src.value is falsy (e.g., computed(() => src.value ? (blobUrl.value ??
src.value) : src.value)) so a cleared src wins over an existing blob, and ensure
any decode error paths that previously left blobUrl set (the function that
creates/assigns blobUrl after decoding) explicitly clear blobUrl on failure so
no stale blob remains.

Comment on lines +162 to +167
export function formatTime(seconds: number): string {
if (isNaN(seconds) || seconds === 0) return '0:00'
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we reuse the one in audioUtils?

audioSrc,
bars,
loading,
isPlaying: playing,
Copy link
Contributor

Choose a reason for hiding this comment

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

The only one that has to be renamed...

watch(
src,
(url) => {
if (url) {
Copy link
Contributor

Choose a reason for hiding this comment

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

When the whole watch body is truthy gated, you can use whenever

const secs = Math.floor(seconds % 60)
return `${mins}:${secs.toString().padStart(2, '0')}`
}
export { formatTime } from '@/utils/formatUtil'
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of re-exporting, can the consumers all just import from formatUtil?

Comment on lines +191 to +192
align?: 'center' | 'bottom'
variant?: 'compact' | 'expanded'
Copy link
Contributor

Choose a reason for hiding this comment

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

Worth using cva?

"
:style="{
height: (bar.height / 100) * height + 'px',
minHeight: '2px'
Copy link
Contributor

Choose a reason for hiding this comment

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

This one could be baked into the classlist, since it's constant.

align === 'center' ? 'items-center' : 'items-end'
)
"
:style="{ height: height + 'px' }"
Copy link
Contributor

Choose a reason for hiding this comment

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

For all of the styles derived from height, one option is to use a CSS variable instead that you can set once at a common root and use something like h-(--wave-bar-height) so that you're not mutating styles on as many DOM elements.

@DrJKL DrJKL assigned viva-jinyi and unassigned DrJKL Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants