chore(site): updated graph and wording

This commit is contained in:
Nicholas Kissel 2026-01-28 15:57:58 -08:00
parent f79019e786
commit 65513f9086
9 changed files with 274 additions and 451 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

View file

@ -5,14 +5,13 @@ import { motion, AnimatePresence } from 'framer-motion';
import { ArrowRight, Terminal, Check } from 'lucide-react';
const CTA_TITLES = [
'Control any coding agent with one SDK.',
'Claude Code, Codex, OpenCode, Amp — unified.',
'Swap agents without refactoring.',
'Universal events. Universal sessions.',
'Stream, store, and replay agent transcripts.',
'Human-in-the-loop, built in.',
'One SDK. Every coding agent.',
'Deploy anywhere. Same API everywhere.',
'Run coding agents in sandboxes. Control them over HTTP.',
'A server inside your sandbox. An API for your app.',
'Claude Code, Codex, OpenCode, Amp — one HTTP API.',
'Your app connects remotely. The coding agent runs isolated.',
'Streaming events. Handling permissions. Managing sessions.',
'Install with curl. Connect over HTTP. Control any coding agent.',
'The bridge between your app and sandboxed coding agents.',
];
function AnimatedCTATitle() {
@ -72,7 +71,6 @@ const CopyInstallButton = () => {
export function CTASection() {
return (
<section className='relative overflow-hidden border-t border-white/10 px-6 py-32 text-center'>
<div className='absolute inset-0 z-0 bg-gradient-to-b from-black to-zinc-900/50' />
<motion.div
animate={{ opacity: [0.3, 0.5, 0.3] }}
transition={{ duration: 4, repeat: Infinity }}
@ -89,8 +87,8 @@ export function CTASection() {
transition={{ duration: 0.5, delay: 0.1 }}
className='mb-10 text-lg leading-relaxed text-zinc-400'
>
Universal SDK for coding agents. <br className='hidden md:block' />
Control Claude Code, Codex, OpenCode, and Amp with one API.
A server that runs inside isolated environments. <br className='hidden md:block' />
Your app connects remotely to control any coding agent.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}

View file

@ -8,7 +8,7 @@ const faqs = [
{
question: 'Does this replace the Vercel AI SDK?',
answer:
"No, they're complementary. AI SDK is for building chat interfaces and calling LLMs. This SDK is for controlling autonomous coding agents that write code and run commands. Use AI SDK for your UI, use this when you need an agent to actually code.",
"No, they're complementary. AI SDK is for building chat interfaces and calling LLMs. This SDK is for controlling autonomous coding agents that write code and run commands. Use AI SDK for your UI, use this when you need a coding agent to actually code.",
},
{
question: 'Which coding agents are supported?',
@ -23,7 +23,7 @@ const faqs = [
{
question: 'Can I run this locally or does it require a sandbox provider?',
answer:
"Both. Run locally for development, deploy to E2B, Daytona, or Vercel Sandboxes for production.",
'Both. Run locally for development, deploy to E2B, Daytona, or Vercel Sandboxes for production.',
},
{
question: 'Does it support [platform]?',
@ -40,6 +40,21 @@ const faqs = [
answer:
"Rust gives us a single static binary, fast startup, and predictable memory usage. That makes it easy to run inside sandboxes or in CI without shipping a large runtime, such as Node.js.",
},
{
question: "Why can't I just run coding agents locally?",
answer:
"You can for development. But in production, you need isolation. Coding agents execute arbitrary code — that can't happen on your servers. Sandboxes provide the isolation; this SDK provides the HTTP API to control coding agents remotely.",
},
{
question: "How is this different from the agent's official SDK?",
answer:
"Official SDKs assume local execution. They spawn processes and expect interactive terminals. This SDK runs a server inside a sandbox that you connect to over HTTP — designed for remote control from the start.",
},
{
question: 'Why not just SSH into the sandbox?',
answer:
"Coding agents expect interactive terminals with proper TTY handling. SSH with piped commands breaks tool confirmations, streaming output, and human-in-the-loop flows. The SDK handles all of this over a clean HTTP API.",
},
];
function FAQItem({ question, answer }: { question: string; answer: string }) {
@ -84,7 +99,7 @@ export function FAQ() {
Frequently Asked Questions
</h2>
<p className="text-zinc-400">
Common questions about the Coding Agent SDK.
Common questions about running agents in sandboxes.
</p>
</div>

View file

@ -2,40 +2,6 @@
import { Workflow, Server, Database, Download, Globe } from 'lucide-react';
import { FeatureIcon } from './ui/FeatureIcon';
import { CopyButton } from './ui/CopyButton';
function AgentLogo({ name, color, src }: { name: string; color: string; src?: string }) {
return (
<div className="flex items-center gap-2 px-2 py-1 rounded bg-zinc-800/50 border border-white/5">
{src ? (
<img src={src} alt={name} className="w-4 h-4" style={{ filter: 'brightness(0) invert(1)' }} />
) : (
<div
className="w-4 h-4 rounded-sm flex items-center justify-center text-[8px] font-bold"
style={{ backgroundColor: `${color}20`, color }}
>
{name[0]}
</div>
)}
<span className="text-[10px] text-zinc-400">{name}</span>
</div>
);
}
function ProviderLogo({ name, src }: { name: string; src?: string }) {
return (
<div className="flex items-center gap-2 px-2 py-1 rounded bg-zinc-800/50 border border-white/5">
{src ? (
<img src={src} alt={name} className="h-3 w-auto" style={{ filter: 'brightness(0) invert(1)' }} />
) : (
<div className="w-4 h-4 rounded-sm flex items-center justify-center text-[8px] font-bold bg-blue-500/20 text-blue-400">
D
</div>
)}
<span className="text-[10px] text-zinc-400">{name}</span>
</div>
);
}
export function FeatureGrid() {
return (
@ -43,216 +9,90 @@ export function FeatureGrid() {
<div className="relative z-10 mx-auto max-w-7xl px-6">
<div className="mb-16">
<h2 className="mb-4 text-3xl font-medium tracking-tight text-white md:text-5xl">
Full feature coverage.
How it works.
</h2>
<p className="text-lg leading-relaxed text-zinc-400">
Available as an HTTP API or TypeScript SDK.
A server runs inside your sandbox. Your app connects over HTTP to control any coding agent.
</p>
</div>
<div className="grid grid-cols-12 gap-4">
{/* Universal Agent API - Span 7 cols */}
<div className="col-span-12 lg:col-span-7 row-span-2 group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50 min-h-[400px]">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{/* Universal Agent API - Span full width */}
<div className="col-span-full group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Top Shine Highlight */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Top Left Reflection/Glow */}
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(255,79,0,0.15)_0%,transparent_50%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
{/* Sharp Edge Highlight */}
<div className="pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t border-orange-500 opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100" />
<div className="relative z-10 flex flex-col gap-4">
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Workflow}
color="text-orange-400"
<FeatureIcon
icon={Workflow}
color="text-orange-400"
bgColor="bg-orange-500/10"
hoverBgColor="group-hover:bg-orange-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(255,79,0,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Universal Agent API</h4>
</div>
<p className="text-zinc-400 leading-relaxed text-lg max-w-md">
<p className="text-zinc-400 leading-relaxed text-lg max-w-2xl">
Claude Code, Codex, OpenCode, and Amp each have different APIs. We provide a single,
unified interface to control them all.
</p>
</div>
<div className="mt-auto relative z-10 bg-black/50 rounded-xl border border-white/5 p-5 overflow-hidden">
<div className="relative w-full aspect-[16/9] bg-[#050505] rounded-xl border border-white/10 overflow-hidden flex items-center justify-center">
{/* Subtle Background Grid */}
<div className="absolute inset-0 opacity-[0.03] pointer-events-none"
style={{ backgroundImage: 'linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)', backgroundSize: '40px 40px' }} />
<svg viewBox="0 0 800 450" className="w-full h-full relative z-10">
<defs>
{/* Glow effect for active lines */}
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="2.5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
{/* Define curved paths with their respective brand colors */}
{(() => {
const curvedPaths = [
{ d: "M480 225 C540 225, 560 90, 620 90", label: "Claude", color: "#d97757" },
{ d: "M480 225 C540 225, 560 180, 620 180", label: "OpenAI", color: "#ffffff" },
{ d: "M480 225 C540 225, 560 270, 620 270", label: "OpenCode", color: "#10B981" },
{ d: "M480 225 C540 225, 560 360, 620 360", label: "Amp", color: "#F59E0B" }
];
return (
<>
{/* Connection Lines */}
<g className="stroke-zinc-800" fill="none" strokeWidth="1.5">
{/* App -> Agent (Straight) */}
<path d="M180 225 L320 225" strokeDasharray="4 4" />
{/* Agent -> Providers (Curved) */}
{curvedPaths.map((path, i) => (
<path key={i} d={path.d} strokeDasharray="4 4" />
))}
</g>
{/* High-Performance Tracers */}
{/* Blue Tracer: App to SDK */}
<circle r="2.5" fill="#3B82F6" filter="url(#glow)">
<animateMotion path="M180 225 L320 225" dur="1.2s" repeatCount="indefinite" />
<animate attributeName="opacity" values="0;1;0" dur="1.2s" repeatCount="indefinite" />
</circle>
{/* Colored Tracers: SDK to Providers (following curves and matching brand colors) */}
{curvedPaths.map((path, i) => (
<circle key={i} r="2.5" fill={path.color} filter="url(#glow)">
<animateMotion path={path.d} dur="2s" begin={`${i * 0.4}s`} repeatCount="indefinite" />
<animate attributeName="opacity" values="0;1;0" dur="2s" begin={`${i * 0.4}s`} repeatCount="indefinite" />
</circle>
))}
</>
);
})()}
{/* Nodes */}
{/* App Node */}
<g transform="translate(80, 190)">
<rect width="100" height="70" rx="12" fill="#111" stroke="#333" strokeWidth="1" />
<text x="50" y="42" fill="#999" textAnchor="middle" fontSize="14" fontWeight="600" className="uppercase tracking-tighter">Client App</text>
</g>
{/* Central SDK Node */}
<g transform="translate(320, 180)">
<rect width="160" height="90" rx="14" fill="#18181B" stroke="#3B82F6" strokeWidth="2" />
<text x="80" y="52" fill="white" textAnchor="middle" fontSize="14" fontWeight="800">Sandbox Agent SDK</text>
</g>
{/* Provider Nodes with Logos - Vertical Layout (centered) */}
{/* Claude */}
<g transform="translate(620, 50)">
<rect width="140" height="80" rx="10" fill="#111" stroke="#222" strokeWidth="1" />
<foreignObject x="0" y="10" width="140" height="32">
<div className="flex justify-center">
<img src="/logos/claude.svg" alt="Claude" className="h-8 w-8" />
</div>
</foreignObject>
<text x="70" y="62" fill="#999" textAnchor="middle" fontSize="11" fontWeight="600">Claude Code</text>
</g>
{/* Codex */}
<g transform="translate(620, 140)">
<rect width="140" height="80" rx="10" fill="#111" stroke="#222" strokeWidth="1" />
<foreignObject x="0" y="10" width="140" height="32">
<div className="flex justify-center">
<svg className="h-8 w-8" viewBox="0 0 24 24" fill="none">
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="#ffffff" />
</svg>
</div>
</foreignObject>
<text x="70" y="62" fill="#999" textAnchor="middle" fontSize="11" fontWeight="600">Codex</text>
</g>
{/* OpenCode */}
<g transform="translate(620, 230)">
<rect width="140" height="80" rx="10" fill="#111" stroke="#222" strokeWidth="1" />
<foreignObject x="0" y="10" width="140" height="32">
<div className="flex justify-center">
<svg className="h-8 w-auto" viewBox="0 0 32 40" fill="none">
<path d="M24 32H8V16H24V32Z" fill="#4B4646"/>
<path d="M24 8H8V32H24V8ZM32 40H0V0H32V40Z" fill="#F1ECEC"/>
</svg>
</div>
</foreignObject>
<text x="70" y="62" fill="#999" textAnchor="middle" fontSize="11" fontWeight="600">OpenCode</text>
</g>
{/* Amp */}
<g transform="translate(620, 320)">
<rect width="140" height="80" rx="10" fill="#111" stroke="#222" strokeWidth="1" />
<foreignObject x="0" y="12" width="140" height="28">
<div className="flex justify-center">
<img src="/logos/amp.svg" alt="Amp" className="h-6 w-auto" style={{ filter: 'brightness(0) invert(1)' }} />
</div>
</foreignObject>
<text x="70" y="62" fill="#999" textAnchor="middle" fontSize="11" fontWeight="600">Amp</text>
</g>
</svg>
</div>
</div>
</div>
{/* Server Mode - Span 5 cols */}
<div className="col-span-12 lg:col-span-5 group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Streaming Events */}
<div className="group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Top Shine Highlight */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Top Left Reflection/Glow */}
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(34,197,94,0.15)_0%,transparent_50%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
{/* Sharp Edge Highlight */}
<div className="pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t border-green-500 opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100" />
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Server}
color="text-green-400"
<FeatureIcon
icon={Server}
color="text-green-400"
bgColor="bg-green-500/10"
hoverBgColor="group-hover:bg-green-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(34,197,94,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Server Mode</h4>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Streaming Events</h4>
</div>
<p className="text-zinc-400 text-sm leading-relaxed">
Run as an HTTP server anywhere. One command to bridge coding agents to your
application.
Real-time SSE stream of everything the agent does. Persist to your storage, replay sessions, audit everything.
</p>
<div className="mt-auto relative z-10 p-3 bg-black/40 rounded-lg border border-white/5 font-mono text-xs text-green-400">
$ sandbox-agent server
</div>
</div>
{/* Universal Schema - Span 5 cols */}
<div className="col-span-12 lg:col-span-5 group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Handling Permissions */}
<div className="group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Top Shine Highlight */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Top Left Reflection/Glow */}
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(168,85,247,0.15)_0%,transparent_50%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
{/* Sharp Edge Highlight */}
<div className="pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t border-purple-500 opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100" />
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Database}
color="text-purple-400"
<FeatureIcon
icon={Database}
color="text-purple-400"
bgColor="bg-purple-500/10"
hoverBgColor="group-hover:bg-purple-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(168,85,247,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Universal Schema</h4>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Handling Permissions</h4>
</div>
<p className="text-zinc-400 text-sm leading-relaxed">
Standardized session schema that covers all features of all agents. Includes tool calls, permission requests, file edits, etc.
Approve or deny tool executions remotely over HTTP. Human-in-the-loop flows work seamlessly across the network.
</p>
</div>
{/* Automatic Agent Installation - Span 8 cols */}
<div className="col-span-12 md:col-span-8 group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Managing Sessions */}
<div className="group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Top Shine Highlight */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Top Left Reflection/Glow */}
@ -260,67 +100,43 @@ export function FeatureGrid() {
{/* Sharp Edge Highlight */}
<div className="pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t border-amber-500 opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100" />
<div className="flex flex-col gap-4 relative z-10">
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Download}
color="text-amber-400"
bgColor="bg-amber-500/10"
hoverBgColor="group-hover:bg-amber-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(245,158,11,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Automatic Agent Installation</h4>
</div>
<p className="text-zinc-400 text-sm leading-relaxed">
Agents are automatically installed on first use. No manual setup required.
</p>
</div>
<div className="mt-auto w-full relative z-10">
<div className="flex flex-wrap gap-2">
{['Claude Code', 'Codex', 'OpenCode', 'Amp'].map((agent) => (
<span
key={agent}
className="px-3 py-1.5 rounded-md bg-zinc-800/50 border border-white/5 text-xs font-mono text-zinc-400"
>
{agent}
</span>
))}
</div>
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Download}
color="text-amber-400"
bgColor="bg-amber-500/10"
hoverBgColor="group-hover:bg-amber-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(245,158,11,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Managing Sessions</h4>
</div>
<p className="text-zinc-400 text-sm leading-relaxed">
Create sessions, send messages, persist transcripts. Full session lifecycle management over HTTP.
</p>
</div>
{/* Provider Agnostic - Span 4 cols */}
<div className="col-span-12 md:col-span-4 group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Runs Inside Any Sandbox */}
<div className="group relative flex flex-col gap-4 overflow-hidden rounded-2xl border border-white/5 bg-zinc-900/30 p-6 backdrop-blur-sm transition-colors duration-500 hover:bg-zinc-900/50">
{/* Top Shine Highlight */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Top Left Reflection/Glow */}
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(59,130,246,0.15)_0%,transparent_50%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
{/* Sharp Edge Highlight */}
<div className="pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t border-blue-500 opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100" />
<div className="relative z-10 mb-2 flex items-center gap-3">
<FeatureIcon
icon={Globe}
color="text-blue-400"
<FeatureIcon
icon={Globe}
color="text-blue-400"
bgColor="bg-blue-500/10"
hoverBgColor="group-hover:bg-blue-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(59,130,246,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Provider Agnostic</h4>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">Runs Inside Any Sandbox</h4>
</div>
<p className="text-zinc-500 text-sm leading-relaxed">
Run locally, in Docker, or deploy to E2B, Daytona, and Vercel. Same SDK everywhere.
Lightweight static binary. One curl command to install inside E2B, Daytona, Vercel Sandboxes, or Docker.
</p>
<div className="mt-auto flex flex-wrap gap-2">
{['Local', 'Docker', 'E2B', 'Daytona', 'Vercel', 'Netlify'].map((provider) => (
<span
key={provider}
className="px-2 py-1 rounded-md bg-zinc-800/50 border border-white/5 text-[10px] font-mono text-zinc-400"
>
{provider}
</span>
))}
</div>
</div>
</div>
</div>

View file

@ -1,11 +1,158 @@
'use client';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { Terminal, Check, ArrowRight } from 'lucide-react';
const ADAPTERS = [
{ label: 'Claude Code', color: '#D97757', x: 35, y: 70, logo: '/logos/claude.svg' },
{ label: 'Codex', color: '#10A37F', x: 185, y: 70, logo: 'openai' },
{ label: 'Amp', color: '#F59E0B', x: 35, y: 155, logo: '/logos/amp.svg' },
{ label: 'OpenCode', color: '#8B5CF6', x: 185, y: 155, logo: 'opencode' },
];
function UniversalAPIDiagram() {
const [activeIndex, setActiveIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setActiveIndex((prev) => (prev + 1) % ADAPTERS.length);
}, 2000);
return () => clearInterval(interval);
}, []);
return (
<div className="relative w-full aspect-[16/9] bg-[#050505] rounded-xl border border-white/10 overflow-hidden flex items-center justify-center">
{/* Background Grid */}
<div
className="absolute inset-0 opacity-[0.03] pointer-events-none"
style={{
backgroundImage:
'linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)',
backgroundSize: '40px 40px',
}}
/>
{/* Dynamic Background Glow */}
<div
className="absolute top-1/2 right-1/4 -translate-y-1/2 w-64 h-64 blur-[100px] rounded-full transition-colors duration-1000 opacity-20"
style={{ backgroundColor: ADAPTERS[activeIndex].color }}
/>
<svg viewBox="0 0 800 450" className="w-full h-full relative z-10">
<defs>
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="3" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
{/* YOUR APP NODE */}
<g transform="translate(60, 175)">
<rect width="180" height="100" rx="16" fill="#0A0A0A" stroke="#333" strokeWidth="2" />
<text x="90" y="55" fill="#FFFFFF" textAnchor="middle" fontSize="20" fontWeight="700">
Your App
</text>
</g>
{/* HTTP/SSE LINE */}
<g>
<path d="M240 225 L360 225" stroke="#3B82F6" strokeWidth="2" strokeDasharray="6 4" fill="none" opacity="0.6" />
<circle r="4" fill="#3B82F6" filter="url(#glow)">
<animateMotion path="M240 225 L360 225" dur="2s" repeatCount="indefinite" />
</circle>
<circle r="4" fill="#3B82F6" filter="url(#glow)">
<animateMotion path="M360 225 L240 225" dur="2s" repeatCount="indefinite" />
</circle>
<rect x="255" y="195" width="90" height="22" rx="11" fill="#111" stroke="#333" strokeWidth="1" />
<text x="300" y="210" fill="#60A5FA" textAnchor="middle" fontSize="11" fontWeight="800" fontFamily="monospace">
HTTP / SSE
</text>
</g>
{/* SANDBOX BOUNDARY */}
<g transform="translate(360, 45)">
<rect width="380" height="360" rx="24" fill="#080808" stroke="#333" strokeWidth="1.5" />
<rect width="380" height="45" rx="12" fill="rgba(255,255,255,0.02)" />
<text x="190" y="28" fill="#FFFFFF" textAnchor="middle" fontSize="14" fontWeight="800" letterSpacing="0.2em">
SANDBOX
</text>
{/* SANDBOX AGENT SDK */}
<g transform="translate(25, 65)">
<rect width="330" height="270" rx="20" fill="#0D0D0F" stroke="#3B82F6" strokeWidth="2" />
<text x="165" y="35" fill="#FFFFFF" textAnchor="middle" fontSize="18" fontWeight="800">
Sandbox Agent Server
</text>
<line x1="40" y1="50" x2="290" y2="50" stroke="#333" strokeWidth="1" />
{/* PROVIDER ADAPTERS */}
{ADAPTERS.map((p, i) => {
const isActive = i === activeIndex;
return (
<g key={i} transform={`translate(${p.x}, ${p.y})`}>
<rect
width="110"
height="65"
rx="12"
fill={isActive ? '#1A1A1E' : '#111'}
stroke={isActive ? p.color : '#333'}
strokeWidth={isActive ? 2 : 1.5}
/>
<foreignObject x="0" y="8" width="110" height="28">
<div className="flex justify-center" style={{ opacity: isActive ? 1 : 0.4 }}>
{p.logo === 'openai' ? (
<svg className="h-6 w-6" viewBox="0 0 24 24" fill="none">
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="#ffffff" />
</svg>
) : p.logo === 'opencode' ? (
<svg className="h-6 w-auto" viewBox="0 0 32 40" fill="none">
<path d="M24 32H8V16H24V32Z" fill="#4B4646"/>
<path d="M24 8H8V32H24V8ZM32 40H0V0H32V40Z" fill="#F1ECEC"/>
</svg>
) : (
<img src={p.logo} alt={p.label} className="h-6 w-6" style={{ filter: 'brightness(0) invert(1)' }} />
)}
</div>
</foreignObject>
<text
x="55"
y="52"
fill="#FFFFFF"
textAnchor="middle"
fontSize="11"
fontWeight="600"
opacity={isActive ? 1 : 0.4}
>
{p.label}
</text>
</g>
);
})}
{/* Active Agent Label */}
<text
x="165"
y="250"
fill={ADAPTERS[activeIndex].color}
textAnchor="middle"
fontSize="10"
fontWeight="800"
fontFamily="monospace"
letterSpacing="0.1em"
>
CONNECTED TO {ADAPTERS[activeIndex].label.toUpperCase()}
</text>
</g>
</g>
</svg>
</div>
);
}
const CopyInstallButton = () => {
const [copied, setCopied] = useState(false);
const installCommand = 'npx skills add https://sandboxagent.dev/docs';
const installCommand = 'SandboxAgent.connect({ endpoint: "..." })';
const handleCopy = async () => {
try {
@ -35,11 +182,11 @@ export function Hero() {
<div className="flex flex-col lg:flex-row items-center gap-16">
<div className="flex-1 text-center lg:text-left">
<h1 className="mb-6 text-5xl font-medium leading-[1.1] tracking-tighter text-white md:text-7xl">
Universal API for <br />
Coding Agents
Run Coding Agents in Sandboxes.<br />
Control Them Over HTTP.
</h1>
<p className="mt-8 text-xl text-zinc-400 leading-relaxed max-w-2xl mx-auto lg:mx-0">
One SDK to control Claude Code, Codex, OpenCode, and Amp. Unified events, session management, and human-in-the-loop. Swap agents with zero refactoring.
The Sandbox Agent SDK is a server that runs inside your sandbox. Your app connects remotely to control Claude Code, Codex, OpenCode, or Amp streaming events, handling permissions, managing sessions.
</p>
<div className="mt-10 flex flex-col items-center gap-4 sm:flex-row sm:justify-center lg:justify-start">
@ -54,83 +201,11 @@ export function Hero() {
</div>
</div>
<div className="flex-1 w-full max-w-xl">
<div className="relative group">
<div className="absolute -inset-1 rounded-xl bg-gradient-to-r from-zinc-700 to-zinc-800 opacity-20 blur" />
<div className="group relative overflow-hidden rounded-xl border border-white/10 bg-zinc-900/50 shadow-2xl backdrop-blur-xl">
<div className="flex items-center justify-between border-b border-white/5 bg-white/5 px-4 py-3">
<div className="flex items-center gap-2">
<div className="h-3 w-3 rounded-full border border-zinc-500/50 bg-zinc-500/20" />
<div className="h-3 w-3 rounded-full border border-zinc-500/50 bg-zinc-500/20" />
<div className="h-3 w-3 rounded-full border border-zinc-500/50 bg-zinc-500/20" />
</div>
<div className="font-mono text-xs text-zinc-500">example_agent.ts</div>
</div>
<pre className="overflow-x-auto p-6 font-mono text-sm leading-relaxed">
<code>
<span className="text-purple-400">const</span>
<span className="text-zinc-300"> agents = </span>
<span className="text-purple-400">await</span>
<span className="text-zinc-300"> client.</span>
<span className="text-blue-400">listAgents</span>
<span className="text-zinc-300">();</span>
{"\n\n"}
<span className="text-purple-400">await</span>
<span className="text-zinc-300"> client.</span>
<span className="text-blue-400">createSession</span>
<span className="text-zinc-300">(</span>
<span className="text-green-400">"demo"</span>
<span className="text-zinc-300">{", {"}</span>
{"\n"}
<span className="text-zinc-300">{" agent: "}</span>
<span className="text-green-400">"codex"</span>
<span className="text-zinc-300">,</span>
{"\n"}
<span className="text-zinc-300">{" agentMode: "}</span>
<span className="text-green-400">"default"</span>
<span className="text-zinc-300">,</span>
{"\n"}
<span className="text-zinc-300">{" permissionMode: "}</span>
<span className="text-green-400">"plan"</span>
<span className="text-zinc-300">,</span>
{"\n"}
<span className="text-zinc-300">{"});"}</span>
{"\n\n"}
<span className="text-purple-400">await</span>
<span className="text-zinc-300"> client.</span>
<span className="text-blue-400">postMessage</span>
<span className="text-zinc-300">(</span>
<span className="text-green-400">"demo"</span>
<span className="text-zinc-300">{", { message: "}</span>
<span className="text-green-400">"Hello from the SDK."</span>
<span className="text-zinc-300">{" });"}</span>
{"\n\n"}
<span className="text-purple-400">for await</span>
<span className="text-zinc-300"> (</span>
<span className="text-purple-400">const</span>
<span className="text-zinc-300"> event </span>
<span className="text-purple-400">of</span>
<span className="text-zinc-300"> client.</span>
<span className="text-blue-400">streamEvents</span>
<span className="text-zinc-300">(</span>
<span className="text-green-400">"demo"</span>
<span className="text-zinc-300">{", { offset: "}</span>
<span className="text-amber-400">0</span>
<span className="text-zinc-300">{" })) {"}</span>
{"\n"}
<span className="text-zinc-300">{" console."}</span>
<span className="text-blue-400">log</span>
<span className="text-zinc-300">(event.type, event.data);</span>
{"\n"}
<span className="text-zinc-300">{"}"}</span>
</code>
</pre>
</div>
</div>
<div className="flex-1 w-full max-w-2xl">
<UniversalAPIDiagram />
</div>
</div>
</div>
</section>
);
}

View file

@ -1,124 +1,31 @@
'use client';
import { motion } from 'framer-motion';
import { X, Check } from 'lucide-react';
const frictions = [
{
number: '01',
title: 'Fragmented Agent Scaffolds',
description:
'Claude Code, Codex, OpenCode, and Amp each have proprietary APIs. Swapping agents means rewriting your entire integration.',
solution: 'Unified control plane for all agent engines.',
visual: (
<div className="mt-6 space-y-3">
<div className="flex items-center gap-3">
<div className="h-px flex-1 bg-gradient-to-r from-red-500/50 to-transparent" />
<span className="text-xs text-zinc-500">Claude Bridge</span>
</div>
<div className="flex items-center gap-3">
<div className="h-px flex-1 bg-gradient-to-r from-red-500/50 to-transparent" />
<span className="text-xs text-zinc-500">Amp Bridge</span>
</div>
<div className="flex items-center gap-3 mt-4">
<div className="h-px flex-1 bg-gradient-to-r from-green-500 to-green-500/20" />
<span className="text-xs text-green-400 font-medium">API</span>
</div>
<div className="mt-4 bg-black/60 rounded-lg border border-white/5 p-3 font-mono text-xs">
<div className="text-zinc-500">
<span className="text-zinc-600">01</span>{' '}
<span className="text-purple-400">agent</span>
<span className="text-zinc-400">.</span>
<span className="text-blue-400">spawn</span>
<span className="text-zinc-400">(</span>
<span className="text-green-400">"claude-code"</span>
<span className="text-zinc-400">)</span>
</div>
<div className="text-zinc-500">
<span className="text-zinc-600">02</span>{' '}
<span className="text-purple-400">agent</span>
<span className="text-zinc-400">.</span>
<span className="text-blue-400">spawn</span>
<span className="text-zinc-400">(</span>
<span className="text-green-400">"amp"</span>
<span className="text-zinc-400">)</span>
</div>
<div className="text-zinc-600 mt-2">// Exactly same methods</div>
</div>
</div>
),
title: 'Coding Agents Need Sandboxes',
problem:
"You can't let AI execute arbitrary code on your production servers. Coding agents need isolated environments, but existing SDKs assume local execution.",
solution: 'A server that runs inside the sandbox and exposes HTTP/SSE.',
accentColor: 'orange',
},
{
number: '02',
title: 'Deploy Anywhere',
description:
"Whether you're running locally, in Docker, or with E2B, Daytona, and Vercel — you shouldn't need different integration code for each.",
solution: 'One SDK, any environment. Deploy locally or to any cloud provider with a single config change.',
visual: (
<div className="mt-6">
<div className="flex items-center justify-between gap-2 text-xs">
<div className="flex-1 text-center py-2 px-3 rounded-lg bg-zinc-800/50 border border-white/5 text-zinc-400">
E2B
</div>
<div className="text-zinc-500">+</div>
<div className="flex-1 text-center py-2 px-3 rounded-lg bg-zinc-800/50 border border-white/5 text-zinc-400">
Daytona
</div>
<div className="text-zinc-500">+</div>
<div className="flex-1 text-center py-2 px-3 rounded-lg bg-zinc-800/50 border border-white/5 text-zinc-400">
Vercel
</div>
</div>
<div className="mt-4 bg-black/60 rounded-lg border border-white/5 p-3 font-mono text-xs">
<div className="text-zinc-500 mb-1"># Works with all providers</div>
<div>
<span className="text-green-400">SANDBOX_PROVIDER</span>
<span className="text-zinc-400">=</span>
<span className="text-amber-400">"daytona"</span>
</div>
</div>
</div>
),
title: 'Every Coding Agent is Different',
problem:
'Claude Code, Codex, OpenCode, and Amp each have proprietary APIs, event formats, and behaviors. Swapping coding agents means rewriting your entire integration.',
solution: 'One HTTP API. Write your code once, swap coding agents with a config change.',
accentColor: 'purple',
},
{
number: '03',
title: 'Transient State',
description:
'Transcripts and session data are usually lost when the agent process ends. Debugging and replay become impossible.',
solution: 'Standardized session JSON. Stream events to your own storage in real-time.',
visual: (
<div className="mt-6">
<div className="bg-black/60 rounded-lg border border-white/5 p-3 font-mono text-xs overflow-hidden">
<div className="text-zinc-500 mb-2"># Session persisted automatically</div>
<div className="space-y-1">
<div>
<span className="text-blue-400">"events"</span>
<span className="text-zinc-400">: [</span>
</div>
<div className="pl-4">
<span className="text-zinc-400">{'{ '}</span>
<span className="text-blue-400">"type"</span>
<span className="text-zinc-400">: </span>
<span className="text-green-400">"tool_call"</span>
<span className="text-zinc-400">{' }'}</span>
</div>
<div className="pl-4">
<span className="text-zinc-400">{'{ '}</span>
<span className="text-blue-400">"type"</span>
<span className="text-zinc-400">: </span>
<span className="text-green-400">"message"</span>
<span className="text-zinc-400">{' }'}</span>
</div>
<div className="text-zinc-400">]</div>
</div>
<div className="mt-3 flex items-center gap-2 text-zinc-500">
<span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
<span>Streaming to Rivet Actors</span>
</div>
</div>
</div>
),
title: 'Sessions Are Ephemeral',
problem:
'Coding agent transcripts live in the sandbox. When the process ends, you lose everything. Debugging and replay become impossible.',
solution: 'Universal event schema streams to your storage. Persist to Postgres or Rivet, replay later, audit everything.',
accentColor: 'blue',
},
];
@ -156,11 +63,10 @@ export function PainPoints() {
className="mb-16"
>
<h2 className="mb-6 text-3xl font-medium tracking-tight text-white md:text-5xl">
Integrating coding agents is hard.
Running coding agents remotely is hard.
</h2>
<p className="max-w-2xl text-lg leading-relaxed text-zinc-400">
Every agent has its own API, event format, and session model. Swapping agents means
rewriting your entire integration.
Coding agents need sandboxes, but existing SDKs assume local execution. SSH breaks, CLI wrappers are fragile, and building from scratch means reimplementing everything for each coding agent.
</p>
</motion.div>
@ -192,20 +98,31 @@ export function PainPoints() {
className={`pointer-events-none absolute left-0 top-0 z-20 h-24 w-24 rounded-tl-2xl border-l border-t ${styles.border} opacity-0 transition-opacity duration-500 [mask-image:linear-gradient(135deg,black_0%,transparent_50%)] group-hover:opacity-100`}
/>
<div className="relative z-10">
<div className="relative z-10 flex flex-col h-full">
{/* Title */}
<h3 className="mb-3 text-xl font-medium text-white">{friction.title}</h3>
<h3 className="mb-4 text-xl font-medium text-white">{friction.title}</h3>
{/* Description */}
<p className="text-sm leading-relaxed text-zinc-500">{friction.description}</p>
{/* Solution */}
<div className="mt-4 border-t border-white/5 pt-4">
<p className="text-sm font-medium text-zinc-300">{friction.solution}</p>
{/* Problem */}
<div className="mb-4">
<div className="flex items-center gap-2 mb-2">
<div className="flex items-center justify-center w-5 h-5 rounded-full bg-red-500/20">
<X className="w-3 h-3 text-red-400" />
</div>
<span className="text-xs font-semibold uppercase tracking-wider text-red-400">Problem</span>
</div>
<p className="text-sm leading-relaxed text-zinc-500">{friction.problem}</p>
</div>
{/* Visual */}
{friction.visual}
{/* Solution */}
<div className="mt-auto pt-4 border-t border-white/5">
<div className="flex items-center gap-2 mb-2">
<div className="flex items-center justify-center w-5 h-5 rounded-full bg-green-500/20">
<Check className="w-3 h-3 text-green-400" />
</div>
<span className="text-xs font-semibold uppercase tracking-wider text-green-400">Solution</span>
</div>
<p className="text-sm font-medium leading-relaxed text-zinc-300">{friction.solution}</p>
</div>
</div>
</motion.div>
);

View file

@ -22,12 +22,12 @@ const { title, description = "Universal SDK for coding agents. Control Claude Co
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:image" content="/logos/sanboxagent.svg" />
<meta property="og:image:width" content="570" />
<meta property="og:image:height" content="98" />
<meta property="og:image:alt" content="Sandbox Agent SDK Logo" />
<meta property="og:image" content="/og.png" />
<meta property="og:image:width" content="2400" />
<meta property="og:image:height" content="1260" />
<meta property="og:image:alt" content="Sandbox Agent SDK - Run Coding Agents in Sandboxes. Control Them Over HTTP." />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="/logos/sanboxagent.svg" />
<meta name="twitter:image" content="/og.png" />
</head>
<body class="min-h-screen">
<slot />

View file

@ -2,6 +2,7 @@
import Layout from '../layouts/Layout.astro';
import { Navigation } from '../components/Navigation';
import { Hero } from '../components/Hero';
import { PainPoints } from '../components/PainPoints';
import { FeatureGrid } from '../components/FeatureGrid';
import { GetStarted } from '../components/GetStarted';
import { Inspector } from '../components/Inspector';
@ -9,11 +10,12 @@ import { FAQ } from '../components/FAQ';
import { Footer } from '../components/Footer';
---
<Layout title="Coding Agent SDK - Universal SDK for Coding Agents">
<Layout title="Sandbox Agent SDK - Run Coding Agents in Sandboxes. Control Them Over HTTP.">
<div class="min-h-screen bg-black text-white selection:bg-accent/30">
<Navigation client:load />
<main>
<Hero client:load />
<PainPoints client:visible />
<FeatureGrid client:visible />
<GetStarted client:visible />
<Inspector client:visible />