Skip to content

Commit 5ea86e1

Browse files
RhysSullivanclaude
andcommitted
marketing: one door on the homepage hero
Drop the Cloud / Desktop / Self-hosted tabs from the hero. One Start on Cloud button, a ghost Copy setup prompt beside it, and a fine-print link to the Run it section for the local options. The rail stops selling: the Get started, star, and YC boxes become two quiet text lines. Extract the intro steps and the copy button into components. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent a72e51d commit 5ea86e1

7 files changed

Lines changed: 170 additions & 305 deletions

File tree

‎apps/marketing/.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ pnpm-debug.log*
2323
# jetbrains setting folder
2424
.idea/
2525
.vercel
26+
.preview/
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
// The "Copy setup prompt" button: a dashed ghost button beside the primary,
3+
// carrying the three agent marks. Copies `setupPrompt`; the click handler
4+
// lives in pages/index.astro.
5+
import { setupPrompt } from "../../content/site-copy";
6+
7+
const logos = import.meta.glob<string>("../../assets/logos/*.svg", {
8+
eager: true,
9+
query: "?url",
10+
import: "default",
11+
});
12+
const logo = (name: string): string => {
13+
const hit = Object.entries(logos).find(([k]) => k.endsWith(`/${name}.svg`));
14+
if (!hit) throw new Error(`missing logo ${name}`);
15+
return hit[1];
16+
};
17+
const marks = ["claude", "codex", "cursor"];
18+
19+
20+
---
21+
22+
<button
23+
type="button"
24+
class="btn-ghost copy-btn doc__copy"
25+
data-copy={setupPrompt}
26+
data-event="marketing_setup_prompt_copied"
27+
>
28+
<span class="doc__copy-logos" aria-hidden="true">
29+
{marks.map((n) => <img src={logo(n)} alt="" width="14" height="14" />)}
30+
</span>
31+
<span>Copy setup prompt</span>
32+
<span class="copy-icons" aria-hidden="true">
33+
<svg class="copy-icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>
34+
<svg class="copy-icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>
35+
</span>
36+
</button>

‎apps/marketing/src/components/variants/doc-body.astro‎

Lines changed: 12 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,19 @@
11
---
22
// Document-style homepage body. Reads like a short paper about the product:
33
// one modest headline, plain first-person prose, six beats separated by
4-
// hairlines, the two demos kept as numbered figures, and one way to start.
4+
// hairlines, the two demos kept as numbered figures, and one door in: Cloud,
5+
// with a setup prompt for visitors who already have an agent open.
56
// Sits inside the rail layout; the rail's "On this page" list points at the
67
// section ids below.
78
import { AnimatedBeamDemo } from "../animated-beam-demo";
89
import { ContextBloatDemo } from "../context-bloat-demo";
9-
import { setupPrompt } from "../../content/site-copy";
1010
import Testimonials from "./testimonials.astro";
11+
import IntroSteps from "./intro-steps.astro";
12+
import CopyPrompt from "./copy-prompt.astro";
1113
import "../../styles/variants/doc.css";
1214
// Avatar goes through Vite so it ships as a hashed asset; new /public files
1315
// are not picked up by the deploy pipeline.
1416
import rhysAvatar from "../../assets/rhys-sullivan.jpg";
15-
// Brand marks for the hover reveals in the intro steps.
16-
const logos = import.meta.glob<string>("../../assets/logos/*.svg", {
17-
eager: true,
18-
query: "?url",
19-
import: "default",
20-
});
21-
const logo = (name: string): string => {
22-
const hit = Object.entries(logos).find(([k]) => k.endsWith(`/${name}.svg`));
23-
if (!hit) throw new Error(`missing logo ${name}`);
24-
return hit[1];
25-
};
26-
const toolLogos = ["github", "linear", "sentry", "stripe", "notion", "slack", "jira", "gmail"];
27-
const agentLogos = ["claude", "codex", "cursor", "chatgpt", "gemini", "hermes", "copilot", "windsurf", "opencode", "zed", "grok"];
28-
// The three marks on the copy button; the full list would crowd it.
29-
const agentLogosShort = ["claude", "codex", "cursor"];
3017
const X_URL = "https://x.com/RhysSullivan";
3118
3219
interface Props {
@@ -39,91 +26,15 @@ const { gh } = Astro.props;
3926
{/* ── Intro ── */}
4027
<header class="doc__intro">
4128
<h1 class="doc__title">Executor is an MCP gateway.</h1>
42-
<ol class="doc__steps">
43-
<li>
44-
<span class="doc__num">01</span>
45-
<span>
46-
Connect{" "}
47-
<span class="doc__pop" tabindex="0">
48-
<span class="doc__pop-word">everything</span>
49-
<span class="doc__pop-panel" aria-hidden="true" inert>
50-
{toolLogos.map((n, i) => (
51-
<span class="doc__pop-tile" style={`--i:${i}`}><img src={logo(n)} alt="" width="18" height="18" /></span>
52-
))}
53-
<span class="doc__pop-pill" style={`--i:${toolLogos.length}`}>any OpenAPI, GraphQL, or MCP</span>
54-
</span>
55-
</span>
56-
{" "}to Executor.
57-
</span>
58-
</li>
59-
<li>
60-
<span class="doc__num">02</span>
61-
<span>
62-
Give{" "}
63-
<span class="doc__pop" tabindex="0">
64-
<span class="doc__pop-word">your agent</span>
65-
<span class="doc__pop-panel" aria-hidden="true" inert>
66-
{agentLogos.map((n, i) => (
67-
<span class="doc__pop-tile" style={`--i:${i}`}><img src={logo(n)} alt="" width="18" height="18" /></span>
68-
))}
69-
<span class="doc__pop-pill" style={`--i:${agentLogos.length}`}>any MCP client</span>
70-
</span>
71-
</span>
72-
{" "}the Executor tool.
73-
</span>
74-
</li>
75-
<li>
76-
<span class="doc__num">03</span>
77-
<span>That's it.{" "}<a href="#install">Get started.</a></span>
78-
</li>
79-
</ol>
80-
<p class="doc__subhead">One MCP. All your accounts.</p>
81-
<div class="doc__tabs" role="tablist" aria-label="How to run Executor">
82-
<button type="button" role="tab" aria-selected="true" data-doc-tab="cloud">Cloud</button>
83-
<button type="button" role="tab" aria-selected="false" data-doc-tab="local">Desktop / CLI</button>
84-
<button type="button" role="tab" aria-selected="false" data-doc-tab="self">Self-hosted</button>
85-
</div>
86-
<div class="doc__tabpanes">
87-
<div role="tabpanel" data-doc-pane="cloud">
88-
<p>Sign in, point your agent at one URL, done. Free for up to three people and 100,000 executions a month.</p>
89-
<div class="doc__actions"><a href="/cloud" class="btn-primary">Start on Cloud</a><button type="button" class="btn-secondary copy-btn doc__copy" data-copy={setupPrompt} data-event="marketing_setup_prompt_copied">
90-
<span class="doc__copy-logos" aria-hidden="true">
91-
{agentLogosShort.map((n) => <img src={logo(n)} alt="" width="14" height="14" />)}
92-
</span>
93-
<span>Copy setup prompt</span>
94-
<span class="copy-icons" aria-hidden="true">
95-
<svg class="copy-icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>
96-
<svg class="copy-icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>
97-
</span>
98-
</button></div>
99-
</div>
100-
<div role="tabpanel" data-doc-pane="local" data-inactive aria-hidden="true" inert>
101-
<p>Nothing leaves your machine. A desktop app for Mac, Windows, and Linux, or a CLI that runs in the background. Same local endpoint either way.</p>
102-
<div class="doc__actions"><span class="doc__dl" data-download>
103-
<a data-os="mac-arm64" href={`${gh}/releases/latest/download/executor-desktop-mac-arm64.dmg`} class="btn-primary">Download for Mac</a>
104-
<a data-os="mac-x64" href={`${gh}/releases/latest/download/executor-desktop-mac-x64.dmg`} class="btn-primary">Download for Mac (Intel)</a>
105-
<a data-os="win-x64" href={`${gh}/releases/latest/download/executor-desktop-win-x64.exe`} class="btn-primary">Download for Windows</a>
106-
<a data-os="linux-x64" href={`${gh}/releases/latest/download/executor-desktop-linux-x86_64.AppImage`} class="btn-primary">Download for Linux</a>
107-
<details class="download-other doc__dl-other hidden" data-download-other>
108-
<summary>Other platforms ▾</summary>
109-
<div class="download-other-list" data-download-other-list></div>
110-
</details>
111-
</span><code class="doc__cmd">npm i -g executor</code><button type="button" class="btn-secondary copy-btn doc__copy" data-copy={setupPrompt} data-event="marketing_setup_prompt_copied">
112-
<span class="doc__copy-logos" aria-hidden="true">
113-
{agentLogosShort.map((n) => <img src={logo(n)} alt="" width="14" height="14" />)}
114-
</span>
115-
<span>Copy setup prompt</span>
116-
<span class="copy-icons" aria-hidden="true">
117-
<svg class="copy-icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>
118-
<svg class="copy-icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>
119-
</span>
120-
</button></div>
121-
</div>
122-
<div role="tabpanel" data-doc-pane="self" data-inactive aria-hidden="true" inert>
123-
<p>One Docker image on your own box. It is the same code Cloud runs.</p>
124-
<div class="doc__actions"><a href="https://executor.sh/docs/hosted/docker" class="btn-primary">Self-hosting docs</a><a href={gh} class="btn-secondary">Source on GitHub</a></div>
125-
</div>
29+
<IntroSteps />
30+
<p class="doc__subhead">One MCP. All your accounts. Free for up to three people.</p>
31+
<div class="doc__actions">
32+
<a href="/cloud" class="btn-primary">Start on Cloud</a>
33+
<CopyPrompt />
12634
</div>
35+
<p class="doc__subhead doc__subhead--fine">
36+
Rather keep it on your machine? <a href="#install">Desktop, CLI, or self-hosted ↓</a>
37+
</p>
12738
</header>
12839

12940
<figure class="doc__fig doc__fig--hero">
@@ -305,29 +216,6 @@ const { gh } = Astro.props;
305216
</section>
306217
</article>
307218

308-
<script>
309-
for (const list of document.querySelectorAll<HTMLElement>(".doc__tabs")) {
310-
const root = list.parentElement!;
311-
list.addEventListener("click", (e) => {
312-
const tab = (e.target as HTMLElement).closest<HTMLElement>("[data-doc-tab]");
313-
if (!tab) return;
314-
const key = tab.dataset.docTab;
315-
for (const t of list.querySelectorAll<HTMLElement>("[data-doc-tab]")) {
316-
t.setAttribute("aria-selected", String(t === tab));
317-
}
318-
for (const p of root.querySelectorAll<HTMLElement>("[data-doc-pane]")) {
319-
const off = p.dataset.docPane !== key;
320-
p.toggleAttribute("data-inactive", off);
321-
p.toggleAttribute("inert", off);
322-
p.setAttribute("aria-hidden", String(off));
323-
for (const el of p.querySelectorAll<HTMLElement>("a, button")) {
324-
el.tabIndex = off ? -1 : 0;
325-
}
326-
}
327-
});
328-
}
329-
</script>
330-
331219
<script>
332220
// Show one download button for the visitor's OS and tuck the rest behind
333221
// "Other platforms". Without JS or on an unknown OS, all four stay visible.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
// The three numbered intro steps with the hover-reveal logo panels.
3+
const logos = import.meta.glob<string>("../../assets/logos/*.svg", {
4+
eager: true,
5+
query: "?url",
6+
import: "default",
7+
});
8+
const logo = (name: string): string => {
9+
const hit = Object.entries(logos).find(([k]) => k.endsWith(`/${name}.svg`));
10+
if (!hit) throw new Error(`missing logo ${name}`);
11+
return hit[1];
12+
};
13+
const toolLogos = ["github", "linear", "sentry", "stripe", "notion", "slack", "jira", "gmail"];
14+
const agentLogos = ["claude", "codex", "cursor", "chatgpt", "gemini", "hermes", "copilot", "windsurf", "opencode", "zed", "grok"];
15+
---
16+
17+
<ol class="doc__steps">
18+
<li>
19+
<span class="doc__num">01</span>
20+
<span>
21+
Connect{" "}
22+
<span class="doc__pop" tabindex="0">
23+
<span class="doc__pop-word">everything</span>
24+
<span class="doc__pop-panel" aria-hidden="true" inert>
25+
{toolLogos.map((n, i) => (
26+
<span class="doc__pop-tile" style={`--i:${i}`}><img src={logo(n)} alt="" width="18" height="18" /></span>
27+
))}
28+
<span class="doc__pop-pill" style={`--i:${toolLogos.length}`}>any OpenAPI, GraphQL, or MCP</span>
29+
</span>
30+
</span>
31+
{" "}to Executor.
32+
</span>
33+
</li>
34+
<li>
35+
<span class="doc__num">02</span>
36+
<span>
37+
Give{" "}
38+
<span class="doc__pop" tabindex="0">
39+
<span class="doc__pop-word">your agent</span>
40+
<span class="doc__pop-panel" aria-hidden="true" inert>
41+
{agentLogos.map((n, i) => (
42+
<span class="doc__pop-tile" style={`--i:${i}`}><img src={logo(n)} alt="" width="18" height="18" /></span>
43+
))}
44+
<span class="doc__pop-pill" style={`--i:${agentLogos.length}`}>any MCP client</span>
45+
</span>
46+
</span>
47+
{" "}the Executor tool.
48+
</span>
49+
</li>
50+
<li>
51+
<span class="doc__num">03</span>
52+
<span>That's it.</span>
53+
</li>
54+
</ol>

‎apps/marketing/src/components/variants/rail-b.astro‎

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
---
22
// Rail, variant B: "Gridline rail".
3-
// Compact and technical: mark-only wordmark, a tight link stack, an outlined
4-
// CTA, and a numbered mono index. A full-height hairline closes the right edge.
3+
// Compact and technical: mark-only wordmark, a tight link stack, two quiet
4+
// meta lines (open source, YC), and a numbered mono index. The rail does not
5+
// sell; the hero owns the call to action. A full-height hairline closes the
6+
// right edge.
57
import "../../styles/variants/rail.css";
6-
import ycBackedBy from "../../assets/yc-backed-by.svg?url";
78
import rhysAvatar from "../../assets/rhys-sullivan.jpg";
89
910
const X_URL = "https://x.com/RhysSullivan";
@@ -47,38 +48,13 @@ const pad = (index: number) => String(index + 1).padStart(2, "0");
4748
<a href={SIGN_IN} class="rail__link rail__link--keep">Sign in</a>
4849
</nav>
4950

50-
<div class="rail__cta">
51-
<a href="#install" class="rail__box rail__box--primary">Get started</a>
52-
<a
53-
href={GH}
54-
target="_blank"
55-
rel="noopener"
56-
class="rail__box gh-star"
57-
aria-label="Star Executor on GitHub"
58-
>
59-
<svg
60-
class="gh-star__ico"
61-
width="13"
62-
height="13"
63-
viewBox="0 0 16 16"
64-
aria-hidden="true"
65-
>
66-
<path
67-
fill="#e3b341"
68-
d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.75.75 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25z"
69-
></path>
70-
</svg>
71-
<span>Star on GitHub</span>
72-
{stars != null && <span class="gh-star__n">{stars}</span>}
51+
<div class="rail__meta">
52+
<a href={GH} target="_blank" rel="noopener" class="rail__meta-line">
53+
<span>Open source</span>
54+
{stars != null && <span class="rail__meta-n">★ {stars}</span>}
7355
</a>
74-
<a
75-
href="https://www.ycombinator.com"
76-
target="_blank"
77-
rel="noopener noreferrer"
78-
class="rail__box rail__box--yc"
79-
aria-label="Backed by Y Combinator"
80-
>
81-
<img src={ycBackedBy} alt="Backed by Y Combinator" width="350" height="125" />
56+
<a href="https://www.ycombinator.com" target="_blank" rel="noopener noreferrer" class="rail__meta-line">
57+
<span>Backed by Y Combinator</span>
8258
</a>
8359
</div>
8460

0 commit comments

Comments
 (0)