Files
cameleer-website/docs/superpowers/plans/2026-04-24-cameleer-website-copy-refresh.md
hsiegeln 2526b1f0fc docs: implementation plan for copy + brand refresh
13 tasks, each self-contained with exact file paths, final copy,
verification steps, and a commit at the end. Covers: logo + favicon
import (tasks 1-3), SEO meta (task 4), Hero static + rotating H1
(tasks 5-6), all five section copy rewrites (tasks 7-11), OG image
redesign (task 12), end-to-end verification (task 13). CSP-safe
rotation via Astro <script> bundling (script-src 'self' respected).
2026-04-24 23:34:38 +02:00

1089 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.