diff --git a/app/changelog/page.tsx b/app/changelog/page.tsx
index 1cfd351..ce2380f 100644
--- a/app/changelog/page.tsx
+++ b/app/changelog/page.tsx
@@ -2,9 +2,9 @@ import type { Metadata } from "next";
import Link from "next/link";
import { Fragment } from "react";
import { Terminal, ArrowLeft, Github, ExternalLink } from "lucide-react";
-import { ArcadeSplash } from "@/components/changelog/ArcadeSplash";
-import { ArcadeBackground } from "@/components/changelog/ArcadeBackground";
-import { InstallBlock } from "@/components/changelog/InstallBlock";
+import { ArcadeSplash } from "@/components/marketing/arcade/ArcadeSplash";
+import { ArcadeBackground } from "@/components/marketing/arcade/ArcadeBackground";
+import { InstallBlock } from "@/components/marketing/changelog/InstallBlock";
export const dynamic = "force-static";
diff --git a/app/roadmap/page.tsx b/app/roadmap/page.tsx
new file mode 100644
index 0000000..4509faa
--- /dev/null
+++ b/app/roadmap/page.tsx
@@ -0,0 +1,105 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+import { Terminal, ArrowLeft, Github } from "lucide-react";
+import { ArcadeBackground } from "@/components/marketing/arcade/ArcadeBackground";
+import { RoadmapBoard } from "@/components/marketing/roadmap/RoadmapBoard";
+
+export const dynamic = "force-static";
+
+export const metadata: Metadata = {
+ title: "Roadmap · AI DevKit Skills",
+ description: "What's in progress on AI DevKit Skills, and what's already shipped.",
+};
+
+const ACCENT = "#82AAFF";
+const REPO = "https://github.com/CommandOSSLabs/ai-devkit";
+
+// Same corner-mark decoration as the changelog page's "Back to site" link —
+// reused directly, not re-derived, so the two pages read as one site.
+function CornerMark({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+export default function RoadmapPage() {
+ return (
+
+ {/* Same ambient background as /changelog, no splash — the reveal
+ moment belongs to the changelog; landing here should feel calm. */}
+
+
+
+
+
+
+
+
+
+
ai-devkit
+
+
+
+
+
+
+
+
Back to site
+
+
+
+
+
+
+
+ Roadmap
+
+
+ What's In Progress
+
+
+ What's being worked on right now, and what's already shipped. Next and Later are open —
+ there's no fixed plan for them yet.
+
+
+ Want something prioritized?{" "}
+
+ Open an issue on GitHub
+
+ .
+
+
+
+ View the repo on GitHub
+
→
+
+
+
+
+
+
+
+ );
+}
diff --git a/components/changelog/ArcadeBackground.tsx b/components/marketing/arcade/ArcadeBackground.tsx
similarity index 96%
rename from components/changelog/ArcadeBackground.tsx
rename to components/marketing/arcade/ArcadeBackground.tsx
index 2f18bac..51ca172 100644
--- a/components/changelog/ArcadeBackground.tsx
+++ b/components/marketing/arcade/ArcadeBackground.tsx
@@ -8,8 +8,8 @@
import { useEffect, useRef } from "react";
import { cn } from "@/lib/utils";
-import { Arcade } from "./arcade/engine";
-import { COLORWAYS } from "./arcade/params";
+import { Arcade } from "./engine";
+import { COLORWAYS } from "./params";
const DARK_COLORWAY = COLORWAYS.findIndex((c) => c.name === "Cyanide Dark");
diff --git a/components/changelog/ArcadeSplash.tsx b/components/marketing/arcade/ArcadeSplash.tsx
similarity index 97%
rename from components/changelog/ArcadeSplash.tsx
rename to components/marketing/arcade/ArcadeSplash.tsx
index dd87cd7..e8063ac 100644
--- a/components/changelog/ArcadeSplash.tsx
+++ b/components/marketing/arcade/ArcadeSplash.tsx
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useRef, useState } from "react";
-import { Arcade } from "./arcade/engine";
+import { Arcade } from "./engine";
const TOTAL_MS = 5000;
const FADE_MS = 600;
diff --git a/components/changelog/arcade/engine.ts b/components/marketing/arcade/engine.ts
similarity index 100%
rename from components/changelog/arcade/engine.ts
rename to components/marketing/arcade/engine.ts
diff --git a/components/changelog/arcade/params.ts b/components/marketing/arcade/params.ts
similarity index 100%
rename from components/changelog/arcade/params.ts
rename to components/marketing/arcade/params.ts
diff --git a/components/changelog/arcade/shaders.ts b/components/marketing/arcade/shaders.ts
similarity index 100%
rename from components/changelog/arcade/shaders.ts
rename to components/marketing/arcade/shaders.ts
diff --git a/components/changelog/arcade/text-mask.ts b/components/marketing/arcade/text-mask.ts
similarity index 100%
rename from components/changelog/arcade/text-mask.ts
rename to components/marketing/arcade/text-mask.ts
diff --git a/components/changelog/arcade/textures.ts b/components/marketing/arcade/textures.ts
similarity index 100%
rename from components/changelog/arcade/textures.ts
rename to components/marketing/arcade/textures.ts
diff --git a/components/changelog/InstallBlock.tsx b/components/marketing/changelog/InstallBlock.tsx
similarity index 100%
rename from components/changelog/InstallBlock.tsx
rename to components/marketing/changelog/InstallBlock.tsx
diff --git a/components/marketing/roadmap/RoadmapBoard.tsx b/components/marketing/roadmap/RoadmapBoard.tsx
new file mode 100644
index 0000000..f12d165
--- /dev/null
+++ b/components/marketing/roadmap/RoadmapBoard.tsx
@@ -0,0 +1,165 @@
+"use client";
+
+// Three-column board (Now / Next / Later) plus a Shipped section that
+// mirrors the real /changelog. Same bordered-card, mono-label visual
+// language as the changelog page — border-subtle cards, "$ ref"-style
+// commit/PR chips, accent color reused from there.
+
+import { useState } from "react";
+import Link from "next/link";
+import { CATEGORIES, ROADMAP_ITEMS, STATUS_DESCRIPTIONS, STATUS_LABELS, type RoadmapCategory, type RoadmapItem, type RoadmapStatus } from "./data";
+
+const COLUMNS: RoadmapStatus[] = ["now", "next", "later"];
+
+const STATUS_DOT: Record = {
+ now: "bg-emerald-400 animate-pulse",
+ next: "bg-amber-400",
+ later: "bg-[var(--text-disabled)]",
+ shipped: "bg-emerald-400",
+};
+
+function StatusDot({ status }: { status: RoadmapStatus }) {
+ return ;
+}
+
+function RefChip({ label, url }: { label: string; url: string }) {
+ return (
+
+ $
+ {label}
+
+ );
+}
+
+function ActiveCard({ item }: { item: Extract }) {
+ return (
+
+
{item.title}
+
{item.description}
+
+ {item.category}
+ {item.pr && }
+
+
+ );
+}
+
+function ShippedCard({ item }: { item: Extract }) {
+ const content = (
+ <>
+
+ {item.shippedDate}
+ >
+ );
+
+ const className = "group flex items-start gap-3 border border-[var(--border-subtle)] p-4 transition-colors hover:border-[var(--border-strong)]";
+
+ if (item.href) {
+ return (
+
+ {content}
+
+ );
+ }
+ return {content}
;
+}
+
+export function RoadmapBoard() {
+ const [filter, setFilter] = useState(null);
+
+ const filtered = filter ? ROADMAP_ITEMS.filter((item) => item.category === filter) : ROADMAP_ITEMS;
+ const itemsFor = (status: RoadmapStatus) =>
+ filtered.filter((item): item is Extract => item.status !== "shipped" && item.status === status);
+ const shipped = filtered.filter((item): item is Extract => item.status === "shipped");
+
+ return (
+
+
+
+
+ {CATEGORIES.map((cat) => (
+
+ ))}
+
+
+
+ {COLUMNS.map((status) => {
+ const items = itemsFor(status);
+ return (
+
+
+
+
+ {STATUS_LABELS[status]}
+ {items.length}
+
+
{STATUS_DESCRIPTIONS[status]}
+
+
+ {items.map((item) => (
+
+ ))}
+ {items.length === 0 && (
+
Nothing here yet
+ )}
+
+
+ );
+ })}
+
+
+ {shipped.length > 0 && (
+
+
+
+
+ {STATUS_LABELS.shipped}
+ {shipped.length}
+
+
+ Full changelog →
+
+
+
+ {shipped.map((item) => (
+
+
+
+ ))}
+
+
+ )}
+
+ );
+}
diff --git a/components/marketing/roadmap/data.ts b/components/marketing/roadmap/data.ts
new file mode 100644
index 0000000..d743fc5
--- /dev/null
+++ b/components/marketing/roadmap/data.ts
@@ -0,0 +1,95 @@
+// Real signal only — no invented plans. "Now" comes from actual open PRs,
+// "Shipped" mirrors the real /changelog entries, "Next" comes from the
+// draft design doc at docs/design/visualize.md. "Later" has nothing behind
+// it yet, so it stays empty rather than promise something that isn't decided.
+
+export type RoadmapCategory = "Website" | "Skills";
+
+export type RoadmapStatus = "now" | "next" | "later" | "shipped";
+
+interface RoadmapItemBase {
+ id: string;
+ title: string;
+ description: string;
+ category: RoadmapCategory;
+}
+
+interface ActiveRoadmapItem extends RoadmapItemBase {
+ status: "now" | "next" | "later";
+ /** Open PR covering this work, if any. */
+ pr?: string;
+}
+
+interface ShippedRoadmapItem extends RoadmapItemBase {
+ status: "shipped";
+ shippedDate: string;
+ /** Commit or PR reference shown as a "$ git show"-style chip. */
+ ref?: { label: string; url: string };
+ /** Link to the changelog entry covering the ship. */
+ href?: string;
+}
+
+export type RoadmapItem = ActiveRoadmapItem | ShippedRoadmapItem;
+
+export const CATEGORIES: RoadmapCategory[] = ["Website", "Skills"];
+
+export const STATUS_LABELS: Record = {
+ now: "In Progress",
+ next: "Next",
+ later: "Later",
+ shipped: "Shipped",
+};
+
+export const STATUS_DESCRIPTIONS: Record = {
+ now: "Being worked on right now.",
+ next: "Queued up after what's in progress.",
+ later: "On the radar, not yet started.",
+ shipped: "Already live.",
+};
+
+const REPO = "https://github.com/CommandOSSLabs/ai-devkit";
+
+export const ROADMAP_ITEMS: RoadmapItem[] = [
+ {
+ id: "browse-skills-nav",
+ status: "now",
+ category: "Website",
+ title: "Browse Skills nav + loading transition",
+ description: "A dedicated nav button to browse skills, with a TextMorph transition while the list loads.",
+ pr: `${REPO}/pull/15`,
+ },
+ {
+ id: "repo-meta-rate-limit",
+ status: "now",
+ category: "Website",
+ title: "Fix GitHub repo-meta rate limiting",
+ description: "Stops hitting GitHub's rate limit on repo metadata calls and removes a dead WebGL scroll loop left running behind it.",
+ pr: `${REPO}/pull/13`,
+ },
+ {
+ id: "cmk-visualize",
+ status: "next",
+ category: "Skills",
+ title: "New skill: cmk:visualize",
+ description: "Turns content you already have — a design doc, a tracker query, a raw description — into a rendered diagram, slide deck, or animated teaser, instead of a wall of markdown.",
+ },
+ {
+ id: "cmk-interpret",
+ status: "shipped",
+ category: "Skills",
+ shippedDate: "Aug 14",
+ title: "New skill: cmk:interpret",
+ description: "For user-invoked interpret sessions, plus acceptance-criteria notation for requirements.",
+ ref: { label: "0d7b298", url: `${REPO}/commit/0d7b298` },
+ href: "/changelog",
+ },
+ {
+ id: "skills-site-launch",
+ status: "shipped",
+ category: "Website",
+ shippedDate: "Aug 13",
+ title: "skills.commandoss.com launched",
+ description: "Homepage moved to the skills page, nav links go to real URLs, and the install box got a package-manager switcher.",
+ href: "/changelog",
+ },
+];