voice basis + copy rework: heart on the landing page, head on /get-started
PRODUCT.md carries the language foundation (one feeling: lightness); the landing page drops spec-speak to a three-code-span jargon budget; the new /get-started/ page inherits install, first-ship, and the under-the-hood detail. Styles extracted to shared site.css.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5 files changed,
+262
−96
CLAUDE.md+7 −2PRODUCT.md+62 −0get-started/index.html+87 −0index.html+29 −94site.css+77 −0
diff --git a/CLAUDE.md b/CLAUDE.md| index 7a38a2d..3c4b036 100644 |
| --- a/CLAUDE.md |
| +++ b/CLAUDE.md |
| @@ -5,10 +5,15 @@ The marketing site for **Carloku** โ the hosted CARLOS platform |
| brand; CARLOS is the framework/CLI/console name. Never rename CARLOS things |
| to Carloku here. |
| +**Voice lives in PRODUCT.md** โ the one feeling is lightness ("finally, |
| +simple"); the landing page appeals to the heart, /get-started carries the |
| +tech. Read it before touching copy. |
| + |
| Rules inherited from the `website` repo, which governs the sibling site: |
| -- **One page, zero dependencies.** No frameworks, no fetched fonts, no |
| - analytics, no JavaScript, no build step. |
| +- **Small site, zero dependencies.** Two pages (`/`, `/get-started/`) and |
| + one shared `site.css`. No frameworks, no fetched fonts, no analytics, no |
| + JavaScript, no build step. |
| - **Light and dark** via `prefers-color-scheme` โ keep both working. |
| - **AI authorship is always marked** with a visible ๐ค (cascades from a |
| heading); person-emoji (๐จ/๐ค/๐ง) blocks are certified human and |
diff --git a/PRODUCT.md b/PRODUCT.md| new file mode 100644 |
| index 0000000..50ba0f0 |
| --- /dev/null |
| +++ b/PRODUCT.md |
| @@ -0,0 +1,62 @@ |
| +# ๐ค PRODUCT.md โ Carloku |
| + |
| +**What this site is.** carloku.com markets Carloku, the commercial cloud |
| +offering of the open-source CARLOS platform. dashboard.carloku.com is the |
| +product; this site is the doorway. The framework and platform keep the |
| +CARLOS name โ Carloku is only ever the hosted offering. |
| + |
| +**Audience.** Both at once: the solo dev with a side project and the small |
| +team shipping product. One voice for both โ personal and direct, no |
| +enterprise theater. The reader is one person at a keyboard, whatever their |
| +badge says. |
| + |
| +## The one feeling: lightness |
| + |
| +"Finally, simple." A visitor should exhale. Hosting they can hold in their |
| +head. Supporting notes, in order: **calm** (deploys without dread, apps that |
| +doze, going back is easy) and **trust through openness** (open source |
| +underneath, nothing moves behind your back). |
| + |
| +The audit for every sentence on the landing page: *does this make the |
| +reader feel lighter โ or merely better informed?* Better-informed-only |
| +sentences belong on /get-started or in future docs. That is the whole |
| +division of labor between the pages. |
| + |
| +## Message map (fact โ what the heart hears) |
| + |
| +| Fact | What it means to the reader | |
| +|---|---| |
| +| `carlos ship` โ private live URL | look at the real, running thing before anyone else does | |
| +| promote serves the same bytes | what you approved is exactly what people get โ nothing rebuilt behind your back | |
| +| rollback = promote the previous release | changing your mind is allowed; back is the same small motion as forward | |
| +| hibernation | quiet apps doze and wake on their own; nothing to switch off, nothing to babysit | |
| +| automatic certificates | the padlock just appears; renewals are never your job | |
| +| Keymail passkey sign-in | no password to invent, reuse, or leak | |
| +| open-source platform underneath | hosted here, never locked here โ you can read every moving part | |
| + |
| +## Voice rules |
| + |
| +- Second person, active. "You ship." The platform is the quiet one in the |
| + room. |
| +- Short words, short sentences. Cut until it hurts, then once more. |
| +- **The landing page's jargon budget is three code spans**: `carlos ship`, |
| + `carlos promote`, and one rollback mention. Commands appear as |
| + incantations โ three words you can hold in your head โ never as |
| + documentation. |
| +- Never on the landing page: immutable, content-addressed, canary, |
| + signature/signed, provision, TLS, converge, infra, artifact, registry. |
| + All of it lives happily on /get-started ("Under the hood") or in docs. |
| +- No pricing language until billing exists (CLAUDE.md rule). Describe |
| + hibernation by behavior, never by cost. |
| +- No claims we can't cash today. Where the product is young, say young โ |
| + honesty reads as confidence. |
| +- Em-dashes sparingly; exclamation marks never. |
| + |
| +## Page roles |
| + |
| +- **/** persuades. Heart first; the three commands are the only tech. |
| +- **/get-started** instructs, still warmly. Install, sign in, first ship โ |
| + plus "Under the hood," where the landing page's former spec-speak |
| + retired to. |
| +- Docs (future) explain. Until they exist, /get-started links to |
| + carlosframework.com for the platform's full design. |
diff --git a/get-started/index.html b/get-started/index.html| new file mode 100644 |
| index 0000000..d3e22ef |
| --- /dev/null |
| +++ b/get-started/index.html |
| @@ -0,0 +1,87 @@ |
| +<!doctype html> |
| +<html lang="en"> |
| +<head> |
| +<meta charset="utf-8"> |
| +<meta name="viewport" content="width=device-width, initial-scale=1"> |
| +<title>Get started โ Carloku</title> |
| +<meta name="description" content="๐ค Install the carlos CLI, sign in with a passkey, and ship your first app to Carloku."> |
| +<meta property="og:title" content="Get started โ Carloku"> |
| +<meta property="og:description" content="Install the carlos CLI, sign in with a passkey, and ship your first app."> |
| +<meta property="og:type" content="website"> |
| +<meta property="og:url" content="https://carloku.com/get-started/"> |
| +<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)"> |
| +<meta name="theme-color" content="#16141c" media="(prefers-color-scheme: dark)"> |
| +<link rel="icon" href="/favicon.svg" type="image/svg+xml"> |
| +<link rel="stylesheet" href="/site.css"> |
| +</head> |
| +<body> |
| +<header class="hero"> |
| + <p class="eyebrow"><a href="/">๐ค CARLOKU</a></p> |
| + <h1>Get started<span class="dot">.</span></h1> |
| + <p class="lede">This is the head half; the heart half is that you'll be live |
| + before it feels like work. Four steps, one small tool.</p> |
| +</header> |
| +<main> |
| + <article> |
| + <section> |
| + <h2>1 ยท Install the CLI</h2> |
| + <pre><code>brew install carlosframework/tap/carlos</code></pre> |
| + <p>Not on Homebrew? Prebuilt binaries live at |
| + <a href="https://github.com/carlosframework/releases">github.com/carlosframework/releases</a>. |
| + It's one static binary: put it on your PATH and you're done.</p> |
| + </section> |
| + <section> |
| + <h2>2 ยท Sign in</h2> |
| + <p>Create your account at <a href="https://dashboard.carloku.com">dashboard.carloku.com</a> โ |
| + you sign in with a passkey through Keymail, so there's no password to invent. |
| + Then connect your terminal:</p> |
| + <pre><code>carlos auth login -console https://dashboard.carloku.com</code></pre> |
| + <p>The CLI prints a short code; you approve it in the browser you're already |
| + signed in to. That's the whole ceremony.</p> |
| + </section> |
| + <section> |
| + <h2>3 ยท Create and ship</h2> |
| + <pre><code>carlos apps create -app hello |
| +carlos ship -app hello -kind static -version v1 ./public |
| +</code></pre> |
| + <p>Shipping uploads exactly what's in the directory and gives your app a private |
| + address you can open right away. Version strings are yours to choose; a git |
| + short SHA is the house convention.</p> |
| + </section> |
| + <section> |
| + <h2>4 ยท Promote</h2> |
| + <pre><code>carlos promote -app hello v1 stable</code></pre> |
| + <p>Promotion is the "go" button: the release you just looked at starts serving |
| + for real. To roll back, promote the previous version: it's the same command |
| + pointed at an older name.</p> |
| + <p class="note">Carloku is young and moving quickly. If anything on this page |
| + surprises you, the <a href="https://dashboard.carloku.com">dashboard</a> is the |
| + source of truth, and the platform underneath is open source.</p> |
| + </section> |
| + <section> |
| + <h2>Under the hood</h2> |
| + <p>For the technically curious, this is the part we keep off the front page:</p> |
| + <ul> |
| + <li>A release is an immutable, content-addressed artifact. Promotion moves a |
| + signed pointer; nothing is ever rebuilt between preview and production, and |
| + every box verifies the signature before running a release.</li> |
| + <li>Channels carry releases through canary and bake stages, so production |
| + only adopts what has already served traffic.</li> |
| + <li>Idle apps hibernate: the process stops, the route stays, and the first |
| + request wakes it.</li> |
| + <li>Custom domains get per-host certificates minted and renewed |
| + automatically.</li> |
| + </ul> |
| + <p>The whole design is public โ read it at |
| + <a href="https://carlosframework.com">carlosframework.com</a>.</p> |
| + </section> |
| + </article> |
| +</main> |
| +<footer> |
| + <p>๐ค Written by an LLM (Claude), on the ideas, instruction, and editing of humans. |
| + AI-written text here is always marked and always disclosed; see |
| + <a href="https://11factor.org/#x">factor X</a>.</p> |
| + <p><a href="/">โ carloku.com</a> ยท <a href="https://github.com/carlosframework/carloku">Source on GitHub</a>.</p> |
| +</footer> |
| +</body> |
| +</html> |
diff --git a/index.html b/index.html| index 851413f..a270228 100644 |
| --- a/index.html |
| +++ b/index.html |
| @@ -4,127 +4,62 @@ |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>Carloku โ the hosted CARLOS platform</title> |
| -<meta name="description" content="๐ค Ship immutable releases with instant canary URLs, promote the same bytes to production, and idle apps hibernate until the next request. Carloku is the hosted home of the CARLOS platform."> |
| +<meta name="description" content="๐ค Hosting small enough to hold in your head. Ship with one small command, put it live with another, and stop carrying the rest. Carloku is the hosted home of the CARLOS platform."> |
| <meta property="og:title" content="Carloku"> |
| -<meta property="og:description" content="Ship immutable releases with instant canary URLs, promote the same bytes to production, and idle apps hibernate until the next request."> |
| +<meta property="og:description" content="Hosting small enough to hold in your head. Ship with one small command, put it live with another, and stop carrying the rest."> |
| <meta property="og:type" content="website"> |
| <meta property="og:url" content="https://carloku.com/"> |
| <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)"> |
| <meta name="theme-color" content="#16141c" media="(prefers-color-scheme: dark)"> |
| <link rel="icon" href="/favicon.svg" type="image/svg+xml"> |
| -<style> |
| - :root { |
| - --bg: #ffffff; |
| - --ink: #201d29; |
| - --muted: #6f6480; |
| - --accent: #5b3e96; |
| - --accent-strong: #4c3380; |
| - --accent-soft: rgba(91, 62, 150, 0.09); |
| - --rule: #eae7f0; |
| - --max: 42rem; |
| - --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; |
| - --sans: ui-sans-serif, system-ui, -apple-system, sans-serif; |
| - } |
| - @media (prefers-color-scheme: dark) { |
| - :root { |
| - --bg: #16141c; |
| - --ink: #f0eef6; |
| - --muted: #a99ebd; |
| - --accent: #b394f2; |
| - --accent-strong: #c9b2f7; |
| - --accent-soft: rgba(179, 148, 242, 0.12); |
| - --rule: #2c2836; |
| - } |
| - } |
| - * { box-sizing: border-box; margin: 0; } |
| - body { |
| - background: var(--bg); color: var(--ink); |
| - font-family: var(--sans); line-height: 1.6; |
| - padding: 0 1.25rem; |
| - } |
| - main, footer { max-width: var(--max); margin: 0 auto; } |
| - header.hero { max-width: var(--max); margin: 0 auto; padding: 5rem 0 3rem; } |
| - .eyebrow { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); letter-spacing: 0.08em; } |
| - h1 { font-size: clamp(2rem, 7vw, 2.6rem); line-height: 1.15; margin: 0.5rem 0 1rem; } |
| - h1 .dot { color: var(--accent); } |
| - .lede { font-size: 1.15rem; color: var(--muted); max-width: 36rem; } |
| - .cta { margin: 2rem 0 0; display: flex; gap: 1rem; flex-wrap: wrap; } |
| - .cta a.primary { |
| - background: var(--accent); color: var(--bg); text-decoration: none; |
| - padding: 0.65rem 1.2rem; border-radius: 0.4rem; font-weight: 600; |
| - } |
| - .cta a.primary:hover { background: var(--accent-strong); } |
| - .cta a.secondary { color: var(--accent); text-decoration: none; padding: 0.65rem 0; font-weight: 600; } |
| - .cta a.secondary:hover, footer a:hover { text-decoration: underline; } |
| - a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 0.2em; } |
| - ::selection { background: var(--accent); color: var(--bg); } |
| - section { border-top: 1px solid var(--rule); padding: 2.5rem 0; } |
| - h2 { font-size: 1.3rem; margin-bottom: 1.25rem; } |
| - ol.ship { list-style: none; counter-reset: step; display: grid; gap: 1.25rem; } |
| - ol.ship li { counter-increment: step; padding-left: 2.4rem; position: relative; } |
| - ol.ship li::before { |
| - content: counter(step); position: absolute; left: 0; top: 0.1rem; |
| - width: 1.6rem; height: 1.6rem; border-radius: 50%; |
| - background: var(--accent-soft); color: var(--accent); |
| - font-family: var(--mono); font-size: 0.85rem; |
| - display: grid; place-items: center; |
| - } |
| - code { font-family: var(--mono); font-size: 0.9em; background: var(--accent-soft); padding: 0.1em 0.35em; border-radius: 0.25em; } |
| - ul.features { list-style: none; display: grid; gap: 0.9rem; } |
| - ul.features li strong { display: block; } |
| - ul.features li span { color: var(--muted); } |
| - footer { border-top: 1px solid var(--rule); padding: 2rem 0 3rem; font-size: 0.9rem; color: var(--muted); } |
| - footer p { margin-bottom: 0.6rem; } |
| - footer a { color: var(--accent); text-decoration: none; } |
| -</style> |
| +<link rel="stylesheet" href="/site.css"> |
| </head> |
| <body> |
| <header class="hero"> |
| <p class="eyebrow">๐ค CARLOKU</p> |
| <h1>Ship it. Promote it. Sleep<span class="dot">.</span></h1> |
| - <p class="lede">Carloku is the hosted home of the CARLOS platform. One command packs |
| - your app into an immutable release with an instant canary URL; one more promotes the |
| - same bytes to production. Idle apps hibernate and wake on the next request.</p> |
| + <p class="lede">Carloku is the hosted CARLOS platform: hosting small enough to |
| + hold in your head. You ship, you look at it, you say go. The rest โ certificates, |
| + passwords, servers idling through the night โ stops being your job.</p> |
| <div class="cta"> |
| - <a class="primary" href="https://dashboard.carloku.com">Open the dashboard</a> |
| - <a class="secondary" href="https://carlosframework.com">About CARLOS <span aria-hidden="true">โ</span></a> |
| + <a class="primary" href="/get-started/">Get started</a> |
| + <a class="secondary" href="https://dashboard.carloku.com">Open the dashboard</a> |
| </div> |
| </header> |
| <main> |
| <section> |
| - <h2>How shipping works</h2> |
| + <h2>The whole workflow</h2> |
| <ol class="ship" role="list"> |
| - <li><strong><code>carlos ship</code></strong> โ packs your working tree into a |
| - content-addressed release and uploads it. You get a canary URL serving exactly |
| - those bytes, immediately.</li> |
| - <li><strong><code>carlos promote</code></strong> โ signs that release onto a |
| - channel. Production adopts the same bytes the canary served; nothing is rebuilt |
| - on the way.</li> |
| - <li><strong>Roll back by promoting the previous release.</strong> Releases are |
| - immutable, so going back is the same operation as going forward.</li> |
| + <li><strong><code>carlos ship</code></strong>. Your app goes up, and you get a |
| + private link to the real, running thing. Look at it. Poke it. It's live, just |
| + not public yet.</li> |
| + <li><strong><code>carlos promote</code></strong>. The exact thing you just |
| + looked at becomes the public thing. Nothing is rebuilt behind your back; what |
| + you approved is what people get.</li> |
| + <li><strong>Changed your mind?</strong> Point at yesterday's version and promote |
| + that instead. Going back is the same small motion as going forward.</li> |
| </ol> |
| </section> |
| <section> |
| - <h2>What you get</h2> |
| + <h2>What you stop thinking about</h2> |
| <ul class="features" role="list"> |
| - <li><strong>Signed releases</strong> <span>every release is signature-verified |
| - before a box will run it.</span></li> |
| - <li><strong>Channels with bake time</strong> <span>canaries pick a release up |
| - first; production holds until it has baked.</span></li> |
| - <li><strong>Hibernation</strong> <span>apps sleep when idle and wake on request โ |
| - a sleeping app uses no compute.</span></li> |
| - <li><strong>Custom domains, automatic TLS</strong> <span>point DNS at Carloku; |
| - certificates are minted and renewed for you.</span></li> |
| - <li><strong>Sign in with Keymail</strong> <span>passkey-backed sign-in โ no |
| - passwords, on the dashboard or the CLI.</span></li> |
| + <li><strong>Certificates</strong> <span>point your domain at Carloku and the |
| + padlock appears. Renewals happen without you.</span></li> |
| + <li><strong>Passwords</strong> <span>sign in with a passkey, on the dashboard |
| + and in the terminal. There's nothing to invent, reuse, or leak.</span></li> |
| + <li><strong>Idle servers</strong> <span>apps doze when nobody's around and wake |
| + the instant someone shows up. A quiet app is just quiet.</span></li> |
| + <li><strong>What's really running</strong> <span>the platform under Carloku is |
| + open source. You can read every moving part โ or run it yourself. Hosted here, |
| + never locked here.</span></li> |
| </ul> |
| </section> |
| </main> |
| <footer> |
| <p>๐ค Written by an LLM (Claude), on the ideas, instruction, and editing of humans. |
| - AI-written text here is always marked and always disclosed โ see |
| + AI-written text here is always marked and always disclosed; see |
| <a href="https://11factor.org/#x">factor X</a>.</p> |
| - <p>Carloku runs on <a href="https://carlosframework.com">CARLOS</a> โ the framework |
| + <p>Carloku runs on <a href="https://carlosframework.com">CARLOS</a>: the framework |
| is open, and this site is itself a CARLOS app, shipped with <code>carlos ship</code>.</p> |
| <p><a href="https://github.com/carlosframework/carloku">Source for this site on GitHub</a>.</p> |
| </footer> |
diff --git a/site.css b/site.css| new file mode 100644 |
| index 0000000..8bb4206 |
| --- /dev/null |
| +++ b/site.css |
| @@ -0,0 +1,77 @@ |
| +/* ๐ค Carloku shared stylesheet โ both pages, zero dependencies. */ |
| +:root { |
| + --bg: #ffffff; |
| + --ink: #201d29; |
| + --muted: #6f6480; |
| + --accent: #5b3e96; |
| + --accent-strong: #4c3380; |
| + --accent-soft: rgba(91, 62, 150, 0.09); |
| + --rule: #eae7f0; |
| + --max: 42rem; |
| + --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; |
| + --sans: ui-sans-serif, system-ui, -apple-system, sans-serif; |
| +} |
| +@media (prefers-color-scheme: dark) { |
| + :root { |
| + --bg: #16141c; |
| + --ink: #f0eef6; |
| + --muted: #a99ebd; |
| + --accent: #b394f2; |
| + --accent-strong: #c9b2f7; |
| + --accent-soft: rgba(179, 148, 242, 0.12); |
| + --rule: #2c2836; |
| + } |
| +} |
| +* { box-sizing: border-box; margin: 0; } |
| +body { |
| + background: var(--bg); color: var(--ink); |
| + font-family: var(--sans); line-height: 1.6; |
| + padding: 0 1.25rem; |
| +} |
| +main, footer { max-width: var(--max); margin: 0 auto; } |
| +header.hero { max-width: var(--max); margin: 0 auto; padding: 5rem 0 3rem; } |
| +.eyebrow { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); letter-spacing: 0.08em; } |
| +.eyebrow a { color: var(--muted); text-decoration: none; } |
| +.eyebrow a:hover { color: var(--accent); } |
| +h1 { font-size: clamp(2rem, 7vw, 2.6rem); line-height: 1.15; margin: 0.5rem 0 1rem; } |
| +h1 .dot { color: var(--accent); } |
| +.lede { font-size: 1.15rem; color: var(--muted); max-width: 36rem; } |
| +.cta { margin: 2rem 0 0; display: flex; gap: 1rem; flex-wrap: wrap; align-items: center; } |
| +.cta a.primary { |
| + background: var(--accent); color: var(--bg); text-decoration: none; |
| + padding: 0.65rem 1.2rem; border-radius: 0.4rem; font-weight: 600; |
| +} |
| +.cta a.primary:hover { background: var(--accent-strong); } |
| +.cta a.secondary { color: var(--accent); text-decoration: none; padding: 0.65rem 0; font-weight: 600; } |
| +.cta a.secondary:hover, footer a:hover { text-decoration: underline; } |
| +a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 0.2em; } |
| +::selection { background: var(--accent); color: var(--bg); } |
| +section { border-top: 1px solid var(--rule); padding: 2.5rem 0; } |
| +h2 { font-size: 1.3rem; margin-bottom: 1.25rem; } |
| +ol.ship { list-style: none; counter-reset: step; display: grid; gap: 1.25rem; } |
| +ol.ship li { counter-increment: step; padding-left: 2.4rem; position: relative; } |
| +ol.ship li::before { |
| + content: counter(step); position: absolute; left: 0; top: 0.1rem; |
| + width: 1.6rem; height: 1.6rem; border-radius: 50%; |
| + background: var(--accent-soft); color: var(--accent); |
| + font-family: var(--mono); font-size: 0.85rem; |
| + display: grid; place-items: center; |
| +} |
| +code { font-family: var(--mono); font-size: 0.9em; background: var(--accent-soft); padding: 0.1em 0.35em; border-radius: 0.25em; } |
| +pre { |
| + background: var(--accent-soft); padding: 1rem 1.25rem; border-radius: 0.5rem; |
| + overflow-x: auto; font-family: var(--mono); font-size: 0.9rem; line-height: 1.5; |
| + margin: 1rem 0; |
| +} |
| +pre code { background: none; padding: 0; font-size: inherit; } |
| +ul.features { list-style: none; display: grid; gap: 0.9rem; } |
| +ul.features li strong { display: block; } |
| +ul.features li span { color: var(--muted); } |
| +article p, article ul { margin-bottom: 1rem; max-width: var(--max); } |
| +article h2 { margin-top: 0; } |
| +article a { color: var(--accent); text-decoration: none; } |
| +article a:hover { text-decoration: underline; } |
| +.note { border-left: 1px solid var(--rule); padding-left: 1rem; color: var(--muted); font-size: 0.95rem; } |
| +footer { border-top: 1px solid var(--rule); padding: 2rem 0 3rem; font-size: 0.9rem; color: var(--muted); } |
| +footer p { margin-bottom: 0.6rem; } |
| +footer a { color: var(--accent); text-decoration: none; } |