From ab640992671fb6dfedb3521581e51e54613f6f49 Mon Sep 17 00:00:00 2001 From: bntvllnt Date: Mon, 13 Jul 2026 14:22:59 +0200 Subject: [PATCH 1/2] docs(roadmap): record GSC-validated SEO paths + component gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 90d GSC analysis (sc-domain:ui.vllnt.ai/.com) of real search demand: - seo-content-engine: SYNC note with the highest-impact CAPTURE paths the data proves and that don't exist yet (/alternatives/radix, /alternatives/mui, a /react/{component} framework-qualified namespace), plus the honest finding that "AI UI development" has zero head-term demand today — a recall/GEO bet, not a capture play. - Later: multiselect + filter-bar component gaps (GSC demand exists, no component in the registry today). Planning/analysis only — no page built (per direction). --- ROADMAP.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 02770323..11474920 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,7 +5,7 @@ > **Next:** `agent-ui-cli` (MVP) · `ai-elements-parity`. > **Horizon (gated):** `native-parity` (needs an RN consumer) · the front-studio line (`studio` → `studio-hub` — after the CLI ships + a real need). > **Visibility track:** SEO/GEO phases — `search-consolidation` → `ai-toolchain-registration` → `visibility-measurement` → `seo-content-engine` → `backlink-authority`. Diagnosis: infra is DONE (`agent-surface`) but GSC shows indexed-yet-buried (141 pages, 2 clicks/90d, 0 AI-query visibility) + a dead `.com` twin outranking the live `.ai`. Full plan: [strategy dossier](https://claude.ai/code/artifact/6e2359db-a626-4226-aa54-a9e53ecfd766). -> **Last updated:** 2026-07-02 +> **Last updated:** 2026-07-13 > **Channels:** `@latest` = `0.3.0` · `@canary` = `0.4.0-canary.` (auto-publishes on every merge to main). Tracking: [milestone 0.3.0](https://github.com/vllnt/ui/milestone/1) Convention: phases are kebab-case outcome slugs, ordered DONE → ACTIVE → PLANNED. Tasks carry stable `.` IDs; functional tasks pair with a `Validate`/`E2E` task. History is never deleted. Shipped 0.3.0 detail lives in `CHANGELOG.md` and the 197 closed issues; phases below summarize it. @@ -253,6 +253,8 @@ Falls out of API-first (`studio.11`) — registration is just another API — pl **Exit criteria:** `/blog` + `/blog/[slug]` render MDX posts with BlogPosting JSON-LD, Shiki highlighting, per-post OG + RSS; `/integrations/{tool}` + `/alternatives/{competitor}` pages ship and are in the sitemap; 3 flagship guides live; each `/components/[slug]` has unique copy + live demo + install command. **Verify:** a dev searching "how to build a chat ui with the vercel ai sdk" finds a VLLNT guide; `/alternatives/assistant-ui` renders a comparison table; a blog post shows correct BlogPosting rich data. Personas: dev in organic search; dev comparing libraries; AI answer engine extracting a table. (needs: search-consolidation done first) +**SYNC 2026-07-13 — GSC-validated path additions** (90d, `sc-domain:ui.vllnt.ai`): fold into `.4`/`.5`/`.6`/`.7`. Highest-impact **capture** paths the data proves, none of which exist today: `/alternatives/radix` (~20 impr across "radix dialog/slider/popover/scroll-area/button…", no page) + `/alternatives/mui` (cross-framework "material design X" / "angular X"); a `/react/{component}` framework-qualified namespace seeded from proven clusters — `react callout` (~60 impr, comp exists but buried pos 80+), `react floating action button` (~40 impr across react/angular/js variants, comp exists, pos 58–95); un-bury `callout` + `floating-action-button` in the `.6` uniqueness pass. **Create** paths (your AI pillar): `/guides/ai-ui` reads as `.7` flagship-guide territory — but GSC shows **zero** demand for "AI UI development", so it is a recall/GEO bet (compounding, not near-term impressions); AI *component* pages already rank pos 5–7 (`ai-chat-input`, `ai-source-citation`), so the pillar should funnel to `/families/ai` + those. + - [ ] seo-content-engine.1 Add the MDX blog: `content/blog/{slug}/{locale}.mdx` + `lib/blog.ts` (Content Collections `@content-collections/mdx`, Zod frontmatter — NOT Contentlayer; Velite fallback) mirroring `lib/content.ts` (needs: search-consolidation.4) → docs/specs/blog-system.md - [ ] seo-content-engine.2 Routes `/blog` + `/blog/[slug]` with `generateMetadata` + BlogPosting/Breadcrumb JSON-LD + Shiki build-time highlighting + per-post OG via `ImageResponse` (cmd: `curl -s https://ui.vllnt.com/blog/ | grep -c '"@type":"BlogPosting"'`) - [ ] seo-content-engine.3 Blog RSS + sitemap + llms.txt entries (extend `app/rss.xml`, `sitemap.ts`, `llms.txt/route.ts`) (cmd: `curl -s https://ui.vllnt.com/sitemap.xml | grep -c /blog/`) @@ -290,6 +292,8 @@ Unscheduled — pull into a phase when prioritized. - **agent-ui-cli-v1** — config bundle, `doctor` wrapper, `add`, `ci` reusable workflow (+ `act` for local==CI), `list`/`info`/`why`/`search`, `vllnt.config`, `upgrade`; **drift gates** — `api-extractor` (public-API `.api.md` diff), `dependency-cruiser` (import boundaries across 309 components), `sherif` (dep-version drift); **test** — wrap Storybook 10 `addon-vitest` (interaction + a11y + coverage via Vitest browser mode), don't rebuild; **dual-primitive** — `context`/`check` handle `--base radix|base-ui` (Base UI ascendant, Radix at plateau). - **agent-ui-cli-v2** — `audit` (knip + size-limit + dependency-cruiser graph), baseline gating, i18n lint, client security, `new`/scaffold, `theme new`/`edit`, `remove`/`diff`, `watch`/`report`. (Whole-site `audit --browser` + visual regression are now the **`studio`** phase; the human↔agent review loop is **`review-loop`**. Chrome DevTools MCP + Playwright MCP feed both.) - **docs + search** — `/docs` expansion (#248), Pagefind full-text (#257), Sandpack playground (#256), `/vs` pages (#258), `/templates` (#259), i18n via next-intl (#281). +- **multiselect** — multi-select / token-input component. GSC surfaces demand with **no component today**: "multiselect" / "multiselect ui" / "multiselect 2" / "material design multi select" (~12 impr/90d, pos 73–92, `sc-domain:ui.vllnt.ai`). New registry item (component + story + test + `registry:build`); pull into a `demand-driven-components` phase when prioritized. +- **filter-bar** — faceted filter bar. GSC surfaces demand with **no component today**: "filter bar" / "filter bars" (~5 impr/90d, pos 78–87). New registry item; pairs with the `multiselect` gap above. --- From 04312ea4d93ba2a8141fcc8469be2e415f208e1a Mon Sep 17 00:00:00 2001 From: bntvllnt Date: Fri, 17 Jul 2026 16:03:30 +0200 Subject: [PATCH 2/2] docs(roadmap): add mdx-content-system phase + GSC-validated content paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the full MDX-max plan and the GSC-validated SEO paths as roadmap work, per the roadmap convention. New phase `mdx-content-system` [PLANNED] (7 tasks, sequenced before seo-content-engine): - Shared MDX component map, extended frontmatter schema (JSON-LD from frontmatter), generic /guides|/vs|/react [slug] shells, sitemap via content glob, an author guard for the MDX evaluate() bracket hazard, and migration of the 3 shipped TSX /vs pages onto the MDX shell. - Outcome: a new content page = one .mdx file drop (no TSX, no sitemap edit), i18n-ready via fr.mdx with zero code change. seo-content-engine: +7 tasks (.9-.15) for the GSC-proven paths — /vs/radix, /vs/mui, /react/{callout,floating-action-button,code-block}, /guides/ai-ui pillar (+ mobile coming-soon), /guides/streaming-ui + /guides/design-tokens, and the assistant-ui namespace migration. Namespace decisions recorded: /vs = tools+libs, /alternatives = direct competitors, /integrations = how-to-use, /guides = evergreen reference, /blog = dated articles. --- ROADMAP.md | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 11474920..f94a75cc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,7 +4,7 @@ > **Now:** `component-sidebar` — finish `.5`/`.6`, then ship `@vllnt/ui@0.4.0`. > **Next:** `agent-ui-cli` (MVP) · `ai-elements-parity`. > **Horizon (gated):** `native-parity` (needs an RN consumer) · the front-studio line (`studio` → `studio-hub` — after the CLI ships + a real need). -> **Visibility track:** SEO/GEO phases — `search-consolidation` → `ai-toolchain-registration` → `visibility-measurement` → `seo-content-engine` → `backlink-authority`. Diagnosis: infra is DONE (`agent-surface`) but GSC shows indexed-yet-buried (141 pages, 2 clicks/90d, 0 AI-query visibility) + a dead `.com` twin outranking the live `.ai`. Full plan: [strategy dossier](https://claude.ai/code/artifact/6e2359db-a626-4226-aa54-a9e53ecfd766). +> **Visibility track:** SEO/GEO phases — `search-consolidation` → `ai-toolchain-registration` → `visibility-measurement` → `mdx-content-system` → `seo-content-engine` → `backlink-authority`. Diagnosis: infra is DONE (`agent-surface`) but GSC shows indexed-yet-buried (141 pages, 2 clicks/90d, 0 AI-query visibility) + a dead `.com` twin outranking the live `.ai`. Full plan: [strategy dossier](https://claude.ai/code/artifact/6e2359db-a626-4226-aa54-a9e53ecfd766). > **Last updated:** 2026-07-13 > **Channels:** `@latest` = `0.3.0` · `@canary` = `0.4.0-canary.` (auto-publishes on every merge to main). Tracking: [milestone 0.3.0](https://github.com/vllnt/ui/milestone/1) @@ -247,13 +247,29 @@ Falls out of API-first (`studio.11`) — registration is just another API — pl - [ ] visibility-measurement.3 Add server-log crawler monitoring for GPTBot/ClaudeBot/Claude-Code/PerplexityBot/OAI-SearchBot — proves llms.txt consumption (cmd: `grep -Ec 'GPTBot|ClaudeBot|Claude-Code' access.log`) - [ ] visibility-measurement.4 Script a recurring GSC position/impressions review via `gsc.py` (cmd: `python3 gsc.py query --site sc-domain:ui.vllnt.com --dimensions query --days 28`) +## mdx-content-system [PLANNED] + +**Goal:** Make every content page one `.mdx` file — shared component map, frontmatter-driven JSON-LD, generic shells — so a new page is a file drop, not a route. +**Exit criteria:** A new page ships by adding one `content/pages///en.mdx` — no TSX, no `staticRoutes()` edit; the body may embed `` / `` from a shared map; JSON-LD (FAQPage/TechArticle) is emitted by the shell from frontmatter, never the body; the page is sitemapped automatically; adding `fr.mdx` localizes it with zero code change. +**Verify:** a maintainer drops `content/pages/guides/foo/en.mdx` carrying a `` + `faq:` frontmatter → `/guides/foo` renders the grid, Rich Results shows FAQPage, `/sitemap.xml` lists it, and adding `fr.mdx` makes `/fr/guides/foo` French. Personas: maintainer authoring content (no TSX); AI answer engine extracting the FAQ; translator adding a locale. (needs: search-consolidation.4 for the LD helpers) + +Infra already exists and is under-used: `MDXContent` (`packages/ui/src/components/mdx-content/mdx-content.tsx`) accepts a `components` map, defaults `enableMDX = true`, auto-detects JSX via `/<[A-Z]/` after stripping fenced blocks, falls back to `ReactMarkdown` + `remarkGfm` (GFM tables), and `removeImportStatements` drops import lines. `getPageContent` already resolves `/.mdx` → default locale → flat file, so i18n is opt-in per page. Today every caller passes the **empty** default map — that is the gap this phase closes. + +- [ ] mdx-content-system.1 Shared MDX component map `apps/registry/lib/mdx-components.tsx` (`ComponentGrid`, `CompareTable`, `Faq`, `InstallCommand`, `Preview`), passed as `` from every content shell (cmd: `grep -rc 'components={mdxComponents}' apps/registry/app/\[locale\]` → ≥4) +- [ ] mdx-content-system.2 Extend `pageFrontmatterSchema` (`apps/registry/lib/schemas.ts`) with `faq[]`, `componentSlugs[]`, `updated`, `type: +guide|vs|react`; shells emit FAQPage/TechArticle LD from frontmatter via `lib/jsonld.ts` (test: `pnpm test lib/schemas.test.ts`) +- [ ] mdx-content-system.3 Generic MDX shells `/guides/[slug]`, `/vs/[slug]`, `/react/[slug]` reading `getPageContent()` — a new page is one `.mdx`, zero TSX → docs/specs/mdx-content-system.md +- [ ] mdx-content-system.4 Sitemap enumerates MDX slugs by globbing `content/pages/**` instead of hand-listed `staticRoutes()` entries (cmd: `curl -s https://ui.vllnt.com/sitemap.xml | grep -c /guides/`) +- [ ] mdx-content-system.5 Author guard for the `evaluate()` hazard — a page containing JSX must not use inline `` `` `` code-spans (MDX 3 parses them as JSX; only fenced blocks are stripped before detection) (test: `pnpm test content-mdx-brackets.test.ts`) +- [ ] mdx-content-system.6 Migrate the 3 shipped TSX `/vs` pages (shadcn, vercel-ai-sdk, assistant-ui) onto the `/vs/[slug]` MDX shell, URLs unchanged (needs: mdx-content-system.3) (cmd: `curl -s https://ui.vllnt.com/vs/shadcn | grep -c '/en.mdx` with `` + `faq:` renders the grid, emits FAQPage LD, and appears in the sitemap; `fr.mdx` serves `/fr/guides/`; the 3 migrated `/vs` pages still render tables at unchanged URLs (E2E: `pnpm test:e2e mdx-content`) + ## seo-content-engine [PLANNED] **Goal:** Build the content flywheel — an MDX blog plus programmatic integration / alternative / comparison pages that capture long-tail install intent and definitional AI-wedge queries. **Exit criteria:** `/blog` + `/blog/[slug]` render MDX posts with BlogPosting JSON-LD, Shiki highlighting, per-post OG + RSS; `/integrations/{tool}` + `/alternatives/{competitor}` pages ship and are in the sitemap; 3 flagship guides live; each `/components/[slug]` has unique copy + live demo + install command. -**Verify:** a dev searching "how to build a chat ui with the vercel ai sdk" finds a VLLNT guide; `/alternatives/assistant-ui` renders a comparison table; a blog post shows correct BlogPosting rich data. Personas: dev in organic search; dev comparing libraries; AI answer engine extracting a table. (needs: search-consolidation done first) +**Verify:** a dev searching "how to build a chat ui with the vercel ai sdk" finds a VLLNT guide; `/alternatives/assistant-ui` renders a comparison table; a blog post shows correct BlogPosting rich data. Personas: dev in organic search; dev comparing libraries; AI answer engine extracting a table. (needs: search-consolidation done first · mdx-content-system for the MDX shells) -**SYNC 2026-07-13 — GSC-validated path additions** (90d, `sc-domain:ui.vllnt.ai`): fold into `.4`/`.5`/`.6`/`.7`. Highest-impact **capture** paths the data proves, none of which exist today: `/alternatives/radix` (~20 impr across "radix dialog/slider/popover/scroll-area/button…", no page) + `/alternatives/mui` (cross-framework "material design X" / "angular X"); a `/react/{component}` framework-qualified namespace seeded from proven clusters — `react callout` (~60 impr, comp exists but buried pos 80+), `react floating action button` (~40 impr across react/angular/js variants, comp exists, pos 58–95); un-bury `callout` + `floating-action-button` in the `.6` uniqueness pass. **Create** paths (your AI pillar): `/guides/ai-ui` reads as `.7` flagship-guide territory — but GSC shows **zero** demand for "AI UI development", so it is a recall/GEO bet (compounding, not near-term impressions); AI *component* pages already rank pos 5–7 (`ai-chat-input`, `ai-source-citation`), so the pillar should funnel to `/families/ai` + those. +**SYNC 2026-07-13 — GSC evidence + namespace split** (90d, `sc-domain:ui.vllnt.ai`). **Evidence:** demand is entirely component-level and framework-qualified (`react callout` ~60 impr @pos 80+, `react floating action button` ~40 impr @58–95, `radix {dialog,slider,popover,scroll-area,button}` ~20 impr) — components that mostly *exist* but rank buried, so `.6`'s uniqueness pass outranks new paths for `callout` + `floating-action-button`. The **"AI UI development" head term has zero demand**: the pillar (`.13`) is a recall/GEO bet (compounding, not near-term impressions), justified because AI *component* pages already rank pos 5–7 (`ai-chat-input`, `ai-source-citation`) and the pillar funnels to them + `/families/ai`. **Namespace decision (2026-07-13):** `/vs` = tools + libs (shadcn, radix, mui, vercel-ai-sdk) · `/alternatives` (`.5`) = direct competitors (assistant-ui, copilotkit, ai-elements) — the shipped `/vs/assistant-ui` migrates in `.11` · `/integrations` (`.4`) stays distinct (how-to-use intent, not comparison) · `/guides` = evergreen reference (new namespace, `.13`/`.14`) while `/blog` (`.1`–`.3`, `.7`) stays dated articles. All new content pages are **MDX** on the `mdx-content-system` shells. - [ ] seo-content-engine.1 Add the MDX blog: `content/blog/{slug}/{locale}.mdx` + `lib/blog.ts` (Content Collections `@content-collections/mdx`, Zod frontmatter — NOT Contentlayer; Velite fallback) mirroring `lib/content.ts` (needs: search-consolidation.4) → docs/specs/blog-system.md - [ ] seo-content-engine.2 Routes `/blog` + `/blog/[slug]` with `generateMetadata` + BlogPosting/Breadcrumb JSON-LD + Shiki build-time highlighting + per-post OG via `ImageResponse` (cmd: `curl -s https://ui.vllnt.com/blog/ | grep -c '"@type":"BlogPosting"'`) @@ -263,6 +279,13 @@ Falls out of API-first (`studio.11`) — registration is just another API — pl - [ ] seo-content-engine.6 Per-component uniqueness pass: unique copy + live demo + install command on each `/components/[slug]` → docs/specs/component-page-uniqueness.md - [ ] seo-content-engine.7 Publish 3 flagship guides (best react components for AI agents; assistant-ui vs ai-elements vs vllnt; render tool calls in react) — answer-first, stats + tables, TechArticle LD (cmd: `curl -s https://ui.vllnt.com/blog/best-react-components-for-ai-agents | grep -c '` queries (needs: mdx-content-system.3) (cmd: `curl -sI https://ui.vllnt.com/react/callout | grep -c 200`) +- [ ] seo-content-engine.13 `/guides/ai-ui` pillar MDX — AI-UI-development reference: `` + `faq:` frontmatter, funnels to `/families/ai` + `/build/*` + `/vs/*`, with a Mobile/React-Native coming-soon section (needs: mdx-content-system.3) → docs/specs/ai-ui-pillar.md +- [ ] seo-content-engine.14 `/guides/streaming-ui` + `/guides/design-tokens` evergreen MDX reference pages (needs: mdx-content-system.3) (cmd: `curl -sI https://ui.vllnt.com/guides/design-tokens | grep -c 200`) +- [ ] seo-content-engine.15 Validate seo-content-engine.9–14: E2E — `/vs/radix` + `/vs/mui` render comparison tables; `/vs/assistant-ui` 301s to `/alternatives/assistant-ui`; `/react/callout` returns 200 with unique copy; `/guides/ai-ui` emits FAQPage LD + renders the AI grid + the mobile coming-soon section; all appear in `/sitemap.xml` (E2E: `pnpm test:e2e content-paths`) ## backlink-authority [PLANNED]