Marketing landing page for numi — a blazingly fast Rust CLI that generates type-safe code from Apple project resources.
Live at https://numi.elata.ai.
- Astro 5 — static site generation, zero-JS by default
- React 19 — islands only (
CopyInstall,ConfigShowcase) - Tailwind CSS v4 — via
@tailwindcss/vite - Shiki — build-time syntax highlighting for TOML / Swift / YAML
- Cloudflare Pages — static hosting
Fonts are self-hosted (Inter + JetBrains Mono) via @fontsource/*. No runtime font requests, no Google Fonts CDN.
# install
npm install
# dev server — http://localhost:4321
npm run dev
# production build
npm run build
# preview the built site
npm run previewRequires Node 20+.
src/
├── pages/
│ └── index.astro # the single landing page
├── layouts/
│ └── Base.astro # <html>, meta, OG tags, font imports
├── components/
│ ├── astro/ # static, zero-JS Astro components
│ │ ├── Nav.astro
│ │ ├── Hero.astro
│ │ ├── Quickstart.astro
│ │ ├── ValueGrid.astro
│ │ ├── ConfigShowcase.astro
│ │ ├── TemplatesRow.astro
│ │ ├── CISnippet.astro
│ │ ├── FinalCTA.astro
│ │ ├── Footer.astro
│ │ └── CodeBlock.astro # Shiki-rendered at build time
│ └── react/ # hydrated islands
│ ├── CopyInstall.tsx # client:load — clipboard pill
│ └── ConfigShowcase.tsx # client:visible — tab switcher
├── styles/
│ └── global.css # Tailwind import, @theme tokens, base styles
└── lib/
└── snippets.ts # numi.toml + generated Swift samples + CI YAML
public/
├── numi-logo.png # hero logo
├── favicon.svg
├── _headers # Cloudflare security + cache headers
└── _redirects # placeholder
The site is aggressively static. JavaScript only ships for the two interactive pieces:
| Island | Directive | Why |
|---|---|---|
CopyInstall.tsx |
client:load |
Above-the-fold clipboard API + "Copied!" state |
ConfigShowcase.tsx |
client:visible |
Tab state; three pre-rendered Shiki blocks swapped via hidden |
Everything else — Nav, Hero layout, value grid, code blocks, footer — is pure Astro SSG with no client runtime.
All tokens live in src/styles/global.css under @theme. Dark-first palette:
| Token | Value | Use |
|---|---|---|
--color-ink |
#0B0D12 |
page background |
--color-surface |
#11141B |
panels |
--color-surface-raised |
#181C26 |
cards |
--color-border |
#242A38 |
hairlines, dividers |
--color-text |
#E6E9F2 |
primary text |
--color-text-muted |
#8A93A6 |
secondary text |
--color-primary |
#F05138 |
CTAs, numi orange |
--color-accent |
#7CE3FF |
inline code, signals |
--color-success |
#4ADE80 |
numi check OK |
Typography: Inter for UI and headings (600 weight, -0.035em tracking for the .display utility), JetBrains Mono for code and the install pill.
Deployed as a static export to Cloudflare Pages — no SSR adapter, no server runtime.
Cloudflare Pages dashboard settings:
| Field | Value |
|---|---|
| Framework preset | Astro |
| Build command | npm run build |
| Build output directory | dist |
| Environment variable | NODE_VERSION=20 |
On every push to main, Cloudflare builds and publishes automatically. public/_headers controls security and cache headers.
Note: No
wrangler.tomlat the repo root. Cloudflare Pages' v3 build image misinterprets it as a Workers project and runswrangler deploy(Workers-only) instead of publishingdist/. Keeping the dashboard config as the source of truth avoids the issue.
- Code samples (
numi.toml, generated Swift, CI YAML) live insrc/lib/snippets.ts. Edit once, picked up everywhere. - Value prop tiles and quickstart steps are data arrays in the same file.
- Section copy (headings, taglines) lives inline in each
src/components/astro/*.astrocomponent.
MIT. Part of the oops-rs family.