Project: Vibe2
Live at: http://localhost:5175/ (dev). Public vibe2.co.uk currently shows a "Launching Soon" placeholder, so all screenshots below are taken from the local dev build.
Owner: Ted (one operator, no team)
Built by: Expedient AI
Status: Active development. Production-ready stack, real LiteAPI integration, 200+ indexed URLs.
A curated short-break travel website for UK travellers. The thesis: most travel sites are search engines with marketing bolted on. Vibe2 is a magazine with bookings bolted on. The user picks a mood ("party", "beach", "wine", "wellness", "skiing"), gets a hand-curated top-10 of cities, drills into any city, and books a real hotel at the real price. No fake "from £X" rates. No "Was £Y, now £Z" strikethroughs. No infinite carousel of OTAs pretending to be editorial.
The brochure-style content (Top 10 party cities in Europe, Top 10 wine destinations, etc.) is the SEO and brand asset. The booking flow is the conversion. The two have to feel like the same product.
I pulled Playwright screenshots of the dev server on 2026-06-18 against http://localhost:5175/. Verified via DOM extraction that every page below renders real content with real prices and real images.
| Route | What renders |
|---|---|
/ |
Vibe hero (h1: "Find a 3-night escape you'll actually take"), mood picker, romantic vibe carousel, UK clubbing spotlight panel, 9-category editorial guides grid, deals row, footer |
/vibes |
All 8 vibes in a clean grid (Party, Beach, Wellness, Food, Adventure, Romantic, Culture, Cheap & Easy) |
/party-cities |
Top 10 party cities in Europe (Berlin, Budapest, Barcelona, Belgrade, Prague, Amsterdam, London, Lisbon, Krakow, Bucharest), each a card |
/beach-parties |
Top 10 beach party destinations (Ibiza, Zrce/Pag, Mykonos, etc.) |
/uk-clubbing |
10 UK cities with a real UK map image, real venue names (Fabric, Ministry of Sound, Drumsheds, Corsica Studios in London) |
/party-cities/london |
Per-city long-form page with 6 famous things to do, real hotel cards (£120 to £253 observed) |
/beach-parties/ibiza |
Per-beach page (Amnesia, Pacha, Ushuaia, Privilege), hotels £68 to £307 |
/lisbon |
Wheel-of-destinations landing page, 1,353 words, 13 images, hotels £129 to £288 |
/hotel/lp72f4b |
Real hotel page (Hotel Football, Old Trafford, a Tribute Portfolio Hotel), 60-image gallery, live LiteAPI rates, Add a Flight section |
/deals |
2,231 words, 39 hotel cards, real cross-hotel deals grid |
/?destination=lisbon |
Same route, but home page becomes a clean results page (no marketing chrome below the cards) |
/?vibe=party |
Same pattern with vibe filter active |
src/data/*.js)These are real LiteAPI rates, not mock data. The site enforces a hard rule (in AGENTS.md) against fake "from £X" pricing, and the rendering reflects that.
/v3.0/* to LiteAPI to avoid CORS in dev~/projects/vibe2-api)prebookId so the front end can poll real booking state instead of a "Booking Requested!" placeholder/api/bookings/{prebookId} is polled by the React app to surface live booking statesrc/data/*.js files, hand-curated by TedSeoHead component (react-helmet-async) writes unique <title>, meta description, canonical, Open Graph, Twitter card, and three JSON-LD schemas (FAQPage, ItemList, BreadcrumbList) for every brochure and wheel pagescripts/generate-sitemap.mjs and auto-discovers new destinations by regex-extracting slug: '...' fields from data filesrobots.txt, llms.txt, llms-full.txt all maintainedBrochure categories that feel editorial, not transactional. Each category is a top-10 with personality copy ("Techno without end. 24-hour clubs." for Berlin, not "Top nightlife destination, 4.2 stars"). Plum Guide, Mr & Mrs Smith, and Hopper were the design references.
Asymmetric layouts only. A hard rule in AGENTS.md forbids 3-equal-card hero/trust layouts. The home page is hero + 1 vibe carousel + 1 editorial row + 1 deals grid, never more, because more reads as "comprehensive search engine" instead of "curation site".
Real prices, always. Every hotel card shows the actual cheapest rate pulled live from LiteAPI. The Cancellation tab says "Non-refundable" when the rate is NRFN, never a fake was/now strikethrough. Verified above: £120, £125, £126 for London hotels, £61 for Hotel Football, etc.
Home page becomes a results page. When a search is active (vibe, region, destination, AI), the home page hides Featured Collections, Editorial Picks, Cheapest Escapes, Best For, Trust, and Newsletter. The user sees results, not half-results, half-marketing.
70+ European airports, no IATA knowledge required. A static 78-airport list with Haversine-based "nearest airport to this hotel" lookup. The user types "Bris" and gets Bristol. LiteAPI's network endpoint is the fallback, but local-first means instant.
Per-page dynamic h2 and subheading. When the user picks a vibe, the section heading changes from a generic "Pick the mood" to "Where the night starts: party hotel breaks in the UK" plus a 30-word long-tail subheading. Each variant is a distinct SEO target. Google sees "party hotel UK", "romantic weekend", "spa retreat UK" as separate semantic units, not one page.
Long-form wheel landing pages. The 8 wheel destinations (Lisbon, Bali, Marrakech, Tokyo, Cape Town, Reykjavik, Mexico City, Santorini) each get a 1,000+ word landing page with 10 best things to do, hotel options, FAQPage + ItemList + BreadcrumbList schema. Screenshot 09-wheel-lisbon.png shows the Lisbon page at 1,353 words with 13 images and 21 buttons.
/health check operational (sqlite OK, supabase OK, redis not yet wired)vibe2.co.uk: shows "Launching Soon" placeholder. The build is ready, the public switch has not been flipped yetAll screenshots below were captured on 2026-06-18 from http://localhost:5175/ using Playwright (Chromium 1.59.1, viewport 1440x900 desktop or 390x844 mobile). Full-page captures scroll the entire page; top-crop captures show only the visible viewport.
| # | File | Viewport | Page |
|---|---|---|---|
| 01 | 01-home-desktop-top.png |
desktop | / viewport top |
| 02 | 02-home-desktop-full.png |
desktop | / full scroll |
| 03 | 03-vibes-index.png |
desktop | /vibes full |
| 04 | 04-party-cities.png |
desktop | /party-cities full |
| 05 | 05-beach-parties.png |
desktop | /beach-parties full |
| 06 | 06-uk-clubbing.png |
desktop | /uk-clubbing full |
| 07 | 07-destination-london.png |
desktop | /party-cities/london full |
| 08 | 08-destination-ibiza.png |
desktop | /beach-parties/ibiza full |
| 09 | 09-wheel-lisbon.png |
desktop | /lisbon full |
| 10 | 10-wheel-bali.png |
desktop | /bali full |
| 11 | 11-hotel-detail.png |
desktop | /hotel/lp72f4b full |
| 12 | 12-deals-page.png |
desktop | /deals full |
| 13 | 13-home-mobile-top.png |
mobile | / viewport top |
| 14 | 14-home-mobile-full.png |
mobile | / full scroll |
| 15 | 15-home-as-results-destination.png |
desktop | /?destination=lisbon (home-as-results pattern) |
| 16 | 16-home-as-results-vibe.png |
desktop | /?vibe=party (home-as-results pattern) |
| 17 | 17-hotel-add-flight.png |
desktop | /hotel/lp72f4b scrolled to Add a Flight |
| 18 | 18-deals-top.png |
desktop | /deals viewport top |
| 19 | 19-uk-clubbing-mobile.png |
mobile | /uk-clubbing full |
Use 5-7 of these screenshots in this order:
The work.html card already references /assets/img/vibe2.png. That image is the old single-screenshot summary; the per-page screenshots above are the new evidence-backed case study.
curl http://localhost:5175/ returns 200, 1546 bytes of SPA shell)src/data/*.js) to verify the 90 destination entries, 78 airports, 8 vibes, 8 wheel destinations/vibes is intentionally sparse. The vibes index page is a thin 8-card grid, not a long-form page. The screenshot is 97KB because the page is genuinely small, not because it failed to render. DOM extraction confirms all 8 vibes are present.mcp_minimax_understand_image was unreachable for cross-checking screenshots via vision. Verification was done via DOM text extraction instead, which is more reliable for "what actually rendered" questions.Captured 2026-06-18 by Hermes Agent subagent. Screenshots: /Users/hollyiq600/hermes-shared/websites/expedient-ai/assets/img/case-studies/vibe2/. Manifest: _screenshot-manifest.json.
# Vibe2 Case Study Brief
**Project:** Vibe2
**Live at:** `http://localhost:5175/` (dev). Public `vibe2.co.uk` currently shows a "Launching Soon" placeholder, so all screenshots below are taken from the local dev build.
**Owner:** Ted (one operator, no team)
**Built by:** Expedient AI
**Status:** Active development. Production-ready stack, real LiteAPI integration, 200+ indexed URLs.
---
## What it is
A curated short-break travel website for UK travellers. The thesis: most travel sites are search engines with marketing bolted on. Vibe2 is a magazine with bookings bolted on. The user picks a mood ("party", "beach", "wine", "wellness", "skiing"), gets a hand-curated top-10 of cities, drills into any city, and books a real hotel at the real price. No fake "from £X" rates. No "Was £Y, now £Z" strikethroughs. No infinite carousel of OTAs pretending to be editorial.
The brochure-style content (Top 10 party cities in Europe, Top 10 wine destinations, etc.) is the SEO and brand asset. The booking flow is the conversion. The two have to feel like the same product.
## What I observed on the live build
I pulled Playwright screenshots of the dev server on 2026-06-18 against `http://localhost:5175/`. Verified via DOM extraction that every page below renders real content with real prices and real images.
### Pages visited
| Route | What renders |
|---|---|
| `/` | Vibe hero (h1: "Find a 3-night escape you'll actually take"), mood picker, romantic vibe carousel, UK clubbing spotlight panel, 9-category editorial guides grid, deals row, footer |
| `/vibes` | All 8 vibes in a clean grid (Party, Beach, Wellness, Food, Adventure, Romantic, Culture, Cheap & Easy) |
| `/party-cities` | Top 10 party cities in Europe (Berlin, Budapest, Barcelona, Belgrade, Prague, Amsterdam, London, Lisbon, Krakow, Bucharest), each a card |
| `/beach-parties` | Top 10 beach party destinations (Ibiza, Zrce/Pag, Mykonos, etc.) |
| `/uk-clubbing` | 10 UK cities with a real UK map image, real venue names (Fabric, Ministry of Sound, Drumsheds, Corsica Studios in London) |
| `/party-cities/london` | Per-city long-form page with 6 famous things to do, real hotel cards (£120 to £253 observed) |
| `/beach-parties/ibiza` | Per-beach page (Amnesia, Pacha, Ushuaia, Privilege), hotels £68 to £307 |
| `/lisbon` | Wheel-of-destinations landing page, 1,353 words, 13 images, hotels £129 to £288 |
| `/hotel/lp72f4b` | Real hotel page (Hotel Football, Old Trafford, a Tribute Portfolio Hotel), 60-image gallery, live LiteAPI rates, Add a Flight section |
| `/deals` | 2,231 words, 39 hotel cards, real cross-hotel deals grid |
| `/?destination=lisbon` | Same route, but home page becomes a clean results page (no marketing chrome below the cards) |
| `/?vibe=party` | Same pattern with vibe filter active |
### Verified content counts (from `src/data/*.js`)
- 9 brochure categories
- 90 destination city entries across the data files (10 in 9 categories)
- 10 UK clubbing cities
- 8 wheel-of-destinations landing pages (Lisbon, Bali, Marrakech, Tokyo, Cape Town, Reykjavik, Mexico City, Santorini)
- 78 European airports in the local autocomplete list
- 202 URLs in the generated sitemap (per CHANGELOG, up from 45)
### Verified pricing (live from LiteAPI on 2026-06-18)
- London party hotels: £120, £125, £126, £240, £250, £252, £253 per night
- Ibiza beach hotels: £68, £83, £126, £136, £153, £165, £252, £307 per night
- Lisbon wheel landing hotels: £129, £258, £288 per night
- Hotel Football (Old Trafford) gallery rate: £61, £73, £121 per night observed
- Deals page rows: £29, £31, £58, £62, £63, £87 per night observed
These are real LiteAPI rates, not mock data. The site enforces a hard rule (in AGENTS.md) against fake "from £X" pricing, and the rendering reflects that.
## Stack and architecture
### Front end
- Vite 5 + React 18, React Router 6, CSS Modules per component (no Tailwind, no UI framework)
- Framer Motion for entry animations only
- Phosphor Icons throughout
- All routes client-side rendered, the dev server proxies `/v3.0/*` to LiteAPI to avoid CORS in dev
### Back end (separate repo at `~/projects/vibe2-api`)
- FastAPI on Railway
- Two jobs: a LiteAPI webhook receiver (booking lifecycle events) and a static host for the built React app
- SQLite keyed by `prebookId` so the front end can poll real booking state instead of a "Booking Requested!" placeholder
- Endpoint `/api/bookings/{prebookId}` is polled by the React app to surface live booking state
### Data
- Notion is the design/CMS spec
- LiteAPI is the live data source (hotels, rates, reviews, weather, maps, airports)
- All destination copy (top-10s, famous things, when-to-go, cost labels) lives in static `src/data/*.js` files, hand-curated by Ted
- Wikipedia + Wikimedia Commons for real hero photos of real destinations. AI image generation used only for UK clubbing city heroes where Wikipedia returns no lead image
- One hard rule: no AI-generated photos of real places. Real photos from Wikimedia only, with attribution documented in the data file headers
### SEO
- Per-page `SeoHead` component (react-helmet-async) writes unique `<title>`, meta description, canonical, Open Graph, Twitter card, and three JSON-LD schemas (FAQPage, ItemList, BreadcrumbList) for every brochure and wheel page
- Sitemap generated by `scripts/generate-sitemap.mjs` and auto-discovers new destinations by regex-extracting `slug: '...'` fields from data files
- `robots.txt`, `llms.txt`, `llms-full.txt` all maintained
## What it does that an off-the-shelf OTA cannot
1. **Brochure categories that feel editorial, not transactional.** Each category is a top-10 with personality copy ("Techno without end. 24-hour clubs." for Berlin, not "Top nightlife destination, 4.2 stars"). Plum Guide, Mr & Mrs Smith, and Hopper were the design references.
2. **Asymmetric layouts only.** A hard rule in `AGENTS.md` forbids 3-equal-card hero/trust layouts. The home page is hero + 1 vibe carousel + 1 editorial row + 1 deals grid, never more, because more reads as "comprehensive search engine" instead of "curation site".
3. **Real prices, always.** Every hotel card shows the actual cheapest rate pulled live from LiteAPI. The Cancellation tab says "Non-refundable" when the rate is NRFN, never a fake was/now strikethrough. Verified above: £120, £125, £126 for London hotels, £61 for Hotel Football, etc.
4. **Home page becomes a results page.** When a search is active (vibe, region, destination, AI), the home page hides Featured Collections, Editorial Picks, Cheapest Escapes, Best For, Trust, and Newsletter. The user sees results, not half-results, half-marketing.
5. **70+ European airports, no IATA knowledge required.** A static 78-airport list with Haversine-based "nearest airport to this hotel" lookup. The user types "Bris" and gets Bristol. LiteAPI's network endpoint is the fallback, but local-first means instant.
6. **Per-page dynamic h2 and subheading.** When the user picks a vibe, the section heading changes from a generic "Pick the mood" to "Where the night starts: party hotel breaks in the UK" plus a 30-word long-tail subheading. Each variant is a distinct SEO target. Google sees "party hotel UK", "romantic weekend", "spa retreat UK" as separate semantic units, not one page.
7. **Long-form wheel landing pages.** The 8 wheel destinations (Lisbon, Bali, Marrakech, Tokyo, Cape Town, Reykjavik, Mexico City, Santorini) each get a 1,000+ word landing page with 10 best things to do, hotel options, FAQPage + ItemList + BreadcrumbList schema. Screenshot `09-wheel-lisbon.png` shows the Lisbon page at 1,353 words with 13 images and 21 buttons.
## What is shipping vs in development
- Front end: full app, all routes working, real LiteAPI rates flowing, all 9 brochure categories live, all 8 wheel landing pages live
- Back end: webhook receiver is live, static site host is live, deep `/health` check operational (sqlite OK, supabase OK, redis not yet wired)
- Public site `vibe2.co.uk`: shows "Launching Soon" placeholder. The build is ready, the public switch has not been flipped yet
- Future work (from CHANGELOG and SKILL): finish the UK map pin refinement, wire the AI search to a deeper LiteAPI rate surface, integrate the Apple Wallet pass for booking confirmations (referenced in the webhook event types)
## Screenshot index
All screenshots below were captured on 2026-06-18 from `http://localhost:5175/` using Playwright (Chromium 1.59.1, viewport 1440x900 desktop or 390x844 mobile). Full-page captures scroll the entire page; top-crop captures show only the visible viewport.
### Additional verified content from the live DOM
- Home page editorial guides grid shows all 9 brochure categories: party-cities, beach-parties, wellness-retreats, foodie-cities, adventure-destinations, skiing-destinations, hiking-destinations, wine-destinations, uk-clubbing
- UK clubbing spotlight panel on the home page renders the stats line verbatim: "10 UK CITIES / 100 CLUB NIGHTS + FESTIVALS / £0-£30 TYPICAL TICKET"
- Vibes index page renders 8 named vibes in this order: Party, Beach, Wellness, Food, Adventure, Romantic, Culture, Cheap & Easy
- Each per-city page includes a "Famous things to do" section with venue names, type tag, and a 1-line editorial note (e.g. London: Fabric / Ministry of Sound / Drumsheds / Corsica Studios)
- Each per-city page includes a "Where you'll stay in {City}" section with real hotel cards and live LiteAPI prices
| # | File | Viewport | Page |
|---|---|---|---|
| 01 | `01-home-desktop-top.png` | desktop | `/` viewport top |
| 02 | `02-home-desktop-full.png` | desktop | `/` full scroll |
| 03 | `03-vibes-index.png` | desktop | `/vibes` full |
| 04 | `04-party-cities.png` | desktop | `/party-cities` full |
| 05 | `05-beach-parties.png` | desktop | `/beach-parties` full |
| 06 | `06-uk-clubbing.png` | desktop | `/uk-clubbing` full |
| 07 | `07-destination-london.png` | desktop | `/party-cities/london` full |
| 08 | `08-destination-ibiza.png` | desktop | `/beach-parties/ibiza` full |
| 09 | `09-wheel-lisbon.png` | desktop | `/lisbon` full |
| 10 | `10-wheel-bali.png` | desktop | `/bali` full |
| 11 | `11-hotel-detail.png` | desktop | `/hotel/lp72f4b` full |
| 12 | `12-deals-page.png` | desktop | `/deals` full |
| 13 | `13-home-mobile-top.png` | mobile | `/` viewport top |
| 14 | `14-home-mobile-full.png` | mobile | `/` full scroll |
| 15 | `15-home-as-results-destination.png` | desktop | `/?destination=lisbon` (home-as-results pattern) |
| 16 | `16-home-as-results-vibe.png` | desktop | `/?vibe=party` (home-as-results pattern) |
| 17 | `17-hotel-add-flight.png` | desktop | `/hotel/lp72f4b` scrolled to Add a Flight |
| 18 | `18-deals-top.png` | desktop | `/deals` viewport top |
| 19 | `19-uk-clubbing-mobile.png` | mobile | `/uk-clubbing` full |
## Suggested case-study page (for expedientai.co.uk/work)
Use 5-7 of these screenshots in this order:
1. **02-home-desktop-full.png**: the headline visual. Shows hero + UK clubbing spotlight + editorial guides grid + deals. This is the "what is Vibe2" answer in one image.
2. **04-party-cities.png**: the brochure category page. Shows 10 cities with personality copy and real photos.
3. **06-uk-clubbing.png**: the UK map page. The most distinctive piece of UI. Real UK map image, 10 cities, hover-reveal labels.
4. **07-destination-london.png**: the per-city long-form page. Shows venues (Fabric, Ministry of Sound, Drumsheds) and real hotel cards with real prices.
5. **11-hotel-detail.png**: the booking surface. 60-image gallery, price calendar, Add a Flight section.
6. **09-wheel-lisbon.png**: a wheel landing page. Demonstrates the long-form SEO play (1,353 words, structured data, 10 best things to do).
7. **14-home-mobile-full.png**: mobile-first design. The site is built mobile-first at 375px. Captured at 390x844 (standard smartphone viewport).
The work.html card already references `/assets/img/vibe2.png`. That image is the old single-screenshot summary; the per-page screenshots above are the new evidence-backed case study.
## How I worked
1. Verified the dev server is reachable (`curl http://localhost:5175/` returns 200, 1546 bytes of SPA shell)
2. Captured 14 baseline screenshots across 9 distinct routes (Playwright headless Chromium)
3. Dumped DOM text + headings + price snippets from each page to confirm what actually rendered (caught nothing missing; all pages returned the expected h1/h2/h3 hierarchy and real £ prices)
4. Captured 5 extra screenshots covering the home-as-results pattern (the headline UX feature) and the hotel flight add-on
5. Cross-referenced observed counts against the static data files (`src/data/*.js`) to verify the 90 destination entries, 78 airports, 8 vibes, 8 wheel destinations
6. Cross-referenced the sitemap total (202 URLs) against CHANGELOG history
7. Wrote this brief with no invented numbers and no em-dashes (per task constraints)
## Issues encountered
- **`/vibes` is intentionally sparse.** The vibes index page is a thin 8-card grid, not a long-form page. The screenshot is 97KB because the page is genuinely small, not because it failed to render. DOM extraction confirms all 8 vibes are present.
- **`mcp_minimax_understand_image` was unreachable** for cross-checking screenshots via vision. Verification was done via DOM text extraction instead, which is more reliable for "what actually rendered" questions.
- **Public site is in "Launching Soon" mode**, so all visual evidence is from local dev. The public URL will need to be flipped once Ted signs off.
---
*Captured 2026-06-18 by Hermes Agent subagent. Screenshots: `/Users/hollyiq600/hermes-shared/websites/expedient-ai/assets/img/case-studies/vibe2/`. Manifest: `_screenshot-manifest.json`.*