Compare commits

...

10 Commits

Author SHA1 Message Date
hsiegeln
8dec3e792a chore(sections): delete retired DualValueProps + ProductShowcase
Some checks failed
ci / build-test (push) Failing after 3m44s
These two sections were collapsed into ThreeAmWalkthrough.astro
(Task 3). No remaining consumers — removed from the tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:37:33 +02:00
hsiegeln
9cded54ce3 feat(homepage): wire SocialProofStrip + ThreeAmWalkthrough
Updates the homepage section order to the proof-first arc:
  Hero → SocialProofStrip → ThreeAmWalkthrough → HowItWorks
  → WhyUs → PricingTeaser → FinalCTA

The retired DualValueProps and ProductShowcase imports are dropped
here; the unused .astro files themselves are deleted in Task 11.

Page <title> + <meta description> updated to lead with the new H1.

Verified: dist/index.html contains the #walkthrough anchor target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:37:17 +02:00
hsiegeln
21c1122369 refactor(pricing-page): rename tiers Trial/Starter/Scale/Enterprise
Customer-facing tier names replace the internally-coded
MID/HIGH/BUSINESS labels. Pricing structure (envs, apps,
retention, features) is unchanged. CTA labels updated to match.

The 'Everything in X' feature lines reference the new neighbour
names. Footer note 'HIGH and BUSINESS' updated to 'Scale and
Enterprise'.

Verified: dist/ contains no remaining MID/HIGH/BUSINESS strings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:36:43 +02:00
hsiegeln
5f06e5ccad refactor(pricing-teaser): rename tiers, show only 2 cards
- Tier rename: MID → Starter (Scale and Enterprise live on /pricing).
- Homepage shows Trial + Starter only. Starter retains the
  ★ MOST POPULAR ribbon.
- 'See full comparison →' inline link replaced by a clearer
  'See all plans (Scale, Enterprise) →' line below the cards.
- Trial card price stays 'Free'; the tier name stays honest about
  the 14-day cap.

The full /pricing.astro page still shows all four renamed tiers —
updated separately in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:36:07 +02:00
hsiegeln
04b930de62 refactor(final-cta): bookend the hero, drop camel pun
H2 now echoes the Hero (intentional bookend pattern). Sub line
loses the 'No camels harmed' aside. Single primary CTA — no
secondary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:35:41 +02:00
hsiegeln
b1b6b52f3f refactor(why-us): drop 03:00 watermark, reword card 2
The decorative giant '03:00' watermark on card 2 plus its 'live'
ops-desk timestamp gimmick was the third repetition of the 3 AM
metaphor on the homepage — the post-launch review flagged that
five hits turns a sharp pain point into a slogan.

Card 2 reworded to lead with 'operated integration in production
for 15 years' — same pedigree claim, no second 3 AM reference.
The walkthrough section already does the 3 AM beat in full.

Card 1 unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:35:24 +02:00
hsiegeln
0ad067847c refactor(how-it-works): slim repetitive 'no SDK' boilerplate
The 'no code changes / no SDK / no rewrite' line is already said
clearly in the Hero subhead and the WhyUs cards. Repeating it on
step 1 of HowItWorks adds nothing. Step 3's tail 'Nothing to
instrument. Nothing to maintain.' is two sentences saying the
same thing — both removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:34:58 +02:00
hsiegeln
d67a89bacb feat(hero): single H1, annotation pins, microline, anchor CTA
- Drop the rotating headline and its <script> block
- Replace with single category-defining H1: 'Ship Camel integrations.
  Sleep through the night.'
- Add price microline under the CTAs (14-day trial · from €20/mo)
- Replace 'Sign in' secondary CTA with 'See it in action ↓' anchor
  to #walkthrough
- Add three numbered annotation pins overlaid on the screenshot,
  with a 3-up legend below the image (correlation ID, failure
  context, error pinned)

The eyebrow pill is retained — the only surviving camel pun on
the homepage per the pun-budget decision in the spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:34:37 +02:00
hsiegeln
54bbb46755 feat(sections): add ThreeAmWalkthrough component
Replaces DualValueProps + ProductShowcase with a single before/after
split: a styled <pre> block (the 'without' state) next to the
existing /product/error-detail.png screenshot (the 'with' state).
Three short callouts below.

Section anchor #walkthrough is the target for the Hero's
'See it in action ↓' secondary CTA (added in Task 4).

The 'without' panel is implemented as a styled <pre> per the spec —
no asset production required. A future phase may swap to a recorded
terminal screencap; that swap is a one-component change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:33:50 +02:00
hsiegeln
29c2d13776 feat(sections): add SocialProofStrip component
Founder pedigree quote plus design-partner mailto CTA.
Uses auth.salesEmail (not auth.salesMailto) so we can pass a subject.

Two PENDING gates documented in the component:
  - [Founder Name] placeholder
  - 'ex-nJAMS' wording subject to trademark clearance

Component is created but not yet wired into index.astro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 02:33:07 +02:00
11 changed files with 225 additions and 276 deletions

View File

@@ -1,62 +0,0 @@
---
interface Tile {
outcome: string;
capability: string;
}
// tile.capability is a compile-time constant defined below — never feed
// user-supplied or CMS content into set:html further down (XSS risk).
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.',
},
];
---
<section class="border-b border-border">
<div class="max-w-content mx-auto px-6 py-20 md:py-24">
<div class="grid md:grid-cols-3 gap-6 md:gap-8">
{tiles.map((tile, i) => (
<div
class="tile rounded-lg border border-border bg-bg-elevated p-7 md:p-8 transition-all duration-200 ease-out hover:-translate-y-0.5 hover:border-accent/40 hover:shadow-[0_12px_32px_-12px_rgba(240,180,41,0.18)]"
style={`--tile-delay:${i * 110}ms`}
>
<h2 class="text-xl md:text-2xl font-bold text-text mb-3 leading-snug">
{tile.outcome}
</h2>
<p class="text-text-muted leading-relaxed" set:html={tile.capability.replace(/`([^`]+)`/g, '<code class="font-mono text-accent bg-bg border border-border rounded px-1 py-0.5 text-sm">$1</code>')}></p>
</div>
))}
</div>
</div>
</section>
<style>
@keyframes tile-rise {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: translateY(0); }
}
.tile {
opacity: 0;
animation: tile-rise 520ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
animation-delay: var(--tile-delay, 0ms);
}
@media (prefers-reduced-motion: reduce) {
.tile {
opacity: 1;
animation: none;
transition: none;
}
}
</style>

View File

@@ -6,13 +6,13 @@ import TopographicBg from '../TopographicBg.astro';
<TopographicBg opacity={0.18} lines={6} /> <TopographicBg opacity={0.18} lines={6} />
<div class="relative max-w-content mx-auto px-6 py-24 md:py-32 text-center"> <div class="relative max-w-content mx-auto px-6 py-24 md:py-32 text-center">
<h2 class="text-display font-bold text-text mb-6"> <h2 class="text-display font-bold text-text mb-6">
Your camels called. Time to ride. Ship integrations. Sleep through the night.
</h2> </h2>
<p class="text-lg md:text-xl text-text-muted max-w-prose mx-auto mb-10"> <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. 14-day free trial. Your first Camel app, hosted, traced, and running in under ten minutes. No code changes.
</p> </p>
<div class="flex justify-center"> <div class="flex justify-center">
<CTAButtons size="lg" /> <CTAButtons size="lg" showSecondary={false} />
</div> </div>
</div> </div>
</section> </section>

View File

@@ -2,6 +2,19 @@
import CTAButtons from '../CTAButtons.astro'; import CTAButtons from '../CTAButtons.astro';
import TopographicBg from '../TopographicBg.astro'; import TopographicBg from '../TopographicBg.astro';
import Lightbox from '../Lightbox.astro'; import Lightbox from '../Lightbox.astro';
interface Pin {
label: string;
body: string;
top: string;
left: string;
}
const pins: Pin[] = [
{ label: '01', body: 'Correlation ID — click to follow one exchange across services.', top: '14%', left: '12%' },
{ label: '02', body: 'Failure in context — circuit breaker tripped, fallback ran, tried backend:80.', top: '46%', left: '52%' },
{ label: '03', body: 'Full error pinned — exception, stack trace, headers, payload.', top: '78%', left: '78%' },
];
--- ---
<section class="relative overflow-hidden border-b border-border"> <section class="relative overflow-hidden border-b border-border">
<TopographicBg opacity={0.22} lines={11} /> <TopographicBg opacity={0.22} lines={11} />
@@ -22,19 +35,20 @@ import Lightbox from '../Lightbox.astro';
<span aria-hidden="true" class="text-base">✦</span> <span aria-hidden="true" class="text-base">✦</span>
Your camels called. They want a GPS. Your camels called. They want a GPS.
</p> </p>
<h1 <h1 class="font-bold text-text mb-6 hero-h1">
class="font-bold text-text mb-6 hero-rotator" Ship Camel integrations. Sleep through the night.
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> </h1>
<p class="text-lg md:text-xl text-text-muted max-w-prose leading-relaxed mb-10"> <p class="text-lg md:text-xl text-text-muted max-w-prose leading-relaxed mb-8">
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. Cameleer is the hosted runtime and observability platform for Apache Camel — auto-traced, replay-ready, cross-service correlated. The 3 AM page becomes a 30-second answer.
</p>
<CTAButtons
size="lg"
secondaryLabel="See it in action ↓"
secondaryHref="#walkthrough"
/>
<p class="mt-4 font-mono text-xs text-text-faint">
14-day trial · from €20/mo · no credit card
</p> </p>
<CTAButtons size="lg" />
</div> </div>
<div class="lg:col-span-7 relative"> <div class="lg:col-span-7 relative">
<div class="hero-shot relative rounded-lg border border-border-strong bg-bg-elevated overflow-hidden"> <div class="hero-shot relative rounded-lg border border-border-strong bg-bg-elevated overflow-hidden">
@@ -46,7 +60,24 @@ import Lightbox from '../Lightbox.astro';
loading="eager" loading="eager"
/> />
<div class="absolute inset-0 ring-1 ring-inset ring-accent/10 pointer-events-none rounded-lg"></div> <div class="absolute inset-0 ring-1 ring-inset ring-accent/10 pointer-events-none rounded-lg"></div>
{pins.map((pin) => (
<span
aria-hidden="true"
class="hero-pin absolute inline-flex items-center justify-center w-7 h-7 rounded-full bg-accent text-bg font-mono text-xs font-bold pointer-events-none"
style={`top:${pin.top};left:${pin.left}`}
>
{pin.label}
</span>
))}
</div> </div>
<ul class="hero-pin-legend mt-5 grid sm:grid-cols-3 gap-3 text-text-muted">
{pins.map((pin) => (
<li class="flex items-start gap-2 text-sm leading-snug">
<span class="font-mono text-accent text-xs mt-0.5">{pin.label}</span>
<span>{pin.body}</span>
</li>
))}
</ul>
<div aria-hidden="true" class="hero-shot-glow"></div> <div aria-hidden="true" class="hero-shot-glow"></div>
</div> </div>
</div> </div>
@@ -54,36 +85,21 @@ import Lightbox from '../Lightbox.astro';
</section> </section>
<style> <style>
/* Rotating H1 — fluid size + fade transition */ .hero-h1 {
.hero-rotator {
font-size: clamp(2.25rem, 4.5vw, 4rem); font-size: clamp(2.25rem, 4.5vw, 4rem);
line-height: 1.05; line-height: 1.05;
letter-spacing: -0.02em; letter-spacing: -0.02em;
position: relative;
display: block;
/* Reserve enough vertical space that a 2-line wrap of the longest line
does not push the page on swap (mobile wraps line 1 to 2 lines). */
min-height: 2.5em;
} }
.hero-line {
display: block;
opacity: 0;
transition: opacity 700ms ease-in-out;
position: absolute;
inset: 0;
}
.hero-line[data-active] {
opacity: 1;
position: relative;
}
/* Product screenshot frame — subtle dropshadow + amber glow behind */
.hero-shot { .hero-shot {
box-shadow: box-shadow:
0 1px 0 rgba(240, 180, 41, 0.08) inset, 0 1px 0 rgba(240, 180, 41, 0.08) inset,
0 30px 60px -20px rgba(0, 0, 0, 0.6), 0 30px 60px -20px rgba(0, 0, 0, 0.6),
0 10px 25px -10px rgba(0, 0, 0, 0.5); 0 10px 25px -10px rgba(0, 0, 0, 0.5);
} }
.hero-pin {
box-shadow: 0 0 0 4px rgba(240, 180, 41, 0.22), 0 4px 10px -2px rgba(0, 0, 0, 0.5);
transform: translate(-50%, -50%);
}
.hero-shot-glow { .hero-shot-glow {
position: absolute; position: absolute;
inset: 10% -5% 10% -5%; inset: 10% -5% 10% -5%;
@@ -96,7 +112,6 @@ import Lightbox from '../Lightbox.astro';
z-index: -1; z-index: -1;
} }
/* Slow sway on the mark — tasteful, not distracting */
@keyframes hero-mark-sway { @keyframes hero-mark-sway {
0%, 100% { transform: translateY(0) rotate(0deg); } 0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-2px) rotate(-1.5deg); } 50% { transform: translateY(-2px) rotate(-1.5deg); }
@@ -107,34 +122,6 @@ import Lightbox from '../Lightbox.astro';
} }
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.hero-line { transition: none; }
.hero-mark { animation: none; } .hero-mark { animation: none; }
} }
</style> </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>

View File

@@ -10,7 +10,7 @@ const steps: Step[] = [
{ {
n: '01', n: '01',
title: 'Point us at your Camel app', 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.', body: 'Drop it in, or connect one you already run. No code changes.',
}, },
{ {
n: '02', n: '02',
@@ -20,7 +20,7 @@ const steps: Step[] = [
{ {
n: '03', n: '03',
title: 'Watch it run', title: 'Watch it run',
body: 'Browse executions, tap live traffic, replay failed exchanges, follow flows across services. Nothing to instrument. Nothing to maintain.', body: 'Browse executions, tap live traffic, replay failed exchanges, follow flows across services.',
}, },
]; ];
--- ---
@@ -29,7 +29,7 @@ const steps: Step[] = [
<div class="max-w-2xl mb-16"> <div class="max-w-2xl mb-16">
<p class="text-cyan font-mono text-xs tracking-[0.25em] uppercase mb-4">For engineers</p> <p class="text-cyan font-mono text-xs tracking-[0.25em] uppercase mb-4">For engineers</p>
<h2 class="text-hero font-bold text-text mb-4">How it works</h2> <h2 class="text-hero font-bold text-text mb-4">How it works</h2>
<p class="text-text-muted text-lg">Three steps. No code changes. Nothing to maintain.</p> <p class="text-text-muted text-lg">Three steps. Nothing to maintain.</p>
</div> </div>
<ol class="grid md:grid-cols-3 gap-6 md:gap-8"> <ol class="grid md:grid-cols-3 gap-6 md:gap-8">
{steps.map((step) => ( {steps.map((step) => (

View File

@@ -21,27 +21,13 @@ const tiers: Tier[] = [
cta: 'Start free trial', cta: 'Start free trial',
}, },
{ {
name: 'MID', name: 'Starter',
price: '20 € /mo', price: '20 € /mo',
sub: '2 environments · 10 apps · 7-day retention', sub: '2 environments · 10 apps · 7-day retention',
href: auth.signUpUrl, href: auth.signUpUrl,
cta: 'Start on MID', cta: 'Start on Starter',
highlight: true, highlight: true,
}, },
{
name: 'HIGH',
price: 'Contact',
sub: 'Unlimited envs · 50 apps · 90-day retention · Debugger, Replay',
href: auth.salesMailto,
cta: 'Talk to sales',
},
{
name: 'BUSINESS',
price: 'Contact',
sub: 'Unlimited everything · 365-day retention · all features',
href: auth.salesMailto,
cta: 'Talk to sales',
},
]; ];
--- ---
<section class="border-b border-border"> <section class="border-b border-border">
@@ -51,15 +37,14 @@ const tiers: Tier[] = [
<h2 class="text-hero font-bold text-text mb-4">Start free. Grow when you need to.</h2> <h2 class="text-hero font-bold text-text mb-4">Start free. Grow when you need to.</h2>
<p class="text-text-muted text-lg"> <p class="text-text-muted text-lg">
No credit card. No sales call. Just a working trial in ten minutes. 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> </p>
</div> </div>
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-5 lg:items-stretch"> <div class="grid md:grid-cols-2 gap-5 lg:items-stretch max-w-3xl">
{tiers.map((tier) => ( {tiers.map((tier) => (
<div <div
class={`relative rounded-lg bg-bg-elevated p-6 flex flex-col transition-all duration-200 ease-out hover:-translate-y-0.5 class={`relative rounded-lg bg-bg-elevated p-6 flex flex-col transition-all duration-200 ease-out hover:-translate-y-0.5
${tier.highlight ${tier.highlight
? 'ring-2 ring-accent shadow-[0_20px_50px_-20px_rgba(240,180,41,0.35)] lg:-translate-y-2 lg:pt-8 lg:pb-7' ? 'ring-2 ring-accent shadow-[0_20px_50px_-20px_rgba(240,180,41,0.35)] md:-translate-y-2 md:pt-8 md:pb-7'
: 'border border-border hover:border-accent/40 hover:shadow-[0_12px_32px_-12px_rgba(240,180,41,0.18)]'}`} : 'border border-border hover:border-accent/40 hover:shadow-[0_12px_32px_-12px_rgba(240,180,41,0.18)]'}`}
> >
{tier.highlight && ( {tier.highlight && (
@@ -85,5 +70,10 @@ const tiers: Tier[] = [
</div> </div>
))} ))}
</div> </div>
<p class="mt-8 font-mono text-sm text-text-muted">
<a href="/pricing" class="text-cyan hover:text-accent transition-colors">
See all plans (Scale, Enterprise) →
</a>
</p>
</div> </div>
</section> </section>

View File

@@ -1,91 +0,0 @@
---
import TopographicBg from '../TopographicBg.astro';
import Lightbox from '../Lightbox.astro';
interface Callout {
title: string;
body: string;
}
const callouts: Callout[] = [
{
title: 'Cross-service correlation.',
body: 'Every exchange carries its correlation ID forward. One click jumps to what the downstream route did with the same message — 610 ms later.',
},
{
title: 'Runtime detail, not guesswork.',
body: 'Circuit breaker tripped. Fallback path ran. The request tried to reach backend:80. The kind of pieces a 3 AM page actually needs — already captured.',
},
{
title: 'The whole story of a failure.',
body: 'Exception class, message, stack trace, headers, payload — all pinned to the exchange. No log-grepping tour. No SSH into the pod.',
},
];
---
<section class="relative overflow-hidden border-b border-border bg-bg">
<TopographicBg opacity={0.14} lines={7} />
<div class="relative max-w-content mx-auto px-6 py-24 md:py-32">
<div class="max-w-3xl mb-14 md:mb-20">
<p class="text-cyan font-mono text-xs tracking-[0.25em] uppercase mb-4">When it breaks</p>
<h2 class="text-hero font-bold text-text mb-5">
When something breaks, the answer is already waiting.
</h2>
<p class="text-lg text-text-muted leading-relaxed">
Follow a single exchange from ingestion to failure. See the route it took, the fallback that ran, the stack trace, the correlated downstream work — in one place. Without writing a line of tracing code.
</p>
</div>
<div class="grid lg:grid-cols-12 gap-10 lg:gap-14 items-start">
<figure class="lg:col-span-8 relative">
<div class="showcase-shot relative rounded-lg border border-border-strong bg-bg-elevated overflow-hidden">
<Lightbox
src="/product/error-detail.png"
alt="Cameleer Mission Control — complex fulfillment route with circuit breaker, fallback, correlated audit route, and full error context"
width={1920}
height={945}
loading="lazy"
/>
<div class="absolute inset-0 ring-1 ring-inset ring-accent/10 pointer-events-none rounded-lg"></div>
</div>
<div aria-hidden="true" class="showcase-shot-glow"></div>
<figcaption class="sr-only">Screenshot of a failed exchange in Cameleer, showing the full execution graph, fallback path, and exception context.</figcaption>
</figure>
<ul class="lg:col-span-4 space-y-7 lg:pt-4">
{callouts.map((c, i) => (
<li class="relative pl-10">
<span
class="absolute left-0 top-0 inline-flex items-center justify-center w-7 h-7 rounded-full border border-accent/40 bg-accent/10 text-accent font-mono text-xs"
aria-hidden="true"
>
{String(i + 1).padStart(2, '0')}
</span>
<h3 class="text-text font-semibold mb-1.5">{c.title}</h3>
<p class="text-text-muted leading-relaxed">{c.body}</p>
</li>
))}
</ul>
</div>
</div>
</section>
<style>
.showcase-shot {
box-shadow:
0 1px 0 rgba(240, 180, 41, 0.08) inset,
0 40px 80px -30px rgba(0, 0, 0, 0.7),
0 15px 35px -15px rgba(0, 0, 0, 0.5);
}
.showcase-shot-glow {
position: absolute;
inset: -5% -8% -5% -8%;
background: radial-gradient(
55% 55% at 45% 50%,
rgba(92, 200, 255, 0.10),
rgba(240, 180, 41, 0.08) 40%,
transparent 75%
);
filter: blur(50px);
z-index: -1;
}
</style>

View File

@@ -0,0 +1,38 @@
---
import { getAuthConfig } from '../../config/auth';
const auth = getAuthConfig();
// PENDING — must be filled in before publish:
// 1. [Founder Name] placeholder below.
// 2. The "ex-nJAMS" mention is gated on Hendrik's trademark review
// (same pattern as WhyUs.astro §10 caveat). If the review is not
// cleared by publish time, drop the " · ex-nJAMS" suffix from the
// attribution line.
const founderName = '[Founder Name]';
const designPartnerSubject = 'Design partner enquiry — Cameleer';
const designPartnerHref = `mailto:${auth.salesEmail}?subject=${encodeURIComponent(designPartnerSubject)}`;
---
<section class="border-b border-border">
<div class="max-w-content mx-auto px-6 py-16 md:py-20">
<div class="max-w-3xl mx-auto">
<p class="text-accent font-mono text-xs tracking-[0.25em] uppercase mb-4">
// Built by people who've done this before
</p>
<blockquote class="border-l-[3px] border-accent pl-5 max-w-[62ch]">
<p class="text-lg md:text-xl text-text italic leading-relaxed mb-3">
“We spent 15 years building integration monitoring for banks that couldnt afford downtime. Cameleer is what wed build today — purpose-built for Apache Camel, no retrofit.”
</p>
<footer class="text-sm font-mono text-text-muted">
— <span class="text-text">{founderName}</span>, co-founder · ex-nJAMS
</footer>
</blockquote>
<a
href={designPartnerHref}
class="inline-flex items-center gap-2 mt-7 font-mono text-sm text-cyan hover:text-accent transition-colors"
>
Apply to the design-partner program <span aria-hidden="true">→</span>
</a>
</div>
</div>
</section>

View File

@@ -0,0 +1,104 @@
---
import Lightbox from '../Lightbox.astro';
interface Callout {
title: string;
body: string;
}
const callouts: Callout[] = [
{
title: 'Cross-service correlation.',
body: 'Every exchange carries its correlation ID forward. One click jumps to what the downstream route did with the same message.',
},
{
title: 'Runtime detail, not guesswork.',
body: 'Circuit breaker tripped. Fallback path ran. Request tried backend:80. The pieces a 3 AM page actually needs — already captured.',
},
{
title: 'The whole story of a failure.',
body: 'Exception class, message, stack trace, headers, payload — all pinned to the exchange. No log-grepping tour.',
},
];
---
<section id="walkthrough" class="border-b border-border bg-bg">
<div class="max-w-content mx-auto px-6 py-24 md:py-32">
<div class="max-w-3xl mb-14 md:mb-20">
<p class="text-cyan font-mono text-xs tracking-[0.25em] uppercase mb-4">// When something breaks</p>
<h2 class="text-hero font-bold text-text mb-5">
The 3 AM page. With and without Cameleer.
</h2>
<p class="text-lg text-text-muted leading-relaxed">
Same Camel app. Same failed exchange. Different night.
</p>
</div>
<div class="grid md:grid-cols-2 gap-6 md:gap-8 items-stretch">
<div class="without-card relative rounded-lg border border-dashed border-border-strong bg-bg overflow-hidden">
<div class="px-5 pt-5 pb-3 font-mono text-[11px] tracking-[0.2em] uppercase text-text-faint border-b border-border">
Without Cameleer · 03:12 AM
</div>
<pre class="font-mono text-[13px] leading-[1.65] text-text-muted px-5 py-5 overflow-x-auto whitespace-pre"><code><span class="text-text">$</span> kubectl logs camel-router-7d4f8c
<span class="text-rose">ERROR</span> org.apache.camel.CamelExecutionException
at org.apache.camel.processor.SendProcessor.process
at org.apache.camel.processor.Pipeline.process
...
<span class="text-text">$</span> grep "order-842" *.log
router-3.log: <span class="text-accent">WARN</span> exchange order-842 stuck in saga-fulfillment
router-3.log: <span class="text-rose">ERROR</span> processor backend:80 → connect timeout
<span class="text-text">$</span> ssh prod-integration-3
prod-integration-3 $ kubectl logs ...
&gt; <span class="text-cyan">slack #integration-team</span>
"anyone know why order-842 is stuck??"
<span class="text-text-faint">[3 of 4 reactions, no answer]</span>
<span class="text-accent">~47 min later: someone wakes up an SRE.</span></code></pre>
</div>
<figure class="with-card relative rounded-lg border border-border-strong bg-bg-elevated overflow-hidden">
<div class="px-5 pt-5 pb-3 font-mono text-[11px] tracking-[0.2em] uppercase text-accent border-b border-border">
With Cameleer · 30 sec
</div>
<Lightbox
src="/product/error-detail.png"
alt="Cameleer Mission Control — failed exchange order-842 with full execution context"
width={1920}
height={945}
loading="lazy"
imgClass="block w-full h-auto"
/>
<div class="px-5 py-4 font-mono text-[13px] leading-[1.6] text-text-muted border-t border-border">
<span class="text-accent">▸</span> Open exchange <span class="text-text">order-842</span> → see the failure pinned → click <span class="text-text">Replay</span> after fix.
</div>
<div class="absolute inset-0 ring-1 ring-inset ring-accent/10 pointer-events-none rounded-lg"></div>
</figure>
</div>
<ul class="grid md:grid-cols-3 gap-6 md:gap-8 mt-14">
{callouts.map((c, i) => (
<li class="relative pl-10">
<span
class="absolute left-0 top-0 inline-flex items-center justify-center w-7 h-7 rounded-full border border-accent/40 bg-accent/10 text-accent font-mono text-xs"
aria-hidden="true"
>
{String(i + 1).padStart(2, '0')}
</span>
<h3 class="text-text font-semibold mb-1.5">{c.title}</h3>
<p class="text-text-muted leading-relaxed">{c.body}</p>
</li>
))}
</ul>
</div>
</section>
<style>
.with-card {
box-shadow:
0 1px 0 rgba(240, 180, 41, 0.08) inset,
0 30px 60px -25px rgba(0, 0, 0, 0.7),
0 12px 30px -12px rgba(0, 0, 0, 0.5);
}
</style>

View File

@@ -20,32 +20,15 @@
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. 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> </p>
</div> </div>
<div class="relative overflow-hidden rounded-lg border border-border bg-bg-elevated p-8 transition-all duration-200 ease-out hover:-translate-y-0.5 hover:border-accent/40 hover:shadow-[0_12px_32px_-12px_rgba(240,180,41,0.18)]"> <div class="rounded-lg border border-border bg-bg-elevated p-8 transition-all duration-200 ease-out hover:-translate-y-0.5 hover:border-accent/40 hover:shadow-[0_12px_32px_-12px_rgba(240,180,41,0.18)]">
<div <h3 class="text-xl font-bold text-text mb-4">Built by people who've operated integration in production for 15 years.</h3>
aria-hidden="true"
class="pointer-events-none select-none absolute -top-6 -right-4 font-mono font-bold leading-none tracking-tight text-accent/[0.04] text-[7rem] md:text-[9rem]"
>
03:00
</div>
<div class="relative">
<div class="flex items-center gap-2.5 mb-5 font-mono text-xs">
<span aria-hidden="true" class="relative inline-flex w-1.5 h-1.5">
<span class="absolute inset-0 rounded-full bg-accent"></span>
<span class="absolute inset-0 rounded-full bg-accent/60 animate-ping [animation-duration:2.4s]"></span>
</span>
<span class="text-accent tabular-nums tracking-wide">03:00:47.218</span>
<span class="text-text-faint">·</span>
<span class="text-text-faint uppercase tracking-[0.2em]">ops desk</span>
</div>
<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"> <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. We spent over a decade building integration monitoring for banks, insurers, and logistics operators — the kind of shops where a stuck exchange is a regulatory event, not just an inconvenience.
</p> </p>
<p class="text-text-muted leading-relaxed"> <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. Cameleer is what we'd build today, purpose-built for Apache Camel. No legacy, no retrofit, no assumptions about a generic middleware platform.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
</div>
</section> </section>

View File

@@ -3,22 +3,22 @@ import BaseLayout from '../layouts/BaseLayout.astro';
import SiteHeader from '../components/SiteHeader.astro'; import SiteHeader from '../components/SiteHeader.astro';
import SiteFooter from '../components/SiteFooter.astro'; import SiteFooter from '../components/SiteFooter.astro';
import Hero from '../components/sections/Hero.astro'; import Hero from '../components/sections/Hero.astro';
import DualValueProps from '../components/sections/DualValueProps.astro'; import SocialProofStrip from '../components/sections/SocialProofStrip.astro';
import ProductShowcase from '../components/sections/ProductShowcase.astro'; import ThreeAmWalkthrough from '../components/sections/ThreeAmWalkthrough.astro';
import HowItWorks from '../components/sections/HowItWorks.astro'; import HowItWorks from '../components/sections/HowItWorks.astro';
import WhyUs from '../components/sections/WhyUs.astro'; import WhyUs from '../components/sections/WhyUs.astro';
import PricingTeaser from '../components/sections/PricingTeaser.astro'; import PricingTeaser from '../components/sections/PricingTeaser.astro';
import FinalCTA from '../components/sections/FinalCTA.astro'; import FinalCTA from '../components/sections/FinalCTA.astro';
--- ---
<BaseLayout <BaseLayout
title="Cameleer — Run Apache Camel without running Apache Camel" title="Cameleer — Ship Camel integrations. Sleep through the night."
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." description="The hosted runtime and observability platform for Apache Camel. Auto-traced, replay-ready, cross-service correlated — so the 3 AM page becomes a 30-second answer."
> >
<SiteHeader /> <SiteHeader />
<main> <main>
<Hero /> <Hero />
<DualValueProps /> <SocialProofStrip />
<ProductShowcase /> <ThreeAmWalkthrough />
<HowItWorks /> <HowItWorks />
<WhyUs /> <WhyUs />
<PricingTeaser /> <PricingTeaser />

View File

@@ -33,7 +33,7 @@ const tiers: FullTier[] = [
cta: 'Start free trial', cta: 'Start free trial',
}, },
{ {
name: 'MID', name: 'Starter',
price: '20 €', price: '20 €',
priceNote: 'per month', priceNote: 'per month',
envs: '2 environments', envs: '2 environments',
@@ -41,28 +41,28 @@ const tiers: FullTier[] = [
retention: '7-day retention', retention: '7-day retention',
features: ['Everything in Trial', 'Data flow lineage', 'Cross-service correlation'], features: ['Everything in Trial', 'Data flow lineage', 'Cross-service correlation'],
href: auth.signUpUrl, href: auth.signUpUrl,
cta: 'Start on MID', cta: 'Start on Starter',
highlight: true, highlight: true,
}, },
{ {
name: 'HIGH', name: 'Scale',
price: 'Contact', price: 'Contact',
priceNote: 'sales', priceNote: 'sales',
envs: 'Unlimited environments', envs: 'Unlimited environments',
apps: '50 apps', apps: '50 apps',
retention: '90-day retention', retention: '90-day retention',
features: ['Everything in MID', 'Live debugger', 'Exchange replay', 'Live tap'], features: ['Everything in Starter', 'Live debugger', 'Exchange replay', 'Live tap'],
href: auth.salesMailto, href: auth.salesMailto,
cta: 'Talk to sales', cta: 'Talk to sales',
}, },
{ {
name: 'BUSINESS', name: 'Enterprise',
price: 'Contact', price: 'Contact',
priceNote: 'sales', priceNote: 'sales',
envs: 'Unlimited environments', envs: 'Unlimited environments',
apps: 'Unlimited apps', apps: 'Unlimited apps',
retention: '365-day retention', retention: '365-day retention',
features: ['Everything in HIGH', 'Priority support', 'SLA', 'Dedicated success contact'], features: ['Everything in Scale', 'Priority support', 'SLA', 'Dedicated success contact'],
href: auth.salesMailto, href: auth.salesMailto,
cta: 'Talk to sales', cta: 'Talk to sales',
}, },
@@ -117,7 +117,7 @@ const tiers: FullTier[] = [
))} ))}
</div> </div>
<p class="text-center text-text-faint text-sm mt-10"> <p class="text-center text-text-faint text-sm mt-10">
Prices in EUR, excluding VAT. Billed monthly. Annual billing available for HIGH and BUSINESS — <a href={auth.salesMailto} class="text-accent hover:underline">talk to sales</a>. Prices in EUR, excluding VAT. Billed monthly. Annual billing available for Scale and Enterprise — <a href={auth.salesMailto} class="text-accent hover:underline">talk to sales</a>.
</p> </p>
</div> </div>
</section> </section>