All notable changes to this project are documented here. The format is based on Keep a Changelog, and this project follows Semantic Versioning.
Satus is a starter template, so semver is read from the perspective of a project that forked it:
- MAJOR: changes that break a fork on update. Removing or renaming a core
primitive (
Image,Link,Wrapper), restructuring directories or path aliases, dropping a built-in integration, or a Node.js / Next.js major bump. - MINOR: additive capabilities. New components, hooks, utilities, or integrations.
- PATCH: bug fixes, dependency bumps, docs, and internal refactors with no consumer-visible API change.
There are no long-term support branches. Forks track upstream by rebasing onto the
latest tag; security fixes land on the latest release (see SECURITY.md).
bun run satusplugin CLI —satus listshows every integration's installed status, andsatus add <plugin>restores a stripped integration into a living project: files are copied from the public satus repo (the registry), dependencies re-pinned, and shared files re-wired through idempotent AST operations, so adding twice is a no-op.setup:projectrecords the git HEAD sha as"satus": { "ref": … }in package.json andsatus addfetches that pinned ref by default (--fromuses a local checkout,--refoverrides). Both CLIs run non-interactively (--preset/--keep/--yes/--skip-install), verified by a network-free round-trip e2e (lib/scripts/satus.e2e.test.ts). (#185)- Storybook themed to match Satūs: stories render on the site palette through shared CSS tokens (edit the site, the catalogue follows), with a dark/light/red/evil theme toolbar and a branded manager. (#210)
- Optional
/storybookroute that proxies to a standalone Storybook deployment, enabled per-environment viaNEXT_PUBLIC_STORYBOOK_URLand force-disabled in Production. (#210) - One-click Deploy to Vercel button (README + in-app manual) and clearer domain-setup guidance. (#210)
parseApiResponse(lib/utils/validation.ts) — validates external API responses with Zod at the integration boundary (HubSpot, Mailchimp, Shopify GraphQL envelope), so malformed responses fail clearly at the edge instead of crashing downstream. (#198)- React Scan render profiler as an opt-in Orchestra dev tool — toggle 🔬 in the ⌘O palette, off by default (no profiler overhead unless enabled). (#209)
useRevealhook (lib/hooks/use-reveal.ts) — reveal-on-scroll primitive animatingtransform/opacityon the compositor thread via a[data-reveal]/[data-reveal-item]CSS contract inglobal.css; degrades to visible without JS and honors reduced-motion. (#189)- Animation standards section in AGENTS.md — CSS/
useRevealfor reveals, GSAP for orchestration. (#189) AGENTS.mdas the single source of truth for engineering standards;CLAUDE.mdand.cursor/rulesreduced to thin pointers (#175).- Auto-generated
COMPONENTS.mdmanifest viabun run generate:manifest, withbun run manifest:checkto catch drift in CI (#178). SECURITY.mdsecurity policy with private vulnerability reporting (#174).- This
CHANGELOG.md, andpackage.jsonversion synced to the release tag.
- Integration registry is single-source:
INTEGRATION_BUNDLESkeys are typed againstRemovableIdfromlib/integrations/registry,prepare-handoffmatches integrations by id, andnext.config.tscleanup runs through typed ts-morph AST ops — the regexupdateNextConfigis deleted. - Removing the theatre integration now also strips the Theatre.js debug wiring from the webgl fluid/flowmap hooks (via a new
removeCallStatementAST op), so keeping webgl without theatre builds cleanly. - WebGL: deleted the
flowmap-provider,image, andpostprocessingcomponents; the tunnel utility is vendored aslib/webgl/utils/tunnel.ts(replacing thetunnel-ratpackage); renderer/context typing is honest (noascasts);GlobalCanvasis lazy-loaded bylib/featuresrather than re-exported asLazyGlobalCanvasfromglobal-canvas. - Integrations: Shopify customer actions run through
runFormAction; Turnstile validation extracted tolib/integrations/turnstile(shared across integrations); the cart reconciler uses a discriminated union and every cart action returns oneCartActionResultshape; optimistic add wraps instartTransition; the Mailchimp error path validates with Zod. - App:
error.tsxandglobal-error.tsxrender a sharedErrorView;APP_BASE_URLis exported once fromlib/env;fb:app_idreads from validated env;next.config.tsexports its config directly; dead nav scroll-lock and its orphaned store removed. - components/ui: form registration is name-based instead of index-based;
real-viewportslimmed to setting only--scrollbar-width; Base UI triggers use render props;fetchJSONresponses are schema-validated; conditionalclassNamespreads replaced withcn(). - Styles: easings and colors are each defined once —
css/easings.cssis a hand-authored@themepartial outside the generator — and thenesting-rulesno-op was dropped from the PostCSS chain. - Dependencies and lib/utils: removed
cross-env(theanalyzescript setsANALYZE=trueinline),tunnel-rat, andpostprocessing;@theatre/coremoved todependencies(imported bylib/webgl/utils/fluidandflowmaps); bumpedgroqandnext-sanity; deleted the unusedlib/utilsmodulescontext,animation,viewport, andeasings, with docs updated to match. - Fonts now load via
next/font/google(Oswald for display, Spline Sans Mono for body) instead of self-hosted woff2 — no font binaries ship in the repo, and the brand type scale (sizes, line-heights, tracking from the Figma spec) is encoded inlib/styles/typography.ts. (#210) - Components are now catalogued in Storybook (
bun storybook) instead of an in-app/componentspage; added stories for accordion, alert-dialog, checkbox, link, marquee, menu, switch, and tabs. (#210) app/page.tsxis now a self-contained in-app manual (clone → ship); replace it with your homepage and deleteapp/page.module.csswhen you start a project. (#210)- Integrations reframed as opt-in plugins isolated under
lib/integrationswith// USAGEnotes — the precursor to the additivesatus add <plugin>CLI proposed in #185. (#210) - Shopify cart types: named the post-reshape line item (
CartLineItem), madeCart.idrequired, and removed 11ascasts;removeItem/updateItemQuantitynow take the client-heldlineId, dropping agetCartround-trip per mutation. (#198) - Mailchimp integration returns typed
MailchimpErrorCodevalues instead of sniffing error strings; tag/note writes are best-effort. (#198) - WebGL: removed the unused
localcanvas mode andcanvas/webgl.tsx, dropped vestigialSceneinheritance fromProgram, and made the flowmap/fluid sims opt-in instead of booting on every WebGL page. (#199, #206) - Sanity example pages wrap
sanityFetchin a'use cache'function for Cache Components (cacheComponents) compatibility, which also dedupes the page andgenerateMetadatafetches. (#205, #208) - Dev scripts deduped: one shared ts-morph
Projectinast-transforms, reusedtoPascalCase/cancelGuard, and renamed the two divergentupdatePackageJsonhelpers. (#198) spring()(lib/utils/animation.ts) documentation now steers to CSSlinear()easing for off-thread springs. (#189)- Dependabot PRs now auto-sync
bun.lockvia apull_request_targetworkflow, so they pass the frozen-lockfile install in CI. (#190) - Consolidated root docs: folded
BOUNDARIES.mdintoARCHITECTURE.mdand refreshed the doc maps inREADME.mdandAGENTS.md(#177).
- The in-app
/componentsshowcase, theapp/(examples)/example routes (R3F, Sanity, Shopify, HubSpot), and theapp/studio/route — component demos moved to Storybook and integration usage distilled into// USAGEcomments inlib/integrations/*. Only the demo surface is gone; the reusable integration code stays. (#210)
cacheTag()crash on/sanityand/sanity/[slug]under Cache Components —sanityFetchcallscacheTag(), which must run inside a'use cache'function. (#208)use-webgl-elementattached twoIntersectionObservers on mount; now one. (#205)- Accordion drove
Collapsible.Rootwith a duplicate controller, and the custom scrollbar overshot when dragged on long pages. (#205) - React Scan dev panel was hijacked by Lenis smooth scroll; added it to Lenis's
preventlist. (#207) - Turnstile dev-mode bypass collapsed to a single path. (#205)
- Shopify cart
addItemnow validates input before creating a cart, so invalid requests no longer leave an orphaned cart and cookie behind (#173).
- Hardened HubSpot form HTML stripping into a complete
stripHtmlTagsparser (a character scan, not regex), resolving the CodeQLjs/incomplete-multi-character-sanitizationalert (#179, #180).
- Hand-rolled
components/ui/dropdown/— superseded by the accessible Base UISelect. (#202, #205) lib/utils/animation.tsre-exports ofclamp/lerp/mapRange/modulo/truncate— import these from@/utils/mathinstead. (#198)- In-repo marketing homepage — the
app/(marketing)landing sections (hero, features, value-props, getting-started, presets) and marketing-only WebGL effects (animated-gradient,liquid-drip,split-text). Satus is a starter kit; its marketing lives at oss.darkroom.engineering/satus. (#188) /homerewrite + redirect and theassets.darkroom.engineeringimageremotePatternfromnext.config.ts. (#188)- Dead code: orphaned WebGL GLSL utilities (
noise/blend/functions) and unusedlib/utilshelpers (normalize,isEmptyObject,twoDigits,numberWithCommas) (#172).
2.0.1 - 2026-06-02
- Storybook 10 component sandbox (
@storybook/nextjs-vite+ MCP addon, wired for Tailwind v4) (#159).
- Integration-removal transforms in
setup:projectrewritten from regex to ts-morph AST operations, resilient to formatting changes (#155). - Client-handoff doc templates extracted from
prepare-handoff.tsinto editable template modules (#156). - Dependency batch:
next/@next/bundle-analyzer16.2.7,react/react-dom19.2.7,@types/react19.2.16,ts-morph28,@typescript/native-previewsnapshot (#171). hamo/tempuspinned to their current dev versions and excluded from Dependabot, since no stable v1 exists upstream (#157, #164).
2.0.0 - 2026-06-01
- New liquid-metal "drip" hero effect (TSL, screen-space, ~120 FPS).
- WebGL layer migrated to TSL NodeMaterials on
WebGPURenderer, with a WebGL2 fallback for browsers without WebGPU (gradient, fluid sim, flowmap, R3F demo). - Next.js 16 Cache Components fixes (
revalidateTagcache profiles); next-sanity 13 (defineLive/defineQuery). - Shopify data layer split from a single 440-line module into focused files plus a
shared
reshape.ts. - Base UI cleanup, server-rendered theme default (removed inline
<script>), leaner.env.example, dependency bumps.
- Browsers without WebGPU now use the WebGL2 backend instead of the classic renderer, so TSL materials and animations work everywhere.