mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 06:10:32 +00:00
68fdfd5e357af2e66512eb8a535fa73d4f697130
77 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4931b0c4b2 |
fix(website): add dark-background favicon for legibility in search results (#12285)
*PR Created by the Glary-Bot Agent* --- ## Summary The comfy.org favicon was reported as illegible in Google search results. The current `logomark.svg` is a transparent yellow "C" — when Google (or any client) composites it onto a white surface (search results, light-theme tab strips), the yellow disappears into the background. Fix: ship a dedicated `/favicon.svg` that wraps the existing yellow logomark in a solid black square, and point `<link rel="icon">` at it. The in-page nav logo, `Organization.logo` Schema.org URL, and any other consumer of `logomark.svg` are left untouched, so transparent-composite contexts (knowledge panels, dark nav) continue to render cleanly. ## Changes - `apps/website/public/favicon.svg` *(new)* — 48×48 SVG: black square + scaled-down original logomark path. Existing path geometry is reused verbatim inside a `<g transform>` so the C glyph is byte-identical to the source. - `apps/website/src/layouts/BaseLayout.astro` — `<link rel="icon" href="/icons/logomark.svg">` → `<link rel="icon" href="/favicon.svg">`. One-line change. ## Why a new file (vs editing `logomark.svg` in place) `logomark.svg` is also used by `SiteNav.vue` (in-page header on the dark `--color-primary-comfy-ink` background) and by the JSON-LD `Organization.logo` URL. Both consumers want the transparent version. Editing it in place would draw an ugly black square in the site's own header. ## User report > "just google searched comfyui and logo isnt legible. We should update.." ## Verification **Built site** - `pnpm typecheck` (astro check): 0 errors, 0 warnings - `pnpm build` (astro build): 280 pages built, exit 0 - Built `dist/index.html` contains exactly one `<link rel="icon" href="/favicon.svg">` and zero references to the old icon path in `<head>` - `oxlint` on changed `.astro` file: 0 warnings, 0 errors **Visual (Playwright on local astro dev server)** - New favicon renders correctly at 16/32/64 px — yellow C centered on black square, no clipping. - In-page nav logo unchanged (yellow C floats cleanly on the dark `--color-primary-comfy-ink` nav background, no black wrapper visible). - Mock of Google search-result row shows the new favicon is high-contrast inside Google's white circular wrapper; the old one is nearly invisible. ## Screenshots ### Google-style search result simulation (before / after)  ### Favicon at native sizes + Google circular wrapper  ### In-page nav header (unchanged after the fix)  ## Notes for reviewers - The change deliberately uses pure black `#000` (matching the user's literal request "make the white background, black") rather than `--color-primary-comfy-ink` (`#211927`). Either would work; happy to switch if brand preference is the ink color. - Search-engine cached favicons can take days/weeks to refresh on Google's side after the new file is deployed. ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12285-fix-website-add-dark-background-favicon-for-legibility-in-search-results-3616d73d365081babbcbedf0b86d3d67) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
4e07fe3a43 |
feat(website): update Terms of Service to legal-approved 2026-05-13 copy (#12286)
*PR Created by the Glary-Bot Agent* --- ## Summary Replaces the `tos.*` i18n keys in `apps/website/src/i18n/translations.ts` with the legal-approved Terms of Service copy from `Comfy - Terms of Service (GP 5.12.26).docx` and surfaces an effective date below the hero on `/terms-of-service`. - Restructures the ToS into 14 sections (intro + 13 numbered sections) to match the new legal-approved structure. - Adds two new keys, `tos.effectiveDateLabel` and `tos.effectiveDate`, rendered as a centered `Effective Date: May 13, 2026` line between the hero and the content (matches the pattern used on the Affiliate Program Terms page). - Subsection labels (*Right to Access and Use Comfy Products.*, *Customer Data.*, etc.) render as h3 headings via the existing `block.N.heading` shape — no changes to `ContentSection.vue` or `contentSections.ts`. - English page meta description tightened to reflect the new scope (Comfy Products: Cloud, API, Enterprise — explicitly excluding Comfy OSS). ## Verbatim legal copy Per request, the copy is **verbatim from the legal-approved `.docx`**, including: - `[URL]` placeholder in §2.7 (Data Retention) where the legal doc has a placeholder pending the real docs page. - `[Address]` placeholder in §12.8 (Notices) where the legal doc has a placeholder pending the finalized mailing address. - Mixed casing in §8 (Disclaimer) and §9 (Limitation of Liability) — e.g. `THE Comfy Products AND OUTPUT…`, `…TOTAL LIABILITY OF Comfy…` — preserved exactly as the legal doc presents it. - §11(c) cross-reference left as written. These are intentional and flagged for follow-up with legal/docs before publishing. I have **not** silently substituted real values for the placeholders or normalized casing — that would be editing legal-approved text. ## Chinese (zh-CN) handling The legal-approved copy was provided in English only. To avoid serving English text under a Chinese page shell: - `apps/website/src/pages/zh-CN/terms-of-service.astro` is **removed**. - `getRoutes()` in `apps/website/src/config/routes.ts` treats `termsOfService` as locale-invariant, so the Chinese footer link emits `/terms-of-service` directly — no redirect hop. - `astro.config.ts` adds a redirect from `/zh-CN/terms-of-service` → `/terms-of-service` as a safety net for any stale external/cached links. - All `zh-CN` values on the new `tos.*` keys are filler (mirrored from English) so the `Record<Locale, string>` type contract holds; they are never served. ## Files changed - `apps/website/src/i18n/translations.ts` — 73 old `tos.*` keys removed, 136 new keys added matching the .docx structure. - `apps/website/src/pages/terms-of-service.astro` — imports `t`, renders effective date, updates meta description. - `apps/website/src/pages/zh-CN/terms-of-service.astro` — **removed**. - `apps/website/astro.config.ts` — adds `/zh-CN/terms-of-service` → `/terms-of-service` redirect. - `apps/website/src/config/routes.ts` — `termsOfService` route stays un-prefixed in non-English locales. ## Verification - `pnpm --filter=@comfyorg/website typecheck` — 0 errors (2 pre-existing hints in unrelated files). - `pnpm --filter=@comfyorg/website build` — 279 pages built, `/terms-of-service/` (English page) and `/zh-CN/terms-of-service/` (redirect stub with `noindex` + `canonical`) both emitted. - Pre-commit lint-staged ran `oxfmt`, `oxlint --type-aware`, `eslint --fix`, and `pnpm typecheck` on every commit — all green. - Rendered HTML spot-checked: English `/terms-of-service` contains the new content with verbatim `[URL]` and `[Address]` placeholders; zh-CN homepage footer now links directly to `/terms-of-service` (no redirect hop); `/zh-CN/privacy-policy` and other locale routes still correctly emit `/zh-CN/…` prefixes. - Manual visual check via `astro preview` + Playwright — sidebar nav, h2 section titles, h3 subsection headings, paragraph wrapping, and inline mailto/href anchors all render correctly. Screenshots attached. ## Code-review follow-ups addressed - **zh-CN regression** — Page removed, route override added, redirect kept as safety net. - **Page description mismatch** — Updated meta description to reflect new scope. - **`docs.comfy.org/data-retention` 404** — Now matches the docx placeholder `[URL]`; flagged to legal/docs. - **Disclaimer / Liability casing** — Restored to match docx verbatim. - **Mailing address** — Now matches the docx placeholder `[Address]`; flagged to legal. - **Section 11(c) cross-reference** — Left verbatim per legal doc. ## Scope notes - English-only legal update per request — no Chinese rewrite, no schema changes, no acceptance-tracking infrastructure. - The signup-flow link on `platform.comfy.org` (`website` repo) already points at `https://www.comfy.org/terms-of-service` and renders the new copy at the same URL — no change needed there. ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12286-feat-website-update-Terms-of-Service-to-legal-approved-2026-05-13-copy-3616d73d3650815b9262f84d12655dfa) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
3b79917011 |
fix(website): restore registry metadata for cloud nodes catalog (#12307)
*PR Created by the Glary-Bot Agent* --- ## Summary The [`/cloud/supported-nodes`](https://comfy-website-preview-pr-12271.vercel.app/cloud/supported-nodes) page was rendering packs without descriptions, icons, or download counts (PR #12271 preview, [`Release: Website` run](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/25866708684/job/76010642686)). The registry enrichment in `apps/website/src/utils/cloudNodes.registry.ts` was silently failing for **two** reasons: 1. **Missing `limit` query parameter.** `api.comfy.org /nodes` applies a default page size of `10` when no `limit` is sent. Each batch of up to 50 `node_id` filters was therefore truncated to 10 results, dropping metadata for every pack past the first ten. 2. **Schema rejected `null` for optional arrays.** The registry serializes empty server-side slices as JSON `null`, so any pack with `supported_os: null` or `supported_accelerators: null` failed Zod validation — and because parse failure is not retryable, the **entire batch** got `null` enrichment. Both bugs produce the same user-visible symptom ("packs fetched, but no metadata"), so they were entangled. ## Changes (2 files) - `cloudNodes.registry.ts`: send `?limit=<batch length>` on every batch and accept `null` for all optional registry fields. The schema normalizes `null → undefined` at the parse boundary via `.transform()`, so the parsed shape continues to match the generated OpenAPI `Node` type contract; downstream code (`toDomainPack`, the rendered `Pack`) is unchanged. - `cloudNodes.registry.test.ts`: two new regression tests: - Server-side default page size: simulates the pre-fix behavior (default `limit=10` truncates) and asserts all 30 batched IDs are enriched. - `null` registry fields: asserts `null` values are normalized to `undefined` on the parsed pack. ## Verification End-to-end fetch against the live registry on this branch (14 packs from the current snapshot): ``` Requested: 14, enriched: 14 comfyui-kjnodes downloads=3,404,416 rgthree-comfy downloads=3,105,034 comfyui-easy-use downloads=2,829,702 comfyui-impact-pack downloads=2,680,589 comfyui_essentials downloads=2,418,367 (supported_os null → undefined) ComfyUI-Crystools downloads=1,729,087 comfyui_layerstyle downloads=1,696,809 comfyui_ultimatesdupscale downloads=1,478,763 comfyui_ipadapter_plus downloads=1,236,442 (supported_os null → undefined) was-node-suite-comfyui downloads=993,960 (supported_os null → undefined) comfyui-advanced-controlnet downloads=600,849 comfyui-animatediff-evolved downloads=503,831 comfyui-cogvideoxwrapper downloads=121,716 (supported_os null → undefined) comfyui_steudio downloads=58,470 (supported_os null → undefined) ``` 5 of 14 packs returned `null` arrays — all parse cleanly now. Sort-by-downloads (already implemented in `useFilteredPacks.ts`) becomes meaningful again once `downloads` is populated. Quality gates: - `pnpm --filter @comfyorg/website test:unit` → 77/77 pass (includes 2 new regression tests) - `pnpm --filter @comfyorg/website typecheck` → 0 errors, 0 warnings on changed files - `pnpm exec eslint` on changed files → clean - `pnpm exec oxfmt --check` on changed files → clean ## Follow-ups (separate tickets) - "New" badge + `dateAdded` field for newly added packs. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12307-fix-website-restore-registry-metadata-for-cloud-nodes-catalog-3626d73d365081288a2cfc30003160cf) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
daab936d15 |
feat: add Cloud Status link to website footer (#12237)
*PR Created by the Glary-Bot Agent* --- ## Summary Adds a "Cloud Status" link to the Contact column of the website footer, pointing to https://status.comfy.org so users can discover the service status page from any page on the marketing site. ## Changes - **What**: New external link in the Contact column of `SiteFooter.vue`, plus matching i18n keys (`footer.cloudStatus` in `en`/`zh-CN`) and a `cloudStatus` entry in the `externalLinks` config. ## Review Focus - Placement: Slotted between Support and Press in the Contact column (alongside the other support/operational links). Open to moving to the Resources column instead if preferred. - URL: `https://status.comfy.org` — assumed convention; swap if a different status page URL is preferred. - Also tightened the `contactColumn` type annotation to `{ title: string; links: FooterLink[] }` to match `companyColumn` / `topColumns` so the `external: true` field is properly typed. ## Screenshots Desktop (Contact column, right side):  Mobile (2×2 grid, Contact column bottom-right):  ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12237-feat-add-Cloud-Status-link-to-website-footer-3606d73d36508190a906fdde6d86706d) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
f176d18fe0 |
fix(website): refresh cloud nodes snapshot in release workflow + strict production builds (#12219)
*PR Created by the Glary-Bot Agent* --- ## Summary `Release: Website` only refreshed the Ashby snapshot, so the cloud-nodes snapshot (`apps/website/src/data/cloud-nodes.snapshot.json`) was stale on every release. `loadPacksForBuild()` then silently fell back to that snapshot because `WEBSITE_CLOUD_API_KEY` was never plumbed through CI or Vercel, leaving production at `/cloud/supported-nodes` with placeholder data (e.g. `rgthree-comfy` listed as supported when it isn't — visible at line 104 of the committed snapshot, last fetched 2026-05-04). ## Changes - **New composite action `.github/actions/cloud-nodes-pull`** mirroring `ashby-pull`: runs `pnpm --filter @comfyorg/website cloud-nodes:refresh-snapshot` with `WEBSITE_CLOUD_API_KEY`. The script already `process.exit(1)`s on any non-`fresh` outcome, so refresh failures are loud. - **`release-website.yaml`** now runs both refreshes and opens a single PR with both updated snapshots. Renamed the job to `refresh-snapshots`, updated branch/commit/title/body for the wider scope, and kept the existing `Release:Website` label so downstream automation is unaffected. - **`cloudNodes.build.ts`** throws when the outcome is `'stale'` **and** `VERCEL_ENV === 'production'`. Preview / local builds keep the snapshot fallback so contributors without key access are unaffected. The CI reporter still runs first so the GitHub annotation explaining *why* it's stale is visible in the failed job. - **`ci-vercel-website-preview.yaml`**: passes `WEBSITE_CLOUD_API_KEY` to `vercel build` in both preview and production jobs, and adds a preflight step on `deploy-production` that hard-fails before `vercel build --prod` if the secret is missing — surfacing config drift with a maintainer-friendly error annotation instead of mid-build. - **`apps/website/README.md`**: documents the production-strictness behavior, the new required secret (GitHub Actions + Vercel env), and the manual refresh path. - **New unit tests** in `cloudNodes.build.test.ts` (6 cases): fresh, stale-no-VERCEL_ENV, stale-on-preview, stale-on-production, failed-regardless, and "still reports on stale-in-production before throwing". ## Manual / one-time steps required before merging This PR cannot finish the job alone. A maintainer must also: 1. Add `WEBSITE_CLOUD_API_KEY` as a **GitHub Actions repo secret** in `Comfy-Org/ComfyUI_frontend`. 2. Add `WEBSITE_CLOUD_API_KEY` to the **Vercel project environment** (`production` env at minimum; `preview` recommended). 3. Investigate why `rgthree-comfy` is in the current snapshot — either the Cloud API was actually returning it on 2026-05-04, the snapshot was generated against a non-production environment, or it was hand-edited. The first manual run of `Release: Website` after this PR merges will confirm. Without step 1, the new `Release: Website` job will fail loudly (the refresh script exits 1 with `missing WEBSITE_CLOUD_API_KEY`). Without step 2, the new preflight will fail the production deploy with a clear error annotation pointing at `apps/website/README.md`. Both failure modes are intentional — they replace today's silent stale snapshot. ## Related (out of scope for this PR) The other half of the original report — production 404s on `/p/supported-models/*`, `/cloud/supported-nodes/*`, `/demos/community-workflows` from PRs #11892 / #11903 / #11942 — is a `comfy-router` allow-list gap (those paths exist in the Vercel build as pre-rendered static HTML). That fix needs to land in `Comfy-Org/comfy-router` and is being handled separately since glary doesn't have access to that repo. ## Verification - `pnpm --filter @comfyorg/website test:unit` — 75/75 pass (6 new in `cloudNodes.build.test.ts`) - `pnpm --filter @comfyorg/website typecheck` — 0 errors, 0 warnings (2 pre-existing hints unrelated to this PR) - `pnpm format` + `pnpm exec eslint` on changed files — clean - `js-yaml` validates `release-website.yaml`, `cloud-nodes-pull/action.yaml`, `ci-vercel-website-preview.yaml` - Oracle code review (round 1) raised 1 warning + 1 suggestion; both addressed in commit 2. **Manual verification not applicable**: the runtime changes are GitHub Actions workflows and a Vercel-env-gated branch in a build-time module — they cannot meaningfully run outside of GitHub Actions / Vercel, and the strict-on-stale path is exhaustively covered by the 6 unit tests (including the exact assertions a manual run would check: throws on `VERCEL_ENV=production` + stale, passes on preview, reports observability annotation before throwing). The end-to-end behavior will be verified by the first `Release: Website` dispatch and the next production deploy after the maintainer adds the secret. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12219-fix-website-refresh-cloud-nodes-snapshot-in-release-workflow-strict-production-build-35f6d73d3650816d8f32d403cb39d733) by [Unito](https://www.unito.io) --------- Co-authored-by: glary <bot@glary.dev> |
||
|
|
e60ae14bc0 |
feat(website): hide Free tier behind SHOW_FREE_TIER flag (#12165)
*PR Created by the Glary-Bot Agent* --- ## Summary Disables the Free tier on the public marketing website (`comfy.org/cloud/pricing` and `comfy.org/cloud`) behind a single boolean flag so re-enabling is a one-line change. The Free tier was already removed from the Comfy Cloud sign-up flow; this PR removes the matching promotional surfaces on the marketing site so users hit the paywall directly. ## Changes - **New** `apps/website/src/config/features.ts` — exports `SHOW_FREE_TIER` (currently `false`). Flip to `true` to restore the previous UX. - **`apps/website/src/components/pricing/PriceSection.vue`** — when `SHOW_FREE_TIER` is `false`: - drops the Free plan card from the pricing array - desktop grid collapses from `lg:grid-cols-4` to `lg:grid-cols-3` - Standard plan's "Everything in Free, plus:" intro is replaced with an aria-hidden spacer so the three remaining cards stay vertically aligned - **`apps/website/src/components/product/cloud/PricingSection.vue`** — hides the "Start free. Upgrade when you're ready." tagline on the `/cloud` pricing teaser. - **New** `apps/website/e2e/pricing.spec.ts` — three @smoke tests asserting the paid tiers + Enterprise are visible and that all Free-tier surfaces are absent. All translation strings (`pricing.plan.free.*`, `cloud.pricing.tagline`) are retained so re-enabling requires no copy work. ## Verification - `pnpm typecheck` — clean (0 errors, 0 warnings; pre-existing hint unrelated) - `pnpm lint` / `oxfmt` — clean - `pnpm test:unit` — 30/30 passing - Playwright e2e (desktop project) — `pricing.spec.ts` 3/3 passing, `cloud.spec.ts` 13/13 still passing - Visual: desktop and mobile pricing pages render with balanced 3-column layout; `/cloud` teaser card still proportional. Screenshot below. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12165-feat-website-hide-Free-tier-behind-SHOW_FREE_TIER-flag-35e6d73d36508164b4dfcfe9fee6b5e7) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> |
||
|
|
93edf166d0 |
fix(website): link careers page to Ashby job description, not application form (#12200)
*PR Created by the Glary-Bot Agent*
---
## Summary
The careers page at comfy.org/careers was linking every role to its
Ashby application form (`.../{id}/application`) instead of the job
description page (`.../{id}/`). Users expect to first read the role
description, not land on the submit-resume page.
Ashby's job board API returns both `jobUrl` (description) and `applyUrl`
(application form). `toDomainRole` was preferring `applyUrl`; this PR
switches to `jobUrl` and renames the `Role` field accordingly so the
field name matches its meaning.
## Changes
- `apps/website/src/utils/ashby.ts`: use `job.jobUrl` directly instead
of `job.applyUrl ?? job.jobUrl`.
- `apps/website/src/data/roles.ts`: rename `Role.applyUrl` →
`Role.jobUrl`.
- `apps/website/src/components/careers/RolesSection.vue`: update the `<a
:href>` binding.
- `apps/website/src/data/ashby-roles.snapshot.json`: regenerated
fallback snapshot — URLs stripped of `/application`, `id`s recomputed
from the new URLs.
- Unit + E2E tests updated; new E2E assertion that links do not end in
`/application` prevents regressions.
The Ashby schema (`ashby.schema.ts`) still accepts `applyUrl` since the
API returns it — we just no longer consume it.
## Verification
- `pnpm test:unit` — 70/70 pass
- `pnpm typecheck` — 0 errors
- `pnpm build` — succeeds; inspected `dist/careers/index.html`, all 19
Ashby links now point to description URLs and zero contain
`/application`
- Oracle code review — 0 issues
Fixes user report in #hiring-ideas (Slack).
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12200-fix-website-link-careers-page-to-Ashby-job-description-not-application-form-35e6d73d3650815cbedadf974f7d3364)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
|
||
|
|
6845d57a80 |
chore(website): refresh Ashby roles snapshot (#12191)
Automated refresh of `apps/website/src/data/ashby-roles.snapshot.json` from the Ashby job board API. **Flow:** 1. `Release: Website` workflow ran (manual trigger). 2. This PR opens with the regenerated snapshot. 3. `CI: Vercel Website Preview` deploys a preview for review. 4. Merging to `main` triggers the production Vercel deploy. The snapshot fallback in `apps/website/src/utils/ashby.ts` remains intact: builds without `WEBSITE_ASHBY_API_KEY` continue to use the committed snapshot. Triggered by workflow run `25746888214`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12191-chore-website-refresh-Ashby-roles-snapshot-35e6d73d365081f4b2e1d802dd412a72) by [Unito](https://www.unito.io) Co-authored-by: Yourz <8287689+Yourz@users.noreply.github.com> |
||
|
|
469a5edf99 |
feat: cloud-nodes catalog at /cloud/supported-nodes (#11903)
*PR Created by the Glary-Bot Agent*
---
## Summary
Adds a comfy.org page that lists every custom-node pack supported on
Comfy Cloud, with per-pack detail subpages. Data is fetched at build
time from `cloud.comfy.org/api/object_info` (gated by
`WEBSITE_CLOUD_API_KEY`), sanitized of user content, joined with public
registry metadata from `api.comfy.org/nodes`, and falls back to a
committed snapshot — mirroring the existing Ashby careers integration
pattern.
- Index: `/cloud/supported-nodes` (en) and
`/zh-CN/cloud/supported-nodes` (zh-CN)
- Detail: `/cloud/supported-nodes/[pack]` and
`/zh-CN/cloud/supported-nodes/[pack]`, generated via `getStaticPaths()`
from the same fetcher as the index so the two routes can never diverge.
## What's new
**Shared package (extracted)**
- `@comfyorg/object-info-parser` — Zod schemas (`zComfyNodeDef`,
`validateComfyNodeDef`), node-source classifier (`getNodeSource`,
`isCustomNode`, `CORE_NODE_MODULES`), and helpers (`groupNodesByPack`,
`sanitizeUserContent`). `src/schemas/nodeDefSchema.ts` and
`src/types/nodeSource.ts` become 1-line re-export shims; existing
imports keep compiling.
**Build-time pipeline**
- `apps/website/src/utils/cloudNodes.ts` — Ashby-style fetcher:
retry/backoff `[1s, 2s, 4s]`, 10 s timeout via AbortController, Zod
envelope + per-node validation, snapshot fallback, memoized via
module-level `inflight` promise.
- `apps/website/src/utils/cloudNodes.registry.ts` — Public registry
enrichment (no auth, batches of 50, single retry, soft-fail).
- `apps/website/src/utils/cloudNodes.ci.ts` — GitHub Actions annotations
+ step summary mirroring the Ashby reporter.
- `apps/website/src/utils/cloudNodes.build.ts` — Single
`loadPacksForBuild()` consumed by both index and detail pages so they
share one source of truth.
- `apps/website/scripts/refresh-cloud-nodes-snapshot.ts` — atomic-rename
refresh CLI that walks pack/node string fields with a user-content
extension regex *before* renaming the snapshot into place.
- Mandatory user-content sanitization strips uploaded filenames from
combo lists (`LoadImage`, `LoadImageMask`, `LoadImageOutput`,
`LoadVideo`, `LoadAudio` zeroed; any combo value matching
`/\.(png|jpe?g|webp|gif|mp4|mov|webm|wav|mp3|flac|ogg|safetensors|ckpt|pt)$/i`
filtered).
**Page + components**
- `apps/website/src/pages/cloud/supported-nodes.astro` (en) + zh-CN
twin.
- `apps/website/src/pages/cloud/supported-nodes/[pack].astro` detail
(en) + zh-CN twin, async `getStaticPaths` driven by
`loadPacksForBuild()`.
-
`apps/website/src/components/cloud-nodes/{HeroSection,PackGridSection,PackCard,PackBanner,NodeList,PackDetail}.vue`
— Vue 3.5 destructured props, `cn()` from `@comfyorg/tailwind-utils`,
design-system tokens only, no PrimeVue.
- Pack card name links to its detail page; banner uses the shared
`fallback-gradient-avatar.svg` asset (copied into
`apps/website/public/assets/images/`) when `banner_url` and `icon` are
missing.
- 25 new `cloudNodes.*` i18n keys in `en` + `zh-CN`.
**Tests**
- 33 unit tests in `@comfyorg/object-info-parser` (schemas, classifier,
sanitizer, grouping).
- 19 new website unit tests covering fetcher (10), CI reporter (6),
registry enrichment (3) — Ashby patterns mirrored.
- E2E: index smoke + search + banner + detail click-through + direct
visit + zh-CN parity.
## Required maintainer follow-up
GitHub Apps cannot push `.github/workflows/*` changes (push was rejected
with `refusing to allow a GitHub App to create or update workflow …
without workflows permission`), so the workflow edits prepared in this
branch were reverted in commit `9be2abce8`. The intended diffs are
documented as copy-paste-ready snippets in `apps/website/README.md`
under the new "Cloud nodes integration → CI wiring" section.
A maintainer must:
1. Provision `WEBSITE_CLOUD_API_KEY` in the repo secrets and the Vercel
project env.
2. Apply the `ci-website-build.yaml` and
`ci-vercel-website-preview.yaml` diffs documented in the README directly
to `main` (or as a follow-up commit on this branch with a maintainer
account).
The committed snapshot lets builds succeed without the secret while the
maintainer step is pending — pages render from
`apps/website/src/data/cloud-nodes.snapshot.json`.
## Self-review (Oracle)
Two warnings caught and fixed in commits `deba5ab02` and `99dfc3381`:
- Index/detail pages now share a single source of truth
(`loadPacksForBuild`), so a fresh fetch can't expose packs whose detail
routes weren't generated.
- Refresh script validates parsed snapshot fields *before* the atomic
rename, instead of regex-scanning the serialized JSON after the file is
already in place.
## Quality gates (local)
```
pnpm --filter @comfyorg/object-info-parser test → 33 passed
pnpm --filter @comfyorg/website test:unit → 42 passed
pnpm --filter @comfyorg/website typecheck → 0 errors
pnpm --filter @comfyorg/website build → 47 pages built (incl. 6 cloud-nodes routes)
pnpm lint → 0 errors (1 pre-existing warning in unrelated test file)
pnpm knip → 0 errors (1 pre-existing tag hint in unrelated file)
```
E2E (`pnpm --filter @comfyorg/website test:e2e`) is intended to be run
by the Vercel/CI pipelines.
## Manual verification
Built `dist/`, served locally on port 4321, drove with Playwright:
- `/cloud/supported-nodes` renders both pack cards, search input, sort
dropdown
- `/cloud/supported-nodes/comfyui-impact-pack` renders the metadata grid
(publisher, downloads, stars, version, license, last updated) and 3
categorized node sections with 5 nodes total
- `/zh-CN/cloud/supported-nodes` localizes hero (`Comfy Cloud 上的自定义节点`),
label (`云端节点目录`), search placeholder (`搜索节点包或节点名称`), sort
- `/zh-CN/cloud/supported-nodes/comfyui-controlnet-aux` localizes every
metadata label (`查看仓库`, `发布者`, `下载量`, `GitHub 星标`, `最新版本`, `许可证`,
`最后更新`) and renders dates with `Intl.DateTimeFormat('zh-CN')`
(`2026年4月27日`)
- Search input narrows pack count from 2 to 1 when typing `impact`
(verified via DOM count)
Banners render the shared `fallback-gradient-avatar.svg` when the
snapshot's image URL doesn't resolve — expected in the local sandbox.
## Preview URL (after CI completes)
`https://comfy-website-preview-pr-{N}.vercel.app/cloud/supported-nodes`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11903-feat-cloud-nodes-catalog-at-cloud-supported-nodes-3566d73d36508194afdec5f389897585)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
|
||
|
|
35443e94f5 |
feat(website): SEO model pages — 207 models, FAQ JSON-LD, partner node support (#11892)
## 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 --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
7ddf71d91b |
fix(website): center GitHubStarBadge text in Safari (#12138)
*PR Created by the Glary-Bot Agent* --- ## Summary The 10px star count text inside the desktop nav GitHub star badge rendered vertically off-center in Safari/WebKit. The text was visibly shifted upward inside the yellow badge body, while Chromium rendered it centered correctly. ## Root cause `NodeBadge.vue` centers its inner text span by setting `flex items-center justify-center` on the segment, then nudging the text with `translate-y-1` (or `translate-y-0` for the small variant). The text span itself is an `inline-block` with no explicit `line-height`, so it inherits the default `line-height: 1.5` (15px for a 10px font). Safari and Chromium distribute that extra leading differently for the `PP Formula Narrow` custom font: Safari pushes the glyph higher inside its 15px line box, while Chromium positions it near the middle. With only a 5px gap above/below the glyph to play with, that browser-specific divergence is enough to make the badge look misaligned in Safari. ## Fix Add `leading-none` to the star count text class so the inline-block's line box equals the font size (10px) and the parent flex container's `items-center` produces deterministic vertical centering across browsers. Verified at lg breakpoint (1440×900) in both WebKit and Chromium via Playwright; the badge now renders identically and is properly centered. ## Verification - `pnpm typecheck` (website) — clean - `pnpm build` (website) — 51 pages built successfully - Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck, typecheck:website) — all passed - Visual inspection in WebKit and Chromium via Playwright Fixes FE-648 ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12138-fix-website-center-GitHubStarBadge-text-in-Safari-35d6d73d3650818aa0e8e0f341b60378) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
759ed3d4e2 |
feat(website): add community-workflows demo page (#11942)
*PR Created by the Glary-Bot Agent* --- Adds a new interactive demo page at `comfy.org/demos/community-workflows` for the [Explore and Use a Community Workflow from the Hub](https://app.arcade.software/flows/mqZh17oWDuWIyhK0xwEV/view) Arcade walkthrough. Built on top of the demo infrastructure merged in #11436. ## Changes - `apps/website/src/config/demos.ts` — register the new demo - `apps/website/src/i18n/translations.ts` — add en + zh-CN strings (title, description, transcript) - `apps/website/public/images/demos/community-workflows-og.png` — 1200×630 OG image so email/social previews render correctly - `apps/website/public/images/demos/community-workflows-thumb.webp` — 1280×720 WebP thumbnail - `apps/website/e2e/demos.spec.ts` — refactored to iterate `demos` from config so every demo (current + future) is exercised in both en and zh-CN, and the iframe `src` is asserted to contain the correct Arcade ID Adding a new demo only requires editing `demos.ts` + `translations.ts` going forward; the e2e refactor is a one-time generalization that gives future demos coverage automatically. ## Verification - `pnpm typecheck:website`: 0 errors, 0 warnings, 0 hints - Pre-commit hook ran `pnpm typecheck`, `oxfmt`, `oxlint`, `eslint` — all clean on staged files - `npx astro build`: 53 pages built; `/demos/community-workflows/` and `/zh-CN/demos/community-workflows/` generated and present in `sitemap-0.xml` - Page rendered in Playwright preview: hero (title, GETTING STARTED, BEGINNER, ~2 min), Arcade embed loads, transcript section present, "What's Next" links to `image-to-video` - zh-CN page shows localized title (探索并使用社区工作流), description, badges, and "What's Next" heading - OG meta tag references the new 1200×630 PNG ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11942-feat-website-add-community-workflows-demo-page-3576d73d36508139b647c774b1d39323) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
d901c63a0b |
feat: convert careers CategoryNav to scroll-spy locator (#12110)
*PR Created by the Glary-Bot Agent*
---
Converts the `CategoryNav` in the careers `RolesSection` from a
click-to-filter button into a scroll-spy section locator, matching the
pattern already used by `ContentSection.vue` (customer story details,
TOS, privacy policy).
## Changes
- **`apps/website/src/components/careers/RolesSection.vue`**
- Replaced category-based filtering with anchor navigation: clicking a
department in the sidebar smooth-scrolls (via existing Lenis/GSAP
`scrollTo` helper) to that department's section with a `-144px` header
offset.
- Removed the `ALL` button — every department is always rendered as its
own scroll target with `id="careers-dept-{key}"`.
- Added `useIntersectionObserver` (rootMargin `-20% 0px -60% 0px`) that
updates the active nav item as the user scrolls. An `isScrolling` guard
prevents the observer from fighting click-jumps mid-animation.
- Added a viewport-entry fade/slide-up animation on each department
section, gated by `motion-safe:` so users with `prefers-reduced-motion`
see content immediately. The reveal state is sticky (one-way) so
sections don't disappear once revealed.
- Active state is driven by raw department keys; both the nav model and
the observer's id-to-key mapping use a single consistent identifier.
- **`apps/website/e2e/careers.spec.ts`**
- Replaced the obsolete "ENGINEERING filter narrows the list" test with
one that validates locator behavior: clicking the department button
scrolls the section into the viewport, sets `aria-pressed="true"`, and
keeps the full role list rendered.
## Verification
- `pnpm --filter @comfyorg/website typecheck` — clean.
- `pnpm exec oxfmt` / `pnpm exec eslint` / `pnpm exec oxlint` — clean.
- Pre-commit lint-staged hooks (stylelint, oxfmt, oxlint, eslint,
typecheck) — passing.
- Manual smoke test via Playwright on `astro dev`: careers page renders
all departments stacked vertically, active department in the sidebar
highlights based on viewport position (DESIGN active on initial scroll),
nav items reflect each department instead of including an `ALL` button.
## Screenshots

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12110-feat-convert-careers-CategoryNav-to-scroll-spy-locator-35b6d73d3650818a9226e5dcb1244756)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary <glary@bot.local>
|
||
|
|
5ca9f3e7e6 |
feat(website): remove left-edge fade-out from local hero illustration (#12137)
*PR Created by the Glary-Bot Agent* --- Removes the left-edge fade-out gradient overlay on the hexagonal hero illustration on the `/download` (local) page. The hex cluster now reads fully edge-to-edge instead of being blended into the page background on the left side. Tracked in [FE-650: Remove fade-out effect on local page hero illustration](https://linear.app/comfyorg/issue/FE-650/remove-fade-out-effect-on-local-page-hero-illustration). ## Change Drops the `<!-- Left-edge fade -->` `<rect>` and its `<defs><linearGradient id="localHeroFadeLeft">…</linearGradient></defs>` from `apps/website/src/components/product/local/HeroSection.vue`. Animation logic (panel expansion + hex ring rotation) is untouched. ## Verification - `pnpm nx typecheck website` — pass (0 errors) - `pnpm nx build website` — pass (51 pages built) - `pnpm exec eslint apps/website/src/components/product/local/HeroSection.vue` — clean - `pnpm format:check apps/website/src/components/product/local/HeroSection.vue` — clean - Manual: `pnpm dev` + visited `/download` at 390×844 (mobile), 1280×800, and 1440×900. Mobile screenshots clearly show the fade is gone; the leftmost hexagons are now fully visible. ## Screenshots Mobile (390×844), before — note the dark fade obscuring the left side of the hex cluster: ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12137-feat-website-remove-left-edge-fade-out-from-local-hero-illustration-35d6d73d365081cba690ed7d46a19882) by [Unito](https://www.unito.io) Co-authored-by: Glary Bot <bot@glary.dev> |
||
|
|
6d5fa743b3 |
fix: seamless SocialProofBar marquee loop (#12139)
*PR Created by the Glary-Bot Agent* --- ## Summary The partner-logo marquee on the homepage `SocialProofBar` glitched on every loop restart — a visible jump where the strip snapped back to the start. ## Root cause The previous implementation rendered all logos as siblings of a single flex container and animated the track from `translateX(0)` to `translateX(-50%)`. Because the `gap` utility inserts spacing between every adjacent pair of items (including the seam between the two duplicated halves), `-50%` of the total width does not equal the distance from one half-start to the next half-start. The mismatch (`gap / 2`) is exactly what the eye sees as a jump. ## Fix - Wrap each duplicated half in its own flex group. - Place the two groups as siblings of an outer `flex w-max gap-X` track with a gap that matches the inner gap. - Animate each group by `translateX(calc(-100% - var(--marquee-gap)))`, where `--marquee-gap` is set inline to the same value as the Tailwind gap class. - Scope the `animation` declaration to `@media (prefers-reduced-motion: no-preference)` so reduced-motion users get a stable, non-animated client list instead of the global "snap to 0.01ms" jump. At `t = end`, the second group sits at `x = 0` — exactly where the first group started — so the next animation cycle is visually indistinguishable from the previous frame. The duplicate carries `aria-hidden="true"` so screen readers don't read the client list twice. ## Verification - `pnpm typecheck`, `pnpm format`, `npx eslint` on changed files: clean. - Geometry verified at runtime on desktop (1440×900) and mobile (390×844): copy widths match, second copy lands at `x = 0` at animation end. - New Playwright regression tests (`apps/website/e2e/responsive.spec.ts`) pause the CSS animation, sample bounding rects at `t=0` and `t≈duration`, and assert the seam invariant — covering desktop forward, mobile forward, and mobile reverse marquees. All 5 SocialProofBar tests pass on both `desktop` and `mobile` projects. - Reduced-motion behavior verified in the browser: `animationName: none`, `transform: none`, tracks at their natural positions. Fixes FE-649 ## Screenshots     ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12139-fix-seamless-SocialProofBar-marquee-loop-35d6d73d36508141b6ccf0167016b8c8) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
d767a325a2 |
FE-604: fix(website): activate last section badge when scrolled to bottom (#12057)
*PR Created by the Glary-Bot Agent* --- ## Summary Fixes the bug where the last badge in `ContentSection`'s sticky sidebar nav stays unhighlighted when the user scrolls to the very bottom of the page on tall viewports (reported on a 14" MacBook M4 Pro at 3024×1964 / 2016×1310 logical, both Chrome and Safari). ## Root cause The scroll-spy uses an IntersectionObserver with `rootMargin: '-20% 0px -60% 0px'`, which makes only a 20%–40% horizontal band from the viewport top "active". When multiple intersecting entries are reported, the callback picks the one whose `boundingClientRect.top` is smallest (highest up on screen). On tall viewports, when the page is scrolled to the absolute bottom, the last *and* the second-to-last sections frequently both sit inside that 20%–40% band at the same time. The "smallest top" tiebreak then selects the second-to-last section, leaving the last badge inactive even though the user has reached the end of the page. ## Fix `apps/website/src/components/common/ContentSection.vue`: 1. Add `isAtBottom()` — true when the viewport bottom has reached the document bottom (within 4px to absorb sub-pixel rounding). 2. The IntersectionObserver callback bails out when `isAtBottom()` so it cannot overwrite the choice below. 3. A passive `scroll` listener (and a one-shot `onMounted` call) sets `activeSection` to the last section whenever the page is at the bottom — including when the component mounts already at the bottom (e.g. hash navigation to a trailing anchor, restored scroll position, or a page shorter than the viewport). 4. Both the scroll handler and the IO callback honor the existing `isScrolling` flag, so click-driven smooth scroll-to-section behavior is unchanged. ## Verification Reproduced the bug at viewport 2016×1310 (14" M4 Pro "More Space" mode) on `/privacy-policy`: - Before fix: at absolute bottom, IntersectionObserver picks `australian-privacy` (second-to-last) — bug confirmed via DOM inspection that showed multiple sections intersecting the active band, with the second-to-last winning the "smallest top" tiebreak. - After fix: - Scrolled to bottom → last badge `CONTACT` is active. - Scrolled to top → first badge `INTRO` is active. - Scrolled mid-page → correct mid-section is active. - Click on a badge → smooth scrolls and that badge becomes active. - Initial render at bottom (loaded `/privacy-policy#contact`, browser scrolls to the bottom on mount) → `CONTACT` active immediately. `pnpm typecheck` and `pnpm typecheck:website` pass; `pnpm lint` reports 0 errors; existing website unit tests pass. Note: The website app currently has no Vue component test setup (`vitest.config.ts` is configured for `node` env, no DOM). Adding component tests for this scroll-spy interaction would require setting up `happy-dom` and `@testing-library/vue` for the website app, which is out of scope for this bug fix. Fixes FE-604 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12057-FE-604-fix-website-activate-last-section-badge-when-scrolled-to-bottom-3596d73d365081faa243f4dd8e6ee54a) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
8c295e7c68 |
fix: remove transition delay from FeedbackSection progress bar (#12059)
*PR Created by the Glary-Bot Agent* --- ## Summary The horizontal progress bar in `FeedbackSection.vue` lagged behind the carousel scroll position because the bar's width was driven reactively by `useScroll`, but the `transition-all duration-200` utility animated each width change over 200ms. As scroll continuously emits new target widths, the bar visibly trailed the scroll position. Removing the transition makes the bar track scroll synchronously. ## Verification - Reproduced the lag locally on `/customers`. - Verified post-fix that `bar.style.width` updates in the same frame as `scrollLeft` changes (samples at scrollLeft 0 / 944 / 1600 → width 0% / 59% / 100%, with `transitionDuration: 0s`). - `pnpm exec eslint`, `pnpm exec oxfmt --check`, `pnpm nx typecheck website`, and `pnpm test:unit` all pass. ## Notes No regression test added — the customers section components have no existing unit/E2E coverage in this repo, and standing up a new test harness for a one-line CSS fix would be disproportionate. Worth following up on broader carousel coverage as a separate task. ## Screenshot After fix, scrolled to second slide — progress bar tracks scroll position synchronously. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12059-fix-remove-transition-delay-from-FeedbackSection-progress-bar-3596d73d36508107bc80dc38ea7ab79e) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
fef2cab31e |
fix(website): prevent video glitch when c-projection.webp loads on /customers (#12060)
*PR Created by the Glary-Bot Agent* --- ## Summary Fix the video position glitch on `/customers` caused by `c-projection.webp` loading. ## Root cause In `HeroSection.vue` the hero `<img>` for `c-projection.webp` had no `width`/`height` attributes, so the browser reserved no space for it. When the image finished loading, the layout shifted ~192px, pushing the `VideoPlayer` below it. `useHeroAnimation` registers a GSAP `ScrollTrigger` parallax against the video in `onMounted` (before the image is loaded), so the cached scroll geometry then went stale and the video visibly glitched. ## Fix - Add explicit `width="1568"` / `height="1763"` to the `<img>` (the image's native size) so the browser reserves the correct aspect-ratio'd space upfront. - Add `h-auto` so the height attribute doesn't override the responsive layout. - Refresh `ScrollTrigger` on the image's `@load` (with `refresh(true)` so measurements happen after layout has settled) as a defensive measure for any sub-pixel adjustments. ## Test coverage Added `apps/website/e2e/customers.spec.ts` with a regression guard that: 1. Asserts the hero `<img>` declares numeric `width`/`height` attributes. 2. Asserts the unloaded image still reserves vertical space (>100px), which is the exact property that prevents the video from jumping when the image finishes loading. Verified the test fails when the `width`/`height` attributes are removed and passes with the fix applied. ## Verification - `pnpm typecheck` clean. - `pnpm test:unit` (website app) — 30/30 pass. - `pnpm test:e2e customers.spec.ts --project=desktop` — passes. - ESLint + oxfmt clean on changed files. - Manual Playwright verification confirmed the video bounding rect stays at `top=785, height=628` through the full image load lifecycle. Reverting the fix in DevTools and re-loading the image reproduces the original ~192px shift. ## Out of scope `apps/website/src/components/contact/FormSection.vue` uses the same `c-projection.webp` pattern (also without `width`/`height`). It runs `useHeroAnimation` with `parallax: false`, so the symptom is much smaller — leaving as a follow-up to keep this PR minimal. - Fixes [FE-607](https://linear.app/comfyorg/issue/FE-607/bug-video-on-customers-shifts-position-when-c-projectionwebp-finishes) ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12060-fix-website-prevent-video-glitch-when-c-projection-webp-loads-on-customers-3596d73d365081ebbcb8db25aaa5c451) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
2322a5a497 |
fix: use webm video for VFX use case right asset (#12040)
*PR Created by the Glary-Bot Agent* --- ## Summary Replaces `right1.webp` with `right1.webm` in the VFX panel of `UseCaseSection`. `BlobMedia` already auto-detects `.webm` URLs and mounts a `<video>` element (with the `.webp` as poster), so this single URL swap is the only change required — matching the pattern used by the other 4 use-case panels. ## Files changed - `apps/website/src/components/home/UseCaseSection.vue` — swap `right1.webp` → `right1.webm`. ## Verification - `pnpm exec nx run website:typecheck` — clean - `pnpm exec eslint` on changed file — clean - `pnpm exec oxfmt --check` — clean - pre-commit lint-staged hooks — passed ## Reviewer note (Oracle finding) VFX is the default active panel, so the homepage's initial right-rail asset moves from ~131 KB `.webp` to ~4.1 MB `.webm`. Behaviorally consistent with the other 4 panels (which already use `.webm`), but worth confirming whether `right1.webm` should be re-encoded smaller on the CDN before promoting this PR out of draft. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12040-fix-use-webm-video-for-VFX-use-case-right-asset-3596d73d365081829976f37b733840f1) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
81d9df61f2 |
fix(website): tighten GitHub ticker spacing on wide screens (#12021)
*PR Created by the Glary-Bot Agent* --- ## Summary The GitHub star ticker reads as detached from the GitHub octocat icon on wider viewports. The CSS gap is constant (`gap-2` = 8px), but the 28px icon next to a 20px badge plus the fixed gap make the pair look like two separate items at `lg+` widths instead of a single coupled unit. ## Change `apps/website/src/components/common/GitHubStarBadge.vue`: - Inner gap `gap-2` → `gap-1` (8px → 4px) so the badge and icon sit closer together. - Icon `size-7` → `size-6 shrink-0` (28px → 24px) so the icon height is closer to the badge height (20px) and the pair reads as one unit. The outer `gap-2` between CTA items in `SiteNav.vue` is intentionally unchanged — it is the correct spacing between unrelated CTA elements. ## Verification - `pnpm typecheck` — 0 errors (1 pre-existing hint in unrelated file). - `pnpm format:check` — clean. - `pnpm exec eslint apps/website/src/components/common/GitHubStarBadge.vue` — clean. - `pnpm test:unit` (apps/website) — 30/30 pass. - Pre-commit hook (oxfmt + oxlint + eslint + typecheck + typecheck:website) — passed. - `/review` (Oracle) — 0 critical, 0 warnings, 0 suggestions. - Manual visual verification at 1280px, 1920px, and 2560px viewports. - Tested longer star strings (`999.9K`, `1.2M`) — no wrapping. ## Before / After (2560px viewport) Before: badge and octocat appear visually detached. After: badge and octocat read as a single tightly-coupled unit. ## Screenshots      ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12021-fix-website-tighten-GitHub-ticker-spacing-on-wide-screens-3586d73d365081be8d66dfbb22b8dc2c) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
d3f802de10 |
feat(pricing): add concurrent API jobs feature to Creator and Pro tiers (#12000)
*PR Created by the Glary-Bot Agent* --- ## Summary Adds a new feature bullet to the Creator and Pro plans on the [cloud pricing page](https://comfy.org/cloud/pricing) to call out included API concurrency: - **Creator**: `3 concurrent API jobs` - **Pro**: `5 concurrent API jobs` Free and Standard tiers do not include API access, so they are not changed. This matches the language landing in the docs PR: [Comfy-Org/docs#965](https://github.com/Comfy-Org/docs/pull/965). ## Changes - `apps/website/src/components/pricing/PriceSection.vue`: added `feature2` to the Creator and Pro plan feature lists. - `apps/website/src/i18n/translations.ts`: added `pricing.plan.creator.feature2` and `pricing.plan.pro.feature2` for `en` and `zh-CN`. - Updated `pricing-tiers-{1-sm,2-md,3-lg,4-xl}` visual regression snapshots in `apps/website/e2e/visual-responsive.spec.ts-snapshots/` to match the new copy. ## Verification - `pnpm nx run @comfyorg/website:typecheck` — clean - ESLint and `oxfmt` clean on changed files (pre-commit lint-staged also passed) - `pnpm exec playwright test --project visual -g "pricing-tiers"` — 4/4 passing against the regenerated snapshots - Manually rendered `localhost:4321/cloud/pricing`; confirmed copy appears in both desktop and mobile layouts and that Free / Standard are unchanged. Screenshots below. ## Screenshots ### Desktop  ### Mobile — Creator  ### Mobile — Pro  ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12000-feat-pricing-add-concurrent-API-jobs-feature-to-Creator-and-Pro-tiers-3586d73d365081559acfc44eb5024c52) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> |
||
|
|
e46667b33f |
feat: replace spin logo video with Three.js instance in homepage HeroSection (#11964)
Replace the pre-rendered `.webm` video in the homepage hero section with an interactive Three.js 3D logo. ## Changes - Add `three` dependency to the website package and pnpm catalog - Add `useHeroLogo` composable that sets up the Three.js scene: - Extruded Comfy "C" logo with stencil-masked image sequence slideshow - Auto-rotation with drag interaction and cursor tilt - Graceful degradation if some textures fail to load - Update `HeroSection.vue` to use the composable instead of a `<video>` element - Upload 16 image sequence frames to `gs://comfy-org-videos/website/homepage/hero-logo-seq/` <img width="1000" height="648" alt="Kapture 2026-05-05 at 20 54 05" src="https://github.com/user-attachments/assets/7a7b1634-2da3-4aa2-871a-f64d4d337b39" /> @coderabbitai approve ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11964-feat-replace-spin-logo-video-with-Three-js-instance-in-homepage-HeroSection-3576d73d365081bbab0ed19dd121830c) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
fb32b9a5c5 |
fix(website): prevent HeroSection fade from bleeding into CloudBannerSection on /download (#11974)
*PR Created by the Glary-Bot Agent* --- ## Summary The left side of `CloudBannerSection` on `/download` showed an unintended fade-out: the bottom-left of the banner appeared darker than the rest of the bar. ## Root cause `product/local/HeroSection.vue` renders an SVG illustration whose container has `lg:z-1` and whose SVG element has `overflow-visible`. The SVG contains a left-edge fade `<rect x="300" y="150" width="250" height="900" fill="url(#localHeroFadeLeft)" />` that paints outside the SVG's `viewBox` (`400 200 550 800`) — including upward into the area occupied by the preceding `CloudBannerSection`. Because `CloudBannerSection` had `position: static` and `z-auto`, the positively-stacked illustration painted over the banner's bottom-left, producing the visible darkening. ## Fix Establish a stacking context on `CloudBannerSection` (`relative z-20`) so it always renders above the hero illustration's overflow on every page that includes the banner (download, api, cloud/enterprise, and zh-CN equivalents). This is a minimal, isolated change to the shared component — no logic or markup structure changes. ## Verification - Reproduced visually at `lg` breakpoint and confirmed the fade is gone after the fix. - Verified `/download`, `/api`, `/cloud/enterprise`, and `/zh-CN/download` render correctly. - `pnpm typecheck` and `pnpm typecheck:website` pass (run automatically by pre-commit hook). - `oxfmt`, `oxlint`, `eslint`, `stylelint` all pass. ### Before  ### After  ## Follow-up Consider adding a Playwright visual regression test for the banner/hero seam on `/download` to catch future stacking regressions (called out by review). ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11974-fix-website-prevent-HeroSection-fade-from-bleeding-into-CloudBannerSection-on-downloa-3576d73d3650813d8924fb54d5f78cee) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
6474faaa17 |
fix(website): prevent illustration cutoff in enterprise hero section (#11973)
*PR Created by the Glary-Bot Agent* --- ## Summary The illustration in the `HeroSection` of `/cloud/enterprise` was getting cut off at the top — the topmost ripple ring was clipped by the section's `overflow-y-clip`/`overflow-hidden`. **Root cause:** the SVG wrapper has `scale-150`, which makes the rendered illustration 50% larger than its layout box and overflows symmetrically (~25% above, ~25% below). The section only had `lg:pb-[min(8vw,10rem)]` — bottom padding — and on lg the wrapper had `lg:translate-y-[40px]` to nudge it down, but that wasn't enough room for the top to escape clipping. On mobile there was no padding at all, so the same issue occurred. **Fix:** add symmetric vertical padding (`pt-16` on mobile, `lg:pt-[min(8vw,10rem)]` mirroring the existing bottom value on lg) so the scaled illustration has room above and below. Removed the now-unnecessary `lg:translate-y-[40px]` since symmetric padding keeps the illustration vertically centered within the flex row. Verified at 375px (mobile), 1024px (lg), and 1440px (xl) viewports — all four ripple rings render fully without clipping at the top. ## Verification - `pnpm typecheck:website` ✅ - `pnpm exec oxfmt --check` on edited file ✅ - `pnpm exec oxlint` on edited file ✅ - `pnpm --filter @comfyorg/website build` ✅ - Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck, typecheck:website) ✅ - Visual verification with Playwright at mobile / lg / xl ## Before vs After **Desktop (1440px) — before:** the topmost ripple ring is clipped at the top of the section. **Desktop (1440px) — after:** all four ripple rings are fully visible. **Mobile (375px) — before:** the top of the outermost ring is cut off by the section's top edge. **Mobile (375px) — after:** the full illustration (rings + blocks) is visible. ## Screenshots     ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11973-fix-website-prevent-illustration-cutoff-in-enterprise-hero-section-3576d73d3650813f9f04c3f93b9b42d6) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
eecbaa8f39 |
fix(website): change 'Blogs' to 'Blog' in Resources nav dropdown (#11970)
*PR Created by the Glary-Bot Agent* --- ## Summary Corrects the "Blogs" label to "Blog" (singular) in the website header's Resources dropdown menu, as requested in #website-and-docs Slack channel. ## Changes - `apps/website/src/i18n/translations.ts`: `nav.blogs` English value `Blogs` → `Blog` (zh-CN translation `博客` left unchanged since it was already correct) This also makes the header consistent with the footer, which already labeled the same link as "Blog". ## Verification - `pnpm typecheck` (astro check): 0 errors, 0 warnings, 0 hints (87 files) - `pnpm test:unit`: 30 tests passed across 4 files - `pnpm exec eslint apps/website/src/i18n/translations.ts`: clean - Manual verification via Playwright on `pnpm dev` — Resources dropdown now displays "Blog" - Code review (oracle): 0 issues found ## Screenshot Resources dropdown after the change: ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11970-fix-website-change-Blogs-to-Blog-in-Resources-nav-dropdown-3576d73d365081638245d235bec04230) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
a763c7132c |
feat(website): add "comfyui app" SEO keywords to product pages (#11834)
*PR Created by the Glary-Bot Agent* --- ## Summary Adds "comfyui app" / "comfyui web app" / "comfy ui application" keywords to the titles and meta descriptions of the home, download, and Comfy Cloud pages (and zh-CN equivalents) to recover organic traffic for those queries. ## Context Organic traffic for the query **"comfyui app"** dropped after `https://docs.comfy.org/interface/app-mode` started outranking the product/landing pages. The docs page about app-mode converts worse than the product pages, so we want Google to prefer comfy.org product pages for that query. The cleanest, lowest-risk lever is on-page SEO metadata. ## Changes - **What**: - `apps/website/src/pages/index.astro` → title `ComfyUI App — Professional Control of Visual AI` + product-focused description. - `apps/website/src/pages/download.astro` → title `Download the ComfyUI App — Run Visual AI Locally` + desktop-app description. - `apps/website/src/pages/cloud/index.astro` → title `Comfy Cloud — The ComfyUI Web App` + web-app description. - `apps/website/src/pages/zh-CN/{index,download,cloud/index}.astro` → localised Chinese titles and descriptions so the zh-CN product pages no longer fall back to the English `BaseLayout` default. - `apps/website/src/layouts/BaseLayout.astro` → unchanged net-net (touched then reverted to neutral copy after review feedback so non-product / non-localised pages keep their existing, generic fallback). - **Breaking**: none. Visual content, routing, and components are untouched — only `<title>` and `<meta>` tags change. ## Review Focus - The keyword copy reads naturally (no stuffing) and stays under typical SERP truncation limits (≤ ~165 chars). - zh-CN pages get Chinese descriptions — they intentionally don't repeat the English keywords, since "comfyui app" is an English-language query. - Pre-existing behaviour preserved: zh-CN pages **without** an explicit description still inherit the English `BaseLayout` default. Fixing that fallback for the whole zh-CN tree is out of scope for this PR — happy to follow up if desired. ## Verification - `pnpm typecheck` — 0 errors - `pnpm build` — 39 pages built clean - `pnpm test:unit` — 23/23 pass - `pnpm format:check apps/website/src` — clean - Manually verified rendered `<title>` and `<meta name="description">` via Playwright on `/`, `/download`, `/cloud`, and the zh-CN equivalents. ## Screenshots Home page rendered with the new title (visible in browser tab / SERP preview); visual content unchanged. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11834-feat-website-add-comfyui-app-SEO-keywords-to-product-pages-3546d73d3650819da11bd665c2fcfb88) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
24fc11aa3e |
fix(website): remove placeholder author info for groove-jones customer story (#11937)
*PR Created by the Glary-Bot Agent* --- Removes the placeholder "GROOVE JONES CONTRIBUTORS" author card from the Groove Jones customer story (`/customers/groove-jones`). The card was rendering with `TBD` / `待补充` values for the contributor name and role. ## Change Deletes 3 i18n keys from `apps/website/src/i18n/translations.ts`: - `customers.detail.groove-jones.topic-10.block.2.label` - `customers.detail.groove-jones.topic-10.block.2.name` - `customers.detail.groove-jones.topic-10.block.2.role` Block types in `ContentSection.vue` are inferred from the presence of suffix keys (`.role` → `author` block) via `deriveSections` in `apps/website/src/config/contentSections.ts`. Removing the keys causes the author card to drop out of the rendered output entirely. The other two blocks in topic-10 (intro paragraph + Dale Carman blockquote) remain unchanged. ## Verification - `pnpm typecheck` — passes - `pnpm lint` — 0 errors (1 pre-existing warning, unrelated) - `pnpm format` — applied - `pnpm knip` — clean (1 pre-existing warning, unrelated) - Manual: ran `pnpm dev` for the website app, navigated to `/customers/groove-jones`, confirmed the conclusion section ends naturally — no `TBD` text, no orphan `CONTRIBUTORS` label, no broken card. Code review (Oracle): 0 critical / 0 warning / 0 suggestion. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11937-fix-website-remove-placeholder-author-info-for-groove-jones-customer-story-3576d73d36508193b1a0c0c3cd887686) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
055486cac0 |
feat(website): add 4 team photos and remove infinite scroll loop (#11945)
## Summary Add 4 new team photos and remove the infinite scroll behavior from the careers page team photos carousel. ## Changes - **What**: - Add 4 new photos (team4–team7) to `TeamPhotosSection.vue` - Remove the infinite scroll loop (`loopedPhotos`, `onScroll` handler, `onMounted` scroll initializer) <img width="1000" height="308" alt="Kapture 2026-05-05 at 11 02 16" src="https://github.com/user-attachments/assets/f5f6737f-c6bf-4abf-8780-d72c895f4015" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11945-feat-website-add-4-team-photos-and-remove-infinite-scroll-loop-3576d73d365081cabebecbc06666b9d9) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
d1df5fadf8 |
fix(website): update payment-failed heading to "Unable to complete payment" (#11943)
*PR Created by the Glary-Bot Agent* --- ## Summary Reword the `payment.failed.title` copy on `comfy.org/payment/failed` from "Payment was not completed" to "Unable to complete payment" — a more active, distinguishing phrasing per design feedback. ## Changes - `apps/website/src/i18n/translations.ts` — update English (`Unable to complete payment`) and Chinese (`无法完成支付`) translations - `apps/website/e2e/payment.spec.ts` — update both English and zh-CN heading assertions to match ## Verification - `pnpm --filter website typecheck` — passes - `pnpm --filter website test:unit` — 30 tests passing - Pre-commit hooks (oxfmt, oxlint, eslint, typecheck, typecheck:website) — all pass - Manual visual verification with Playwright on `/payment/failed` and `/zh-CN/payment/failed` — both render the new heading correctly (screenshots attached) ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11943-fix-website-update-payment-failed-heading-to-Unable-to-complete-payment-3576d73d3650817e85e2e7a3891cc307) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
aef71852f0 |
feat: add demo pages with Arcade embeds at /demos/{slug} (#11436)
*PR Created by the Glary-Bot Agent*
---
## Summary
Adds a demo pages system to the website that embeds Arcade interactive
walkthroughs at `comfy.org/demos/{slug}`. These pages will be linked
from welcome/lifecycle emails via Customer.io.
- Adds `/demos/image-to-video` and `/demos/workflow-templates` as the
first two demos
- Follows the existing `customers/[slug].astro` pattern exactly
(config-driven `getStaticPaths()`)
- Full SEO: OG/Twitter cards, HowTo + LearningResource + BreadcrumbList
JSON-LD schemas
- GEO: AI crawler directives in robots.txt, crawlable transcript
alongside iframe
- A11y: iframe title, sr-only transcript, aria-expanded toggle, noscript
fallback
- Email optimization: 1200x630 OG images, SSG pre-rendered, preconnect
to Arcade CDN
- Full zh-CN localization
- Library index stub at /demos for future expansion
- Automatic sitemap inclusion
## Architecture
Adding a new demo = adding one object to `src/config/demos.ts`.
## Note
OG images are tiny placeholders — replace with real 1200x630 screenshots
before go-live.
## Screenshots


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11436-feat-add-demo-pages-with-Arcade-embeds-at-demos-slug-3486d73d365081abbd72e02bf497a43a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
|
||
|
|
f70285dcb2 |
fix(website): point Install via GitHub buttons to install docs anchor (#11852)
*PR Created by the Glary-Bot Agent* --- ## Summary Updates the "Install via GitHub" CTA buttons on the `/download` page to deep-link to the install instructions section of the ComfyUI README (`#installing`) instead of the repo root, so users land directly on setup steps. ## Changes - `apps/website/src/config/routes.ts`: add `externalLinks.githubInstall = 'https://github.com/Comfy-Org/ComfyUI#installing'` (separate from `externalLinks.github`, which is still used by the navbar/footer/star badge for the generic repo link). - `apps/website/src/components/product/local/HeroSection.vue`: switch the secondary CTA next to "Download Local" from `externalLinks.github` to `externalLinks.githubInstall`. - `apps/website/src/components/product/local/EcoSystemSection.vue`: same swap on the ecosystem-section CTA. The platform-aware `Download Local` button (Windows/macOS installers via `useDownloadUrl`) and the generic GitHub social/repo links elsewhere on the site are unchanged. ## Verification - `pnpm --filter @comfyorg/website typecheck` — 0 errors - `pnpm --filter @comfyorg/website test:unit` — 23/23 passing - `pnpm exec eslint` on changed files — clean - `pnpm exec oxfmt --check` — clean - Manual via `pnpm dev` + Playwright DOM assertion on `/download`: - Hero "INSTALL FROM GITHUB" → `https://github.com/Comfy-Org/ComfyUI#installing` ✓ - EcoSystem "INSTALL FROM GITHUB" → `https://github.com/Comfy-Org/ComfyUI#installing` ✓ - Other "GitHub" links (nav, footer, star badge) → unchanged at `https://github.com/Comfy-Org/ComfyUI` ✓ Per request from #website-and-docs: the local download surfaces should at least link to the ComfyUI install instructions on GitHub. Companion change to comfy-org/website#227. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11852-fix-website-point-Install-via-GitHub-buttons-to-install-docs-anchor-3546d73d365081fe8370cd675ae8f896) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
6762c08134 |
feat(website): add payment success and failed pages (#11855)
*PR Created by the Glary-Bot Agent* --- ## Summary Recreate the two payment status pages that were never migrated from Framer (they weren't in the sitemap, so were missed). The Stripe checkout flow in `comfy-api` redirects to `https://www.comfy.org/payment/{success,failed}` after a checkout session, so users currently hit a 404 on completion or cancel. ## Changes - **What**: New static Astro pages at `/payment/success`, `/payment/failed` and their `/zh-CN/` variants, sharing a `PaymentStatusSection.vue` component built from the existing `BrandButton` / `SectionLabel` primitives. Translation keys live in `src/i18n/translations.ts` for both locales. Pages are `noindex` and explicitly excluded from the generated sitemap. Adds a Playwright e2e spec covering both pages in both locales. - **Dependencies**: none ## Review Focus - **URL slug**: matches production Stripe config (`STRIPE_CANCEL_URL=…/payment/failed` in `comfy-api/run-service-{prod,staging}.yaml`), not `/payment/failure`. - **Primary CTA target**: links to `externalLinks.apiKeys` (`platform.comfy.org/profile/api-keys`) — the platform root is just a redirect, so this avoids a hop. - **Locale-aware secondary CTA**: derived from `getRoutes(locale)` so future i18n/route changes flow through the existing helper. - **Stale fallback** (out of scope): `comfy-api/gateways/stripe/stripe.go:159` has an unrelated stale fallback pointing at `/payments/` (plural) that's overridden by the env config in production. Worth fixing in a follow-up. ## Screenshots EN success / failed and zh-CN success / failed at desktop widths. Mobile viewport stacks the CTA buttons vertically (verified locally). ## Screenshots     ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11855-feat-website-add-payment-success-and-failed-pages-3556d73d3650819f8f45d8ecf27cb264) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
4033dde983 |
refactor(website): replace UseCaseSection scroll override with hover on desktop (#11696)
## Summary
Per product feedback, scroll-jacking the page to step through
'Industries that create with ComfyUI' categories feels bad on desktop.
This PR removes the desktop scroll override and switches to hover-driven
imagery on lg+, while preserving the existing pin/scrub interaction on
mobile/touch breakpoints.
## Changes
- **What**:
- Gate `usePinScrub` setup to `(max-width: 1023px)` so the pin/scrub
only runs on touch breakpoints; desktop never engages it.
- Wire `@mouseenter` and `@focus` on each category button to update the
active category on desktop. Click still works on both modes via the
existing `scrollToIndex` (which falls through to a direct ref set when
no ScrollTrigger instance is present).
- Pass the same `(max-width: 1023px)` to `useParallax` via its existing
`mediaQuery` option so parallax doesn't run against the no-longer-pinned
section on desktop.
- Apply the section's `lg:h-[calc(100vh+60px)]` unconditionally on lg+
since pin no longer drives it; mobile height is still managed
dynamically by `usePinScrub`'s `cacheLayout`.
- **Breaking**: None.
- **Dependencies**: None.
## Review Focus
- Mobile path inside `usePinScrub.onMounted` is byte-identical to main —
only the early-return condition gained one extra clause
(`!window.matchMedia('(max-width: 1023px)').matches`), which mobile
evaluates to `false` so it falls through to the existing setup.
- `onCategoryHover` early-returns when `isEnabled` is true, making it a
no-op on mobile (where pin is engaged), so a tap doesn't accidentally
fight the scrub.
- `@focus` is wired alongside `@mouseenter` so keyboard tab navigation
also previews the imagery.
- The previous Lenis-on-macOS workaround from this branch is reverted —
it was only needed because the scroll override existed.
## Screenshots (if applicable)
N/A — interaction change. Test on desktop (≥1024px) by hovering category
labels — imagery should swap with no scroll-jacking. Test on mobile
(<1024px) by scrolling the section; pin/scrub should engage as before.
---------
Co-authored-by: Marwan Ahmed <marwan@Marwans-MacBook-Pro.local>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
|
||
|
|
24b548aebc |
fix: route footer Support link to Zendesk help center (#11904)
*PR Created by the Glary-Bot Agent* --- ## Summary The "Support" link in the marketing site footer (Contact column) was reusing the Discord external link. Update it to point at the Zendesk help center at `https://support.comfy.org/hc/en-us`, as requested in the `#website-and-docs` Slack thread. ## Changes - `apps/website/src/config/routes.ts` — add `support` entry to `externalLinks` pointing at `https://support.comfy.org/hc/en-us`. - `apps/website/src/components/common/SiteFooter.vue` — use `externalLinks.support` for the Contact > Support entry instead of `externalLinks.discord`. ## Verification - `pnpm format` and `pnpm exec eslint` clean on both files. - `pnpm typecheck` passes. - Verified locally with `pnpm dev` (Astro on `localhost:4321`); the rendered footer Support link now resolves to `https://support.comfy.org/hc/en-us` (screenshot below). ## Notes Reviewer flagged that `/hc/en-us` forces English and bypasses Zendesk locale negotiation. The exact URL was explicitly requested by the user in the Slack thread, so it is preserved here. Switching to a locale-neutral `https://support.comfy.org/` can be done as a follow-up if desired. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11904-fix-route-footer-Support-link-to-Zendesk-help-center-3566d73d36508189abcff34ae766d3c4) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
560e53c68f |
fix: remove coming soon badge from parallel job execution (#11819)
*PR Created by the Glary-Bot Agent* --- Removes the "coming soon" badge from the Parallel Job Execution feature card on the cloud pricing page (`comfy.org/cloud/pricing`). ## Changes - `apps/website/src/components/pricing/WhatsIncludedSection.vue`: drop `isComingSoon: true` from feature11 so it renders with the standard check icon and no badge. The `isComingSoon` mechanism (clock icon + yellow badge) is preserved in the component for future use on other features. ## Note The FAQ copy elsewhere on the site (`cloud.faq.9.a`) still references "one active job at a time" and "parallel runs soon". That copy will be updated separately. ## Verification - `pnpm typecheck` (website): 0 errors - `pnpm lint`: clean (1 pre-existing warning unrelated to this change) - `pnpm format:check`: clean - `pnpm test:unit` (website): 20 passed - Visual check via Playwright on local dev server (see screenshot) ## Screenshots  ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11819-fix-remove-coming-soon-badge-from-parallel-job-execution-3546d73d365081d19060f976095d03ac) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
1999b7fba0 |
fix: remove (beta) from cloud.faq.3.a (#11905)
*PR Created by the Glary-Bot Agent* --- ## Summary Remove `(beta)` from the `cloud.faq.3.a` translation entry in both English and Simplified Chinese (`zh-CN`), since Comfy Cloud is no longer in beta. ## Changes `apps/website/src/i18n/translations.ts`: - en: `Comfy Cloud (beta) has zero setup...` → `Comfy Cloud has zero setup...` - zh-CN: `Comfy Cloud(测试版)无需任何设置...` → `Comfy Cloud 无需任何设置...` ## Verification - Pre-commit hooks (oxfmt, oxlint, eslint, typecheck, typecheck:website) all passed - Code review (oracle): 0 issues, ready to merge - Manual verification via Playwright on `/cloud` and `/zh-CN/cloud` — FAQ item 3 renders updated copy in both locales (screenshots attached) ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11905-fix-remove-beta-from-cloud-faq-3-a-3566d73d36508150997bcf2c89826091) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
5523df1aea |
fix(website): unstretch See all case studies button (#11854)
*PR Created by the Glary-Bot Agent* --- ## Summary The "See all case studies" button on the homepage `CaseStudySpotlightSection` was rendering oddly stretched because it had `class="flex-1 text-center"` while being the sole child of a `flex-row` container — it expanded to fill the entire content column (~592px) instead of sizing to its label. This drops `flex-1`/`text-center` and adds `items-start` to the wrapper so the button sizes to its content and is left-aligned, matching the proportions of every other outline `BrandButton` on the site (Hero, UseCase, customer detail, etc.). ## Changes - `apps/website/src/components/home/CaseStudySpotlightSection.vue`: remove `flex-1 text-center` from the `BrandButton` and align the row's items to the start. `BrandButton` already centers its label internally via `inline-flex … justify-center`, so dropping `text-center` is a no-op visually. ## Before / After - Desktop before: button width = 592px (stretched across the column) - Desktop after: button width = 223px (natural) - Mobile: 1-column layout, now consistently left-aligned ## Review Focus Whether the fix should also live on the `BrandButton` component itself (e.g. a global `max-width`) instead of at the call site. I went with the instance-level fix because every other CTA in the website intentionally uses bare `BrandButton` and lets the content size it; only this one had `flex-1`. A blanket `max-width` would risk changing Hero/MobileMenu buttons that explicitly opt into `w-full lg:w-auto lg:min-w-60`. ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11854-fix-website-unstretch-See-all-case-studies-button-3556d73d365081abb3bbe9dbc51cbc07) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
65876c635d |
feat(website): add responsive media tooling for marketing assets (#11869)
*PR Created by the Glary-Bot Agent*
---
## Summary
Adds the building blocks for a responsive media system on
`apps/website`, motivated by the gallery video blurriness raised in
Slack. Three independent pieces:
1. **`<SiteVideo>` Vue component + URL helper** — emits a `<video>` with
multiple `<source>` tags, designed to pair with assets named
`${name}-${width}.${format}` on `media.comfy.org`.
2. **`scripts/process-videos.sh`** — local-developer `ffmpeg` helper
that produces VP9/WebM + H.264/MP4 variants and a poster JPG. Not wired
into CI; the team uploads to `media.comfy.org` out-of-band.
3. **Marketing image conventions** — shared `MARKETING_FORMATS` /
`MARKETING_WIDTHS` constants and a README documenting how to render
local marketing images via Astro's built-in `<Picture>` from
`astro:assets`.
This PR is **infrastructure only** — no existing pages are modified.
Adoption (e.g. converting `HeroSection`, gallery videos) is a follow-up.
The new files are added to knip's ignore list with the existing "pending
stacked PR" pattern.
## Why this shape
- **No custom `<Picture>` wrapper.** Astro 5 already ships a
`ResponsiveImage` component (name conflict), and Astro's
`LocalImageProps | RemoteImageProps` discriminated union does not
survive a thin wrapper without unsafe `as` casts. Shared constants give
the consistency benefit at lower cost.
- **No CI media-upload step.** The `Release: Website` workflow currently
only refreshes the Ashby snapshot; wiring GCS uploads into it would
require new secrets and team coordination beyond this PR's scope. The
script runs locally and outputs are uploaded to `media.comfy.org` the
same way as today.
- **Single resolution per `<video>`.** `<source media="...">` inside
`<video>` is unreliable across browsers (Safari ignores it). The script
generates multiple widths so callers can pick one per page; JS-based
selection can be layered on later if metrics demand it.
## What's verified
- `pnpm --filter @comfyorg/website test:unit` — 30 pass (7 new for
`buildVideoSources` / `videoKey`)
- `pnpm --filter @comfyorg/website typecheck` — clean
- `pnpm --filter @comfyorg/website build` — 41 pages built clean
- `pnpm knip` — exit 0
- `oxfmt --check` and `oxlint` clean on all changed files
- `bash -n` on `process-videos.sh` clean; usage and missing-deps paths
exercised manually
- Manual: home page and `/gallery` rendered via `astro dev` — both
unchanged with zero console errors (screenshots attached)
## Review feedback addressed
After Oracle review, three follow-up commits land:
- **`SiteVideo` reactivity** — `sources` is now `computed`; the
`<video>` is keyed on the joined source URLs so it remounts when the
source set changes (browsers don't reload on `<source>` mutation).
- **`SiteVideo` accessibility** — `aria-hidden="true"` only when truly
decorative (no `alt` and no `controls`).
- **Shell script robustness** — probes duration with `ffprobe` and falls
back to `t=0` for clips shorter than 1s; enables `nocaseglob` so
`CLIP.MP4` is picked up.
- **Docs** — clarifies when to use `<SiteVideo>` (lightweight
multi-source) vs `<VideoPlayer>` (captions, controls, scrubber).
## Out of scope (follow-ups)
- Converting existing pages (`HeroSection`, customer detail heros,
gallery) to use the new components. Most current images are CDN-hosted
and migrating them is a separate decision.
- Re-encoding the gallery videos at a higher source width to actually
fix the blurriness — that requires the team to run `process-videos.sh`
against the source clips and re-upload.
- Combining `<SiteVideo>`'s multi-source support with `<VideoPlayer>`'s
rich chrome.
## Screenshots


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11869-feat-website-add-responsive-media-tooling-for-marketing-assets-3556d73d3650818899c7f9ed3204c9a5)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
|
||
|
|
7abd9d12c8 |
chore(website): refresh Ashby roles snapshot (#11851)
Automated refresh of `apps/website/src/data/ashby-roles.snapshot.json` from the Ashby job board API. **Flow:** 1. `Release: Website` workflow ran (manual trigger). 2. This PR opens with the regenerated snapshot. 3. `CI: Vercel Website Preview` deploys a preview for review. 4. Merging to `main` triggers the production Vercel deploy. The snapshot fallback in `apps/website/src/utils/ashby.ts` remains intact: builds without `WEBSITE_ASHBY_API_KEY` continue to use the committed snapshot. Triggered by workflow run `25260868155`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11851-chore-website-refresh-Ashby-roles-snapshot-3546d73d365081579f98f13f7b58e611) by [Unito](https://www.unito.io) Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> |
||
|
|
dd9cb42fa1 |
feat: add Run your first workflow button to home hero (#11848)
## Summary Add an outline-style `BrandButton` to the right side of the home page hero section linking to the workflows page. ## Changes - **What**: - Added a `Run your first workflow` outline button below the subtitle in `apps/website/src/components/home/HeroSection.vue`, linking to `externalLinks.workflows`. Mirrors the button pattern from `product/local/HeroSection.vue`. - Added `hero.runFirstWorkflow` i18n entry (en + zh-CN) in `apps/website/src/i18n/translations.ts`. ## Review Focus - Confirmed alignment with design spec. <img width="1505" height="776" alt="image" src="https://github.com/user-attachments/assets/215e667d-1827-447b-99b8-eba8cb5ec7e3" /> <img width="335" height="700" alt="image" src="https://github.com/user-attachments/assets/aeac0876-74c3-4e12-a4b3-203f9e541bc2" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11848-feat-add-Run-your-first-workflow-button-to-home-hero-3546d73d365081358d54eddfda71111e) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
809fba7b36 |
feat: add Groove Jones customer story (#11849)
## Summary Add a new customer story for Groove Jones — Crocs x NFL FOOH holiday campaign for Dick's Sporting Goods, delivered with Comfy. ## Changes - **What**: - New entry in [`apps/website/src/config/customerStories.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/config/customerStories.ts) registering slug `groove-jones` with cover image hosted on `media.comfy.org/website/customers/groove-jones/`. - Added `customers.story.groove-jones.{category,title,body}` and `customers.detail.groove-jones.topic-1` … `topic-10` translations (en + zh-CN) in [`apps/website/src/i18n/translations.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/i18n/translations.ts). 10 sections matching design sidebar: INTRO, THE OUTPUT, THE PROBLEM, HOW COMFY SOLVED THE PROBLEM, BRAND-TRAINED LORAS, MULTI-MODEL ORCHESTRATION, THE PIPELINE, VERSION CONTROL, FINISHING IN NUKE, THE TAKEAWAY. - Includes 2 pull quotes (Doug Hogan, Dale Carman), 1 final blockquote + author card, and 3 inline images. - Routes `/customers/groove-jones` and `/zh-CN/customers/groove-jones` are auto-generated by `[slug].astro`. ## Review Focus - Contributors author card uses `TBD` placeholder names/roles — to be filled in. - No `readMoreHref` set yet (no public blog post URL). - All 4 images uploaded to `gs://comfy-org-videos/website/customers/groove-jones/` and served via `media.comfy.org`. <img width="1000" height="535" alt="Kapture 2026-05-02 at 23 17 04" src="https://github.com/user-attachments/assets/28654d24-0d49-4303-82ac-b6923cd6bc93" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11849-feat-add-Groove-Jones-customer-story-3546d73d36508128a64bd6809ad77447) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
3c7781190a |
feat(website): add llms.txt for GEO discovery by AI search agents (#11830)
## Summary Adds `/llms.txt` at the apex following the [llms.txt standard](https://llmstxt.org) — a curated, link-based markdown file that tells LLM-based search agents (ChatGPT search, Perplexity, Claude search, Google AI Overviews, etc.) what's most important on the site. It complements `robots.txt` (crawler permissions) and `sitemap-index.xml` (URL inventory) by giving AI agents a short, prose-friendly index they can ingest into a context window. ## What's in the file 28 links across 6 sections: - **Product** (6) — homepage, Local download, Cloud, Cloud pricing, API, Enterprise - **Workflows and Gallery** (2) — gallery + community workflows site - **Customers and Case Studies** (5) — customers index + 4 named studios (Series Entertainment, Moment Factory, Ubisoft Chord, Open Story Movement) - **Developers and Documentation** (4) — docs.comfy.org, ComfyUI repo, Comfy-Org GitHub org, registry.comfy.org - **Company** (6) — about, careers, contact, blog, privacy, terms - **Optional** (5) — `zh-CN` locale variant, long-form enterprise case studies, blog posts (de-prioritized per spec — agents can skip if context-limited) The intro paragraph names the four product surfaces (Local, Cloud, API, Enterprise), the named customers, and the use-case industries (VFX & animation, advertising, gaming, eCommerce/fashion) — so an agent that ingests only the prose still gets the elevator pitch. ## Verification - All 28 URLs verified live (`HTTP 200`) before commit. - File is plain markdown — no build step. Astro/Vercel will serve it from `apps/website/public/llms.txt` exactly as it serves `robots.txt` (which lives in the same directory and ships at `https://comfy.org/robots.txt`). - Will verify on the Vercel preview deploy after this PR opens that `curl -sI https://<preview>/llms.txt` returns `200` with a sensible `content-type`. (`robots.txt` currently serves as `text/plain; charset=utf-8` — `.txt` will likely do the same; that's fine for AI agents.) ## Decisions - **No `llms-full.txt` yet.** That variant inlines full prose of key pages and requires curating substantive content. Deferred to a follow-up — the marketing-site pages are mostly Vue-rendered hero/feature blocks rather than long-form prose, so a meaningful `llms-full.txt` would need either dedicated copy or a build step that flattens i18n strings + section text. Tracking separately. - **No comment line in `robots.txt`.** I considered adding a `# AI agents: see /llms.txt` comment above the `Sitemap:` directive, but decided against it: (a) the convention is to probe the well-known path `/llms.txt` directly, not to discover it via robots.txt; (b) `robots.txt` was just polished in #11823 with a deliberate compact design and adding a non-standard comment would muddy that; (c) zero implementations I checked actually parse robots.txt for llms.txt hints. Easy to add later if needed. ## Context Third of three follow-ups from the SEO/GEO sweep on 2026-05-02: 1. ~~Comfy-Router: add `X-Content-Type-Options: nosniff` to apex security headers~~ (separate PR on `Comfy-Org/comfy-router`) 2. ~~Cloudflare: enable "Always Use HTTPS"~~ (dashboard toggle, no PR) 3. **This PR** — add `llms.txt` for GEO discovery ## Testing - [x] All linked URLs return 200 - [x] File parses as valid markdown - [ ] Preview deploy serves `/llms.txt` (will verify once preview is up) ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11830-feat-website-add-llms-txt-for-GEO-discovery-by-AI-search-agents-3546d73d365081a98c6bfc5301699f64) by [Unito](https://www.unito.io) |
||
|
|
167a1e6a0c |
fix(website): override X-Robots-Tag to index,follow on production deployment (#11831)
## P0 SEO fix — entire marketing site is currently `noindex` A deep-audit sweep on **2026-05-02** confirmed that every page on `comfy.org` (home, `/about`, `/pricing`, `/customers`, `/careers`, …) is being served with: ``` x-robots-tag: noindex ``` This hides the entire marketing site from Google and other search engines. ### Root cause `comfy.org` reaches the Astro marketing site via a Cloudflare Worker reverse proxy ([`comfy-router`](https://github.com/Comfy-Org/comfy-router)) that does: ```js fetch('https://website-frontend-comfyui.vercel.app/...') ``` Per Vercel's KB article [Avoiding duplicate-content with vercel.app URLs](https://vercel.com/kb/guide/avoiding-duplicate-content-with-vercel-app-urls): > By default, Vercel adds an `X-Robots-Tag: noindex` HTTP header to all deployments hosted on `vercel.app` URLs. […] This header tells search engines like Google not to index these deployment URLs. Because `website-frontend-comfyui.vercel.app` is **not** registered as a Production custom domain on the Vercel project, Vercel applies that header — and our Worker faithfully forwards it back to `comfy.org` clients (and Googlebot). ### Fix Vercel's documented workaround for proxied `*.vercel.app` setups is to override the header via `vercel.json` ([blog post by Dan Denney](https://www.dandenney.com/posts/front-end-dev/fixing-x-robots-nofollow-with-vercel/)): ```json "headers": [ { "source": "/(.*)", "has": [ { "type": "host", "value": "website-frontend-comfyui.vercel.app" } ], "headers": [ { "key": "X-Robots-Tag", "value": "index, follow" } ] } ] ``` ### Why the `has` host filter Critical scoping detail: without the `has` filter, the override would also apply to PR-preview deployments at `comfy-website-preview-pr-N.vercel.app`. We want previews to **stay** `noindex` to avoid duplicate-content competition with production. The filter pins the override to the production deployment hostname only. The hostname matches `WEBSITE_ORIGIN` in `comfy-router/src/index.js`: ```js const WEBSITE_ORIGIN = 'https://website-frontend-comfyui.vercel.app'; ``` ### Defense in depth A parallel PR on `comfy-router` (TBD) will also strip `X-Robots-Tag: noindex` at the Worker layer, so the public `comfy.org` response is correct even if a future Vercel project change re-introduces the upstream header. ### Verification (after merge + Vercel production deploy) ```bash # Production should no longer be noindex curl -sI https://comfy.org/ | grep -i x-robots-tag curl -sI https://comfy.org/about | grep -i x-robots-tag curl -sI https://comfy.org/pricing | grep -i x-robots-tag # Expect: empty output, OR "x-robots-tag: index, follow" # Direct Vercel production hostname curl -sI https://website-frontend-comfyui.vercel.app/ | grep -i x-robots-tag # Expect: "x-robots-tag: index, follow" # Preview deploys must stay noindex (proves the host filter works) curl -sI https://comfy-website-preview-pr-<N>.vercel.app/ | grep -i x-robots-tag # Expect: "x-robots-tag: noindex" ``` ### Pre-merge state (for the record) ``` $ curl -sI https://comfy.org/ | grep -iE 'x-robots-tag|x-served-by' x-served-by: vercel-website x-robots-tag: noindex ``` ### Scope Minimum delta — only `apps/website/vercel.json`. No other files touched. ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11831-fix-website-override-X-Robots-Tag-to-index-follow-on-production-deployment-3546d73d365081489b62e6633d25dfe5) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <christian@comfy.org> Co-authored-by: GitHub Action <action@github.com> |
||
|
|
e831daae59 |
feat(website): point robots.txt at /sitemap-index.xml + AI crawler rules (#11823)
## Summary Once [comfy-router#22](https://github.com/Comfy-Org/comfy-router/pull/22) ships, `comfy.org/sitemap-index.xml` will return a unified index aggregating both the website (38 URLs) and workflow-templates sitemaps. This PR: 1. Reverts `Sitemap:` back to `/sitemap-index.xml` (was `/sitemap-0.xml` in #11802 as a workaround for the 404). 2. Adds explicit allow records for 21 search and AI/LLM crawlers (GPTBot, ChatGPT-User, OAI-SearchBot, Google-Extended, ClaudeBot, Claude-Web, anthropic-ai, PerplexityBot, Perplexity-User, Applebot-Extended, Bytespider, Amazonbot, CCBot, Meta-ExternalAgent, Meta-ExternalFetcher, Diffbot, etc.). 3. Adds `Disallow:` for `/_astro/`, `/_website/`, `/_vercel/` — Vercel build artifacts that aren't useful to crawl. ## Why granular UAs Stacked `User-agent:` records (per [RFC 9309 §2.2](https://datatracker.ietf.org/doc/html/rfc9309#section-2.2)) share one rule block. Listing each bot explicitly: - Signals intent to AI bots that look for their UA in robots.txt before crawling more aggressively. - Surfaces our crawl policy clearly to anyone inspecting the file. - Lets us add per-bot Disallows in future without restructuring. ## Merge order ⚠️ **Do NOT merge until comfy-router#22 is deployed to production.** Until then, `/sitemap-index.xml` returns 404 and this PR would re-break the issue PR #11802 patched. Verification: ```bash curl -sI https://comfy.org/sitemap-index.xml # expect: HTTP/2 200, x-served-by: worker-sitemap-index ``` Once that returns 200, this is safe to merge. ## Verification (after merge + deploy) ```bash # robots.txt is served and points at the unified index curl -s https://comfy.org/robots.txt | grep '^Sitemap:' # → Sitemap: https://comfy.org/sitemap-index.xml # Each AI crawler can fetch it for ua in 'GPTBot/1.0' 'ClaudeBot/1.0' 'PerplexityBot/1.0' 'Google-Extended' 'Applebot-Extended'; do curl -s -o /dev/null -w "$ua → %{http_code}\n" -A "$ua" https://comfy.org/robots.txt done # Sitemap is reachable from robots.txt SITEMAP=$(curl -s https://comfy.org/robots.txt | awk -F': ' '/^Sitemap:/ {print $2}') curl -s "$SITEMAP" | xmllint --noout - && echo "valid XML" ``` ## Linear / closes - Closes FE-437 (AI crawler rules) - Updates FE-432 — the robots.txt change in #11802 was a workaround that's no longer needed once #22 ships ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11823-feat-website-point-robots-txt-at-sitemap-index-xml-AI-crawler-rules-3546d73d3650811dbceedd06c00db444) by [Unito](https://www.unito.io) |
||
|
|
4ed00cec08 |
update: robots.txt to point to /sitemap-0.xml (#11802)
## Summary <!-- One sentence describing what changed and why. --> robots.txt at [comfy.org](https://comfy.org/) references /sitemap-index.xml which returns 404. The actual working sitemap is at /sitemap-0.xml (200, 38 URLs). This blocks search engines from discovering the sitemap. ## Changes - **What**: <!-- Core functionality added/modified --> - Update robots.txt to point to /sitemap-0.xml, OR ## Review Focus <!-- Critical design decisions or edge cases that need attention --> <!-- If this PR fixes an issue, uncomment and update the line below --> <!-- Fixes #ISSUE_NUMBER --> ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes --> ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11802-update-robots-txt-to-point-to-sitemap-0-xml-3536d73d365081bb9545eb96dd1e8025) by [Unito](https://www.unito.io) |
||
|
|
ef98ba0e8f |
feat: add plum/ink color primitives and standardize design tokens (#11139)
*PR Created by the Glary-Bot Agent* --- ## Summary Adds new `plum` and `ink` color scales for Comfy Hub branding and standardizes existing tokens to align with current Figma design system. ### Changes **Phase 1 — New primitives** (`_palette.css`) - Added `plum-300/400/500/600` and `ink-100` through `ink-900` **Phase 2 — Token cleanup** (`style.css`) - Removed deprecated `slate-100/200/300` primitives (cool blue-grey, removed from Figma) - Removed duplicate `graphite-400` (identical hex to slate-100) - Dark mode: migrated 6 slate/graphite references to muted-foreground, smoke-700, smoke-800, charcoal-200 - Light mode: replaced 3 `ash-500` references with `smoke-800` per designer alignment ### Token migration detail | Dark mode token | Old value | New value | Rationale | |---|---|---|---| | `--node-component-header-icon` | slate-300 (#5b5e7d) | muted-foreground (smoke-800) | Figma `node/foreground-secondary` | | `--node-component-slot-text` | slate-200 (#9fa2bd) | smoke-700 (#a0a0a0) | Lighter neutral for text contrast | | `--node-component-surface-highlight` | slate-100 (#9c9eab) | smoke-800 (#8a8a8a) | Neutral grey highlight | | `--node-component-tooltip-border` | slate-300 (#5b5e7d) | charcoal-200 (#494a50) | Consistent with dark border tokens | | `--text-secondary` | slate-100 (#9c9eab) | smoke-700 (#a0a0a0) | Adequate contrast on dark surfaces | | `--widget-background-highlighted` | graphite-400 (#9c9eab) | smoke-800 (#8a8a8a) | Removed duplicate, neutral replacement | ### Visual note These changes shift some dark mode colors from cool blue-grey to neutral grey. This is intentional per the design team. The `--node-component-surface-highlight` and `--node-component-tooltip-border` tokens should be QA'd as the designer noted. ### Not included (Phase 3) Hub Dark overlay theme will ship separately once the Hub UI work is ready to validate against. ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11139-feat-add-plum-ink-color-primitives-and-standardize-design-tokens-33e6d73d365081418e13e0efe6161fb5) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
a934056246 |
feat(website): add PostHog analytics (#11735)
## Summary Adds PostHog page analytics to the marketing website (`apps/website/`). ## Changes - **What**: New `posthog.ts` script with `initPostHog`/`capturePageview`. Wired into `BaseLayout.astro` behind `import.meta.env.PROD` (mirroring the GTM gate). Pageviews are captured on every `astro:page-load` so ClientRouter view-transition navigations are tracked, not just hard reloads. - **Dependencies**: `posthog-js` (already in the workspace catalog at `^1.358.1`; previously used by the workbench telemetry provider). ## Review Focus - API host is set to `https://t.comfy.org` to match `src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.ts` — confirm that proxy is OK to share with the website surface. - Project token is hard-coded inline. It is a public `phc_…` frontend token (designed to ship to clients); this matches the pattern used for `gtmId` in the same file. Happy to switch to a `PUBLIC_POSTHOG_KEY` env var if preferred. - `person_profiles: 'identified_only'` to avoid creating profiles for every anonymous visitor — flag if you want full anonymous tracking instead. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11735-feat-website-add-PostHog-analytics-3516d73d3650811189c6d64c3af4ded9) by [Unito](https://www.unito.io) |
||
|
|
17c18b0707 |
fix: embed HubSpot contact form (#11723)
## Summary Embed the HubSpot-hosted contact sales form on `/contact` and `/zh-CN/contact` so HubSpot owns submission handling, validation, anti-spam/security updates, tracking context, and form configuration. ## Changes - **What**: Replaces the custom local contact form stub with a HubSpot embed component using the HubSpot-hosted developer/raw HTML script and `hs-form-html` container. - **Localization**: Uses the existing English form ID by default and switches to the zh-CN form ID for `/zh-CN/contact`. - **Styling**: Applies HubSpot form CSS custom properties to match the Comfy contact page colors and `PP Formula` font more closely. - **Docs**: Updates the website README with the developer embed snippet and the zh-CN form ID. - **Dependencies**: None. ## Why Embedded Form - HubSpot docs say forms should be loaded with the HubSpot-hosted JavaScript file, and that security, anti-spam, accessibility, and performance improvements will not propagate if the embed runtime is copied or self-hosted: https://developers.hubspot.com/docs/cms/start-building/building-blocks/modules/forms - The direct form submission endpoint is documented under `v3 legacy`: https://developers.hubspot.com/docs/api-reference/legacy/marketing/forms/v3-legacy/submit-data-unauthenticated - HubSpot’s legacy API overview says numeric-versioned APIs are legacy and will be deprecated in a future release: https://developers.hubspot.com/docs/api-reference/legacy/overview ## Review Focus - Confirm the portal ID and form IDs are correct: - `en`: `94e05eab-1373-47f7-ab5e-d84f9e6aa262` - `zh-CN`: `6885750c-02ef-4aa2-ba0d-213be9cccf93` - Check visual fit on `/contact` and `/zh-CN/contact`, especially font, background, inputs, radio controls, and submit button. - Confirm the developer/raw HTML embed remains the preferred integration over a custom Forms API POST. ## Local Checks - `pnpm exec oxfmt --check apps/website/src/components/contact/HubspotFormEmbed.vue apps/website/README.md` - `pnpm exec eslint apps/website/src/components/contact/HubspotFormEmbed.vue` - `pnpm --filter @comfyorg/website typecheck` - `pnpm --filter @comfyorg/website test:unit` - `pnpm --filter @comfyorg/website build` - Commit hooks: stylelint, oxfmt, oxlint, eslint, `pnpm typecheck`, `pnpm typecheck:website` - Push hook: `pnpm knip --cache` Build completed with existing non-fatal environment warnings: Node `v25.8.1` vs requested `24.x`, unresolved website font paths deferred to runtime, `transformWithEsbuild` deprecation, and missing Ashby env falling back to the committed snapshot. Incredibly, during the taking of these screenshots, I discovered a bug in macos, where despite the snapshot/record bar not existing, from me esc'ing out, some of the tooltips persist. Closing and reopening the lid did not fix this. I didn't see the process in activity monitor. <img width="1512" height="862" alt="Screenshot 2026-04-29 at 7 09 55 PM" src="https://github.com/user-attachments/assets/92518795-6845-4b34-8da3-54048b440eb1" /> <img width="1512" height="862" alt="Screenshot 2026-04-29 at 7 13 18 PM" src="https://github.com/user-attachments/assets/f7609e58-898d-413c-975c-b02b70b84e73" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11723-fix-embed-HubSpot-contact-form-3506d73d365081528bfbe4b024c2a21f) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com> |
||
|
|
810381ab63 |
Stabilize website GitHub stars in visual snapshots (#11771)
## Summary Stabilize the website nav GitHub star count in visual-test builds so snapshot comparisons do not drift as the live GitHub count changes. ## Changes - **What**: Added `WEBSITE_GITHUB_STARS_OVERRIDE` for build-time star-count overrides and set it to `111000` in the website E2E and screenshot-update workflows. - **Dependencies**: None. ## Review Focus Confirm the deterministic build-time override is preferable to screenshot masking, since Playwright masks draw a colored rectangle whose geometry can also drift when masked content changes size. ## Screenshots (if applicable) Not included; this keeps visual-test input data stable rather than changing the UI. |
||
|
|
eb8f8b75b5 |
fix: correct zh-CN translations across landing, product, and pricing pages (#11655)
*PR Created by the Glary-Bot Agent* --- ## Summary Applies translation corrections to the Chinese (zh-CN) version of the website, requested in the `#project-new-website-brand-refresh` Slack thread by a native-speaker reviewer. ### Changes (in `apps/website/src/i18n/translations.ts` + `apps/website/src/pages/zh-CN/index.astro`) - **Landing — blog section badges**: `如何` → `了解`, `运作` → `运行方式` - **Landing — hero headline**: `专业控制` → `最强可控性` (also updates the zh-CN page `<title>`) - **Landing — hero subtitle**: `Comfy 是面向视觉专业人士的 AI 创作引擎,让您掌控每个模型、每个参数和每个输出。` → `Comfy 是面向专业视觉人士的 AI 创作引擎。您可以精确掌控每个模型、每个参数和每个输出。` - **Landing — showcase subtitle**: `从社区模板开始,或从零构建。` → `从工作流模板开始,或从零构建。` - **Landing — showcase feature1 title**: `节点式完全控制` → `节点带来的可控性` - **Landing — use case body**: `由 60,000+ 节点、数千个工作流 和一个比任何公司都更快构建的社区驱动。` → `60,000+ 节点,数千条工作流,一个比任何公司速度都更快的社区。` - **All `查看xx特性` CTAs** (local / cloud / API / enterprise product cards): `特性` → `属性` - **All `合作节点` pricing copy**: `合作节点` → `合作伙伴节点` (correct translation for "partner node") ### Verification - `pnpm typecheck` (astro check): 0 errors, 0 warnings, 0 hints - `pnpm build`: completes successfully; rebuilt zh-CN pages contain the new strings and no longer contain the old ones - Manual Playwright verification on `/zh-CN/` (hero, showcase badges, showcase feature card, use-case body, product cards) and `/zh-CN/cloud/pricing/` (`合作伙伴节点` appears 4×, `合作节点` appears 0×) ### Notes on review feedback A review pass flagged two of the swaps (`特性→属性` and `从社区模板→从工作流模板`) as potential style concerns. Both changes are kept as-is because they were specified verbatim by the native-speaker reviewer who requested this pass. ## Screenshots     ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11655-fix-correct-zh-CN-translations-across-landing-product-and-pricing-pages-34e6d73d3650816daddde4a90fb47a01) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |