Skip to main content
vibld

Template

Common Groove

A shared-listening web app where people join rooms that play the same track in sync, chat alongside the music, and (in private rooms) talk over WebRTC voice with automatic music ducking. The landing is a calm catalog-style page with a spinning vinyl, now-playing details and an 'Enter' action; inside, users browse genre rooms, search tracks, manage queues and share profile cards.

Shared listening room app · Website · Portfolio · full-stack app (auth + DB)

A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.

Start from this templateRead the build prompt

Typefaces

Arimo has Helvetica Neue's proportions for the Swiss headings, and Anek Latin is a clean catalog-card body.

  • ArimoHeadings: headings 42px medium, slight negative tracking
  • Anek LatinBody: body 16px (14px meta), 12px tracked uppercase labels

Who it is for

  • Music community builders and curators
  • Friends hosting group listening sessions
  • Startups prototyping social listening
  • Music discovery enthusiasts

Layout

  1. Top bar: tracked wordmark, outlined Login button left; global mini-player with track/artist and prev/pause/next/mute right
  2. Split landing: left half with large spinning vinyl record showing cover art in the label; right column with title, description, rule, 'Now playing' track + progress bar, key/value spec rows (Format, Access, Experience), outlined 'Enter' button
  3. Footer credit line; floating 'Tap to unmute' pill
  4. Room directory by genre
  5. Room view: player + queue (drag to reorder) + live chat column (+ voice panel in private rooms)
  6. Search results (from an embeddable video source) to add to queue
  7. Profile page with shareable card + QR code
  8. Moderation tools

Palette

Calm, curatorial, analog, minimal, intimate. It feels like browsing an archive of records in a quiet gallery.

  • background#ececea
  • text#201f1d
  • primary olive#60664c
  • secondary taupe (muted text)#6a625b
  • card#f3f3f2
  • muted surface#e2e1df
  • decorative hairline#cfcdc9
  • input / outline-button border#8c877d

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on background13.92:14.5:1
Aatext on cards14.83:14.5:1
Aatext on muted surface12.60:14.5:1
Aasecondary taupe text on background5.06:14.5:1
Aasecondary text on muted surface4.58:14.5:1
Aaolive link/primary text on background5.07:14.5:1
Aalight text on olive primary button5.40:14.5:1
Aatoast text on dark pill14.83:14.5:1
input/outline button border on background3.02:13:1
input border on card3.22:13:1
progress bar fill on muted track4.59:13:1
focus ring on background13.92:13:1

As vibld’s tokens

The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.

  • background
  • card
  • muted
  • primary
  • secondary
  • accent
  • destructive *

Type scale

Display
Helvetica Neue medium, 42px with slight negative tracking (Helvetica Neue is not on Google Fonts; a vibld project loads Arimo)
Body
Anek Latin 16px (14px for dense chat/queue meta), line-height 1.5–1.6; tracked uppercase 12px labels at weight 500

Swiss, catalog-like typography; key/value rows read like an archive record card

Spacing and imagery

Two-column 50/50 split with vertical hairline divider, generous whitespace, 2px (.125rem) radius, thin rules between spec rows, pill toasts

Rendered spinning vinyl record with photo on the label; album/video thumbnails in queues and search

Components

  • Global persistent mini-player
  • Spinning vinyl visual
  • Now-playing progress bar
  • Spec key/value list
  • Room directory cards by genre
  • Sync player with room state
  • Drag-and-drop queue
  • Live chat column
  • Voice chat panel with mute and ducking
  • Track search results
  • Shareable profile card with QR code
  • Moderation/report menu
  • Login dialog
  • Unmute prompt toast

Interactions

  • Vinyl rotates while playing, stops on pause
  • Playback syncs across listeners in real time
  • Player survives route changes
  • Drag to reorder queue
  • Chat messages stream in live
  • Voice activity ducks music volume
  • Tap-to-unmute prompt for autoplay policies
  • Fallback 'finding alternative' when a source fails

Data

  • Profile{id, username, avatar, bio, favorite_genres[]}
  • Room{id, slug, name, genre, is_private, owner_id, current_track_id, started_at}
  • QueueItem{id, room_id, track_ref, title, artist, added_by, position}
  • Message{id, room_id, user_id, body, created_at}
  • RoomMember{room_id, user_id, role: owner|mod|listener}
  • Report{id, message_id, reporter_id, reason, status}

Build prompt

The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.

The baseline
### How to use these prompts
Paste a template's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project.

### Engineering baseline
- TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone.
- Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only.
- Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables.

### Data and auth baseline (full-stack templates)
- Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views.
- Store roles in a separate table checked by a security-definer function, never in a user-editable profile field.
- Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs.
- Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms.
- Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data.

### Accessibility and UX baseline
- Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change.
- Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels.
- Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images.
- Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives.
- Build mobile-first and test at 375px, 768px and 1280px.

### Content guardrails
- Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text.
- Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.
### Goal
Build a shared-listening web app called **Common Groove**. The audience is music communities and friend groups who want to hear the same track together, chat, and talk over the music in private rooms. The landing page should feel like an archive record card; inside, users browse genre rooms, add tracks to a shared queue, and share a profile card.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix), lucide-react, React Router, TanStack Query, Framer Motion, dnd-kit for the queue, react-hook-form + zod, and a QR code library. Supabase provides Auth, Postgres, Realtime (presence, playback broadcast, chat), Storage (avatars) and Edge Functions (search proxy, moderation, WebRTC signaling). An embeddable video player API is the playback source.

### Pages & layout
1. Top bar: tracked wordmark and outlined Login left; a persistent mini-player (title, artist, previous, play/pause, next, mute) right.
2. Landing: split 50/50 with a hairline divider. The left shows a large vinyl record with cover art on the label, spinning while playing. The right shows the title, a one-line description, a rule, a "Now playing" block with progress bar and times, spec rows (Format, Access, Experience), and an outlined "Enter" button.
3. Rooms: directory grouped by genre with listener counts and the current track.
4. Room: player and vinyl, the queue (drag to reorder, add from search), a chat column, and a voice panel in private rooms (join, mute, speaking indicators).
5. Search: results with add-to-queue.
6. Profile: avatar, genres, recent rooms, and a shareable card with QR code.
7. Moderation: reported messages for owners and moderators.

### Design system
Tokens: `--background: #ececea; --foreground: #201f1d; --primary: #60664c; --primary-foreground: #f3f3f2; --secondary: #6a625b; --card: #f3f3f2; --muted: #e2e1df; --border: #cfcdc9 (decorative hairlines); --input-border: #8c877d; --radius: .125rem`. Fonts: Anek Latin 400/500 for UI and Anek Latin 500 for the 42px title (-2% tracking). Scale: 42 / 20 / 16 / 14 / 12px (16px body, line-height 1.6; 14px for dense chat/queue meta; 12px uppercase labels at weight 500, 0.08em tracking). Buttons are 1px outlined rectangles using the #8c877d border; toasts are dark pills. Motion: 33 rpm spin (1.8s per turn) linear; 200ms panels. Light only.
- Typeface: Arimo (Google Fonts) for headings 42px medium, slight negative tracking.

### Components & interactions
- Sync engine: the room stores `current_track` and `started_at`; clients compute the offset and seek; drift over 1.5s triggers a resync; a host-only skip.
- Autoplay blocked: show a "Tap to unmute" pill. Source failure: show "Finding alternative…" and skip ahead after a timeout.
- Queue: drag handles with keyboard reordering (dnd-kit sensors); optimistic moves with rollback.
- Chat: auto-scroll unless scrolled up; rate-limited send; report menu.
- Voice: ducks music to 30% while anyone speaks; mute and leave; permission-denied state.

### Data & state
Tables: `profiles`, `rooms(id, slug, name, genre, is_private, owner_id, current_item_id, started_at)`, `room_members(room_id, user_id, role)`, `queue_items(id, room_id, track_ref, title, artist, added_by, position)`, `messages(id, room_id, user_id, body, created_at)`, `reports(id, message_id, reporter_id, reason, status)`. Playback state lives in a global player context outside the router. Seed rooms per genre with invented names.

### Accessibility
#201f1d on #ececea is about 14:1; secondary taupe #6a625b and olive #60664c both pass as text, and #f3f3f2 on olive buttons passes. The vinyl is decorative and stops under reduced motion; player controls are labelled 44px buttons. Chat is an `aria-live="polite"` log with a labelled input. Queue reordering must work by keyboard with announcements. Voice speaking indicators need text, not only color. Verified contrast: secondary taupe text on background: #6a625b on #ececea = 5.06:1; light text on olive primary button: #f3f3f2 on #60664c = 5.4:1; input/outline button border on background: #8c877d on #ececea = 3.02:1.

### Security
RLS: public rooms are readable by all; private rooms only by members. Only members insert messages, only for themselves. Queue writes are allowed only for members; reordering and skipping only for owners and moderators. Reports are visible only to room moderators. Validate message length (1–500) with zod and a DB check; render as plain text. Rate-limit messages per user via an edge function. The search proxy keeps the video API key server-side. WebRTC signaling is authenticated per room. Only the anon key ships to the client.

### Performance & SEO
Lazy-load the player API; code-split routes; paginate chat; unsubscribe realtime channels on leave. Private rooms are `noindex`.

### Guardrails
- Use invented room names, users and placeholder art; no real artists' images as branding.
- Don't store voice audio; voice is peer-to-peer only.
- Keep only username, avatar and genres.
- Keep components small and typed, never use `any`, and surface sync and permission errors visibly.
- Done when: two browsers stay within 1.5s of each other in the same room; non-members cannot read private-room messages (verified via RLS); the queue reorders by mouse and keyboard; music ducks during voice; a blocked source advances to the next track automatically.

Open the builderAll templatesThis palette on its own