Files

5.3 KiB
Raw Permalink Blame History

Vibn — Marketing Site

Production Vite + React 18 + Tailwind CSS implementation of the Vibn marketing homepage and beta-invite signup page.

Stack

  • Vite 6 — dev server, HMR, multi-page build
  • React 18 — function components + hooks, no router (two static entries)
  • Tailwind CSS 3 — utility classes + a small @layer components block for things that don't compress cleanly to utilities (gradients, pseudo-elements, custom shadows)
  • No CSS-in-JS, no UI library — design tokens live as CSS custom properties so a tweak panel or theme switcher can runtime-swap the accent palette
  • Geist + Geist Mono — loaded from Google Fonts in each entry HTML

Getting started

npm install
npm run dev          # http://localhost:5173 (homepage)
                     # http://localhost:5173/beta.html (signup)
npm run build        # production build → dist/
npm run preview      # serve the built bundle

Project layout

vibn-app/
├── index.html              ← homepage entry
├── beta.html               ← beta-signup entry
├── vite.config.js          ← multi-page input config
├── tailwind.config.js      ← design tokens + named animations
├── postcss.config.js
├── public/
│   └── logo-black.png      ← favicon (V_ mark on black)
└── src/
    ├── main.jsx            ← mounts <App />
    ├── beta-main.jsx       ← mounts <BetaApp />
    ├── styles.css          ← Tailwind + tokens + keyframes + .btn / .card / .logo-mark
    ├── App.jsx             ← homepage composition
    ├── BetaApp.jsx         ← signup-page composition
    ├── lib/
    │   └── primitives.jsx  ← Logo, LogoMark, Arrow, Eyebrow, Glow, TrustStrip
    └── components/
        ├── Nav.jsx
        ├── Hero.jsx                ← Reddit-quote / promise variants + prompt input
        ├── Wall.jsx                ← faux chat-window "homework wall" scene
        ├── CrossedOut.jsx          ← animated strike-through term wall
        ├── Journey.jsx             ← 4-step path + "where others stop" marker
        ├── Audience.jsx            ← 3 audience cards w/ Reddit-style quotes
        ├── Closing.jsx
        ├── Footer.jsx
        ├── LaunchModal.jsx         ← hero prompt-submit modal
        └── beta/
            ├── BetaForm.jsx        ← 5-step form
            ├── Confirmed.jsx       ← submitted state w/ queue card + referral
            └── Benefits.jsx        ← "what you get inside" trio

Design tokens

All colors are exposed as CSS custom properties (see src/styles.css, :root block) and aliased in tailwind.config.js → theme.extend.colors:

Tailwind class CSS var Default
bg-bg --c-bg oklch(0.155 0.008 60)
bg-bg-1 --c-bg-1 oklch(0.185 0.009 60)
text-fg --c-fg oklch(0.97 0.005 80)
text-fg-dim --c-fg-dim oklch(0.78 0.006 80)
text-fg-mute --c-fg-mute oklch(0.58 0.006 80)
text-fg-faint --c-fg-faint oklch(0.42 0.006 80)
text-accent --c-accent oklch(0.74 0.175 35) (coral)
bg-accent --c-accent (same)
border-hairline --c-hairline oklch(0.32 0.010 60 / 0.55)
text-ok --c-ok oklch(0.78 0.16 155)

To re-theme at runtime, set the variables on :root from JS:

document.documentElement.style.setProperty("--c-accent", "#9ee649");
document.documentElement.style.setProperty("--c-accent-glow", "#9ee64959");
document.documentElement.style.setProperty("--c-accent-fg",  "#0f1408");

Type scale

Fluid clamp() sizes are used inline:

  • Hero headline: clamp(44px, 7.4vw, 104px)
  • Section H2: clamp(36px, 4.8vw, 64px)
  • Body / sub: clamp(1617px, 1.62.2vw, 1928px)

Geist is the body face; Geist Mono is reserved for tags, eyebrows, code, and "trust strip" details.

Animations

Keyframes are defined once in styles.css; some are also registered as named Tailwind utilities (animate-caret-blink, animate-pulse-ok, etc.) for ergonomics. Anything not in the config uses an inline style={{ animation: ... }} with the keyframe name.

Notes & next steps

  • No router. Homepage links to /beta.html directly. Drop in react-router-dom if you need client-side navigation between more pages.
  • Form submission is a stub. BetaForm just waits 700 ms and toggles to the confirmed state. Wire to your real endpoint (e.g. fetch("/api/invite", …)).
  • Queue position is deterministic on email. Replace with the real one from your backend.
  • The hero "Live from minute one" pill is currently not rendered in this port (the marketing prototype defaults it off). Re-add by uncommenting the pill in Hero.jsx if you want it back.
  • The Tweaks panel from the prototype is not ported. Tweaks are a design-time tool; runtime theming is enough via the CSS-var token system.

Browser support

Uses oklch(), text-wrap: balance, and backdrop-filter. Safari 15.4+, Chrome 111+, Firefox 113+.