Skip to content

feat(video): video preview composables and metadata utils - #14121

Merged
jtydhr88 merged 1 commit into
mainfrom
feat/video-preview-composables
Jul 27, 2026
Merged

feat(video): video preview composables and metadata utils#14121
jtydhr88 merged 1 commit into
mainfrom
feat/video-preview-composables

Conversation

@jtydhr88

Copy link
Copy Markdown
Collaborator

This is seperate part for the big PR of video edit, crop, trim PR #14118

Summary

  • useVideoSourceUrl resolves a playable url for the video a node operates on: the linked upstream node (with subgraph passthrough) or the node itself, preferring executed output previews over the file widget; keyed store subscription, rand cache-buster stripped
  • useVideoFilmstrip samples thumbnail strips off a hidden video element with seek timeouts and stale-load bail-out
  • videoMetadataUtil fetches exact fps/frame count/duration/size from the backend /video_metadata endpoint (falls back gracefully when absent); videoFrameUtil holds frame/time conversion helpers

@jtydhr88
jtydhr88 requested a review from a team July 26, 2026 21:34
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 26, 2026
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1732 passed, 0 failed · 1 flaky

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

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/27/2026, 03:13:32 PM UTC

Links

📦 Bundle: 8.1 MB gzip ⚪ 0 B

Details

Summary

  • Raw size: 34 MB baseline 34 MB — ⚪ 0 B
  • Gzip: 8.1 MB baseline 8.1 MB — ⚪ 0 B
  • Brotli: 5.6 MB baseline 5.6 MB — ⚪ 0 B
  • Bundles: 420 current • 420 baseline

Category Glance
Vendor & Third-Party ⚪ 0 B (15.7 MB) · Other ⚪ 0 B (12.4 MB) · Data & Services ⚪ 0 B (3.37 MB) · Graph Workspace ⚪ 0 B (1.25 MB) · Panels & Settings ⚪ 0 B (551 kB) · Utilities & Hooks ⚪ 0 B (357 kB) · + 5 more

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

Main entry bundles and manifests

Status: 1 unchanged

Graph Workspace — 1.25 MB (baseline 1.25 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

Status: 2 unchanged

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

Top-level views, pages, and routed surfaces

Status: 16 unchanged

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

Configuration panels, inspectors, and settings screens

Status: 26 unchanged

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

Authentication, profile, and account management bundles

Status: 10 unchanged

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

Modals, dialogs, drawers, and in-app editors

Status: 6 unchanged

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

Reusable component library chunks

Status: 14 unchanged

Data & Services — 3.37 MB (baseline 3.37 MB) • ⚪ 0 B

Stores, services, APIs, and repositories

Status: 17 unchanged

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

Helpers, composables, and utility bundles

Status: 35 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

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

Bundles that do not match a named category

Status: 277 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.7 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.6 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.2 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.0 MB heap
large-graph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.5 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.1 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 72.0 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.6 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.5 MB heap
subgraph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.0 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 44.5 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 138ms TBT · 93.2 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.2 MB heap
vue-large-graph-idle: · 55.4 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 158.6 MB heap
vue-large-graph-pan: · 55.4 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 388ms TBT · 168.6 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 48.3 MB heap

⚠️ 9 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
canvas-idle: task duration 417ms 534ms +28% ⚠️ z=4.5
canvas-zoom-sweep: task duration 308ms 428ms +39% ⚠️ z=4.4
dom-widget-clipping: task duration 294ms 425ms +44% ⚠️ z=3.7
large-graph-idle: task duration 557ms 708ms +27% ⚠️ z=3.1
large-graph-pan: task duration 960ms 1353ms +41% ⚠️ z=6.3
large-graph-pan: script duration 295ms 464ms +57% ⚠️ z=2.8
minimap-idle: task duration 561ms 762ms +36% ⚠️ z=5.0
minimap-idle: script duration 70ms 122ms +74% ⚠️ z=2.4
subgraph-idle: task duration 390ms 544ms +40% ⚠️ z=5.5
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.5
canvas-idle: p95 frame time 17ms 17ms -1%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 6ms 11ms +90% z=-0.0
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 10 10 +0% z=-2.1
canvas-idle: task duration 417ms 534ms +28% ⚠️ z=4.5
canvas-idle: script duration 14ms 21ms +55% z=-1.8
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 67.7 MB 67.7 MB +0%
canvas-idle: DOM nodes 20 20 +0% z=-2.0
canvas-idle: event listeners 6 4 -33% z=-1.6
canvas-mouse-sweep: avg frame time 17ms 17ms -0% z=-0.9
canvas-mouse-sweep: p95 frame time 17ms 17ms -1%
canvas-mouse-sweep: layout duration 2ms 4ms +55% z=0.6
canvas-mouse-sweep: style recalc duration 23ms 42ms +82% z=-0.1
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 73 74 +1% z=-2.0
canvas-mouse-sweep: task duration 607ms 923ms +52% z=1.0
canvas-mouse-sweep: script duration 78ms 130ms +67% z=-0.8
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 62.5 MB 56.6 MB -10%
canvas-mouse-sweep: DOM nodes 57 -105 -284% z=-64.7
canvas-mouse-sweep: event listeners 4 -65 -1713% z=-17.5
canvas-zoom-sweep: avg frame time 17ms 17ms -0% z=0.5
canvas-zoom-sweep: p95 frame time 17ms 17ms -1%
canvas-zoom-sweep: layout duration 0ms 1ms +36% z=0.6
canvas-zoom-sweep: style recalc duration 13ms 18ms +42% z=-0.7
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 30 32 +5% z=0.5
canvas-zoom-sweep: task duration 308ms 428ms +39% ⚠️ z=4.4
canvas-zoom-sweep: script duration 15ms 25ms +68% z=-0.7
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 71.2 MB 71.2 MB +0%
canvas-zoom-sweep: DOM nodes 80 77 -4% z=-2.8
canvas-zoom-sweep: event listeners 21 19 -10% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.2
dom-widget-clipping: p95 frame time 17ms 17ms -0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 6ms 8ms +43% z=-2.0
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 14 11 -25% z=-5.2
dom-widget-clipping: task duration 294ms 425ms +44% ⚠️ z=3.7
dom-widget-clipping: script duration 43ms 64ms +49% z=-1.0
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 52.7 MB 53.0 MB +0%
dom-widget-clipping: DOM nodes 24 17 -29% z=-3.6
dom-widget-clipping: event listeners 2 1 -50% variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=0.2
large-graph-idle: p95 frame time 17ms 17ms -0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 6ms 8ms +47% z=-3.7
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 9 8 -11% z=-11.5
large-graph-idle: task duration 557ms 708ms +27% ⚠️ z=3.1
large-graph-idle: script duration 70ms 112ms +60% z=0.9
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 63.0 MB 61.5 MB -2%
large-graph-idle: DOM nodes -266 -267 +0% z=-322.7
large-graph-idle: event listeners -129 -129 +0% z=-25.4
large-graph-pan: avg frame time 17ms 17ms +0% z=-0.2
large-graph-pan: p95 frame time 17ms 17ms +0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 10ms 14ms +44% z=-4.1
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 69 68 -1% z=-2.4
large-graph-pan: task duration 960ms 1353ms +41% ⚠️ z=6.3
large-graph-pan: script duration 295ms 464ms +57% ⚠️ z=2.8
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 61.2 MB 61.1 MB -0%
large-graph-pan: DOM nodes -267 -269 +1% z=-174.6
large-graph-pan: event listeners -129 -128 -1% z=-160.5
large-graph-zoom: avg frame time 17ms 17ms +0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 6ms 8ms +36%
large-graph-zoom: style recalc duration 10ms 15ms +44%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 65 64 -2%
large-graph-zoom: task duration 1107ms 1564ms +41%
large-graph-zoom: script duration 358ms 554ms +54%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 79.9 MB 72.0 MB -10%
large-graph-zoom: DOM nodes 12 -131 -1192%
large-graph-zoom: event listeners 6 -63 -1142%
minimap-idle: avg frame time 17ms 17ms +0% z=0.1
minimap-idle: p95 frame time 17ms 17ms +0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 6ms 8ms +38% z=-1.3
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 10 8 -25% z=-3.0
minimap-idle: task duration 561ms 762ms +36% ⚠️ z=5.0
minimap-idle: script duration 70ms 122ms +74% ⚠️ z=2.4
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 65.8 MB 63.6 MB -3%
minimap-idle: DOM nodes -267 -270 +1% z=-211.4
minimap-idle: event listeners -129 -129 +0% z=-202.3
subgraph-dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.9
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 8ms 11ms +45% z=-1.7
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 47 -3% z=-2.5
subgraph-dom-widget-clipping: task duration 309ms 415ms +34% z=2.0
subgraph-dom-widget-clipping: script duration 86ms 125ms +46% z=-0.5
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 53.3 MB 53.5 MB +0%
subgraph-dom-widget-clipping: DOM nodes 22 19 -14% z=-2.8
subgraph-dom-widget-clipping: event listeners 8 8 +0% z=-1.4
subgraph-idle: avg frame time 17ms 17ms +0% z=0.4
subgraph-idle: p95 frame time 17ms 17ms +1%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 5ms 11ms +98% z=0.3
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 10 10 -5% z=-2.1
subgraph-idle: task duration 390ms 544ms +40% ⚠️ z=5.5
subgraph-idle: script duration 12ms 17ms +47% z=-1.0
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 67.6 MB 68.0 MB +1%
subgraph-idle: DOM nodes 20 19 -5% z=-1.9
subgraph-idle: event listeners 6 5 -17% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms -0% z=-0.1
subgraph-mouse-sweep: p95 frame time 17ms 17ms -1%
subgraph-mouse-sweep: layout duration 3ms 5ms +37% z=-0.4
subgraph-mouse-sweep: style recalc duration 26ms 41ms +56% z=-0.4
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 78 +2% z=-1.4
subgraph-mouse-sweep: task duration 594ms 889ms +50% z=1.8
subgraph-mouse-sweep: script duration 62ms 102ms +65% z=0.2
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 59.2 MB 44.5 MB -25%
subgraph-mouse-sweep: DOM nodes 62 -266 -529% z=-149.0
subgraph-mouse-sweep: event listeners 4 -133 -3425% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms -0%
subgraph-transition-enter: p95 frame time 17ms 17ms +0%
subgraph-transition-enter: layout duration 9ms 13ms +52%
subgraph-transition-enter: style recalc duration 24ms 32ms +34%
subgraph-transition-enter: layout count 15 13 -13%
subgraph-transition-enter: style recalc count 19 17 -11%
subgraph-transition-enter: task duration 725ms 972ms +34%
subgraph-transition-enter: script duration 21ms 37ms +73%
subgraph-transition-enter: TBT 108ms 138ms +28%
subgraph-transition-enter: heap used 92.2 MB 93.2 MB +1%
subgraph-transition-enter: DOM nodes 13673 13673 +0%
subgraph-transition-enter: event listeners 2369 2371 +0%
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 25ms 40ms +61%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 249 250 +0%
viewport-pan-sweep: task duration 3359ms 4844ms +44%
viewport-pan-sweep: script duration 952ms 1508ms +58%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 65.7 MB 61.2 MB -7%
viewport-pan-sweep: DOM nodes -266 -268 +1%
viewport-pan-sweep: event listeners -113 -113 +0%
vue-large-graph-idle: avg frame time 17ms 18ms +5%
vue-large-graph-idle: p95 frame time 17ms 17ms -0%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 11817ms 17801ms +51%
vue-large-graph-idle: script duration 436ms 618ms +42%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 157.8 MB 158.6 MB +0%
vue-large-graph-idle: DOM nodes -8311 -8311 +0%
vue-large-graph-idle: event listeners -16384 -16382 -0%
vue-large-graph-pan: avg frame time 17ms 18ms +5%
vue-large-graph-pan: p95 frame time 17ms 17ms +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 13ms 21ms +65%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 69 157 +127%
vue-large-graph-pan: task duration 14299ms 21597ms +51%
vue-large-graph-pan: script duration 676ms 947ms +40%
vue-large-graph-pan: TBT 7ms 388ms +5443%
vue-large-graph-pan: heap used 156.6 MB 168.6 MB +8%
vue-large-graph-pan: DOM nodes -8311 -8311 +0%
vue-large-graph-pan: event listeners -16380 -16379 -0%
workflow-execution: avg frame time 17ms 17ms +0% z=0.6
workflow-execution: p95 frame time 17ms 17ms -0%
workflow-execution: layout duration 0ms 0ms +39% z=-7.8
workflow-execution: style recalc duration 14ms 20ms +48% z=-1.7
workflow-execution: layout count 2 2 +0% z=-5.4
workflow-execution: style recalc count 15 15 -3% z=-1.6
workflow-execution: task duration 86ms 119ms +39% z=-0.4
workflow-execution: script duration 7ms 10ms +43% z=-6.3
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 48.1 MB 48.3 MB +0%
workflow-execution: DOM nodes 121 127 +5% z=-4.8
workflow-execution: event listeners 67 66 -1% z=3.2
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-07-27T15:24:20.356Z",
  "gitSha": "bf806cb020c77c24bf54a8323c5c45258dfd0904",
  "branch": "feat/video-preview-composables",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2036.2890000000107,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.527999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 556.436,
      "heapDeltaBytes": 3472132,
      "heapUsedBytes": 71028964,
      "domNodes": 20,
      "jsHeapTotalBytes": 20586496,
      "scriptDurationMs": 23.708999999999996,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2020.9650000000465,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 11.079999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 511.44499999999994,
      "heapDeltaBytes": 3491184,
      "heapUsedBytes": 70998584,
      "domNodes": 20,
      "jsHeapTotalBytes": 20848640,
      "scriptDurationMs": 18.845,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1828.0920000000265,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 40.419999999999995,
      "layouts": 12,
      "layoutDurationMs": 3.4990000000000006,
      "taskDurationMs": 893.593,
      "heapDeltaBytes": -1661584,
      "heapUsedBytes": 65821632,
      "domNodes": 57,
      "jsHeapTotalBytes": 21897216,
      "scriptDurationMs": 130.814,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1889.024000000063,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 44.318,
      "layouts": 12,
      "layoutDurationMs": 3.9609999999999994,
      "taskDurationMs": 952.2760000000001,
      "heapDeltaBytes": -14837320,
      "heapUsedBytes": 52793320,
      "domNodes": -267,
      "jsHeapTotalBytes": 22024192,
      "scriptDurationMs": 129.81599999999997,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1755.1159999999868,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 19.607,
      "layouts": 6,
      "layoutDurationMs": 0.6119999999999999,
      "taskDurationMs": 479.47200000000004,
      "heapDeltaBytes": 7298568,
      "heapUsedBytes": 74612272,
      "domNodes": 78,
      "jsHeapTotalBytes": 20586496,
      "scriptDurationMs": 29.961000000000002,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1715.249999999969,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 16.409,
      "layouts": 6,
      "layoutDurationMs": 0.7240000000000001,
      "taskDurationMs": 375.796,
      "heapDeltaBytes": 7125800,
      "heapUsedBytes": 74703268,
      "domNodes": 76,
      "jsHeapTotalBytes": 20062208,
      "scriptDurationMs": 20.339999999999996,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 732.8340000000253,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.937,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 473.83699999999993,
      "heapDeltaBytes": -11875844,
      "heapUsedBytes": 55775024,
      "domNodes": 20,
      "jsHeapTotalBytes": 21110784,
      "scriptDurationMs": 71.584,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 579.7620000000734,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 6.684000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 375.55899999999997,
      "heapDeltaBytes": -12078360,
      "heapUsedBytes": 55277920,
      "domNodes": 14,
      "jsHeapTotalBytes": 21635072,
      "scriptDurationMs": 57.406000000000006,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2015.2719999999817,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.697,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 723.195,
      "heapDeltaBytes": 5675204,
      "heapUsedBytes": 66998672,
      "domNodes": -266,
      "jsHeapTotalBytes": 4792320,
      "scriptDurationMs": 116.673,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2041.2960000001021,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.042,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 693.5029999999999,
      "heapDeltaBytes": 2839476,
      "heapUsedBytes": 62036684,
      "domNodes": -268,
      "jsHeapTotalBytes": 5316608,
      "scriptDurationMs": 108.186,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2251.008000000013,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 14.65,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1376.8580000000002,
      "heapDeltaBytes": 6094044,
      "heapUsedBytes": 65676080,
      "domNodes": -268,
      "jsHeapTotalBytes": 4997120,
      "scriptDurationMs": 472.72200000000004,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2194.1790000000765,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 13.389999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1328.862,
      "heapDeltaBytes": 2354884,
      "heapUsedBytes": 62549880,
      "domNodes": -270,
      "jsHeapTotalBytes": 4997120,
      "scriptDurationMs": 455.22200000000004,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3380.471,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 15.749000000000002,
      "layouts": 60,
      "layoutDurationMs": 8.107999999999999,
      "taskDurationMs": 1581.5210000000002,
      "heapDeltaBytes": 25058504,
      "heapUsedBytes": 86555556,
      "domNodes": 10,
      "jsHeapTotalBytes": 8912896,
      "scriptDurationMs": 569.685,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3296.0709999999835,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 14.384,
      "layouts": 60,
      "layoutDurationMs": 7.617,
      "taskDurationMs": 1547.385,
      "heapDeltaBytes": 925344,
      "heapUsedBytes": 64461172,
      "domNodes": -272,
      "jsHeapTotalBytes": 7675904,
      "scriptDurationMs": 537.393,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2030.9300000000121,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 8.28,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 835.4630000000001,
      "heapDeltaBytes": 6230632,
      "heapUsedBytes": 66670708,
      "domNodes": -271,
      "jsHeapTotalBytes": 4005888,
      "scriptDurationMs": 136.83499999999998,
      "eventListeners": -131,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "minimap-idle",
      "durationMs": 2025.4170000000613,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.671999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 689.397,
      "heapDeltaBytes": 6493612,
      "heapUsedBytes": 66772992,
      "domNodes": -269,
      "jsHeapTotalBytes": 4530176,
      "scriptDurationMs": 107.47599999999998,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 607.9780000000028,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 11.138,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 422.02400000000006,
      "heapDeltaBytes": -11470632,
      "heapUsedBytes": 56027704,
      "domNodes": 18,
      "jsHeapTotalBytes": 22421504,
      "scriptDurationMs": 124.778,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 629.1549999999688,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 11,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 407.962,
      "heapDeltaBytes": -11299376,
      "heapUsedBytes": 56271972,
      "domNodes": 20,
      "jsHeapTotalBytes": 21110784,
      "scriptDurationMs": 124.76399999999998,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2014.8170000000505,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 10.727,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 588.188,
      "heapDeltaBytes": 3652692,
      "heapUsedBytes": 71260880,
      "domNodes": 16,
      "jsHeapTotalBytes": 20586496,
      "scriptDurationMs": 20.845,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1995.176000000015,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.508000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 499.96,
      "heapDeltaBytes": 3313736,
      "heapUsedBytes": 71324976,
      "domNodes": 22,
      "jsHeapTotalBytes": 20848640,
      "scriptDurationMs": 14.13,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1755.2919999999972,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 42.675,
      "layouts": 16,
      "layoutDurationMs": 4.9910000000000005,
      "taskDurationMs": 938.4140000000001,
      "heapDeltaBytes": -20808664,
      "heapUsedBytes": 46851436,
      "domNodes": -268,
      "jsHeapTotalBytes": 20451328,
      "scriptDurationMs": 109.47500000000001,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1732.456999999954,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 39.77799999999999,
      "layouts": 16,
      "layoutDurationMs": 4.174,
      "taskDurationMs": 838.693,
      "heapDeltaBytes": -21189024,
      "heapUsedBytes": 46383220,
      "domNodes": -264,
      "jsHeapTotalBytes": 20189184,
      "scriptDurationMs": 94.602,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1401.1090000000195,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 31.560999999999993,
      "layouts": 13,
      "layoutDurationMs": 13.12,
      "taskDurationMs": 972.0699999999999,
      "heapDeltaBytes": 31020392,
      "heapUsedBytes": 97704100,
      "domNodes": 13673,
      "jsHeapTotalBytes": 14417920,
      "scriptDurationMs": 36.50600000000001,
      "eventListeners": 2371,
      "totalBlockingTimeMs": 138,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8952.777000000026,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 41.842000000000006,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 5162.055,
      "heapDeltaBytes": 9306220,
      "heapUsedBytes": 67926680,
      "domNodes": -268,
      "jsHeapTotalBytes": 6017024,
      "scriptDurationMs": 1594.8950000000002,
      "eventListeners": -113,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8313.467000000059,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 38.644,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4525.744000000001,
      "heapDeltaBytes": 1826728,
      "heapUsedBytes": 60393860,
      "domNodes": -267,
      "jsHeapTotalBytes": 7151616,
      "scriptDurationMs": 1421.344,
      "eventListeners": -113,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17782.510000000002,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17738.917999999998,
      "heapDeltaBytes": -41234784,
      "heapUsedBytes": 166930140,
      "domNodes": -8311,
      "jsHeapTotalBytes": -13570048,
      "scriptDurationMs": 640.5860000000001,
      "eventListeners": -16381,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 18.329999999999927,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 17884.893999999917,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17863.83,
      "heapDeltaBytes": -58277956,
      "heapUsedBytes": 165579920,
      "domNodes": -8311,
      "jsHeapTotalBytes": -15138816,
      "scriptDurationMs": 594.6969999999999,
      "eventListeners": -16382,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 21939.37900000003,
      "styleRecalcs": 159,
      "styleRecalcDurationMs": 23.127999999999982,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 21873.237,
      "heapDeltaBytes": -30279284,
      "heapUsedBytes": 176714296,
      "domNodes": -8311,
      "jsHeapTotalBytes": -14180352,
      "scriptDurationMs": 984.5390000000001,
      "eventListeners": -16380,
      "totalBlockingTimeMs": 422,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 21372.144000000048,
      "styleRecalcs": 154,
      "styleRecalcDurationMs": 18.502999999999993,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 21320.896999999997,
      "heapDeltaBytes": -31079252,
      "heapUsedBytes": 176896536,
      "domNodes": -8311,
      "jsHeapTotalBytes": -14180352,
      "scriptDurationMs": 909.792,
      "eventListeners": -16378,
      "totalBlockingTimeMs": 354,
      "frameDurationMs": 18.333333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 463.7870000000248,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 19.897000000000002,
      "layouts": 2,
      "layoutDurationMs": 0.4470000000000001,
      "taskDurationMs": 121.42100000000002,
      "heapDeltaBytes": -15936368,
      "heapUsedBytes": 50675348,
      "domNodes": 132,
      "jsHeapTotalBytes": 8265728,
      "scriptDurationMs": 10.636,
      "eventListeners": 67,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "workflow-execution",
      "durationMs": 462.5859999999875,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 20.897,
      "layouts": 2,
      "layoutDurationMs": 0.39800000000000013,
      "taskDurationMs": 116.55199999999999,
      "heapDeltaBytes": -16156944,
      "heapUsedBytes": 50634424,
      "domNodes": 121,
      "jsHeapTotalBytes": 8003584,
      "scriptDurationMs": 10.041000000000002,
      "eventListeners": 65,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 755dd6f9-b1c6-43a1-b4e4-d52c97db6dd9

📥 Commits

Reviewing files that changed from the base of the PR and between 77b9e1d and 315ec2e.

📒 Files selected for processing (8)
  • src/composables/video/useVideoFilmstrip.test.ts
  • src/composables/video/useVideoFilmstrip.ts
  • src/composables/video/useVideoSourceUrl.test.ts
  • src/composables/video/useVideoSourceUrl.ts
  • src/utils/videoFrameUtil.test.ts
  • src/utils/videoFrameUtil.ts
  • src/utils/videoMetadataUtil.test.ts
  • src/utils/videoMetadataUtil.ts

📝 Walkthrough

Walkthrough

Changes

Video processing

Layer / File(s) Summary
Metadata and frame conversion contracts
src/utils/videoMetadataUtil.ts, src/utils/videoFrameUtil.ts, src/utils/*.test.ts
Adds validated backend metadata retrieval, frame/time conversion helpers, millisecond rounding, and tests for valid and fallback cases.
Reactive video source resolution
src/composables/video/useVideoSourceUrl.ts, src/composables/video/useVideoSourceUrl.test.ts
Resolves video URLs from node outputs, file widgets, upstream nodes, and nested subgraph outputs while tracking reactive dependencies.
Video filmstrip generation
src/composables/video/useVideoFilmstrip.ts, src/composables/video/useVideoFilmstrip.test.ts
Loads metadata, samples frames through seeking and canvas rendering, handles stale loads and failures, resets state, and exposes reactive video properties and thumbnails.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Consumer
  participant useVideoSourceUrl
  participant useVideoFilmstrip
  participant VideoElement
  participant MetadataAPI
  participant Canvas

  Consumer->>useVideoSourceUrl: resolve reactive videoUrl
  useVideoSourceUrl-->>useVideoFilmstrip: provide videoUrl
  useVideoFilmstrip->>VideoElement: load video and await metadata
  useVideoFilmstrip->>MetadataAPI: fetchVideoMetadata(videoUrl)
  MetadataAPI-->>useVideoFilmstrip: return validated metadata
  useVideoFilmstrip->>VideoElement: seek to sample time
  VideoElement-->>useVideoFilmstrip: emit seeked
  useVideoFilmstrip->>Canvas: draw video frame
  Canvas-->>useVideoFilmstrip: return JPEG data URL
  useVideoFilmstrip-->>Consumer: update thumbnails and video properties
Loading

Possibly related PRs


Important

Pre-merge checks failed

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

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the high-level summary but omits the template's Changes, Review Focus, and Screenshots sections. Add the required Changes section (What/Breaking/Dependencies), plus Review Focus and Screenshots if applicable.
End-To-End Regression Coverage For Fixes ❓ Inconclusive Commit subjects and PR title aren’t available here, so the bug-fix signal can’t be verified from PR metadata alone. Provide the PR title and commit subjects (or a screenshot/export of the PR metadata) so the bug-fix check can be applied.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding video preview composables and metadata utilities.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed No changed files are under src/lib/litegraph/, src/ecs/, or graph-entity paths; this PR only adds video composables/utilities/tests, so the ADR check is not applicable.
✨ 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 feat/video-preview-composables

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/composables/video/useVideoFilmstrip.test.ts`:
- Around line 113-198: Add focused tests around useVideoFilmstrip for failed or
timed-out metadata loading, asserting error.value and reset state after the
catch path; mock canvas getContext to return null and verify the resulting
behavior; and cover the isLoadStale race by switching videoUrl before the first
load resolves, ensuring stale results do not overwrite the second URL’s state.
Reuse existing video mocks and wait helpers while preserving the current
happy-path tests.
- Around line 168-185: The test duplicates the video and canvas creation wiring
already handled by installVideoMocks. Extend installVideoMocks with an optional
onVideoCreated callback, invoke it for each created MockVideoElement, and update
“samples the configured number of frames” to use that callback for seekCount
while retaining the existing metadata emission and canvas behavior.

In `@src/composables/video/useVideoFilmstrip.ts`:
- Around line 78-84: Update the seek wait handling in the filmstrip loop around
waitForEvent so timeout rejections continue skipping the frame, while genuine
video error-event rejections stop processing and propagate the media error
through error.value. Replace the unconditional catch-and-continue behavior
without changing successful seek handling or the alreadyAtTarget path.
- Around line 92-135: Update useVideoFilmstrip and its waitForEvent error flow
so the error ref exposes stable typed error codes or keys instead of raw English
messages or DOM event names. Replace the Canvas-unavailable and video-load
failure assignments, and map timeout/load failures to user-facing translation
keys configured in src/locales/en/main.json; let consuming components translate
and format the displayed message through vue-i18n.
- Around line 114-201: Extract the duplicated media-state assignments from the
loadVideo catch block and the falsy-url branch of the videoUrl watch callback
into a shared resetState helper. Have both paths call resetState, while
preserving their distinct error and loading behavior and keeping the existing
default FPS value.
- Around line 71-90: The filmstrip loop in useVideoFilmstrip must not rely on a
seeked event for an already-at-target currentTime, especially for the first
sample at time 0. Preserve the alreadyAtTarget bypass and add or update coverage
in src/composables/video/useVideoFilmstrip.test.ts:19-70 to verify the
first-frame path captures successfully without waiting on a seek event; no
direct change is required there beyond the requested test coverage.

In `@src/composables/video/useVideoSourceUrl.test.ts`:
- Around line 88-102: Extend the test around mountSource and the videoUrl
fallback to use reactive mocked store state, initially asserting the upstream
widget URL, then add the executed output to the mocked state and await
nextTick() before asserting videoUrl switches to the preview URL. Ensure the
test exercises the keyed subscription and reactive transition, not only initial
resolution.

In `@src/composables/video/useVideoSourceUrl.ts`:
- Around line 61-69: Update sourceFileWidgetValue to key widgetValueStore
lookups with the source node’s containing graph ID rather than
source.graph.rootGraph.id, while preserving the local widget fallback. Extend
the subgraph-related tests to cover distinct root and containing-subgraph IDs,
ensuring nested nodes read their own file widget instead of a same-ID root
widget.
- Around line 88-90: The self-source branch in useVideoSourceUrl must prioritize
the executed outputUrl before fileUrl, matching the preview-priority contract;
update src/composables/video/useVideoSourceUrl.ts lines 88-90 accordingly.
Update src/composables/video/useVideoSourceUrl.test.ts lines 104-115 to expect
already-trimmed.mp4 when both URLs exist, while preserving coverage for falling
back to the widget URL when no output exists.

In `@src/utils/videoFrameUtil.ts`:
- Around line 8-20: Require a finite positive fallback FPS before performing
fallback conversion: update both fallback checks in frameToTime and timeToFrame
in src/utils/videoFrameUtil.ts (lines 8-20) to validate with Number.isFinite and
a value greater than zero, otherwise return 0. Add negative and non-finite
fallback cases to src/utils/videoFrameUtil.test.ts (lines 12-33) and verify they
return 0.

In `@src/utils/videoMetadataUtil.ts`:
- Around line 16-33: Update viewQueryFromUrl to validate that the parsed URL’s
origin matches the configured Comfy API origin before reading its query
parameters, while preserving relative same-origin URL handling. Reject external
/view URLs by returning undefined, and add a test verifying they do not trigger
the video metadata API request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b9812e12-afdf-4496-840d-3c67c4c6494e

📥 Commits

Reviewing files that changed from the base of the PR and between a98cfa3 and 77b9e1d.

📒 Files selected for processing (8)
  • src/composables/video/useVideoFilmstrip.test.ts
  • src/composables/video/useVideoFilmstrip.ts
  • src/composables/video/useVideoSourceUrl.test.ts
  • src/composables/video/useVideoSourceUrl.ts
  • src/utils/videoFrameUtil.test.ts
  • src/utils/videoFrameUtil.ts
  • src/utils/videoMetadataUtil.test.ts
  • src/utils/videoMetadataUtil.ts

Comment thread src/composables/video/useVideoFilmstrip.test.ts
Comment thread src/composables/video/useVideoFilmstrip.test.ts
Comment thread src/composables/video/useVideoFilmstrip.ts
Comment thread src/composables/video/useVideoFilmstrip.ts
Comment thread src/composables/video/useVideoFilmstrip.ts
Comment thread src/composables/video/useVideoSourceUrl.test.ts
Comment thread src/composables/video/useVideoSourceUrl.ts
Comment thread src/composables/video/useVideoSourceUrl.ts
Comment thread src/utils/videoFrameUtil.ts Outdated
Comment thread src/utils/videoMetadataUtil.ts
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.96970% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/composables/video/useVideoFilmstrip.ts 96.85% 4 Missing ⚠️
src/utils/videoMetadataUtil.ts 92.85% 2 Missing ⚠️
src/composables/video/useVideoSourceUrl.ts 98.46% 1 Missing ⚠️
@@            Coverage Diff             @@
##             main   #14121      +/-   ##
==========================================
+ Coverage   79.53%   79.55%   +0.01%     
==========================================
  Files        1700     1727      +27     
  Lines      110882   111715     +833     
  Branches    37719    37222     -497     
==========================================
+ Hits        88190    88871     +681     
- Misses      22220    22351     +131     
- Partials      472      493      +21     
Flag Coverage Δ
unit 68.32% <96.96%> (+0.20%) ⬆️

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

Files with missing lines Coverage Δ
src/utils/videoFrameUtil.ts 100.00% <100.00%> (ø)
src/composables/video/useVideoSourceUrl.ts 98.46% <98.46%> (ø)
src/utils/videoMetadataUtil.ts 92.85% <92.85%> (ø)
src/composables/video/useVideoFilmstrip.ts 96.85% <96.85%> (ø)

... and 43 files with indirect coverage changes

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

@jtydhr88
jtydhr88 force-pushed the feat/video-preview-composables branch from 77b9e1d to 050ba6a Compare July 26, 2026 22:01
@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pillar5-agent Ready Ready Preview, Comment Jul 26, 2026 10:02pm

Request Review

@jtydhr88

Copy link
Copy Markdown
Collaborator Author

@coderabbitai approve

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Comments resolved and changes approved.

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two blocking correctness issues remain on the current head: authoritative metadata is only partially applied, and nested subgraph outputs are only unwrapped one level.


if (isLoadStale(loadId, url)) return

fps.value = metadata?.fps ?? options.fps ?? DEFAULT_VIDEO_FPS

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: The backend metadata is only used for FPS, size, and frame count; its duration, width, and height are discarded, and sampling still uses videoDuration. When loadedmetadata reports a non-finite duration (common for some fragmented/streamed MP4s), this normalizes to 0 even if /video_metadata returns a valid duration, so every filmstrip sample targets frame zero and the UI reports a zero duration. Could we derive effective duration/dimensions from the backend values when present and pass that effective duration into sampleFilmstripFrames?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

const link = current.getInputLink(slot)
if (!link) return undefined
upstream =
upstream.resolveSubgraphOutputLink(link.origin_slot)?.outputNode ?? null

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: This unwraps only one subgraph boundary. If that output is itself another SubgraphNode (VideoEdit <- OuterSubgraph <- InnerSubgraph <- LoadVideo), resolution stops on the inner wrapper, so neither the actual loader output nor its file widget is found. resolveSubgraphOutputLink exposes the next link.origin_slot; could we continue traversing subgraph outputs (with a cycle guard) until reaching a concrete source node?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

@dante01yoon dante01yoon assigned jtydhr88 and unassigned dante01yoon Jul 27, 2026
@jtydhr88 jtydhr88 assigned dante01yoon and unassigned jtydhr88 Jul 27, 2026
@jtydhr88
jtydhr88 merged commit 3471706 into main Jul 27, 2026
63 checks passed
@jtydhr88
jtydhr88 deleted the feat/video-preview-composables branch July 27, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants