The public website for Amble, your professional Rep: the story, and the waitlist for the closed beta.
This project is deliberately separate from the product repo (../amble). Nothing here imports from, writes to, or runs inside that directory.
PLAN.md— what we're building and what's decided.BRIEF.md— what the site inherits from Amble.../amble/PRODUCT_SPEC.mdand../amble/DESIGN_SYSTEM.md— source of truth for voice and design.
Astro 7 with @astrojs/node in middleware mode, served by server.mjs (Express + compression). Pages are prerendered, EN at /, ES at /es/. The waitlist is the only server code: Postgres + Resend. The home's motion uses GSAP (ScrollTrigger, Flip) and Lenis.
npm install
cp .env.example .env # point DATABASE_URL at a local Postgres
npm run db:migrate
npm run devWithout RESEND_API_KEY, confirmation links are printed to the server log instead of emailed.
Other scripts:
npm run statsprints the last 14 days of anonymous counts (views, how far people scroll, sign-ups).npm testruns the unit tests.npm run ogregenerates the social cards (public/og-*.png) andpublic/favicon-closed.svg.node design/blink-frames.mtsrenders the eye's blink, frame by frame, todesign/blink-frames.html.
- One service from this repo plus a Postgres plugin.
- Build:
npm run build. Start:npm start(appliesdb/schema.sql, then runsserver.mjs). - Variables:
DATABASE_URL(from the Postgres plugin),RESEND_API_KEY,WAITLIST_FROM,SITE_URL=https://amble.fyi,HOST=0.0.0.0. Railway setsPORT. server.mjscompresses responses, caches hashed assets for a year and revalidates HTML. The waitlist's rate limit reads the client IP from the lastX-Forwarded-Forhop, which Railway's proxy sets.- Astro rejects cross-site form posts by checking
Originagainst the request host; the custom domain must reach the service with its ownHostheader.