Skip to content

2 cases built from this template

Same prompt, different [VARIABLES]. Click one to preview it above.

About this template

A two-page website for a neighborhood yoga studio: a home page with the practice styles, an intro offer, teacher bios, membership comparison and a first-timer FAQ, and a schedule page with the full weekly class grid filterable by level and style. The default content follows an invented studio in Boulder teaching vinyasa, yin and restorative classes, but the structure suits any studio or movement space: change the brand, city, street, practice styles and founding year and every section still reads true. The home page opens on an airy photograph of the empty studio in morning light, then moves through three practice-style cards, a warm intro-offer band, four teacher cards with AI-generated teaching portraits (fictional people users swap for their own staff photos), specialties and a one-line philosophy each, a three-tier membership comparison that shows the per-class math, and a plain-spoken FAQ. The schedule page lays the week out as day columns with class cards (time, name, level pill, duration, teacher), filter chips for level and style, and a booking modal that confirms in the browser with a saved spot card — no backend, nothing submitted. The palette is warm sand and shell with deep green-grey text and a single dusty clay accent; Marcellus sets the headlines in a calm Roman serif and Mulish the body, both self-hosted. To adapt it, swap the variables and rewrite the copy in one content file; classes, teachers, tiers and hours all read from it.

The template prompt

The live demo was built from exactly this text — nothing added. The other cases only change the values of the [VARIABLES].

# Yoga Studio Website

Build this website exactly as described below. Replace the [VARIABLES] with your own values; keep everything else.

## Brief
A two-page website for [BRAND], a neighborhood yoga studio on [STREET] in [CITY], open since [FOUNDED], teaching [PRACTICE]. It must feel like a real, calm studio: airy photography of the empty room, mats and props, the three practice styles explained in plain words, an intro offer, teacher bios, a membership comparison with per-class math, a first-timer FAQ, a weekly schedule filterable by level and style, and a booking modal that confirms client-side with a saved spot. Pages: index.html (home), schedule.html (the week). Everything runs in the browser; nothing is sent anywhere.

- Audience: Adults within a short drive deciding to try a first class, plus lapsed members comparing schedules at 10pm. Mixed ages, mostly women, wary of being the newest person in the room; they want to know exactly what a first visit feels like and what it costs.
- Goal: Fill mats with the intro offer and keep them with memberships. Within ten seconds a visitor should feel the room's calm, see the intro price, and find a beginner-friendly class this week.
- Tone: Warm, unhurried and specific, like a teacher greeting a first-timer at the door. Short sentences, concrete numbers (minutes, dollars, mats), no wellness jargon, no medical claims, no exclamation marks.

## Stack
- Framework: Vite 5 + React 18 + TypeScript
- Styling: Tailwind CSS 3.4
- Libraries: react (MIT), react-dom (MIT), motion (motion.dev, import from 'motion/react') (MIT), lucide-react (ISC), tailwindcss (MIT), postcss (MIT), autoprefixer (MIT), vite (MIT), @vitejs/plugin-react (MIT), typescript (Apache-2.0), @fontsource/marcellus (OFL-1.1), @fontsource-variable/mulish (OFL-1.1)
- Build: `npm run build` → static files in `dist/`. No backend, no server code, no external APIs.
- Setup:
  - Scaffold with npm create vite@latest using the react-ts template. Two real HTML pages at the project root: index.html (entry src/main-home.tsx) and schedule.html (entry src/main-schedule.tsx).
  - vite.config.ts: base './', plugins [react()], build { outDir 'dist', sourcemap false, assetsInlineLimit 0, rollupOptions { input { index: resolve(__dirname, 'index.html'), schedule: resolve(__dirname, 'schedule.html') } } }. Do not copy src/ into dist/.
  - Tailwind 3.4 through PostCSS (tailwindcss + postcss + autoprefixer), content ['./index.html', './schedule.html', './src/**/*.{ts,tsx}']. In tailwind.config.ts add every color under Design to theme.extend.colors with kebab-case keys (sand, shell, card, fern, moss, clay, clay-deep, rule, night) and fontFamily display ['Marcellus', 'Georgia', 'serif'], sans ['Mulish Variable', 'system-ui', 'sans-serif']. Set borderRadius DEFAULT to 18px and add maxWidth { container: '1160px' }.
  - In src/fonts.ts import '@fontsource/marcellus/400.css' and '@fontsource-variable/mulish'; import src/fonts.ts and src/index.css from both entry files.
  - File layout: src/content.ts (every string, number, class, teacher, tier, hour, FAQ answer and image path for both pages, typed), src/lib/brand.ts (brandSlug = [BRAND] lowercased with every run of non-alphanumeric characters replaced by '-', emailDomain = brandSlug without hyphens + '.com'), src/lib/storage.ts (safe localStorage get/set wrapped in try/catch, keys prefixed with brandSlug + ':'), src/lib/useOpenNow.ts (studio open indicator from the hours table).
  - State: src/store/booking.ts is a tiny external store (useSyncExternalStore) holding the modal state { classId, day, name } and the confirmed spots list, persisted to localStorage key brandSlug + ':spots'. Booking a full class is prevented client-side (capacity per class from content.ts, seeded already-taken counts stable across reloads).
  - Components in src/components/: Header.tsx, MobileMenu.tsx, Reveal.tsx (Motion whileInView wrapper), Eyebrow.tsx, LevelPill.tsx, Footer.tsx; home: Hero.tsx, IntroOffer.tsx, Styles.tsx (StyleCard.tsx), Teachers.tsx (TeacherCard.tsx), Memberships.tsx (TierCard.tsx), Faq.tsx; schedule: ScheduleMasthead.tsx, FilterBar.tsx, WeekGrid.tsx (DayColumn.tsx, ClassCard.tsx), BookingModal.tsx, FirstTimers.tsx. src/pages/Home.tsx and Schedule.tsx compose them; both pages render Header and Footer.
  - Before the first build, download every image listed under Assets into public/images/ with curl -L -o using the exact file names given. The build itself never fetches anything.
  - public/favicon.svg as described under Assets. Both HTML files: lang en, <meta name='theme-color' content='#F5F1E8'>, <link rel='icon' href='./favicon.svg' type='image/svg+xml'>. Titles: index.html '<title>[BRAND] — Yoga on [STREET], [CITY]</title>', schedule.html '<title>The week — [BRAND]</title>'.
  - Write ASSETS.md at the project root as described under Assets.
  - dist/ holds the two HTML files, hashed JS/CSS, the woff2 fonts, favicon.svg and the six images. Keep it under 10 MB.

## Variables
- [BRAND] — Studio name (default: "Stillwater Yoga"). Invented studio name. Used in the wordmark, titles, footer, email (hello@ + brandSlug without hyphens + .com) and localStorage keys. Never a real studio or franchise.
- [CITY] — City (default: "Boulder, Colorado"). Where the studio is. Used in the hero eyebrow, the getting-here line and the footer. The street stays invented-sounding; only the city may be real.
- [STREET] — Street (default: "Linden Court"). The invented street the studio sits on ('9 Linden Court'). Drives the address and hero copy. Common English words, not a real address.
- [PRACTICE] — Practice styles (default: "Vinyasa, Yin and Restorative"). The three styles the studio teaches. Drives the three style cards, the class names in the week grid (keep 3 styles and 20 weekly classes), the filter chips and the teacher specialties. Keep exactly three comma-separated style names.
- [FOUNDED] — Year opened (default: "2018"). Four-digit year. Drives the hero eyebrow, the wordmark line 'Est. [FOUNDED]', the story line and teacher 'practicing since' spans.
- [CREDIT] — keep a small "Template by VibeFather" link to https://vibefather.ai/t/yoga-studio-website in the footer (default: yes; delete this line to remove it)

The copy under Pages & Sections is written for the default values. If your values differ, rewrite every headline, paragraph, label and image for them — same length, tone and structure. Layout, colors, type and motion stay as described.
Keep all copy, image paths and links in one content file (for example `src/content.ts`), keyed by section, so the content can be swapped later without touching components.

## Design
### Colors
- Sand `#F5F1E8` — Page background on both pages, input fill.
- Shell `#EDE6D8` — Alternate section background (Styles, Memberships), hover fill for rows and chips, image wells.
- Card `#FDFBF6` — Card surfaces (class cards, teacher cards, tier cards, modal), light panel background.
- Fern `#2A352F` — Headlines and body text, primary outline buttons, icon color, modal border.
- Moss `#6E7F6A` — Secondary text, captions, eyebrows, level pills for gentle classes, open dot.
- Clay `#AE7A64` — The one accent: primary buttons, prices, intro offer border and headline accents, selected chips, focus ring.
- Clay Deep `#916152` — Primary button hover and pressed state, level 2 pill.
- Rule `#DCD3C2` — 1px hairlines, card borders, input borders, day-column dividers.
- Night `#26302B` — Footer, hero overlay base, photo overlays (as rgba(38,48,43,x)).

### Typography
- Display: H1, H2, H3, class names, teacher names, prices in large sizes, the wordmark: Marcellus (OFL), weights 400
- Text and UI: body, eyebrows, buttons, nav, form fields, schedule times, numbers (font-variant-numeric tabular-nums for times and prices): Mulish (OFL), weights 400/600/800

### Layout & motion
- Spacing: 8px base unit. Container max-width 1160px, centered, side padding 48px desktop, 32px tablet, 20px under 640px. 12-column grid, column gap 24px. Section vertical padding 104px desktop, 80px under 1024px, 64px under 640px. Type scale: H1 clamp(42px, 6vw, 88px) Marcellus 400, line-height 1.06, letter-spacing 0; H2 clamp(32px, 4vw, 54px) Marcellus 400, line-height 1.1; H3 24px Marcellus 400, line-height 1.25; lead paragraph Mulish 400 18px / 1.7 Fern at 85% opacity; body Mulish 400 16px / 1.75 (max-width 64ch); eyebrow Mulish 800 12px uppercase letter-spacing 0.18em Moss, preceded by a 24px x 1px Clay line with 12px gap; caption Mulish 400 13px Moss. Buttons: height 50px, padding 0 28px, Mulish 600 14px letter-spacing 0.06em. Primary: Clay fill, Card text. Secondary: 1px Fern border, Fern text, transparent (on photos: 1px Card border, Card text). Small buttons 38px high, padding 0 16px, 12px text. Inputs: height 50px, 1px Rule border, Card fill, 16px Mulish, focus border Clay. Focus ring everywhere: 2px Clay outline with 3px offset.
- Radius: 18px on cards, photos, inputs, chips and the modal. 999px only for level pills, filter chips, teacher initials and the open dot.
- Motion: Easing: --ease-out cubic-bezier(0.22, 0.61, 0.36, 1) for reveals and the modal; --ease-io cubic-bezier(0.65, 0, 0.35, 1) for filters and the FAQ. Slow and calm — nothing bounces, nothing snaps.
- Motion: Reveal: blocks wrapped in <Reveal> start at opacity 0, translateY(16px) and animate to rest over 900ms --ease-out when 15% visible (Motion whileInView, viewport once). Siblings stagger by 100ms (index prop).
- Motion: Hero photo: on load the image scales from 1.05 to 1.0 over 2600ms --ease-out; while scrolling, the image translates 0 to 8% of its height as the hero scrolls out (Motion useScroll, offset ['start start', 'end start']). H1 lines rise from translateY(24px) and opacity 0 with 160ms stagger, starting 300ms after load.
- Motion: Breathing dot: a 10px Clay circle under the hero headline scales 1 to 1.5 and back on a 5000ms ease-in-out loop (inhale/exhale), pausing under reduced motion to a static dot.
- Motion: Class cards: hover lifts 4px and softens the border to Fern over 300ms; clicking opens the BookingModal. Filter changes fade cards out (opacity, 8px y) and re-stagger them in over 350ms --ease-io.
- Motion: Booking modal: Night overlay fades to 45% over 300ms; the Card panel rises 24px and fades in over 380ms --ease-out; closing reverses in 260ms. The confirmation view crossfades inside the panel and the spot number types in character by character over 600ms. Escape and overlay click close.
- Motion: FAQ accordions: height 0 to auto and opacity 0 to 1 over 340ms --ease-io; the Plus icon rotates 45 degrees into an X.
- Motion: Membership tiers: the middle (featured) tier is outlined 1px Clay and lifted 8px; on hover each tier's per-class math line counts the price down/up to the effective per-class value over 500ms.
- Motion: Header: transparent over the photo hero with Card text; after 40px of scroll it gets Sand at 94% opacity, backdrop-filter blur(10px), Fern text and a 1px Rule bottom border, 250ms transition. On schedule.html it is solid from the start.
- Motion: Links: .link-draw grows a 1px currentColor underline from 0% to 100% width over 300ms --ease-out on hover and focus-visible.
- Motion: prefers-reduced-motion: reduce — disable the hero scale and parallax, H1 rise, breathing dot, count-ups, type-in and staggered filters (render at rest). Color and border hover changes stay. Use CSS @media in index.css plus Motion's useReducedMotion in components.
- Imagery: Real photography only, calm and airy, all six made for this template in one consistent style: soft daylight, pale wood, linen and plants, empty rooms and still-life props, documentary editorial look, fine grain. Two photo kinds, never mixed: room and prop stills (the hero, the three style cards, the evening candle shot — no people, no hands, no faces) and teacher portraits (AI-generated fictional people, head-and-shoulders headshots only, natural light, never full-body poses, never hands touching props, never resembling any real individual; they are placeholders users swap for their own staff). Schedule and class avatars are never photos: initials circles drawn in code. No readable text or logos anywhere. Every photo uses object-fit cover with the object-position given under Assets, 18px corners, no shadow; photos on Sand get a 1px Rule outline. Captions below photos in Mulish 13px Moss. Drawn in code: the favicon, the wordmark (type only), level pills, teacher initials circles, the breathing dot, dividers and the modal spot card. Icons: lucide-react only, stroke width 1.5.

## Pages & Sections
### Home (`index.html`)
1. **Content file and copy rules** — All copy below is written for the default values ([BRAND] = Stillwater Yoga, [CITY] = Boulder, Colorado, [STREET] = Linden Court, [PRACTICE] = Vinyasa, Yin and Restorative, [FOUNDED] = 2018). Put every string, number and list in src/content.ts and render from it; both pages share one content file. If any variable value differs, rewrite every headline, style card, class, teacher bio, tier, hour and FAQ answer so it is specific and believable for the new studio, keeping the same structure, counts and lengths (3 styles, 20 weekly classes, 4 teachers (portraits), 3 tiers). All people, classes, streets and figures are invented. Studio facts used throughout: address 9 [STREET], [CITY]; phone (720) 555-0129; email hello@ + emailDomain ([email protected]); one room, 18 mats; props free to borrow; hours (client clock): Mon–Fri 6:00–21:00, Sat 7:30–17:00, Sun 8:00–16:00. Intro offer: 3 classes in 14 days for $30. Drop-in $22, 10-class pack $180 ($18 a class), monthly unlimited $135. Mats, blocks, straps and blankets free; tea after class. Teacher portraits are AI-generated fictional people matching the default roster (not resembling any real individuals); alt stays 'A fictional yoga teacher' so studios swap in their own photos.
   Layout: n/a
   Motion: n/a
2. **Header (all pages)** — Left: wordmark '[BRAND]' (Marcellus 22px, letter-spacing 0.05em) with a second line 'Yoga studio · Est. [FOUNDED]' (Mulish 800 10px uppercase letter-spacing 0.22em), linking to ./index.html. Center nav (Mulish 600 14px): 'The week' → ./schedule.html, 'Styles' → ./index.html#styles, 'Teachers' → ./index.html#teachers, 'Membership' → ./index.html#membership. Current page link has a 1px underline. Right: primary button 'Book a class' → ./schedule.html and the hamburger (Lucide Menu 22px, under 820px) opening MobileMenu: full-screen Shell panel, links at Marcellus 28px, the book button at the bottom, close icon top right.
   Layout: Fixed top, height 76px, container-aligned. Over the home hero only it starts transparent with Card text. Mobile menu covers the viewport with a 300ms slide from the right.
3. **Hero** — Background photo hero-studio.webp with a Night gradient overlay strengthening to about rgba(38,48,43,.55) behind the text column so light copy stays readable; on mobile add top padding below the sticky header and give the header a solid background so the H1 clears it. Eyebrow (Card, line in Card at 60%): '[STREET] · [CITY] · Est. [FOUNDED]'. H1 in two lines: 'Slow down,' / '*on your way in.*' Lead (Card at 88%, max-width 560px): '[BRAND] is one bright room on [STREET] with 18 mats, borrowed props and teachers who learned to teach before they learned to market. [PRACTICE], seven days a week, first class nerves understood.' Buttons: primary 'Claim 3 classes for $30' → ./index.html#intro, secondary on-photo 'See the week' → ./schedule.html. Under the buttons the breathing dot with the caption (Card at 70%): 'Inhale on the way in. Exhale on the way out.' Bottom ledger of four items (Marcellus 26px Card value, Mulish 800 12px uppercase label at 70%): '3 for $30' / 'Intro offer, 14 days'; '20 classes' / 'Every week, all levels'; '18 mats' / 'One room, never crowded'; '7 days' / 'From 6am to 9pm'.
   Layout: Height 92svh, min-height 640px, max-height 980px. Image object-fit cover, object-position 50% 55%. Overlay linear-gradient(180deg, rgba(38,48,43,0.44) 0%, rgba(38,48,43,0.10) 35%, rgba(38,48,43,0.22) 60%, rgba(38,48,43,0.78) 100%). Content block anchored bottom-left inside the container, 120px above the ledger, max-width 760px. Ledger: absolute bottom 0, full container width, a 1px Card/25% top border, 4 equal columns, padding 24px 0 32px. Under 768px: H1 at 42px, ledger becomes a 2x2 grid, buttons stack full-width.
4. **Intro offer** — Section id='intro' (its header must clear the sticky bar on load). A wide Card panel with a 1px Clay border and 18px radius, anchored by a ticket-style number block visual ('3') drawn in code on the left: left, eyebrow 'First time here' and H2 'Three classes, thirty dollars, two weeks.' with body 'New to [BRAND] or new to yoga? Take any three classes within fourteen days for $30 — mats and props included, no membership talk until you''re ready.'; right, primary button 'Start with the week' → ./schedule.html and caption 'Book from the schedule; pay at the studio.' Corner note top right of the panel in Mulish 13px Moss: 'One per person, generously interpreted.'
   Layout: Sand background, panel container-aligned, vertical padding 40px, two columns (7 text / 4 button, offset 1), items vertically centered, 48px inner padding. Under 768px stack with the button full-width.
5. **Styles** — Section id='styles'. Eyebrow 'What we teach' and H2 'Three styles, one room.' Three cards (photos are room and prop stills only — never people; the Yin card uses the evening candle-studio still): 1) 'Vinyasa' — photo mats-still.webp, alt 'Rolled mats and folded blankets on a shelf by the window' — 'Movement tied to breath, one pose flowing into the next. Expect warmth, a little sweat and a clear thread through the hour. Our 6:30am sunrise class is this, before coffee.' — pill row 'Levels 1–2 · 60 min'. 2) 'Yin' — photo props-still.webp, alt 'Yoga blocks, a strap and a ceramic bowl arranged on pale wood' — 'Long, quiet holds close to the floor — two to five minutes each. The deep stretch happens while you do nothing at all, which is harder than it sounds and worth it.' — pills 'All levels · 60 min'. 3) 'Restorative' — photo candle-studio.webp, alt 'Candles and folded blankets laid out in a dim studio room' — 'Bolsters, blankets and almost no effort. The 7:30pm class ends by candlelight; regulars describe it as a nap that counts. Come tired, leave lighter.' — pills 'Gentle · 75 min'. Each card links 'Find a class' → ./schedule.html?style=<slug> (the schedule page filters to that style; opened without a query all classes show — never an error).
   Layout: Shell background. Three equal columns (24px gap), cards on Card with 1px Rule border, 28px padding: photo top (aspect 4:3, 18px radius), name Marcellus 26px, body Mulish 15px / 1.7, pills, small secondary button. Under 900px: stacked.
6. **Teachers** — Section id='teachers'. Eyebrow 'The teachers' and H2 'Four people, four reasons to come.' Cards with AI-generated teaching portraits (4:3) — fictional people, calm studio light: 1) teacher-amara.webp, alt 'Amara teaching a morning flow, a fictional yoga teacher' — Amara Chen — 'Vinyasa lead' — 'Twelve years of practice, the last five at [BRAND]. Trained in Mysore and Boulder; teaches the sunrise classes and the level 2 flows.' — philosophy '*"Strong beats fast, every time."*' — 'Teaches Mon, Wed, Fri'. 2) teacher-devon.webp, alt 'Devon seated in a quiet yin pose, a fictional yoga teacher' — Devon Alvarez — 'Yin & breathwork' — 'Came to yoga from distance running and stayed for the stillness. Runs the midday yin and the breath workshop on Saturdays.' — '*"The pose ends when you stop fighting it."*' — 'Teaches Tue, Thu, Sat'. 3) teacher-priya.webp, alt 'Priya arranging bolsters for restorative class, a fictional yoga teacher' — Priya Raman — 'Restorative' — 'Ten years teaching restorative and yoga nidra. Believes the 7:30pm class is the real event of the day and schedules her life around it.' — '*"Rest is a skill. Practice it."*' — 'Teaches Wed, Fri, Sun'. 4) teacher-sam.webp, alt 'Sam guiding a foundations pose, a fictional yoga teacher' — Sam Whitfield — 'Foundations & community' — 'Six years in, permanently curious. Teaches the beginner foundations course and remembers every name by week two, without tricks.' — '*"Show up. That''s the whole practice."*' — 'Teaches Mon, Sat, Sun'. Portraits are head-and-shoulders headshots only (no full-body poses, no hands on props), cropped 3:4 at consistent framing so card heights match.
   Layout: Warm White background. Four equal columns (24px gap) on desktop, 2x2 under 1024px, one column under 640px. Card: teaching portrait top (aspect 4:3, 18px radius), name Marcellus 24px, role line Mulish 800 12px uppercase Clay, bio Mulish 15px / 1.6, philosophy line Mulish 600 italic 15px Espresso, teaching days caption.
7. **Memberships** — Section id='membership'. Eyebrow 'Membership' and H2 'Simple math, no contracts.' Three tier cards: 1) 'Drop-in' — $22 — 'One class, any time. Bring a friend and they pay the same; no codes, no fine print.' — per-class line '$22 a class'. 2) 'Class pack' (featured, 1px Clay outline, lifted) — $180 — 'Ten classes, valid four months. Shareable within a household; we track it so you don''t have to.' — per-class line '$18 a class — you save $40'. 3) 'Monthly unlimited' — $135 — 'Every class, every style, including the workshops'' open portions. Pause it twice a year, no questions.' — per-class line '$15 a class at 9 classes — most members come 11'. Under the grid: caption 'All options include mats, props and tea. Cancel anytime; the door stays open either way.' Buttons per tier: 'Pay at the studio' (secondary, non-payment link to ./schedule.html).
   Layout: Shell background. Three columns (24px gap), middle tier lifted 8px and outlined Clay. Card surfaces, 32px padding: tier name Mulish 800 12px uppercase Moss, price Marcellus 44px Fern, description Mulish 15px / 1.7, per-class line Mulish 600 13px Clay, full-width secondary button. Under 900px: stacked, no lift.
8. **FAQ** — Eyebrow 'Before your first class' and H2 'Asked once an hour, answered here.' Five accordions: 1) 'What should I bring?' — 'Yourself and comfortable clothes. Mats, blocks, straps and blankets are free to borrow — most people borrow everything for the first month.' 2) 'What do the levels mean?' — 'All levels: breathing is the only prerequisite. Level 1 adds standing sequences, Level 2 expects familiarity with the poses, Gentle means we stay low and slow. Every teacher offers options in both directions.' 3) 'Can I arrive late?' — 'Doors close when class starts — it''s a one-room studio and the door talks. If you''re five minutes early, you''re perfectly on time.' 4) 'I can''t touch my toes.' — 'Neither could half the room, once. Toes are a direction, not a destination; every pose has a version that meets today''s body.' 5) 'Do you have showers?' — 'One, with towels. The tea after class is the better reason to linger.'
   Layout: Sand background, accordion rows with 1px Rule dividers, question in Marcellus 20px, answer Mulish 16px / 1.75 max-width 64ch, Plus icon right. Container max-width 760px.
9. **Footer (all pages)** — Night background. Four columns: 1) wordmark '[BRAND]' (Marcellus 22px Card) over 'Yoga studio · [STREET], [CITY]'. 2) 'Find us': address '9 [STREET]', '[CITY]', phone (720) 555-0129, hello@ + emailDomain. 3) 'Hours': Mon–Fri 6:00–21:00, Sat 7:30–17:00, Sun 8:00–16:00, caption 'The room opens 15 minutes before class.' 4) 'Around the studio': 'The week' → ./schedule.html, 'Styles' → ./index.html#styles, 'Teachers' → ./index.html#teachers, 'Membership' → ./index.html#membership. Bottom line under a 1px Card/15% rule: '© [BRAND]. Breathe first.' Text in Card at 80%, links Card with .link-draw.
   Layout: Vertical padding 72px, 4 equal columns, bottom line 40px below the rule. Under 768px: two columns, then stacked.

### The week (`schedule.html`)
1. **Masthead** — Solid header from the start. Eyebrow 'The week', H1 'Twenty classes, one calm room.' Lead (max-width 620px): 'Filter by level or style, click a class, and your mat is held in this browser. Pay at the studio — cash, card or a membership you already love.' Right, the open-now pill (Moss dot + 'Studio open · closes 9pm' computed from the hours table) and caption 'Times are local; the studio clock is atomic, allegedly.'
   Layout: Sand background, container-aligned, vertical padding 136px top (header height) + 48px. H1 max-width 720px. Masthead bottom border 1px Rule, 64px below text. Under 860px the pill wraps under the lead.
2. **Filter bar** — Sticky under the header (top 76px) on Card at 96% with blur and a 1px Rule bottom border. Left 'Level' chips (999px): 'All levels', 'Gentle', 'Level 1', 'Level 2'. Right 'Style' chips: the three styles from [PRACTICE] plus 'All styles'. One chip active per group; active chip fills Fern with Card text. Far right: live count '20 classes this week' updating with the filter, and a 'Reset' text button that appears when any filter is active.
   Layout: Chips scroll horizontally under 768px; count and Reset stay pinned right. Chips swap fill over 150ms.
3. **Week grid** — Seven day columns (Mon–Sun) with the day name (Mulish 800 12px uppercase Moss) and date-free (no dates shown — the pattern repeats weekly). Class cards in each column, ordered by time: time (Mulish 600 13px, tabular-nums), name (Marcellus 19px), level pill, duration caption '60 min', teacher round avatar 28px (the teacher portraits reused), spots left caption ('4 mats left' or 'Full — waitlist at the desk'). The 20 classes: Mon 6:30 Sunrise Vinyasa (L2, 60m, AC), 12:15 Yin & Breath (All, 45m, DA), 18:00 Slow Flow (L1, 60m, AC), 19:30 Candlelight Restorative (Gentle, 75m, PR); Tue 6:30 Sunrise Vinyasa (L2, 60m, AC), 12:15 Lunch Express Flow (All, 45m, SW), 18:00 Foundations (L1, 75m, SW), 19:30 Deep Yin (All, 60m, DA); Wed 6:30 Slow Flow (L1, 60m, PR), 9:30 Gentle Morning (Gentle, 60m, PR), 18:00 Vinyasa 2 (L2, 60m, AC), 19:30 Restorative & Sound (Gentle, 75m, PR); Thu 6:30 Sunrise Vinyasa (L2, 60m, AC), 12:15 Yin & Breath (All, 45m, DA), 18:00 Slow Flow (L1, 60m, SW), 19:30 Deep Yin (All, 60m, DA); Fri 6:30 Vinyasa 2 (L2, 60m, AC), 18:00 Community Flow (All, 60m, SW, 'Pay what you can'), 19:30 Candlelight Restorative (Gentle, 75m, PR); Sat 8:00 Foundations (L1, 75m, SW), 9:30 Vinyasa All Levels (All, 60m, AC), 11:00 Breath Workshop (All, 90m, DA); Sun 9:00 Slow Flow (L1, 60m, PR), 11:00 Yin & Tea (All, 75m, DA), 17:00 Restorative Reset (Gentle, 60m, PR). Style tags map each class to Vinyasa, Yin or Restorative for the style filter. Full classes (2 of the 20, seeded stable from the class id) show struck-through 'Full'. Filters default to All levels and All styles (a first-timer sees every class). 'Pay what you can' renders as a pill on its own line above the title; 'Full · waitlist' stays on one line; full classes use a muted title with a 'Full' pill, never a strikethrough. Teacher marks in cells are initials circles drawn in code (Shell fill, Fern initials) — never photos. Card heights align per row; under 760px the grid becomes a vertical day-by-day list with sticky day headers (no sideways scroll).
   Layout: Sand background. 7 equal columns with 16px gaps on desktop (each column min-width 150px); under 1024px the grid scrolls horizontally as a whole (scroll-snap per column, edge fade). Class card: Card surface, 1px Rule border, 18px radius, 16px padding, stacked rows; hover lifts 4px. Filtered-out cards remove with a fade (Motion AnimatePresence, popLayout).
4. **Booking modal** — Opened by clicking any class card (except Full ones, which show a shake and the waitlist note). Panel on Card: eyebrow 'Hold a mat', class name (Marcellus 28px), detail rows (Day & time · Level · Duration · Teacher name from initials), body 'We hold the mat for ten minutes past start. Pay at the studio — drop-in $22, the intro offer counts, memberships too.' Name input (required, placeholder 'Name on the mat'). Buttons: primary 'Hold my mat' (disabled until a name), secondary 'Not today'. Confirming swaps the panel to the spot view: a Sage-free Fern check circle drawn stroke-by-stroke, 'You''re in.' (Marcellus 30px), 'for [NAME]', 'Spot 12 of 18' (computed from seeded taken counts + the booking), class detail line, caption 'Saved in this browser — screenshot it if you''re the careful kind. See you on the mat.' Buttons 'Book another class' (closes the modal) and 'Back to the studio' → ./index.html. Bookings persist in localStorage; a booked class shows 'Held for you' on its card.
   Layout: Fixed overlay (Night at 45%), centered Card panel max-width 480px, 24px padding, 18px radius, focus-trapped, Escape and overlay click close. Panel rise/fade as in Motion. Under 480px the panel is bottom-anchored full-width with rounded top corners.
5. **First-timer note** — A Shell band above the footer: left, eyebrow 'First class checklist' and a single-line list with Lucide icons: Check 'Arrive 10 minutes early', Check 'Everything''s provided', Check 'Socks optional, opinions welcome'; right, primary button 'Claim 3 classes for $30' → ./index.html#intro with caption 'Pay at the studio, no card online.'
   Layout: Full-width band, container-aligned, two columns (8 / 3 offset 1), vertical padding 72px. Under 768px stacked, button full-width.

## Assets
- image: Template photos made for this design (free to redistribute with the template). Download each with curl -L -o into public/images/: https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/hero-studio.webp → public/images/hero-studio.webp (Home hero, Styles card Vinyasa; object-position 50% 55%; alt 'Bright empty yoga studio with pale wood floors, plants and stacked mats'); https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/candle-studio.webp → public/images/candle-studio.webp (Styles card Restorative; alt 'Candles and folded blankets laid out in a dim studio room'); https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/teacher-amara.webp → public/images/teacher-amara.webp (Teacher card Amara; alt 'Amara teaching a morning flow, a fictional yoga teacher'); https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/teacher-devon.webp → public/images/teacher-devon.webp (Teacher card Devon, Styles card Yin, week-grid avatar; alt 'Devon seated in a quiet yin pose, a fictional yoga teacher'); https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/teacher-priya.webp → public/images/teacher-priya.webp (Teacher card Priya; alt 'Priya arranging bolsters for restorative class, a fictional yoga teacher'); https://media.vibefather.ai/assets/759c26bd-aebe-42a7-b843-360f97ba8db8/teacher-sam.webp → public/images/teacher-sam.webp (Teacher card Sam; alt 'Sam guiding a foundations pose, a fictional yoga teacher'). Six files in total.
- image: Write ASSETS.md at the project root with a table: path, source URL, author, license — one row for each photo (source 'media.vibefather.ai, made for this template', author 'VibeFather', license 'Distributed with the template'), plus rows for @fontsource/marcellus and @fontsource-variable/mulish (OFL-1.1) and lucide-react (ISC). Never replace photos with stock sites (Unsplash, Pexels, Pixabay) or images with people, faces or readable branding.
- icon: lucide-react only: CalendarDays, Menu, X, Plus, Check, ArrowRight, Clock, Phone, Mail, MapPin, Sun, Moon, Wind, Flower2, Leaf, Heart, Sparkles, Users. Stroke width 1.5, 16–24px, color inherits. public/favicon.svg hand-written: viewBox 0 0 32 32, a 32x32 rect rx 9 filled #2A352F, a Card (#FDFBF6) lotus-style glyph made of three simple petal arcs. No other logo: the studio name is always set as type.
- font: Install @fontsource/marcellus and @fontsource-variable/mulish and import them in src/fonts.ts as listed in Setup. Vite bundles the woff2 files into dist/.
- image: Drawn in code: the favicon, teacher initials circles, level and filter pills, the breathing dot, the open-now dot, the modal check circle, dividers and day-column rules. No other bitmaps, no illustrations, no map tiles.

## Don'ts
- No backend, no form submission, no fetch to any API: bookings, capacity and confirmations live in the browser only (localStorage); nothing is charged or sent.
- Every internal link points to a file name (./index.html, ./schedule.html, ./schedule.html?style=yin, ./index.html#intro) — never to a bare directory; schedule.html opened without a query shows all classes.
- Self-host everything: fonts through Fontsource, icons as npm packages or inline SVG, images downloaded into public/images/. No CDN <script> or <link> tags, no Google Fonts, no analytics.
- Production build: minified, no source maps, no src/ copied into dist/, single command npm run build, output in dist/ under 10 MB.
- Portraits and studio photographs are AI-generated fictional people (not resembling any real individual) used as template placeholders; no real people appear anywhere.
- No medical or therapeutic claims anywhere; experience language only ('leave lighter', never 'heals' or 'treats').
- No dates or years anywhere except 'Est. [FOUNDED]'; the week grid is date-free and repeats weekly; the site never shows today's date.
- Never mention VibeFather or any other brand inside the site except the optional credit footer link; all copy is invented US English.
- Respect prefers-reduced-motion everywhere: disable parallax, the breathing dot, count-ups, type-in and staggered filter animations; keep color/border hovers.
- The site must work at 1440x900 desktop and 390x844 mobile with zero console errors; the modal works with keyboard only, focus-traps while open, and every interactive element has a visible focus ring.
- Keep copy concrete: no lorem, no filler, no wellness clichés; times, prices and capacities always come from src/content.ts.

---
— Prompt by VibeFather · https://vibefather.ai/t/yoga-studio-website · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown

Free for personal projects under CC BY-NC 4.0. Commercial use comes with Pro.

DESIGN.md

The design system on its own — colors, type, spacing and motion. Apply this look to a project you already have.

---
name: "Yoga Studio Website"
colors:
  sand: "#F5F1E8"
  shell: "#EDE6D8"
  card: "#FDFBF6"
  fern: "#2A352F"
  moss: "#6E7F6A"
  clay: "#AE7A64"
  clay_deep: "#916152"
  rule: "#DCD3C2"
  night: "#26302B"
typography:
  display_h1_h2_h3_class_names_teacher_names_prices_in_large_sizes_the_wordmark: { family: "Marcellus", weights: [400] }
  text_and_ui_body_eyebrows_buttons_nav_form_fields_schedule_times_numbers_font_variant_numeric_tabular_nums_for_times_and_prices: { family: "Mulish", weights: [400, 600, 800] }
spacing: "8px base unit. Container max-width 1160px, centered, side padding 48px desktop, 32px tablet, 20px under 640px. 12-column grid, column gap 24px. Section vertical padding 104px desktop, 80px under 1024px, 64px under 640px. Type scale: H1 clamp(42px, 6vw, 88px) Marcellus 400, line-height 1.06, letter-spacing 0; H2 clamp(32px, 4vw, 54px) Marcellus 400, line-height 1.1; H3 24px Marcellus 400, line-height 1.25; lead paragraph Mulish 400 18px / 1.7 Fern at 85% opacity; body Mulish 400 16px / 1.75 (max-width 64ch); eyebrow Mulish 800 12px uppercase letter-spacing 0.18em Moss, preceded by a 24px x 1px Clay line with 12px gap; caption Mulish 400 13px Moss. Buttons: height 50px, padding 0 28px, Mulish 600 14px letter-spacing 0.06em. Primary: Clay fill, Card text. Secondary: 1px Fern border, Fern text, transparent (on photos: 1px Card border, Card text). Small buttons 38px high, padding 0 16px, 12px text. Inputs: height 50px, 1px Rule border, Card fill, 16px Mulish, focus border Clay. Focus ring everywhere: 2px Clay outline with 3px offset."
radius: "18px on cards, photos, inputs, chips and the modal. 999px only for level pills, filter chips, teacher initials and the open dot."
---

# Yoga Studio Website — Design System

Apply this design system to an existing project. It describes the look and feel only; for the full site, use prompt.md.

## Colors
- **Sand** `#F5F1E8` — Page background on both pages, input fill.
- **Shell** `#EDE6D8` — Alternate section background (Styles, Memberships), hover fill for rows and chips, image wells.
- **Card** `#FDFBF6` — Card surfaces (class cards, teacher cards, tier cards, modal), light panel background.
- **Fern** `#2A352F` — Headlines and body text, primary outline buttons, icon color, modal border.
- **Moss** `#6E7F6A` — Secondary text, captions, eyebrows, level pills for gentle classes, open dot.
- **Clay** `#AE7A64` — The one accent: primary buttons, prices, intro offer border and headline accents, selected chips, focus ring.
- **Clay Deep** `#916152` — Primary button hover and pressed state, level 2 pill.
- **Rule** `#DCD3C2` — 1px hairlines, card borders, input borders, day-column dividers.
- **Night** `#26302B` — Footer, hero overlay base, photo overlays (as rgba(38,48,43,x)).

## Typography
- **Display: H1, H2, H3, class names, teacher names, prices in large sizes, the wordmark** — Marcellus (OFL), weights 400. Self-host the font files.
- **Text and UI: body, eyebrows, buttons, nav, form fields, schedule times, numbers (font-variant-numeric tabular-nums for times and prices)** — Mulish (OFL), weights 400/600/800. Self-host the font files.

## Spacing & shape
- Spacing: 8px base unit. Container max-width 1160px, centered, side padding 48px desktop, 32px tablet, 20px under 640px. 12-column grid, column gap 24px. Section vertical padding 104px desktop, 80px under 1024px, 64px under 640px. Type scale: H1 clamp(42px, 6vw, 88px) Marcellus 400, line-height 1.06, letter-spacing 0; H2 clamp(32px, 4vw, 54px) Marcellus 400, line-height 1.1; H3 24px Marcellus 400, line-height 1.25; lead paragraph Mulish 400 18px / 1.7 Fern at 85% opacity; body Mulish 400 16px / 1.75 (max-width 64ch); eyebrow Mulish 800 12px uppercase letter-spacing 0.18em Moss, preceded by a 24px x 1px Clay line with 12px gap; caption Mulish 400 13px Moss. Buttons: height 50px, padding 0 28px, Mulish 600 14px letter-spacing 0.06em. Primary: Clay fill, Card text. Secondary: 1px Fern border, Fern text, transparent (on photos: 1px Card border, Card text). Small buttons 38px high, padding 0 16px, 12px text. Inputs: height 50px, 1px Rule border, Card fill, 16px Mulish, focus border Clay. Focus ring everywhere: 2px Clay outline with 3px offset.
- Radius: 18px on cards, photos, inputs, chips and the modal. 999px only for level pills, filter chips, teacher initials and the open dot.

## Motion
- Easing: --ease-out cubic-bezier(0.22, 0.61, 0.36, 1) for reveals and the modal; --ease-io cubic-bezier(0.65, 0, 0.35, 1) for filters and the FAQ. Slow and calm — nothing bounces, nothing snaps.
- Reveal: blocks wrapped in <Reveal> start at opacity 0, translateY(16px) and animate to rest over 900ms --ease-out when 15% visible (Motion whileInView, viewport once). Siblings stagger by 100ms (index prop).
- Hero photo: on load the image scales from 1.05 to 1.0 over 2600ms --ease-out; while scrolling, the image translates 0 to 8% of its height as the hero scrolls out (Motion useScroll, offset ['start start', 'end start']). H1 lines rise from translateY(24px) and opacity 0 with 160ms stagger, starting 300ms after load.
- Breathing dot: a 10px Clay circle under the hero headline scales 1 to 1.5 and back on a 5000ms ease-in-out loop (inhale/exhale), pausing under reduced motion to a static dot.
- Class cards: hover lifts 4px and softens the border to Fern over 300ms; clicking opens the BookingModal. Filter changes fade cards out (opacity, 8px y) and re-stagger them in over 350ms --ease-io.
- Booking modal: Night overlay fades to 45% over 300ms; the Card panel rises 24px and fades in over 380ms --ease-out; closing reverses in 260ms. The confirmation view crossfades inside the panel and the spot number types in character by character over 600ms. Escape and overlay click close.
- FAQ accordions: height 0 to auto and opacity 0 to 1 over 340ms --ease-io; the Plus icon rotates 45 degrees into an X.
- Membership tiers: the middle (featured) tier is outlined 1px Clay and lifted 8px; on hover each tier's per-class math line counts the price down/up to the effective per-class value over 500ms.
- Header: transparent over the photo hero with Card text; after 40px of scroll it gets Sand at 94% opacity, backdrop-filter blur(10px), Fern text and a 1px Rule bottom border, 250ms transition. On schedule.html it is solid from the start.
- Links: .link-draw grows a 1px currentColor underline from 0% to 100% width over 300ms --ease-out on hover and focus-visible.
- prefers-reduced-motion: reduce — disable the hero scale and parallax, H1 rise, breathing dot, count-ups, type-in and staggered filters (render at rest). Color and border hover changes stay. Use CSS @media in index.css plus Motion's useReducedMotion in components.

## Imagery
Real photography only, calm and airy, all six made for this template in one consistent style: soft daylight, pale wood, linen and plants, empty rooms and still-life props, documentary editorial look, fine grain. Two photo kinds, never mixed: room and prop stills (the hero, the three style cards, the evening candle shot — no people, no hands, no faces) and teacher portraits (AI-generated fictional people, head-and-shoulders headshots only, natural light, never full-body poses, never hands touching props, never resembling any real individual; they are placeholders users swap for their own staff). Schedule and class avatars are never photos: initials circles drawn in code. No readable text or logos anywhere. Every photo uses object-fit cover with the object-position given under Assets, 18px corners, no shadow; photos on Sand get a 1px Rule outline. Captions below photos in Mulish 13px Moss. Drawn in code: the favicon, the wordmark (type only), level pills, teacher initials circles, the breathing dot, dividers and the modal spot card. Icons: lucide-react only, stroke width 1.5.

## Tone
Warm, unhurried and specific, like a teacher greeting a first-timer at the door. Short sentences, concrete numbers (minutes, dollars, mats), no wellness jargon, no medical claims, no exclamation marks.

---
— Prompt by VibeFather · https://vibefather.ai/t/yoga-studio-website · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown