feat(site): rewrite landing page — Claude Code Command Center

Reposition cladm from "monitor & launcher" to "command center" with
embedded PTY grid, tabbed workspaces, and pane controls. New hero
animation shows picker → grid transition. JSX workspace mockup with
4 active panes, traffic-light buttons, and live terminal content.
Updated features, two-mode controls, and metadata throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-28 21:00:37 +00:00
parent 1a99a83fd7
commit ccfae53233
3 changed files with 483 additions and 333 deletions

View File

@@ -14,9 +14,9 @@ const pixel = Silkscreen({
});
export const metadata: Metadata = {
title: "cladm — Monitor & launch Claude Code sessions",
title: "cladm — Claude Code Command Center",
description:
"Multi-project Claude Code session monitor. Track busy/idle status in real time, see usage costs, get notified when Claude finishes, and launch everything in parallel.",
"Multiproject workspace for Claude Code. Embedded terminal grid with tabbed workspaces, pane controls, real-time status tracking, usage monitoring, and full keyboard-driven workflow.",
icons: {
icon: [
{ url: "/favicon.ico", sizes: "32x32" },
@@ -26,8 +26,8 @@ export const metadata: Metadata = {
apple: "/apple-touch-icon.png",
},
openGraph: {
title: "cladm",
description: "Monitor & launch Claude Code sessions across all your projects",
title: "cladm — Claude Code Command Center",
description: "Manage all your Claude Code sessions from one terminal. Embedded PTY grid, tabbed workspaces, live monitoring, and pane controls.",
url: "https://claudm.com",
siteName: "cladm",
type: "website",
@@ -36,14 +36,14 @@ export const metadata: Metadata = {
url: "/og-image.png",
width: 1200,
height: 630,
alt: "cladm — Monitor & launch Claude Code sessions",
alt: "cladm — Claude Code Command Center",
},
],
},
twitter: {
card: "summary_large_image",
title: "cladm",
description: "Monitor & launch Claude Code sessions across all your projects",
title: "cladm — Claude Code Command Center",
description: "Manage all your Claude Code sessions from one terminal. Embedded PTY grid, tabbed workspaces, live monitoring, and pane controls.",
images: ["/og-image.png"],
},
};

View File

@@ -11,10 +11,7 @@ import {
NetworkIcon,
GamepadIcon,
BlocksIcon,
ArrowRightIcon,
ExternalLinkIcon,
LinkedinIcon,
MailIcon,
SpaceInvadersIcon,
EyeIcon,
BellIcon,
@@ -90,13 +87,56 @@ function FeatureBlock({
);
}
function GridPaneMockup({
name,
status,
elapsed,
children,
focused,
}: {
name: string;
status: "busy" | "idle";
elapsed?: string;
children: React.ReactNode;
focused?: boolean;
}) {
return (
<div className={`bg-bg border ${focused ? "border-accent" : "border-border"}`}>
{/* Pane title bar */}
<div className="flex items-center justify-between px-3 py-1 border-b border-border bg-surface-2/60">
<div className="font-[family-name:var(--font-mono)] text-[10px] flex items-center gap-1.5">
{status === "busy" ? (
<span className="text-green"></span>
) : (
<>
<span className="text-yellow"></span>
{elapsed && <span className="text-dim">{elapsed}</span>}
</>
)}
<span className="text-text">{name}</span>
</div>
<div className="flex items-center gap-1">
<span className="text-cyan text-[8px]"></span>
<span className="text-dim text-[8px]"></span>
<span className="text-[#27c93f] text-[8px]"></span>
<span className="text-[#ff5f56] text-[8px]"></span>
</div>
</div>
{/* Pane content */}
<div className="p-3 font-[family-name:var(--font-mono)] text-[10px] text-dim leading-relaxed">
{children}
</div>
</div>
);
}
export default function Home() {
return (
<div className="min-h-screen bg-bg selection:bg-accent/30">
<SubscribeModal />
{/* ══════ HERO ══════ */}
<section className="relative overflow-hidden scanlines">
{/* Grid background */}
<div
className="absolute inset-0 opacity-[0.04]"
style={{
@@ -142,14 +182,13 @@ export default function Home() {
</h1>
<p className="font-[family-name:var(--font-pixel)] text-accent text-lg md:text-xl mb-5">
MULTI-PROJECT CLAUDE CODE MONITOR
CLAUDE CODE COMMAND CENTER
</p>
<p className="font-[family-name:var(--font-mono)] text-dim text-sm max-w-md leading-relaxed mb-8">
Track all your Claude Code sessions in one place. See
busy/idle status in real time, monitor usage costs, get
notified when Claude finishes, and launch everything in
parallel Terminal windows.
Manage all your Claude Code sessions from one terminal.
An embedded PTY grid with tabbed workspaces, pane controls,
real-time status tracking, and full keyboard-driven workflow.
</p>
{/* Install command */}
@@ -169,7 +208,7 @@ export default function Home() {
</p>
</div>
{/* Right — terminal cascade */}
{/* Right — terminal cascade: picker → grid */}
<div className="flex-1 w-full max-w-xl">
<TerminalCascade />
</div>
@@ -186,50 +225,185 @@ export default function Home() {
</div>
</section>
{/* ══════ DEMO GIF ══════ */}
{/* ══════ THE WORKSPACE ══════ */}
<section className="max-w-5xl mx-auto px-6 py-20">
<div className="text-center mb-10">
<div className="text-center mb-4">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-3">
// SEE IT IN ACTION
// THE WORKSPACE
</h2>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs max-w-2xl mx-auto leading-relaxed">
Every Claude Code session runs in an embedded terminal pane no separate windows.
See all your projects at once, switch focus with a click, and never lose track of what Claude is doing.
</p>
</div>
<TerminalWindow title="cladm">
<Image
src="/demo.gif"
alt="cladm demo showing project navigation"
width={980}
height={500}
className="w-full"
unoptimized
/>
</TerminalWindow>
{/* Grid workspace mockup */}
<div className="mt-10">
<div className="pixel-border bg-surface overflow-hidden">
{/* Tab bar */}
<div className="flex items-center bg-surface-2 border-b-2 border-border">
<div className="px-4 py-2 border-b-2 border-accent font-[family-name:var(--font-mono)] text-xs">
<span className="text-green"></span>
<span className="text-text"> acme-api</span>
<span className="text-dim"> · </span>
<span className="text-yellow"></span>
<span className="text-text"> quantum-dash</span>
</div>
<div className="px-4 py-2 font-[family-name:var(--font-mono)] text-xs text-dim border-b-2 border-transparent">
<span className="text-green"></span>
<span> ml-pipeline</span>
<span className="text-dim"> · </span>
<span className="text-green"></span>
<span> infra-k8s</span>
</div>
<div className="ml-auto px-3 py-2 font-[family-name:var(--font-mono)] text-[10px] text-dim">
<span className="text-accent">+</span> add pane
</div>
</div>
{/* Pane grid */}
<div className="grid grid-cols-2 gap-[2px] p-[2px]">
{/* Pane 1: acme-api */}
<GridPaneMockup name="acme-api" status="busy" focused>
<div className="text-green mb-1">&gt; I&apos;ll analyze the authentication module and</div>
<div className="text-green">{" "}fix the token refresh bug you mentioned.</div>
<div className="mt-2">
<span className="text-accent"></span> Reading src/auth/token.ts
</div>
<div>
<span className="text-accent"></span> Reading src/auth/middleware.ts
</div>
<div>
<span className="text-accent"></span> Grep: refreshToken pattern
</div>
<div className="text-green mt-1">
Found 3 files with stale token logic.
<span className="cursor-blink text-accent">_</span>
</div>
</GridPaneMockup>
{/* Pane 2: quantum-dash */}
<GridPaneMockup name="quantum-dash" status="idle" elapsed="4m">
<div className="text-text">I&apos;ve updated the chart component to use</div>
<div className="text-text">the new streaming data format. Changes:</div>
<div className="mt-2">
<span className="text-green"></span> src/components/chart.tsx
</div>
<div>
<span className="text-green"></span> src/hooks/useChartData.ts
</div>
<div>
<span className="text-green"></span> src/types/stream.d.ts
</div>
<div className="mt-2 text-yellow">Waiting for your input...</div>
</GridPaneMockup>
{/* Pane 3: ml-pipeline */}
<GridPaneMockup name="ml-pipeline" status="busy">
<div className="text-green">&gt; Building the BERT fine-tuning pipeline</div>
<div className="text-green">{" "}with the new training dataset.</div>
<div className="mt-2">
<span className="text-accent"></span> Writing src/train.py
</div>
<div className="mt-1">
Processing: epoch 3/10{" "}
<span className="text-accent"></span>
<span className="text-border"></span>{" "}
<span className="text-text">30%</span>
</div>
</GridPaneMockup>
{/* Pane 4: infra-k8s */}
<GridPaneMockup name="infra-k8s" status="busy">
<div className="text-green">&gt; Updating the Kubernetes deployment</div>
<div className="text-green">{" "}manifests for staging.</div>
<div className="mt-2">
<span className="text-accent"></span> Reading k8s/staging/deployment.yaml
</div>
<div>
<span className="text-accent"></span> Reading k8s/staging/service.yaml
</div>
<div className="mt-1 text-green">
Scaling replicas 2 4 for load test
<span className="cursor-blink text-accent">_</span>
</div>
</GridPaneMockup>
</div>
</div>
</div>
{/* Feature callouts */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-10">
<div className="text-center">
<div className="font-[family-name:var(--font-pixel)] text-accent text-xs uppercase tracking-wider mb-2">
Embedded PTY Grid
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Each pane runs a real pseudo-terminal via forkpty(). Full I/O, ANSI colors, resize no tmux needed.
</p>
</div>
<div className="text-center">
<div className="font-[family-name:var(--font-pixel)] text-accent text-xs uppercase tracking-wider mb-2">
Tabbed Workspaces
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Group sessions into tabs. Inline pane names with status icons show what&apos;s running at a glance.
</p>
</div>
<div className="text-center">
<div className="font-[family-name:var(--font-pixel)] text-accent text-xs uppercase tracking-wider mb-2">
Pane Controls
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Traffic-light buttons on every pane: close, expand, minimize, plus a folder-open button. Fully mouse-driven.
</p>
</div>
</div>
</section>
<PixelDivider />
{/* ══════ SCREENSHOTS ══════ */}
{/* ══════ SMART PICKER ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-12 text-center">
// SCREENSHOTS
</h2>
<div className="text-center mb-4">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-3">
// THE SMART PICKER
</h2>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs max-w-2xl mx-auto leading-relaxed">
It starts with a smart project picker. cladm reads{" "}
<code className="text-accent">~/.claude/history.jsonl</code> to discover every project
you&apos;ve used with Claude Code git branch, sync status, dirty state, session history, stack detection all loaded in parallel.
Select what you need, hit Enter, and the grid workspace takes over.
</p>
</div>
<div className="space-y-16">
{/* Main view */}
<div className="mt-8">
<TerminalWindow title="cladm — 8 projects">
<Image
src="/demo.gif"
alt="cladm smart picker showing project navigation and selection"
width={980}
height={500}
className="w-full"
unoptimized
/>
</TerminalWindow>
</div>
{/* Picker screenshots */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mt-12">
<div>
<div className="flex items-center gap-4 mb-4">
<div className="flex items-center gap-4 mb-3">
<div className="h-[2px] flex-1 bg-border" />
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider whitespace-nowrap">
PROJECT LIST
</h3>
<div className="h-[2px] flex-1 bg-border" />
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs text-center mb-6">
All your projects sorted by recent Claude usage. Git branch, sync
status, dirty state, session count, and auto-detected stack at a
glance.
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] text-center mb-4">
Sorted by recent Claude usage. Git metadata, session count, and stack tags at a glance.
</p>
<TerminalWindow title="cladm — 8 projects">
<TerminalWindow title="cladm — project list">
<Image
src="/screenshot-main.png"
alt="cladm main project list view"
@@ -240,25 +414,21 @@ export default function Home() {
</TerminalWindow>
</div>
{/* Expanded view */}
<div>
<div className="flex items-center gap-4 mb-4">
<div className="flex items-center gap-4 mb-3">
<div className="h-[2px] flex-1 bg-border" />
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider whitespace-nowrap">
EXPANDED VIEW
</h3>
<div className="h-[2px] flex-1 bg-border" />
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs text-center mb-6">
Press <Keycap>&rarr;</Keycap> to expand. Browse branches, see
session conversations with last prompt and Claude&apos;s response.
Running sessions show <span className="text-green"> running</span> or{" "}
<span className="text-yellow"> idle</span> status inline. Resume any session directly.
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] text-center mb-4">
Browse branches, past sessions with conversation previews. Resume any session directly.
</p>
<TerminalWindow title="cladm — 2 selected (1 branch switch)">
<TerminalWindow title="cladm — expanded">
<Image
src="/screenshot-expanded.png"
alt="cladm expanded view with sessions and branches"
alt="cladm expanded view with sessions"
width={980}
height={600}
className="w-full"
@@ -273,104 +443,83 @@ export default function Home() {
{/* ══════ LIVE MONITORING ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-12 text-center">
// LIVE SESSION MONITORING
// REAL-TIME STATUS
</h2>
<div className="max-w-2xl mx-auto">
<div className="pixel-border bg-surface p-6">
<p className="font-[family-name:var(--font-mono)] text-dim text-xs leading-relaxed mb-5">
cladm detects all running Claude Code sessions across every project and shows their real-time status.
When any session finishes, a sound plays and the dock icon bounces so you never miss it, even across dozens of parallel sessions.
</p>
<div className="space-y-3 font-[family-name:var(--font-mono)] text-xs">
<div className="flex items-center gap-3">
<span className="text-green text-base"></span>
<span className="text-text">Busy</span>
<span className="text-dim"> Claude is actively processing</span>
</div>
<div className="flex items-center gap-3">
<span className="text-yellow text-base"></span>
<span className="text-dim">3m</span>
<span className="text-text">Idle</span>
<span className="text-dim"> Claude finished 3 min ago, waiting for input</span>
</div>
<div className="flex items-center gap-3">
<span className="text-dim text-base"></span>
<span className="text-text ml-[22px]">No session</span>
<span className="text-dim"> No active Claude process</span>
</div>
</div>
<div className="mt-5 pt-4 border-t border-border">
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Detection reads the tail of each session&apos;s JSONL in{" "}
<code className="text-accent">~/.claude/projects/</code>. A session is
busy if the file was written recently OR the last assistant message
has a pending tool call. This prevents false idle triggers during
long-running tools and subtasks.
</p>
</div>
</div>
</div>
</section>
<PixelDivider />
{/* ══════ USAGE + IDLE PANELS ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-12 text-center">
// USAGE & IDLE PANELS
</h2>
<div className="space-y-12 max-w-4xl mx-auto">
{/* Usage panel screenshot */}
<div>
<div className="flex items-center gap-4 mb-4">
<div className="h-[2px] flex-1 bg-border" />
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider whitespace-nowrap">
USAGE TRACKING
<div className="max-w-3xl mx-auto">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Status indicators */}
<div className="pixel-border bg-surface p-6">
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider mb-4">
Session Status
</h3>
<div className="h-[2px] flex-1 bg-border" />
<div className="space-y-3 font-[family-name:var(--font-mono)] text-xs">
<div className="flex items-center gap-3">
<span className="text-green text-base"></span>
<span className="text-text">Busy</span>
<span className="text-dim"> Claude is actively working</span>
</div>
<div className="flex items-center gap-3">
<span className="text-yellow text-base"></span>
<span className="text-dim">3m</span>
<span className="text-text">Idle</span>
<span className="text-dim"> waiting for your input</span>
</div>
<div className="flex items-center gap-3">
<span className="text-dim text-base"></span>
<span className="text-text ml-[22px]">No session</span>
<span className="text-dim"> not running</span>
</div>
</div>
<div className="mt-4 pt-3 border-t border-border">
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Status visible in both picker rows and grid pane headers.
Sound + dock bounce on idle transitions.
</p>
</div>
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs text-center mb-6">
Press <Keycap>u</Keycap> to toggle. Tracks session (5h window), weekly
all-model and sonnet-only costs against configurable plan limits, plus monthly totals.
</p>
<TerminalWindow title="cladm — usage panel">
<Image
src="/screenshot-usage.png"
alt="cladm usage tracking panel with session, weekly, and monthly cost bars"
width={980}
height={500}
className="w-full"
/>
</TerminalWindow>
</div>
{/* Idle sessions screenshot */}
<div>
<div className="flex items-center gap-4 mb-4">
<div className="h-[2px] flex-1 bg-border" />
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider whitespace-nowrap">
IDLE SESSIONS
{/* Usage tracking */}
<div className="pixel-border bg-surface p-6">
<h3 className="font-[family-name:var(--font-pixel)] text-text text-xs uppercase tracking-wider mb-4">
Usage Tracking
</h3>
<div className="h-[2px] flex-1 bg-border" />
<div className="space-y-3 font-[family-name:var(--font-mono)] text-[10px]">
<div>
<div className="flex justify-between mb-1">
<span className="text-dim">session (5h)</span>
<span className="text-text">$2.40 / $5.00</span>
</div>
<div className="h-2 bg-bg border border-border">
<div className="h-full bg-accent" style={{ width: "48%" }} />
</div>
</div>
<div>
<div className="flex justify-between mb-1">
<span className="text-dim">weekly all-model</span>
<span className="text-text">$18.50 / $100</span>
</div>
<div className="h-2 bg-bg border border-border">
<div className="h-full bg-green" style={{ width: "18.5%" }} />
</div>
</div>
<div>
<div className="flex justify-between mb-1">
<span className="text-dim">monthly total</span>
<span className="text-text">$67.20</span>
</div>
<div className="h-2 bg-bg border border-border">
<div className="h-full bg-cyan" style={{ width: "33.6%" }} />
</div>
</div>
</div>
<div className="mt-4 pt-3 border-t border-border">
<p className="font-[family-name:var(--font-mono)] text-dim text-[10px] leading-relaxed">
Press <Keycap>u</Keycap> in picker mode. Tracks session, weekly,
and monthly costs against configurable plan limits.
</p>
</div>
</div>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs text-center mb-6">
Press <Keycap>i</Keycap> to toggle. Shows sessions waiting for your
input, sorted by most recently idle. Press Enter to focus a session&apos;s
Terminal tab directly.
</p>
<TerminalWindow title="cladm — idle sessions (2)">
<Image
src="/screenshot-idle.png"
alt="cladm idle sessions panel showing waiting sessions with elapsed time"
width={980}
height={500}
className="w-full"
/>
</TerminalWindow>
</div>
</div>
</section>
@@ -384,81 +533,84 @@ export default function Home() {
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<FeatureBlock
icon={<TerminalIcon size={28} />}
title="EMBEDDED GRID"
desc="Run multiple Claude Code sessions side by side in a tiled terminal grid. Each pane is a real PTY with full I/O — no separate windows needed."
/>
<FeatureBlock
icon={<BlocksIcon size={28} />}
title="TABBED WORKSPACES"
desc="Group sessions into named tabs. Inline pane indicators show project names and busy/idle status at a glance."
/>
<FeatureBlock
icon={<GamepadIcon size={28} />}
title="PANE CONTROLS"
desc="Traffic-light buttons on every pane: close, minimize, expand to full screen. Blue button opens the project folder."
/>
<FeatureBlock
icon={<SearchIcon size={28} />}
title="SELECT MODE"
desc="Double-click any pane to enter select mode. Copy text from the full scrollback buffer — up to 5,000 lines of history."
/>
<FeatureBlock
icon={<EyeIcon size={28} />}
title="LIVE MONITORING"
desc="Track all Claude sessions across every project. Busy/idle status updates in real time with elapsed timers."
desc="Track busy/idle status across all sessions in real time. Elapsed timers show how long each session has been waiting."
/>
<FeatureBlock
icon={<TrendingUpIcon size={28} />}
title="USAGE TRACKING"
desc="Session, weekly, and monthly cost bars. Track all-model and sonnet-only usage against configurable plan limits."
desc="Session, weekly, and monthly cost bars against configurable plan limits. Track all-model and sonnet-only usage."
/>
<FeatureBlock
icon={<BellIcon size={28} />}
title="NOTIFICATIONS"
desc="Sound + dock bounce when any session finishes. Never miss a completed task across dozens of parallel sessions."
/>
<FeatureBlock
icon={<ThunderIcon size={28} />}
title="FOCUS SESSION"
desc="Press Enter on any idle session to instantly focus its Terminal tab. Flash animation highlights the window."
/>
<FeatureBlock
icon={<SearchIcon size={28} />}
title="AUTO-DISCOVERY"
desc="Reads ~/.claude/history.jsonl to find every project you've used with Claude Code. No config needed."
/>
<FeatureBlock
icon={<NetworkIcon size={28} />}
title="GIT METADATA"
desc="Branch, sync status (ahead/behind), last commit, dirty state — all loaded in parallel per project."
/>
<FeatureBlock
icon={<FolderIcon size={28} />}
title="SESSION BROWSER"
desc="Expand any project to browse past sessions. See conversation previews and resume directly."
title="AUTO-DISCOVERY"
desc="Reads ~/.claude/history.jsonl to find every project. Git branch, sync status, dirty state — all loaded in parallel."
/>
<FeatureBlock
icon={<TerminalIcon size={28} />}
title="PARALLEL LAUNCH"
desc="Select multiple projects and hit Enter. Each opens in a new Terminal.app window simultaneously."
/>
<FeatureBlock
icon={<BlocksIcon size={28} />}
title="STACK DETECTION"
desc="Auto-detects project stack: TypeScript, Python, Rust, Go, Docker, and more from config files."
icon={<ThunderIcon size={28} />}
title="DIRECT PTY"
desc="Native pseudo-terminal management via forkpty(). No tmux dependency. Zero configuration. Just works."
/>
</div>
</section>
<PixelDivider />
{/* ══════ KEYBINDINGS ══════ */}
{/* ══════ CONTROLS ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-12 text-center">
// CONTROLS
</h2>
<div className="max-w-2xl mx-auto">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 max-w-4xl mx-auto">
{/* Picker mode */}
<div className="pixel-border bg-surface p-6">
<div className="grid grid-cols-2 gap-y-3 font-[family-name:var(--font-mono)] text-xs">
<h3 className="font-[family-name:var(--font-pixel)] text-accent text-xs uppercase tracking-wider mb-4 text-center">
Picker Mode
</h3>
<div className="grid grid-cols-2 gap-y-2 font-[family-name:var(--font-mono)] text-xs">
{[
["↑ ↓", "Navigate"],
["Space", "Toggle selection"],
["Space", "Toggle select"],
["→", "Expand project"],
["←", "Collapse"],
["Enter", "Launch selected / focus session"],
["i", "Toggle idle sessions panel"],
["u", "Toggle usage panel"],
["/", "Filter projects"],
["Enter", "Launch grid"],
["/", "Filter"],
["a", "Select all"],
["n", "Deselect all"],
["s", "Cycle sort mode"],
["f", "Open folder in Finder"],
["g", "Go to active session"],
["PgUp PgDn", "Jump 15 rows"],
["q / Esc", "Quit"],
["s", "Cycle sort"],
["u", "Usage panel"],
["i", "Idle sessions"],
["f", "Open folder"],
["g", "Go to session"],
["q", "Quit"],
].map(([key, desc]) => (
<div key={key} className="contents">
<div className="text-accent">{key}</div>
@@ -467,12 +619,58 @@ export default function Home() {
))}
</div>
</div>
{/* Grid mode */}
<div className="pixel-border bg-surface p-6">
<h3 className="font-[family-name:var(--font-pixel)] text-accent text-xs uppercase tracking-wider mb-4 text-center">
Grid Mode
</h3>
<div className="grid grid-cols-2 gap-y-2 font-[family-name:var(--font-mono)] text-xs">
{[
["Click", "Focus pane"],
["Dbl-click", "Select mode"],
["Alt+1-9", "Switch tab"],
["Alt+n/p", "Next/prev tab"],
["+ button", "Add pane"],
["Esc", "Back to picker"],
].map(([key, desc]) => (
<div key={key} className="contents">
<div className="text-accent">{key}</div>
<div className="text-dim">{desc}</div>
</div>
))}
</div>
<div className="mt-4 pt-3 border-t border-border">
<div className="font-[family-name:var(--font-pixel)] text-text text-[10px] uppercase tracking-wider mb-2">
Pane Buttons
</div>
<div className="grid grid-cols-2 gap-y-2 font-[family-name:var(--font-mono)] text-xs">
{[
["● blue", "Open folder"],
["● green", "Expand pane"],
["● yellow", "Minimize"],
["● red", "Close pane"],
].map(([key, desc], i) => (
<div key={key} className="contents">
<div className={
i === 0 ? "text-cyan" :
i === 1 ? "text-[#27c93f]" :
i === 2 ? "text-yellow" :
"text-[#ff5f56]"
}>{key}</div>
<div className="text-dim">{desc}</div>
</div>
))}
</div>
</div>
</div>
</div>
</section>
<PixelDivider />
{/* ══════ INSTALL ══════ */}
{/* ══════ QUICK START ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-12 text-center">
// QUICK START
@@ -514,91 +712,13 @@ export default function Home() {
<div className="mt-6 text-center">
<p className="font-[family-name:var(--font-mono)] text-dim text-xs">
Or try with mock data:{" "}
Try with mock data:{" "}
<code className="text-yellow">cladm --demo</code>
</p>
</div>
</div>
</section>
{/* ══════ LAUNCH RESULT ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<h2 className="font-[family-name:var(--font-pixel)] text-accent text-sm uppercase tracking-[0.3em] mb-4 text-center">
// HIT ENTER
</h2>
<p className="font-[family-name:var(--font-mono)] text-dim text-xs text-center mb-10 max-w-lg mx-auto">
Select your projects, press Enter, and watch them all launch in
parallel. Each project opens a fresh Claude Code session in its own
Terminal window.
</p>
<div className="flex flex-col md:flex-row items-center gap-6">
{/* Mini cladm picker */}
<div className="flex-1 w-full">
<TerminalWindow title="cladm — 3 selected">
<div className="p-3 font-[family-name:var(--font-mono)] text-[10px] leading-relaxed">
<div className="text-dim mb-1">
{" PROJECT BRANCH LAST USE"}
</div>
<div className="bg-[#283457] px-1">
<span className="text-green"></span>
<span className="text-green"> []</span>
<span className="text-text">
{" "}
acme-api{" "}
</span>
<span className="text-magenta">main</span>
<span className="text-cyan">{" "}25m ago</span>
</div>
<div className="px-1">
<span className="text-yellow"></span>
<span className="text-dim">2m</span>
<span className="text-green">[]</span>
<span className="text-text"> quantum-dashboard{" "}</span>
<span className="text-magenta">feat/cha</span>
<span className="text-cyan">{" "}1h ago</span>
</div>
<div className="px-1">
<span className="text-green"></span>
<span className="text-green"> []</span>
<span className="text-text"> ml-pipeline{" "}</span>
<span className="text-magenta">exp/bert</span>
<span className="text-cyan">{" "}just now</span>
</div>
<div className="px-1">
<span className="text-dim"></span>
<span className="text-dim"> [ ]</span>
<span className="text-dim"> pixel-engine{" "}develop{" "}3h ago</span>
</div>
</div>
</TerminalWindow>
</div>
{/* Arrow */}
<div className="font-[family-name:var(--font-pixel)] text-accent text-2xl flex-shrink-0 rotate-90 md:rotate-0">
&gt;&gt;&gt;
</div>
{/* Claude Code terminals */}
<div className="flex-1 w-full">
<div className="relative">
{/* Stacked terminal windows effect */}
<div className="absolute top-3 left-3 right-[-3px] bottom-[-3px] border-2 border-border bg-surface-2 opacity-40" />
<div className="absolute top-[6px] left-[6px] right-[-6px] bottom-[-6px] border-2 border-border bg-surface-2 opacity-20" />
<TerminalWindow title="claude — acme-api">
<Image
src="/claude-terminal.webp"
alt="Claude Code session launched in Terminal"
width={960}
height={518}
className="w-full"
/>
</TerminalWindow>
</div>
</div>
</div>
</section>
{/* ══════ NEWSLETTER ══════ */}
<section className="max-w-5xl mx-auto px-6 py-16">
<div className="max-w-md mx-auto">
@@ -665,7 +785,7 @@ export default function Home() {
</div>
</div>
<div className="mt-6 font-[family-name:var(--font-mono)] text-dim text-[10px] text-center">
Built with Bun + OpenTUI. Pixel art by the cladm creatures.
Built with Bun + OpenTUI. Direct PTY grid, no tmux. Pixel art by the cladm creatures.
</div>
</div>
</footer>

View File

@@ -1,7 +1,6 @@
"use client";
import { useEffect, useState, useCallback } from "react";
import Image from "next/image";
const projects = [
{ name: "acme-api", branch: "main", time: "25m ago", status: "busy" as const },
@@ -10,13 +9,13 @@ const projects = [
];
type Phase =
| "typing" // cladm console visible, cursor selecting projects
| "selecting" // checkboxes toggling on one by one
| "enter" // "Enter" flash, cladm fades
| "cascade" // terminals fly in
| "hold" // terminals visible
| "fadeout" // everything fades, restart
| "pause"; // brief gap before loop
| "typing"
| "selecting"
| "enter"
| "grid"
| "hold"
| "fadeout"
| "pause";
export function TerminalCascade() {
const [phase, setPhase] = useState<Phase>("typing");
@@ -27,31 +26,18 @@ export function TerminalCascade() {
setSelectedCount(0);
setPhase("typing");
// Typing/appear cladm console
const t1 = setTimeout(() => setPhase("selecting"), 800);
// Toggle checkboxes one by one
const t2 = setTimeout(() => setSelectedCount(1), 1200);
const t3 = setTimeout(() => setSelectedCount(2), 1600);
const t4 = setTimeout(() => setSelectedCount(3), 2000);
// Enter pressed
const t5 = setTimeout(() => setPhase("enter"), 2600);
// Cascade terminals in
const t6 = setTimeout(() => setPhase("cascade"), 3200);
// Hold
const t7 = setTimeout(() => setPhase("hold"), 3800);
// Fade out
const t8 = setTimeout(() => setPhase("fadeout"), 6200);
// Pause then restart
const t6 = setTimeout(() => setPhase("grid"), 3400);
const t7 = setTimeout(() => setPhase("hold"), 4000);
const t8 = setTimeout(() => setPhase("fadeout"), 7000);
const t9 = setTimeout(() => {
setPhase("pause");
setCycle((c) => c + 1);
}, 7000);
}, 7800);
return [t1, t2, t3, t4, t5, t6, t7, t8, t9];
}, []);
@@ -65,19 +51,18 @@ export function TerminalCascade() {
return () => clearTimeout(start);
}, [cycle, runCycle]);
const showCladm = phase === "typing" || phase === "selecting" || phase === "enter";
const showCascade = phase === "cascade" || phase === "hold" || phase === "fadeout";
const showPicker = phase === "typing" || phase === "selecting" || phase === "enter";
const showGrid = phase === "grid" || phase === "hold" || phase === "fadeout";
return (
<div className="relative w-full min-h-[340px]">
{/* ── CLADM console (cause) ── */}
<div className="relative w-full min-h-[360px]">
{/* ── Picker (select projects) ── */}
<div
className={`transition-all duration-500 ${
showCladm ? "opacity-100 scale-100" : "opacity-0 scale-95 pointer-events-none absolute inset-0"
showPicker ? "opacity-100 scale-100" : "opacity-0 scale-95 pointer-events-none absolute inset-0"
}`}
>
<div className="pixel-border bg-surface overflow-hidden">
{/* Title bar */}
<div className="flex items-center gap-2 px-4 py-2 bg-surface-2 border-b-2 border-border">
<div className="w-3 h-3 bg-[#ff5f56]" />
<div className="w-3 h-3 bg-[#ffbd2e]" />
@@ -86,7 +71,6 @@ export function TerminalCascade() {
cladm {selectedCount} selected
</span>
</div>
{/* Project rows */}
<div className="p-3 font-[family-name:var(--font-mono)] text-[11px] leading-relaxed">
<div className="text-dim mb-1 text-[10px]">
{" PROJECT BRANCH LAST USE"}
@@ -121,15 +105,14 @@ export function TerminalCascade() {
<span></span><span> </span>[ ] pixel-engine{" "}develop{" "}3h ago
</div>
{/* Enter hint */}
<div className="mt-3 pt-2 border-t border-border text-[10px]">
{phase === "enter" ? (
<span className="text-accent font-bold cascade-flash">
Launching 3 projects...
Launching 3 sessions into grid...
</span>
) : (
<span className="text-dim">
navigate · space toggle · enter launch
navigate · space toggle · enter launch grid
</span>
)}
</div>
@@ -137,45 +120,92 @@ export function TerminalCascade() {
</div>
</div>
{/* ── Terminal cascade (effect) ── */}
{/* ── Grid workspace (result) ── */}
<div
className={`transition-opacity duration-500 ${
showCascade ? "opacity-100" : "opacity-0 pointer-events-none absolute inset-0"
className={`transition-opacity duration-600 ${
showGrid ? "opacity-100" : "opacity-0 pointer-events-none absolute inset-0"
}`}
>
<div className="relative h-[320px]">
{projects.map((proj, i) => (
<div
key={`term-${proj.name}-${cycle}`}
className={`absolute left-0 right-0 border-2 bg-surface overflow-hidden
${phase === "cascade" || phase === "hold" ? "cascade-in" : ""}
${phase === "hold" && i === projects.length - 1 ? "cascade-glow" : ""}`}
style={{
animationDelay: `${i * 0.2}s`,
top: `${i * 80}px`,
marginLeft: `${i * 16}px`,
marginRight: `${(projects.length - 1 - i) * 16}px`,
zIndex: i + 1,
borderColor: "var(--color-border)",
}}
>
<div className="flex items-center gap-1.5 px-3 py-1 bg-surface-2 border-b border-border">
<div className="w-[7px] h-[7px] bg-[#ff5f56]" />
<div className="w-[7px] h-[7px] bg-[#ffbd2e]" />
<div className="w-[7px] h-[7px] bg-[#27c93f]" />
<span className="ml-2 font-[family-name:var(--font-mono)] text-dim text-[9px] truncate">
claude {proj.name}
</span>
</div>
<Image
src="/claude-welcome.png"
alt="Claude Code welcome screen"
width={570}
height={260}
className="w-full h-auto"
/>
<div className={`pixel-border bg-surface overflow-hidden ${phase === "hold" ? "cascade-glow" : phase === "grid" ? "cascade-in" : ""}`}>
{/* Tab bar */}
<div className="flex items-center bg-surface-2 border-b-2 border-border">
<div className="px-3 py-1.5 border-b-2 border-accent font-[family-name:var(--font-mono)] text-[9px]">
<span className="text-green"></span>
<span className="text-text"> acme-api</span>
<span className="text-dim"> · </span>
<span className="text-yellow"></span>
<span className="text-text"> quantum-dash</span>
</div>
))}
<div className="px-3 py-1.5 font-[family-name:var(--font-mono)] text-[9px] text-dim border-b-2 border-transparent">
<span className="text-green"></span>
<span> ml-pipeline</span>
</div>
</div>
{/* Pane grid */}
<div className="grid grid-cols-2 gap-px bg-border">
{/* Pane 1: acme-api (busy) */}
<div className="bg-surface">
<div className="flex items-center justify-between px-2 py-[3px] border-b border-border">
<div className="font-[family-name:var(--font-mono)] text-[8px]">
<span className="text-green"></span>
<span className="text-text"> acme-api</span>
</div>
<div className="flex items-center gap-[3px]">
<span className="text-cyan text-[6px]"></span>
<span className="text-[#27c93f] text-[6px]"></span>
<span className="text-[#ff5f56] text-[6px]"></span>
</div>
</div>
<div className="p-2 font-[family-name:var(--font-mono)] text-[8px] text-dim leading-[1.6] h-[85px]">
<div className="text-green">&gt; I&apos;ll fix the token refresh bug</div>
<div>Reading src/auth/token.ts...</div>
<div>Reading src/auth/middleware.ts...</div>
<div>Grep: refreshToken pattern<span className="cursor-blink text-accent">_</span></div>
</div>
</div>
{/* Pane 2: quantum-dash (idle) */}
<div className="bg-surface">
<div className="flex items-center justify-between px-2 py-[3px] border-b border-border">
<div className="font-[family-name:var(--font-mono)] text-[8px]">
<span className="text-yellow"></span>
<span className="text-dim"> 4m </span>
<span className="text-text">quantum-dash</span>
</div>
<div className="flex items-center gap-[3px]">
<span className="text-cyan text-[6px]"></span>
<span className="text-[#27c93f] text-[6px]"></span>
<span className="text-[#ff5f56] text-[6px]"></span>
</div>
</div>
<div className="p-2 font-[family-name:var(--font-mono)] text-[8px] text-dim leading-[1.6] h-[85px]">
<div className="text-text">Updated chart component</div>
<div className="text-text">New hook: useChartData.ts</div>
<div className="text-yellow mt-1">Waiting for input...</div>
</div>
</div>
{/* Pane 3: ml-pipeline (busy, full width) */}
<div className="bg-surface col-span-2">
<div className="flex items-center justify-between px-2 py-[3px] border-b border-border">
<div className="font-[family-name:var(--font-mono)] text-[8px]">
<span className="text-green"></span>
<span className="text-text"> ml-pipeline</span>
</div>
<div className="flex items-center gap-[3px]">
<span className="text-cyan text-[6px]"></span>
<span className="text-[#27c93f] text-[6px]"></span>
<span className="text-[#ff5f56] text-[6px]"></span>
</div>
</div>
<div className="p-2 font-[family-name:var(--font-mono)] text-[8px] text-dim leading-[1.6] h-[65px]">
<div className="text-green">&gt; Building BERT fine-tuning pipeline</div>
<div>Processing dataset: train.jsonl</div>
<div>Epoch 3/10 <span className="text-accent"></span><span className="text-border"></span> 30%</div>
</div>
</div>
</div>
</div>
</div>
</div>