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
2 changes: 1 addition & 1 deletion web/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ a {

@media (hover: hover) and (pointer: fine) {
.btn-primary:hover {
background: var(--primary-500);
background: var(--primary-700);
border-color: var(--primary-800);
}
}
Expand Down
5 changes: 2 additions & 3 deletions web/app/landing.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -1935,10 +1935,9 @@
background: var(--agent-tools-band-bg);
}

/* The homepage hero's wash is a flat vertical fade: the animated backdrop
carries the hero, so no highlight competes with it. */
/* A plain navy field keeps the homepage's message in focus. */
.homeLanding::before {
background: linear-gradient(180deg, #10273a 0%, #13314a 52%, #0d2638 100%);
background: #0d2638;
}

/* Lift the page content above the hero wash. Targeted at the two content
Expand Down
4 changes: 2 additions & 2 deletions web/components/InvestorStrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import s from './investor-strip.module.css';
// and already web-ready, so they skip the /_next/image round trip too.
const LOGO_IMAGE_PROPS = { loading: 'eager', unoptimized: true } as const;

export function InvestorStrip() {
export function InvestorStrip({ compact = false }: { compact?: boolean } = {}) {
const logos = [
<Image key="0" className={s.investorHustle} src="/investors/hustle-fund.svg" alt="Hustle Fund" {...LOGO_IMAGE_PROPS} width={205} height={27} />,
<Image key="1" className={s.investorActive} src="/investors/active-capital.svg" alt="Active Capital" {...LOGO_IMAGE_PROPS} width={185} height={30} />,
Expand All @@ -26,7 +26,7 @@ export function InvestorStrip() {
];

return (
<section className={s.backers} aria-label="Agent Relay investors">
<section className={`${s.backers}${compact ? ` ${s.compact}` : ''}`} aria-label="Agent Relay investors">
<p>Backed by</p>
<div className={`${s.investorGroup} ${s.desktopInvestors}`}>{logos}</div>
<div className={s.mobileInvestors} role="img" aria-label="Hustle Fund, Active Capital, Y Combinator, Cortical Ventures, and Yonder">
Expand Down
22 changes: 10 additions & 12 deletions web/components/homepage/HomeHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@ import type { CSSProperties } from 'react';

import { InvestorStrip } from '../InvestorStrip';
import { AgentIcons } from '../AgentSignup';
import { HOME_HERO_DESCRIPTION, HOME_HERO_TITLE_LINES, HOME_SIGNUP_HREF } from '../../lib/home-copy';
import { HeroBackdrop } from './HeroBackdrop';
import { HOME_HERO_SUBTITLE, HOME_HERO_TITLE_LINES, HOME_SIGNUP_HREF } from '../../lib/home-copy';
import s from '../../app/landing.module.css';
import home from './home-hero.module.css';

/**
* The homepage hero: the two-line headline rising in, the description, one
* sign-up button with the agent logos turning in it, and the backers, over a
* faint animated backdrop of agents talking. The button is marked so the nav can show its
* own once this one scrolls away.
* sign-up button and the backers on plain navy.
* The button is marked so the nav can show its own once this one scrolls away.
*/
export function HomeHero() {
return (
<div className={s.heroSection}>
<HeroBackdrop />
<section className={s.heroCenter}>
<div className={s.heroCenterColumn}>
<div className={`${s.heroSection} ${home.hero}`}>
<section className={`${s.heroCenter} ${home.copy}`}>
<div className={`${s.heroCenterColumn} ${home.content}`}>
<h1 className={`${s.headline} ${s.heroCenterHeadline}`}>
{HOME_HERO_TITLE_LINES.map((line, index) => (
<span className={s.heroTitleLine} key={line}>
Expand All @@ -28,9 +26,9 @@ export function HomeHero() {
))}
</h1>

<p className={`${s.subtitle} ${s.heroCenterSubtitle}`}>{HOME_HERO_DESCRIPTION}</p>
<p className={`${s.subtitle} ${s.heroCenterSubtitle}`}>{HOME_HERO_SUBTITLE}</p>

<div className={s.heroCenterCtas}>
<div className={`${s.heroCenterCtas} ${home.actions}`}>
<a className={`${s.ctaPrimary} ${s.heroCta}`} href={HOME_SIGNUP_HREF} data-hero-signup="">
<AgentIcons mono />
Connect your agents for free
Expand All @@ -42,7 +40,7 @@ export function HomeHero() {
</div>
</section>

<InvestorStrip />
<InvestorStrip compact />
</div>
);
}
18 changes: 15 additions & 3 deletions web/components/homepage/RotatingHeadline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import { AGENT_TOOLS, type AgentTool } from '../home/AgentMarks';
import { TypeScriptLogo } from '../home/icons';
import s from './rotating-headline.module.css';

type Tool = AgentTool | 'custom';
type Tool = AgentTool | 'custom' | 'dots' | 'pi';

/** The agents we work with, plus one built on our SDK. */
const TOOLS: Record<Tool, { name: string; logo: ReactNode }> = {
...AGENT_TOOLS,
muse: { name: 'Muse', logo: <img src="/logos/muse-transparent.png" alt="" /> },
dots: { name: 'Dots', logo: <img src="/logos/dot.webp" alt="" /> },
pi: { name: 'Pi', logo: <img className={s.monoLogo} src="/logos/pi.svg" alt="" /> },
custom: { name: 'your custom agent', logo: <TypeScriptLogo className={s.fill} /> },
};

/**
* Each step swaps one side, and every pair keeps Claude Code or Codex on one
* side: the other tools take turns talking to the two agents people know.
* Start with familiar coding agents, then mix in hosted assistants and
* cross-provider conversations as the rotation progresses.
*/
const PAIRS: [Tool, Tool][] = [
['claude', 'codex'],
Expand All @@ -31,12 +34,21 @@ const PAIRS: [Tool, Tool][] = [
['opencode', 'codex'],
['opencode', 'claude'],
['grok', 'claude'],
['dots', 'claude'],
['dots', 'muse'],
['muse', 'grokbot'],
['muse', 'claude'],
['pi', 'claude'],
['pi', 'codex'],
['grok', 'codex'],
['custom', 'codex'],
['claude', 'codex'],
['claude', 'antigravity'],
['codex', 'antigravity'],
['codex', 'grokbot'],
['codex', 'pi'],
['claude', 'pi'],
['claude', 'dots'],
['claude', 'grokbot'],
['claude', 'muse'],
['codex', 'muse'],
Expand Down
52 changes: 52 additions & 0 deletions web/components/homepage/home-hero.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.hero.hero {
--investor-strip-padding-top: 6rem;
padding-top: 28px;
padding-bottom: 24px;
}

.hero .copy {
padding-top: 64px;
}

.hero .content {
gap: 28px;
}

.hero .actions {
margin-top: 24px;
}

.hero .copy h1 {
font-size: clamp(42px, 6.2vw, 92px);
font-weight: 500;
}

.hero .copy p {
max-width: 44ch;
margin-top: 16px;
text-wrap: balance;
}

@media (max-width: 600px) {
.hero.hero {
--investor-strip-padding-top: 4.5rem;
padding-top: 16px;
padding-bottom: 16px;
}

.hero .copy {
padding-top: 48px;
}

.hero .content {
gap: 24px;
}

.hero .actions {
margin-top: 20px;
}

.hero .copy h1 {
font-size: 8.2vw;
}
}
8 changes: 8 additions & 0 deletions web/components/homepage/rotating-headline.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@
height: 100%;
}

.logo img {
object-fit: contain;
}

.monoLogo {
filter: brightness(0) invert(1);
}

.char {
display: inline-block;
}
Expand Down
15 changes: 15 additions & 0 deletions web/components/investor-strip.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
.investorYonder svg { width: 25px; height: 25px; }
.investorYonder strong { font-size: 1rem; font-weight: 720; letter-spacing: 0.015em; }

/* A quieter investor row for the homepage hero. */
.compact .investorGroup { gap: 1.25rem clamp(1.25rem, 3vw, 2.5rem); }
.compact .investorHustle { width: 112px; }
.compact .investorActive { width: 106px; }
.compact .investorCortical { width: 116px; }
.compact .investorYc,
.compact .investorYonder { gap: 0.375rem; }
.compact .investorYc > span { width: 22px; height: 22px; font-size: 17px; }
.compact .investorYc strong { font-size: 13px; }
.compact .investorYonder svg { width: 19px; height: 19px; }
.compact .investorYonder strong { font-size: 0.75rem; }

@media (max-width: 680px) {
.backers { padding-bottom: 3rem; }
.investorGroup { gap: 1.5rem 1.25rem; }
Expand All @@ -63,6 +75,9 @@
.investorCortical { width: 130px; }
.investorYc strong { font-size: 15px; }
.investorYonder strong { font-size: 0.9rem; }
.compact .investorHustle { width: 100px; }
.compact .investorActive { width: 98px; }
.compact .investorCortical { width: 104px; }
}

@keyframes investorFade {
Expand Down
3 changes: 3 additions & 0 deletions web/lib/home-copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ export const HOME_HERO_TITLE = HOME_HERO_TITLE_LINES.join(' ');
export const HOME_HERO_DESCRIPTION =
'Your agents should talk to each other, just not through you. Connect your agents and your teammates’ agents so they can coordinate directly, without the copy-paste.';

export const HOME_HERO_SUBTITLE =
'Connect your coding agents and your teammates’ agents. Let them coordinate directly.';

/** Google sign-in that lands on the connect-your-agents page. */
export const HOME_SIGNUP_HREF = teamsCloudUrl('/api/auth/google/start?next=%2Fteams%2Fconnect');
Binary file added web/public/logos/dot.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/public/logos/muse-transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions web/public/logos/pi.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.