Cactus Landing
Style direction: Reference landing study
$ npx cactus add cactus
Copied!
Aa
InterBody
Cactus Site Recreation Spec
Use this document as a direct implementation source for recreating the current site in React + Tailwind.
Global Design Variables
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
:root {
color-scheme: dark;
--background: #0a0908;
--foreground: #f2f2f4;
--card: #171615;
--card-foreground: #efeff1;
--popover: #090909;
--popover-foreground: #f0f0f2;
--primary: #f2f2f4;
--primary-foreground: #121214;
--secondary: #08080b;
--secondary-foreground: #f2f2f4;
--muted: #171615;
--muted-foreground: #75767d;
--accent: #2d2c2b;
--accent-foreground: #ececee;
--destructive: #ff5370;
--destructive-foreground: #f2f2f4;
--border: #1f1e1d;
--input: #222120;
--ring: #8e8f94;
--chart-1: #c792ea;
--chart-2: #82aaff;
--chart-3: #89ddff;
--chart-4: #f78c6c;
--chart-5: #ffcb6b;
--radius: 12px;
--sidebar: #171615;
--sidebar-foreground: #f0f0f2;
--sidebar-primary: #f2f2f4;
--sidebar-primary-foreground: #121214;
--sidebar-accent: #2d2c2b;
--sidebar-accent-foreground: #ececee;
--sidebar-border: #1f1e1d;
--sidebar-ring: #8e8f94;
--shadow-medium: rgb(0 0 0 / 45%);
--shadow-strong: rgb(0 0 0 / 55%);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
Global Base Styles
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
background: var(--color-background);
color: var(--color-foreground);
}
button,
a {
cursor: pointer;
font-family: inherit;
}
App Section Order
import { Navbar } from './sections/Navbar'
import { HeroSection } from './sections/HeroSection'
import { LogoCloudSection } from './sections/LogoCloudSection'
import { CoreFeaturesSection } from './sections/CoreFeaturesSection'
import { UseCasesSection } from './sections/UseCasesSection'
import { BenefitsSection } from './sections/BenefitsSection'
import { TestimonialsSection } from './sections/TestimonialsSection'
import { PricingSection } from './sections/PricingSection'
import { WaysToCodeSection } from './sections/WaysToCodeSection'
import { FaqSection } from './sections/FaqSection'
import { CtaSection } from './sections/CtaSection'
import { FooterSection } from './sections/FooterSection'
function App() {
return (
<div className="min-h-screen bg-[var(--color-background)] text-[var(--color-foreground)] antialiased">
<Navbar />
<HeroSection />
<LogoCloudSection />
<CoreFeaturesSection />
<UseCasesSection />
<BenefitsSection />
<TestimonialsSection />
<PricingSection />
<WaysToCodeSection />
<FaqSection />
<CtaSection />
<FooterSection />
</div>
)
}
export default App
Shared Data and Reusable Components (required)
Data Source: siteData.ts
export type NavLink = {
label: string
href: string
}
export const navLinks: NavLink[] = [
{ label: 'Features', href: '#core-features' },
{ label: 'Use cases', href: '#use-cases' },
{ label: 'Testimonials', href: '#testimonials' },
{ label: 'Pricing', href: '#pricing' },
{ label: 'FAQ', href: '#faq' },
]
export const brandRows = [
['SignFlow', 'CloudSync', 'NotionKit', 'DataStream'],
['NotionKit', 'DataStream', 'SignFlow', 'CloudSync'],
]
const sharedImageUrl = 'https://images.unsplash.com/photo-1771925183858-88607574e804?auto=format&fit=crop&w=3732&q=80'
export const imageAssets = {
heroBackground: sharedImageUrl,
heroEditor: sharedImageUrl,
cardBackgroundA: sharedImageUrl,
cardBackgroundB: sharedImageUrl,
cardBackgroundC: sharedImageUrl,
cardBackgroundD: sharedImageUrl,
editorWide: sharedImageUrl,
editorSidebar: sharedImageUrl,
editorChat: sharedImageUrl,
useCaseEditor: sharedImageUrl,
terminal: sharedImageUrl,
browser: sharedImageUrl,
avatarSarah: sharedImageUrl,
avatarEthan: sharedImageUrl,
avatarEmma: sharedImageUrl,
avatarArthur: sharedImageUrl,
arrowRight: sharedImageUrl,
}
export const coreFeatureCards = [
{
title: 'Context-perfect AI chat',
body: 'Ask once, get exactly what you need. Our AI understands your entire codebase and gives you precise answers with cactus line references.',
cta: 'Try AI chat',
image: imageAssets.editorWide,
background: imageAssets.cardBackgroundA,
reverse: false,
},
{
title: 'Precision autocomplete',
body: 'Stop choosing between 10 suggestions. Cactus gives you one perfect completion that matches your code style and intent.',
cta: 'See it in action',
image: imageAssets.editorSidebar,
background: imageAssets.cardBackgroundB,
reverse: true,
},
{
title: 'AI-powered terminal',
body: 'Debug smarter with instant error detection, suggested fixes, and command optimization. Let Cactus handle the terminal heavy lifting.',
cta: 'Explore terminal',
image: imageAssets.editorWide,
background: imageAssets.cardBackgroundC,
reverse: false,
},
]
export const useCaseTabs = ['Full-stack', 'Debug & refactor', 'API integration', 'Testing & CI/CD']
export const useCasePanels = [
{
subtitle: 'Full-stack development',
text: 'Build frontend and backend seamlessly. Cactus understands your entire stack—from React components to database queries—and helps you ship faster with context-aware suggestions.',
button: 'Start building',
},
{
subtitle: 'Debugging and refactoring',
text: 'Find bugs instantly with precise error detection. Refactor with AI that understands dependencies across your entire codebase.',
button: 'Get started',
},
{
subtitle: 'API integration',
text: 'Connect to any API in minutes. Cactus generates type-safe requests, handles authentication, and suggests error handling.',
button: 'Get started',
},
{
subtitle: 'Testing & CI/CD',
text: 'Write tests faster with AI-generated test cases. Set up CI/CD pipelines with precise configuration. Ship with confidence, every time.',
button: 'Get started',
},
]
export const benefits = [
{
icon: 'target',
title: 'Full codebase understanding',
text: 'AI that understands your entire project, not just the current file.',
},
{
icon: 'cube',
title: 'Works out of the box',
text: 'Install once, start coding. Zero configuration required.',
},
{
icon: 'lock',
title: 'Your code stays yours',
text: '100% private by default. Your code never leaves your machine.',
},
{
icon: 'bolt',
title: 'Instant responses',
text: 'Sub-50ms autocomplete and real-time AI. No lag, ever.',
},
{
icon: 'braces',
title: 'Every language you use',
text: '50+ languages supported with the same precision.',
},
{
icon: 'spark',
title: 'Refactor with confidence',
text: 'Change once, update everywhere. Zero broken imports.',
},
]
export const testimonials = [
{
quote:
"Cactus cut my development time in half. The AI actually understands what I'm building and suggests exactly what I need. No more wading through irrelevant completions.",
name: 'Sarah Chen',
role: 'Senior Engineer',
avatar: imageAssets.avatarSarah,
},
{
quote:
"Finally, an AI editor that doesn't feel like it's guessing. Context-aware suggestions that actually make sense. It's like pair programming with someone who knows your codebase.",
},
{
quote:
'I was skeptical about AI coding tools until Cactus. The precision is unmatched—it gets my code style, understands dependencies, and never breaks my builds. Game changer.',
name: 'Emma Larsson',
role: 'Full-stack Developer',
avatar: imageAssets.avatarEmma,
},
{
quote:
'Zero setup, instant productivity. I switched from Cursor and never looked back. Cactus just works, and it\'s noticeably faster. The refactoring feature alone is worth it.',
},
{
quote:
"Best AI autocomplete I've ever used. It's like Cactus reads my mind—one suggestion, always the right one. And the privacy-first approach gives me peace of mind.",
name: 'Ethan R',
role: 'Devops',
avatar: imageAssets.avatarEthan,
},
{
quote:
'Cactus eliminated the back-and-forth I had with other AI assistants. Ask once, get the cactus answer with line numbers and context. My productivity has skyrocketed.',
},
{
quote: 'Get the cactus answer with line numbers and context. My productivity has skyrocketed.',
compact: true,
},
{
quote: 'No more wading through irrelevant completions.',
compact: true,
},
{
quote: 'The privacy-first approach gives me peace of mind.',
compact: true,
},
]
export const pricingCards = [
{
name: 'Free',
price: '€0',
suffix: '/month',
description: 'Perfect for trying Cactus. All core features included, forever.',
cta: 'Get started',
features: [
'Unlimited local projects',
'AI autocomplete (basic)',
'Code chat assistant',
'50+ languages support',
'Terminal integration',
],
},
{
name: 'Pro',
badge: 'Popular',
price: '€29',
suffix: '/month',
description: 'For developers who need advanced features and unlimited AI requests.',
cta: 'Start 14-day trial',
highlight: true,
features: [
'Everything in Free',
'Unlimited AI requests',
'Advanced context (full codebase)',
'Priority AI responses',
'Smart refactoring tools',
'Multi-file editing',
],
},
{
name: 'Enterprise',
price: 'Custom',
description: 'For teams that need dedicated support, custom deployment, and advanced security.',
cta: 'Contact sales',
features: [
'Everything in Pro',
'Unlimited team members',
'Self-hosted deployment',
'SSO & SAML',
'Custom AI model training',
'Dedicated support manager',
'SLA guarantees',
],
},
]
export const waysToCode = [
{
title: 'Command line',
description: 'Install via npm and start coding instantly from your terminal.',
image: imageAssets.terminal,
action: 'npm install -g cactus',
copy: true,
},
{
title: 'Desktop app',
description: 'Native macOS, Windows, and Linux app with full offline support.',
image: imageAssets.editorChat,
action: 'Download for macOS',
external: false,
},
{
title: 'Browser',
description: 'Try Cactus instantly in your browser. No installation required.',
image: imageAssets.browser,
action: 'Open in browser',
external: true,
},
]
export const faqQuestions = [
'Is Cactus really free?',
'How does Cactus compare to Cursor or GitHub Copilot?',
'Is my code private?',
'What languages does Cactus support?',
'Can I use Cactus offline?',
'How do I migrate from my current editor?',
]
Component: BrandMark.tsx
export function BrandMark({ className = 'h-4 w-4' }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 26 22" fill="none" aria-hidden="true">
<path
d="M13 11C13 11.304 12.862 11.591 12.625 11.781L7.625 15.781C7.194 16.126 6.564 16.056 6.219 15.625C5.874 15.194 5.944 14.564 6.375 14.219L10.399 11L6.375 7.781C5.944 7.436 5.874 6.806 6.219 6.375C6.564 5.944 7.194 5.874 7.625 6.219L12.625 10.219C12.862 10.409 13 10.696 13 11ZM19 14L14 14C13.448 14 13 14.448 13 15C13 15.552 13.448 16 14 16L19 16C19.552 16 20 15.552 20 15C20 14.448 19.552 14 19 14ZM26 2L26 20C26 21.105 25.105 22 24 22L2 22C0.895 22 0 21.105 0 20L0 2C0 0.895 0.895 0 2 0L24 0C25.105 0 26 0.895 26 2ZM24 20L24 2L2 2L2 20Z"
fill="currentColor"
/>
</svg>
)
}
Component: SectionHeading.tsx
type SectionHeadingProps = {
eyebrow: string
leading: string
muted: string
id?: string
className?: string
}
export function SectionHeading({ eyebrow, leading, muted, id, className = '' }: SectionHeadingProps) {
return (
<div id={id} className={className}>
<p className="text-[20px] font-medium tracking-tight text-[var(--color-muted-foreground)]">// {eyebrow}</p>
<h2 className="mt-2 text-[44px] font-medium leading-[1.05] tracking-[-0.04em] text-[var(--color-foreground)] md:text-[56px]">
{leading} <span className="text-[var(--color-muted-foreground)]">{muted}</span>
</h2>
</div>
)
}
Component: UiIcon.tsx
type UiIconProps = {
kind: string
}
export function UiIcon({ kind }: UiIconProps) {
if (kind === 'target') {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<circle cx="12" cy="12" r="7" stroke="currentColor" strokeWidth="1.6" />
<circle cx="12" cy="12" r="2.3" fill="currentColor" />
</svg>
)
}
if (kind === 'cube') {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<path d="M12 3.8L5 7.9V16.1L12 20.2L19 16.1V7.9L12 3.8Z" stroke="currentColor" strokeWidth="1.5" />
<path d="M5 7.9L12 12L19 7.9" stroke="currentColor" strokeWidth="1.5" />
<path d="M12 12V20.2" stroke="currentColor" strokeWidth="1.5" />
</svg>
)
}
if (kind === 'lock') {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<rect x="5.3" y="10" width="13.4" height="9.7" rx="2" stroke="currentColor" strokeWidth="1.5" />
<path d="M8.7 10V7.7A3.3 3.3 0 0112 4.4A3.3 3.3 0 0115.3 7.7V10" stroke="currentColor" strokeWidth="1.5" />
</svg>
)
}
if (kind === 'bolt') {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<path d="M13.9 3.8L7.6 12.2H12L10.9 20.2L17.4 11.8H13L13.9 3.8Z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />
</svg>
)
}
if (kind === 'braces') {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<path d="M9.4 6.5C8.2 6.5 7.4 7.2 7.4 8.4V10C7.4 11 7 11.8 6 12C7 12.2 7.4 13 7.4 14V15.6C7.4 16.8 8.2 17.5 9.4 17.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
<path d="M14.6 6.5C15.8 6.5 16.6 7.2 16.6 8.4V10C16.6 11 17 11.8 18 12C17 12.2 16.6 13 16.6 14V15.6C16.6 16.8 15.8 17.5 14.6 17.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
</svg>
)
}
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<path d="M12 4.6L13.9 8.7L18.4 9.3L15.2 12.4L16 16.9L12 14.7L8 16.9L8.8 12.4L5.6 9.3L10.1 8.7L12 4.6Z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />
</svg>
)
}
Component: SyntaxCodeBlock.tsx
type SyntaxCodeBlockProps = {
compact?: boolean
}
const codeLines = [
[
{ text: 'import ', className: 'text-[var(--color-chart-1)]' },
{ text: '{ useMemo } ', className: 'text-[var(--color-foreground)]' },
{ text: 'from ', className: 'text-[var(--color-chart-1)]' },
{ text: "'react'", className: 'text-[var(--color-chart-2)]' },
],
[
{ text: 'import ', className: 'text-[var(--color-chart-1)]' },
{ text: '{ createClient } ', className: 'text-[var(--color-foreground)]' },
{ text: 'from ', className: 'text-[var(--color-chart-1)]' },
{ text: "'@/lib/db'", className: 'text-[var(--color-chart-2)]' },
],
[],
[{ text: 'export ', className: 'text-[var(--color-chart-1)]' }, { text: 'async function ', className: 'text-[var(--color-chart-2)]' }, { text: 'getProjects', className: 'text-[var(--color-chart-5)]' }, { text: '() {', className: 'text-[var(--color-foreground)]' }],
[{ text: ' const ', className: 'text-[var(--color-chart-1)]' }, { text: 'db ', className: 'text-[var(--color-foreground)]' }, { text: '= ', className: 'text-[var(--color-chart-3)]' }, { text: 'createClient', className: 'text-[var(--color-chart-5)]' }, { text: '()', className: 'text-[var(--color-foreground)]' }],
[{ text: ' const ', className: 'text-[var(--color-chart-1)]' }, { text: '{ data, error } ', className: 'text-[var(--color-foreground)]' }, { text: '= ', className: 'text-[var(--color-chart-3)]' }, { text: 'await ', className: 'text-[var(--color-chart-1)]' }, { text: 'db.projects.list', className: 'text-[var(--color-chart-2)]' }, { text: '({', className: 'text-[var(--color-foreground)]' }],
[{ text: " select: '*',", className: 'text-[var(--color-chart-4)]' }],
[{ text: " orderBy: 'updated_at',", className: 'text-[var(--color-chart-4)]' }],
[{ text: ' limit: ', className: 'text-[var(--color-chart-4)]' }, { text: '20', className: 'text-[var(--color-chart-5)]' }],
[{ text: ' })', className: 'text-[var(--color-foreground)]' }],
[],
[{ text: ' if ', className: 'text-[var(--color-chart-1)]' }, { text: '(error) ', className: 'text-[var(--color-foreground)]' }, { text: 'throw ', className: 'text-[var(--color-chart-1)]' }, { text: 'error', className: 'text-[var(--color-destructive)]' }],
[{ text: ' return ', className: 'text-[var(--color-chart-1)]' }, { text: 'data', className: 'text-[var(--color-foreground)]' }],
[{ text: '}', className: 'text-[var(--color-foreground)]' }],
]
export function SyntaxCodeBlock({ compact = false }: SyntaxCodeBlockProps) {
return (
<div className="h-full w-full bg-[var(--color-secondary)]">
<div className="flex items-center gap-1.5 border-b border-[var(--color-border)] px-3 py-2 md:px-4">
<span className="h-2 w-2 rounded-full bg-[var(--color-destructive)]" />
<span className="h-2 w-2 rounded-full bg-[var(--color-chart-5)]" />
<span className="h-2 w-2 rounded-full bg-[var(--color-chart-3)]" />
</div>
<div className={`h-[calc(100%-33px)] overflow-hidden ${compact ? 'px-3 py-2' : 'px-3 py-3 md:px-4 md:py-4'}`}>
<pre className={`font-mono ${compact ? 'text-[9px] leading-[1.45] md:text-[10px]' : 'text-[10px] leading-[1.55] md:text-[12px]'}`}>
{codeLines.map((segments, lineIndex) => (
<div key={lineIndex} className="whitespace-pre">
<span className="mr-3 inline-block w-4 select-none text-right text-[var(--color-muted-foreground)] md:w-5">{lineIndex + 1}</span>
{segments.map((segment, segmentIndex) => (
<span key={`${lineIndex}-${segmentIndex}`} className={segment.className}>
{segment.text}
</span>
))}
</div>
))}
</pre>
</div>
</div>
)
}
Section-by-Section Source (title + code)
Navbar
Component File: src/sections/Navbar.tsx
import { BrandMark } from '../components/BrandMark'
import { navLinks } from '../data/siteData'
export function Navbar() {
return (
<nav className="mx-auto flex w-full max-w-[1136px] items-center justify-between px-4 pb-7 pt-5 md:px-7 md:pb-10 md:pt-6">
<a href="#hero" className="flex items-center gap-2 text-[var(--color-foreground)]">
<BrandMark className="h-[14px] w-[17px]" />
<span className="text-[20px] font-medium tracking-[-0.02em]">Cactus</span>
</a>
<div className="hidden items-center gap-8 md:flex">
{navLinks.map((link) => (
<a
key={link.label}
href={link.href}
className="text-[16px] font-medium text-[var(--color-muted-foreground)] transition-colors hover:text-[var(--color-foreground)]"
>
{link.label}
</a>
))}
</div>
<a
href="#cta"
className="hidden rounded-[8px] border border-[var(--color-border)] bg-transparent px-4 py-[9px] text-[16px] font-medium text-[var(--color-foreground)] md:inline-flex"
>
Get Started
</a>
<button
type="button"
className="flex h-10 w-10 items-center justify-center rounded-md text-white md:hidden"
aria-label="Open menu"
>
<span className="flex flex-col gap-1.5">
<span className="h-0.5 w-[18px] rounded bg-[var(--color-foreground)]" />
<span className="h-0.5 w-[18px] rounded bg-[var(--color-foreground)]" />
<span className="h-0.5 w-[18px] rounded bg-[var(--color-foreground)]" />
</span>
</button>
</nav>
)
}
Hero: Code with cactus precision.
Component File: src/sections/HeroSection.tsx
import { imageAssets } from '../data/siteData'
import { SyntaxCodeBlock } from '../components/SyntaxCodeBlock'
export function HeroSection() {
return (
<header id="hero" className="mx-auto w-full max-w-[1136px] px-4 md:px-7">
<div className="mx-auto max-w-[780px] text-center">
<h1 className="text-[40px] font-medium leading-[0.95] tracking-[-0.05em] text-[var(--color-foreground)] md:text-[56px]">
Code with cactus precision.
</h1>
<p className="mx-auto mt-5 max-w-[730px] text-[16px] leading-[1.35] tracking-[0em] text-[var(--color-muted-foreground)]">
The AI-native code editor that gets it exactly right.
<br className="hidden md:block" />
No approximation. No bloat. Just perfect code, every time.
</p>
<div className="mt-8 flex items-center justify-center gap-3">
<button
type="button"
className="rounded-[10px] bg-[var(--color-primary)] px-5 py-[11px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
Download for macOs
</button>
<button
type="button"
className="hidden rounded-[10px] border border-transparent px-3 py-[11px] text-[16px] font-medium tracking-[0em] text-[var(--color-foreground)] md:inline-flex"
>
Discover product
</button>
</div>
</div>
<div className="relative mt-9 overflow-hidden rounded-[14px] border border-[var(--color-border)] bg-[var(--color-secondary)]">
<img
src={imageAssets.heroBackground}
alt=""
className="h-[220px] w-full object-cover md:h-[598px]"
loading="eager"
decoding="async"
/>
<div className="absolute inset-x-[11%] bottom-[14%] top-[8%] overflow-hidden rounded-[10px] border border-[var(--color-border)] bg-[var(--color-secondary)] shadow-[0_30px_70px_var(--shadow-medium)] md:inset-x-[13%] md:bottom-[15%] md:top-[8%]">
<SyntaxCodeBlock />
</div>
</div>
</header>
)
}
Logo Cloud: Trusted by developers at leading companies
Component File: src/sections/LogoCloudSection.tsx
import { brandRows } from '../data/siteData'
function LogoGlyph({ variant }: { variant: number }) {
if (variant === 0) {
return (
<svg viewBox="0 0 28 29" className="h-5 w-5" fill="none" aria-hidden="true">
<g transform="translate(-0.001 0.346)">
<path d="M17.684 8.086C16.546 7.325 15.208 6.92 13.839 6.92V0C16.576 0 19.252 0.812 21.528 2.332C23.804 3.853 25.578 6.014 26.625 8.543C27.673 11.072 27.947 13.855 27.413 16.539C26.879 19.224 25.561 21.69 23.625 23.625C21.69 25.561 19.224 26.879 16.539 27.413C13.855 27.947 11.072 27.673 8.543 26.625C6.014 25.578 3.853 23.804 2.332 21.528C0.812 19.252 0 16.576 0 13.839H6.92C6.92 15.208 7.325 16.546 8.086 17.684C8.846 18.822 9.927 19.708 11.191 20.232C12.456 20.756 13.847 20.893 15.189 20.626C16.532 20.359 17.764 19.7 18.732 18.732C19.7 17.764 20.359 16.532 20.626 15.189C20.893 13.847 20.756 12.456 20.232 11.191C19.708 9.927 18.822 8.846 17.684 8.086Z" fill="currentColor" />
<path d="M6.92 0C6.92 0.909 6.741 1.809 6.393 2.648C6.045 3.488 5.535 4.25 4.893 4.893C4.25 5.535 3.488 6.045 2.648 6.393C1.809 6.741 0.909 6.92 0 6.92V13.839C1.817 13.839 3.617 13.481 5.296 12.786C6.975 12.09 8.501 11.071 9.786 9.786C11.071 8.501 12.09 6.975 12.786 5.296C13.481 3.617 13.839 1.817 13.839 0H6.92Z" fill="currentColor" />
</g>
</svg>
)
}
if (variant === 1) {
return (
<svg viewBox="0 0 29 29" className="h-5 w-5" fill="none" aria-hidden="true">
<g transform="translate(0.84 1.095)">
<path d="M0 13.839C0 6.196 6.196 0 13.839 0C21.482 0 27.679 6.196 27.679 13.839C27.679 21.482 21.482 27.679 13.839 27.679C6.196 27.679 0 21.482 0 13.839ZM18.157 6.447C18.367 5.7 17.642 5.259 16.981 5.73L7.745 12.31C7.028 12.821 7.141 13.839 7.915 13.839H10.347V13.82H15.087L11.224 15.183L9.522 21.232C9.312 21.978 10.036 22.42 10.698 21.948L19.933 15.369C20.651 14.858 20.538 13.839 19.764 13.839H16.076Z" fill="currentColor" />
</g>
</svg>
)
}
if (variant === 2) {
return (
<svg viewBox="0 0 28 22.4" className="h-[18px] w-6" fill="none" aria-hidden="true">
<g transform="translate(0.492 2.24)">
<path d="M17.944 17.589H24.14L8.791 0H2.595Z" fill="currentColor" />
<path d="M11.971 0L26.768 16.956V0H22.764V5.353L18.092 0Z" fill="currentColor" />
<path d="M0 0.589V17.589H4.004V12.236L8.676 17.589H14.835Z" fill="currentColor" />
</g>
</svg>
)
}
return (
<svg viewBox="0 0 28 29" className="h-5 w-5" fill="none" aria-hidden="true">
<g transform="translate(0.81 0.638)">
<path d="M17.363 0.729L14.642 0L12.348 8.559L10.278 0.832L7.556 1.561L9.793 9.91L4.221 4.338L2.229 6.33L8.341 12.442L0.729 10.403L0 13.124L8.316 15.353C8.221 14.942 8.171 14.514 8.171 14.074C8.171 10.962 10.694 8.439 13.806 8.439C16.918 8.439 19.441 10.962 19.441 14.074C19.441 14.511 19.391 14.936 19.297 15.345L26.855 17.37L27.585 14.648L19.235 12.411L26.847 10.371L26.118 7.65L17.769 9.887L23.341 4.315L21.348 2.323L15.321 8.35Z" fill="currentColor" />
<path d="M19.292 15.376C19.059 16.363 18.567 17.249 17.891 17.959L23.366 23.435L25.358 21.442Z" fill="currentColor" />
<path d="M17.838 18.017C17.154 18.715 16.29 19.237 15.32 19.505L17.313 26.941L20.034 26.212Z" fill="currentColor" />
<path d="M15.217 19.532C14.767 19.648 14.296 19.709 13.81 19.709C13.289 19.709 12.785 19.639 12.307 19.507L10.313 26.949L13.034 27.678Z" fill="currentColor" />
<path d="M12.209 19.479C11.254 19.197 10.405 18.669 9.735 17.968L4.246 23.457L6.238 25.45Z" fill="currentColor" />
<path d="M9.692 17.92C9.033 17.215 8.553 16.34 8.325 15.369L0.742 17.401L1.471 20.122Z" fill="currentColor" />
</g>
</svg>
)
}
export function LogoCloudSection() {
return (
<section className="mx-auto mt-14 w-full max-w-[1136px] px-4 md:mt-20 md:px-7">
<div className="text-center">
<p className="text-[32px] font-medium leading-[1.1] tracking-[-0.03em] text-[var(--color-foreground)] md:text-[36px]">
Trusted by developers at leading companies
</p>
<p className="mt-2 text-[20px] font-medium tracking-[-0.03em] text-[var(--color-muted-foreground)]">Used by developers at</p>
</div>
<div className="mt-9 space-y-5">
{brandRows.map((row, rowIndex) => (
<div key={rowIndex} className="grid grid-cols-2 gap-y-5 md:grid-cols-4">
{row.map((brand, brandIndex) => (
<div
key={`${brand}-${rowIndex}-${brandIndex}`}
className="flex items-center justify-center gap-2 text-[28px] font-medium tracking-[-0.03em] text-[var(--color-foreground)] md:text-[36px]"
>
<LogoGlyph variant={brandIndex} />
<span>{brand}</span>
</div>
))}
</div>
))}
</div>
</section>
)
}
Core Features: Code with precision. Ship with confidence.
Component File: src/sections/CoreFeaturesSection.tsx
import { SectionHeading } from '../components/SectionHeading'
import { SyntaxCodeBlock } from '../components/SyntaxCodeBlock'
import { coreFeatureCards } from '../data/siteData'
export function CoreFeaturesSection() {
return (
<section id="core-features" className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Core features" leading="Code with precision." muted="Ship with confidence." />
<div className="mt-8 space-y-7 md:space-y-10">
{coreFeatureCards.map((card) => (
<article
key={card.title}
className="grid overflow-hidden rounded-[14px] border border-[var(--color-border)] bg-[var(--color-card)] md:grid-cols-2"
>
<div
className={`relative min-h-[260px] border-[var(--color-border)] ${
card.reverse ? 'order-2 md:order-2 md:border-l' : 'order-1 md:border-r'
}`}
>
<img src={card.background} alt="" className="h-full w-full object-cover" decoding="async" loading="lazy" />
<div className="absolute inset-4 overflow-hidden rounded-[10px] border border-[var(--color-border)] bg-[var(--color-secondary)] shadow-[0_20px_50px_var(--shadow-medium)]">
<SyntaxCodeBlock compact />
</div>
</div>
<div
className={`flex flex-col items-start justify-center px-6 py-7 md:px-10 md:py-11 ${
card.reverse ? 'order-1 md:order-1' : 'order-2'
}`}
>
<h3 className="text-[30px] font-medium leading-[1.05] tracking-[-0.03em] text-[var(--color-foreground)] md:text-[36px]">{card.title}</h3>
<p className="mt-4 max-w-[510px] text-[16px] leading-[1.3] tracking-[0em] text-[var(--color-muted-foreground)]">{card.body}</p>
<button
type="button"
className="mt-6 rounded-[10px] bg-[var(--color-primary)] px-4 py-[10px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
{card.cta}
</button>
</div>
</article>
))}
</div>
</section>
)
}
Use Cases: One tool. Every use case.
Component File: src/sections/UseCasesSection.tsx
import { useCasePanels, useCaseTabs, imageAssets } from '../data/siteData'
import { SectionHeading } from '../components/SectionHeading'
import { SyntaxCodeBlock } from '../components/SyntaxCodeBlock'
export function UseCasesSection() {
return (
<section id="use-cases" className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Use cases" leading="One tool." muted="Every use case." />
<div className="mt-6 hidden rounded-[14px] border border-[var(--color-border)] bg-[var(--color-card)] p-1 md:flex md:w-fit">
{useCaseTabs.map((tab, tabIndex) => (
<button
key={tab}
type="button"
className={`rounded-[10px] px-5 py-[9px] text-[16px] font-medium tracking-[0em] ${
tabIndex === 0 ? 'bg-[var(--color-secondary)] text-[var(--color-foreground)]' : 'text-[var(--color-muted-foreground)]'
}`}
>
{tab}
</button>
))}
</div>
<article className="mt-6 hidden overflow-hidden rounded-[14px] border border-[var(--color-border)] bg-[var(--color-card)] md:block">
<div className="relative h-[630px]">
<img src={imageAssets.cardBackgroundD} alt="" className="h-full w-full object-cover" loading="lazy" decoding="async" />
<div className="absolute inset-x-[15%] top-[10%] bottom-[11%] overflow-hidden rounded-[10px] border border-[var(--color-border)] bg-[var(--color-secondary)] shadow-[0_30px_70px_var(--shadow-strong)]">
<SyntaxCodeBlock />
</div>
</div>
<div className="flex items-end justify-between gap-8 px-8 py-7">
<div>
<p className="text-[14px] font-medium tracking-[0em] text-[var(--color-muted-foreground)]">{useCasePanels[0].subtitle}</p>
<p className="mt-2 max-w-[840px] text-[30px] leading-[1.12] tracking-[-0.03em] text-[var(--color-foreground)] md:text-[36px]">{useCasePanels[0].text}</p>
</div>
<button
type="button"
className="mb-1 rounded-[10px] bg-[var(--color-primary)] px-4 py-[10px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
{useCasePanels[0].button}
</button>
</div>
</article>
<div className="md:hidden">
<div className="mt-4 flex gap-3 overflow-x-auto pb-3 [scrollbar-width:none]">
{useCasePanels.map((panel) => (
<article key={panel.subtitle} className="w-[92%] shrink-0 snap-start rounded-[12px] border border-[var(--color-border)] bg-[var(--color-card)] p-3">
<div className="overflow-hidden rounded-[10px] border border-[var(--color-border)]">
<img src={imageAssets.useCaseEditor} alt="" className="h-[190px] w-full object-cover" loading="lazy" decoding="async" />
</div>
<p className="mt-4 text-[13px] font-medium text-[var(--color-muted-foreground)]">{panel.subtitle}</p>
<p className="mt-1 text-[16px] font-medium leading-[1.28] tracking-[0em] text-[var(--color-foreground)]">{panel.text}</p>
<button
type="button"
className="mt-4 rounded-[10px] bg-[var(--color-primary)] px-4 py-[9px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
{panel.button}
</button>
</article>
))}
</div>
<div className="mt-2 flex items-center justify-center gap-2">
{[0, 1, 2, 3].map((dot) => (
<span key={dot} className={`h-2 w-2 rounded-full ${dot === 0 ? 'bg-[var(--color-primary)]' : 'bg-[var(--color-muted-foreground)]'}`} />
))}
</div>
</div>
</section>
)
}
Benefits: Ship faster. Code better.
Component File: src/sections/BenefitsSection.tsx
import { SectionHeading } from '../components/SectionHeading'
import { UiIcon } from '../components/UiIcon'
import { benefits } from '../data/siteData'
export function BenefitsSection() {
return (
<section className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Benefits" leading="Ship faster." muted="Code better." />
<div className="mt-8 grid gap-2.5 md:grid-cols-3">
{benefits.map((benefit) => (
<article key={benefit.title} className="rounded-[12px] border border-[var(--color-border)] bg-[var(--color-card)] p-5 md:p-6">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-[var(--color-secondary)] text-[var(--color-foreground)]">
<UiIcon kind={benefit.icon} />
</div>
<h3 className="mt-4 text-[24px] font-medium leading-[1.15] tracking-[-0.02em] text-[var(--color-foreground)]">{benefit.title}</h3>
<p className="mt-2 text-[16px] leading-[1.3] tracking-[0em] text-[var(--color-muted-foreground)]">{benefit.text}</p>
</article>
))}
</div>
</section>
)
}
Testimonials: Loved by developers. Built for productivity.
Component File: src/sections/TestimonialsSection.tsx
import { SectionHeading } from '../components/SectionHeading'
import { testimonials } from '../data/siteData'
export function TestimonialsSection() {
return (
<section id="testimonials" className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Testimonials" leading="Loved by developers." muted="Built for productivity." />
<div className="mt-8 grid gap-3 md:grid-cols-3 md:gap-4">
{testimonials.map((testimonial, index) => (
<article
key={`${testimonial.quote.slice(0, 24)}-${index}`}
className={`rounded-[12px] border border-[var(--color-border)] bg-[var(--color-card)] ${testimonial.compact ? 'p-4' : 'p-5'}`}
>
<p className={`tracking-[0em] text-[var(--color-foreground)] ${testimonial.compact ? 'text-[14px] leading-[1.3]' : 'text-[16px] leading-[1.35]'}`}>
{testimonial.quote}
</p>
{testimonial.name ? (
<div className="mt-4 flex items-center gap-3 border-t border-[var(--color-border)] pt-3">
<img
src={testimonial.avatar}
alt={testimonial.name}
className="h-10 w-10 rounded-full object-cover"
loading="lazy"
decoding="async"
/>
<div>
<p className="text-[16px] font-medium tracking-[0em] text-[var(--color-foreground)]">{testimonial.name}</p>
<p className="text-[14px] tracking-[0em] text-[var(--color-muted-foreground)]">{testimonial.role}</p>
</div>
</div>
) : null}
</article>
))}
</div>
</section>
)
}
Pricing: Start free. Scale as you grow.
Component File: src/sections/PricingSection.tsx
import { pricingCards } from '../data/siteData'
import { SectionHeading } from '../components/SectionHeading'
export function PricingSection() {
return (
<section id="pricing" className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Pricing" leading="Start free." muted="Scale as you grow." />
<div className="mt-6 flex items-center gap-2 rounded-[13px] bg-[var(--color-card)] p-1.5 text-[16px] font-medium tracking-[0em] text-[var(--color-muted-foreground)] md:w-fit">
<button type="button" className="rounded-[10px] bg-[var(--color-secondary)] px-3 py-2 text-[var(--color-foreground)]">
Monthly
</button>
<button type="button" className="rounded-[10px] px-3 py-2">
Yearly
</button>
<span className="px-2 text-[var(--color-muted-foreground)]">Save 20%</span>
</div>
<div className="mt-6 grid gap-3 md:grid-cols-3 md:gap-4">
{pricingCards.map((card) => (
<article
key={card.name}
className={`rounded-[12px] border p-5 md:p-6 ${
card.highlight ? 'border-[var(--color-border)] bg-[var(--color-card)]' : 'border-[var(--color-border)] bg-[var(--color-card)]'
}`}
>
<div className="flex items-center justify-between">
<h3 className="text-[30px] font-medium tracking-[-0.03em] text-[var(--color-foreground)] md:text-[32px]">{card.name}</h3>
{card.badge ? (
<span className="rounded-full border border-[var(--color-border)] px-2.5 py-1 text-[13px] font-medium text-[var(--color-muted-foreground)]">{card.badge}</span>
) : null}
</div>
<p className="mt-3 flex items-end gap-1 text-[48px] font-medium leading-none tracking-[-0.04em] text-[var(--color-foreground)] md:text-[56px]">
{card.price}
{card.suffix ? <span className="mb-[6px] text-[16px] text-[var(--color-muted-foreground)]">{card.suffix}</span> : null}
</p>
<p className="mt-4 min-h-[74px] text-[16px] leading-[1.3] tracking-[0em] text-[var(--color-muted-foreground)]">{card.description}</p>
<button
type="button"
className={`mt-5 rounded-[10px] px-4 py-[10px] text-[16px] font-medium tracking-[0em] ${
card.highlight ? 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)]' : 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)]'
}`}
>
{card.cta}
</button>
<div className="mt-6 border-t border-[var(--color-border)] pt-5">
<p className="mb-3 text-center text-[14px] font-medium text-[var(--color-muted-foreground)]">Features</p>
<ul className="space-y-2.5">
{card.features.map((feature) => (
<li key={feature} className="flex items-start gap-2.5 text-[16px] leading-[1.35] tracking-[0em] text-[var(--color-muted-foreground)]">
<span className="mt-[0.55em] inline-block h-2 w-2 rounded-full border border-[var(--color-border)]" />
<span>{feature}</span>
</li>
))}
</ul>
</div>
</article>
))}
</div>
</section>
)
}
Three Ways to Code: Start coding your way.
Component File: src/sections/WaysToCodeSection.tsx
import { waysToCode, imageAssets } from '../data/siteData'
import { SectionHeading } from '../components/SectionHeading'
export function WaysToCodeSection() {
return (
<section className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<SectionHeading eyebrow="Three ways to code" leading="Start coding your way." muted="Choose what works best." />
<div className="mt-8 grid gap-3 md:grid-cols-3 md:gap-4">
{waysToCode.map((item) => (
<article key={item.title} className="rounded-[12px] border border-[var(--color-border)] bg-[var(--color-card)] p-3 md:p-4">
<div className="overflow-hidden rounded-[10px] border border-[var(--color-border)]">
<img src={item.image} alt={item.title} className="h-[255px] w-full object-cover md:h-[295px]" loading="lazy" decoding="async" />
</div>
<h3 className="mt-4 text-[30px] font-medium leading-[1.08] tracking-[-0.03em] text-[var(--color-foreground)] md:text-[32px]">{item.title}</h3>
<p className="mt-1 min-h-[72px] text-[16px] leading-[1.3] tracking-[0em] text-[var(--color-muted-foreground)]">{item.description}</p>
<button
type="button"
className="mt-4 inline-flex items-center gap-2 rounded-[10px] bg-[var(--color-primary)] px-4 py-[10px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
{item.action}
{item.external || !item.copy ? (
<img src={imageAssets.arrowRight} alt="" className="h-3 w-3" />
) : (
<span className="inline-flex h-5 w-5 items-center justify-center rounded border border-[var(--color-border)] text-[13px]">⎘</span>
)}
</button>
</article>
))}
</div>
</section>
)
}
FAQ: Questions? We’ve got answers.
Component File: src/sections/FaqSection.tsx
import { SectionHeading } from '../components/SectionHeading'
import { faqQuestions } from '../data/siteData'
export function FaqSection() {
return (
<section id="faq" className="mx-auto mt-20 w-full max-w-[1136px] px-4 md:mt-28 md:px-7">
<div className="grid gap-6 md:grid-cols-[1.05fr_1fr] md:gap-8">
<SectionHeading eyebrow="FAQ" leading="Questions?" muted="We've got answers." />
<div className="space-y-3">
{faqQuestions.map((question) => (
<button
key={question}
type="button"
className="flex w-full items-center justify-between rounded-[10px] border border-[var(--color-border)] bg-[var(--color-card)] px-4 py-[13px] text-left text-[16px] font-medium tracking-[0em] text-[var(--color-foreground)]"
>
<span>{question}</span>
<span className="text-[20px] leading-none text-[var(--color-muted-foreground)]">+</span>
</button>
))}
</div>
</div>
</section>
)
}
CTA: Start coding with precision today
Component File: src/sections/CtaSection.tsx
import { imageAssets } from '../data/siteData'
export function CtaSection() {
return (
<section id="cta" className="mx-auto mt-16 w-full max-w-[1136px] px-4 md:mt-24 md:px-7">
<article className="overflow-hidden rounded-[14px] border border-[var(--color-border)] bg-[var(--color-card)] md:grid md:grid-cols-[1fr_1.08fr]">
<div className="order-2 px-6 pb-7 pt-5 md:order-1 md:flex md:flex-col md:justify-center md:px-10 md:py-10">
<h2 className="max-w-[430px] text-[40px] font-medium leading-[0.98] tracking-[-0.04em] text-[var(--color-foreground)] md:text-[56px]">
Start coding with precision today
</h2>
<p className="mt-4 max-w-[460px] text-[16px] leading-[1.35] tracking-[0em] text-[var(--color-muted-foreground)]">
Free forever. Install in seconds.
<br />
Start building immediately.
</p>
<button
type="button"
className="mt-6 w-fit rounded-[10px] bg-[var(--color-primary)] px-4 py-[10px] text-[16px] font-medium tracking-[0em] text-[var(--color-primary-foreground)]"
>
Download for macOS
</button>
</div>
<div className="order-1 p-3 md:order-2 md:p-4">
<div className="overflow-hidden rounded-[10px] border border-[var(--color-border)] bg-[var(--color-secondary)]">
<img
src={imageAssets.editorSidebar}
alt="Cactus editor"
className="h-[238px] w-full object-cover md:h-[378px]"
loading="lazy"
decoding="async"
/>
</div>
</div>
</article>
</section>
)
}
Footer
Component File: src/sections/FooterSection.tsx
import { BrandMark } from '../components/BrandMark'
import { navLinks } from '../data/siteData'
function SocialButton({ label }: { label: string }) {
return (
<a
href="/"
className="inline-flex h-9 w-9 items-center justify-center rounded border border-[var(--color-border)] bg-[var(--color-secondary)]/45 text-[16px] text-[var(--color-foreground)]"
aria-label={label}
>
{label}
</a>
)
}
export function FooterSection() {
return (
<footer className="mt-10 bg-[var(--color-card)]">
<div className="mx-auto grid w-full max-w-[1136px] gap-10 px-4 py-12 md:grid-cols-[1fr_auto] md:px-7 md:py-14">
<div className="order-2 space-y-6 md:order-1">
<div>
<a href="#hero" className="inline-flex items-center gap-2 text-[var(--color-foreground)]">
<BrandMark className="h-[14px] w-[17px]" />
<span className="text-[20px] font-medium tracking-[-0.02em]">Cactus</span>
</a>
<p className="mt-4 max-w-[420px] text-[14px] leading-[1.35] tracking-[0em] text-[var(--color-muted-foreground)]">
The AI code editor built for precision. Write less, build more, ship faster.
</p>
<div className="mt-5 flex gap-2.5">
<SocialButton label="X" />
<SocialButton label="◈" />
<SocialButton label="in" />
</div>
</div>
</div>
<div className="order-1 md:order-2">
<p className="text-[14px] font-medium tracking-[0em] text-[var(--color-foreground)]">Navigation</p>
<div className="mt-4 space-y-3">
{navLinks.map((link) => (
<a key={link.label} href={link.href} className="block text-[14px] tracking-[0em] text-[var(--color-muted-foreground)]">
{link.label}
</a>
))}
</div>
</div>
</div>
</footer>
)
}