Skip to content

Commit baa3ea8

Browse files
bloveclaude
andcommitted
copy(website): tagline is "The open-source thread-plane for agents." on three lines
Drops "enterprise" (gtm.md already lists it as reading sales-first) and hyphenates thread-plane. HERO_H1_LINES breaks the H1 where it is meant to break; a spec asserts the lines rejoin to HERO_H1, and both the hero and the OG card render from the lines. The description drops "enterprise" to match. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 9bc2a17 commit baa3ea8

19 files changed

Lines changed: 65 additions & 37 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<p align="center">
22
<img
33
src="https://threadplane.ai/assets/hero.svg"
4-
alt="Threadplane — the open-source thread plane for enterprise agents"
4+
alt="Threadplane — the open-source thread-plane for agents"
55
width="100%"
66
/>
77
</p>
88

99
<p align="center">
10-
<em>The open-source thread plane for enterprise agents.</em>
10+
<em>The open-source thread-plane for agents.</em>
1111
</p>
1212

1313
<p align="center">
@@ -33,7 +33,7 @@
3333

3434
---
3535

36-
**Threadplane is the open-source thread plane for enterprise agents.** Chat, durable
36+
**Threadplane is the open-source thread-plane for agents.** Chat, durable
3737
threads, persistence, human approvals, tool progress, subagents, and generative UI — built on
3838
Angular Signals and dependency injection, for Angular 20–22. Your backend stays
3939
where it is: Threadplane adapts a LangGraph or AG-UI agent into a runtime-neutral

apps/website/e2e/website.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async function expectNoHorizontalOverflow(
2121
test('landing page renders hero headline', async ({ page }) => {
2222
await page.goto('/');
2323
await expect(page.locator('#hero-heading')).toBeVisible();
24-
await expect(page.locator('#hero-heading')).toHaveText('The open-source thread plane for enterprise agents.');
24+
await expect(page.locator('#hero-heading')).toHaveText('The open-source thread-plane for agents.');
2525
const headline = await page.locator('#hero-heading').textContent();
2626
expect(headline?.toLowerCase()).toContain('angular');
2727
});

apps/website/src/app/opengraph-image.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* If either changes, re-resolve them here.
3333
*/
3434
import { ImageResponse } from 'next/og';
35-
import { HERO_H1, HERO_SUBHEAD, POSITIONING_PROOF_POINTS, PRIMARY_TAGLINE } from '../lib/positioning';
35+
import { HERO_H1_LINES, HERO_SUBHEAD, POSITIONING_PROOF_POINTS, PRIMARY_TAGLINE } from '../lib/positioning';
3636
import { loadCardFonts } from './og-font';
3737

3838
// Node runtime (not edge) so we can read the bundled Garamond TTF off disk.
@@ -159,6 +159,8 @@ export default async function OpenGraphImage() {
159159
<div
160160
style={{
161161
display: 'flex',
162+
flexDirection: 'column',
163+
alignItems: 'center',
162164
marginTop: 34,
163165
fontSize: 52,
164166
fontWeight: 600,
@@ -167,7 +169,9 @@ export default async function OpenGraphImage() {
167169
color: TOKENS.textPrimary,
168170
}}
169171
>
170-
{HERO_H1}
172+
{HERO_H1_LINES.map((line) => (
173+
<div key={line} style={{ display: 'flex' }}>{line}</div>
174+
))}
171175
</div>
172176

173177
{/* What you get. Wrapped to two lines on purpose — see the header. */}

apps/website/src/components/landing/Hero.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Button } from '../ui/Button';
88
import { trackCtaClick } from '../../lib/analytics/client';
99
import {
1010
HERO_EYEBROW,
11-
HERO_H1,
11+
HERO_H1_LINES,
1212
HERO_PRIMARY_LABEL,
1313
HERO_SECONDARY_HREF,
1414
HERO_SECONDARY_LABEL,
@@ -31,7 +31,14 @@ export function Hero() {
3131
<Container>
3232
<div className="hero-stack">
3333
<Eyebrow tone="accent" className="hero-eyebrow">{HERO_EYEBROW}</Eyebrow>
34-
<h1 id="hero-heading" className="hero-heading">{HERO_H1}</h1>
34+
<h1 id="hero-heading" className="hero-heading">
35+
{HERO_H1_LINES.map((line, i) => (
36+
<React.Fragment key={line}>
37+
{i > 0 ? ' ' : ''}
38+
<span className="hero-heading-line">{line}</span>
39+
</React.Fragment>
40+
))}
41+
</h1>
3542
<p className="hero-subhead">
3643
{HERO_SUBHEAD_SEGMENTS.map((segment) =>
3744
segment.highlight ? (

apps/website/src/lib/positioning.spec.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
formatAngularRange,
1111
HERO_EYEBROW,
1212
HERO_H1,
13+
HERO_H1_LINES,
1314
HERO_PRIMARY_LABEL,
1415
HERO_SECONDARY_HREF,
1516
HERO_SECONDARY_LABEL,
@@ -47,15 +48,20 @@ function parses(code: string): boolean {
4748
describe('positioning: hero copy', () => {
4849
it('names the exact category in eyebrow, H1, title and description', () => {
4950
expect(HERO_EYEBROW).toBe('Angular · LangGraph & AG-UI');
50-
expect(HERO_H1).toBe('The open-source thread plane for enterprise agents.');
51+
expect(HERO_H1).toBe('The open-source thread-plane for agents.');
5152
expect(HERO_SUBHEAD).toBe('Chat, threads, approvals, and generative UI on Signals and DI. Your backend stays where it is.');
52-
expect(HOME_TITLE).toBe('Threadplane — The open-source thread plane for enterprise agents');
53+
expect(HOME_TITLE).toBe('Threadplane — The open-source thread-plane for agents');
5354
expect(HOME_DESCRIPTION).toBe(
54-
'The open-source thread plane for enterprise agents: chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.',
55+
'The open-source thread-plane for agents: chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.',
5556
);
5657
expect(HOME_DESCRIPTION.length).toBeLessThanOrEqual(160);
5758
});
5859

60+
it('H1 lines join back to HERO_H1 on three lines', () => {
61+
expect(HERO_H1_LINES).toHaveLength(3);
62+
expect(HERO_H1_LINES.join(' ')).toBe(HERO_H1);
63+
});
64+
5965
it('subhead segments join back to HERO_SUBHEAD, with exactly one highlight', () => {
6066
// The segments exist only so Hero.tsx can marker-highlight one phrase.
6167
// If they ever stop reassembling the source-of-truth string, the rendered

apps/website/src/lib/positioning.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { WEBSITE_SUPPORTED_ANGULAR_MAJORS } from '../components/pricing/angular-
33
import type { StageBeat } from './stage-beats';
44

55
export const HERO_EYEBROW = 'Angular · LangGraph & AG-UI';
6-
export const HERO_H1 = 'The open-source thread plane for enterprise agents.';
6+
export const HERO_H1 = 'The open-source thread-plane for agents.';
7+
/**
8+
* The H1 broken where it is meant to break: three lines, one thought each.
9+
* HERO_H1 stays the single source of truth — positioning.spec.ts asserts the
10+
* lines join back to it with single spaces, so the rendered heading, the
11+
* <title> and the social card cannot drift apart.
12+
*/
13+
export const HERO_H1_LINES: readonly string[] = ['The open-source', 'thread-plane', 'for agents.'];
714
export const HERO_SUBHEAD =
815
'Chat, threads, approvals, and generative UI on Signals and DI. Your backend stays where it is.';
916

@@ -28,13 +35,13 @@ export const HERO_SECONDARY_LABEL = 'See it running in the docs →';
2835
export const HERO_SECONDARY_HREF = '/docs/chat/guides/generative-ui?mode=run';
2936

3037
/** Kept for layout.tsx default title and the OG image alt. */
31-
export const PRIMARY_TAGLINE = 'Threadplane — The open-source thread plane for enterprise agents';
38+
export const PRIMARY_TAGLINE = 'Threadplane — The open-source thread-plane for agents';
3239
export const HOME_TITLE = PRIMARY_TAGLINE;
3340
export const HOME_DESCRIPTION =
34-
'The open-source thread plane for enterprise agents: chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.';
41+
'The open-source thread-plane for agents: chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.';
3542
/** Longer form used by layout.tsx OG/Twitter defaults and the About page. */
3643
export const LONG_SUBHEAD =
37-
'Threadplane is the open-source thread plane for enterprise agents: signal-native chat, durable threads, persistence, human approvals, tool progress, subagents, and generative UI for Angular, on LangGraph and AG-UI — without replacing your backend or design system.';
44+
'Threadplane is the open-source thread-plane for agents: signal-native chat, durable threads, persistence, human approvals, tool progress, subagents, and generative UI for Angular, on LangGraph and AG-UI — without replacing your backend or design system.';
3845

3946
// ── Trust line (values verified by positioning.spec.ts + angular-support-copy.spec.ts) ──
4047
export function formatAngularRange(majors: readonly number[]): string {

apps/website/src/lib/site-metadata.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import { resolveWebsiteDir } from './website-dir';
1818

1919
describe('site positioning copy', () => {
2020
it('exports the approved primary tagline and supporting copy', () => {
21-
expect(PRIMARY_TAGLINE).toBe('Threadplane — The open-source thread plane for enterprise agents');
22-
expect(LONG_SUBHEAD).toContain('open-source thread plane for enterprise agents');
21+
expect(PRIMARY_TAGLINE).toBe('Threadplane — The open-source thread-plane for agents');
22+
expect(LONG_SUBHEAD).toContain('open-source thread-plane for agents');
2323
expect(LONG_SUBHEAD).toContain('LangGraph and AG-UI');
2424
expect(HERO_SUBHEAD).toBe(
2525
'Chat, threads, approvals, and generative UI on Signals and DI. Your backend stays where it is.',
@@ -65,7 +65,7 @@ describe('site positioning copy', () => {
6565
type: 'website',
6666
});
6767

68-
expect(metadata.title).toBe('Threadplane — The open-source thread plane for enterprise agents');
68+
expect(metadata.title).toBe('Threadplane — The open-source thread-plane for agents');
6969
expect(metadata.description).toBe(HOME_DESCRIPTION);
7070
});
7171
});
@@ -142,7 +142,7 @@ describe('createPageMetadata article fields', () => {
142142
expect(openGraph.images[0].url).toBe('/opengraph-image');
143143
expect(openGraph.images[0].width).toBe(1200);
144144
expect(openGraph.images[0].height).toBe(630);
145-
expect(openGraph.images[0].alt).toMatch(/open-source thread plane for enterprise agents/);
145+
expect(openGraph.images[0].alt).toMatch(/open-source thread-plane for agents/);
146146
});
147147

148148
it('accepts a page-specific social image', () => {

apps/website/src/lib/site-metadata.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const DEFAULT_SOCIAL_IMAGE_META = {
2020
url: DEFAULT_SOCIAL_IMAGE,
2121
width: 1200,
2222
height: 630,
23-
alt: 'Threadplane — the open-source thread plane for enterprise agents. Chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.',
23+
alt: 'Threadplane — the open-source thread-plane for agents. Chat, durable threads, persistence, human approvals, and generative UI for Angular, on LangGraph and AG-UI.',
2424
} as const;
2525
export {
2626
CODING_AGENT_PROMPT,

apps/website/src/styles/landing.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
margin-bottom: 24px;
2424
letter-spacing: -0.02em;
2525
}
26+
/* One line per thought; the space between the spans keeps textContent equal to HERO_H1. */
27+
.hero-heading-line {
28+
display: block;
29+
}
2630
.hero-subhead {
2731
font-family: var(--font-inter);
2832
font-size: var(--text-body-lg);

docs/gtm/messaging.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
## Positioning statement (durable)
66

7-
> For Angular teams building AI agents on LangGraph, AG-UI, or custom backends, Threadplane is the open-source thread plane for enterprise agents: it turns streaming agent events into production-ready Angular experiences: chat, durable threads, interrupts, subagents, planning, memory, generative UI, fallbacks, observability, and tests. Unlike React-first agent UI stacks or raw streaming SDKs, Threadplane is Angular-native, DI-friendly, design-system-first, self-hostable, and built for enterprise Angular apps.
7+
> For Angular teams building AI agents on LangGraph, AG-UI, or custom backends, Threadplane is the open-source thread-plane for agents: it turns streaming agent events into production-ready Angular experiences: chat, durable threads, interrupts, subagents, planning, memory, generative UI, fallbacks, observability, and tests. Unlike React-first agent UI stacks or raw streaming SDKs, Threadplane is Angular-native, DI-friendly, design-system-first, self-hostable, and built for enterprise Angular apps.
88
99
## Hero (locked for Spec 2 to implement)
1010

@@ -63,7 +63,7 @@ Hidden attribution fields (populated by URL params + referrer): `source_page`, `
6363

6464
## Launch narrative (Spec 6 spine)
6565

66-
> Angular teams are building agents, but the last mile is still messy: streaming state, tool progress, interrupts, durable threads, subagents, planning, memory, generated UI, fallbacks, and tests. React has mature examples. Backend agent frameworks have protocols. Angular teams need something that speaks Signals, DI, templates, standalone components, and enterprise design systems. Threadplane is the MIT-licensed thread plane for enterprise agents: it connects LangGraph, AG-UI, A2UI, and custom backends to production-ready Angular surfaces.
66+
> Angular teams are building agents, but the last mile is still messy: streaming state, tool progress, interrupts, durable threads, subagents, planning, memory, generated UI, fallbacks, and tests. React has mature examples. Backend agent frameworks have protocols. Angular teams need something that speaks Signals, DI, templates, standalone components, and enterprise design systems. Threadplane is the MIT-licensed thread-plane for agents: it connects LangGraph, AG-UI, A2UI, and custom backends to production-ready Angular surfaces.
6767
6868
## Avoid
6969

0 commit comments

Comments
 (0)