Skip to content

feat(website): SEO model pages — 207 models, FAQ JSON-LD, partner node support#11892

Open
christian-byrne wants to merge 23 commits intomainfrom
glary/seo-model-pages
Open

feat(website): SEO model pages — 207 models, FAQ JSON-LD, partner node support#11892
christian-byrne wants to merge 23 commits intomainfrom
glary/seo-model-pages

Conversation

@christian-byrne
Copy link
Copy Markdown
Contributor

@christian-byrne christian-byrne commented May 4, 2026

Summary

  • Adds programmatic SEO model pages at /p/supported-models/[slug] for 207 models auto-generated from workflow_templates (180 local + 27 partner nodes)
  • 3-file architecture: generated-models.json (auto-generated, checked in) + model-metadata.ts (editorial overrides) + models.ts (65-line merger)
  • Full JSON-LD per page: SoftwareApplication + BreadcrumbList + FAQPage (targeting AI Overviews / People Also Ask)
  • Partner node support: directory: 'partner_nodes' hides Download button, shows VIEW TUTORIAL
  • generate-models.ts: walks workflow_templates for local models + API_PROVIDER_MAP for 30+ partner integrations (Kling, Meshy, Luma, Runway, Stability AI, ByteDance, Google, etc.)
  • Weekly GH Actions workflow opens issue when new models appear in workflow_templates but not in generated-models.json
  • add-model-page Claude skill for Slack-driven model page PRs

Files changed

File Purpose
apps/website/src/config/generated-models.json Auto-generated, 207 models (27 partner + 180 local)
apps/website/src/config/model-metadata.ts Editorial overrides: docsUrl, blogUrl, featured (9 entries)
apps/website/src/config/models.ts 65-line merger — imports JSON + overrides, exports models + getModelBySlug
apps/website/scripts/generate-models.ts Build-time parser; run with pnpm generate:models
apps/website/src/i18n/translations.ts ~30 UI keys added (no per-model keys — displayName is plain string)
apps/website/src/pages/p/supported-models/[slug].astro Dynamic route with 3x JSON-LD schemas
apps/website/src/pages/p/supported-models/index.astro Model grid index page
apps/website/src/components/models/ModelHeroSection.vue Hero component
.github/workflows/model-page-discovery.yaml Weekly auto-discovery workflow
.claude/skills/add-model-page/SKILL.md Claude skill for adding/updating model pages

Test plan

  • pnpm build passes in apps/website
  • /p/supported-models index renders 207 model cards
  • /p/supported-models/kling-ai shows Partner Node eyebrow, no Download button, VIEW TUTORIAL CTA
  • /p/supported-models/flux-1-dev shows Diffusion Model eyebrow, Download + Tutorial buttons
  • /p/supported-models/umt5-xxl-fp8-e4m3fn-scaled redirects 301 to umt5-xxl-fp16 (canonicalSlug)
  • Structured data validator shows FAQPage + SoftwareApplication + BreadcrumbList valid

Fixes FE-421

- 103-model registry (100 local + 3 partner nodes) in models.ts with docsUrl/blogUrl fields
- Dynamic [slug].astro route with SoftwareApplication + BreadcrumbList + FAQPage JSON-LD
- ModelHeroSection.vue with partner node support and docs/tutorial CTAs
- "What is X?" section on every model page targeting AI Overviews / PAA
- generate-models.ts parser with API_PROVIDER_MAP for 30+ partner node providers
- Auto-discovery GH Actions workflow (weekly, opens issue on new models)
- add-model-page Glary-Bot skill for non-dev Slack-driven PRs
- Index page listing all 103 models

Closes FE-421
@christian-byrne christian-byrne requested a review from a team May 4, 2026 06:50
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label May 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a "Supported Models" feature: a generator extracts model entries from workflow templates into a JSON registry, typed model config and helpers, listing and detail pages with SEO/JSON‑LD and a hero component, i18n keys, contributor skill doc, and a weekly GitHub Actions job to surface new models.

Changes

Supported Models feature

Layer / File(s) Summary
Data Shape / Registry
apps/website/src/config/models.ts, apps/website/src/config/generated-models.json, apps/website/src/config/model-metadata.ts
Defines ModelDirectory and Model interface; exports models: readonly Model[] built from generated-models.json merged with modelMetadata; generated-models.json populated with provider and model entries (some with canonicalSlug); model-metadata.ts provides per-model overrides.
Discovery / Generation
apps/website/scripts/generate-models.ts, apps/website/package.json
New script scans top-level workflow template JSON files for embedded models arrays, aggregates/counts template usage, maps api_*.json to partner entries via API_PROVIDER_MAP, canonicalizes quant variants and assigns canonicalSlug, and writes the combined output (default: apps/website/src/config/generated-models.json). Adds generate:models npm script.
Routing / URLs
apps/website/src/config/routes.ts
Adds baseRoutes.models = '/p/supported-models' and exports modelDetail(slug: string); locale routes now include the new models route.
Pages / SEO
apps/website/src/pages/p/supported-models/index.astro, apps/website/src/pages/p/supported-models/[slug].astro
Adds listing and dynamic detail pages; getStaticPaths generated from models; detail page redirects to canonicalSlug when present, injects JSON‑LD (SoftwareApplication, BreadcrumbList, FAQ), meta timestamps, renders hero and conditional tutorial link, and includes workflow gallery placeholders.
UI Component & Layout Slot
apps/website/src/components/models/ModelHeroSection.vue, apps/website/src/layouts/BaseLayout.astro
New ModelHeroSection Vue SFC with typed props and conditional CTAs (workflows, huggingface hidden for partners, tutorial/blog when present). BaseLayout adds a named <slot name="head" /> for injecting head content.
Localization
apps/website/src/i18n/translations.ts
Adds models translation block (hero eyebrow, CTAs, tutorial/blog labels, workflow count, "What is {name}?" section, Supported Models title/subtitle, breadcrumb labels).
Skill / Contributor Guidance
.claude/skills/add-model-page/SKILL.md
New procedural guidance for `add
Automation Workflow
.github/workflows/model-page-discovery.yaml
Scheduled/manual GitHub Actions workflow runs the generator against workflow templates, diffs discovered slugs vs existing models.ts, outputs new_count/new_slugs, and opens an issue listing newly discovered slugs when present.
Minor Wiring
apps/website/src/config/models.ts helpers
Adds exported helpers: getModelBySlug, getFeaturedModels, and getModelsByDirectory consumed by pages/components.

Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant ListingPage as "Listing Page"
    participant DetailPage as "Detail Page"
    participant Registry as "models (models.ts)"
    participant Layout as "BaseLayout"
    participant Hero as "ModelHeroSection"

    User->>Browser: Navigate to /p/supported-models
    Browser->>ListingPage: Request listing
    ListingPage->>Registry: import models array
    ListingPage->>Browser: Render grid of model cards
    User->>Browser: Click a model card
    Browser->>DetailPage: Request /p/supported-models/:slug
    DetailPage->>Registry: getModelBySlug(slug)
    DetailPage->>Layout: Render page with inline JSON-LD
    DetailPage->>Hero: Pass model props
    Hero->>Browser: Render hero + CTAs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hopped through templates, slugs in tow,
Counted workflows where new models grow.
Cards and schema, hero lit bright,
Weekly checks keep discovery in sight —
A comfy hop to cataloged glow.


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
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.
End-To-End Regression Coverage For Fixes ❓ Inconclusive Commit subjects are explicitly marked as omitted in the review context, preventing evaluation of bug-fix language and corresponding regression test requirements. Retrieve commit subject lines via git log to verify bug-fix language presence and confirm appropriate regression test coverage exists under browser_tests/.
✅ Passed checks (5 passed)
Check name Status Explanation
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 PR modifies only website-related files under apps/website/ with no changes to src/lib/litegraph/, src/ecs/, or graph entity-related code.
Title check ✅ Passed The title accurately describes the main feature: adding SEO model pages for 207 models with FAQ JSON-LD and partner node support.
Description check ✅ Passed The description is comprehensive and well-structured, covering summary, changes, test plan, and issue reference, exceeding template requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch glary/seo-model-pages

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🌐 Website E2E

Tip

All tests passed.

Status ✅ Passed
Report View Report

🔗 Website Preview

Website Preview: https://comfy-website-preview-pr-11892.vercel.app

This commit: https://website-frontend-j2nxtay6m-comfyui.vercel.app

Last updated: 2026-05-04T23:57:51Z for b0986f1

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🎭 Playwright: ✅ 1485 passed, 0 failed

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

📦 Bundle: 5.26 MB gzip 🟢 -402 B

Details

Summary

  • Raw size: 24.2 MB baseline 24.2 MB — 🟢 -1.37 kB
  • Gzip: 5.26 MB baseline 5.26 MB — 🟢 -402 B
  • Brotli: 4.07 MB baseline 4.07 MB — 🟢 -303 B
  • Bundles: 259 current • 259 baseline • 118 added / 118 removed

Category Glance
Other 🟢 -1.37 kB (8.82 MB) · Vendor & Third-Party ⚪ 0 B (9.94 MB) · Data & Services ⚪ 0 B (3.05 MB) · Graph Workspace ⚪ 0 B (1.24 MB) · Panels & Settings ⚪ 0 B (489 kB) · Utilities & Hooks ⚪ 0 B (365 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BJW8hS1P.js (removed) 22.6 kB 🟢 -22.6 kB 🟢 -8.01 kB 🟢 -6.87 kB
assets/index-DHvG302d.js (new) 22.6 kB 🔴 +22.6 kB 🔴 +8.01 kB 🔴 +6.89 kB

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-Bzw7IZ90.js (new) 1.24 MB 🔴 +1.24 MB 🔴 +265 kB 🔴 +199 kB
assets/GraphView-fWny1Ijk.js (removed) 1.24 MB 🟢 -1.24 MB 🟢 -265 kB 🟢 -199 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-Ie2cRhVa.js (new) 19.6 kB 🔴 +19.6 kB 🔴 +5.14 kB 🔴 +4.57 kB
assets/CloudSurveyView-Zul1WPgY.js (removed) 19.6 kB 🟢 -19.6 kB 🟢 -5.14 kB 🟢 -4.58 kB
assets/CloudLoginView-CQ9rJe2N.js (removed) 12.4 kB 🟢 -12.4 kB 🟢 -3.51 kB 🟢 -3.1 kB
assets/CloudLoginView-ESeCQq9G.js (new) 12.4 kB 🔴 +12.4 kB 🔴 +3.51 kB 🔴 +3.11 kB
assets/CloudSignupView-CscfXn5B.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +3 kB 🔴 +2.65 kB
assets/CloudSignupView-Dxem97WC.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -3 kB 🟢 -2.64 kB
assets/UserCheckView-Cmvsgnnn.js (new) 9.07 kB 🔴 +9.07 kB 🔴 +2.33 kB 🔴 +2.08 kB
assets/UserCheckView-D4ujwD2_.js (removed) 9.07 kB 🟢 -9.07 kB 🟢 -2.33 kB 🟢 -2.04 kB
assets/CloudLayoutView-BXhryAWs.js (removed) 7.73 kB 🟢 -7.73 kB 🟢 -2.45 kB 🟢 -2.14 kB
assets/CloudLayoutView-CVOAkwDL.js (new) 7.73 kB 🔴 +7.73 kB 🔴 +2.45 kB 🔴 +2.15 kB
assets/CloudForgotPasswordView-CK4QxP5Q.js (new) 6.14 kB 🔴 +6.14 kB 🔴 +2.18 kB 🔴 +1.91 kB
assets/CloudForgotPasswordView-Cwxzieef.js (removed) 6.14 kB 🟢 -6.14 kB 🟢 -2.18 kB 🟢 -1.93 kB
assets/CloudAuthTimeoutView-BdsxjNzS.js (removed) 5.5 kB 🟢 -5.5 kB 🟢 -2.01 kB 🟢 -1.77 kB
assets/CloudAuthTimeoutView-Dl5twlMn.js (new) 5.5 kB 🔴 +5.5 kB 🔴 +2.01 kB 🔴 +1.77 kB
assets/CloudSubscriptionRedirectView-BGVqBk2r.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +2 kB 🔴 +1.77 kB
assets/CloudSubscriptionRedirectView-WJ32Bwmw.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -2 kB 🟢 -1.77 kB
assets/UserSelectView-ClRqiuDy.js (new) 4.73 kB 🔴 +4.73 kB 🔴 +1.75 kB 🔴 +1.56 kB
assets/UserSelectView-DhFIHblG.js (removed) 4.73 kB 🟢 -4.73 kB 🟢 -1.75 kB 🟢 -1.55 kB

Status: 9 added / 9 removed / 2 unchanged

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-D6TgcqYh.js (new) 46.7 kB 🔴 +46.7 kB 🔴 +9.62 kB 🔴 +8.56 kB
assets/KeybindingPanel-DY-D8Q-x.js (removed) 46.7 kB 🟢 -46.7 kB 🟢 -9.62 kB 🟢 -8.55 kB
assets/SecretsPanel-BSv7puwf.js (new) 22.9 kB 🔴 +22.9 kB 🔴 +5.55 kB 🔴 +4.87 kB
assets/SecretsPanel-qnis18c9.js (removed) 22.9 kB 🟢 -22.9 kB 🟢 -5.54 kB 🟢 -4.88 kB
assets/LegacyCreditsPanel-CFlTgJrJ.js (removed) 21.7 kB 🟢 -21.7 kB 🟢 -5.91 kB 🟢 -5.21 kB
assets/LegacyCreditsPanel-VeVyA7mk.js (new) 21.7 kB 🔴 +21.7 kB 🔴 +5.91 kB 🔴 +5.2 kB
assets/SubscriptionPanel-D03eZcCL.js (new) 20 kB 🔴 +20 kB 🔴 +5.11 kB 🔴 +4.5 kB
assets/SubscriptionPanel-Df4bsz72.js (removed) 20 kB 🟢 -20 kB 🟢 -5.11 kB 🟢 -4.49 kB
assets/AboutPanel-BpW2hhRj.js (removed) 12 kB 🟢 -12 kB 🟢 -3.32 kB 🟢 -2.98 kB
assets/AboutPanel-DYEkRLDS.js (new) 12 kB 🔴 +12 kB 🔴 +3.33 kB 🔴 +2.98 kB
assets/ExtensionPanel-D2kmcZDk.js (removed) 9.97 kB 🟢 -9.97 kB 🟢 -2.91 kB 🟢 -2.6 kB
assets/ExtensionPanel-NSNPz4Ch.js (new) 9.97 kB 🔴 +9.97 kB 🔴 +2.91 kB 🔴 +2.59 kB
assets/ServerConfigPanel-BUiVi6wR.js (removed) 7.05 kB 🟢 -7.05 kB 🟢 -2.36 kB 🟢 -2.11 kB
assets/ServerConfigPanel-D5rvuoWQ.js (new) 7.05 kB 🔴 +7.05 kB 🔴 +2.36 kB 🔴 +2.12 kB
assets/UserPanel-BUtgfyiW.js (removed) 6.75 kB 🟢 -6.75 kB 🟢 -2.24 kB 🟢 -1.99 kB
assets/UserPanel-C450bafL.js (new) 6.75 kB 🔴 +6.75 kB 🔴 +2.24 kB 🔴 +1.96 kB
assets/cloudRemoteConfig-Cg9hr6vJ.js (removed) 2.05 kB 🟢 -2.05 kB 🟢 -987 B 🟢 -849 B
assets/cloudRemoteConfig-DZDt35nm.js (new) 2.05 kB 🔴 +2.05 kB 🔴 +989 B 🔴 +847 B
assets/refreshRemoteConfig-E5yWGfoM.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +650 B 🔴 +557 B
assets/refreshRemoteConfig-KyctkuJX.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -649 B 🟢 -552 B

Status: 10 added / 10 removed / 11 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-_G1NTJzf.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.29 kB 🟢 -1.1 kB
assets/auth-Bh3BmaRr.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.29 kB 🔴 +1.1 kB
assets/SignUpForm-6UK6Hq75.js (removed) 3.19 kB 🟢 -3.19 kB 🟢 -1.29 kB 🟢 -1.15 kB
assets/SignUpForm-BHybSbEI.js (new) 3.19 kB 🔴 +3.19 kB 🔴 +1.29 kB 🔴 +1.15 kB
assets/UpdatePasswordContent-Cv0gXoKv.js (removed) 2.9 kB 🟢 -2.9 kB 🟢 -1.3 kB 🟢 -1.17 kB
assets/UpdatePasswordContent-Df9gN8mS.js (new) 2.9 kB 🔴 +2.9 kB 🔴 +1.3 kB 🔴 +1.16 kB
assets/authStore-CEul34uD.js (new) 1.19 kB 🔴 +1.19 kB 🔴 +568 B 🔴 +506 B
assets/authStore-oImR3LEO.js (removed) 1.19 kB 🟢 -1.19 kB 🟢 -567 B 🟢 -509 B
assets/auth-CZnuEIFc.js (removed) 348 B 🟢 -348 B 🟢 -216 B 🟢 -190 B
assets/auth-DYdt5wpj.js (new) 348 B 🔴 +348 B 🔴 +214 B 🔴 +186 B

Status: 5 added / 5 removed / 2 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-C16lJxA4.js (removed) 85.8 kB 🟢 -85.8 kB 🟢 -18.6 kB 🟢 -15.9 kB
assets/ComfyHubPublishDialog-CHOVkFm3.js (new) 85.8 kB 🔴 +85.8 kB 🔴 +18.6 kB 🔴 +15.9 kB
assets/useShareDialog-D6jk1gXj.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.78 kB 🟢 -5.12 kB
assets/useShareDialog-OVVEBj31.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.78 kB 🔴 +5.12 kB
assets/ComfyHubPublishDialog-CIqrOKaE.js (removed) 1.35 kB 🟢 -1.35 kB 🟢 -626 B 🟢 -561 B
assets/ComfyHubPublishDialog-Dc3Ilyd6.js (new) 1.35 kB 🔴 +1.35 kB 🔴 +625 B 🔴 +548 B
assets/useSubscriptionDialog-CkAs9Fdj.js (removed) 1.17 kB 🟢 -1.17 kB 🟢 -556 B 🟢 -491 B
assets/useSubscriptionDialog-DgZThLsm.js (new) 1.17 kB 🔴 +1.17 kB 🔴 +557 B 🔴 +486 B

Status: 4 added / 4 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-B8Iw6FP-.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.79 kB 🟢 -3.38 kB
assets/ComfyQueueButton-BuilHQST.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.79 kB 🔴 +3.38 kB
assets/useTerminalTabs-B2oesPfm.js (removed) 11 kB 🟢 -11 kB 🟢 -3.73 kB 🟢 -3.28 kB
assets/useTerminalTabs-CaQXj-hF.js (new) 11 kB 🔴 +11 kB 🔴 +3.73 kB 🔴 +3.28 kB
assets/SubscribeButton-ASYXT1dv.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.05 kB 🔴 +926 B
assets/SubscribeButton-DA_-vaoU.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -919 B
assets/cloudFeedbackTopbarButton-8LH0s7rX.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -943 B 🟢 -831 B
assets/cloudFeedbackTopbarButton-a3Zs5ndd.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +943 B 🔴 +829 B
assets/ComfyQueueButton-DHeq0wl2.js (new) 1.27 kB 🔴 +1.27 kB 🔴 +592 B 🔴 +523 B
assets/ComfyQueueButton-DQkpbJsd.js (removed) 1.27 kB 🟢 -1.27 kB 🟢 -593 B 🟢 -525 B

Status: 5 added / 5 removed / 9 unchanged

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

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-BoHhLS_u.js (removed) 1.99 MB 🟢 -1.99 MB 🟢 -458 kB 🟢 -347 kB
assets/dialogService-Cv6OTr4E.js (new) 1.99 MB 🔴 +1.99 MB 🔴 +458 kB 🔴 +347 kB
assets/api-BbVmQrDO.js (new) 887 kB 🔴 +887 kB 🔴 +212 kB 🔴 +167 kB
assets/api-XadDQ6LM.js (removed) 887 kB 🟢 -887 kB 🟢 -212 kB 🟢 -167 kB
assets/load3dService-CK5BsTVY.js (new) 115 kB 🔴 +115 kB 🔴 +25.1 kB 🔴 +21.3 kB
assets/load3dService-q8KUkQNC.js (removed) 115 kB 🟢 -115 kB 🟢 -25.1 kB 🟢 -21.3 kB
assets/workflowShareService-46YayUwA.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.89 kB 🟢 -4.35 kB
assets/workflowShareService-CxuqzGcY.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.89 kB 🔴 +4.33 kB
assets/keybindingService-B_pyOouO.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.67 kB 🟢 -3.21 kB
assets/keybindingService-D0O5etyt.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.22 kB
assets/releaseStore-FsHmJSiw.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.28 kB 🟢 -2 kB
assets/releaseStore-kGulENoH.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.28 kB 🔴 +2 kB
assets/userStore-BfvL68FU.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +870 B 🔴 +762 B
assets/userStore-DeK_l9-g.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -870 B 🟢 -761 B
assets/audioService-C--00yTi.js (new) 1.8 kB 🔴 +1.8 kB 🔴 +875 B 🔴 +758 B
assets/audioService-DRcDSv5X.js (removed) 1.8 kB 🟢 -1.8 kB 🟢 -877 B 🟢 -764 B
assets/releaseStore-4hUhsfUY.js (removed) 1.19 kB 🟢 -1.19 kB 🟢 -561 B 🟢 -501 B
assets/releaseStore-Dowqn3Fv.js (new) 1.19 kB 🔴 +1.19 kB 🔴 +559 B 🔴 +499 B
assets/workflowDraftStore-DnC_R0jb.js (removed) 1.17 kB 🟢 -1.17 kB 🟢 -554 B 🟢 -494 B
assets/workflowDraftStore-Dp7_mK_X.js (new) 1.17 kB 🔴 +1.17 kB 🔴 +555 B 🔴 +493 B
assets/dialogService-B5uHNeBl.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -547 B 🟢 -491 B
assets/dialogService-YtZsOp1s.js (new) 1.16 kB 🔴 +1.16 kB 🔴 +548 B 🔴 +488 B
assets/settingStore-6gQxlFrs.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +550 B 🔴 +487 B
assets/settingStore-Dwy_GFJN.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -549 B 🟢 -491 B
assets/assetsStore-D1dE8OZt.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +551 B 🔴 +488 B
assets/assetsStore-S5R7mvs6.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -550 B 🟢 -490 B

Status: 13 added / 13 removed / 4 unchanged

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-Dt5FSMrs.js (new) 233 kB 🔴 +233 kB 🔴 +51.8 kB 🔴 +42.2 kB
assets/useConflictDetection-vYN8N4gN.js (removed) 233 kB 🟢 -233 kB 🟢 -51.8 kB 🟢 -42.3 kB
assets/useLoad3d-CTvOah9t.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.09 kB 🟢 -4.49 kB
assets/useLoad3d-D9x9frAe.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.09 kB 🔴 +4.5 kB
assets/useLoad3dViewer-CC9NkR13.js (removed) 20.8 kB 🟢 -20.8 kB 🟢 -4.91 kB 🟢 -4.3 kB
assets/useLoad3dViewer-CjusSzSJ.js (new) 20.8 kB 🔴 +20.8 kB 🔴 +4.91 kB 🔴 +4.3 kB
assets/useFeatureFlags-B883ynNi.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +1.8 kB 🔴 +1.52 kB
assets/useFeatureFlags-D2JDBnDU.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -1.79 kB 🟢 -1.53 kB
assets/useCopyToClipboard-DApDZOUl.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/useCopyToClipboard-n3hngcVH.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/useWorkspaceUI-BSwCA1gX.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +981 B 🔴 +814 B
assets/useWorkspaceUI-CmoN7G_q.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -982 B 🟢 -813 B
assets/subscriptionCheckoutUtil-Clb7yF3x.js (new) 3.31 kB 🔴 +3.31 kB 🔴 +1.36 kB 🔴 +1.19 kB
assets/subscriptionCheckoutUtil-CZ2YDmrQ.js (removed) 3.31 kB 🟢 -3.31 kB 🟢 -1.36 kB 🟢 -1.19 kB
assets/assetPreviewUtil-D-teivVQ.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +956 B 🔴 +837 B
assets/assetPreviewUtil-FG5yhBp9.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -958 B 🟢 -838 B
assets/useUpstreamValue-B1ZMCNMx.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +805 B 🔴 +715 B
assets/useUpstreamValue-CwCf5ztr.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -804 B 🟢 -713 B
assets/useLoad3d-Dy0StuIr.js (new) 1.33 kB 🔴 +1.33 kB 🔴 +616 B 🔴 +551 B
assets/useLoad3d-SZFJx15x.js (removed) 1.33 kB 🟢 -1.33 kB 🟢 -620 B 🟢 -565 B
assets/useLoad3dViewer-o4CX3sex.js (removed) 1.27 kB 🟢 -1.27 kB 🟢 -586 B 🟢 -525 B
assets/useLoad3dViewer-XHzc376T.js (new) 1.27 kB 🔴 +1.27 kB 🔴 +585 B 🔴 +522 B
assets/useCurrentUser-Bdg9mOKK.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -551 B 🟢 -487 B
assets/useCurrentUser-k1KekBhn.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +551 B 🔴 +486 B
assets/useWorkspaceSwitch-BjgBC6K1.js (new) 747 B 🔴 +747 B 🔴 +383 B 🔴 +331 B
assets/useWorkspaceSwitch-CiCEnAOT.js (removed) 747 B 🟢 -747 B 🟢 -387 B 🟢 -334 B

Status: 13 added / 13 removed / 18 unchanged

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

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 8.82 MB (baseline 8.82 MB) • 🟢 -1.37 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-Bxo6zAB6.js (new) 76.7 kB 🔴 +76.7 kB 🔴 +19.9 kB 🔴 +16.9 kB
assets/core-DDJcb3n5.js (removed) 76.7 kB 🟢 -76.7 kB 🟢 -19.9 kB 🟢 -16.9 kB
assets/groupNode-Cg5naHut.js (removed) 74.9 kB 🟢 -74.9 kB 🟢 -18.7 kB 🟢 -16.5 kB
assets/groupNode-CsSAC2-b.js (new) 74.9 kB 🔴 +74.9 kB 🔴 +18.7 kB 🔴 +16.5 kB
assets/WidgetSelect-CHuYP8yN.js (removed) 67.4 kB 🟢 -67.4 kB 🟢 -14.6 kB 🟢 -12.7 kB
assets/WidgetSelect-CsRMYwXB.js (new) 67.4 kB 🔴 +67.4 kB 🔴 +14.6 kB 🔴 +12.7 kB
assets/SubscriptionRequiredDialogContentWorkspace-7ytnwvrZ.js (new) 48.8 kB 🔴 +48.8 kB 🔴 +9.52 kB 🔴 +8.2 kB
assets/SubscriptionRequiredDialogContentWorkspace-CTnL8jRd.js (removed) 48.8 kB 🟢 -48.8 kB 🟢 -9.52 kB 🟢 -8.22 kB
assets/Load3DControls-BF5pwVwr.js (removed) 46.1 kB 🟢 -46.1 kB 🟢 -7.51 kB 🟢 -6.55 kB
assets/Load3DControls-C_jBc-Af.js (new) 46.1 kB 🔴 +46.1 kB 🔴 +7.51 kB 🔴 +6.55 kB
assets/WorkspacePanelContent-BsTRfsph.js (removed) 34.2 kB 🟢 -34.2 kB 🟢 -7.41 kB 🟢 -6.57 kB
assets/WidgetPainter-BB93jMQz.js (removed) 34 kB 🟢 -34 kB 🟢 -8.3 kB 🟢 -7.34 kB
assets/WidgetPainter-oPwQRrlz.js (new) 34 kB 🔴 +34 kB 🔴 +8.3 kB 🔴 +7.36 kB
assets/WorkspacePanelContent-BpSJpkxe.js (new) 32.8 kB 🔴 +32.8 kB 🔴 +7.01 kB 🔴 +6.19 kB
assets/Load3dViewerContent-BtQtRRqR.js (removed) 28 kB 🟢 -28 kB 🟢 -5.85 kB 🟢 -5.07 kB
assets/Load3dViewerContent-CbyD4jHH.js (new) 28 kB 🔴 +28 kB 🔴 +5.85 kB 🔴 +5.08 kB
assets/SubscriptionRequiredDialogContent-BnZF6sQz.js (new) 27.5 kB 🔴 +27.5 kB 🔴 +6.98 kB 🔴 +6.17 kB
assets/SubscriptionRequiredDialogContent-BWTNZ-4T.js (removed) 27.5 kB 🟢 -27.5 kB 🟢 -6.98 kB 🟢 -6.15 kB
assets/WidgetImageCrop-BDG5wjML.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +6.2 kB 🔴 +5.45 kB
assets/WidgetImageCrop-Caal9EOF.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -6.2 kB 🟢 -5.45 kB
assets/SubscriptionPanelContentWorkspace-TxdsFRND.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.18 kB 🟢 -4.56 kB
assets/SubscriptionPanelContentWorkspace-WFsemfp5.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.57 kB
assets/SignInContent-C4-k9MOQ.js (removed) 20.8 kB 🟢 -20.8 kB 🟢 -5.43 kB 🟢 -4.75 kB
assets/SignInContent-DuxiS3ez.js (new) 20.8 kB 🔴 +20.8 kB 🔴 +5.44 kB 🔴 +4.76 kB
assets/CurrentUserPopoverWorkspace-Cml2fSRp.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -4.91 kB 🟢 -4.41 kB
assets/CurrentUserPopoverWorkspace-DtZV6hmG.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +4.91 kB 🔴 +4.39 kB
assets/WidgetInputNumber-BgHXts2o.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.29 kB
assets/WidgetInputNumber-COdJ6dx9.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.84 kB 🟢 -4.29 kB
assets/Load3D-lkHpgB7-.js (new) 18.5 kB 🔴 +18.5 kB 🔴 +4.39 kB 🔴 +3.83 kB
assets/Load3D-X5m7LTl1.js (removed) 18.5 kB 🟢 -18.5 kB 🟢 -4.39 kB 🟢 -3.83 kB
assets/WidgetRecordAudio-B2nVA2d5.js (removed) 17.5 kB 🟢 -17.5 kB 🟢 -5.04 kB 🟢 -4.5 kB
assets/WidgetRecordAudio-bgiSysY4.js (new) 17.5 kB 🔴 +17.5 kB 🔴 +5.04 kB 🔴 +4.51 kB
assets/WidgetRange-CsW53G_R.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.61 kB 🔴 +4.14 kB
assets/WidgetRange-DMJZbgqM.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.61 kB 🟢 -4.12 kB
assets/load3d-BOoYwSc3.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -4.59 kB 🟢 -3.98 kB
assets/load3d-uyfCqR8d.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +4.59 kB 🔴 +3.98 kB
assets/WaveAudioPlayer-BSSpXDay.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.69 kB 🟢 -3.23 kB
assets/WaveAudioPlayer-C3a5Qjan.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.69 kB 🔴 +3.23 kB
assets/WidgetCurve-B6zoSqnm.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -3.93 kB 🟢 -3.57 kB
assets/WidgetCurve-DD5quQgi.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +3.93 kB 🔴 +3.56 kB
assets/TeamWorkspacesDialogContent-DhZBZY3c.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.42 kB 🔴 +3.05 kB
assets/TeamWorkspacesDialogContent-DQSLjj_X.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.42 kB 🟢 -3.05 kB
assets/nodeTemplates-BhuekQwH.js (removed) 9.84 kB 🟢 -9.84 kB 🟢 -3.48 kB 🟢 -3.07 kB
assets/nodeTemplates-DN_m2JP0.js (new) 9.84 kB 🔴 +9.84 kB 🔴 +3.48 kB 🔴 +3.07 kB
assets/NightlySurveyController-Bh-6ifia.js (new) 8.97 kB 🔴 +8.97 kB 🔴 +3.15 kB 🔴 +2.79 kB
assets/NightlySurveyController-DAfLKo9x.js (removed) 8.97 kB 🟢 -8.97 kB 🟢 -3.15 kB 🟢 -2.78 kB
assets/Load3DConfiguration-BPytn5Jm.js (new) 8.61 kB 🔴 +8.61 kB 🔴 +2.54 kB 🔴 +2.23 kB
assets/Load3DConfiguration-C369NCXz.js (removed) 8.61 kB 🟢 -8.61 kB 🟢 -2.54 kB 🟢 -2.23 kB
assets/InviteMemberDialogContent-BJ9vyQ78.js (removed) 7.94 kB 🟢 -7.94 kB 🟢 -2.53 kB 🟢 -2.2 kB
assets/InviteMemberDialogContent-D9hwEWhm.js (new) 7.94 kB 🔴 +7.94 kB 🔴 +2.53 kB 🔴 +2.22 kB
assets/onboardingCloudRoutes-Bh8nsc_V.js (removed) 6.73 kB 🟢 -6.73 kB 🟢 -2.12 kB 🟢 -1.83 kB
assets/onboardingCloudRoutes-CYoFgDY7.js (new) 6.73 kB 🔴 +6.73 kB 🔴 +2.12 kB 🔴 +1.82 kB
assets/CreateWorkspaceDialogContent-Bf1z-Aal.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -2.24 kB 🟢 -1.96 kB
assets/CreateWorkspaceDialogContent-Cn1oVIHe.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +2.24 kB 🔴 +1.95 kB
assets/WidgetWithControl-CZDR7XPD.js (removed) 6.09 kB 🟢 -6.09 kB 🟢 -2.45 kB 🟢 -2.19 kB
assets/WidgetWithControl-hHMMGpWG.js (new) 6.09 kB 🔴 +6.09 kB 🔴 +2.45 kB 🔴 +2.19 kB
assets/FreeTierDialogContent-B0h_-Cr-.js (new) 6.01 kB 🔴 +6.01 kB 🔴 +2.13 kB 🔴 +1.9 kB
assets/FreeTierDialogContent-ByPmBDEh.js (removed) 6.01 kB 🟢 -6.01 kB 🟢 -2.13 kB 🟢 -1.9 kB
assets/EditWorkspaceDialogContent-CQdZRM2q.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +2.2 kB 🔴 +1.93 kB
assets/EditWorkspaceDialogContent-DNFdI8Sw.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -2.2 kB 🟢 -1.92 kB
assets/WidgetTextarea-BRgesFoO.js (removed) 5.76 kB 🟢 -5.76 kB 🟢 -2.27 kB 🟢 -1.99 kB
assets/WidgetTextarea-kExuTPcG.js (new) 5.76 kB 🔴 +5.76 kB 🔴 +2.27 kB 🔴 +2.01 kB
assets/Preview3d-B8hPAzsD.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.92 kB 🔴 +1.67 kB
assets/Preview3d-DCqQS_no.js (removed) 5.73 kB 🟢 -5.73 kB 🟢 -1.92 kB 🟢 -1.69 kB
assets/ValueControlPopover-BCMBGPWa.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +2.01 kB 🔴 +1.81 kB
assets/ValueControlPopover-BlPI0ShA.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -2.01 kB 🟢 -1.81 kB
assets/CancelSubscriptionDialogContent-OepxJGpu.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -2.06 kB 🟢 -1.81 kB
assets/CancelSubscriptionDialogContent-oJ0aMClK.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +2.06 kB 🔴 +1.8 kB
assets/DeleteWorkspaceDialogContent-CddvWcmN.js (removed) 4.85 kB 🟢 -4.85 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/DeleteWorkspaceDialogContent-Jp5kr41_.js (new) 4.85 kB 🔴 +4.85 kB 🔴 +1.88 kB 🔴 +1.63 kB
assets/LeaveWorkspaceDialogContent-0SGqPe0Y.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.82 kB 🔴 +1.59 kB
assets/LeaveWorkspaceDialogContent-BetIj65F.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/RemoveMemberDialogContent-cqlxOZuH.js (new) 4.66 kB 🔴 +4.66 kB 🔴 +1.77 kB 🔴 +1.56 kB
assets/RemoveMemberDialogContent-Jhqi5krj.js (removed) 4.66 kB 🟢 -4.66 kB 🟢 -1.77 kB 🟢 -1.55 kB
assets/RevokeInviteDialogContent-B9mjWHIN.js (new) 4.57 kB 🔴 +4.57 kB 🔴 +1.78 kB 🔴 +1.57 kB
assets/RevokeInviteDialogContent-C5XkUCmm.js (removed) 4.57 kB 🟢 -4.57 kB 🟢 -1.78 kB 🟢 -1.56 kB
assets/InviteMemberUpsellDialogContent-CUX6HkAR.js (new) 4.47 kB 🔴 +4.47 kB 🔴 +1.65 kB 🔴 +1.45 kB
assets/InviteMemberUpsellDialogContent-DbWDl2Gc.js (removed) 4.47 kB 🟢 -4.47 kB 🟢 -1.65 kB 🟢 -1.45 kB
assets/tierBenefits-BR0kPEsT.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.58 kB 🔴 +1.36 kB
assets/tierBenefits-wXHmgABm.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.57 kB 🟢 -1.36 kB
assets/cloudSessionCookie-FPJCUduK.js (removed) 4.31 kB 🟢 -4.31 kB 🟢 -1.57 kB 🟢 -1.37 kB
assets/cloudSessionCookie-ORKqsL1w.js (new) 4.31 kB 🔴 +4.31 kB 🔴 +1.58 kB 🔴 +1.38 kB
assets/Media3DTop-B7KlqHI7.js (removed) 4.04 kB 🟢 -4.04 kB 🟢 -1.71 kB 🟢 -1.5 kB
assets/Media3DTop-B8nTvSqj.js (new) 4.04 kB 🔴 +4.04 kB 🔴 +1.71 kB 🔴 +1.5 kB
assets/saveMesh-DRI2dwKi.js (new) 4.03 kB 🔴 +4.03 kB 🔴 +1.76 kB 🔴 +1.55 kB
assets/saveMesh-DUeVk7yU.js (removed) 4.03 kB 🟢 -4.03 kB 🟢 -1.76 kB 🟢 -1.56 kB
assets/GlobalToast-BuvaaL5D.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/GlobalToast-gK3ZJTdx.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/CloudRunButtonWrapper-BR9W3vPV.js (removed) 2.23 kB 🟢 -2.23 kB 🟢 -1.02 kB 🟢 -909 B
assets/CloudRunButtonWrapper-iEINvrwR.js (new) 2.23 kB 🔴 +2.23 kB 🔴 +1.01 kB 🔴 +910 B
assets/SubscribeToRun-D58wAnJT.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +983 B 🔴 +887 B
assets/SubscribeToRun-Dr9MF7C9.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -982 B 🟢 -866 B
assets/MediaAudioTop-C_V-WFm8.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -1.01 kB 🟢 -856 B
assets/MediaAudioTop-DV4q36Gb.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +1.01 kB 🔴 +864 B
assets/cloudBadges-Dw8pkzJ0.js (new) 1.96 kB 🔴 +1.96 kB 🔴 +977 B 🔴 +849 B
assets/cloudBadges-msi_jELG.js (removed) 1.96 kB 🟢 -1.96 kB 🟢 -976 B 🟢 -850 B
assets/cloudSubscription-B5iQsMXa.js (removed) 1.88 kB 🟢 -1.88 kB 🟢 -896 B 🟢 -779 B
assets/cloudSubscription-BaSGJS60.js (new) 1.88 kB 🔴 +1.88 kB 🔴 +897 B 🔴 +781 B
assets/graphHasMissingNodes-BdYZ441o.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -861 B 🟢 -760 B
assets/graphHasMissingNodes-CHoDvALl.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +861 B 🔴 +759 B
assets/Load3D-D5pB4aU-.js (new) 1.58 kB 🔴 +1.58 kB 🔴 +706 B 🔴 +626 B
assets/Load3D-DMumHBD7.js (removed) 1.58 kB 🟢 -1.58 kB 🟢 -711 B 🟢 -630 B
assets/previousFullPath-C3PM4SW1.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +695 B 🔴 +599 B
assets/previousFullPath-CLM9bK_0.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -695 B 🟢 -595 B
assets/nightlyBadges-CKH2Yz8R.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -743 B 🟢 -650 B
assets/nightlyBadges-TBHQE6Xl.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +741 B 🔴 +674 B
assets/Load3dViewerContent-BFMdR_qi.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +662 B 🔴 +600 B
assets/Load3dViewerContent-CFGRHCU9.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -662 B 🟢 -591 B
assets/SubscriptionPanelContentWorkspace-BAAV8xO_.js (new) 1.35 kB 🔴 +1.35 kB 🔴 +616 B 🔴 +532 B
assets/SubscriptionPanelContentWorkspace-DE_kFnMV.js (removed) 1.35 kB 🟢 -1.35 kB 🟢 -615 B 🟢 -538 B
assets/WidgetLegacy-BTHTrpT2.js (removed) 1.18 kB 🟢 -1.18 kB 🟢 -563 B 🟢 -494 B
assets/WidgetLegacy-DnXljcBE.js (new) 1.18 kB 🔴 +1.18 kB 🔴 +563 B 🔴 +493 B
assets/changeTracker-CqAkWcGH.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +551 B 🔴 +484 B
assets/changeTracker-TtUZ-Eq3.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -550 B 🟢 -485 B

Status: 57 added / 57 removed / 79 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.1 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 49.4 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 46.7 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.4 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.0 MB heap
large-graph-pan: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.6 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.9 MB heap
minimap-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.5 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.9 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.4 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.6 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.4 MB heap
vue-large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 164.5 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 157.5 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.7 MB heap

No regressions detected.

All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.9
canvas-idle: p95 frame time 17ms 17ms +1%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 8ms 6ms -30% z=-5.6
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 8 9 +13% z=-3.8
canvas-idle: task duration 378ms 315ms -16% z=-2.5
canvas-idle: script duration 19ms 14ms -22% z=-4.9
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 68.4 MB 68.1 MB -0%
canvas-idle: DOM nodes 16 17 +6% z=-4.4
canvas-idle: event listeners 4 6 +50% z=-1.2
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +0%
canvas-mouse-sweep: layout duration 4ms 3ms -12% z=-2.4
canvas-mouse-sweep: style recalc duration 38ms 31ms -18% z=-3.7
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 74 72 -3% z=-2.8
canvas-mouse-sweep: task duration 857ms 625ms -27% z=-4.1
canvas-mouse-sweep: script duration 130ms 99ms -24% z=-5.6
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 46.5 MB 49.4 MB +6%
canvas-mouse-sweep: DOM nodes -264 -260 -2% z=-124.6
canvas-mouse-sweep: event listeners -133 -129 -3% z=-33.0
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 1ms 1ms +8% z=-0.5
canvas-zoom-sweep: style recalc duration 20ms 14ms -26% z=-3.0
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 31 +0% z=-0.6
canvas-zoom-sweep: task duration 329ms 247ms -25% z=-3.5
canvas-zoom-sweep: script duration 25ms 18ms -26% z=-3.0
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 46.6 MB 46.7 MB +0%
canvas-zoom-sweep: DOM nodes 76 77 +1% z=-2.8
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
dom-widget-clipping: p95 frame time 17ms 17ms +0%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 6ms 9ms +56% z=-0.6
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 9 12 +33% z=-2.2
dom-widget-clipping: task duration 337ms 299ms -11% z=-4.0
dom-widget-clipping: script duration 59ms 54ms -8% z=-4.3
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 54.8 MB 54.4 MB -1%
dom-widget-clipping: DOM nodes 14 20 +43% z=-1.5
dom-widget-clipping: event listeners 0 2 variance too high
large-graph-idle: avg frame time 17ms 17ms -0% z=-1.0
large-graph-idle: p95 frame time 17ms 17ms -1%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 9ms 8ms -6% z=-3.6
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 9 10 +11% z=-5.1
large-graph-idle: task duration 609ms 508ms -17% z=-0.6
large-graph-idle: script duration 104ms 81ms -22% z=-2.1
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 59.3 MB 58.0 MB -2%
large-graph-idle: DOM nodes -263 -259 -2% z=-313.9
large-graph-idle: event listeners -129 -127 -2% z=-25.1
large-graph-pan: avg frame time 17ms 17ms +0% z=1.3
large-graph-pan: p95 frame time 17ms 17ms +0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 18ms 17ms -6% z=-0.1
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 68 69 +1% z=-0.9
large-graph-pan: task duration 1187ms 901ms -24% z=-4.2
large-graph-pan: script duration 442ms 309ms -30% z=-5.0
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 61.8 MB 62.6 MB +1%
large-graph-pan: DOM nodes -264 -258 -2% z=-167.9
large-graph-pan: event listeners -127 -129 +2% z=-161.7
large-graph-zoom: avg frame time 17ms 17ms +0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 8ms 7ms -2%
large-graph-zoom: style recalc duration 19ms 18ms -6%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 66 66 +0%
large-graph-zoom: task duration 1396ms 1124ms -20%
large-graph-zoom: script duration 511ms 404ms -21%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 74.9 MB 65.9 MB -12%
large-graph-zoom: DOM nodes -267 -263 -1%
large-graph-zoom: event listeners -127 -125 -2%
minimap-idle: avg frame time 17ms 17ms -0% z=-0.9
minimap-idle: p95 frame time 17ms 17ms -1%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 9ms 7ms -18% z=-2.9
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 8 9 +13% z=-0.8
minimap-idle: task duration 616ms 486ms -21% z=-0.9
minimap-idle: script duration 106ms 78ms -26% z=-2.0
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 61.6 MB 69.5 MB +13%
minimap-idle: DOM nodes -265 -260 -2% z=-204.1
minimap-idle: event listeners -129 -127 -2% z=-199.3
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms -1%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 11ms 11ms +2% z=-2.0
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 45 47 +4% z=-1.6
subgraph-dom-widget-clipping: task duration 365ms 293ms -20% z=-4.6
subgraph-dom-widget-clipping: script duration 123ms 100ms -19% z=-4.5
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 55.2 MB 54.9 MB -1%
subgraph-dom-widget-clipping: DOM nodes 16 20 +25% z=-1.9
subgraph-dom-widget-clipping: event listeners 6 8 +33% 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 9ms 8ms -15% z=-3.6
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 9 10 +11% z=-1.4
subgraph-idle: task duration 347ms 286ms -18% z=-2.7
subgraph-idle: script duration 15ms 13ms -10% z=-2.7
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 68.5 MB 68.4 MB -0%
subgraph-idle: DOM nodes 16 20 +25% z=-1.2
subgraph-idle: event listeners 4 6 +50% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms +0% z=0.4
subgraph-mouse-sweep: p95 frame time 17ms 17ms +1%
subgraph-mouse-sweep: layout duration 5ms 4ms -17% z=-2.4
subgraph-mouse-sweep: style recalc duration 38ms 32ms -16% z=-3.3
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 74 76 +3% z=-2.1
subgraph-mouse-sweep: task duration 693ms 562ms -19% z=-2.9
subgraph-mouse-sweep: script duration 100ms 78ms -22% z=-3.5
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 61.3 MB 60.6 MB -1%
subgraph-mouse-sweep: DOM nodes 59 63 +7% z=-1.8
subgraph-mouse-sweep: event listeners 4 4 +0% variance too high
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 53ms 51ms -3%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 249 250 +0%
viewport-pan-sweep: task duration 3838ms 3059ms -20%
viewport-pan-sweep: script duration 1289ms 1035ms -20%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 68.3 MB 66.4 MB -3%
viewport-pan-sweep: DOM nodes -263 -259 -2%
viewport-pan-sweep: event listeners -113 -113 +0%
vue-large-graph-idle: avg frame time 17ms 17ms -3%
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 12525ms 11164ms -11%
vue-large-graph-idle: script duration 634ms 520ms -18%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 163.3 MB 164.5 MB +1%
vue-large-graph-idle: DOM nodes -8331 -8331 +0%
vue-large-graph-idle: event listeners -16464 -16466 +0%
vue-large-graph-pan: avg frame time 17ms 17ms -0%
vue-large-graph-pan: p95 frame time 17ms 17ms -1%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 18ms 18ms -0%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 68 65 -4%
vue-large-graph-pan: task duration 14526ms 13046ms -10%
vue-large-graph-pan: script duration 920ms 748ms -19%
vue-large-graph-pan: TBT 0ms 0ms +0%
vue-large-graph-pan: heap used 157.7 MB 157.5 MB -0%
vue-large-graph-pan: DOM nodes -8331 -8331 +0%
vue-large-graph-pan: event listeners -16488 -16464 -0%
workflow-execution: avg frame time 17ms 17ms -0% z=-0.4
workflow-execution: p95 frame time 17ms 17ms +0%
workflow-execution: layout duration 1ms 1ms -22% z=-3.1
workflow-execution: style recalc duration 23ms 19ms -18% z=-2.5
workflow-execution: layout count 5 4 -20% z=-1.7
workflow-execution: style recalc count 15 16 +7% z=-0.9
workflow-execution: task duration 115ms 100ms -13% z=-2.2
workflow-execution: script duration 24ms 24ms -2% z=-1.9
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 52.7 MB 52.7 MB +0%
workflow-execution: DOM nodes 157 157 +0% z=-0.5
workflow-execution: event listeners 69 71 +3% z=4.4
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-05-05T00:20:21.443Z",
  "gitSha": "3d16f4ce0c5cb4079bad54bb41a56be5d3968307",
  "branch": "glary/seo-model-pages",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2003.6059999999907,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 5.542,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 294.18,
      "heapDeltaBytes": 22785616,
      "heapUsedBytes": 71419324,
      "domNodes": 17,
      "jsHeapTotalBytes": 14942208,
      "scriptDurationMs": 14.381,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2006.2920000000304,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.684999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 315.398,
      "heapDeltaBytes": 22812240,
      "heapUsedBytes": 72144588,
      "domNodes": 17,
      "jsHeapTotalBytes": 14942208,
      "scriptDurationMs": 16.314000000000004,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2014.5820000000185,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.877000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 322.52599999999995,
      "heapDeltaBytes": -5751596,
      "heapUsedBytes": 42819120,
      "domNodes": 16,
      "jsHeapTotalBytes": 14807040,
      "scriptDurationMs": 13.907000000000002,
      "eventListeners": -131,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1706.905000000006,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 31.279,
      "layouts": 12,
      "layoutDurationMs": 3.1240000000000006,
      "taskDurationMs": 652.6719999999999,
      "heapDeltaBytes": 3241100,
      "heapUsedBytes": 51842444,
      "domNodes": -261,
      "jsHeapTotalBytes": 14807040,
      "scriptDurationMs": 99.25300000000001,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1708.3569999999781,
      "styleRecalcs": 71,
      "styleRecalcDurationMs": 28.727,
      "layouts": 12,
      "layoutDurationMs": 3.1400000000000006,
      "taskDurationMs": 624.8000000000001,
      "heapDeltaBytes": -1313896,
      "heapUsedBytes": 47319504,
      "domNodes": -260,
      "jsHeapTotalBytes": 15593472,
      "scriptDurationMs": 94.886,
      "eventListeners": -131,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1704.733000000033,
      "styleRecalcs": 73,
      "styleRecalcDurationMs": 30.956999999999997,
      "layouts": 12,
      "layoutDurationMs": 3.239,
      "taskDurationMs": 621.3989999999999,
      "heapDeltaBytes": -628664,
      "heapUsedBytes": 67332352,
      "domNodes": 56,
      "jsHeapTotalBytes": 19660800,
      "scriptDurationMs": 100.697,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1723.444000000029,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 17.297,
      "layouts": 6,
      "layoutDurationMs": 0.715,
      "taskDurationMs": 279.651,
      "heapDeltaBytes": 553744,
      "heapUsedBytes": 48522504,
      "domNodes": 77,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 26.652,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1705.284000000006,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 14.364,
      "layouts": 6,
      "layoutDurationMs": 0.5289999999999999,
      "taskDurationMs": 240.355,
      "heapDeltaBytes": 67484,
      "heapUsedBytes": 48988036,
      "domNodes": 76,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 15.791,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1715.3469999999515,
      "styleRecalcs": 33,
      "styleRecalcDurationMs": 14.473,
      "layouts": 6,
      "layoutDurationMs": 0.619,
      "taskDurationMs": 246.67999999999998,
      "heapDeltaBytes": 331960,
      "heapUsedBytes": 48956592,
      "domNodes": 79,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 18.138,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 542.8180000000111,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.404,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 314.408,
      "heapDeltaBytes": 9115644,
      "heapUsedBytes": 57084856,
      "domNodes": 20,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 56.351,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 467.2610000000077,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 13.998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 298.505,
      "heapDeltaBytes": 9693740,
      "heapUsedBytes": 57327904,
      "domNodes": 21,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 53.975,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 447.17000000002827,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 7.292,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 272.894,
      "heapDeltaBytes": 9133564,
      "heapUsedBytes": 56863812,
      "domNodes": 19,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 49.696,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2019.3010000000413,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.889000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 507.93399999999997,
      "heapDeltaBytes": 15547024,
      "heapUsedBytes": 74529284,
      "domNodes": -262,
      "jsHeapTotalBytes": 4280320,
      "scriptDurationMs": 80.51799999999997,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2035.368999999946,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.901000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 442.318,
      "heapDeltaBytes": 4095828,
      "heapUsedBytes": 60790616,
      "domNodes": -259,
      "jsHeapTotalBytes": 5009408,
      "scriptDurationMs": 75.32999999999998,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2039.0149999999494,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.444999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 529.52,
      "heapDeltaBytes": 3997056,
      "heapUsedBytes": 60769308,
      "domNodes": -259,
      "jsHeapTotalBytes": 3698688,
      "scriptDurationMs": 95.69800000000001,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2099.2430000000013,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 17.809,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 912.792,
      "heapDeltaBytes": 9781876,
      "heapUsedBytes": 68812604,
      "domNodes": -257,
      "jsHeapTotalBytes": 1019904,
      "scriptDurationMs": 309.053,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2090.828999999985,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 16.933000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 900.5509999999999,
      "heapDeltaBytes": 6544088,
      "heapUsedBytes": 65683220,
      "domNodes": -258,
      "jsHeapTotalBytes": -28672,
      "scriptDurationMs": 318.169,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2073.4939999999824,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 17.220000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 868.386,
      "heapDeltaBytes": -1986476,
      "heapUsedBytes": 57294296,
      "domNodes": -262,
      "jsHeapTotalBytes": 5738496,
      "scriptDurationMs": 292.566,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3098.8739999999666,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 17.266,
      "layouts": 60,
      "layoutDurationMs": 6.957,
      "taskDurationMs": 1077.664,
      "heapDeltaBytes": 8588300,
      "heapUsedBytes": 69144000,
      "domNodes": -263,
      "jsHeapTotalBytes": 4222976,
      "scriptDurationMs": 387.473,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3093.2959999998957,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 18.225999999999996,
      "layouts": 60,
      "layoutDurationMs": 7.463000000000001,
      "taskDurationMs": 1124.557,
      "heapDeltaBytes": -9667604,
      "heapUsedBytes": 52515552,
      "domNodes": -263,
      "jsHeapTotalBytes": 4542464,
      "scriptDurationMs": 403.78400000000005,
      "eventListeners": -125,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3078.2729999999674,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 18.349000000000004,
      "layouts": 60,
      "layoutDurationMs": 7.3439999999999985,
      "taskDurationMs": 1123.586,
      "heapDeltaBytes": 18596156,
      "heapUsedBytes": 79148184,
      "domNodes": -262,
      "jsHeapTotalBytes": -495616,
      "scriptDurationMs": 407.627,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2027.9449999999883,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.220999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 531.058,
      "heapDeltaBytes": 4128632,
      "heapUsedBytes": 63508496,
      "domNodes": -263,
      "jsHeapTotalBytes": 552960,
      "scriptDurationMs": 86.019,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2037.8049999999348,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 6.777000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 434.767,
      "heapDeltaBytes": 13160332,
      "heapUsedBytes": 72865800,
      "domNodes": -260,
      "jsHeapTotalBytes": -757760,
      "scriptDurationMs": 68.477,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2017.1589999999924,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.179000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 486.324,
      "heapDeltaBytes": 13449492,
      "heapUsedBytes": 73448796,
      "domNodes": -260,
      "jsHeapTotalBytes": -233472,
      "scriptDurationMs": 78.116,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 529.389999999978,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 12.022000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 311.59000000000003,
      "heapDeltaBytes": 8837864,
      "heapUsedBytes": 57470028,
      "domNodes": 19,
      "jsHeapTotalBytes": 15990784,
      "scriptDurationMs": 104.871,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 460.2909999999838,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 10.337000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 290.591,
      "heapDeltaBytes": 9083024,
      "heapUsedBytes": 57793752,
      "domNodes": 20,
      "jsHeapTotalBytes": 16252928,
      "scriptDurationMs": 99.09,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 469.97399999997924,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 10.845,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 292.86500000000007,
      "heapDeltaBytes": 8855148,
      "heapUsedBytes": 57532420,
      "domNodes": 22,
      "jsHeapTotalBytes": 15990784,
      "scriptDurationMs": 99.504,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2007.2150000000306,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.210000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 282.62299999999993,
      "heapDeltaBytes": 23087344,
      "heapUsedBytes": 71738864,
      "domNodes": 16,
      "jsHeapTotalBytes": 15204352,
      "scriptDurationMs": 11.837,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2007.3249999999234,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.607000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 302.328,
      "heapDeltaBytes": 1021136,
      "heapUsedBytes": 67382000,
      "domNodes": 20,
      "jsHeapTotalBytes": 19755008,
      "scriptDurationMs": 15.638000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1998.613999999975,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.139999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 286.166,
      "heapDeltaBytes": 23297596,
      "heapUsedBytes": 71847096,
      "domNodes": 22,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 13.154,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1685.2439999999547,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 31.608999999999998,
      "layouts": 16,
      "layoutDurationMs": 4.031,
      "taskDurationMs": 534.1479999999999,
      "heapDeltaBytes": 14154440,
      "heapUsedBytes": 63525716,
      "domNodes": 63,
      "jsHeapTotalBytes": 14942208,
      "scriptDurationMs": 76.831,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1715.1499999999942,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 31.420999999999996,
      "layouts": 16,
      "layoutDurationMs": 3.815,
      "taskDurationMs": 586.29,
      "heapDeltaBytes": 2446328,
      "heapUsedBytes": 50719044,
      "domNodes": -259,
      "jsHeapTotalBytes": 15593472,
      "scriptDurationMs": 77.874,
      "eventListeners": -131,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.669999999999998,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1733.3629999999403,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 32.848,
      "layouts": 16,
      "layoutDurationMs": 3.9230000000000005,
      "taskDurationMs": 561.9909999999999,
      "heapDeltaBytes": 14004872,
      "heapUsedBytes": 63636036,
      "domNodes": 65,
      "jsHeapTotalBytes": 15466496,
      "scriptDurationMs": 83.71600000000001,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8131.513999999981,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 53.346000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3435.94,
      "heapDeltaBytes": 16714112,
      "heapUsedBytes": 74988256,
      "domNodes": -258,
      "jsHeapTotalBytes": 8097792,
      "scriptDurationMs": 1174.602,
      "eventListeners": -113,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8099.481999999966,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 50.698,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 2988.256,
      "heapDeltaBytes": 11426312,
      "heapUsedBytes": 69627508,
      "domNodes": -259,
      "jsHeapTotalBytes": 757760,
      "scriptDurationMs": 958.227,
      "eventListeners": -113,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8101.828000000069,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 50.817,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3059.185,
      "heapDeltaBytes": 10371956,
      "heapUsedBytes": 68495368,
      "domNodes": -260,
      "jsHeapTotalBytes": 3903488,
      "scriptDurationMs": 1035.0549999999998,
      "eventListeners": -113,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 11365.854999999954,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 11353.082,
      "heapDeltaBytes": -24498900,
      "heapUsedBytes": 172026032,
      "domNodes": -8331,
      "jsHeapTotalBytes": 23392256,
      "scriptDurationMs": 520.275,
      "eventListeners": -16466,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 11216.272000000004,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 11163.776,
      "heapDeltaBytes": -31684760,
      "heapUsedBytes": 173247724,
      "domNodes": -8331,
      "jsHeapTotalBytes": 26537984,
      "scriptDurationMs": 539.933,
      "eventListeners": -16465,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10387.022,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10381.403,
      "heapDeltaBytes": -29986612,
      "heapUsedBytes": 172443044,
      "domNodes": -8359,
      "jsHeapTotalBytes": 24440832,
      "scriptDurationMs": 456.07,
      "eventListeners": -16468,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 13176.326000000017,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 17.904000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13144.224000000002,
      "heapDeltaBytes": -23750924,
      "heapUsedBytes": 177130836,
      "domNodes": -8331,
      "jsHeapTotalBytes": -20471808,
      "scriptDurationMs": 735.901,
      "eventListeners": -16460,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 13061.495000000035,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 17.733999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13045.516,
      "heapDeltaBytes": -46915840,
      "heapUsedBytes": 164999056,
      "domNodes": -8331,
      "jsHeapTotalBytes": -5181440,
      "scriptDurationMs": 778.866,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 42,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 12654.421999999955,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 16.351000000000006,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12637.623999999998,
      "heapDeltaBytes": -33476780,
      "heapUsedBytes": 165176676,
      "domNodes": -8331,
      "jsHeapTotalBytes": -4132864,
      "scriptDurationMs": 747.854,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 100.89000000004944,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 14.054,
      "layouts": 3,
      "layoutDurationMs": 1.1049999999999998,
      "taskDurationMs": 67.01000000000002,
      "heapDeltaBytes": 3448168,
      "heapUsedBytes": 53671316,
      "domNodes": 146,
      "jsHeapTotalBytes": 262144,
      "scriptDurationMs": 13.83,
      "eventListeners": 37,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 445.73300000001836,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 20.122,
      "layouts": 4,
      "layoutDurationMs": 1.054,
      "taskDurationMs": 107.58200000000001,
      "heapDeltaBytes": 5155424,
      "heapUsedBytes": 55309784,
      "domNodes": 157,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 24.172,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 442.0619999999644,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 18.730999999999998,
      "layouts": 5,
      "layoutDurationMs": 1.123,
      "taskDurationMs": 99.60000000000001,
      "heapDeltaBytes": 5177460,
      "heapUsedBytes": 56170000,
      "domNodes": 157,
      "jsHeapTotalBytes": 524288,
      "scriptDurationMs": 23.527,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    }
  ]
}

@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@             Coverage Diff             @@
##             main   #11892       +/-   ##
===========================================
- Coverage   71.58%   56.29%   -15.29%     
===========================================
  Files        1494     1385      -109     
  Lines       89332    70894    -18438     
  Branches    24945    18854     -6091     
===========================================
- Hits        63951    39913    -24038     
- Misses      24461    30451     +5990     
+ Partials      920      530      -390     
Flag Coverage Δ
e2e ?
unit 56.29% <ø> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 1008 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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
apps/website/src/pages/p/supported-models/[slug].astro (1)

125-134: ⚡ Quick win

Avoid hydrating this static hero.

ModelHeroSection is presentational, so client:load ships Vue runtime code to every model page without adding behavior. Server-rendering it keeps the SEO page lighter.

Proposed fix
   <ModelHeroSection
     displayName={displayName}
     description={description}
     huggingFaceUrl={model.huggingFaceUrl}
     docsUrl={model.docsUrl}
     blogUrl={model.blogUrl}
     workflowCount={model.workflowCount}
     directory={model.directory}
-    client:load
   />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/website/src/pages/p/supported-models/`[slug].astro around lines 125 -
134, ModelHeroSection is a purely presentational component but is being hydrated
via the client:load directive, which unnecessarily ships the Vue runtime; remove
the client:load attribute from the ModelHeroSection JSX/AST invocation so it is
server-rendered only (leave all props like displayName, description,
huggingFaceUrl, docsUrl, blogUrl, workflowCount, directory untouched), and if
any interactive behavior is later required extract that behavior into a separate
child component and hydrate only that child.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/model-page-discovery.yml:
- Around line 69-95: The script that builds NEW_SLUGS reads model objects' slug
property (m.slug) but generate-models.ts serializes each entry as suggestedSlug,
so m.slug is undefined; update the NEW_SLUGS node snippet to read the correct
property (suggestedSlug) instead of slug (or fall back to suggestedSlug when
slug is absent) so the extracted slugs reflect the generated out.json entries;
modify the map callback in the NEW_SLUGS extraction to use m.suggestedSlug (or
m.suggestedSlug || m.slug) and keep the rest of the JSON.stringify flow
unchanged.

In `@apps/website/src/components/models/ModelHeroSection.vue`:
- Around line 103-106: The anchor that opens the blog in a new tab (the <a>
using :href="blogUrl" and target="_blank" in the ModelHeroSection component)
exposes window.opener; add rel="noopener noreferrer" to that <a> tag so external
pages cannot access the opener and to prevent potential security/performance
issues.

In `@apps/website/src/config/models.ts`:
- Around line 24-31: The Hugging Face links for partner-only models should be
empty to avoid leaking misleading URLs; update the huggingFaceUrl property to an
empty string ('') for any model objects where directory === 'partner_nodes'
(e.g., the model with slug 'nano-banana') and similarly change the other
partner_nodes entries referenced in the review so their huggingFaceUrl is ''
instead of 'https://huggingface.co/'. Ensure you only modify the huggingFaceUrl
field and leave displayName, description, directory, docsUrl and ogImage
untouched.

In `@apps/website/src/i18n/translations.ts`:
- Around line 3598-3602: Add the missing trailing comma after the previous
translation entry ('zh-CN': 'Creative Studios AI 负责人') so the subsequent
translations object (starting at the 'models.hero.eyebrow' block) is valid
JSON/JS; update the translations map by inserting a comma after the 'zh-CN'
entry in translations.ts to fix the parse/build error.

In `@apps/website/src/pages/p/supported-models/`[slug].astro:
- Around line 143-150: The anchor rendering the tutorial link (the JSX that
checks model.docsUrl and renders <a href={model.docsUrl} target="_blank">)
should include rel="noopener noreferrer" to harden external links opened in a
new tab; update that anchor element so the tag that uses model.docsUrl and
target="_blank" also sets rel="noopener noreferrer".

In `@apps/website/src/pages/p/supported-models/index.astro`:
- Around line 9-22: The dirLabel mapping lacks an entry for 'partner_nodes',
causing partner-model cards to show the raw directory name; add a key
'partner_nodes' to the dirLabel Record (the dirLabel constant defined at top of
supported-models page) with an appropriate user-facing label like 'Partner' or
'Partner Nodes' so partner_nodes resolves to a friendly badge text wherever
dirLabel is used.

---

Nitpick comments:
In `@apps/website/src/pages/p/supported-models/`[slug].astro:
- Around line 125-134: ModelHeroSection is a purely presentational component but
is being hydrated via the client:load directive, which unnecessarily ships the
Vue runtime; remove the client:load attribute from the ModelHeroSection JSX/AST
invocation so it is server-rendered only (leave all props like displayName,
description, huggingFaceUrl, docsUrl, blogUrl, workflowCount, directory
untouched), and if any interactive behavior is later required extract that
behavior into a separate child component and hydrate only that child.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 93f33c1f-0aad-4922-b77e-700fb7dff071

📥 Commits

Reviewing files that changed from the base of the PR and between 0491836 and 9bc0d2f.

📒 Files selected for processing (10)
  • .claude/skills/add-model-page/SKILL.md
  • .github/workflows/model-page-discovery.yml
  • apps/website/scripts/generate-models.ts
  • apps/website/src/components/models/ModelHeroSection.vue
  • apps/website/src/config/models.ts
  • apps/website/src/config/routes.ts
  • apps/website/src/i18n/translations.ts
  • apps/website/src/layouts/BaseLayout.astro
  • apps/website/src/pages/p/supported-models/[slug].astro
  • apps/website/src/pages/p/supported-models/index.astro

Comment on lines +69 to +95
# Extract slugs from the generated out.json
NEW_SLUGS=$(node -e "
const fs = require('fs');
const models = JSON.parse(fs.readFileSync('out.json', 'utf8'));
const arr = Array.isArray(models) ? models : Object.values(models);
const slugs = arr.map(m => m.slug).filter(Boolean);
console.log(JSON.stringify(slugs));
")

# Extract slugs from existing models.ts config
EXISTING_SLUGS=$(node -e "
const fs = require('fs');
const content = fs.readFileSync('apps/website/src/config/models.ts', 'utf8');
// Match slug: 'value' or slug: \"value\" patterns
const matches = [...content.matchAll(/slug\s*:\s*['\"]([^'\"]+)['\"]/g)];
const slugs = matches.map(m => m[1]);
console.log(JSON.stringify(slugs));
" 2>/dev/null || echo '[]')

# Find new slugs not in existing config
ADDED_SLUGS=$(node -e "
const newSlugs = $NEW_SLUGS;
const existing = $EXISTING_SLUGS;
const existingSet = new Set(existing);
const added = newSlugs.filter(s => !existingSet.has(s));
console.log(JSON.stringify(added));
")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Read the generated slug field here.

generate-models.ts serializes each entry as suggestedSlug, so m.slug is always undefined and this scan will never report new models.

Proposed fix
-            const slugs = arr.map(m => m.slug).filter(Boolean);
+            const slugs = arr.map(m => m.suggestedSlug ?? m.slug).filter(Boolean);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/model-page-discovery.yml around lines 69 - 95, The script
that builds NEW_SLUGS reads model objects' slug property (m.slug) but
generate-models.ts serializes each entry as suggestedSlug, so m.slug is
undefined; update the NEW_SLUGS node snippet to read the correct property
(suggestedSlug) instead of slug (or fall back to suggestedSlug when slug is
absent) so the extracted slugs reflect the generated out.json entries; modify
the map callback in the NEW_SLUGS extraction to use m.suggestedSlug (or
m.suggestedSlug || m.slug) and keep the rest of the JSON.stringify flow
unchanged.

Comment thread apps/website/src/components/models/ModelHeroSection.vue Outdated
Comment thread apps/website/src/config/models.ts Outdated
Comment thread apps/website/src/i18n/translations.ts
Comment thread apps/website/src/pages/p/supported-models/[slug].astro
Comment thread apps/website/src/pages/p/supported-models/index.astro
Comment thread .claude/skills/add-model-page/SKILL.md Outdated
@@ -0,0 +1,223 @@
---
name: add-model-page
description: 'Add, update, or remove a model page entry in ComfyUI_frontend. Triggered by Glary-Bot Slack commands. Creates a PR to Comfy-Org/ComfyUI_frontend with the change and posts a Vercel preview link back to Slack.'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
description: 'Add, update, or remove a model page entry in ComfyUI_frontend. Triggered by Glary-Bot Slack commands. Creates a PR to Comfy-Org/ComfyUI_frontend with the change and posts a Vercel preview link back to Slack.'
description: 'Add, update, or remove a model page entry on the comfy org website. Creates a PR to Comfy-Org/ComfyUI_frontend apps/website folder with the change and posts a Vercel preview link back to Slack.'

Comment thread .claude/skills/add-model-page/SKILL.md Outdated

# add-model-page

Handle Glary-Bot Slack commands that add, update, or remove model pages in the ComfyUI website.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
Handle Glary-Bot Slack commands that add, update, or remove model pages in the ComfyUI website.
add, update, or remove model pages in the ComfyUI website.

Comment thread .claude/skills/add-model-page/SKILL.md Outdated
Comment on lines +12 to +14
- `@Glary-Bot Add a model page for <model-name>`
- `@Glary-Bot Update the model page for <model-name>`
- `@Glary-Bot Remove <model-name> from model pages`
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
- `@Glary-Bot Add a model page for <model-name>`
- `@Glary-Bot Update the model page for <model-name>`
- `@Glary-Bot Remove <model-name> from model pages`
- `Add a model page for <model-name>`
- `Update the model page for <model-name>`
- `Remove <model-name> from model pages`

Comment thread .claude/skills/add-model-page/SKILL.md Outdated

## Repos involved

- **comfy-router** (this repo): skill lives here, no code changes needed
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
- **comfy-router** (this repo): skill lives here, no code changes needed

Comment thread .claude/skills/add-model-page/SKILL.md Outdated
Comment on lines +19 to +29
- **ComfyUI_frontend** (`Comfy-Org/ComfyUI_frontend`): all file edits happen here

Assume ComfyUI_frontend is checked out at a sibling path. Find it:

```bash
find ~ -maxdepth 5 -name "models.ts" -path "*/website/src/config/*" 2>/dev/null | head -1
```

Set `FRONTEND` to that repo root (parent four levels up from the found path).

Key files inside `$FRONTEND`:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
- **ComfyUI_frontend** (`Comfy-Org/ComfyUI_frontend`): all file edits happen here
Assume ComfyUI_frontend is checked out at a sibling path. Find it:
```bash
find ~ -maxdepth 5 -name "models.ts" -path "*/website/src/config/*" 2>/dev/null | head -1
```
Set `FRONTEND` to that repo root (parent four levels up from the found path).
Key files inside `$FRONTEND`:

Comment thread .claude/skills/add-model-page/SKILL.md Outdated
Run the generator to find the model:

```bash
cd $FRONTEND
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
cd $FRONTEND
cd ComfyUI_frontend

- Fix missing comma in translations.ts (broke build/oxfmt parse)
- Fix partner node huggingFaceUrl: use empty string instead of HF homepage
- Add rel="noopener noreferrer" to external anchor tags
- Remove client:load from ModelHeroSection (presentational, no JS needed)
- Fix GH Actions workflow: rename .yml→.yaml, bump to @v6 actions (pinact exempt),
  pin pnpm action to SHA, fix m.slug→m.suggestedSlug in discovery comparison
- Rewrite add-model-page skill to be repo-agnostic (no Glary-Bot references,
  no hardcoded paths/system assumptions)
@christian-byrne
Copy link
Copy Markdown
Contributor Author

All review comments addressed in the second commit (8fe2dee):

Build-breaking fix:

  • Added missing comma after customers.feedback.role3 in translations.ts (was causing parse error in all build jobs)

Review comments:

  • huggingFaceUrl for partner nodes: '' instead of 'https://huggingface.co/'
  • Added rel="noopener noreferrer" to both external anchor tags
  • Removed client:load from ModelHeroSection — purely presentational, no JS
  • Fixed GH Actions workflow: renamed .yml.yaml, bumped actions to @v6 (exempt per .pinact.yaml), pinned pnpm/action-setup to SHA, fixed m.slugm.suggestedSlug in discovery comparison
  • Rewrote add-model-page skill to be repo-agnostic — no system-specific references

On generate-models.ts being .ts: pnpm tsx executes TypeScript directly, no compile step. CI output is out.json (plain JSON).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

Inline comments:
In @.claude/skills/add-model-page/SKILL.md:
- Around line 110-118: The Chinese translation entries for the keys
'models.MODEL-SLUG.displayName' and 'models.MODEL-SLUG.description' are empty
strings, which prevents i18n fallback to English; update the 'zh-CN' values for
both keys to the same text as their 'en' values (i.e., set 'zh-CN' to "Human
Display Name" for models.MODEL-SLUG.displayName and to "One sentence describing
what this model does." for models.MODEL-SLUG.description) so the UI shows the
English text instead of blank in zh-CN.

In @.github/workflows/model-page-discovery.yaml:
- Around line 63-74: The current step that sets EXISTING_SLUGS swallows
node/script failures by falling back to '[]' (the "|| echo '[]'") which can mark
every discovered slug as new; change the shell logic so the node -e script reads
apps/website/src/config/models.ts and any runtime/file/parse error causes the
workflow to fail (remove the fallback echo and instead propagate non‑zero exit,
or explicitly check the node process exit status and exit with an error
message). Locate the EXISTING_SLUGS assignment and the inline node -e script
(variables like matches, slugs) and ensure errors from that script are not
masked but returned to the caller so the job fails fast.
- Around line 94-127: The workflow currently always creates a new GitHub issue
when NEW_COUNT != 0; add a pre-check that searches for an existing open
discovery issue and skips creation if one exists. Before the gh issue create
step, run a shell step that uses the GH CLI (or gh api) to list open issues in
the repo filtering by a stable title or label (e.g., "New models detected — add
to model pages" or a new dedicated label) or by matching any slug from
NEW_SLUGS; if a matching open issue is found, exit the step successfully without
calling gh issue create. Keep references to the same env vars (NEW_SLUGS,
NEW_COUNT) and the SLUG_LIST generation logic, and only run gh issue create when
the pre-check returns no matches.

In `@apps/website/src/i18n/translations.ts`:
- Around line 4288-4290: Update the English text for the translation key
'models.whisper-large-v3-fp16.description' to fix the article grammar by
changing "a audio encoder" to "an audio encoder"; locate the object keyed by
'models.whisper-large-v3-fp16.description' and replace the en string accordingly
while leaving the 'zh-CN' entry unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a4420a99-ac21-4ef9-bf27-4e88f6f6d794

📥 Commits

Reviewing files that changed from the base of the PR and between 9bc0d2f and 8fe2dee.

📒 Files selected for processing (6)
  • .claude/skills/add-model-page/SKILL.md
  • .github/workflows/model-page-discovery.yaml
  • apps/website/src/components/models/ModelHeroSection.vue
  • apps/website/src/config/models.ts
  • apps/website/src/i18n/translations.ts
  • apps/website/src/pages/p/supported-models/[slug].astro
✅ Files skipped from review due to trivial changes (1)
  • apps/website/src/config/models.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/website/src/components/models/ModelHeroSection.vue
  • apps/website/src/pages/p/supported-models/[slug].astro

Comment thread .claude/skills/add-model-page/SKILL.md Outdated
Comment on lines +110 to +118
```typescript
'models.MODEL-SLUG.displayName': {
en: 'Human Display Name',
'zh-CN': ''
},
'models.MODEL-SLUG.description': {
en: 'One sentence describing what this model does.',
'zh-CN': ''
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the skill currently instructs empty zh-CN values
rg -n "'zh-CN': ''" .claude/skills/add-model-page/SKILL.md

# Verify fallback logic in i18n helper uses nullish-coalescing (does not treat empty string as missing)
rg -n "return translations\\[key\\]\\[locale\\] \\?\\? translations\\[key\\]\\.en" apps/website/src/i18n/translations.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 174


🏁 Script executed:

# Check if there are other instances of empty zh-CN in the skills directory
rg -n "'zh-CN': ''" .claude/skills/ --type markdown

# Verify the context around lines 113 and 117 to ensure they match the snippet
sed -n '110,120p' .claude/skills/add-model-page/SKILL.md

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 412


Populate empty zh-CN translation values in the model template.

Empty strings in translation keys prevent fallback to English because the i18n handler uses nullish coalescing (??), which treats empty string as a valid value. This causes blank Chinese UI text. Update both keys on lines 113 and 117 to use the English values:

Suggested fix
   'models.MODEL-SLUG.displayName': {
     en: 'Human Display Name',
-    'zh-CN': ''
+    'zh-CN': 'Human Display Name'
   },
   'models.MODEL-SLUG.description': {
     en: 'One sentence describing what this model does.',
-    'zh-CN': ''
+    'zh-CN': 'One sentence describing what this model does.'
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/skills/add-model-page/SKILL.md around lines 110 - 118, The Chinese
translation entries for the keys 'models.MODEL-SLUG.displayName' and
'models.MODEL-SLUG.description' are empty strings, which prevents i18n fallback
to English; update the 'zh-CN' values for both keys to the same text as their
'en' values (i.e., set 'zh-CN' to "Human Display Name" for
models.MODEL-SLUG.displayName and to "One sentence describing what this model
does." for models.MODEL-SLUG.description) so the UI shows the English text
instead of blank in zh-CN.

Comment thread .github/workflows/model-page-discovery.yaml Outdated
Comment thread apps/website/src/i18n/translations.ts Outdated
Comment on lines +4288 to +4290
'models.whisper-large-v3-fp16.description': {
en: 'Whisper Large V3 Fp16 — a audio encoder for use in ComfyUI workflows.',
'zh-CN': 'Whisper Large V3 Fp16 — 用于 ComfyUI 工作流的audio encoder。'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix article grammar in the Whisper description.

The English copy says “a audio encoder”; this should be “an audio encoder”.

✏️ Proposed fix
   'models.whisper-large-v3-fp16.description': {
-    en: 'Whisper Large V3 Fp16 — a audio encoder for use in ComfyUI workflows.',
+    en: 'Whisper Large V3 Fp16 — an audio encoder for use in ComfyUI workflows.',
     'zh-CN': 'Whisper Large V3 Fp16 — 用于 ComfyUI 工作流的audio encoder。'
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'models.whisper-large-v3-fp16.description': {
en: 'Whisper Large V3 Fp16 — a audio encoder for use in ComfyUI workflows.',
'zh-CN': 'Whisper Large V3 Fp16 — 用于 ComfyUI 工作流的audio encoder。'
'models.whisper-large-v3-fp16.description': {
en: 'Whisper Large V3 Fp16 — an audio encoder for use in ComfyUI workflows.',
'zh-CN': 'Whisper Large V3 Fp16 — 用于 ComfyUI 工作流的audio encoder。'
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/website/src/i18n/translations.ts` around lines 4288 - 4290, Update the
English text for the translation key 'models.whisper-large-v3-fp16.description'
to fix the article grammar by changing "a audio encoder" to "an audio encoder";
locate the object keyed by 'models.whisper-large-v3-fp16.description' and
replace the en string accordingly while leaving the 'zh-CN' entry unchanged.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/website/src/config/models.ts (1)

35-35: ⚡ Quick win

Add runtime invariants for slug integrity in the registry.

getModelBySlug returns the first match, so duplicate slug values or invalid canonicalSlug references will silently produce wrong routing/redirect behavior. Add a one-time registry validation on module load.

♻️ Proposed patch
 export const models: readonly Model[] = [
@@
 ]
 
+function validateModelsRegistry(input: readonly Model[]): void {
+  const slugs = new Set<string>()
+
+  for (const model of input) {
+    if (slugs.has(model.slug)) {
+      throw new Error(`Duplicate model slug: ${model.slug}`)
+    }
+    slugs.add(model.slug)
+  }
+
+  for (const model of input) {
+    if (
+      model.canonicalSlug !== undefined &&
+      (!slugs.has(model.canonicalSlug) ||
+        model.canonicalSlug === model.slug)
+    ) {
+      throw new Error(
+        `Invalid canonicalSlug "${model.canonicalSlug}" on "${model.slug}"`
+      )
+    }
+  }
+}
+
+validateModelsRegistry(models)
+
 export function getModelBySlug(slug: string): Model | undefined {
   return models.find((m) => m.slug === slug)
 }

Also applies to: 2059-2061

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

In `@apps/website/src/config/models.ts` at line 35, Add a one-time runtime
validation that ensures each entry in the exported models registry has a unique
slug and that any canonicalSlug refers to an existing model slug: on module load
iterate over the models array (reference: models) and build a slug set, assert
no duplicate slug is found (throw with the duplicate slug and model id/name),
then for each model with a canonicalSlug ensure that canonicalSlug exists in the
slug set (throw with the invalid canonicalSlug and model slug if missing); this
validation will prevent getModelBySlug from silently returning the wrong model
and should run immediately when the module is imported.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/website/src/config/models.ts`:
- Line 35: Add a one-time runtime validation that ensures each entry in the
exported models registry has a unique slug and that any canonicalSlug refers to
an existing model slug: on module load iterate over the models array (reference:
models) and build a slug set, assert no duplicate slug is found (throw with the
duplicate slug and model id/name), then for each model with a canonicalSlug
ensure that canonicalSlug exists in the slug set (throw with the invalid
canonicalSlug and model slug if missing); this validation will prevent
getModelBySlug from silently returning the wrong model and should run
immediately when the module is imported.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 87d4350c-1bae-43d8-807d-d7a4f886ddce

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe2dee and 8db4e46.

📒 Files selected for processing (5)
  • .claude/skills/add-model-page/SKILL.md
  • apps/website/scripts/generate-models.ts
  • apps/website/src/components/models/ModelHeroSection.vue
  • apps/website/src/config/models.ts
  • apps/website/src/i18n/translations.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/website/src/i18n/translations.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/website/src/components/models/ModelHeroSection.vue
  • .claude/skills/add-model-page/SKILL.md
  • apps/website/scripts/generate-models.ts

…ations

Architecture:
- Replace 1585-line hand-coded models.ts with generated-models.json (207 models,
  auto-generated by running pnpm generate:models) + 40-line model-metadata.ts for
  editorial overrides (docsUrl, blogUrl, featured) + slim 65-line models.ts that
  merges both. No more manually maintained data file.
- Remove 830 per-model translation keys from translations.ts — displayName is now
  a plain string from the generator, not a TranslationKey
- models.ts no longer imports TranslationKey; displayName/description are strings
- Add generate:models script to website package.json

Design token fixes (pattern-compliance violations):
- Replace text-[var(--color-primary-comfy-yellow)] with text-primary-comfy-yellow
- Replace text-white/70 with text-primary-comfy-canvas/70 (matches existing components)
- Replace invented --color-accent/--color-text-secondary with real tokens
- Fix h1 text from text-white to text-primary-comfy-canvas (matches HeroSection pattern)

i18n fixes:
- Add models.hero.tutorialCta, models.hero.blogLink, models.whatIs.heading,
  models.whatIs.tutorialLink keys
- Use t() for all button labels and UI strings in ModelHeroSection.vue
- partner_nodes added to dirLabel in index.astro

Other:
- H1 now reads "{displayName} in ComfyUI" (FE-421 spec)
- Remove description prop from hero (redundant with What-is section)
- Fix GH Actions discovery: m.slug field now matches generator output
- Update add-model-page skill to document new 3-file architecture
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels May 4, 2026
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 4, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
.github/workflows/model-page-discovery.yaml (1)

94-127: ⚠️ Potential issue | 🟠 Major

Skip issue creation when an open discovery issue already exists.

This still opens a fresh issue on every scheduled run while unresolved slugs remain. Please keep the open-issue precheck from the earlier review before calling gh issue create.

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

In @.github/workflows/model-page-discovery.yaml around lines 94 - 127, The "Open
GitHub issue for new models" step currently creates a new issue every run; add a
precheck that queries existing open discovery issues and skips creating a new
one if any match. Before running gh issue create, run a check (e.g., using gh
issue list or the GitHub Search API) for open issues with the same
title/label/marker used by this workflow; if the check returns a match, exit the
step without calling gh issue create. Use the existing env vars (NEW_COUNT,
NEW_SLUGS) and the step name "Open GitHub issue for new models" to locate and
update this step. Ensure the check runs in the same shell context and gates the
gh issue create invocation so no duplicate issue is opened while an unresolved
discovery issue exists.
🧹 Nitpick comments (2)
apps/website/scripts/generate-models.ts (1)

5-7: ⚡ Quick win

Honor WORKFLOW_TEMPLATES_PATH before falling back to the sibling checkout.

.github/workflows/model-page-discovery.yaml already provides this path, but the script ignores it and always resolves a hard-coded relative location. That makes local/manual runs depend on a specific directory layout and leaves the CI env setting as dead configuration.

Suggested fix
-const TEMPLATES_DIR = fileURLToPath(
-  new URL('../../../../workflow_templates/templates', import.meta.url)
-)
+const DEFAULT_TEMPLATES_DIR = fileURLToPath(
+  new URL('../../../../workflow_templates/templates', import.meta.url)
+)
+
+const TEMPLATES_DIR = process.env.WORKFLOW_TEMPLATES_PATH
+  ? join(process.env.WORKFLOW_TEMPLATES_PATH, 'templates')
+  : DEFAULT_TEMPLATES_DIR
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/website/scripts/generate-models.ts` around lines 5 - 7, The
TEMPLATES_DIR constant currently always resolves a hard-coded relative path;
change its initialization to first check process.env.WORKFLOW_TEMPLATES_PATH and
use that value (as an absolute path) when present, otherwise fall back to the
existing fileURLToPath(new URL('../../../../workflow_templates/templates',
import.meta.url)) behavior; update the declaration of TEMPLATES_DIR so code that
uses TEMPLATES_DIR (the constant) will honor the WORKFLOW_TEMPLATES_PATH env var
set by CI or local overrides.
apps/website/src/pages/p/supported-models/index.astro (1)

9-23: ⚡ Quick win

Extract the directory label map into a shared helper.

This table is duplicated in apps/website/src/components/models/ModelHeroSection.vue (Lines 23-37), so the index badge and detail-page eyebrow can drift again the next time a directory is added or renamed. Centralizing it would prevent another partner_nodes-style mismatch.

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

In `@apps/website/src/pages/p/supported-models/index.astro` around lines 9 - 23,
The directory-to-label map defined as dirLabel in index.astro is duplicated in
ModelHeroSection.vue; extract this mapping into a shared helper (e.g., a new
exported constant or function) and replace the local maps in both
apps/website/src/pages/p/supported-models/index.astro (dirLabel) and the
ModelHeroSection component with imports from that helper so both use the single
source of truth for labels like 'partner_nodes' and 'diffusion_models'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/skills/add-model-page/SKILL.md:
- Around line 76-78: The current existence check looks for literal "slug:
'${SLUG}'" in models.ts but models.ts now builds entries by mapping over
generated-models.json, so change the check to look directly in
generated-models.json (or parse it) for the slug; update any logic that decides
add vs update/remove to inspect generated-models.json (e.g. search for the JSON
key "slug" matching SLUG or use jq/node to parse and check for an object with
slug === SLUG) instead of grepping models.ts so the add→update switch and
remove/update commands correctly detect existing models.
- Around line 141-155: Update the PR recipe's git and commit steps that
currently stage and mention models.ts and translations.ts: replace the git add
and commit descriptions that reference "models.ts" and "translations.ts" with
the current source-of-truth files "generated-models.json" and
"model-metadata.ts", and remove any mention of per-model translation keys
(translations.ts) from the commit message/body; ensure the branch name and PR
title still reference MODEL-SLUG but the bullet list under "Changes" reflects
adding/updating generated-models.json and model-metadata.ts (and note that zh-CN
translation is no longer required per-model).

In @.github/workflows/model-page-discovery.yaml:
- Around line 63-74: The EXISTING_SLUGS extraction currently reads the source
text of models.ts and fails because slugs are generated from
generated-models.json; update the node snippet that sets EXISTING_SLUGS to read
and parse the JSON file (generated-models.json) and extract the slug fields
(e.g., map over parsedModels.map(m => m.slug)) instead of regexing models.ts,
preserving the same JSON-printed fallback (echo '[]') and error suppression so
the workflow still yields a JSON array of slugs when the file is present.

In `@apps/website/scripts/generate-models.ts`:
- Around line 187-193: The try/catch around reading/parsing templates in
generate-models.ts (where readFileSync(filePath), JSON.parse(raw), and
extractModels(data, file, models) are used) currently swallows errors and only
writes a warning; instead abort the generation on any read/parse/extract
failure: catch the error, log a descriptive error to stderr (including the
filename `file` and the actual error message/stack), and exit with a non-zero
status (e.g., process.exit(1)) so the process fails fast and prevents writing a
partial registry.

In `@apps/website/src/config/models.ts`:
- Around line 34-58: The code sets a hardcoded TODAY constant and assigns
publishedDate/modifiedDate for every model, causing stale identical timestamps;
update the models construction in the models export to stop using TODAY—either
populate publishedDate and modifiedDate from existing inputs (e.g., prefer
fields on generatedModels or modelMetadata for each m.slug) or omit
publishedDate/modifiedDate entirely until accurate values are available; remove
the TODAY constant and adjust the mapping that builds models (referencing
models, generatedModels, modelMetadata, publishedDate, modifiedDate) accordingly
so each entry uses real metadata or has no date fields.

---

Duplicate comments:
In @.github/workflows/model-page-discovery.yaml:
- Around line 94-127: The "Open GitHub issue for new models" step currently
creates a new issue every run; add a precheck that queries existing open
discovery issues and skips creating a new one if any match. Before running gh
issue create, run a check (e.g., using gh issue list or the GitHub Search API)
for open issues with the same title/label/marker used by this workflow; if the
check returns a match, exit the step without calling gh issue create. Use the
existing env vars (NEW_COUNT, NEW_SLUGS) and the step name "Open GitHub issue
for new models" to locate and update this step. Ensure the check runs in the
same shell context and gates the gh issue create invocation so no duplicate
issue is opened while an unresolved discovery issue exists.

---

Nitpick comments:
In `@apps/website/scripts/generate-models.ts`:
- Around line 5-7: The TEMPLATES_DIR constant currently always resolves a
hard-coded relative path; change its initialization to first check
process.env.WORKFLOW_TEMPLATES_PATH and use that value (as an absolute path)
when present, otherwise fall back to the existing fileURLToPath(new
URL('../../../../workflow_templates/templates', import.meta.url)) behavior;
update the declaration of TEMPLATES_DIR so code that uses TEMPLATES_DIR (the
constant) will honor the WORKFLOW_TEMPLATES_PATH env var set by CI or local
overrides.

In `@apps/website/src/pages/p/supported-models/index.astro`:
- Around line 9-23: The directory-to-label map defined as dirLabel in
index.astro is duplicated in ModelHeroSection.vue; extract this mapping into a
shared helper (e.g., a new exported constant or function) and replace the local
maps in both apps/website/src/pages/p/supported-models/index.astro (dirLabel)
and the ModelHeroSection component with imports from that helper so both use the
single source of truth for labels like 'partner_nodes' and 'diffusion_models'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 906acb13-0ee9-4f05-8467-db42f39b564c

📥 Commits

Reviewing files that changed from the base of the PR and between 8db4e46 and 213870a.

📒 Files selected for processing (11)
  • .claude/skills/add-model-page/SKILL.md
  • .github/workflows/model-page-discovery.yaml
  • apps/website/package.json
  • apps/website/scripts/generate-models.ts
  • apps/website/src/components/models/ModelHeroSection.vue
  • apps/website/src/config/generated-models.json
  • apps/website/src/config/model-metadata.ts
  • apps/website/src/config/models.ts
  • apps/website/src/i18n/translations.ts
  • apps/website/src/pages/p/supported-models/[slug].astro
  • apps/website/src/pages/p/supported-models/index.astro
✅ Files skipped from review due to trivial changes (4)
  • apps/website/package.json
  • apps/website/src/config/model-metadata.ts
  • apps/website/src/config/generated-models.json
  • apps/website/src/i18n/translations.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/website/src/pages/p/supported-models/[slug].astro

Comment thread .claude/skills/add-model-page/SKILL.md
Comment thread .claude/skills/add-model-page/SKILL.md Outdated
Comment thread .github/workflows/model-page-discovery.yaml
Comment thread apps/website/scripts/generate-models.ts
Comment thread apps/website/src/config/models.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
apps/website/scripts/generate-models.ts (1)

187-193: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast on template parse/read errors instead of continuing with partial output.

Line 191 swallows the exception and still writes a potentially incomplete registry with exit code 0. This can silently drop models and skew discovery results.

Suggested fix
   for (const file of files) {
     const filePath = join(TEMPLATES_DIR, file)
     try {
       const raw = readFileSync(filePath, 'utf8')
       const data: unknown = JSON.parse(raw)
       extractModels(data, file, models)
-    } catch {
-      process.stderr.write(`Warning: failed to parse ${file}\n`)
+    } catch (error) {
+      throw new Error(
+        `Failed to parse ${file}: ${
+          error instanceof Error ? error.message : String(error)
+        }`
+      )
     }
   }

As per coding guidelines, "Implement proper error handling in all code".

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

In `@apps/website/scripts/generate-models.ts` around lines 187 - 193, The
try/catch around reading/parsing templates (readFileSync, JSON.parse) and
calling extractModels(file, models) currently swallows errors and continues,
producing partial output; change it to fail fast by catching the error, log a
clear error via process.stderr.write including the error.message and file name,
and then exit non-zero (e.g., process.exit(1)) or rethrow the error so the
process stops instead of writing an incomplete models registry. Ensure the catch
references the thrown error (e) and includes the file variable and e.message
when reporting.
🧹 Nitpick comments (2)
apps/website/scripts/generate-models.ts (2)

254-263: ⚡ Quick win

Add a duplicate-slug guard before writing output.

If two distinct model names normalize to the same slug, the generated data will contain route-key collisions and downstream model pages can become ambiguous.

Suggested fix
   const combined = [...apiOutput, ...output]
+
+  const seen = new Set<string>()
+  const duplicateSlugs = new Set<string>()
+  for (const model of combined) {
+    if (seen.has(model.slug)) duplicateSlugs.add(model.slug)
+    seen.add(model.slug)
+  }
+  if (duplicateSlugs.size > 0) {
+    throw new Error(
+      `Duplicate slug(s) detected: ${[...duplicateSlugs].join(', ')}`
+    )
+  }

   const defaultOut = join(
     fileURLToPath(new URL('.', import.meta.url)),
     '../src/config/generated-models.json'
   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/website/scripts/generate-models.ts` around lines 254 - 263, Before
calling writeFileSync(outputArg, json, 'utf8'), compute the slug for each entry
in combined (using your existing slug/normalization function or a new helper
like normalizeSlug(model.name)) and check for duplicate slugs; if any duplicates
are found, throw or log an error and exit (e.g., process.exit(1)) so you never
write ambiguous output. Implement the check right after building combined and
before JSON.stringify (referencing combined, json, outputArg, and writeFileSync)
and include the conflicting model names/slugs in the error message to aid
debugging.

183-200: ⚡ Quick win

Make generation deterministic for equal-count ties.

Line 183 relies on unsorted readdirSync order, and Lines 198-200 / 214-216 sort only by template count. When counts tie, ordering (and therefore canonicalSlug choice) can vary across environments.

Suggested fix
-  const files = readdirSync(TEMPLATES_DIR).filter((f) => f.endsWith('.json'))
+  const files = readdirSync(TEMPLATES_DIR)
+    .filter((f) => f.endsWith('.json'))
+    .sort((a, b) => a.localeCompare(b))

-  const sorted = [...models.entries()].sort(
-    ([, a], [, b]) => b.templates.size - a.templates.size
-  )
+  const sorted = [...models.entries()].sort(([nameA, a], [nameB, b]) => {
+    const byCount = b.templates.size - a.templates.size
+    return byCount !== 0 ? byCount : nameA.localeCompare(nameB)
+  })

-      const membersSorted = [...members].sort(
-        ([, a], [, b]) => b.templates.size - a.templates.size
-      )
+      const membersSorted = [...members].sort(
+        ([nameA, a], [nameB, b]) => {
+          const byCount = b.templates.size - a.templates.size
+          return byCount !== 0 ? byCount : nameA.localeCompare(nameB)
+        }
+      )

Also applies to: 214-216

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

In `@apps/website/scripts/generate-models.ts` around lines 183 - 200, The
directory read and subsequent sorts are non-deterministic for ties: ensure
determinism by sorting the files array immediately after
readdirSync(TEMPLATES_DIR) (e.g., sort by filename) so
extractModels/extractApiModels always process in a stable order, and update the
later sort that creates sorted (and the other sort at lines 214-216) to include
a deterministic tiebreaker (e.g., secondary comparison by model slug/name or
filename) so when b.templates.size === a.templates.size the order (and chosen
canonicalSlug) is consistent across runs; update references: files,
TEMPLATES_DIR, extractModels, extractApiModels, models, and sorted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/website/scripts/generate-models.ts`:
- Around line 187-193: The try/catch around reading/parsing templates
(readFileSync, JSON.parse) and calling extractModels(file, models) currently
swallows errors and continues, producing partial output; change it to fail fast
by catching the error, log a clear error via process.stderr.write including the
error.message and file name, and then exit non-zero (e.g., process.exit(1)) or
rethrow the error so the process stops instead of writing an incomplete models
registry. Ensure the catch references the thrown error (e) and includes the file
variable and e.message when reporting.

---

Nitpick comments:
In `@apps/website/scripts/generate-models.ts`:
- Around line 254-263: Before calling writeFileSync(outputArg, json, 'utf8'),
compute the slug for each entry in combined (using your existing
slug/normalization function or a new helper like normalizeSlug(model.name)) and
check for duplicate slugs; if any duplicates are found, throw or log an error
and exit (e.g., process.exit(1)) so you never write ambiguous output. Implement
the check right after building combined and before JSON.stringify (referencing
combined, json, outputArg, and writeFileSync) and include the conflicting model
names/slugs in the error message to aid debugging.
- Around line 183-200: The directory read and subsequent sorts are
non-deterministic for ties: ensure determinism by sorting the files array
immediately after readdirSync(TEMPLATES_DIR) (e.g., sort by filename) so
extractModels/extractApiModels always process in a stable order, and update the
later sort that creates sorted (and the other sort at lines 214-216) to include
a deterministic tiebreaker (e.g., secondary comparison by model slug/name or
filename) so when b.templates.size === a.templates.size the order (and chosen
canonicalSlug) is consistent across runs; update references: files,
TEMPLATES_DIR, extractModels, extractApiModels, models, and sorted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 26a8aedd-a4b8-455a-9475-c22e97b57c2a

📥 Commits

Reviewing files that changed from the base of the PR and between 213870a and a94c75c.

📒 Files selected for processing (4)
  • .claude/skills/add-model-page/SKILL.md
  • apps/website/scripts/generate-models.ts
  • apps/website/src/config/generated-models.json
  • apps/website/src/config/model-metadata.ts
✅ Files skipped from review due to trivial changes (2)
  • apps/website/src/config/generated-models.json
  • apps/website/src/config/model-metadata.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • .claude/skills/add-model-page/SKILL.md

christian-byrne and others added 5 commits May 4, 2026 07:53
…ations

Architecture:
- Replace 1585-line hand-coded models.ts with generated-models.json (207 models,
  auto-generated by running pnpm generate:models) + 40-line model-metadata.ts for
  editorial overrides (docsUrl, blogUrl, featured) + slim 65-line models.ts that
  merges both. No more manually maintained data file.
- Remove 830 per-model translation keys from translations.ts — displayName is now
  a plain string from the generator, not a TranslationKey
- models.ts no longer imports TranslationKey; displayName/description are strings
- Add generate:models script to website package.json

Design token fixes (pattern-compliance violations):
- Replace text-[var(--color-primary-comfy-yellow)] with text-primary-comfy-yellow
- Replace text-white/70 with text-primary-comfy-canvas/70 (matches existing components)
- Replace invented --color-accent/--color-text-secondary with real tokens
- Fix h1 text from text-white to text-primary-comfy-canvas (matches HeroSection pattern)

i18n fixes:
- Add models.hero.tutorialCta, models.hero.blogLink, models.whatIs.heading,
  models.whatIs.tutorialLink keys
- Use t() for all button labels and UI strings in ModelHeroSection.vue
- partner_nodes added to dirLabel in index.astro

Other:
- H1 now reads "{displayName} in ComfyUI" (FE-421 spec)
- Remove description prop from hero (redundant with What-is section)
- Fix GH Actions discovery: m.slug field now matches generator output
- Update add-model-page skill to document new 3-file architecture
- knip.config.ts: add Astro pages/layouts as entry points for website workspace
  so exports used only by Astro pages are correctly traced
- models.ts: remove unused exports getFeaturedModels, getModelsByDirectory
- routes.ts: remove unused modelDetail export
- ModelHeroSection: variant="primary" -> "solid" (only valid variants: solid, outline, outline-dark)
- SKILL.md: update description, Phase 3 grep, Phase 6 git add to match 3-file architecture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ModelDirectory and Model were exported but not imported by any consumer.
Make them module-private to fix knip unused-export check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adding Astro pages as entry points surfaced pre-existing unused dep warnings
(@comfyorg/design-system, tailwindcss) that are unrelated to this PR.
The type export fix (non-export ModelDirectory/Model) is sufficient to resolve
the original knip failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

// Maps api_*.json filename prefix to a canonical display name and slug.
// Add entries here as new partner integrations land in workflow_templates.
const API_PROVIDER_MAP: Record<string, { name: string; slug: string }> = {
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.

Question: why don't we get models through api https://cloud.comfy.org/api/hub/labels?type=model

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The discovery workflow (model-page-discovery.yaml) already uses the hub API to find new slugs — it runs curl https://comfy.org/api/hub/labels?type=model and opens a PR if any new slugs are missing from generated-models.json. The generator script (generate-models.ts) reads local workflow_templates files because that's the only place we can extract workflowCount, directory, and huggingFaceUrl per model — data not available from the labels API. The hub API is also used at generate time for thumbnails (/api/hub/workflows?tag={slug}&limit=1).

@christian-byrne christian-byrne changed the title feat(website): SEO model pages — 103 models, FAQ JSON-LD, partner node support feat(website): SEO model pages — 207 models, FAQ JSON-LD, partner node support May 4, 2026
…dels.ts

models.ts is now a 65-line merger file with no slug strings. The regex match
against models.ts would always return empty [], making every model appear new.
Read from generated-models.json instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
christian-byrne and others added 2 commits May 4, 2026 17:22
…orkflow

generate-models.ts:
- Add thumbnailUrl field to OutputModel
- Fetch representative thumbnail from /api/hub/workflows?tag={slug} at generate time
- Set SKIP_THUMBNAILS=1 to skip network calls for offline/CI use
- Fix error handling: throw on parse failure instead of warn-and-continue
- make run() async; top-level error handler exits with code 1

models.ts:
- Add thumbnailUrl to Model interface
- Remove hardcoded publishedDate/modifiedDate (unreliable for 207 models)

[slug].astro:
- Pass model.thumbnailUrl as ogImage to BaseLayout (falls back to default)
- Remove article:published_time/modified_time meta tags (dates were hardcoded)
- Remove datePublished/dateModified from SoftwareApplication JSON-LD

model-page-discovery.yaml:
- Replace workflow_templates clone + pnpm generator with hub API call
  (curl /api/hub/labels?type=model — no repo clone, no Node setup needed)
- Use sparse-checkout for generated-models.json only (no full clone)
- Add duplicate-issue guard: skip creation if open discovery issue exists
- Fix path inconsistency: single checkout at repo root, no working-directory hops

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels May 4, 2026
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Why is there so few? shouldn't this be easy to get? In Comfy-Org/workflow_templates in the the index.json we have tutorialUrl fields. we can also just search Comfy-Org/docs repo and also search blog.comfy.org.

Comment on lines +8 to +41
// Wave 1 — partner nodes (FE-421 priority)
'nano-banana': {
docsUrl:
'https://docs.comfy.org/tutorials/partner-nodes/google/nano-banana-pro',
featured: true
},
'kling-ai': {
docsUrl:
'https://docs.comfy.org/tutorials/partner-nodes/kling/kling-motion-control',
featured: true
},
'meshy-ai': {
docsUrl: 'https://docs.comfy.org/tutorials/partner-nodes/meshy/meshy-6',
featured: true
},
// Wave 1 — local models
'wan-2-2': {
docsUrl: 'https://docs.comfy.org/tutorials/video/wan/wan2_2',
featured: true
},
'wan-2-1': {
docsUrl: 'https://docs.comfy.org/tutorials/video/wan/wan-video',
featured: true
},
// Wave 2
'flux-1-kontext-dev': {
docsUrl: 'https://docs.comfy.org/tutorials/flux/flux-1-kontext-dev',
featured: true
},
'hunyuan-video': {
docsUrl: 'https://docs.comfy.org/tutorials/video/hunyuan/hunyuan-video',
featured: true
},
// Wave 3
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Remove these useless comments.

…and metadata

generate-models.ts:
- Add buildTutorialUrlMap() — reads all locale index*.json files, maps each
  template's tutorialUrl to the raw model filenames in that template file
- Adds docsUrl to OutputModel; populated for 106 of 207 models at generate time

model-metadata.ts:
- Remove Wave-N section comments
- Add docsUrl for openai-dall-e, ltxv-api, wan-api, flux-1-kontext-dev

models.ts:
- Forward docsUrl from generated JSON into Model (metadata overrides still apply)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@christian-byrne
Copy link
Copy Markdown
Contributor Author

Preview pages (100 of 204 canonical model pages)

Base URL: https://comfy-website-preview-pr-11892.vercel.app/p/supported-models

Full list

christian-byrne and others added 3 commits May 4, 2026 21:30
Resolved conflict in translations.ts: keep models UI keys from this branch
and payment status page keys added in main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- model-metadata.ts: add hubSlug field (only where comfy.org/workflows/model/{slug} returns 200)
- models.ts: add hubSlug to Model interface
- ModelHeroSection: use hubSlug for CTA, fall back to /workflows if absent
- [slug].astro: pass hubSlug, expand FAQ to 4 questions, improve pageDescription
- SKILL.md: document hubSlug field with verification note
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 4, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcva@​1.0.0-beta.41001007180100
Addedclsx@​2.1.11001009480100
Addedcross-env@​10.1.010010010082100
Addedchart.js@​4.5.0961008686100
Addedastro@​5.18.197998898100
Addedaxios@​1.13.5919810096100

View full report

christian-byrne and others added 3 commits May 4, 2026 23:15
Replace broken hub API thumbnail fetch with local webp lookup.
Each template JSON has a companion -1.webp; we use the first
template's webp per model, served via raw.githubusercontent.com.
178/207 models now have thumbnails.
…date

- [slug].astro: directory-aware whatIsDescription used in body + FAQ JSON-LD
- models.ts: runtime invariant validation for duplicate slugs and invalid canonicalSlug refs
- SKILL.md: note that thumbnails come from local webp files, no network needed
@christian-byrne
Copy link
Copy Markdown
Contributor Author

Updates since last review

Thumbnails now working

Replaced the broken hub API thumbnail fetch with direct webp files from workflow_templates/templates/. The generator now picks the first associated template's -1.webp and serves it via raw.githubusercontent.com. 178/207 models now have thumbnails (up from 0).

Hub model page URLs validated

hubSlug in model-metadata.ts is only set when the hub page returns 200. The "Try in Comfy" CTA links to comfy.org/workflows/model/{hubSlug} for validated slugs, falls back to comfy.org/workflows otherwise.

Richer per-model SEO copy

The "What is {name}" body now generates directory-aware descriptions (e.g. "flux1-dev is a diffusion model that generates images or video from text and image prompts...") instead of repeating the meta description. The FAQ JSON-LD also uses this richer copy.

Models registry validation

models.ts now validates at module load: throws on duplicate slugs and on invalid canonicalSlug references.

Review comments addressed

  • rel="noopener noreferrer" on all external links ✓
  • partner_nodes label in dirLabel on index page ✓
  • Duplicate issue guard in model-page-discovery workflow ✓
  • No client:load on ModelHeroSection (it's SSR-only) ✓

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants