Files
cameleer-website/docs/superpowers/plans/2026-04-24-cameleer-website-copy-refresh.md

1089 lines
38 KiB
Markdown
Raw Normal View History

# Cameleer website copy + brand refresh — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Reposition the homepage from "observability tool" to "hosted Camel runtime with observability baked in." Refresh copy (3 rotating Hero headlines, two humor pops, plain-language tone), and replace the placeholder topographic-wave icon with the real camel product logo.
**Architecture:** Pure content + static asset refresh on an Astro 5 site. No new components, no new pages, no new deps. One small piece of client-side JS lives in the Hero (three-line rotation with reduced-motion guard and pause-on-interaction) — delivered via Astro's `<script>` block so it gets bundled and served same-origin (CSP is strict: `script-src 'self'` with no `'unsafe-inline'`; inline `<script>` tags would be blocked).
**Tech Stack:** Astro 5, Tailwind CSS (design tokens already defined), TypeScript, Vitest for logic tests, html-validate + linkinator for build-output checks, Playwright MCP available for browser verification.
**Reference spec:** `docs/superpowers/specs/2026-04-24-cameleer-website-copy-refresh-design.md`
---
## Ground rules
- **Dev server:** `npm run dev` → http://localhost:4321. Leave it running across tasks where possible.
- **Build check:** `npm run build` after any component edit. Treat warnings as errors in component files.
- **No placeholders:** every copy string in this plan is the final copy. Do not paraphrase.
- **Verify visually:** most tasks end with a Playwright navigate-and-screenshot check. The `playwright` MCP tools are available (`mcp__playwright__browser_navigate`, `mcp__playwright__browser_take_screenshot`).
- **Commit scope:** each task ends in a single focused commit. Do not batch.
- **CSP:** use Astro `<script>` blocks (default bundled mode). Never use `is:inline` on a `<script>`. Never use inline `onclick`/`onhover` handlers.
---
## Task 1: Import the real Cameleer product logo + icon set
**Files:**
- Create: `public/cameleer-logo.svg`
- Create: `public/cameleer-logo.png`
- Create: `public/icons/cameleer-16.png`
- Create: `public/icons/cameleer-32.png`
- Create: `public/icons/cameleer-48.png`
- Create: `public/icons/cameleer-180.png`
- Create: `public/icons/cameleer-192.png`
- Create: `public/icons/cameleer-512.png`
Assets come from the sibling `design-system` repo: `C:/Users/Hendrik/Documents/projects/design-system/assets/`.
- [ ] **Step 1: Create the `public/icons/` directory**
```bash
mkdir -p C:/Users/Hendrik/Documents/projects/cameleer-website/public/icons
```
- [ ] **Step 2: Copy the SVG and PNG logo variants**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
cp ../design-system/assets/cameleer-logo.svg public/cameleer-logo.svg
cp ../design-system/assets/cameleer-logo.png public/cameleer-logo.png
cp ../design-system/assets/cameleer-16.png public/icons/cameleer-16.png
cp ../design-system/assets/cameleer-32.png public/icons/cameleer-32.png
cp ../design-system/assets/cameleer-48.png public/icons/cameleer-48.png
cp ../design-system/assets/cameleer-180.png public/icons/cameleer-180.png
cp ../design-system/assets/cameleer-192.png public/icons/cameleer-192.png
cp ../design-system/assets/cameleer-512.png public/icons/cameleer-512.png
```
- [ ] **Step 3: Verify files landed**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
ls -la public/cameleer-logo.svg public/cameleer-logo.png public/icons/
```
Expected: 8 files listed, non-zero sizes. `cameleer-logo.svg` is ~1.5 MB (ship as-is per spec §3.1).
- [ ] **Step 4: Commit**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
git add public/cameleer-logo.svg public/cameleer-logo.png public/icons/
git commit -m "feat(brand): import real cameleer product logo + favicon set
Camel + cameleer figure on compass rose, amber on transparent. Imported
from design-system/assets. Replaces the placeholder topographic-wave icon
across favicon chain, header, and OG assets (subsequent tasks)."
```
---
## Task 2: Update BaseLayout favicon chain + delete placeholder
**Files:**
- Modify: `src/layouts/BaseLayout.astro` — swap the single-favicon line for a proper chain
- Delete: `public/favicon.svg` (placeholder 3-wavy-lines SVG)
- [ ] **Step 1: Replace the favicon `<link>` in BaseLayout**
In `src/layouts/BaseLayout.astro`, find this line:
```html
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
```
Replace with:
```html
<link rel="icon" type="image/svg+xml" href="/cameleer-logo.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/icons/cameleer-32.png" />
<link rel="apple-touch-icon" href="/icons/cameleer-180.png" />
```
- [ ] **Step 2: Delete the placeholder favicon**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
rm public/favicon.svg
```
- [ ] **Step 3: Build to confirm nothing references the deleted file**
```bash
npm run build
```
Expected: build succeeds, no 404s on `/favicon.svg` in the output.
- [ ] **Step 4: Verify the favicon loads in the dev server**
Start the dev server in the background if it isn't running:
```bash
npm run dev
```
Use Playwright MCP to verify:
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_evaluate → document.querySelector('link[rel="icon"][type="image/svg+xml"]').href
```
Expected: ends in `/cameleer-logo.svg` — and a GET for that URL returns 200 (check the Network tab with `mcp__playwright__browser_network_requests`).
- [ ] **Step 5: Commit**
```bash
git add src/layouts/BaseLayout.astro public/favicon.svg
git commit -m "feat(brand): wire favicon chain to real product logo
SVG primary + 32px PNG fallback + Apple touch icon. Removes the
placeholder 3-wavy-lines favicon."
```
---
## Task 3: Replace the inline SVG in SiteHeader with the real logo
**Files:**
- Modify: `src/components/SiteHeader.astro`
- [ ] **Step 1: Replace the inline `<svg>` block with an `<img>` referencing the real logo**
In `src/components/SiteHeader.astro`, find this block (lines ~714):
```astro
<svg width="28" height="28" viewBox="0 0 32 32" aria-hidden="true">
<rect width="32" height="32" rx="6" fill="#0c111a"/>
<g fill="none" stroke="#f0b429" stroke-width="1.6" stroke-linecap="round">
<path d="M4 10 Q10 6 16 12 T28 10"/>
<path d="M4 16 Q10 12 16 18 T28 16"/>
<path d="M4 22 Q10 18 16 24 T28 22"/>
</g>
</svg>
```
Replace with:
```astro
<img
src="/cameleer-logo.svg"
width="32"
height="32"
alt=""
decoding="async"
class="shrink-0"
/>
```
Rationale: `alt=""` is correct — the adjacent `<span>Cameleer</span>` wordmark provides the accessible label, and the `<a aria-label="Cameleer home">` wraps both. An `alt` on the image would cause a duplicate announcement.
- [ ] **Step 2: Verify in the dev server**
With `npm run dev` running:
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_take_screenshot → filename: hero-header.png
```
Expected: the header shows the amber camel-on-compass logo (32px) next to the "Cameleer" wordmark. No broken image icon.
- [ ] **Step 3: Commit**
```bash
git add src/components/SiteHeader.astro
git commit -m "feat(brand): swap header icon for real Cameleer logo
Placeholder 3-wavy-lines SVG replaced with the product logo
(camel + cameleer figure + compass rose)."
```
---
## Task 4: Update homepage title + meta description
**Files:**
- Modify: `src/pages/index.astro` — the `<title>` and `description` props drive every `<meta>` in the head
- [ ] **Step 1: Replace the title and description props**
In `src/pages/index.astro`, find:
```astro
<BaseLayout
title="Cameleer — Zero-code observability for Apache Camel"
description="See every route. Reach into every flow. Zero-code tracing, processor-level detail, and live control for Apache Camel — from a single -javaagent flag."
>
```
Replace with:
```astro
<BaseLayout
title="Cameleer — Run Apache Camel without running Apache Camel"
description="The hosted home for your Camel integrations — with deep tracing, replay, and live control built in. Because you chose Camel to stay free, not to stay up all night."
>
```
- [ ] **Step 2: Build and verify the rendered HTML**
```bash
npm run build
```
```bash
grep -o '<title>[^<]*</title>\|<meta name="description"[^>]*>' dist/index.html
```
Expected:
```
<title>Cameleer — Run Apache Camel without running Apache Camel</title>
<meta name="description" content="The hosted home for your Camel integrations — with deep tracing, replay, and live control built in. Because you chose Camel to stay free, not to stay up all night.">
```
- [ ] **Step 3: Commit**
```bash
git add src/pages/index.astro
git commit -m "feat(copy): update homepage title + meta description
Thesis: 'Run Apache Camel without running Apache Camel.' Reframes the
page from observability tool to hosted runtime platform for Camel."
```
---
## Task 5: Hero — static content rewrite (no rotation yet)
**Files:**
- Modify: `src/components/sections/Hero.astro`
This task rewrites the Hero markup to the new static content. Rotation is added in Task 6. Keeping the two changes separate makes each commit reviewable and keeps a bisection target if rotation regresses something.
- [ ] **Step 1: Rewrite the Hero component**
Replace the entire contents of `src/components/sections/Hero.astro` with:
```astro
---
import CTAButtons from '../CTAButtons.astro';
import RouteDiagram from '../RouteDiagram.astro';
import TopographicBg from '../TopographicBg.astro';
---
<section class="relative overflow-hidden border-b border-border">
<TopographicBg opacity={0.14} lines={10} />
<div class="relative max-w-content mx-auto px-6 pt-20 pb-24 md:pt-28 md:pb-32">
<div class="max-w-3xl">
<div class="flex items-center gap-3 mb-6">
<img
src="/cameleer-logo.svg"
width="48"
height="48"
alt=""
decoding="async"
class="shrink-0"
/>
<p class="text-accent font-mono text-xs tracking-[0.25em] uppercase">
Your camels called. They want a GPS.
</p>
</div>
<h1 class="text-display font-bold text-text mb-6">
Run Apache Camel without running Apache Camel.
</h1>
<p class="text-lg md:text-xl text-text-muted max-w-prose leading-relaxed mb-10">
The hosted home for your Camel integrations — with deep tracing, replay, and live control built in. Because you chose Camel to stay free, not to stay up all night.
</p>
<CTAButtons size="lg" />
</div>
<div class="mt-16 md:mt-20">
<RouteDiagram />
</div>
</div>
</section>
```
Changes vs current:
- Added 48px brand mark next to the kicker (per spec §3.4).
- Kicker text: `Observability · Apache Camel``Your camels called. They want a GPS.`
- H1: `See every route. / Reach into every flow.``Run Apache Camel without running Apache Camel.`
- Subline rewritten — no more `-javaagent` reference.
- [ ] **Step 2: Build to confirm it compiles**
```bash
npm run build
```
Expected: success, no warnings about missing props or broken imports.
- [ ] **Step 3: Visual check in dev server**
With `npm run dev` running:
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_take_screenshot → filename: hero-task5.png
```
Expected: amber camel mark (48px) next to the uppercase "YOUR CAMELS CALLED. THEY WANT A GPS." kicker. Headline reads "Run Apache Camel without running Apache Camel." Subline is the new plain-language version.
- [ ] **Step 4: Commit**
```bash
git add src/components/sections/Hero.astro
git commit -m "feat(copy): Hero static rewrite — new kicker, thesis H1, subline
Drops -javaagent from the hero. Adds the 48px product mark next to the
kicker. Rotation is added in the next commit."
```
---
## Task 6: Hero — three rotating H1 lines with fade, pause, and reduced-motion guard
**Files:**
- Modify: `src/components/sections/Hero.astro` — add two extra `<span>`s inside the H1, add `<style>` and `<script>` blocks
This task adds the rotation. All three lines render in the DOM. The visible one is controlled via a `data-active` attribute; CSS drives the fade. The script cycles `data-active` every 10 seconds, pauses on hover/focus, and does nothing if `prefers-reduced-motion: reduce`.
`aria-live="off"` on the rotation wrapper prevents assistive tech from announcing every swap. `aria-hidden="true"` on the two inactive lines avoids duplicate heading announcements.
- [ ] **Step 1: Replace the H1 + add style + script blocks**
In `src/components/sections/Hero.astro`, replace the current H1:
```astro
<h1 class="text-display font-bold text-text mb-6">
Run Apache Camel without running Apache Camel.
</h1>
```
With:
```astro
<h1
class="text-display font-bold text-text mb-6 hero-rotator"
aria-live="off"
data-hero-rotator
>
<span class="hero-line" data-active aria-hidden="false">Run Apache Camel without running Apache Camel.</span>
<span class="hero-line" aria-hidden="true">Camel integrations, minus the baggage.</span>
<span class="hero-line" aria-hidden="true">Your camels, our caravan. You just ride.</span>
</h1>
```
Then at the bottom of the file (after the closing `</section>`), add:
```astro
<style>
.hero-rotator {
position: relative;
display: block;
/* Reserve height for the tallest line so no layout shift on swap.
Two lines at current H1 size handles all three on most viewports. */
min-height: 2.2em;
}
.hero-line {
display: block;
opacity: 0;
transition: opacity 700ms ease-in-out;
/* Stack all lines on top of each other — only [data-active] is visible. */
position: absolute;
inset: 0;
}
.hero-line[data-active] {
opacity: 1;
position: relative;
}
@media (prefers-reduced-motion: reduce) {
.hero-line {
transition: none;
}
}
</style>
<script>
// Hero rotating headline. Bundled by Astro (CSP: script-src 'self').
const rotator = document.querySelector<HTMLElement>('[data-hero-rotator]');
if (rotator) {
const lines = Array.from(rotator.querySelectorAll<HTMLElement>('.hero-line'));
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!reduced && lines.length > 1) {
let index = 0;
let paused = false;
const pause = () => { paused = true; };
const resume = () => { paused = false; };
rotator.addEventListener('mouseenter', pause);
rotator.addEventListener('mouseleave', resume);
rotator.addEventListener('focusin', pause);
rotator.addEventListener('focusout', resume);
setInterval(() => {
if (paused) return;
lines[index].removeAttribute('data-active');
lines[index].setAttribute('aria-hidden', 'true');
index = (index + 1) % lines.length;
lines[index].setAttribute('data-active', '');
lines[index].setAttribute('aria-hidden', 'false');
}, 10000);
}
}
</script>
```
- [ ] **Step 2: Build to confirm the script is bundled (not inlined)**
```bash
npm run build
```
Then:
```bash
grep -c 'hero-rotator' dist/index.html
ls dist/_astro/*.js 2>&1 | head
```
Expected: the HTML contains the `data-hero-rotator` attribute. A hoisted JS file appears under `dist/_astro/`. The HTML should NOT contain an inline `<script>` block with the rotator code (Astro hoists `<script>` tags by default).
- [ ] **Step 3: Verify CSP compliance in the browser**
With `npm run dev` running:
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_console_messages
```
Expected: no `Content-Security-Policy` violation messages. (Note: CSP headers only apply to `preview`/prod; dev server doesn't enforce them — but the inline-vs-bundled distinction is a build-time property, so if Step 2 confirmed the script was hoisted, CSP will pass in prod.)
- [ ] **Step 4: Verify the rotation behavior visually**
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_evaluate →
Array.from(document.querySelectorAll('.hero-line')).map(l => ({
text: l.textContent?.trim(),
active: l.hasAttribute('data-active'),
ariaHidden: l.getAttribute('aria-hidden'),
}))
```
Expected at page load:
```js
[
{ text: 'Run Apache Camel without running Apache Camel.', active: true, ariaHidden: 'false' },
{ text: 'Camel integrations, minus the baggage.', active: false, ariaHidden: 'true' },
{ text: 'Your camels, our caravan. You just ride.', active: false, ariaHidden: 'true' },
]
```
Wait 11 seconds and re-run the evaluate. Expected: second entry now has `active: true, ariaHidden: 'false'`; first and third are inactive.
- [ ] **Step 5: Verify reduced-motion guard at the code level**
The Playwright MCP in this environment does not expose a media-query emulation tool, so the runtime check is split into two parts:
(a) **Code inspection** — re-read the `<script>` block and confirm:
- `const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;`
- The `setInterval` is inside `if (!reduced && lines.length > 1) { ... }` — so when `reduced` is true, the interval is never registered.
- The CSS `@media (prefers-reduced-motion: reduce) .hero-line { transition: none; }` — so even if a swap fired, it would be instant. Belt and suspenders.
(b) **Optional manual verification** — if you want a live check, toggle reduced-motion at the OS level:
- Windows: Settings → Accessibility → Visual effects → Animation effects: Off
- Then reload the page and wait ~15 seconds. First line should remain active.
If (a) matches the code you just wrote, (b) is optional — the guard is structurally correct and the CSS fallback makes it defensive.
- [ ] **Step 6: Commit**
```bash
git add src/components/sections/Hero.astro
git commit -m "feat(hero): rotate three positioning lines on a 10s cycle
All three lines render in the DOM; CSS drives the fade via data-active.
Reduced-motion users see the first line only (no interval, no fade).
Rotation pauses on hover and keyboard focus. aria-live=off on the
rotator so AT does not announce every swap; aria-hidden flips per-swap
to avoid duplicate heading announcements."
```
---
## Task 7: DualValueProps — three outcome-led tiles
**Files:**
- Modify: `src/components/sections/DualValueProps.astro`
Rewrite the three tile headlines and bodies. Outcome-led, no `-javaagent`, no "nanosecond", no "45+ EIP". Keep the existing card styling.
- [ ] **Step 1: Rewrite the `tiles` array**
In `src/components/sections/DualValueProps.astro`, replace the current `tiles` definition:
```ts
const tiles: Tile[] = [
{
outcome: 'Cut debugging time in half.',
capability:
'Every processor on every route, timed to the nanosecond. Choice branches, splits, multicasts, and error handlers preserved as a proper execution tree — not a pile of log lines.',
},
{
outcome: 'Ship integrations with confidence.',
capability:
'Capture real payloads and replay them on demand. Deep-trace a specific correlation ID across services. Push trace settings to a running agent without a redeploy.',
},
{
outcome: 'Keep what you have built.',
capability:
'One `-javaagent` flag. No code changes, no SDK, no framework lock-in. Native understanding of 45+ EIP node types across Apache Camel 4.x.',
},
];
```
With:
```ts
const tiles: Tile[] = [
{
outcome: 'Ship integrations, then sleep.',
capability:
'Every route, every processor, every exchange — traced automatically. When something breaks at 3 AM, the answer is already waiting for you. So you do not have to be.',
},
{
outcome: 'Debug in daylight.',
capability:
'Replay the exact exchange that failed. Follow a single request across services. See payloads before and after each processor. The pieces your ops team needs at 3 AM, captured already — so 3 AM stays quiet.',
},
{
outcome: 'Keep what you built. Keep what you chose.',
capability:
'You picked Apache Camel on purpose — open, portable, yours. Cameleer runs and understands your Camel apps as they are. No code changes, no SDK, no rewrite, no lock-in.',
},
];
```
Note: the template still renders `tile.capability` through a backtick-to-`<code>` replace. None of the new bodies use backticks, so the replace is a no-op. Keep the template untouched.
- [ ] **Step 2: Build**
```bash
npm run build
```
Expected: success.
- [ ] **Step 3: Visual check**
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_take_screenshot → filename: dualvalue.png
```
Expected: three tiles with the new outcome-led headlines and softened bodies. No backtick-code fragments visible. No mentions of "nanosecond", "-javaagent", "45+", or "EIP".
- [ ] **Step 4: Grep-confirm the removals**
```bash
grep -E 'nanosecond|javaagent|45\+|EIP node' dist/index.html || echo "CLEAN"
```
Expected: `CLEAN`.
- [ ] **Step 5: Commit**
```bash
git add src/components/sections/DualValueProps.astro
git commit -m "feat(copy): DualValueProps — outcome-led, plain language
Three tiles: ship-then-sleep, debug-in-daylight, keep-what-you-chose.
Drops -javaagent, nanosecond, and 45+ EIP node types from the landing
copy — those belong in docs."
```
---
## Task 8: HowItWorks — three softer steps, drop the bash snippet
**Files:**
- Modify: `src/components/sections/HowItWorks.astro`
- [ ] **Step 1: Rewrite the `steps` array and the section subtitle**
In `src/components/sections/HowItWorks.astro`, replace the `steps` constant and the subtitle paragraph.
The `steps` constant:
```ts
const steps: Step[] = [
{
n: '01',
title: 'Add the agent',
body: 'Drop the Cameleer agent JAR alongside your Camel app and start it with a single flag. That is the entire installation.',
code: 'java \\\n -javaagent:cameleer-agent.jar \\\n -jar your-camel-app.jar',
},
{
n: '02',
title: 'Launch your app',
body: 'Every route, processor, exchange, and route graph is discovered and reported automatically. Configurable redaction keeps sensitive fields out of the trace.',
},
{
n: '03',
title: 'See it in Mission Control',
body: 'Browse executions, tap live traffic, replay failed exchanges, and follow flows across services. Nothing to instrument, nothing to maintain.',
},
];
```
Becomes:
```ts
const steps: Step[] = [
{
n: '01',
title: 'Point us at your Camel app',
body: 'Drop it in, or connect one you already run. No code changes. No SDK. Nothing to rewrite.',
},
{
n: '02',
title: 'We take it from there',
body: 'Every route, every processor, every exchange — discovered and traced automatically. Sensitive fields are masked by default.',
},
{
n: '03',
title: 'Watch it run',
body: 'Browse executions, tap live traffic, replay failed exchanges, follow flows across services. Nothing to instrument. Nothing to maintain.',
},
];
```
The subtitle:
```astro
<p class="text-text-muted text-lg">Three steps. No code changes. Works across Camel 4.x.</p>
```
Becomes:
```astro
<p class="text-text-muted text-lg">Three steps. No code changes. Nothing to maintain.</p>
```
The `code?` field on Step 1 is gone; the `{step.code && (...)}` conditional in the template renders nothing for steps without code. No template change needed.
- [ ] **Step 2: Build**
```bash
npm run build
```
- [ ] **Step 3: Confirm the bash snippet is gone**
```bash
grep -E 'javaagent|cameleer-agent\.jar' dist/index.html || echo "CLEAN"
```
Expected: `CLEAN`.
- [ ] **Step 4: Visual check**
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_take_screenshot → filename: howitworks.png
```
Expected: three numbered cards with the new titles and bodies. No `<pre>` block in any card.
- [ ] **Step 5: Commit**
```bash
git add src/components/sections/HowItWorks.astro
git commit -m "feat(copy): HowItWorks — plain-language steps, bash snippet gone
Step 1 no longer shows java -javaagent:... on the marketing page; that
detail belongs in docs/install. Subtitle tightened to 'Nothing to
maintain.'"
```
---
## Task 9: WhyUs — softer, warmer bodies with 3-AM framing
**Files:**
- Modify: `src/components/sections/WhyUs.astro`
- [ ] **Step 1: Replace both tile bodies and the second tile's headline**
Find the first tile (lines ~1422):
```astro
<div class="rounded-lg border border-border bg-bg-elevated p-8">
<h3 class="text-xl font-bold text-text mb-4">Generic APMs do not understand Camel. Cameleer does.</h3>
<p class="text-text-muted leading-relaxed mb-4">
Our Java agent speaks 45+ Apache Camel EIP node types natively — choices, splits, multicasts, doTry, error handlers, dynamic endpoints, thread boundaries in async routes. It extracts your route topology as a first-class graph, not a pile of metrics.
</p>
<p class="text-text-muted leading-relaxed">
A bidirectional protocol lets the server push deep-trace requests, per-route recording toggles, and signed config changes back to running agents — turning passive observability into active control. Not something you build in a weekend.
</p>
</div>
```
Replace with:
```astro
<div class="rounded-lg border border-border bg-bg-elevated p-8">
<h3 class="text-xl font-bold text-text mb-4">Generic APMs do not understand Camel. Cameleer does.</h3>
<p class="text-text-muted leading-relaxed mb-4">
Most monitoring tools see your app as a Java process and a pile of HTTP calls. Cameleer understands that you are running a Camel app — choices, splits, multicasts, error handlers, and every other EIP pattern as first-class citizens.
</p>
<p class="text-text-muted leading-relaxed">
So when you ask "why did this exchange fail?", you get an answer, not a log tail. And you can reach back into a running app to replay a message, deep-trace a correlation ID, or toggle recording — observability that does things, not just shows them.
</p>
</div>
```
Find the second tile (lines ~2331):
```astro
<div class="rounded-lg border border-border bg-bg-elevated p-8">
<h3 class="text-xl font-bold text-text mb-4">Built by people who have shipped this class of product before.</h3>
<p class="text-text-muted leading-relaxed mb-4">
The Cameleer team spent years building and supporting integration monitoring for banks, insurers, and logistics operators. We know what integration teams actually need at 3 AM — and what they never use.
</p>
<p class="text-text-muted leading-relaxed">
Cameleer is what we would build today, purpose-built for Apache Camel — no legacy, no retrofit, no assumptions about a generic middleware platform.
</p>
</div>
```
Replace with:
```astro
<div class="rounded-lg border border-border bg-bg-elevated p-8">
<h3 class="text-xl font-bold text-text mb-4">Built by people who know what 3 AM looks like.</h3>
<p class="text-text-muted leading-relaxed mb-4">
We spent years building integration monitoring for banks, insurers, and logistics operators — the kind of shops where a stuck exchange at 3 AM means someone's phone is ringing. We know what integration teams actually need then, and what they never use.
</p>
<p class="text-text-muted leading-relaxed">
Cameleer is what we would build today, purpose-built for Apache Camel. No legacy, no retrofit, no assumptions about a generic middleware platform.
</p>
</div>
```
Keep the existing comment block at the top of the file (trademark review note).
- [ ] **Step 2: Build**
```bash
npm run build
```
- [ ] **Step 3: Confirm the removals**
```bash
grep -E '45\+|bidirectional protocol|signed config changes|deep-trace requests' dist/index.html || echo "CLEAN"
```
Expected: `CLEAN`.
- [ ] **Step 4: Commit**
```bash
git add src/components/sections/WhyUs.astro
git commit -m "feat(copy): WhyUs — warmer language, 3-AM framing
Tile 2 headline now 'Built by people who know what 3 AM looks like.'
Bodies soften 'bidirectional protocol / signed config' into plain-value
language. nJAMS-legacy trademark review note preserved."
```
---
## Task 10: PricingTeaser — subline tweak
**Files:**
- Modify: `src/components/sections/PricingTeaser.astro`
- [ ] **Step 1: Replace the subline paragraph**
Find (lines ~5255):
```astro
<p class="text-text-muted text-lg">
No credit card for the trial.
<a href="/pricing" class="text-accent hover:underline">See full comparison →</a>
</p>
```
Replace with:
```astro
<p class="text-text-muted text-lg">
No credit card. No sales call. Just a working trial in ten minutes.
<a href="/pricing" class="text-accent hover:underline">See full comparison →</a>
</p>
```
Tier cards and prices unchanged.
- [ ] **Step 2: Build**
```bash
npm run build
```
- [ ] **Step 3: Commit**
```bash
git add src/components/sections/PricingTeaser.astro
git commit -m "feat(copy): PricingTeaser — 'no credit card, no sales call'
Subline slightly warmer and more concrete ('a working trial in ten
minutes'). Tier cards untouched."
```
---
## Task 11: FinalCTA — second humor pop
**Files:**
- Modify: `src/components/sections/FinalCTA.astro`
- [ ] **Step 1: Replace the headline and subline**
Find:
```astro
<h2 class="text-display font-bold text-text mb-6">
Start seeing your routes.
</h2>
<p class="text-lg md:text-xl text-text-muted max-w-prose mx-auto mb-10">
14-day free trial. Your first app, instrumented and live in under 10 minutes.
</p>
```
Replace with:
```astro
<h2 class="text-display font-bold text-text mb-6">
Your camels called. Time to ride.
</h2>
<p class="text-lg md:text-xl text-text-muted max-w-prose mx-auto mb-10">
14-day free trial. Your first Camel app, hosted, traced, and running in under ten minutes. No code changes. No camels harmed.
</p>
```
CTAButtons block unchanged.
- [ ] **Step 2: Build**
```bash
npm run build
```
- [ ] **Step 3: Visual check**
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_take_screenshot → filename: finalcta.png
```
Expected: large centered "Your camels called. Time to ride." over the topographic background, subline ends with "No camels harmed.", CTA buttons still work.
- [ ] **Step 4: Commit**
```bash
git add src/components/sections/FinalCTA.astro
git commit -m "feat(copy): FinalCTA — 'Your camels called. Time to ride.'
Second humor pop (pairing with the Hero kicker). Subline adds the
tasteful-absurd 'No camels harmed.' closer."
```
---
## Task 12: Redesign OG image around the new thesis
**Files:**
- Modify: `public/og-image.svg` — full rewrite
Target: 1200×630, solid dark background (`#060a13`), amber accents (`#f0b429`), centered layout with the real logo + the thesis headline + a short subhead.
- [ ] **Step 1: Read the current OG image to understand conventions**
```bash
cat C:/Users/Hendrik/Documents/projects/cameleer-website/public/og-image.svg
```
Note the existing dimensions, font references, and colors, so the replacement keeps the same structural shape.
- [ ] **Step 2: Replace the file with the new design**
Write the following to `public/og-image.svg`:
```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" width="1200" height="630">
<rect width="1200" height="630" fill="#060a13"/>
<!-- Subtle topographic lines -->
<g fill="none" stroke="#f0b429" stroke-width="1.2" stroke-linecap="round" opacity="0.10">
<path d="M0 140 Q200 80 400 160 T800 140 T1200 160"/>
<path d="M0 250 Q200 190 400 270 T800 250 T1200 270"/>
<path d="M0 360 Q200 300 400 380 T800 360 T1200 380"/>
<path d="M0 470 Q200 410 400 490 T800 470 T1200 490"/>
</g>
<!-- Product mark (fallback: amber circle w/ wordmark — real PNG logo embedded would exceed OG size budget) -->
<g transform="translate(90, 110)">
<circle cx="60" cy="60" r="58" fill="none" stroke="#f0b429" stroke-width="2"/>
<text x="60" y="74" text-anchor="middle" font-family="DM Sans, system-ui, sans-serif" font-size="40" font-weight="700" fill="#f0b429">C</text>
</g>
<text x="220" y="190" font-family="DM Sans, system-ui, sans-serif" font-size="28" font-weight="600" fill="#f0b429" letter-spacing="3">CAMELEER</text>
<text x="90" y="340" font-family="DM Sans, system-ui, sans-serif" font-size="64" font-weight="700" fill="#f4f5f7">Run Apache Camel</text>
<text x="90" y="420" font-family="DM Sans, system-ui, sans-serif" font-size="64" font-weight="700" fill="#f4f5f7">without running Apache Camel.</text>
<text x="90" y="500" font-family="DM Sans, system-ui, sans-serif" font-size="28" font-weight="400" fill="#a0a8b8">The hosted home for your Camel integrations.</text>
<text x="90" y="540" font-family="DM Sans, system-ui, sans-serif" font-size="28" font-weight="400" fill="#a0a8b8">Deep tracing, replay, and live control — built in.</text>
</svg>
```
Rationale for the "C" fallback mark: the real product PNG logo at OG resolution would bloat the SVG past reasonable social-card budgets, and embedding a raster inside SVG is awkward. The amber circle-C on topographic lines reads correctly at the common 600×315 OG thumbnail render.
- [ ] **Step 3: Verify the SVG renders**
Open the file in a browser or image viewer to confirm it renders at 1200×630 and the headline doesn't overflow.
```
mcp__playwright__browser_navigate → http://localhost:4321/og-image.svg
mcp__playwright__browser_take_screenshot → filename: og-image.png
```
Expected: centered dark card, amber topographic lines, amber circle "C" mark top-left, "Run Apache Camel / without running Apache Camel." as the main text, softened subhead below.
- [ ] **Step 4: Commit**
```bash
git add public/og-image.svg
git commit -m "feat(brand): redesign OG image around new thesis
1200x630, solid #060a13 ground, amber topographic lines, circle-C mark,
headline 'Run Apache Camel without running Apache Camel.' plus short
subhead. The full camel-compass product logo is not embedded — raster
inside SVG at OG size would bloat the asset. Circle-C wordmark reads
cleanly at the 600x315 thumbnail render."
```
---
## Task 13: End-to-end verification
**Files:** none modified; verification-only.
- [ ] **Step 1: Clean build + run all static checks**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
rm -rf dist
npm run build
npm run test
npm run lint:html
npm run lint:links
```
Expected: all green. `lint:html` checks the built HTML against `.htmlvalidate.json`. `lint:links` walks internal links in the built output.
- [ ] **Step 2: Full-page visual capture in the dev server**
```bash
npm run dev
```
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_resize → width: 1440, height: 900
mcp__playwright__browser_take_screenshot → filename: homepage-desktop.png, fullPage: true
mcp__playwright__browser_resize → width: 375, height: 812
mcp__playwright__browser_take_screenshot → filename: homepage-mobile.png, fullPage: true
```
Visual review checklist — walk through each screenshot and confirm:
- [ ] Header: amber camel-on-compass logo + "Cameleer" wordmark, nav link "Pricing", CTA buttons on the right.
- [ ] Hero: 48px brand mark next to the "YOUR CAMELS CALLED. THEY WANT A GPS." kicker. Headline reads the current rotation line (one of the three). Subline starts with "The hosted home for your Camel integrations".
- [ ] DualValueProps: three tiles with the new headlines ("Ship integrations, then sleep.", "Debug in daylight.", "Keep what you built. Keep what you chose.").
- [ ] HowItWorks: three cards with "Point us at your Camel app", "We take it from there", "Watch it run". No `<pre>` bash snippet anywhere.
- [ ] WhyUs: tile 2 headline reads "Built by people who know what 3 AM looks like."
- [ ] PricingTeaser: subline reads "No credit card. No sales call. Just a working trial in ten minutes."
- [ ] FinalCTA: "Your camels called. Time to ride." + subline ending in "No camels harmed."
- [ ] **Step 3: Observe rotation live**
With the browser still open, wait ~25 seconds on the homepage and watch the H1 cycle. Expected order:
1. Run Apache Camel without running Apache Camel.
2. Camel integrations, minus the baggage.
3. Your camels, our caravan. You just ride.
4. (wraps back to #1)
- [ ] **Step 4: Confirm no forbidden terms appear in the built HTML**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
grep -i -E 'javaagent|bytebuddy|nanosecond|45\+ EIP|\-jar your-camel-app' dist/index.html || echo "CLEAN"
```
Expected: `CLEAN`. If anything shows up, the corresponding earlier task regressed — re-open that task's step that removed the term.
- [ ] **Step 5: Confirm the real logo assets are actually reachable**
```bash
cd C:/Users/Hendrik/Documents/projects/cameleer-website
for path in /cameleer-logo.svg /icons/cameleer-32.png /icons/cameleer-180.png; do
curl -sI "http://localhost:4321$path" | head -1
done
```
Expected: each line begins with `HTTP/1.1 200`.
- [ ] **Step 6: Confirm no console errors or CSP violations in `preview` mode**
```bash
npm run preview
```
Then:
```
mcp__playwright__browser_navigate → http://localhost:4321
mcp__playwright__browser_console_messages
```
Expected: no messages with level `error`. `preview` mode emits the real CSP headers, so this is the definitive CSP check.
- [ ] **Step 7: No commit**
This is verification only. If any step fails, it points to a regression in an earlier task — fix it there with an amended commit or a follow-up fix commit in the relevant task's scope, not as a general cleanup.
---
## Spec coverage verification (self-review)
| Spec section | Covered by task |
|---|---|
| §2.1 new thesis in copy | Task 4 (title), Task 5 (Hero H1 default), Task 6 (rotation) |
| §2.2 three rotating lines + behavior + accessibility | Task 6 |
| §2.3 forbidden terms | Tasks 4, 5, 7, 8, 9 — each task removes specific terms; Task 13 Step 4 greps the final HTML |
| §3.1 import asset list | Task 1 |
| §3.2 header icon swap | Task 3 |
| §3.3 favicon chain + delete placeholder | Task 2 |
| §3.4 Hero brand mark (48px next to kicker) | Task 5 |
| §3.5 OG image redesign | Task 12 |
| §4.1 Hero copy (kicker, H1, subline, remove `-javaagent`) | Tasks 5 + 6 |
| §4.2 DualValueProps rewrite | Task 7 |
| §4.3 HowItWorks rewrite + drop bash snippet | Task 8 |
| §4.4 WhyUs softening + tile 2 headline | Task 9 |
| §4.5 PricingTeaser subline tweak | Task 10 |
| §4.6 FinalCTA humor pop | Task 11 |
All spec sections are covered by at least one task.