Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,24 @@ export default defineConfig({
// discovered mid-hydration, the re-optimize invalidates the in-flight
// import chain, and every large island on the page silently fails to
// hydrate — docs sidebar dropdowns dead until a lucky reload.
//
// `@rivet-gg/components` is a linked workspace package, which Vite serves
// as raw source in dev: its barrel `src/index.ts` fans out to ~130
// separate module requests on every page that imports even `cn`, and on
// a high-latency link that waterfall dominates page load. Listing it
// here pre-bundles it into a handful of chunks like any other dep. The
// cost is that edits inside packages/components need a dev-server
// restart (or `astro dev --force`) instead of HMR. Production builds are
// unaffected: optimizeDeps only applies to the dev server. Subpath
// entries are separate optimizer entries, so list each one the site
// imports; those resolve to `.tsx` files, which Vite refuses to treat
// as optimizable entries unless the extension is listed.
optimizeDeps: {
extensions: ['.tsx'],
include: [
'@rivet-gg/components',
'@rivet-gg/components/header',
'@rivet-gg/components/mdx',
'mermaid',
'framer-motion',
'@rivet-gg/icons',
Expand Down
1 change: 1 addition & 0 deletions src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const footer = {
product: VISIBLE_PRODUCTS.map((item) => ({ name: item.name, href: `/${item.id}` })),
company: [
{ name: "Cloud Pricing", href: "/cloud" },
{ name: "Bring Your Own Cloud", href: "/cloud/byoc" },
{ name: "Enterprise", href: "/enterprise" },
{ name: "Careers", href: "/careers" },
{ name: "Talk to an engineer", href: "/talk-to-an-engineer" },
Expand Down
24 changes: 17 additions & 7 deletions src/components/marketing/DeploymentOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ export const DeploymentOptions = ({
<article className={DEPLOY_CARD_CLASS}>
<div className="mb-3 flex h-6 items-center gap-2.5">
<Laptop className="h-4 w-4 text-pine" aria-hidden="true" />
<h3 className={DEPLOY_CARD_TITLE_CLASS}>Local</h3>
<h3 className={DEPLOY_CARD_TITLE_CLASS}>Local & Self-Host</h3>
</div>
<p className={BODY_CLASS}>
Install {productName} and run it locally while you build.
Install {productName} and run it locally while you build. When you ship,
run the same open-source control plane as a Rust binary or container on
your own infrastructure.
</p>
<div className="flex-1" />
<div className="mt-6 border-t border-ink/10 pt-6">
Expand All @@ -51,6 +53,13 @@ export const DeploymentOptions = ({
>
Open the quickstart
</a>
<a
href={canonicalizeInternalHref(selfHostHref)}
className="mt-4 inline-flex items-center gap-1.5 text-sm font-medium text-pine no-underline hover:underline"
>
Read self-hosting docs
<span aria-hidden="true">→</span>
</a>
</div>
</article>

Expand All @@ -77,15 +86,16 @@ export const DeploymentOptions = ({
<article className={DEPLOY_CARD_CLASS}>
<div className="mb-3 flex h-6 items-center gap-2.5">
<Server className="h-4 w-4 text-pine" aria-hidden="true" />
<h3 className={DEPLOY_CARD_TITLE_CLASS}>Self-Host</h3>
<h3 className={DEPLOY_CARD_TITLE_CLASS}>BYOC</h3>
</div>
<p className={BODY_CLASS}>
Run the open-source Rivet control plane as a Rust binary or container on
your infrastructure.
Run the control plane inside your own VPC, fully managed by Rivet. Your
data never leaves your cloud and there is no inbound management
connection.
</p>
<div className="flex-1" />
<a href={canonicalizeInternalHref(selfHostHref)} className={`mt-6 ${DEPLOY_GHOST_BUTTON_CLASS}`}>
Read self-hosting docs
<a href="/cloud/byoc/" className={`mt-6 ${DEPLOY_GHOST_BUTTON_CLASS}`}>
Read the BYOC docs
</a>
</article>
</div>
Expand Down
44 changes: 19 additions & 25 deletions src/components/marketing/diagrams/deploymentDiagrams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@

import { motion, useInView, useReducedMotion } from 'framer-motion';
import { useRef } from 'react';
import { Icon, faRailway, faVercel, faCloudflare, faAws, faKubernetes } from '@rivet-gg/icons';

// ---------------------------------------------------------------------------
// The three deployment models drawn on one shared axis: every variant is the
// identical backend → control plane → storage stack, and only the containment
// boundary moves. Pine names what Rivet Cloud runs, ink names what you run,
// and the dashed arrow is the backend dialling out across the network
// and the dashed arrow is the BYOC operator dialling out across the network
// boundary. Pine only — no ember; the page's one accent CTA lives elsewhere.
// Restated from the self-host docs (src/content/self-host/index.mdx).
// Restated from the self-host docs (src/content/self-host/index.mdx) and the
// BYOC docs (/cloud/byoc/).
// ---------------------------------------------------------------------------

type DeploymentDiagramVariant = 'managed' | 'byoc' | 'self-hosted';
export type DeploymentDiagramVariant = 'managed' | 'byoc' | 'self-hosted';

const DEPLOYMENT_DIAGRAM_ARIA: Record<DeploymentDiagramVariant, string> = {
managed:
'Fully managed architecture: your backend, the control plane, and storage all run inside Rivet Cloud.',
byoc:
'Bring-your-own-compute architecture: your backend runs on your infrastructure — such as Railway, Vercel, Cloudflare, AWS, or Kubernetes — and connects outbound to the control plane and storage in Rivet Cloud.',
'Bring-your-own-cloud architecture: your backend, the control plane, and storage all run inside your VPC. A Rivet operator connects outbound to Rivet Cloud, which manages updates and maintenance.',
'self-hosted':
'Fully self-hosted architecture: your backend, the control plane, and storage all run on infrastructure you control.',
};

const COMPUTE_PROVIDERS = [faRailway, faVercel, faCloudflare, faAws, faKubernetes];

// Staged fade-in gated on scroll-into-view; settled instantly under reduced
// motion. Same hook as workflowDiagrams.tsx.
const useDiagram = () => {
Expand Down Expand Up @@ -95,8 +93,8 @@ const Zone = ({
);

// The one edge that crosses the network boundary: a dashed arrow pointing
// from your backend into Rivet Cloud (your backend dials out; no inbound
// path to your infra). The shaft sits on the diagram's center axis — the
// from your VPC into Rivet Cloud (the operator dials out; no inbound path
// to your infra). The shaft sits on the diagram's center axis — the
// label hangs off it absolutely so it cannot push the arrow off-center.
const CrossConnector = ({ show, at }: { show: Show; at: number }) => (
<motion.div className='relative flex min-h-7 flex-1 justify-center' {...show(at)}>
Expand All @@ -114,6 +112,7 @@ const CrossConnector = ({ show, at }: { show: Show; at: number }) => (
const Backend = () => <Node title='Your backend' sub='application code' />;
const ControlPlane = () => <Node title='Control plane' sub='scheduling · routing' ink />;
const Storage = () => <Node title='Storage' sub='actor state' />;
const Management = () => <Node title='Managed by Rivet' sub='updates · maintenance' />;

export const DeploymentDiagram = ({ variant }: { variant: DeploymentDiagramVariant }) => {
const { ref, show } = useDiagram();
Expand All @@ -127,30 +126,25 @@ export const DeploymentDiagram = ({ variant }: { variant: DeploymentDiagramVaria
>
{variant === 'byoc' ? (
<>
<Zone tone='ink' label='Your infrastructure' show={show} at={0}>
<Zone tone='ink' label='Your VPC' grow show={show} at={0}>
<motion.div {...show(1)}>
<Backend />
</motion.div>
<motion.div
aria-hidden='true'
className='mt-2.5 flex flex-wrap items-center justify-center gap-x-3 gap-y-1.5 border-t border-ink/10 pt-2.5 text-ink-faint'
{...show(1.5)}
>
{COMPUTE_PROVIDERS.map((provider, i) => (
<Icon key={i} icon={provider} className='h-3.5 w-3.5' />
))}
</motion.div>
</Zone>
<CrossConnector show={show} at={2} />
<Zone tone='pine' label='Rivet Cloud' show={show} at={2.5}>
<motion.div {...show(3)}>
<Connector show={show} at={1.5} />
<motion.div {...show(2)}>
<ControlPlane />
</motion.div>
<Connector show={show} at={3.5} />
<motion.div {...show(4)}>
<Connector show={show} at={2.5} />
<motion.div {...show(3)}>
<Storage />
</motion.div>
</Zone>
<CrossConnector show={show} at={3.5} />
<Zone tone='pine' label='Rivet Cloud' show={show} at={4}>
<motion.div {...show(4.5)}>
<Management />
</motion.div>
</Zone>
</>
) : (
<Zone
Expand Down
66 changes: 44 additions & 22 deletions src/components/marketing/pricing/PricingPageClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
import {
Icon,
faCloudArrowUp,
faServer,
faShareNodes
faCloudCheck,
faServer
} from '@rivet-gg/icons';
import imgYC from '@/images/logos/yc.svg';
import imgA16z from '@/images/logos/a16z.svg';
Expand All @@ -39,38 +39,49 @@ import {
} from '@/components/marketing/deployKit';
import { InkPanel } from '@/components/marketing/editorial/InkPanel';
import { SectionRule } from '@/components/marketing/SectionRule';
import { DeploymentDiagram } from '@/components/marketing/diagrams/deploymentDiagrams';
import { DeploymentDiagram, type DeploymentDiagramVariant } from '@/components/marketing/diagrams/deploymentDiagrams';

// --- Page Sections ---

const SelfHostingComparison = () => {
const deploymentModels = [
const deploymentModels: Array<{
title: string;
description: string;
hint: string;
icon: typeof faCloudArrowUp;
diagram: DeploymentDiagramVariant;
cta: string;
href: string;
primary: boolean;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · Show the bring-your-own-compute boundary accurately

This card explicitly offers a configuration where the backend runs on Vercel, Railway, Cloudflare, AWS, or Kubernetes, but its managed diagram and accessible description place the backend inside the Rivet Cloud boundary. The comparison therefore tells visitors choosing that advertised option that Rivet Cloud operates their backend, which contradicts the card copy and the deployment model.

Use a diagram/ARIA variant that separates customer compute from Rivet Cloud for this option, or present bring-your-own compute as its own model rather than attaching it to the fully managed diagram.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Medium · Show the bring-your-own-compute boundary accurately

This card explicitly offers a configuration where the backend runs on Vercel, Railway, Cloudflare, AWS, or Kubernetes, but its managed diagram and accessible description place the backend inside the Rivet Cloud boundary. The comparison therefore tells visitors choosing that advertised option that Rivet Cloud operates their backend, which contradicts the card copy and the deployment model.

Use a diagram/ARIA variant that separates customer compute from Rivet Cloud for this option, or present bring-your-own compute as its own model rather than attaching it to the fully managed diagram.

secondaryLink?: { label: string; href: string };
}> = [
{
title: 'Fully managed',
description: 'Rivet Cloud runs your backend, the control plane, and storage. Nothing to operate.',
title: 'Rivet Cloud',
description: 'Rivet Cloud runs the control plane and storage. Run your backend on Rivet Cloud too, or bring your own compute from Vercel, Railway, Cloudflare, AWS, or Kubernetes.',
hint: 'Best for most teams shipping to production.',
icon: faCloudArrowUp,
diagram: 'managed' as const,
diagram: 'managed',
cta: 'Get Started',
href: 'https://dashboard.rivet.dev',
primary: true,
secondaryLink: { label: 'Connect your own compute', href: '/actors/self-host/' },
},
{
title: 'Bring your own compute',
description: 'Your backend runs on your own infrastructure and connects outbound to the control plane in Rivet Cloud.',
hint: 'Best for serverless platforms and keeping compute in your VPC.',
icon: faShareNodes,
diagram: 'byoc' as const,
cta: 'Connect Your Host',
href: '/actors/self-host/',
title: 'Bring your own cloud',
description: 'The whole stack runs inside your VPC, and Rivet manages it for you over an outbound connection.',
hint: 'Best for data residency without anything to operate.',
icon: faCloudCheck,
diagram: 'byoc',
cta: 'Read the BYOC Docs',
href: '/cloud/byoc/',
primary: false,
},
{
title: 'Fully self-hosted',
description: 'You run the entire stack on infrastructure you control, including air-gapped networks.',
hint: 'Best for strict compliance and air-gapped environments.',
icon: faServer,
diagram: 'self-hosted' as const,
diagram: 'self-hosted',
cta: 'View on GitHub',
href: 'https://github.com/rivet-dev/rivet',
primary: false,
Expand Down Expand Up @@ -112,12 +123,23 @@ const SelfHostingComparison = () => {
</div>

<p className="mt-4 text-xs leading-relaxed text-ink-faint">{model.hint}</p>
<a
href={canonicalizeInternalHref(model.href)}
className={`mt-6 ${model.primary ? DEPLOY_WHITE_BUTTON_CLASS : DEPLOY_GHOST_BUTTON_CLASS}`}
>
{model.cta}
</a>
<div className="mt-6 flex flex-col gap-4">
<a
href={canonicalizeInternalHref(model.href)}
className={model.primary ? DEPLOY_WHITE_BUTTON_CLASS : DEPLOY_GHOST_BUTTON_CLASS}
>
{model.cta}
</a>
{model.secondaryLink ? (
<a
href={canonicalizeInternalHref(model.secondaryLink.href)}
className="inline-flex items-center gap-1.5 text-sm font-medium text-pine no-underline hover:underline"
>
{model.secondaryLink.label}
<span aria-hidden="true">→</span>
</a>
) : null}
</div>
</article>
))}
</div>
Expand All @@ -130,7 +152,7 @@ const SelfHostingComparison = () => {
<div>
<h3 className={CARD_TITLE_CLASS}>Enterprise Edition</h3>
<p className="mt-2 max-w-3xl text-[15px] leading-relaxed text-ink-soft">
Add multi-tenancy, access controls, backups, and deployment guidance to a self-hosted deployment.
Add multi-tenancy, access controls, backups, and deployment guidance to a BYOC or self-hosted deployment.
</p>
<a href="/enterprise/" className="mt-3 inline-flex text-sm font-medium text-pine transition-colors motion-reduce:transition-none hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-pine focus-visible:ring-offset-2 focus-visible:ring-offset-paper">
Explore Enterprise
Expand Down
23 changes: 21 additions & 2 deletions src/components/marketing/sections/AgentStackSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,26 @@ ${answeringLayers
// cards in normal document flow so every need remains readable below it,
// including the taller agentOS step, without introducing a nested scroll
// container.
// On phones each card snaps to the slot between the diagram and the bottom
// of the screen and grows to fill it. The root is the snap container (the
// cards live in normal flow), with `proximity` so the rest of the page
// scrolls freely and only settles when a card is already close.
`[data-agent-stack-story]{
--agent-stack-sticky-top:calc(var(--header-height,3.5rem) + 2.5rem);
--agent-stack-panel-height:38svh;
--agent-stack-card-top:calc(var(--agent-stack-sticky-top) + var(--agent-stack-panel-height) + 1.5rem);
}
@media (max-width: 47.999rem){
html{scroll-snap-type:y proximity;}
[data-agent-stack-step]{
scroll-snap-align:start;
scroll-margin-top:var(--agent-stack-card-top);
}
[data-agent-stack-card]{
display:flex;
flex-direction:column;
min-height:calc(100svh - var(--agent-stack-card-top) - 1rem);
}
}
[data-agent-stack-story] [data-mobile-plate]{
opacity:.24;
Expand Down Expand Up @@ -811,7 +829,7 @@ const MobileStackStory = () => (
className="pointer-events-none absolute inset-x-0 bottom-full h-10 bg-paper"
/>
<div
className="h-[38svh] overflow-hidden rounded-xl border border-ink/10 bg-paper px-3 py-2 md:h-[46svh] md:p-5"
className="h-[var(--agent-stack-panel-height)] overflow-hidden rounded-xl border border-ink/10 bg-paper px-3 py-2 md:h-[46svh] md:p-5"
data-agent-stack-diagram-panel=""
>
<CompactStackDiagram />
Expand Down Expand Up @@ -852,7 +870,8 @@ const MobileStackStory = () => (
</h3>
</div>

<div className="mt-4">
{/* Grows on phones so the solution line anchors to the card's bottom. */}
<div className="mt-4 flex-1">
<p className="text-xs font-medium text-ink-faint">
What agents need
</p>
Expand Down
6 changes: 3 additions & 3 deletions src/components/marketing/sections/OnPremSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import {
const pillars = [
{
title: "Single Rust binary",
body: "One process to install, monitor, and upgrade.",
body: "One process to install, monitor, and upgrade, on Kubernetes with the Enterprise Helm chart or as a systemd unit.",
},
{
title: "Kubernetes or systemd",
body: "Deploy with the Enterprise Helm chart or a systemd unit.",
title: "Managed in your VPC",
body: "With BYOC, Rivet deploys and maintains the control plane inside your cloud over an outbound connection.",
},
{
title: "Storage you control",
Expand Down
Loading
Loading