chore: fix bad merge

This commit is contained in:
Nathan Flurry 2026-02-11 07:52:48 -08:00
parent 1dd45908a3
commit 94353f7696
205 changed files with 19244 additions and 14866 deletions

View file

@ -0,0 +1,112 @@
'use client';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ArrowRight, Terminal, Check } from 'lucide-react';
const CTA_TITLES = [
'Run coding agents in sandboxes. Control them over HTTP.',
'A server inside your sandbox. An API for your app.',
'Claude Code, Codex, OpenCode, Amp, Pi — 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() {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex(prev => (prev + 1) % CTA_TITLES.length);
}, 3000);
return () => clearInterval(interval);
}, []);
return (
<h2 className='min-h-[1.2em] text-4xl font-medium tracking-tight text-white md:text-5xl'>
<AnimatePresence mode='wait'>
<motion.span
key={currentIndex}
initial={{ opacity: 0, y: 5 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -5 }}
transition={{ duration: 0.1 }}
style={{ display: 'block' }}
>
{CTA_TITLES[currentIndex]}
</motion.span>
</AnimatePresence>
</h2>
);
}
const CopyInstallButton = () => {
const [copied, setCopied] = useState(false);
const installCommand = 'curl -sSL https://sandboxagent.dev/install | sh';
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(installCommand);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
console.error('Failed to copy:', err);
}
};
return (
<button
onClick={handleCopy}
className='inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-white/10 bg-white/5 px-4 py-2 text-sm text-white subpixel-antialiased shadow-sm transition-colors hover:border-white/20'
>
{copied ? <Check className='h-4 w-4' /> : <Terminal className='h-4 w-4' />}
{installCommand}
</button>
);
};
export function CTASection() {
return (
<section className='relative overflow-hidden border-t border-white/10 px-6 py-32 text-center'>
<motion.div
animate={{ opacity: [0.3, 0.5, 0.3] }}
transition={{ duration: 4, repeat: Infinity }}
className='pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-zinc-500/10 via-transparent to-transparent opacity-50'
/>
<div className='relative z-10 mx-auto max-w-3xl'>
<div className='mb-8'>
<AnimatedCTATitle />
</div>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className='mb-10 text-lg leading-relaxed text-zinc-400'
>
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 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className='flex flex-col items-center justify-center gap-4 sm:flex-row'
>
<a
href='/docs'
className='inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-white/10 bg-white px-4 py-2 text-sm text-black subpixel-antialiased shadow-sm transition-colors hover:bg-zinc-200'
>
Read the Docs
<ArrowRight className='h-4 w-4' />
</a>
<CopyInstallButton />
</motion.div>
</div>
</section>
);
}

View file

@ -18,7 +18,7 @@ const faqs = [
{
question: 'How is session data persisted?',
answer:
"This SDK does not handle persisting session data. In v2, traffic is ACP JSON-RPC over <code>/v2/rpc</code>; persist envelopes in your own storage if you need replay or auditing.",
"This SDK does not handle persisting session data. Events stream in a universal JSON schema that you can persist anywhere. Consider using Postgres or <a href='https://rivet.gg' target='_blank' rel='noopener noreferrer' class='text-orange-400 hover:underline'>Rivet Actors</a> for data persistence.",
},
{
question: 'Can I run this locally or does it require a sandbox provider?',
@ -61,14 +61,14 @@ function FAQItem({ question, answer }: { question: string; answer: string }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="border-t border-white/10 first:border-t-0">
<div className="border-b border-white/5">
<button
onClick={() => setIsOpen(!isOpen)}
className="group flex w-full items-center justify-between py-5 text-left"
className="flex w-full items-center justify-between py-5 text-left"
>
<span className="text-base font-normal text-white pr-4 group-hover:text-zinc-300 transition-colors">{question}</span>
<span className="text-base font-medium text-white pr-4">{question}</span>
<ChevronDown
className={`h-4 w-4 shrink-0 text-zinc-500 transition-transform duration-200 ${
className={`h-5 w-5 shrink-0 text-zinc-500 transition-transform duration-200 ${
isOpen ? 'rotate-180' : ''
}`}
/>
@ -82,7 +82,7 @@ function FAQItem({ question, answer }: { question: string; answer: string }) {
transition={{ duration: 0.2 }}
className="overflow-hidden"
>
<p className="pb-5 text-sm leading-relaxed text-zinc-500" dangerouslySetInnerHTML={{ __html: answer }} />
<p className="pb-5 text-sm leading-relaxed text-zinc-400" dangerouslySetInnerHTML={{ __html: answer }} />
</motion.div>
)}
</AnimatePresence>
@ -92,40 +92,22 @@ function FAQItem({ question, answer }: { question: string; answer: string }) {
export function FAQ() {
return (
<section className="border-t border-white/10 py-48">
<div className="mx-auto max-w-7xl px-6">
<section className="relative overflow-hidden border-t border-white/5 py-24">
<div className="mx-auto max-w-3xl px-6">
<div className="mb-12 text-center">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-2 text-2xl font-normal tracking-tight text-white md:text-4xl"
>
<h2 className="mb-4 text-3xl font-medium tracking-tight text-white">
Frequently Asked Questions
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="mx-auto max-w-xl text-base leading-relaxed text-zinc-500"
>
</h2>
<p className="text-zinc-400">
Common questions about running agents in sandboxes.
</motion.p>
</p>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className="mx-auto max-w-3xl"
>
<div className="divide-y divide-white/5 rounded-2xl border border-white/5 bg-zinc-900/30 px-6">
{faqs.map((faq, index) => (
<FAQItem key={index} question={faq.question} answer={faq.answer} />
))}
</motion.div>
</div>
</div>
</section>
);

View file

@ -1,120 +1,169 @@
'use client';
import { motion } from 'framer-motion';
import { Workflow, Server, Database, Download, Globe, Plug } from 'lucide-react';
import { FeatureIcon } from './ui/FeatureIcon';
export function FeatureGrid() {
return (
<section id="features" className="border-t border-white/10 py-48">
<div className="mx-auto max-w-7xl px-6">
<div className="mb-12">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-2 text-2xl font-normal tracking-tight text-white md:text-4xl"
>
<section id="features" className="relative overflow-hidden border-t border-white/5 py-32">
<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">
How it works.
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="max-w-xl text-base leading-relaxed text-zinc-500"
>
</h2>
<p className="text-lg leading-relaxed text-zinc-400">
A server runs inside your sandbox. Your app connects over HTTP to control any coding agent.
</motion.p>
</p>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"
>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{/* Universal Agent API - Span full width */}
<div className="group col-span-full flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-orange-400">
<Workflow className="h-4 w-4" />
</div>
<h4 className="text-base font-normal text-white">Universal Agent API</h4>
</div>
<p className="text-zinc-500 leading-relaxed text-base max-w-2xl">
Claude Code, Codex, OpenCode, Amp, and Pi each have different APIs. We provide a single,
unified interface to control them all.
</p>
</div>
<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" />
{/* Streaming Events */}
<div className="group flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-green-400">
<Server className="h-4 w-4" />
<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"
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>
<h4 className="text-base font-normal text-white">Streaming Events</h4>
<p className="text-zinc-400 leading-relaxed text-lg max-w-2xl">
Claude Code, Codex, OpenCode, Amp, and Pi each have different APIs. We provide a single,
unified interface to control them all.
</p>
</div>
<p className="text-zinc-500 text-sm leading-relaxed">
</div>
{/* 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"
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">Streaming Events</h4>
</div>
<p className="text-zinc-400 text-sm leading-relaxed">
Real-time SSE stream of everything the agent does. Persist to your storage, replay sessions, audit everything.
</p>
</div>
{/* Universal Schema */}
<div className="group flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-purple-400">
<Database className="h-4 w-4" />
</div>
<h4 className="text-base font-normal text-white">Universal Schema</h4>
{/* 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"
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>
</div>
<p className="text-zinc-500 text-sm leading-relaxed">
Standardized session schema that covers all features of all agents. Includes tool calls, permission requests, file edits, etc.
<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.
</p>
</div>
{/* Runs Inside Any Sandbox */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-blue-400">
<Globe className="h-4 w-4" />
</div>
<h4 className="text-base font-normal text-white">Runs Inside Any Sandbox</h4>
<div className="lg:col-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">
{/* 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"
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">Runs Inside Any Sandbox</h4>
</div>
<p className="text-zinc-500 text-sm leading-relaxed">
<p className="text-zinc-400 text-sm leading-relaxed">
Lightweight static binary. One curl command to install inside E2B, Daytona, Vercel Sandboxes, or Docker.
</p>
</div>
{/* Session Management */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-amber-400">
<Download className="h-4 w-4" />
</div>
<h4 className="text-base font-normal text-white">Session Management</h4>
{/* Automatic Agent Installation */}
<div className="lg:col-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">
{/* 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(245,158,11,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-amber-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={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-500 text-sm leading-relaxed">
<p className="text-zinc-400 text-sm leading-relaxed">
Create sessions, send messages, persist transcripts. Full session lifecycle management over HTTP.
</p>
</div>
{/* OpenCode SDK & UI Support */}
<div className="group lg:col-span-2 flex flex-col gap-4 rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="flex items-center gap-3">
<div className="text-zinc-500 transition-colors group-hover:text-pink-400">
<Plug className="h-4 w-4" />
</div>
<h4 className="text-base font-normal text-white">OpenCode Support</h4>
<span className="rounded-full border border-white/10 px-2 py-0.5 text-[10px] font-medium text-zinc-500 transition-colors group-hover:text-pink-400 group-hover:border-pink-400/30">Experimental</span>
<div className="lg:col-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">
{/* 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(236,72,153,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-pink-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={Plug}
color="text-pink-400"
bgColor="bg-pink-500/10"
hoverBgColor="group-hover:bg-pink-500/20"
glowShadow="group-hover:shadow-[0_0_15px_rgba(236,72,153,0.5)]"
/>
<h4 className="text-sm font-medium uppercase tracking-wider text-white">OpenCode SDK & UI Support</h4>
<span className="rounded-full bg-pink-500/20 px-2 py-0.5 text-xs font-medium text-pink-300">Experimental</span>
</div>
<p className="text-zinc-500 text-sm leading-relaxed">
<p className="text-zinc-400 text-sm leading-relaxed">
Connect OpenCode CLI, SDK, or web UI to control agents through familiar OpenCode tooling.
</p>
</div>
</motion.div>
</div>
</div>
</section>
);

View file

@ -1,7 +1,5 @@
'use client';
import { motion } from 'framer-motion';
const footer = {
products: [
{ name: 'Actors', href: 'https://rivet.dev/docs/actors' },
@ -50,22 +48,16 @@ const footer = {
export function Footer() {
return (
<footer className="border-t border-white/10 bg-black">
<div className="mx-auto max-w-6xl px-6 py-16 lg:py-20">
<footer className="border-t border-white/10 bg-zinc-950">
<div className="mx-auto max-w-7xl px-6 py-12 lg:py-16">
<div className="xl:grid xl:grid-cols-12 xl:gap-16">
{/* Logo & Social */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="space-y-6 xl:col-span-4"
>
<a href="https://rivet.dev" className="inline-block">
<img src="/rivet-logo-text-white.svg" alt="Rivet" className="h-6 w-auto opacity-90 hover:opacity-100 transition-opacity" />
<div className="space-y-6 xl:col-span-4">
<a href="https://rivet.dev">
<img src="/rivet-logo-text-white.svg" alt="Rivet" className="h-6 w-auto" />
</a>
<p className="text-sm leading-6 text-zinc-500">
Infrastructure for software that thinks
<p className="text-sm leading-6 text-zinc-400">
Build and scale stateful workloads
</p>
<div className="flex space-x-4">
{footer.social.map((item) => (
@ -81,87 +73,64 @@ export function Footer() {
</a>
))}
</div>
</motion.div>
</div>
{/* Links */}
<div className="mt-12 grid grid-cols-2 gap-8 md:grid-cols-3 xl:col-span-8 xl:mt-0">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
>
<div>
<h3 className="text-sm font-semibold leading-6 text-white">Products</h3>
<ul role="list" className="mt-4 space-y-3">
{footer.products.map((item) => (
<li key={item.name}>
<a
href={item.href}
className="text-sm leading-6 text-zinc-500 hover:text-white transition-colors"
className="text-sm leading-6 text-zinc-400 hover:text-white transition-colors"
>
{item.name}
</a>
</li>
))}
</ul>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.15 }}
>
</div>
<div>
<h3 className="text-sm font-semibold leading-6 text-white">Developers</h3>
<ul role="list" className="mt-4 space-y-3">
{footer.developers.map((item) => (
<li key={item.name}>
<a
href={item.href}
className="text-sm leading-6 text-zinc-500 hover:text-white transition-colors"
className="text-sm leading-6 text-zinc-400 hover:text-white transition-colors"
>
{item.name}
</a>
</li>
))}
</ul>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
</div>
<div>
<h3 className="text-sm font-semibold leading-6 text-white">Legal</h3>
<ul role="list" className="mt-4 space-y-3">
{footer.legal.map((item) => (
<li key={item.name}>
<a
href={item.href}
className="text-sm leading-6 text-zinc-500 hover:text-white transition-colors"
className="text-sm leading-6 text-zinc-400 hover:text-white transition-colors"
>
{item.name}
</a>
</li>
))}
</ul>
</motion.div>
</div>
</div>
</div>
{/* Bottom */}
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.3 }}
className="mt-12 border-t border-white/10 pt-8"
>
<p className="text-xs text-zinc-600 text-center">
<div className="mt-12 border-t border-white/10 pt-8">
<p className="text-xs text-zinc-500 text-center">
&copy; {new Date().getFullYear()} Rivet Gaming, Inc. All rights reserved.
</p>
</motion.div>
</div>
</div>
</footer>
);

View file

@ -1,6 +1,5 @@
'use client';
import { motion } from 'framer-motion';
import { Code, Server, GitBranch } from 'lucide-react';
import { CopyButton } from './ui/CopyButton';
@ -87,7 +86,7 @@ function SdkCodeHighlighted() {
);
}
const sandboxCommand = `curl -fsSL https://releases.rivet.dev/sandbox-agent/latest/install.sh | sh`;
const sandboxCommand = `curl -fsSL https://releases.rivet.dev/sandbox-agent/0.2.x/install.sh | sh`;
const sourceCommands = `git clone https://github.com/rivet-dev/sandbox-agent
cd sandbox-agent
@ -95,55 +94,44 @@ cargo run -p sandbox-agent --release`;
export function GetStarted() {
return (
<section id="get-started" className="border-t border-white/10 py-48">
<div className="mx-auto max-w-7xl px-6">
<div className="mb-12">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-2 text-2xl font-normal tracking-tight text-white md:text-4xl"
>
<section id="get-started" className="relative overflow-hidden border-t border-white/5 py-32">
<div className="relative z-10 mx-auto max-w-7xl px-6">
<div className="mb-16 text-center">
<h2 className="mb-4 text-3xl font-medium tracking-tight text-white md:text-5xl">
Get Started
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="max-w-xl text-base leading-relaxed text-zinc-500"
>
</h2>
<p className="text-lg text-zinc-400">
Choose the installation method that works best for your use case.
</motion.p>
</p>
<p className="mt-4 text-sm text-zinc-500">
Quick OpenCode attach: <span className="font-mono text-white">npx @sandbox-agent/gigacode</span>
</p>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="grid grid-cols-1 gap-4 md:grid-cols-3"
>
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
{/* Option 1: SDK */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<Code className="h-4 w-4" />
<div className="group relative flex flex-col 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">
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
<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" />
<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-4 flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-500/10 text-blue-400 transition-all duration-300 group-hover:bg-blue-500/20 group-hover:shadow-[0_0_15px_rgba(59,130,246,0.5)]">
<Code className="h-5 w-5" />
</div>
<div>
<h3 className="text-base font-normal text-white">TypeScript SDK</h3>
<h3 className="text-lg font-semibold text-white">TypeScript SDK</h3>
<p className="text-xs text-zinc-500">Embed in your application</p>
</div>
</div>
<p className="mb-4 text-sm leading-relaxed text-zinc-500">
<p className="relative z-10 mb-4 text-sm leading-relaxed text-zinc-400 min-h-[4.5rem]">
Import the TypeScript SDK directly into your Node or browser application. Full type safety and streaming support.
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<div className="relative z-10 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/5 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/5 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">example.ts</span>
<CopyButton text={sdkCodeRaw} />
</div>
@ -152,25 +140,29 @@ export function GetStarted() {
</div>
</div>
{/* Option 2: HTTP API */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<Server className="h-4 w-4" />
{/* Option 2: Sandbox */}
<div className="group relative flex flex-col 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">
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
<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" />
<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-4 flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-green-500/10 text-green-400 transition-all duration-300 group-hover:bg-green-500/20 group-hover:shadow-[0_0_15px_rgba(34,197,94,0.5)]">
<Server className="h-5 w-5" />
</div>
<div>
<h3 className="text-base font-normal text-white">HTTP API</h3>
<h3 className="text-lg font-semibold text-white">HTTP API</h3>
<p className="text-xs text-zinc-500">Run as a server</p>
</div>
</div>
<p className="mb-4 text-sm leading-relaxed text-zinc-500">
<p className="relative z-10 mb-4 text-sm leading-relaxed text-zinc-400 min-h-[4.5rem]">
Run as an HTTP server and connect from any language. Deploy to E2B, Daytona, Vercel, or your own infrastructure.
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<div className="relative z-10 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/5 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/5 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">terminal</span>
<CopyButton text={sandboxCommand} />
</div>
@ -180,7 +172,7 @@ export function GetStarted() {
<span className="text-zinc-300">curl -fsSL \</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-green-400">https://releases.rivet.dev/sandbox-agent/latest/install.sh</span>
<span className="text-green-400">https://releases.rivet.dev/sandbox-agent/0.2.x/install.sh</span>
<span className="text-zinc-300"> | </span>
<span className="text-blue-400">sh</span>
</code>
@ -189,25 +181,29 @@ export function GetStarted() {
</div>
</div>
{/* Option 3: Open Source */}
<div className="group flex flex-col rounded-2xl border border-white/10 bg-white/[0.02] p-6 transition-colors hover:border-white/20">
<div className="mb-4 flex items-center gap-3">
<div className="text-zinc-500">
<GitBranch className="h-4 w-4" />
{/* Option 3: Build from Source */}
<div className="group relative flex flex-col 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">
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(245,158,11,0.15)_0%,transparent_50%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
<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="relative z-10 mb-4 flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-amber-500/10 text-amber-400 transition-all duration-300 group-hover:bg-amber-500/20 group-hover:shadow-[0_0_15px_rgba(245,158,11,0.5)]">
<GitBranch className="h-5 w-5" />
</div>
<div>
<h3 className="text-base font-normal text-white">Open Source</h3>
<h3 className="text-lg font-semibold text-white">Open Source</h3>
<p className="text-xs text-zinc-500">Full control</p>
</div>
</div>
<p className="mb-4 text-sm leading-relaxed text-zinc-500">
<p className="relative z-10 mb-4 text-sm leading-relaxed text-zinc-400 min-h-[4.5rem]">
Clone the repo and build with Cargo. Customize, contribute, or embed directly in your Rust project.
</p>
<div className="flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/10 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2">
<div className="relative z-10 flex-1 flex flex-col">
<div className="overflow-hidden rounded-lg border border-white/5 bg-black/50 flex-1 flex flex-col">
<div className="flex items-center justify-between border-b border-white/5 bg-white/5 px-3 py-2">
<span className="text-[10px] font-medium text-zinc-500">terminal</span>
<CopyButton text={sourceCommands} />
</div>
@ -230,7 +226,7 @@ export function GetStarted() {
</div>
</div>
</div>
</motion.div>
</div>
</div>
</section>
);

View file

@ -1,45 +1,23 @@
'use client';
import { motion } from 'framer-motion';
export function Inspector() {
return (
<section className="border-t border-white/10 py-48">
<div className="mx-auto max-w-7xl px-6">
<div className="mb-12 text-center">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-2 text-2xl font-normal tracking-tight text-white md:text-4xl"
>
Built-in Debugger
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="mx-auto max-w-xl text-base leading-relaxed text-zinc-500"
>
Inspect sessions, view event payloads, and troubleshoot without writing&nbsp;code.
</motion.p>
</div>
<section className="relative overflow-hidden border-t border-white/5 py-24">
<div className="mx-auto max-w-4xl px-6 text-center">
<h2 className="mb-4 text-3xl font-medium tracking-tight text-white md:text-5xl">
Built-in Debugger
</h2>
<p className="mb-12 text-lg text-zinc-400">
Inspect sessions, view event payloads, and troubleshoot without writing code.
</p>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
className="overflow-hidden rounded-2xl border border-white/10"
>
<div className="overflow-hidden rounded-2xl border border-white/10 shadow-2xl">
<img
src="/images/inspector.png"
alt="Sandbox Agent Inspector"
className="w-full"
/>
</motion.div>
</div>
</div>
</section>
);

View file

@ -6,12 +6,11 @@ import { GitHubStars } from './GitHubStars';
function NavItem({ href, children }: { href: string; children: React.ReactNode }) {
return (
<a
href={href}
className="px-3 py-2 text-sm font-medium text-zinc-400 transition-colors duration-200 hover:text-white"
>
{children}
</a>
<div className="px-2.5 py-2 opacity-60 hover:opacity-100 transition-all duration-200">
<a href={href} className="text-white text-sm">
{children}
</a>
</div>
);
}
@ -35,17 +34,15 @@ export function Navigation() {
isScrolled ? "before:border-white/10" : "before:border-transparent"
}`}
>
{/* Background with blur */}
<div
className={`absolute inset-0 -z-[1] hidden overflow-hidden rounded-2xl transition-all duration-300 ease-in-out md:block ${
isScrolled
? "bg-black/80 backdrop-blur-lg"
: "bg-transparent backdrop-blur-none"
: "bg-black backdrop-blur-none"
}`}
/>
<header
className={`bg-black/60 border-b-transparent sticky top-0 z-10 flex flex-col items-center border-b backdrop-blur-md pt-2 pb-2 md:static md:bg-transparent md:rounded-2xl md:max-w-[1200px] md:border-transparent md:backdrop-blur-none transition-all hover:opacity-100 ${
className={`bg-black/60 border-b-transparent sticky top-0 z-10 flex flex-col items-center border-b backdrop-blur pt-2 pb-2 md:static md:bg-transparent md:rounded-2xl md:max-w-[1200px] md:border-transparent md:backdrop-none md:backdrop-blur-none transition-all hover:opacity-100 ${
isScrolled ? "opacity-100" : "opacity-80"
}`}
>
@ -56,24 +53,24 @@ export function Navigation() {
<a href="https://rivet.dev" className="flex items-center">
<img src="/rivet-icon.svg" alt="Rivet" className="size-8" />
</a>
<span className="text-white/20">|</span>
<span className="text-white/30">|</span>
<a href="/" className="flex items-center">
<img src="/logos/sandboxagent.svg" alt="Sandbox Agent SDK" className="h-6 w-auto" />
</a>
</div>
{/* Desktop Nav */}
<div className="hidden md:flex items-center ml-2">
<div className="hidden md:flex items-center">
<NavItem href="/docs">Docs</NavItem>
<NavItem href="https://github.com/rivet-dev/sandbox-agent/releases">Changelog</NavItem>
</div>
</div>
{/* Right side */}
<div className="hidden md:flex flex-row items-center gap-2">
<div className="hidden md:flex flex-row items-center">
<a
href="https://discord.gg/auCecybynK"
className="inline-flex items-center justify-center whitespace-nowrap rounded-md border border-white/10 px-4 py-2 h-10 text-sm hover:border-white/20 text-white/90 hover:text-white transition-colors"
className="inline-flex items-center justify-center whitespace-nowrap rounded-md border border-white/10 px-4 py-2 h-10 text-sm mr-2 hover:border-white/20 text-white/90 hover:text-white transition-colors"
aria-label="Discord"
>
<svg
@ -93,7 +90,7 @@ export function Navigation() {
{/* Mobile menu button */}
<button
className="md:hidden text-zinc-400 hover:text-white p-2 transition-colors"
className="md:hidden text-zinc-400 hover:text-white p-2"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
@ -104,26 +101,26 @@ export function Navigation() {
{/* Mobile menu */}
{mobileMenuOpen && (
<div className="md:hidden border border-white/10 bg-black/95 backdrop-blur-lg rounded-2xl mt-2 mx-2 shadow-xl">
<div className="px-4 py-4 space-y-1">
<div className="md:hidden border border-white/10 bg-black/95 backdrop-blur-lg rounded-2xl mt-2 mx-2">
<div className="px-4 py-4 space-y-2">
<a
href="/docs"
className="block py-2.5 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors font-medium"
className="block py-2 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Docs
</a>
<a
href="https://github.com/rivet-dev/sandbox-agent/releases"
className="block py-2.5 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors font-medium"
className="block py-2 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
Changelog
</a>
<div className="border-t border-white/10 pt-3 mt-3 space-y-1">
<div className="border-t border-white/10 pt-2 mt-2 space-y-2">
<a
href="https://discord.gg/auCecybynK"
className="flex items-center gap-3 py-2.5 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
className="flex items-center gap-2 py-2 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(false)}
aria-label="Discord"
>
@ -135,11 +132,11 @@ export function Navigation() {
>
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
</svg>
<span className="font-medium">Discord</span>
<span>Discord</span>
</a>
<GitHubStars
repo="rivet-dev/sandbox-agent"
className="flex items-center gap-3 py-2.5 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors w-full"
className="flex items-center gap-2 py-2 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors"
onClick={() => setMobileMenuOpen(false)}
/>
</div>

View file

@ -1,91 +1,133 @@
'use client';
import { motion } from 'framer-motion';
import { Shield, Layers, Database, X, Check } from 'lucide-react';
import { X, Check } from 'lucide-react';
const frictions = [
{
icon: Shield,
number: '01',
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',
},
{
icon: Layers,
number: '02',
title: 'Every Coding Agent is Different',
problem:
'Claude Code, Codex, OpenCode, Amp, and Pi 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',
},
{
icon: Database,
number: '03',
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',
},
];
const accentStyles = {
orange: {
gradient: 'from-orange-500/20',
border: 'border-orange-500/30',
glow: 'rgba(255,79,0,0.15)',
number: 'text-orange-500',
},
purple: {
gradient: 'from-purple-500/20',
border: 'border-purple-500/30',
glow: 'rgba(168,85,247,0.15)',
number: 'text-purple-500',
},
blue: {
gradient: 'from-blue-500/20',
border: 'border-blue-500/30',
glow: 'rgba(59,130,246,0.15)',
number: 'text-blue-500',
},
};
export function PainPoints() {
return (
<section className="border-t border-white/10 py-48">
<section className="relative overflow-hidden border-t border-white/5 py-32">
<div className="mx-auto max-w-7xl px-6">
<div className="mb-12">
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-2 text-2xl font-normal tracking-tight text-white md:text-4xl"
>
Running coding agents remotely is hard.
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
className="max-w-2xl text-base leading-relaxed text-zinc-500"
>
The Sandbox Agent SDK is a server that runs inside your sandbox. Your app connects remotely to control Claude Code, Codex, OpenCode, Amp, or Pi streaming events, handling permissions, managing sessions.
</motion.p>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="grid grid-cols-1 gap-8 md:grid-cols-3"
className="mb-16"
>
{frictions.map((friction) => (
<div key={friction.title} className="flex flex-col border-t border-white/10 pt-6">
<div className="mb-3 text-zinc-500">
<friction.icon className="h-4 w-4" />
</div>
<h3 className="mb-4 text-base font-normal text-white">{friction.title}</h3>
<div className="mb-4">
<div className="flex items-center gap-2 mb-2">
<X className="h-3 w-3 text-zinc-600" />
<span className="text-[10px] font-medium uppercase tracking-wider text-zinc-600">Problem</span>
</div>
<p className="text-sm leading-relaxed text-zinc-500">
{friction.problem}
</p>
</div>
<div className="mt-auto border-t border-white/5 pt-4">
<div className="flex items-center gap-2 mb-2">
<Check className="h-3 w-3 text-green-400" />
<span className="text-[10px] font-medium uppercase tracking-wider text-zinc-400">Solution</span>
</div>
<p className="text-sm leading-relaxed text-zinc-300">
{friction.solution}
</p>
</div>
</div>
))}
<h2 className="mb-6 text-3xl font-medium tracking-tight text-white md:text-5xl">
Running coding agents remotely is hard.
</h2>
<p className="max-w-2xl text-lg leading-relaxed text-zinc-400">
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>
<div className="grid gap-6 md:grid-cols-3">
{frictions.map((friction, index) => {
const styles = accentStyles[friction.accentColor as keyof typeof accentStyles];
return (
<motion.div
key={friction.number}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="group relative flex flex-col 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 */}
<div className="absolute left-0 right-0 top-0 z-10 h-[1px] bg-gradient-to-r from-transparent via-white/20 to-transparent" />
{/* Hover glow */}
<div
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style={{
background: `radial-gradient(circle at top left, ${styles.glow} 0%, transparent 50%)`,
}}
/>
{/* Corner highlight */}
<div
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 flex flex-col h-full">
{/* Title */}
<h3 className="mb-4 text-xl font-medium text-white">{friction.title}</h3>
{/* 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>
{/* 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>
);
})}
</div>
</div>
</section>
);