A modern Next.js 16 starter with React 19, Tailwind CSS v4, and optional WebGL. Satūs means "beginning" in Latin.
Run bun dev and open localhost:3000 — the landing page is a step-by-step manual that walks you from a fresh clone to a shippable site. The rest of this README is the reference version.
Note: This README is for template developers. For client handoff, see PROD-README.md.
After deploying, run
bun run env:setuponce your project has env vars (see Environment variables). The base URL for SEO, canonical URLs, sitemaps, and social cards comes from Vercel;NEXT_PUBLIC_BASE_URLonly overrides it.
- Next.js 16 + React 19 — App Router with
cacheComponentsand instant navigations on, React Compiler, strict TypeScript - Tailwind v4 + CSS Modules — side by side under one cascade contract, so utility and module styles can't silently fight
- Opt-in integrations — Sanity, Shopify, HubSpot, and Mailchimp stay isolated under
lib/integrations; WebGL lives underlib/webglbehindlib/features;bun run setup:projectstrips the rest - Bun + oxc toolchain — Bun as runtime and test runner;
oxlintandoxfmtcover TS, CSS, Markdown, YAML and TOML, and sort imports and Tailwind classes at format time
Requires Node.js >= 24.20 and Bun >= 1.4.0.
bun install
bun dev # open localhost:3000 for the manualIntegrations switch on as you add their env vars, see Environment variables.
Trim what you don't need: bun run setup:project strips unused integrations (code, deps, env) interactively. Details, including the non-interactive flags, live in lib/integrations/README.md.
A project's env vars are committed as one .env file, encrypted with dotenvx. Satus itself ships none: a fork's first bun dotenvx set creates its .env and its own key (a shared .env would make every fork encrypt to satus's key). Next loads the file in bun dev, local builds and Vercel production and preview (CI builds without it, see below). Every value is encrypted, public ones included, and lib/env-files.test.ts fails on a plain one. Without the key nothing runs: lib/env.ts throws on any value it could not decrypt. Next decrypts the file on load through @dotenvx/next-env, which replaces @next/env via overrides in package.json. bunfig.toml turns off Bun's own .env loading, which would otherwise set the still-encrypted values first.
The base URL is not in the file. On Vercel, production uses VERCEL_PROJECT_PRODUCTION_URL and previews use their own VERCEL_BRANCH_URL, so share cards and absolute links on a preview point at that preview. Locally it falls back to localhost. Vercel's "Enable access to System Environment Variables" must stay on. Vercel picks the shortest production custom domain: if the site lives on www.example.com and the apex redirects there, set NEXT_PUBLIC_BASE_URL to the www address.
Overrides: when a key needs a different value locally or in builds, put only that key in an encrypted .env.development (for bun dev) or .env.production (for builds) with bun dotenvx set KEY "value" -f .env.production. Everything else still comes from .env. Each file has its own key, so add one only when a value really differs.
Private keys never go in git (.env.keys is ignored).
- Starting a project:
bun dotenvx set KEY "value"for each variable (.env.examplelists them). The first call creates.envand its key. Commit.env, then runbun run env:setup: it sends the key to the linked Vercel project (production and preview) without printing it. It needs the folder linked withvercel link. - Joining a project: get the line
DOTENV_PRIVATE_KEY="..."from whoever set it up and put it in.env.keysat the repo root. - Adding or changing a variable:
bun dotenvx set KEY "value", then commit.env. This needs only the public key in the file's header, not the private key. A new variable also goes inlib/env.tsand.env.example. - Reading a value:
bun dotenvx get KEY. Removing one:bun dotenvx del KEY. - Personal overrides:
.env.localis still loaded first and stays out of git. - Vercel: needs only the private keys:
DOTENV_PRIVATE_KEY, plusDOTENV_PRIVATE_KEY_PRODUCTIONonce there's a.env.production(env:setupsends both). Values set in the Vercel dashboard override the file and can't be read back, so keep them out. - CI: holds no key.
ci.ymldeletes the encrypted files before building, so CI builds with every integration off, like a fresh fork; the Vercel preview build is the check with real config. This keeps the key away from dependency code in Dependabot and fork PRs. - Client handoff: the repo plus the private key. There is no vendor account to transfer.
To share the key: bun run env:setup --copy puts the lines for a teammate's .env.keys on your clipboard without showing them.
app/ # Next.js routes ((site)/page.tsx is the manual; the root layout is a bare shell shared with /studio); llms.txt/, agent-content/, sitemap.ts, robots.ts, and manifest.ts (AEO surfaces) live at the app/ root
components/ # UI components
lib/ # Everything non-UI
├── hooks/ # Custom React hooks
├── integrations/ # Opt-in plugins (Sanity, Shopify, HubSpot…)
├── features/ # Feature flags gating opt-in surfaces (e.g. WebGL)
├── webgl/ # 3D graphics (opt-in, behind lib/features)
├── seo/ # Sitemap, robots, and metadata helpers
├── utils/ # Pure utilities
├── scripts/ # CLI tools (setup:project, handoff, generate)
├── styles/ # CSS & Tailwind
└── dev/ # Debug tools (optional)
Mental model: UI →
components/, everything else →lib/. Integrations are opt-in plugins, not baked-in defaults. Conventions live in AGENTS.md.
| Area | Documentation |
|---|---|
| Engineering Standards | AGENTS.md - Canonical rules for all AI tools and contributors |
| Architecture | ARCHITECTURE.md - Key decisions, patterns, customization |
| Security | SECURITY.md - Security policy, CSP composition, vulnerability reporting |
| Component Inventory | COMPONENTS.md - Auto-generated component/hook/utility manifest |
| Changelog | CHANGELOG.md - Release history and versioning policy |
| App Router | app/README.md - Pages, layouts, routing |
| API Routes | app/api/README.md - Endpoint reference, webhook setup |
| Components | components/README.md - UI reference |
| Library | lib/README.md - Hooks, utils, integrations |
| Integrations | lib/integrations/README.md - Sanity, Shopify, etc. |
| Everything else | AGENTS.md § Documentation Map lists every README in the repo |
bun dev # Development server
bun run build # Production build
bun run check # lint + format check + type-aware lint + typegen + tsc + unit tests + oxlint-plugin tests + manifest + asset budget (run before pushing)
bun run setup:project # Strip integrations you don't need
bun run handoff # Client delivery: strips branding, swaps in PROD-README, generates inventory (--dry-run, --force)The full list lives in package.json.
vercelvercel (or the Deploy button above) links and deploys the project the first time. Once the project is linked, push to the tracked branch and Vercel deploys automatically — the CLI is only needed again for manual/preview deploys.
Optional GitHub Secrets for the Lighthouse CI workflow: VERCEL_TOKEN
(Vercel API token — the job skips gracefully with a warning when it's absent
or invalid) and VERCEL_AUTOMATION_BYPASS_SECRET (needed when previews are
Deployment Protection-guarded — the audit step skips loudly without it
instead of scoring the SSO login page).
See ARCHITECTURE.md for the deployment checklist and cache strategies.
Satus is built for one job: content-driven marketing and creative sites with real motion, a CMS, and sometimes a storefront. The usual alternatives are good at different jobs — here is where the lines actually are, checked against each project in August 2026.
| Feature | Satūs | create-next-app |
next-forge |
create-t3-app |
next-enterprise |
|---|---|---|---|---|---|
| Built for | creative & marketing sites | bare scaffold | SaaS monorepo | typesafe full-stack apps | enterprise apps |
| Next.js today | 16.3 | 16.3 | 16.1 | 15.5 | 15.5 |
Instant navigations on (cacheComponents) |
✓ | ✗ opt-in | ✗ | ✗ | ✗ |
| Bun runtime + test runner | ✓ | ✗ | ✗ | ✗ | ✗ |
oxc toolchain (oxlint + oxfmt) |
✓ | ✗ | ✗ | ✗ | ✗ |
| Tailwind + CSS Modules under a cascade contract | ✓ | ✗ | ✗ | ✗ | ✗ |
| Animation stack (Lenis, GSAP, Tempus) | ✓ | ✗ | ✗ | ✗ | ✗ |
| WebGL module (React Three Fiber) | ✓ opt-in | ✗ | ✗ | ✗ | ✗ |
| CMS integration | ✓ Sanity | ✗ | ✓ | ✗ | ✗ |
| E-commerce storefront | ✓ Shopify | ✗ | ✗ | ✗ | ✗ |
| Auth | ✗ | ✗ | ✓ Clerk | ✓ | ✗ |
| Payments | ✗ | ✗ | ✓ Stripe | ✗ | ✗ |
| Database / ORM | ✗ | ✗ | ✓ Prisma | ✓ | ✗ |
| Turborepo monorepo | ✗ | ✗ | ✓ | ✗ | ✗ |
| Pick your pieces | ✓ strip after clone | ✗ | ✗ | ✓ choose at init | ✗ |
| Unit tests | ✓ bun test |
✗ | ✓ Vitest | ✗ | ✓ Vitest |
| E2E tests (Playwright) | ✓ with a11y + instant-nav asserts | ✗ | ✗ | ✗ | ✓ |
| Storybook | ✗ | ✗ | ✓ | ✗ | ✓ |
| CI quality gates | ✓ | ✗ | ✗ release only | ✗ | ✓ |
| Performance budgets in CI | ✓ asset weight (Lighthouse advisory) | ✗ | ✗ | ✗ | ✓ bundle size |
| Security headers + rate limiting | ✓ enforced CSP, composed | ✗ | ✓ Arcjet | ✗ | ✗ |
| Observability wired | ✗ | ✗ | ✓ | ✗ | ✓ OpenTelemetry |
| Agent-ready docs | ✓ AGENTS.md + llms.txt + manifest | ✓ AGENTS.md | ✗ | ✗ | ✗ |
Pick something else when the job is different: next-forge for a SaaS with billing, create-t3-app when the product is a typesafe API-heavy app, next-enterprise when the org runs Kubernetes and wants observability from day one. For a content site that has to move well and ship fast, this is the shorter path.
MIT - Built by darkroom.engineering
