vibe-prototypes

A lightweight, zero-build prototype server for the Let's Vibe wellness platform. It serves design-system docs, standalone HTML prototypes, and source files from one place — markdown is rendered to clean HTML, code files are syntax-highlighted on the fly, and everything else is served statically with a browsable directory index.

Use it to explore the Living Sanctuary brand system (letsvibe-brand/), demo interactive mockups (prototypes/), and read code without leaving the browser.

New here, or not technical? Open the home page and follow Start here: copy-ready prompts for Claude to create a prototype or a new version, with no coding. Source: getting-started/prompts.json. Claude Code users can also run the shortcuts in .claude/commands/: /get-latest, /new-prototype, /new-version, /check-standards and /ship (each is explained with an example on the home page).

AI agents and AI-assisted contributors: read and follow AGENTS.md before generating or changing anything in this repo. It holds the mandatory structure, brand and deployment rules.

Quick start

pnpm install      # install dependencies (pnpm@10.12.4)
pnpm start        # or: node app.js

Then open http://localhost:3000.

No build step, no environment variables, no config — node app.js serves the repo root on port 3000.

Deploying to Vercel

Import the repo in Vercel with no extra settings. vercel.json routes every request to api/index.js, which re-exports the Express app from app.js, so markdown rendering, view-source and the directory tree behave exactly as they do locally. includeFiles bundles prototypes/ and letsvibe-brand/ into the function. New top-level folders must be added to that glob.

Useful routes

URL What you get
/ Browsable directory index of the repo
/letsvibe-brand/README.md Brand system quick-start (rendered markdown)
/letsvibe-brand/brand/BRAND_GUIDELINES.md Full brand & design guidelines
/letsvibe-brand/docs/index.html Interactive styleguide
/prototypes/wellness-hub/v8 Wellness Hub interactive prototype (latest)
/prototypes/wellness-hub/v7 Wellness Hub — previous version
/letsvibe-brand/tokens/tokens.json Any code file → syntax-highlighted view

How it works

app.js is an Express 5 server with three layered middleware, applied in order:

  1. Markdown rendering — any GET/HEAD request for a *.md file is parsed with marked (code blocks highlighted via highlight.js), sanitized with DOMPurify (bound to a shared jsdom window), and wrapped in a GitHub-style page with light/dark themes.
  2. View source — navigating directly to a developer file (.js, .ts, .json, .css, .scss, .yml, and ~20 more) returns a syntax-highlighted page. This is gated on the Sec-Fetch-Dest: document header, so the same file requested as a page asset (<link>, <script>, fetch) still serves raw — keeping the live prototypes working. .html/.htm are intentionally excluded so prototypes render instead of showing source.
  3. Static serving — everything else is served by express.static, with serve-index providing a directory browser (with node_modules hidden).

Path traversal is guarded by safeResolve, which rejects any request that resolves outside the repo root.

Project structure

vibe-prototypes/
├── app.js                       # Express server (markdown render + view-source + static)
├── package.json                 # deps; `start` script
├── CHANGELOG.md                 # Keep a Changelog + SemVer
├── letsvibe-brand/              # "Living Sanctuary" design system
│   ├── README.md                #   brand system quick-start
│   ├── CHANGELOG.md
│   ├── brand/
│   │   └── BRAND_GUIDELINES.md   #   voice, color, type, components, a11y, do/don'ts
│   ├── tokens/                  #   design tokens in 5 formats:
│   │   ├── tokens.json           #     W3C design tokens
│   │   ├── tokens.css            #     CSS custom properties
│   │   ├── tokens.scss           #     SCSS variables + maps
│   │   ├── tokens.ts             #     TypeScript (React / React Native)
│   │   └── tailwind.preset.js    #     Tailwind preset
│   ├── css/
│   │   ├── base.css             #   resets, fonts, focus, reduced-motion
│   │   └── components.css       #   orb, buttons, chips, cards, media helpers
│   └── docs/index.html          #   interactive styleguide
└── prototypes/                  # versioned interactive prototypes
    ├── partners/                # v1/
    ├── vibe-landing/            # v1/
    └── wellness-hub/            # v7/, v8/ (latest) — each version has its own index.html
        └── index.html           #   standalone interactive prototype

Stack

No bundler, no test suite, and no framework — by design. This repo is a self-contained reference/exploration tool and does not depend on the other apps in the monorepo.

Adding & generating prototypes

This server is a drop-in static host: there is no build step, no prototype registry, no environment variables, and no SPA history-fallback. You add a prototype by putting a file on disk; you run it by starting the server; you generate one by handing the prompt below to an AI. The single fact that drives every routing decision: unknown URL paths are never rewritten to index.html, so a deep link or reload only works if it maps to a real file on disk.

1. How to add a prototype

Prototypes live under a name + version folder and are served at the matching URL — the path on disk is the route:

prototypes/<name>/<version>/index.html
On disk Served at
prototypes/wellness-hub/v7/index.html http://localhost:3000/prototypes/wellness-hub/v7
prototypes/<name>/v1/index.html http://localhost:3000/prototypes/<name>/v1

Conventions

No registration, no build. Drop the folder in and it is served immediately — there is nothing to import, register, or compile.

Find it via the directory index. Open http://localhost:3000/ for the browsable index (powered by serve-index, node_modules hidden), then drill into prototypes/ → <name> → <version>. Any .md you add renders as a styled page; any source file (.js, .css, .json, .ts, …) opens as a syntax-highlighted "view source" page when you navigate to it directly, but the same file still serves raw when loaded as a page asset (<link> / <script> / fetch), so your prototype keeps working. .html / .htm are excluded from view-source so prototypes render. (More on this in How it works.)

Brand tokens are picked up automatically — if you reference them. The "Living Sanctuary" design system lives in letsvibe-brand/. From a prototypes/<name>/<version>/ folder, link the tokens with a relative path three levels up to the repo root:

<!-- from prototypes/<name>/<version>/index.html -->
<link rel="stylesheet" href="../../../letsvibe-brand/tokens/tokens.css">
<link rel="stylesheet" href="../../../letsvibe-brand/css/base.css">
<link rel="stylesheet" href="../../../letsvibe-brand/css/components.css">

These load raw because they are page assets, not direct navigation (the view-source highlighter only triggers on Sec-Fetch-Dest: document). So var(--pine), var(--citrine-soft), var(--font-display), etc. resolve as normal stylesheets. For a fully portable single file you may instead copy the token :root block inline into a <style>. Either way, consume the tokens rather than hard-coding hex, and honor prefers-reduced-motion.

⚠️ Routing constraint — read before choosing navigation. This server has no catch-all / history.pushState fallback. Unknown URLs are not rewritten to index.html, so a client-side router that pushes sub-paths like /flow/step-2 will 404 on reload or deep-link — the server looks for a file at that path and finds none.

Option How Real browser history? Deep-link + reload? Best for
(a) Multi-page Separate real .html files linked with <a href> Yes (native) Yes — every screen is a real file The default. Simplest and most robust here.
(b) Hash routing One file; routes live in the fragment (#/step-2) driven by hashchange / popstate Yes — each hash is a history entry Yes — the fragment travels with the URL; the server only ever serves the one file A single-file SPA feel with no server changes.
(c) pushState Only if every pushed path maps to a real served file Yes Only for paths backed by real files Avoid unless every path is a real file.

Do not use pushState to paths that have no backing file. It otherwise requires editing app.js to add an SPA fallback — out of scope. When in doubt, use (a) or (b): both produce genuine Back/Forward history and reloadable, shareable URLs on this static server.

2. How to run it locally

See Quick start for the full story; the essentials:

pnpm install      # pnpm@10.12.4
pnpm start        # or: node app.js

Then open http://localhost:3000 (port 3000, serves the repo root) and navigate to prototypes/<name>/<version>. No build, no env vars, no config.

3. AI prompt template — generate a handoff-ready prototype

Paste the block below into Claude (or another capable AI), fill the <PLACEHOLDERS>, and you'll get a self-contained prototype that drops onto this server and is engineered for a Creative Technologist to fold into a real codebase — explicit data seams, a typed state model, marked component boundaries, and a machine-readable flow map.

You are building a self-contained interactive prototype for the "Let's Vibe" wellness
platform. It will be dropped, with NO build step, onto a static Express server that serves
the repo root and the file's path AS its URL. Follow every constraint below exactly.

PROTOTYPE
- Name:         <PROTOTYPE_NAME>           (kebab-case, e.g. onboarding-flow)
- Version:      <VERSION>                  (e.g. v1)
- Demonstrates: <WHAT IT DEMONSTRATES>     (the product story / value this proves)
- Key screens / flow: <KEY SCREENS / FLOW> (e.g. Welcome -> Goals -> Plan -> Confirmation)

OUTPUT LOCATION (the folder IS the route — do not change this shape)
  file on disk:  prototypes/<PROTOTYPE_NAME>/<VERSION>/index.html
  served at:     http://localhost:3000/prototypes/<PROTOTYPE_NAME>/<VERSION>
                 (the directory URL serves its index.html — no /index.html needed)
  ...plus any sibling .html screens and a FLOW.md, all inside that same folder.

HARD SERVER CONSTRAINTS (the server has NONE of these: build step, bundler, env vars,
config, prototype registry, or SPA history fallback / catch-all route)
- There is NO catch-all: an unknown URL is NOT rewritten to index.html. So:
  * DO use MULTI-PAGE navigation (real sibling .html files linked with <a href>), OR
    HASH routing (#/screen with hashchange + popstate).
  * DO NOT use history.pushState to virtual sub-paths — they 404 on reload/deep-link.
- Follow AGENTS.md "URLs, browser history and deep links": it is mandatory.
- Every screen MUST produce a REAL browser history entry, so Back/Forward work and EVERY
  screen is independently deep-linkable AND reloadable. The state that defines "which
  screen" must live in the URL (the .html file path, or the #hash) — never in memory only.
- ACCESSIBLE AND RESPONSIVE ARE MANDATORY: follow AGENTS.md section 5 (WCAG 2.2 AA, mobile-first,
  no horizontal scroll from 320px). Do not return a prototype that fails either.
- Self-contained: vanilla HTML/CSS/JS, no npm install, no CDN that could go offline
  (inline small deps). It must run by opening its URL on this server, nothing else.

DESIGN TOKENS — "Living Sanctuary" (consume them; do not invent colors/fonts)
- Reference them with (3 levels up from the version folder; loads raw as an asset):
    <link rel="stylesheet" href="../../../letsvibe-brand/tokens/tokens.css">
    <link rel="stylesheet" href="../../../letsvibe-brand/css/base.css">
    <link rel="stylesheet" href="../../../letsvibe-brand/css/components.css">
  For maximum portability you MAY instead copy the token :root block inline.
- Use the token vars, e.g.:
    surfaces: --mist / --paper        text: --ink / --ink-soft
    brand greens (carry the design): --sage / --sage-deep / --pine / --pine-2
    spotlight: --citrine / --citrine-soft  (ONE gold spotlight per screen — never more)
    type: --font-display (Fraunces, headings) / --font-body (Hanken Grotesk, text)
    --s-* spacing, --r-* radius, --dur-* / --ease motion.
  Motion is calm and reactive: ALWAYS use CSS transitions (JS only toggles a class/attribute), with the
  --dur-*/--ease tokens, and MUST honor @media (prefers-reduced-motion: reduce).
  LIGHT AND DARK MODE ARE REQUIRED (see AGENTS.md "Light and dark mode (required)"): declare
  color-scheme light dark, follow prefers-color-scheme using the token mapping (mist/paper/ink/ink-soft in
  light; ink/pine-2/on-dark/on-dark-soft in dark; CTA uses the -on-dark tokens in dark). Design the dark
  theme, do not just invert. No hardcoded hex.

HANDOFF-READY — this is the point of the deliverable. A Creative Technologist must be able
to lift this into a production React/Vue codebase with the seams already drawn:

1. DATA SEAMS (mock vs real) — isolate ALL fake data in ONE place per screen, a clearly
   labeled block:
     // === MOCK DATA BOUNDARY — replace with real API/props ===
     //   shape:    { ...the exact object/array shape a real source must return }
     //   source:   GET /api/<resource>   (or: prop passed from parent)
     //   replace:  swap the literal below for a fetch()/prop; nothing else changes
   No fake data may be inlined into markup or logic — only read through these boundaries,
   so the swap is a single, obvious edit.

2. STATE MODEL — declare ONE explicit state object at the top of the script with typed
   fields (use JSDoc @typedef), documenting which fields are URL-derived (the source of
   truth for the current screen) vs ephemeral UI state. Show the single function that maps
   URL -> state and the single function that renders state -> DOM. No hidden globals.

3. COMPONENT BOUNDARIES — build each screen and each reusable piece (card, header, stepper,
   button group) as a small named factory/function returning its markup, each preceded by:
     // <ComponentName> — props: { ... }  | future: maps to a <ComponentName> component
   so the React/Vue extraction is mechanical.

4. INTEGRATION POINTS — at the top of index.html, a comment block listing every external
   thing this prototype would touch in production: API endpoints (method + path + purpose),
   auth/identity assumptions, analytics events fired, and any platform capabilities faked.

5. "WHAT IS FAKED VS REAL" — a short table (in FLOW.md AND as a top-of-file comment) with
   columns: Concern | Faked here | Real source in production | Where to wire it.

FLOW MAP (so an AI agent can crawl and replay the journey)
- Create prototypes/<PROTOTYPE_NAME>/<VERSION>/FLOW.md containing:
  * A route -> screen -> state table: the semantic URL of each screen (real .html path or
    #hash), the screen's human name, what state/URL params it reads, and its exit links
    (which screens it can navigate to). Every screen reachable from index.html.
  * A 3-6 line prose FLOW description of the journey, its goal, and decision points.
  * The "faked vs real" table from item 5.
- Mirror a compact version of the route -> screen -> state map as a comment block at the
  TOP of index.html, so the flow is discoverable from the entry file alone.
- URLs MUST be semantic and self-describing (e.g. .../goals.html or #/goals), so an agent
  can deep-link to and replay any step. Example shape:
    /prototypes/<name>/<VERSION>/             -> Welcome -> { step: "welcome" }
    /prototypes/<name>/<VERSION>/#/intake     -> Intake  -> { step: "intake", answers: {} }
    /prototypes/<name>/<VERSION>/summary.html -> Summary -> { step: "summary" }

ACCEPTANCE CHECK (verify before returning)
  [ ] Opening the entry URL and EVERY screen URL directly (cold reload) renders correctly.
  [ ] Browser Back/Forward move through screens in the right order.
  [ ] No history.pushState to a path without a matching real file.
  [ ] URLs / HISTORY / DEEP LINKS (required): every view, step, tab, detail and meaningful modal has
      its own URL (real .html file or #/hash route; query params inside the hash for filters/sort/
      page). Opening any route cold or reloading lands exactly on that view (no bounce through
      home). Navigation PUSHES history; in-view refinements and auto-redirects REPLACE it. Links
      are real <a href>. Signed-out deep links go to sign-in and return to the requested route.
      Unknown routes show a not-found view. document.title, focus and scroll update per
      navigation. Never put secrets or personal data in a URL. All routes + sample deep links are
      listed in FLOW.md and at the top of index.html.
  [ ] All mock data sits behind labeled MOCK DATA BOUNDARY blocks; markup/logic read only
      through them.
  [ ] Tokens used for all color/type/spacing; exactly one citrine/gold spotlight per screen;
      prefers-reduced-motion honored.
  [ ] LIGHT AND DARK MODE (required): both designed with the token mapping, color-scheme declared, every
      screen and deep link checked and axe-scanned in BOTH modes, no flash of the wrong theme, CTA rule
      and AA contrast hold in both.
  [ ] FLOW.md exists with the route->screen->state table, prose flow, and faked-vs-real
      table; index.html repeats the route map at the top.
  [ ] ACCESSIBILITY (required, WCAG 2.2 AA): semantic landmarks (one <main>, one <h1>, ordered
      headings, <html lang>), real <button>/<a> elements, visible :focus-visible on every
      control, full keyboard operation with no traps, labels for every field, alt text,
      aria-live for dynamic updates, AA contrast in light AND dark, no color-only meaning,
      zoom never disabled.
  [ ] RESPONSIVE (required): viewport meta tag, mobile-first, no horizontal scroll from 320px,
      fluid layout (grid/flex, clamp, rem), verified at 320 / 375 / 768 / 1024 / 1280 px,
      works at 200% text size, touch targets >= 44px.

DELIVERABLES
  prototypes/<PROTOTYPE_NAME>/<VERSION>/index.html      (entry + top-of-file flow/integration map)
  prototypes/<PROTOTYPE_NAME>/<VERSION>/<screen>.html   (one per screen, if multi-page)
  prototypes/<PROTOTYPE_NAME>/<VERSION>/FLOW.md         (flow map + faked-vs-real table)
  prototypes/<PROTOTYPE_NAME>/<VERSION>/CHANGELOG.md      (changes from previous versions and updates made)
- State the routing strategy you chose (multi-page or hash) and why, at the top of FLOW.md.

GIT
- Repository location is 'https://github.com/HighestVibrations/vibe-prototypes'
- use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit format
- IF there is a previous version ensure CHANGELOG.md created for the new version speaks to changes from previous version. 

After the AI generates the files, drop the folder under prototypes/, run pnpm start, and open http://localhost:3000/prototypes/<name>/<version>. Reload each screen and exercise Back/Forward to confirm the routing constraint is respected before handing off.