diff --git a/website/app/layout.ts b/website/app/layout.ts index 30c0225d3..bb1513dbe 100644 --- a/website/app/layout.ts +++ b/website/app/layout.ts @@ -18,11 +18,7 @@ import { siteFooter } from '#lib/site-footer.ts'; */ const TITLE = 'WebJs - The Web Framework for AI Agents'; -const DESCRIPTION = 'A model-agnostic full-stack web framework that needs no training data. An agent reads the whole stack end to end, so small models and large ones both ship production-ready architecture and a design system from the very first line of code. Web components, SSR, progressive enhancement, file-based routing, and server actions, with zero build step. Runs on Node 24+ or Bun.'; -// Describes what the social card itself SAYS (public/og.png), which is the -// benefit-led line, not the page title. Kept in lockstep with the headline in -// scripts/generate-og.mjs. -const OG_IMAGE_ALT = 'WebJs, any AI model produces production-ready code'; +const DESCRIPTION = 'A full-stack web framework built on web components, SSR, and progressive enhancement, with zero build step. Lean enough for AI agents to read end to end. File-based routing, server actions, and streaming SSR on web standards. Runs on Node 24+ or Bun.'; const NAV = [ { label: 'Docs', href: DOCS_URL + '/docs/getting-started', ext: true }, @@ -64,7 +60,7 @@ export function generateMetadata(ctx: { url: string }) { image, 'image:width': '1200', 'image:height': '630', - 'image:alt': OG_IMAGE_ALT, + 'image:alt': TITLE, 'site_name': 'WebJs', }, twitter: { card: 'summary_large_image', title: TITLE, description: DESCRIPTION, image }, diff --git a/website/app/page.ts b/website/app/page.ts index 7e364c6fd..c0ebf3c6f 100644 --- a/website/app/page.ts +++ b/website/app/page.ts @@ -32,7 +32,7 @@ export const metadata = { '@type': 'WebSite', name: 'WebJs', url: SITE_URL, - description: 'A model-agnostic, web-components-first full-stack web framework with no build step, readable end to end by any AI model without training data.', + description: 'An AI-first, web-components-first full-stack web framework with no build step.', }, { '@context': 'https://schema.org', @@ -159,15 +159,13 @@ export default function LandingPage() {
-

- Production-ready code from any AI model +

+ The web framework for AI agents

- WebJs is a full-stack web framework that needs no training data. An - agent reads the whole stack end to end, so small models and large ones - both ship production-ready architecture and a design system from the - very first line of code. Web components and SSR, zero build step, on - Node 24+ or Bun. + WebJs is a full-stack framework built on web components, SSR, and + progressive enhancement, with zero build step. Standards that outlast + frameworks. Runs on Node 24+ or Bun.

@@ -333,9 +331,9 @@ export default function LandingPage() {
${STATS.map(s => html` diff --git a/website/app/why/page.ts b/website/app/why/page.ts index 8b3b42823..581163900 100644 --- a/website/app/why/page.ts +++ b/website/app/why/page.ts @@ -34,7 +34,7 @@ export function generateMetadata(ctx: { url: string }) { image, 'image:width': '1200', 'image:height': '630', - 'image:alt': 'Why WebJs, the model-agnostic web framework that needs no training data', + 'image:alt': 'Why WebJs, the framework your AI agent already understands', 'site_name': 'WebJs', }, twitter: { card: 'summary_large_image', title, description, image }, diff --git a/website/public/og-why.png b/website/public/og-why.png index c5569641c..efc60e721 100644 Binary files a/website/public/og-why.png and b/website/public/og-why.png differ diff --git a/website/public/og.png b/website/public/og.png index 84f053925..0efbbc5f4 100644 Binary files a/website/public/og.png and b/website/public/og.png differ diff --git a/website/scripts/generate-og-why.mjs b/website/scripts/generate-og-why.mjs index 00ca77ec2..999fd6de2 100644 --- a/website/scripts/generate-og-why.mjs +++ b/website/scripts/generate-og-why.mjs @@ -4,13 +4,7 @@ * A sibling of scripts/generate-og.mjs (the home-page card): same dark, on-brand * look and the same render pipeline (headless Chromium at 2x, downscaled to an * exact 1200x630 with ImageMagick for crisp text), but with the pitch page's - * headline and tags. - * - * Like the home card, the copy leads with the BENEFIT (any model, small or - * large, produces production-ready code because no training data is required) - * and keeps only the two technical facts that make the claim credible. The full - * argument lives on /why. The card has to earn the click first. Run it whenever - * the /why headline or look changes: + * AI-era headline and tags. Run it whenever the /why headline or look changes: * * node scripts/generate-og-why.mjs * @@ -92,7 +86,7 @@ const html = ` } .sub{ font-size:22px; line-height:1.4; color:${T.fgMuted}; font-weight:400; - max-width:46ch; margin-top:-12px; + max-width:34ch; margin-top:-14px; } .sub b{ color:${T.fg}; font-weight:600; } .accent{ @@ -132,26 +126,26 @@ const html = `
webjs
-
Why WebJs
+
Built for the AI era
-

The model-agnostic web framework

-
No training data required. Point any model at it, small or large, and get production-ready code.
+

The framework your AI agent already understands

+
A full-stack JavaScript framework your AI agent can read end to end.
-
01 Any model works
-
The whole framework is plain JS in node_modules. An agent reads it into context and learns the real API instead of guessing.
+
01 Framework source
+
No build, node_modules holds plain JS. The agent reads the whole framework and fits it into context.
-
02 Code that ships
-
No build, so what you write is what runs. The agent debugs the running app against the real source, not a bundle.
+
02 Your app code
+
Served to the browser as written. The agent debugs the running app against the real source, not a bundle.

-
ANY MODEL  ·  NO TRAINING DATA  ·  NO BUILD
+
NO TRAINING DATA  ·  NO BUNDLER  ·  ANY MODEL
github.com/webjsdev/webjs
diff --git a/website/scripts/generate-og.mjs b/website/scripts/generate-og.mjs index ec712bdb0..658d5d5c3 100644 --- a/website/scripts/generate-og.mjs +++ b/website/scripts/generate-og.mjs @@ -13,14 +13,8 @@ * from node_modules. ImageMagick is the only external, non-npm tool. The card * mirrors the dark-theme design tokens declared in * app/layout.ts - * (background, foreground, accent, the warm accent glow), so a regenerated card - * always matches the live site's look. - * - * The copy is deliberately BENEFIT-led rather than a copy of the hero headline: - * a social card is read in a timeline by someone who has never heard of WebJs, - * so it answers "what do I get" (production-ready code out of any model, small - * or large, with no training data) before "how does it work". The mechanism - * lives on the page. The card sells the outcome. + * (background, foreground, accent, the warm accent glow) and the hero + * headline, so a regenerated card always matches the live site. */ import { chromium } from 'playwright'; import { execFileSync } from 'node:child_process'; @@ -84,11 +78,11 @@ const html = ` inset 0 1px 0 color-mix(in oklch, white 30%, transparent); } .word{ font-family:'Inter Tight',sans-serif; font-weight:700; font-size:31px; letter-spacing:-0.02em; } - .mid{ flex:1; display:flex; flex-direction:column; justify-content:center; gap:34px; padding-top:40px; } + .mid{ flex:1; display:flex; flex-direction:column; justify-content:center; } h1{ font-family:'Inter Tight',sans-serif; font-weight:800; - font-size:52px; line-height:1.05; letter-spacing:-0.035em; - max-width:20ch; + font-size:66px; line-height:1.05; letter-spacing:-0.035em; + max-width:18ch; } .accent{ white-space:nowrap; @@ -96,30 +90,9 @@ const html = ` -webkit-background-clip:text; background-clip:text; color:transparent; } p.lede{ - margin-top:-12px; max-width:80ch; - font-size:22px; line-height:1.4; color:${T.fgMuted}; - } - p.lede b{ color:${T.fg}; font-weight:600; } - /* Two benefit cards, sharing the /why card's grid so the two social cards - read as one system. The split here is deliberately broader than /why's - (which argues the model-agnostic case): this is the site-wide default card, - also serving /blog, /articles and /compare, so one card covers what the - agent gets and the other what the shipped app gets. */ - .cards{ display:grid; grid-template-columns:1fr 1fr; gap:20px; } - .card{ - border:1px solid ${T.border}; border-radius:18px; - background:color-mix(in oklch, ${T.bgDeep} 60%, transparent); - padding:24px 26px; display:flex; flex-direction:column; gap:12px; + margin-top:26px; max-width:30ch; + font-size:25px; line-height:1.5; color:${T.fgMuted}; } - .clabel{ - display:flex; align-items:center; gap:9px; - font-family:'JetBrains Mono',monospace; font-weight:500; - font-size:14px; letter-spacing:0.1em; text-transform:uppercase; color:${T.accent}; - } - .cnum{ color:${T.fgSubtle}; } - .ctext{ font-size:21px; line-height:1.42; color:${T.fg}; font-weight:400; } - .ctext .q{ color:${T.fgMuted}; } - .mono{ font-family:'JetBrains Mono',monospace; font-size:0.86em; color:${T.fgMuted}; } .foot{ display:flex; align-items:center; justify-content:space-between; font-family:'JetBrains Mono',monospace; font-weight:500; @@ -134,23 +107,13 @@ const html = `
webjs
-

Any AI model. Production-ready code.

-

A full-stack web framework that needs no training data. Small models and large ones both ship production-ready architecture and a design system from the very first line of code.

-
-
-
01 What your agent gets
-
The whole stack fits in context. Plain JS in node_modules, built on the web components and forms every model already knows.
-
-
-
02 What you ship
-
Server-rendered HTML that works without JavaScript. No bundler in between, on Node 24+ or Bun.
-
-
+

The web framework for AI agents

+

A full-stack framework built on web components, SSR, and progressive enhancement, with zero build step. Standards that outlast frameworks.


-
MODEL AGNOSTIC  ·  NO TRAINING DATA  ·  NO BUILD
+
AI-FIRST  ·  WEB-COMPONENTS-FIRST  ·  NO BUILD
github.com/webjsdev/webjs
diff --git a/website/test/ssr/page-ssr.test.ts b/website/test/ssr/page-ssr.test.ts index 65703d26b..13e630d25 100644 --- a/website/test/ssr/page-ssr.test.ts +++ b/website/test/ssr/page-ssr.test.ts @@ -39,13 +39,5 @@ test('home metadata is single-source and consistent across title, og, and twitte assert.equal(m.twitter.title, m.title, 'twitter:title matches the '); assert.equal(m.openGraph.description, m.description, 'og:description matches the meta description'); assert.equal(m.twitter.description, m.description, 'twitter:description matches the meta description'); - // og:image:alt deliberately does NOT mirror the title. Alt text describes the - // IMAGE, and the card (public/og.png) carries its own benefit-led headline - // rather than the page title, so tying the two together would force one of - // them to be wrong. What must hold is that it stays a real description - // instead of silently going empty or falling back to the title. - const alt = m.openGraph['image:alt']; - assert.equal(typeof alt, 'string', 'og image alt is a string'); - assert.ok(alt.trim().length > 20, `og image alt is a real description, got ${JSON.stringify(alt)}`); - assert.notEqual(alt, m.title, 'og image alt describes the card, not the page title'); + assert.equal(m.openGraph['image:alt'], m.title, 'og image alt matches the title'); });