From cb5ac8b7309530680f99aa83b6548f718721ff13 Mon Sep 17 00:00:00 2001 From: Vivek Date: Tue, 8 Sep 2026 09:17:22 +0530 Subject: [PATCH 01/14] fix(website): drop the intro video and the AI-first lede The landing page no longer carries the intro video. The bytes stay in the R2 bucket, so restoring the section later is an editorial call rather than a re-upload. "AI-first" comes out of the one-line definition on the landing page, /why-webjs and /what-is-webjs. It leads with what WebJs is instead. The sentence is duplicated across the visible lede, the meta description and the OG-image generator on each page, so all three move together and the cards are regenerated to match. The positioning is not retired: the /what-is-webjs FAQ entry and capability card that explain it stay. /why-webjs also gains "web components" in its category line, which is the one differentiator the shortest version of the sentence was dropping. --- website/app/layout.ts | 2 +- website/app/page.ts | 92 +--------------------- website/app/what-is-webjs/page.ts | 8 +- website/app/why-webjs/page.ts | 4 +- website/public/og-what.png | Bin 118760 -> 114824 bytes website/public/og-why.png | Bin 139018 -> 132449 bytes website/public/og.png | Bin 133552 -> 129496 bytes website/scripts/generate-og-what.mjs | 2 +- website/scripts/generate-og-why.mjs | 2 +- website/scripts/generate-og.mjs | 2 +- website/test/ssr/intro-video-ssr.test.ts | 66 ---------------- website/test/ssr/landing-copy-ssr.test.ts | 38 +++++++++ website/test/ssr/why-webjs-ssr.test.ts | 2 +- 13 files changed, 51 insertions(+), 167 deletions(-) delete mode 100644 website/test/ssr/intro-video-ssr.test.ts create mode 100644 website/test/ssr/landing-copy-ssr.test.ts diff --git a/website/app/layout.ts b/website/app/layout.ts index 011866707..152f891d2 100644 --- a/website/app/layout.ts +++ b/website/app/layout.ts @@ -43,7 +43,7 @@ const TITLE = 'WebJs: Full-stack web components framework, no build step'; // The true version of that idea is about LOCATION, not volume: the source sits // in the app's own node_modules at the installed version, so an agent opens // the file it needs instead of recalling an API from training data. -const DESCRIPTION = 'An AI-first full-stack JavaScript web components framework with no build step. Production-ready architecture from your very first prompt. Node 24+ or Bun.'; +const DESCRIPTION = 'A full-stack JavaScript web components framework with no build step. Production-ready architecture from your very first prompt. Node 24+ or Bun.'; const NAV = [ { label: 'Docs', href: DOCS_START_PATH, ext: false }, diff --git a/website/app/page.ts b/website/app/page.ts index 69df58a60..acc988bb7 100644 --- a/website/app/page.ts +++ b/website/app/page.ts @@ -42,7 +42,7 @@ export const metadata = { '@id': `${SITE_URL}#website`, name: 'WebJs', url: SITE_URL, - description: 'An AI-first, web-components-first full-stack web framework with no build step.', + description: 'A web-components-first full-stack web framework with no build step.', publisher: { '@id': `${SITE_URL}#organization` }, }, { @@ -246,92 +246,6 @@ function sourceWindow(title: string, sample: string) { `; } -/** - * The landing page's intro video, self-hosted rather than embedded. - * - * The player is the browser's own, so it works with scripting disabled. The - * YouTube iframe this replaced could not, because its player needs JS inside - * the frame, so the section used to hide itself from a JS-off reader rather - * than show a broken embed. - * - * REPLACING THE VIDEO, for whoever does it next. - * - * The bytes live in the Cloudflare R2 bucket `webjs-videos`, served from - * videos.webjs.dev. The key carries no version, so a new cut overwrites - * `intro.mp4` in place and nothing in this file changes: - * - * env -u CLOUDFLARE_API_TOKEN npx wrangler r2 object put \ - * webjs-videos/intro.mp4 --file \ - * --content-type video/mp4 \ - * --cache-control "public, max-age=86400, s-maxage=31536000" \ - * --remote - * - * Then purge that URL at the edge (Caching, then Purge Cache, then the custom - * single-file purge), or the old bytes keep serving for the `s-maxage` year. - * - * Three things about this are easy to get wrong. - * - * 1. R2 object metadata cannot be edited after upload. `Cache-Control` is set - * at write time or not at all, so every upload has to pass it again. There - * is no bucket-level setting, and the dashboard uploader has no field for - * it, which is why an upload made there serves no header of its own. - * - * 2. The `env -u` is load bearing. A `CLOUDFLARE_API_TOKEN` in the environment - * overrides wrangler's OAuth credentials, and that token carries no R2 - * permission, so the upload fails with an authentication error that names - * nothing. Unsetting it for the one call falls back to the OAuth login. - * - * 3. A purge clears the edge and never a browser. That is why `max-age` is a - * day rather than a year, and why the header is deliberately not - * `immutable`: anyone holding the old file needs a way to pick the new one - * up, and 24 hours is that way. `s-maxage` keeps the edge copy long lived - * regardless, since the edge can be purged and a browser cannot. - * - * A versioned key (`intro-2026-08-21.mp4`) is the other valid shape. Take it - * and the tradeoff inverts: put `immutable` back, raise `max-age` to a year, - * and update the src below on every cut. - * - * The thumbnail at `intro-thumbnail.webp` is uploaded the same way, with - * `--content-type image/webp`. It is 1920 wide because the box is capped at - * max-w-3xl (about 718 CSS px), so that already covers a 2x display and a - * wider encode buys nothing a viewport can show. - */ -const INTRO_VIDEO = html` -
-
- -
- -
-
-
-`; - - export default function LandingPage() { return html`