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

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

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

Other:
- H1 now reads "{displayName} in ComfyUI" (FE-421 spec)
- Remove description prop from hero (redundant with What-is section)
- Fix GH Actions discovery: m.slug field now matches generator output
- Update add-model-page skill to document new 3-file architecture
2026-05-04 23:08:56 +00:00
..

Website Scripts

refresh-ashby-snapshot.ts

Pulls the latest job postings from Ashby and writes src/data/ashby-roles.snapshot.json. Invoked by the Release: Website GitHub Actions workflow; also runnable locally via pnpm --filter @comfyorg/website ashby:refresh-snapshot.

process-videos.sh

Generates multi-resolution VP9/WebM + H.264/MP4 variants and a poster frame for marketing videos using ffmpeg. Run locally before uploading the outputs to media.comfy.org; this is not wired into CI.

apps/website/scripts/process-videos.sh \
  ./video-sources \
  ./dist/videos \
  "640 960 1280 1920"

Output

For each source video at ./video-sources/foo.mp4, you get:

foo-640.webm   foo-640.mp4
foo-960.webm   foo-960.mp4
foo-1280.webm  foo-1280.mp4
foo-1920.webm  foo-1920.mp4
foo-poster.jpg

The naming convention is enforced by buildVideoSources() in src/utils/video.ts, which the <SiteVideo> Vue component uses to emit <source> URLs.

Pairing with <SiteVideo>

Once the assets are uploaded, render them with:

<SiteVideo
  name="foo"
  base-url="https://media.comfy.org/website/marketing"
  :width="1280"
  :formats="['webm', 'mp4']"
  poster="https://media.comfy.org/website/marketing/foo-poster.jpg"
  autoplay
  loop
/>

<SiteVideo> vs <VideoPlayer>

  • SiteVideo — lightweight multi-source <video> for decorative or autoplay marketing clips. No custom controls, no captions UI.
  • VideoPlayer — full-featured player with custom scrubber, mute, fullscreen, and caption toggles. Use this for content with subtitles or user-driven playback.

If you need both responsive sources and the rich VideoPlayer chrome, the two are not yet combined; either pick one or extend VideoPlayer to accept a source list.

Encoder choices

  • VP9/WebM at CRF 32 — preferred by Chrome and Firefox; smaller files.
  • H.264/MP4 at CRF 23, High profile, +faststart — universal fallback, required for Safari iOS.
  • Poster JPG at q4 — extracted from t=1s when the clip is long enough, otherwise t=0; scaled to 1280w. Use this as the poster attribute so the video shows something while loading.

Why a single resolution per video

<source media="..."> inside <video> is unreliable across browsers (Safari ignores it). The simplest correct strategy is to ship one well-sized resolution and let CSS scale it down on smaller viewports. The script generates multiple widths so you can pick a different one per page (e.g. 1280w for a hero, 640w for a thumbnail), or wire up JavaScript-based selection later if metrics demand it.