From 1ee89265f07ba5f86152e6d73425740d3935a440 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Tue, 12 May 2026 20:05:27 -0700 Subject: [PATCH] feat(website): dynamic OG image + library README headers (Group D.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two brand-facing improvements: 1. apps/website/src/app/opengraph-image.tsx — dynamic 1200×630 PNG via Next.js ImageResponse, served at /opengraph-image. Picks up automatically for every route via Next.js metadata convention; per-route overrides can be added by dropping an opengraph-image file in any route folder. Fetches Inter + JetBrains Mono via Google Fonts at request time. Headline falls back to Inter Bold (Satori does not decode woff2, and bundling EB Garamond TTF would add ~250KB to the repo for marginal typography gain). 2. Library README headers: - libs/render/README.md — was 3 lines of Nx scaffolding. Now has a real intro, install command, capability summary, doc links. - libs/chat/README.md — title changed from "chat" to "@ngaf/chat — Drop-in agent chat UI for Angular 20+", and the misleading "generated with Nx" boilerplate replaced with a real one-line description. Body content unchanged. Both READMEs are public on npmjs.com when their packages are published. Root README + library badges + cacheplane.ai/assets/{hero,arch}.svg intentionally untouched — they're dark-mode-friendly graphics that work as a coherent GitHub-README aesthetic. All 35 website e2e tests pass. Co-Authored-By: Claude Opus 4.7 --- apps/website/src/app/opengraph-image.tsx | 187 +++++++++++++++++++++++ libs/chat/README.md | 6 +- libs/render/README.md | 31 +++- 3 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 apps/website/src/app/opengraph-image.tsx diff --git a/apps/website/src/app/opengraph-image.tsx b/apps/website/src/app/opengraph-image.tsx new file mode 100644 index 000000000..3e88f28d8 --- /dev/null +++ b/apps/website/src/app/opengraph-image.tsx @@ -0,0 +1,187 @@ +/** + * Default OpenGraph + Twitter share card for the marketing site. + * + * Renders a 1200×630 PNG at request time via Next.js ImageResponse. + * Per-route overrides can be added by dropping an `opengraph-image.tsx` + * file in any route folder. + */ +import { ImageResponse } from 'next/og'; + +export const runtime = 'edge'; +export const alt = 'Angular Agent Framework — Signal-native streaming for Angular + LangGraph'; +export const size = { width: 1200, height: 630 }; +export const contentType = 'image/png'; + +async function loadFont(family: string, weight: number): Promise { + try { + // Modern UA → woff2. Older UA → ttf. We ask for both and pick the first that resolves. + // ImageResponse wants the raw font binary; woff2 is fine (Satori decompresses internally). + const css = await fetch( + `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:wght@${weight}&display=swap`, + { headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' } }, + ).then((res) => res.text()); + // Grab any url(...) src — the first one is the woff2 the modern UA gets. + const match = css.match(/src:\s*url\((https?:\/\/[^)]+)\)/); + if (!match) return null; + const fontRes = await fetch(match[1]); + if (!fontRes.ok) return null; + return await fontRes.arrayBuffer(); + } catch { + return null; + } +} + +export default async function OpenGraphImage() { + const [garamondBold, interRegular, interBold, monoBold] = await Promise.all([ + loadFont('EB+Garamond', 700), + loadFont('Inter', 400), + loadFont('Inter', 600), + loadFont('JetBrains+Mono', 700), + ]); + const fonts = [ + garamondBold && { name: 'EB Garamond', data: garamondBold, weight: 700 as const, style: 'normal' as const }, + interRegular && { name: 'Inter', data: interRegular, weight: 400 as const, style: 'normal' as const }, + interBold && { name: 'Inter', data: interBold, weight: 600 as const, style: 'normal' as const }, + monoBold && { name: 'JetBrains Mono', data: monoBold, weight: 700 as const, style: 'normal' as const }, + ].filter((f): f is NonNullable => f !== null); + + return new ImageResponse( + ( +
+ {/* Eyebrow */} +
+ Angular Agent Framework · MIT +
+ + {/* Headline — EB Garamond serif matches marketing-site h1 */} +
+ Ship agentic Angular apps without rewriting your frontend. +
+ + {/* Subhead */} +
+ Signal-native streaming for LangGraph and AG-UI. Headless primitives plus + opinionated compositions for Angular 20+ teams shipping to production. +
+ + {/* Footer row — pill trust signals + wordmark */} +
+
+ MIT + LangGraph + AG-UI + Angular 20+ +
+
+ 🛩️ + cacheplane.ai +
+
+
+ ), + { + ...size, + fonts, + }, + ); +} + +interface PillBadgeProps { + tone: 'accent' | 'neutral' | 'angular'; + children: React.ReactNode; +} + +function PillBadge({ tone, children }: PillBadgeProps) { + const styles = { + accent: { + bg: 'rgba(0, 64, 144, 0.08)', + border: 'rgba(0, 64, 144, 0.18)', + color: '#004090', + }, + neutral: { + bg: '#ffffff', + border: '#e6e8ee', + color: '#555770', + }, + angular: { + bg: 'rgba(221, 0, 49, 0.06)', + border: 'rgba(221, 0, 49, 0.18)', + color: '#DD0031', + }, + }[tone]; + + return ( +
+ {children} +
+ ); +} diff --git a/libs/chat/README.md b/libs/chat/README.md index 218a59c85..ecd6088ac 100644 --- a/libs/chat/README.md +++ b/libs/chat/README.md @@ -1,6 +1,8 @@ -# chat +# @ngaf/chat -This library was generated with [Nx](https://nx.dev). +Drop-in agent chat UI for Angular 20+. Headless primitives that read from a runtime-neutral `Agent` contract, plus opinionated compositions (``, ``, GenUI surfaces) you can ship in days. + +Part of the [Angular Agent Framework](https://github.com/cacheplane/angular-agent-framework). MIT licensed. ## Runtime adapters diff --git a/libs/render/README.md b/libs/render/README.md index c2aa1a6ae..e3954e5cf 100644 --- a/libs/render/README.md +++ b/libs/render/README.md @@ -1,3 +1,30 @@ -# render +# @ngaf/render -This library was generated with [Nx](https://nx.dev). +Generative UI for Angular. Agents emit structured JSON specs; this library renders them into Angular components you already own. Supports the Vercel `json-render` and Google A2UI v1 protocols out of the box. + +Part of the [Angular Agent Framework](https://github.com/cacheplane/angular-agent-framework). MIT licensed. + +## Install + +```bash +npm install @ngaf/render +``` + +## What it does + +- **Spec-driven rendering** — agents return JSON; you map each node type to one of your Angular components via a registry +- **Two protocols supported** — Vercel `json-render` and Google A2UI v1 +- **Per-component fallback API** — when a spec node has no registered component, you control what renders (and surface it to your observability layer) +- **Readiness gate** — holds renders until the surface is real, so users never see mystery partial UI +- **Streaming partial renders** — works with `@ngaf/partial-json` to render progressive JSON as it streams + +## Documentation + +- [Quickstart](https://cacheplane.ai/docs/render/getting-started/quickstart) +- [Component registry](https://cacheplane.ai/docs/render/guides/registry) +- [Fallback patterns](https://cacheplane.ai/docs/render/guides/fallback) +- [A2UI v1 protocol](https://cacheplane.ai/docs/render/a2ui/overview) + +## License + +MIT — free for any use. See [LICENSE](../../LICENSE).