Evolve Stores
A static-site generator that builds 32 independent brand storefronts from one codebase, with build-time voice and brand-isolation gates and gated digital delivery.
- 32
- independent storefronts generated from one codebase (11 brand + 21 community-hub)
- 21
- community-hub stores, all isolation-gated at build time

Problem
Selling small digital products and merch across many small brands the operator runs or advises on had been outsourced to a rented platform (a Stan-store-style tool), which meant per-transaction platform fees, a shared visual shell that could not carry each brand's own identity, and no way to enforce, at build time, the rules a catalog of this many brands needs: that a brand with its own separate identity never shows another brand's name on its pages, and that no page ships with an em or en dash, a character known to silently break Cloudflare Pages deploys. The repo names this directly: it is a Stan-store replacement built to be owned rather than rented.
The catalog also has a structural constraint a generic storefront tool cannot express: some brands carry their own separate identities, and community-hub sites need their own unbranded stores at scale (21 of them) without becoming 21 separate hand-maintained codebases. A single generator with per-brand configuration and a build-time isolation check is the only way to get both economies of scale and a hard guarantee against cross-brand leakage, rather than relying on a person remembering to check each site by hand before every deploy.
What was built
The build is evolve-stores: a plain-Node static-site generator (no framework, no package.json) that produces independent storefronts, one per brand, each shipping to its own Cloudflare Pages project. brands.mjs and communities.mjs together register 32 stores (11 brand-level storefronts plus 21 community-hub storefronts), each with its own domain, palette, and Cloudflare Pages project name; build.mjs renders every brand's HTML pages, an OG image, and a per-brand Cloudflare Pages Function (_worker.js) that gates paid downloads. build.sh runs generate, then screenshot-renders each og.png with headless Chromium, then two hard gates: a voice guard that fails the build on any em or en dash in served HTML, and an isolation gate that greps every brand flagged isolated for other brands' names and the shared analytics property id and fails the build if any appear.
On top of the storefront shell sits a digital-delivery layer. Small PDFs (lead magnets and paid guides) are embedded as base64 directly in the generated worker and served after the worker verifies the buyer's Stripe Checkout session server-side. Larger products, such as multi-gigabyte 4K b-roll packs and a home-by-home video library, are stored in Cloudflare R2 and served through a presigned S3-compatible redirect generated at request time, because they are too large to embed. A subscription membership tier ($99/month, cap-gated downloads against a D1-backed usage table) was added most recently, verified by Stripe webhook signature checks, and hardened after a same-day adversarial security review that fixed five real defects before the tier could take money. Node's built-in test runner covers the pure helper functions that get inlined into the generated Workers.
Technical approach
The generator's most consequential decision is architectural: pure helper functions (Stripe signature verification, HMAC token signing for passwordless login, R2 presigning, membership quota decisions) are written once as plain, closure-free functions in broll-lib.mjs and members-lib.mjs, then pulled into the generated Cloudflare Pages Function by calling .toString() on each function and splicing the source text directly into the worker file that gen-download.mjs writes. That means the exact code executing at the edge is also the code Node's built-in test runner exercises directly, with no separate build step or bundler translating between the two, and no drift is possible between "what was tested" and "what is deployed" because they are the same source text.
The delivery layer is split by product size rather than by brand: PDFs small enough to embed are read from disk, base64-encoded, and inlined into the generated worker at build time, then served only after the worker calls Stripe to verify the buyer's Checkout session server-side. Anything too large to embed, including multi-gigabyte 4K b-roll packs and a home-by-home video library, is stored in R2 and served through an S3-compatible presigned URL computed per request rather than a stored public link, which keeps the objects private while avoiding any origin bandwidth cost. The distinction is enforced structurally in the type of each catalog entry rather than by convention, so a product's delivery path is chosen by its declared type, not by which brand it happens to belong to.
The build pipeline enforces two brand-safety invariants mechanically rather than procedurally. A voice guard scans every generated HTML file for an em or en dash and fails the entire build if it finds one, because that character is known to silently break a Cloudflare Pages deploy. A separate isolation gate runs only against brands flagged isolated in the registry (every community-hub store among them) and greps their rendered output for other brands' names and the shared analytics property id, failing the build on any hit. Both gates run inside build.sh after page generation and before any deploy step, so a leak is caught in the same run that would otherwise ship it, not caught later by a person reviewing the live site.
Creative approach
Craft
The store shell borrows a sectioned, editorial layout (store-sections.mjs) rather than a flat product grid: items are grouped under headed sections in an order the brand itself declares, with a leftover bucket for anything that doesn't fit a named section so nothing silently disappears from the page. Titles use a small braced-word convention, "Creative. Strategic. {Impactful.}", where the braced word alone is picked out in an accent typeface, giving the generator a single, reusable way to typeset an emphasized word without hand-authored markup per brand. Consecutive items that share a group label get that label printed once above the run rather than repeated per card, a small legibility decision that keeps a long single-column list from feeling like a spreadsheet. The Studio home-tour library page pushes the same restraint further: home titles are rendered digit-free from the source registry, and a client-side search filters by builder, community, model, or month against a normalized data attribute rather than a server round trip.
Reframe
The catalog for Evolve Studio was rebuilt around "honest counts": pack sizes and preview clips were re-cut so the copy states exactly what ships (30 and 46 clips, not rounded or aspirational numbers), and the preview montages were rebuilt from the same final cut rather than an earlier draft. A parallel rule in build.mjs renders a pack's <video> element only when its source asset actually has bytes, which converts a placeholder-preview problem (a 0-byte file silently shipping as a broken player) into a structural impossibility rather than a review checklist item. The same discipline shows up in the delivery worker: a monthly membership slot is now checked against R2 availability before being spent, so a download that cannot actually happen no longer costs the buyer part of their quota.
Process and what failed
The clearest documented failure-then-fix is the membership tier's security review, run the same day it was built: three model reviewers plus a skeptic attacked the feature before it could take money, and found five real defects, each fixed with an accompanying test rather than a note. A canceled, longer-dated subscription could shadow a member's active one and lock them out; the webhook accepted any subscription checkout when no membership payment link was configured, instead of failing closed; a download that could not be delivered still consumed a monthly slot; a missing or erroring database binding crashed the request instead of returning a clean 503; and the sign-in email was sent before the response, which let response timing leak whether an email address was an active member. All five are visible as a single commit with matching test additions, which is a different artifact than a design decision described after the fact.
Outcome
All 32 storefronts build from the same generator, and on 2026-09-23 every checked store domain, the Studio, University, Agentic and Estates stores and the isolation-gated stores alike, returned HTTP 200 in production. Digital delivery is live for embedded PDFs, verified against Stripe Checkout sessions; for the Studio B-roll packs, which sell through live payment links; and for the Studio home-tour library, where each home lists automatically once its R2-backed archive verifies. The newest piece, the $99/month Studio membership, went live after its same-day adversarial review and its five fixes.
What the repo does not show: no revenue, order-count or subscriber figure exists for any store, so none is claimed. One automated test, the clip-index check for the Florida Lifestyle pack, has nothing to assert against because that pack has no footage yet; the store lists it as opening soon rather than selling it.
Related work
- Live2026Community Hub Network21 independently branded community-guide sites, each with live local data, lead capture, and automated monthly digests, built to stay legally clear of brokerage advertising rules.
- Live2026Evolve Agentic SiteA 61-page trilingual marketing and productized-service site with its own tiered pricing engine, four live D1-backed lead endpoints, and a documented history of pricing model…
- Live2026Evolve With AIA courtroom-themed landing page for a satirical AI-operator show, with a self-generating lead-magnet PDF pipeline, an email-gated toolkit, and an evidence-discipline standard…