From 6114db5e0f17174b94228848d50588fc9859ab55 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 09:39:15 -0700 Subject: [PATCH 1/5] docs(specs): home positioning strip redesign Replace stat-shaped tiles below the hero with four differentiator claims grounded in current competitive research (CopilotKit, Vercel AI SDK 5, assistant-ui). Co-Authored-By: Claude Opus 4.7 --- .../2026-05-01-home-stats-strip-redesign.md | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-01-home-stats-strip-redesign.md diff --git a/docs/superpowers/specs/2026-05-01-home-stats-strip-redesign.md b/docs/superpowers/specs/2026-05-01-home-stats-strip-redesign.md new file mode 100644 index 000000000..104cb664c --- /dev/null +++ b/docs/superpowers/specs/2026-05-01-home-stats-strip-redesign.md @@ -0,0 +1,113 @@ +# Home page positioning strip redesign + +**Date:** 2026-05-01 +**Status:** Design — pending plan +**Scope:** Replace `StatsStrip` (the section directly below the hero on `/`) with a differentiator-focused positioning strip. + +## Problem + +The current section directly below the hero is `apps/website/src/components/landing/StatsStrip.tsx`, a 4-tile grid of stat-shaped claims: + +- `14+ Capabilities` — vague; "capability" is undefined and uncountable. +- `100% Signal-Native` — table stakes for modern Angular, not a differentiator. +- `20+ Angular Version` — awkward phrasing; belongs on a badge, not positioning. +- `OSS Source Available` — conflates two distinct license categories; the project is MIT. + +The strip's visual format (big number + label) forces synthetic numbers onto claims that aren't fundamentally numeric. Right after the hero, the visitor is asking "why this and not the React tools I already use?" — the current strip does not answer that. + +## Goal + +Replace the strip with **4 positioning claims** that differentiate NGAF against the actual competitive set (CopilotKit, Vercel AI SDK 5, assistant-ui, vanilla AG-UI/LangGraph wiring). Each claim must be defensible against a current competitor product page. + +## Non-goals + +- Not redesigning the hero, ProblemSection, or any section below. +- Not adding new pages or routes. +- Not changing the design tokens or glass-card system — reuse existing tokens. +- Not adding logos or social-proof imagery (separate concern). + +## Competitive context (from research, 2026-05-01) + +- **CopilotKit** ships `@copilotkitnext/angular` with services + headless UI + chat components. Full Angular customization is tier-gated. No A2UI renderer on the Angular side. +- **Vercel AI SDK 5** has official Angular support with signal-based primitives, but does not speak LangGraph natively. +- **assistant-ui** is React-only. +- **AG-UI** is a protocol; Angular is one of its listed renderers. Not a UI library. + +Implication: NGAF cannot claim "first/only Angular agent framework." It *can* claim runtime neutrality, full-parity LangGraph streaming, built-in generative UI (json-render + A2UI), and unrestricted MIT licensing. + +## Claims that will NOT appear + +- "First Angular agent framework" — false (CopilotKit, Vercel AI SDK). +- "Built on signals" / "Zoneless" / "Modern Angular" — baseline. +- "Open source" alone — every competitor is OSS. +- "Cockpit DevTools" — not yet a shipped product surface; the libs under `libs/cockpit-*` are contracts only. +- "Type-safe" — table stakes. + +## Design + +### Section structure + +Same 4-cell grid as today, but each cell becomes a positioning card with: + +1. **Eyebrow** — short uppercase mono tag identifying the dimension (e.g. `RUNTIME`, `STREAMING`, `GENERATIVE UI`, `LICENSE`). +2. **Claim headline** — one short sentence in serif (Garamond), ~6–10 words. +3. **Supporting line** — one sentence in sans/secondary, ≤25 words, naming the concrete proof. + +No big numbers. No icons in v1 (icons can be added in a follow-up if a designer pass calls for them). + +### Visual treatment + +- Reuse `tokens.glass` (bg, blur, border, shadow) so the card aesthetic matches `ProblemSection` and `TheStack`. +- Container: `max-width: 1040px`, `padding: 64px 32px`, centered. +- Grid: `repeat(auto-fit, minmax(240px, 1fr))`, 4 columns on desktop, 2 on tablet, 1 on mobile. +- Card padding: `24px 22px`. Border-radius: `18px` (match ProblemSection stat cards). +- Animation: keep the existing staggered fade-in from `StatsStrip` (`framer-motion`, `delay: i * 0.1`). + +### Copy (exact text) + +**Card 1 — RUNTIME** +> **One Angular UI. Any agent runtime.** +> Same primitives drive LangGraph, AG-UI, CrewAI, Mastra, Pydantic AI, AWS Strands, and your own backend. + +**Card 2 — STREAMING** +> **Full-parity LangGraph streaming.** +> `agent()` ships everything React's `useStream()` does — interrupt, subagents, branch and history, tool progress — plus `error()`, `status()`, and `reload()`. + +**Card 3 — GENERATIVE UI** +> **Generative UI, built in.** +> Render Vercel `json-render` and Google A2UI specs into Angular components. No second framework to bolt on. + +**Card 4 — LICENSE** +> **MIT. Headless primitives, drop-in compositions.** +> No tier gates on Angular. Use the unstyled primitives, or the opinionated chat shell — your call. + +### Order + +`RUNTIME → STREAMING → GENERATIVE UI → LICENSE`. This walks the visitor from the broadest claim (works with anything) down to the most concrete commercial signal (no paywall on Angular). + +### Accessibility + +- The section gets `aria-labelledby` pointing at a visually-hidden `

` with text "What makes the Angular Agent Framework different". +- Each card is a `
`; eyebrow is a `

` with mono styling, not a heading. Claim headline is `

`. Supporting line is `

`. +- Inline code (`agent()`, `useStream()`, `json-render`) wrapped in `` with mono font. +- Color contrast: all text uses `tokens.colors.textPrimary` / `textSecondary`; verify against glass background at the lightest gradient stop. + +### Implementation footprint + +- New file: `apps/website/src/components/landing/PositioningStrip.tsx`. +- Delete: `apps/website/src/components/landing/StatsStrip.tsx`. +- Edit: `apps/website/src/app/page.tsx` — swap `` for ``, update the comment from `2. Trust — quick credibility stats` to `2. Differentiation — positioning vs other agent UIs`. +- No changes to `ProblemSection`, `PilotSolution`, `TheStack`, `WhitePaperSection`, or `PilotFooterCTA`. + +### Risk and mitigation + +- **A2UI claim has a short shelf-life.** CopilotKit blogged about React + A2UI in early 2026; Angular parity is plausible within 6 months. The claim is true today; revisit on the next quarterly content review. +- **Naming CopilotKit indirectly via "tier gates."** The copy says "No tier gates on Angular" without naming CopilotKit. Defensible factual statement; not a comparative ad. +- **LangGraph parity claim depends on the README parity table staying current.** If `@ngaf/langgraph` drifts behind upstream `useStream()`, this card becomes a liability. Add a note in the lib README that the parity table is load-bearing for marketing copy. + +## Testing + +- Visual: render `/` in dev server, verify 4-up desktop / 2-up tablet / 1-up mobile via `preview_resize`. +- Console / network: zero new errors or requests vs. current `StatsStrip`. +- A11y: `aria-labelledby` resolves, headings nest correctly under the hero `

`, inline `` is announced. +- No new unit tests required — this is presentational. From 91625ae490a60f20e9ec6da6a23c66ffec330c64 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 09:47:17 -0700 Subject: [PATCH 2/5] docs(plans): home positioning strip implementation plan Co-Authored-By: Claude Opus 4.7 --- .../2026-05-01-home-positioning-strip.md | 284 ++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-01-home-positioning-strip.md diff --git a/docs/superpowers/plans/2026-05-01-home-positioning-strip.md b/docs/superpowers/plans/2026-05-01-home-positioning-strip.md new file mode 100644 index 000000000..dd83e971c --- /dev/null +++ b/docs/superpowers/plans/2026-05-01-home-positioning-strip.md @@ -0,0 +1,284 @@ +# Home Positioning Strip Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace `StatsStrip` (the section directly below the hero on `/`) with a four-card differentiator-focused `PositioningStrip`. + +**Architecture:** New presentational Angular-website React component that renders a 4-cell glass-card grid (RUNTIME / STREAMING / GENERATIVE UI / LICENSE) using existing `tokens.glass` styles and `framer-motion` staggered fade-in. Page-level swap in `apps/website/src/app/page.tsx`. Delete the old `StatsStrip` component. No new design tokens, no new dependencies. + +**Tech Stack:** Next.js (apps/website), React, TypeScript, framer-motion, `@ngaf/design-tokens` (`tokens.glass`, `tokens.colors`). + +**Spec:** `docs/superpowers/specs/2026-05-01-home-stats-strip-redesign.md` + +--- + +## File Structure + +- **Create:** `apps/website/src/components/landing/PositioningStrip.tsx` — new component, single responsibility: render the 4 differentiator cards. +- **Delete:** `apps/website/src/components/landing/StatsStrip.tsx` — replaced wholesale. +- **Modify:** `apps/website/src/app/page.tsx` — swap import and JSX usage; update inline comment on the relevant line. + +No tests are added: this is a purely presentational component matching the same convention used by sibling components in `apps/website/src/components/landing/` (e.g. `ProblemSection.tsx`, `TheStack.tsx` — none ship unit tests). Verification is done in-browser via the preview tools per repo convention. + +--- + +## Task 1: Create PositioningStrip component + +**Files:** +- Create: `apps/website/src/components/landing/PositioningStrip.tsx` + +- [ ] **Step 1: Create the component file** + +Write the file with the exact contents below. The four cards are defined in a `CARDS` array so the JSX is a single map. Inline `` spans use `var(--font-mono)` to match the rest of the site. + +```tsx +'use client'; +import { motion } from 'framer-motion'; +import type { ReactNode } from 'react'; +import { tokens } from '@ngaf/design-tokens'; + +interface Card { + eyebrow: string; + headline: string; + body: ReactNode; +} + +const CARDS: Card[] = [ + { + eyebrow: 'Runtime', + headline: 'One Angular UI. Any agent runtime.', + body: 'Same primitives drive LangGraph, AG-UI, CrewAI, Mastra, Pydantic AI, AWS Strands, and your own backend.', + }, + { + eyebrow: 'Streaming', + headline: 'Full-parity LangGraph streaming.', + body: ( + <> + agent() ships everything React's{' '} + useStream() does — interrupt, subagents, branch and history, tool progress — plus{' '} + error(),{' '} + status(), and{' '} + reload(). + + ), + }, + { + eyebrow: 'Generative UI', + headline: 'Generative UI, built in.', + body: ( + <> + Render Vercel json-render and Google A2UI specs into Angular components. No second framework to bolt on. + + ), + }, + { + eyebrow: 'License', + headline: 'MIT. Headless primitives, drop-in compositions.', + body: 'No tier gates on Angular. Use the unstyled primitives, or the opinionated chat shell — your call.', + }, +]; + +export function PositioningStrip() { + return ( +
+

+ What makes the Angular Agent Framework different +

+ +
+ {CARDS.map((card, i) => ( + +

+ {card.eyebrow} +

+

+ {card.headline} +

+

+ {card.body} +

+
+ ))} +
+
+ ); +} +``` + +- [ ] **Step 2: Verify the file compiles in isolation** + +Run: `npx tsc --noEmit -p apps/website/tsconfig.json` +Expected: no new TypeScript errors referencing `PositioningStrip.tsx`. (Pre-existing errors elsewhere are out of scope; only fail on errors in the new file.) + +- [ ] **Step 3: Commit** + +```bash +git add apps/website/src/components/landing/PositioningStrip.tsx +git commit -m "feat(website): add PositioningStrip component" +``` + +--- + +## Task 2: Wire PositioningStrip into the home page and remove StatsStrip + +**Files:** +- Modify: `apps/website/src/app/page.tsx` +- Delete: `apps/website/src/components/landing/StatsStrip.tsx` + +- [ ] **Step 1: Replace the import in `page.tsx`** + +In `apps/website/src/app/page.tsx`, change line 2 from: + +```tsx +import { StatsStrip } from '../components/landing/StatsStrip'; +``` + +to: + +```tsx +import { PositioningStrip } from '../components/landing/PositioningStrip'; +``` + +- [ ] **Step 2: Replace the JSX usage and update its comment** + +In the same file, change the block currently at lines 21–22: + +```tsx + {/* 2. Trust — quick credibility stats */} + +``` + +to: + +```tsx + {/* 2. Differentiation — positioning vs other agent UIs */} + +``` + +Leave the rest of the file unchanged. + +- [ ] **Step 3: Delete the old component file** + +Run: `git rm apps/website/src/components/landing/StatsStrip.tsx` +Expected: file removed; no other files reference `StatsStrip` (verify with `git grep StatsStrip` — should return nothing). + +- [ ] **Step 4: Type-check** + +Run: `npx tsc --noEmit -p apps/website/tsconfig.json` +Expected: no errors mentioning `StatsStrip` or `PositioningStrip`. + +- [ ] **Step 5: Commit** + +```bash +git add apps/website/src/app/page.tsx +git commit -m "feat(website): swap StatsStrip for PositioningStrip on home" +``` + +--- + +## Task 3: Visual verification in the dev server + +**Files:** none (verification only) + +- [ ] **Step 1: Start the dev server** + +Use `preview_start` for the website app (working directory: repo root, command per the website package — typically `npm run dev -w apps/website` or the equivalent Nx target `nx serve website`). Confirm the server is up. + +- [ ] **Step 2: Navigate to `/` and capture desktop snapshot** + +Use `preview_snapshot` at default viewport. Verify: +- Hero renders unchanged. +- Below the hero: 4 cards in a row (or 2×2 if viewport is below ~1040 + padding). +- Each card shows: uppercase eyebrow (RUNTIME / STREAMING / GENERATIVE UI / LICENSE), serif headline, secondary body text. +- Inline code in the STREAMING and GENERATIVE UI cards renders in monospace. + +- [ ] **Step 3: Check console and network for regressions** + +Use `preview_console_logs` and `preview_network`. Expected: no new errors compared to a baseline `/` load. Framer-motion's `whileInView` should not warn. + +- [ ] **Step 4: Test responsive layout** + +Use `preview_resize` to 1280px (desktop, 4-up), 900px (tablet, expect 2-up since `minmax(240px, 1fr)` allows 3 only above ~1000px of available track), and 480px (mobile, 1-up). Take a snapshot at each. Verify no horizontal scroll, no overflow, and headlines do not truncate awkwardly. + +- [ ] **Step 5: Capture screenshot proof** + +Use `preview_screenshot` at the default desktop viewport, scoped to the positioning section. Save evidence for the PR description. + +- [ ] **Step 6: Stop the dev server** + +Use `preview_stop`. + +--- + +## Self-review notes + +- **Spec coverage:** All four cards in the spec's "Copy (exact text)" section are present verbatim in `CARDS`. Order matches spec: RUNTIME → STREAMING → GENERATIVE UI → LICENSE. Visual treatment (glass tokens, 18px radius, staggered motion, `auto-fit minmax(240px, 1fr)` grid, `max-width: 1040px`, `padding: 64px 32px`) matches the spec's "Visual treatment" section. Accessibility: `aria-labelledby` plus visually-hidden `

`, `
` per card, `

` headline, mono `` for identifiers — matches spec. +- **Placeholder scan:** No TBD/TODO. All code blocks are complete. +- **Type consistency:** `Card` interface used once locally; `CARDS` is the only consumer. No cross-task type drift. +- **Out of scope per spec:** ProblemSection, hero, lower sections — unchanged. From 2723c532871608fbbda66226d01af65376f348d7 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 10:13:45 -0700 Subject: [PATCH 3/5] feat(website): add PositioningStrip component --- .../components/landing/PositioningStrip.tsx | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 apps/website/src/components/landing/PositioningStrip.tsx diff --git a/apps/website/src/components/landing/PositioningStrip.tsx b/apps/website/src/components/landing/PositioningStrip.tsx new file mode 100644 index 000000000..f60eba489 --- /dev/null +++ b/apps/website/src/components/landing/PositioningStrip.tsx @@ -0,0 +1,137 @@ +'use client'; +import { motion } from 'framer-motion'; +import type { ReactNode } from 'react'; +import { tokens } from '@ngaf/design-tokens'; + +interface Card { + eyebrow: string; + headline: string; + body: ReactNode; +} + +const CARDS: Card[] = [ + { + eyebrow: 'Runtime', + headline: 'One Angular UI. Any agent runtime.', + body: 'Same primitives drive LangGraph, AG-UI, CrewAI, Mastra, Pydantic AI, AWS Strands, and your own backend.', + }, + { + eyebrow: 'Streaming', + headline: 'Full-parity LangGraph streaming.', + body: ( + <> + agent() ships everything React's{' '} + useStream() does — interrupt, subagents, branch and history, tool progress — plus{' '} + error(),{' '} + status(), and{' '} + reload(). + + ), + }, + { + eyebrow: 'Generative UI', + headline: 'Generative UI, built in.', + body: ( + <> + Render Vercel json-render and Google A2UI specs into Angular components. No second framework to bolt on. + + ), + }, + { + eyebrow: 'License', + headline: 'MIT. Headless primitives, drop-in compositions.', + body: 'No tier gates on Angular. Use the unstyled primitives, or the opinionated chat shell — your call.', + }, +]; + +export function PositioningStrip() { + return ( +
+

+ What makes the Angular Agent Framework different +

+ +
+ {CARDS.map((card, i) => ( + +

+ {card.eyebrow} +

+

+ {card.headline} +

+

+ {card.body} +

+
+ ))} +
+
+ ); +} From 23851590ba812c226bba741593566d1b9de5781e Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 10:15:44 -0700 Subject: [PATCH 4/5] feat(website): swap StatsStrip for PositioningStrip on home Replace the trust-focused social proof stats section with a differentiation-focused positioning strip that highlights key architectural advantages vs other agent UI frameworks. Co-Authored-By: Claude Opus 4.7 --- apps/website/src/app/page.tsx | 6 +-- .../src/components/landing/StatsStrip.tsx | 47 ------------------- 2 files changed, 3 insertions(+), 50 deletions(-) delete mode 100644 apps/website/src/components/landing/StatsStrip.tsx diff --git a/apps/website/src/app/page.tsx b/apps/website/src/app/page.tsx index 8792e9915..5681b4628 100644 --- a/apps/website/src/app/page.tsx +++ b/apps/website/src/app/page.tsx @@ -1,5 +1,5 @@ import { HeroTwoCol } from '../components/landing/HeroTwoCol'; -import { StatsStrip } from '../components/landing/StatsStrip'; +import { PositioningStrip } from '../components/landing/PositioningStrip'; import { ProblemSection } from '../components/landing/ProblemSection'; import { PilotSolution } from '../components/landing/PilotSolution'; import { TheStack } from '../components/landing/TheStack'; @@ -18,8 +18,8 @@ export default async function HomePage() { {/* 1. Hook — headline, animation, CTA */} - {/* 2. Trust — quick credibility stats */} - + {/* 2. Differentiation — positioning vs other agent UIs */} + {/* 3. Problem — last-mile gap narrative */} {/* 4. Solution — pilot-to-prod program */} diff --git a/apps/website/src/components/landing/StatsStrip.tsx b/apps/website/src/components/landing/StatsStrip.tsx deleted file mode 100644 index 5f897558f..000000000 --- a/apps/website/src/components/landing/StatsStrip.tsx +++ /dev/null @@ -1,47 +0,0 @@ -'use client'; -import { motion } from 'framer-motion'; -import { tokens } from '@ngaf/design-tokens'; - -const STATS = [ - { value: '14+', label: 'Capabilities' }, - { value: '100%', label: 'Signal-Native' }, - { value: '20+', label: 'Angular Version' }, - { value: 'OSS', label: 'Source Available' }, -]; - -export function StatsStrip() { - return ( -
-
- {STATS.map((stat, i) => ( - -
{stat.value}
-
{stat.label}
-
- ))} -
-
- ); -} From 57729438d23da279d473803da35540a393074330 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 1 May 2026 10:20:14 -0700 Subject: [PATCH 5/5] fix(website): pin PositioningStrip to 4-up at >=1024px Previous auto-fit minmax(240px, 1fr) wrapped to 3 columns at 1280px since 4*240+3*16=1008 exceeds the 976px inner width. Use explicit breakpoints: 1-up <640px, 2-up <1024px, 4-up otherwise. Co-Authored-By: Claude Opus 4.7 --- .../components/landing/PositioningStrip.tsx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/website/src/components/landing/PositioningStrip.tsx b/apps/website/src/components/landing/PositioningStrip.tsx index f60eba489..6bbe1fb41 100644 --- a/apps/website/src/components/landing/PositioningStrip.tsx +++ b/apps/website/src/components/landing/PositioningStrip.tsx @@ -47,9 +47,23 @@ const CARDS: Card[] = [ export function PositioningStrip() { return (
+

-
+
{CARDS.map((card, i) => (