Refine Vertex landing page design and animations

This commit is contained in:
Rami Bitar
2026-09-15 00:07:54 -04:00
parent e2e4474eb6
commit ad7d003ed4
26 changed files with 480 additions and 260 deletions
+170 -232
View File
@@ -1,34 +1,25 @@
"use client"
import Image from "next/image"
import { useState } from "react"
import {
Activity,
ArrowRight,
Check,
ChevronDown,
ChevronRight,
CircleCheck,
Code2,
Gauge,
Globe2,
LockKeyhole,
Network,
Route,
ShieldCheck,
Sparkles,
Waypoints,
Workflow,
Zap,
} from "lucide-react"
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"
import { ThemeToggle } from "@/components/theme-toggle"
import { UsageChart } from "@/components/usage-chart"
import { AnimatedList } from "@/components/ui/animated-list"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/components/ui/chart"
import { FlickeringGrid } from "@/components/ui/flickering-grid"
import { Globe } from "@/components/ui/globe"
import { Marquee } from "@/components/ui/marquee"
@@ -41,15 +32,27 @@ import {
} from "@/components/ui/terminal"
import { cn } from "@/lib/utils"
const providers = [
{ name: "OpenAI", mark: "OA" },
{ name: "Anthropic", mark: "A" },
{ name: "Gemini", mark: "G" },
{ name: "Meta", mark: "M" },
{ name: "Mistral", mark: "MI" },
{ name: "xAI", mark: "x" },
{ name: "Cohere", mark: "C" },
{ name: "DeepSeek", mark: "DS" },
// Original SVG artwork sourced from https://svgl.app.
const integrations = [
{ name: "Supabase", src: "/logos/integrations/supabase.svg" },
{ name: "Notion", src: "/logos/integrations/notion.svg" },
{ name: "Figma", src: "/logos/integrations/figma.svg" },
{ name: "Dropbox", src: "/logos/integrations/dropbox.svg" },
{ name: "Gmail", src: "/logos/integrations/gmail.svg" },
{ name: "Slack", src: "/logos/integrations/slack.svg" },
{ name: "Google Drive", src: "/logos/integrations/google-drive.svg" },
{ name: "GitHub", src: "/logos/integrations/github.svg" },
]
const customerLogos = [
{ name: "OpenAI", src: "/logos/openai.svg", width: 110, height: 31 },
{ name: "Retool", src: "/logos/retool.svg", width: 113, height: 25 },
{ name: "Stripe", src: "/logos/stripe.svg", width: 73, height: 31 },
{ name: "Wise", src: "/logos/wise.svg", width: 96, height: 23 },
{ name: "Tailwind CSS", src: "/logos/tailwindcss.svg", width: 262, height: 33, className: "w-full max-w-[158px] brightness-0" },
{ name: "Medium", src: "/logos/medium.svg", width: 132, height: 21 },
{ name: "Next.js", src: "/logos/nextjs.svg", width: 394, height: 80 },
{ name: "Linear", src: "/logos/linear.svg", width: 122, height: 31 },
]
const routingEvents = [
@@ -57,7 +60,7 @@ const routingEvents = [
icon: <Route className="size-4" />,
title: "Routed to Claude Sonnet",
meta: "342ms · 8.2k tokens",
accent: "bg-violet-500/15 text-violet-500",
accent: "bg-blue-600/15 text-blue-600 dark:text-blue-400",
},
{
icon: <Zap className="size-4" />,
@@ -85,21 +88,6 @@ const routingEvents = [
},
]
const usageData = [
{ time: "08:00", cost: 28, latency: 54 },
{ time: "10:00", cost: 35, latency: 48 },
{ time: "12:00", cost: 31, latency: 64 },
{ time: "14:00", cost: 48, latency: 57 },
{ time: "16:00", cost: 41, latency: 72 },
{ time: "18:00", cost: 57, latency: 66 },
{ time: "20:00", cost: 52, latency: 82 },
]
const chartConfig = {
cost: { label: "Requests", color: "#2563eb" },
latency: { label: "Latency", color: "#8b5cf6" },
} satisfies ChartConfig
const reviews = [
{
initials: "MK",
@@ -171,12 +159,23 @@ const globeConfig = {
],
}
function VertexMark({ className }: { className?: string }) {
return (
<Image
src="/logo.svg"
alt=""
width={24}
height={24}
className={cn("brightness-0 dark:invert", className)}
aria-hidden="true"
/>
)
}
function Brand({ compact = false }: { compact?: boolean }) {
return (
<span className="inline-flex items-center gap-2.5">
<span className="relative inline-flex size-8 items-center justify-center overflow-hidden rounded-[10px] bg-blue-600 text-white shadow-[0_0_28px_rgba(37,99,235,.32)]">
<Waypoints className="size-[18px]" aria-hidden="true" />
</span>
<VertexMark className="size-8" />
{!compact && (
<span className="text-[17px] font-semibold tracking-[-0.03em]">Vertex</span>
)}
@@ -184,17 +183,19 @@ function Brand({ compact = false }: { compact?: boolean }) {
)
}
function ProviderMark({ mark, name, small = false }: { mark: string; name: string; small?: boolean }) {
function IntegrationMark({ src, name }: { src: string; name: string }) {
return (
<span
aria-label={name}
className={cn(
"inline-flex items-center justify-center rounded-full border border-border/80 bg-background font-mono font-semibold shadow-sm",
small ? "size-9 text-[10px]" : "size-11 text-xs"
)}
className="inline-flex size-full items-center justify-center rounded-full border border-black/10 bg-white p-2 shadow-sm"
title={name}
>
{mark}
<Image
src={src}
alt={`${name} logo`}
width={28}
height={28}
className="size-full object-contain"
/>
</span>
)
}
@@ -203,13 +204,15 @@ function SectionHeading({
eyebrow,
title,
description,
className,
}: {
eyebrow: string
title: string
description: string
className?: string
}) {
return (
<div className="border-b px-6 py-16 text-center sm:px-10 sm:py-20">
<div className={cn("border-b px-6 py-16 text-center sm:px-10 sm:py-20", className)}>
<div className="mx-auto max-w-2xl">
<p className="mb-4 font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-blue-600 dark:text-blue-400">
{eyebrow}
@@ -226,19 +229,14 @@ function SectionHeading({
}
function FeatureCopy({
icon: Icon,
title,
description,
}: {
icon: React.ComponentType<{ className?: string }>
title: string
description: string
}) {
return (
<div className="relative z-10 border-t bg-background/85 p-6 backdrop-blur-sm sm:p-7">
<div className="mb-4 flex size-9 items-center justify-center rounded-lg border bg-muted/50 text-blue-600 dark:text-blue-400">
<Icon className="size-4" />
</div>
<div className="relative z-10 bg-background p-6 sm:p-7">
<h3 className="text-lg font-medium tracking-[-0.025em]">{title}</h3>
<p className="mt-2 max-w-md text-sm leading-6 text-muted-foreground">{description}</p>
</div>
@@ -269,56 +267,57 @@ export function VertexLandingPage() {
return (
<div className="min-h-screen bg-background text-foreground selection:bg-blue-600 selection:text-white">
<header className="sticky top-0 z-50 mx-auto max-w-[1280px] border-x border-b bg-background/82 backdrop-blur-xl supports-[backdrop-filter]:bg-background/72">
<div className="flex h-16 items-center justify-between px-5 sm:px-8">
<header className="sticky top-0 z-50 w-full border-b bg-background/86 backdrop-blur-xl supports-[backdrop-filter]:bg-background/74">
<div className="mx-auto flex h-16 max-w-[1280px] items-center justify-between px-5 sm:px-8">
<a href="#top" aria-label="Vertex home">
<Brand />
</a>
<nav aria-label="Main navigation" className="hidden items-center gap-1 rounded-full border bg-muted/40 p-1 md:flex">
<nav aria-label="Main navigation" className="hidden items-center gap-8 md:flex lg:gap-10">
{[
["Products", "#features"],
["Models", "#models"],
["Features", "#features"],
["Developers", "#developers"],
["Pricing", "#pricing"],
["Docs", "#developers"],
].map(([label, href]) => (
<a
key={label}
href={href}
className="rounded-full px-4 py-1.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-background hover:text-foreground"
className="inline-flex items-center gap-1 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
>
{label}
{label === "Products" && <ChevronDown className="size-3" />}
</a>
))}
</nav>
<div className="flex items-center gap-2">
<ThemeToggle />
<a
href="#pricing"
className="hidden h-9 items-center gap-1.5 rounded-full bg-blue-600 px-4 text-xs font-medium text-white shadow-[0_6px_24px_rgba(37,99,235,.25)] transition hover:bg-blue-500 sm:inline-flex"
className="hidden h-9 items-center gap-1.5 rounded-sm bg-blue-600 px-4 text-xs font-medium text-white shadow-[0_6px_24px_rgba(23,61,166,.28)] transition hover:bg-blue-500 sm:inline-flex"
>
Open dashboard <ChevronRight className="size-3.5" />
Get started <ChevronRight className="size-3.5" />
</a>
<ThemeToggle />
</div>
</div>
</header>
<main id="top" className="mx-auto max-w-[1280px] border-x">
<section className="vertex-grid relative overflow-hidden border-b px-6 pb-14 pt-24 text-center sm:px-10 sm:pb-20 sm:pt-28 lg:pt-32">
<div className="pointer-events-none absolute inset-x-0 top-0 h-56 bg-gradient-to-b from-blue-600/[0.07] to-transparent" />
<section className="hero-gradient relative border-b px-6 pb-14 pt-24 text-center sm:px-10 sm:pb-20 sm:pt-28 lg:pt-32">
<span className="frame-cross left-0 top-0" aria-hidden="true" />
<span className="frame-cross right-0 top-0" aria-hidden="true" />
<span className="frame-cross bottom-0 left-0" aria-hidden="true" />
<span className="frame-cross bottom-0 right-0" aria-hidden="true" />
<div className="relative z-10 mx-auto max-w-4xl">
<a
href="#features"
className="mb-7 inline-flex items-center gap-2 rounded-full border bg-background/75 px-3.5 py-1.5 text-xs text-muted-foreground shadow-sm backdrop-blur"
className="mb-7 inline-flex items-center justify-center rounded-full border border-blue-600/15 bg-gradient-to-br from-white/80 via-blue-600/10 to-blue-600/20 px-5 py-2 text-xs font-medium text-foreground shadow-[inset_0_1px_0_rgba(255,255,255,.6),0_4px_20px_rgba(23,61,166,.1)] backdrop-blur-xl transition-colors hover:border-blue-600/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background dark:border-white/15 dark:from-white/10 dark:via-blue-600/15 dark:to-blue-600/30 dark:shadow-[inset_0_1px_0_rgba(255,255,255,.12),0_4px_20px_rgba(23,61,166,.15)] dark:hover:border-white/30"
>
<Sparkles className="size-3.5 text-blue-600 dark:text-blue-400" />
The unified AI gateway
<ArrowRight className="size-3.5" />
</a>
<h1 className="text-balance text-[44px] font-medium leading-[0.98] tracking-[-0.06em] sm:text-6xl md:text-7xl lg:text-[82px]">
One API for every
<span className="block bg-gradient-to-r from-blue-600 via-blue-500 to-violet-500 bg-clip-text text-transparent">
AI model.
</span>
<span className="block">AI model.</span>
</h1>
<p className="mx-auto mt-6 max-w-2xl text-pretty text-base leading-7 text-muted-foreground sm:text-lg">
Route, optimize, and observe every model request through one OpenAI-compatible endpoint built for production.
@@ -326,97 +325,65 @@ export function VertexLandingPage() {
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
<a
href="#pricing"
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-full bg-blue-600 px-6 text-sm font-medium text-white shadow-[0_10px_32px_rgba(37,99,235,.28)] transition hover:-translate-y-0.5 hover:bg-blue-500 sm:w-auto"
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-sm bg-blue-600 px-6 text-sm font-medium text-white shadow-[0_10px_32px_rgba(23,61,166,.32)] transition hover:-translate-y-0.5 hover:bg-blue-500 sm:w-auto"
>
Get your API key <ArrowRight className="size-4" />
</a>
<a
href="#models"
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-full border bg-background/70 px-6 text-sm font-medium transition hover:bg-muted sm:w-auto"
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-sm border bg-background/70 px-6 text-sm font-medium transition hover:bg-muted sm:w-auto"
>
Explore models
</a>
</div>
</div>
<div className="relative z-10 mx-auto mt-16 max-w-4xl overflow-hidden rounded-2xl border bg-background/80 p-4 shadow-[0_32px_90px_rgba(0,0,0,.08)] backdrop-blur sm:p-6 dark:shadow-[0_32px_90px_rgba(0,0,0,.35)]">
<div className="absolute inset-0 bg-[linear-gradient(to_right,var(--border)_1px,transparent_1px),linear-gradient(to_bottom,var(--border)_1px,transparent_1px)] bg-[size:32px_32px] opacity-35" />
<div className="relative grid items-center gap-4 sm:grid-cols-[1fr_auto_1fr_auto_1fr]">
<div className="rounded-xl border bg-background p-4 text-left shadow-sm">
<div className="flex items-center gap-2 text-xs font-medium">
<Code2 className="size-4 text-blue-600" /> Your application
</div>
<code className="mt-3 block truncate rounded-md bg-muted px-2.5 py-2 font-mono text-[10px] text-muted-foreground sm:text-xs">
POST /v1/chat/completions
</code>
</div>
<ArrowRight className="mx-auto hidden size-4 text-muted-foreground sm:block" />
<div className="relative rounded-xl border border-blue-500/30 bg-blue-600 p-4 text-left text-white shadow-[0_10px_40px_rgba(37,99,235,.25)]">
<div className="flex items-center gap-2 text-xs font-medium">
<Waypoints className="size-4" /> Vertex Gateway
</div>
<div className="mt-3 flex items-center gap-2 font-mono text-[10px] text-blue-100 sm:text-xs">
<span className="size-1.5 animate-pulse rounded-full bg-emerald-300" /> Routing by latency
</div>
</div>
<ArrowRight className="mx-auto hidden size-4 text-muted-foreground sm:block" />
<div className="rounded-xl border bg-background p-4 text-left shadow-sm">
<div className="flex items-center gap-2 text-xs font-medium">
<Network className="size-4 text-violet-500" /> Best available model
</div>
<div className="mt-3 flex -space-x-2">
{providers.slice(0, 4).map((provider) => (
<ProviderMark key={provider.name} {...provider} small />
))}
</div>
</div>
</div>
</div>
</section>
<section id="models" className="border-b">
<p className="border-b py-7 text-center text-sm text-muted-foreground">
Every leading model, one gateway
</p>
<div className="relative flex min-h-[260px] items-center justify-center overflow-hidden border-b px-6 py-20 text-center sm:min-h-[340px] sm:py-28">
<FlickeringGrid
className="absolute inset-0 [mask-image:radial-gradient(520px_circle_at_center,white,transparent)]"
squareSize={3}
gridGap={8}
color="#173DA6"
maxOpacity={0.34}
flickerChance={0.08}
/>
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_12%,var(--background)_78%)] opacity-70" />
<h2 className="relative z-10 max-w-3xl text-balance text-4xl font-medium leading-[1.02] tracking-[-0.05em] sm:text-5xl md:text-6xl">
Every leading model,
<span className="block text-blue-600 dark:text-blue-400">one gateway.</span>
</h2>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4">
{providers.map((provider) => (
{customerLogos.map((logo) => (
<div
key={provider.name}
className="group flex h-28 items-center justify-center gap-3 border-r border-b last:border-r-0 even:border-r-0 sm:even:border-r sm:[&:nth-child(4n)]:border-r-0 [&:nth-last-child(-n+2)]:border-b-0 sm:[&:nth-last-child(-n+4)]:border-b-0"
key={logo.name}
className="group flex h-32 items-center justify-center border-r border-b px-6 last:border-r-0 even:border-r-0 sm:h-36 sm:even:border-r sm:[&:nth-child(4n)]:border-r-0 [&:nth-last-child(-n+2)]:border-b-0 sm:[&:nth-last-child(-n+4)]:border-b-0"
>
<ProviderMark {...provider} />
<span className="text-sm font-medium tracking-tight text-muted-foreground transition-colors group-hover:text-foreground sm:text-base">
{provider.name}
</span>
<Image
src={logo.src}
alt={`${logo.name} logo`}
width={logo.width}
height={logo.height}
className={cn("h-auto max-h-8 w-auto max-w-[132px] opacity-75 transition-all duration-200 group-hover:scale-[1.03] group-hover:opacity-100 dark:invert", logo.className)}
/>
</div>
))}
</div>
</section>
<section className="grid border-b sm:grid-cols-[56px_1fr_56px]">
<div className="hatched hidden border-r sm:block" aria-hidden="true" />
<div className="px-6 py-16 text-center sm:px-12 sm:py-20">
<h2 className="text-balance text-3xl font-medium tracking-[-0.045em] sm:text-4xl">
Switch models without rewriting your stack.
</h2>
<p className="mx-auto mt-4 max-w-2xl text-pretty text-sm leading-6 text-muted-foreground sm:text-base">
One stable API gives your team the freedom to change providers, enforce policies, and optimize every request behind the scenes.
</p>
</div>
<div className="hatched hidden border-l sm:block" aria-hidden="true" />
</section>
<section id="features" className="border-b">
<SectionHeading
eyebrow="The gateway layer"
title="Infrastructure for model choice"
description="Everything you need to move quickly across models without giving up reliability, control, or visibility."
/>
<section id="features" className="border-b px-4 py-4 sm:px-8 sm:py-8">
<div className="border-x border-t">
<SectionHeading
eyebrow="The gateway layer"
title="Infrastructure for model choice"
description="Everything you need to move quickly across models without giving up reliability, control, or visibility."
/>
<div className="grid lg:grid-cols-12">
<div className="grid lg:grid-cols-12">
<article className="flex min-h-[520px] flex-col border-b lg:col-span-7 lg:border-r">
<div className="flex flex-1 items-center justify-center overflow-hidden bg-muted/20 p-5 sm:p-10">
<div className="flex flex-1 items-center justify-center overflow-hidden bg-background p-5 sm:p-10">
<Terminal className="max-w-xl bg-background shadow-[0_24px_70px_rgba(0,0,0,.12)]" sequence>
<TypingAnimation duration={22}>
{"> curl https://api.vertex.ai/v1/chat/completions \\"}
@@ -427,7 +394,7 @@ export function VertexLandingPage() {
<AnimatedSpan className="text-blue-500">
→ evaluating 14 available models
</AnimatedSpan>
<AnimatedSpan className="text-violet-500">
<AnimatedSpan className="text-blue-600 dark:text-blue-400">
→ route selected: anthropic/claude-sonnet
</AnimatedSpan>
<AnimatedSpan className="text-emerald-500">
@@ -439,39 +406,38 @@ export function VertexLandingPage() {
</Terminal>
</div>
<FeatureCopy
icon={Code2}
title="One compatible endpoint"
description="Use the OpenAI SDK you already know. Change one base URL and reach every supported model."
/>
</article>
<article className="flex min-h-[520px] flex-col border-b lg:col-span-5">
<div className="relative flex flex-1 items-center justify-center overflow-hidden bg-muted/20">
<div className="absolute left-1/2 top-1/2 z-10 flex size-20 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-2xl bg-blue-600 text-white shadow-[0_12px_50px_rgba(37,99,235,.4)]">
<Waypoints className="size-8" />
</div>
<OrbitingCircles radius={84} iconSize={38} duration={16}>
{providers.slice(0, 4).map((provider) => (
<ProviderMark key={provider.name} {...provider} small />
<div className="relative flex flex-1 items-center justify-center overflow-hidden bg-background">
<VertexMark className="absolute left-1/2 top-1/2 z-10 size-12 -translate-x-1/2 -translate-y-1/2" />
<OrbitingCircles className="z-10" radius={84} iconSize={44} duration={16}>
{integrations.slice(0, 4).map((integration) => (
<IntegrationMark key={integration.name} {...integration} />
))}
</OrbitingCircles>
<OrbitingCircles radius={150} iconSize={38} duration={24} reverse>
{providers.slice(4).map((provider) => (
<ProviderMark key={provider.name} {...provider} small />
<OrbitingCircles className="z-10" radius={150} iconSize={44} duration={24} reverse>
{integrations.slice(4).map((integration) => (
<IntegrationMark key={integration.name} {...integration} />
))}
</OrbitingCircles>
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_15%,var(--background)_74%)] opacity-55" />
<div
aria-hidden="true"
className="pointer-events-none absolute inset-x-0 bottom-0 z-20 h-32 bg-gradient-to-t from-background via-background/80 to-transparent"
/>
</div>
<FeatureCopy
icon={Route}
title="Intelligent model routing"
description="Route by price, latency, capability, or your own policy—with automatic provider fallbacks."
title="Seamless integrations"
description="Connect your favorite tools and bring AI into the workflows your team already uses."
/>
</article>
<article className="flex min-h-[430px] flex-col border-b lg:col-span-4 lg:border-b-0 lg:border-r">
<div className="relative h-[270px] flex-1 overflow-hidden bg-muted/20 p-4">
<AnimatedList delay={1150} className="gap-2">
<div className="relative h-[360px] shrink-0 overflow-hidden bg-background">
<AnimatedList delay={1150} className="absolute inset-x-4 top-4 gap-2">
{routingEvents.map((event) => (
<div key={event.title} className="mx-auto flex w-full max-w-sm items-center gap-3 rounded-xl border bg-background/95 p-3 shadow-sm">
<span className={cn("flex size-9 shrink-0 items-center justify-center rounded-lg", event.accent)}>
@@ -487,57 +453,33 @@ export function VertexLandingPage() {
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-background to-transparent" />
</div>
<FeatureCopy
icon={ShieldCheck}
title="Automatic failover"
description="Keep requests moving through rate limits, outages, and changing provider availability."
/>
</article>
<article className="flex min-h-[430px] flex-col border-b lg:col-span-4 lg:border-b-0 lg:border-r">
<div className="flex h-[270px] flex-1 items-center bg-muted/20 px-4 pt-5">
<ChartContainer config={chartConfig} className="h-[220px] w-full">
<AreaChart data={usageData} margin={{ left: -24, right: 8, top: 12, bottom: 0 }}>
<defs>
<linearGradient id="fillCost" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-cost)" stopOpacity={0.45} />
<stop offset="95%" stopColor="var(--color-cost)" stopOpacity={0} />
</linearGradient>
<linearGradient id="fillLatency" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-latency)" stopOpacity={0.26} />
<stop offset="95%" stopColor="var(--color-latency)" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid vertical={false} strokeDasharray="3 3" />
<XAxis dataKey="time" axisLine={false} tickLine={false} tickMargin={8} />
<YAxis hide domain={[0, 100]} />
<ChartTooltip content={<ChartTooltipContent indicator="line" />} />
<Area dataKey="latency" type="monotone" fill="url(#fillLatency)" stroke="var(--color-latency)" strokeWidth={1.5} />
<Area dataKey="cost" type="monotone" fill="url(#fillCost)" stroke="var(--color-cost)" strokeWidth={2} />
</AreaChart>
</ChartContainer>
<div className="relative h-[360px] shrink-0 overflow-hidden bg-background">
<UsageChart />
</div>
<FeatureCopy
icon={Gauge}
title="Unified cost and latency"
description="Compare providers, trace every request, and control spend from one clear operating view."
/>
</article>
<article className="flex min-h-[430px] flex-col lg:col-span-4">
<div className="relative h-[270px] flex-1 overflow-hidden bg-muted/20">
<div className="relative h-[360px] shrink-0 overflow-hidden bg-background">
<Globe className="top-6 max-w-[360px]" config={globeConfig} />
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_105%,rgba(37,99,235,.18),transparent_58%)]" />
<div className="absolute left-5 top-5 flex items-center gap-2 rounded-full border bg-background/85 px-3 py-1.5 font-mono text-[10px] shadow-sm backdrop-blur">
<span className="size-1.5 animate-pulse rounded-full bg-emerald-500" /> 8 regions online
</div>
</div>
<FeatureCopy
icon={Globe2}
title="Global inference gateway"
description="Route requests through the nearest healthy region for consistently fast model access."
/>
</article>
</div>
</div>
</section>
@@ -550,27 +492,23 @@ export function VertexLandingPage() {
<div className="grid md:grid-cols-3">
{[
{
number: "01",
icon: Code2,
title: "Change one base URL",
text: "Keep your existing OpenAI-compatible SDK, payloads, and streaming logic.",
},
{
number: "02",
icon: Workflow,
title: "Set a routing policy",
text: "Choose a model directly or let Vertex optimize for cost, quality, or latency.",
},
{
number: "03",
icon: Gauge,
title: "Observe every request",
text: "Trace performance and spend across models, applications, and environments.",
},
].map((step, index) => (
<article key={step.number} className={cn("relative p-8 sm:p-10", index < 2 && "border-b md:border-b-0 md:border-r")}>
<span className="font-mono text-xs text-blue-600 dark:text-blue-400">{step.number}</span>
<step.icon className="mt-10 size-6" />
<article key={step.title} className={cn("relative p-8 sm:p-10", index < 2 && "border-b md:border-b-0 md:border-r")}>
<step.icon className="size-6" />
<h3 className="mt-5 text-lg font-medium tracking-tight">{step.title}</h3>
<p className="mt-2 text-sm leading-6 text-muted-foreground">{step.text}</p>
</article>
@@ -610,14 +548,15 @@ export function VertexLandingPage() {
eyebrow="Simple pricing"
title="Start free. Scale without surprises."
description="Pay for the models you use and add platform controls when your team needs them."
className="border-b-0"
/>
<div className="flex justify-center border-b py-6">
<div className="inline-flex rounded-full border bg-muted/40 p-1" aria-label="Billing cadence">
<div className="inline-flex rounded-sm border bg-muted/40 p-1" aria-label="Billing cadence">
<button
type="button"
aria-pressed={!annual}
onClick={() => setAnnual(false)}
className={cn("rounded-full px-4 py-1.5 text-xs font-medium transition", !annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground")}
className={cn("rounded-sm px-4 py-1.5 text-xs font-medium transition", !annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground")}
>
Monthly
</button>
@@ -625,7 +564,7 @@ export function VertexLandingPage() {
type="button"
aria-pressed={annual}
onClick={() => setAnnual(true)}
className={cn("rounded-full px-4 py-1.5 text-xs font-medium transition", annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground")}
className={cn("rounded-sm px-4 py-1.5 text-xs font-medium transition", annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground")}
>
Annual <span className="text-blue-600 dark:text-blue-400">−20%</span>
</button>
@@ -661,42 +600,42 @@ export function VertexLandingPage() {
features: ["Everything in Team", "SAML SSO and audit logs", "Custom retention and regions", "Dedicated capacity", "Enterprise SLA"],
},
].map((plan) => (
<article key={plan.name} className={cn("relative flex flex-col bg-background p-7 sm:p-9", plan.popular && "bg-blue-600/[0.035]")}>
{plan.popular && (
<span className="absolute right-6 top-7 rounded-full bg-blue-600 px-2.5 py-1 font-mono text-[9px] font-semibold uppercase tracking-wider text-white">
Most popular
</span>
)}
<p className="text-sm font-medium">{plan.name}</p>
<div className="mt-7 flex items-end gap-2">
<span className="text-4xl font-medium tracking-[-0.05em]">{plan.price}</span>
{plan.cadence && <span className="pb-1 text-xs text-muted-foreground">{plan.cadence}</span>}
<article key={plan.name} className={cn("relative flex flex-col bg-background", plan.popular && "pricing-card-popular")}>
<div className="relative z-10 flex flex-1 flex-col p-7 sm:p-9">
<div className="flex min-h-7 flex-wrap items-center justify-between gap-2">
<p className="text-sm font-medium">{plan.name}</p>
{plan.popular && (
<span className="rounded-full border border-blue-600/40 px-3 py-1 text-xs font-medium text-blue-600 dark:border-[#5479db]/40 dark:text-blue-400">
Most popular
</span>
)}
</div>
<div className="mt-7 flex items-end gap-2">
<span className="text-4xl font-medium tracking-[-0.05em]">{plan.price}</span>
{plan.cadence && <span className="pb-1 text-xs text-muted-foreground">{plan.cadence}</span>}
</div>
<p className="mt-4 min-h-12 text-sm leading-6 text-muted-foreground">{plan.description}</p>
<a
href="#top"
className={cn(
"mt-7 inline-flex h-10 items-center justify-center rounded-sm border text-sm font-medium transition",
plan.popular ? "border-blue-600 bg-blue-600 text-white hover:bg-blue-500" : "bg-background hover:bg-muted"
)}
>
{plan.action}
</a>
<ul className="mt-7 space-y-3">
{plan.features.map((feature) => (
<li key={feature} className="flex items-start gap-2.5 text-sm text-muted-foreground">
<Check className="mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400" />
{feature}
</li>
))}
</ul>
</div>
<p className="mt-4 min-h-12 text-sm leading-6 text-muted-foreground">{plan.description}</p>
<a
href="#top"
className={cn(
"mt-7 inline-flex h-10 items-center justify-center rounded-full border text-sm font-medium transition",
plan.popular ? "border-blue-600 bg-blue-600 text-white hover:bg-blue-500" : "bg-background hover:bg-muted"
)}
>
{plan.action}
</a>
<div className="my-7 border-t" />
<ul className="space-y-3">
{plan.features.map((feature) => (
<li key={feature} className="flex items-start gap-2.5 text-sm text-muted-foreground">
<Check className="mt-0.5 size-4 shrink-0 text-blue-600 dark:text-blue-400" />
{feature}
</li>
))}
</ul>
</article>
))}
</div>
<p className="border-t px-6 py-5 text-center text-xs text-muted-foreground">
Model usage is billed separately at transparent provider rates. No long-term contracts.
</p>
</section>
<section className="border-b py-16 sm:py-20">
@@ -716,21 +655,22 @@ export function VertexLandingPage() {
</div>
</section>
<section className="grid border-b sm:grid-cols-[56px_1fr_56px]">
<div className="hatched hidden border-r sm:block" aria-hidden="true" />
<section className="relative border-b">
<span className="frame-cross left-0 top-0" aria-hidden="true" />
<span className="frame-cross right-0 top-0" aria-hidden="true" />
<span className="frame-cross bottom-0 left-0" aria-hidden="true" />
<span className="frame-cross bottom-0 right-0" aria-hidden="true" />
<div className="relative overflow-hidden px-6 py-24 text-center sm:px-10 sm:py-28">
<FlickeringGrid
className="absolute inset-0 [mask-image:radial-gradient(420px_circle_at_center,white,transparent)]"
squareSize={3}
gridGap={7}
color="#2563eb"
color="#173DA6"
maxOpacity={0.42}
flickerChance={0.08}
/>
<div className="relative z-10 mx-auto max-w-3xl">
<div className="mx-auto mb-7 flex size-12 items-center justify-center rounded-2xl bg-blue-600 text-white shadow-[0_10px_40px_rgba(37,99,235,.35)]">
<Waypoints className="size-6" />
</div>
<VertexMark className="mx-auto mb-7 size-12" />
<h2 className="text-balance text-4xl font-medium tracking-[-0.055em] sm:text-5xl md:text-6xl">
Build on every model.
<span className="block text-blue-600 dark:text-blue-400">Ship through one API.</span>
@@ -740,7 +680,6 @@ export function VertexLandingPage() {
</p>
</div>
</div>
<div className="hatched hidden border-l sm:block" aria-hidden="true" />
</section>
<footer className="px-6 py-10 sm:px-10">
@@ -759,9 +698,8 @@ export function VertexLandingPage() {
<a className="hover:text-foreground" href="#top">Privacy</a>
</div>
</div>
<div className="mt-10 flex flex-col gap-2 border-t pt-6 text-[11px] text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
<div className="mt-10 text-[11px] text-muted-foreground">
<span>© 2026 Vertex, Inc. All rights reserved.</span>
<span className="inline-flex items-center gap-1.5"><span className="size-1.5 rounded-full bg-emerald-500" /> All systems operational</span>
</div>
</footer>
</main>