The public Construct Computer website. It preserves the established landing-page design while replacing the previous custom build and router with a statically prerendered React application.
- React Router framework mode with Vite and React 19
- Tailwind CSS 4 and shadcn/Radix primitives
- Repository-authored MDX editorial content
- Cloudflare Pages, Pages Functions, D1, Turnstile, and WAF
- PostHog analytics with full autocapture and unmasked session replay
- Vitest, Playwright, axe, ESLint, Prettier, and strict TypeScript
| Command | Purpose |
|---|---|
pnpm dev |
Functions on :8788 and the site on :5173, /api proxied |
pnpm dev:web |
The site alone (no Functions) |
pnpm dev:api |
The Pages Functions alone |
pnpm build |
Generate discovery files and prerender every public route |
pnpm preview |
Serve the built site and Pages Functions with Wrangler |
pnpm test |
Run unit and API tests |
pnpm test:e2e |
Build and test the deployed Pages behavior in Chromium |
pnpm lint |
Run ESLint |
pnpm typecheck |
Generate route types and run TypeScript |
pnpm check |
Run lint, types, unit tests, and the production build |
- Install Node 24 and pnpm 11.15.0.
- Run
pnpm install. - Use
.env.examplefor public Vite variables and.dev.vars.examplefor local Pages secrets. - Apply the local database migration with
pnpm wrangler d1 migrations apply DB --local. - Run
pnpm devfor the site with its Functions (it applies the local D1 migrations and writes.dev.varsfrom the example if missing; signups and claims are not sent to Listmonk unless you start it withLISTMONK_LIVE=1, sincewrangler.jsoncpoints at the production list), orpnpm test:e2efor the complete Pages, Function, Turnstile and D1 flow.
Cloudflare's published Turnstile test keys are intentionally included in the example and E2E configuration. Production keys must be configured in Cloudflare.
app/features/landing/owns the homepage sections, motion, media, and beta modal.app/content/is the editorial source of truth.app/content/resources.tsmaps generated MDX metadata into one ordered collection.- Every editorial resource uses
/blog/<slug>/; company and legal utilities remain top-level. app/lib/route-manifest.tsdrives prerendering, canonical metadata, sitemap entries, feeds, crawler files, and OG images.functions/api/beta-signup.tstakes the site's signups;functions/api/embed/runs Night Shift, the playable show X renders inside a post (see below).scripts/finalize-build.mjscreates a real404.htmland removes the SPA fallback.
See docs/decisions/001-static-prerendered-react.md for the architectural rationale and docs/search-and-deployment.md for production setup and indexing operations.
For Twitterbot, the homepage carries X Player Card tags (functions/player-card.ts swaps them into the prerendered page, which is a large image card for Discord and everyone else), so a post that links construct.computer renders /embed/ inside the post on desktop and opens it full screen from the phone apps. The page is Night Shift (app/features/night-shift/), the launch film as a one minute show you play: wake the mascot at 11 pm, hand it your list in a Slack thread, pull the chain, then skip or peek through its night shift until the morning report. The email comes last, as the exit offer of a free first month of Pro. The show runs on a small engine in app/features/show/ (a 960 by 720 board scaled to fit, the mascot, the speech bubble and the CRT). public/_headers lets only X frame that path.
functions/api/embed/session.ts turns the viewer's first name into a signed session token (Turnstile, five sessions an hour per address, a row in D1's embed_sessions with keyed hashes only). functions/api/embed/claim.ts takes the email at the exit offer, subscribes it to the newsletter in Listmonk like every other form does (cta_source embed-x, the post's src as the campaign; Listmonk is the only place leads are kept) and hands back EMBED_PROMO_CODE, which it also emails through Cloudflare Email Service (functions/claim-email.ts). "Start tonight" and the email's button open /?promo=CODE, where app/features/landing/promo-welcome.tsx welcomes the visitor and keeps the code for checkout. shared/embed-schema.ts holds the wire shapes and the per-address cap. There is no overall cap. EMBED_SESSION_SECRET is a Pages secret.
Add articles, guides, and comparisons as MDX under app/content/blog/. The filename is the canonical /blog/<slug>/ slug, and every file is discovered automatically.
Frontmatter requires title, description, published (YYYY-MM-DD), a registered author ID, nonempty tags, kind (article, guide, or comparison), and draft. seoTitle is optional. Add updated only after a substantive update and use a date later than published. Run pnpm generate:content; the build fails on invalid or stale metadata.
The homepage social image source is assets/og/home.png. Generation copies it to public/og/home.png after rebuilding other OG images, so replace the source file rather than editing the generated copy.
pnpm check && pnpm test:e2e is the release gate. It verifies all canonical pages, the real 404 response, the ordered resource grid, the Turnstile-checked newsletter signup, and automated accessibility checks.