Page 1 of 21
System Requirements Document for vybe
1. Introduction
vybe is a music social media application built with React Native Expo and delivered on iOS, Android, and Web. Its product intent is friend-centered listening: the app exists so that a listener can see what their friends are currently listening to, browse friends' favorite songs, artists, and albums, share their own favorites, post songs, post song lyrics and quotes, and move through a TikTok-style vertical scroll of 30-second previews of posted songs.
The audience is Gen-Z listeners who already live inside Spotify, TikTok, and group chats. The emotional register of the product is kinetic, social, and playful: what friends are playing right now should feel alive rather than filed. vybe is not a utility, not a chart tool, and not a premium instrument — it is a place where sound and friends move.
Access is anchored to Spotify: a visitor signs in with Spotify, and then completes an account creation for the vybe app itself, based on that Spotify account. The 30-second previews come from Apple Music's public API. Supabase is the database.
Page 2 of 21
2. System Overview
vybe is a single first-party application delivered through React Native Expo to iOS, Android, and Web. It has a public entry surface, an identity access boundary built on Spotify sign-in followed by vybe account creation, and a protected social core: a friend-centered activity feed, friends' favorites browsing, the user's own favorites overview and editing workspace, two focused post composers (song posts and lyric/quote posts), and a TikTok-style vertical previews destination.
Current actors are the three accepted personas: the Music Sharer, the Friend-Feed Listener, and the New Account Creator. Spotify is an external identity provider; Apple Music's public API is an external preview-content provider; Supabase is the application database. None of these are personas.
Current delivery covers: Spotify sign-in; vybe account creation linked to the Spotify account; returning verification through Spotify; friend-centered current-listening visibility; friends' favorite songs, artists, and albums; the user's own favorites (view and edit); posting songs; posting lyrics and quotes; and vertical 30-second preview browsing sourced from Apple Music's public API.
Narrow exclusions for the current horizon: no account-management surface beyond first-use creation and returning verification; no differentiated permission tiers or role-based visibility over shared product state; no messaging, chat, or direct-message capability; no charting, analytics, or premium-instrument tooling; no stock photography of people and no illustration-led imagery.
Page 3 of 21
2a. Product Interpretation and Delivery Boundary
vybe is delivered as a first-party application with custom UI on iOS, Android, and Web. The public entry surface is anonymously reachable and explains the friend-centered listening experience, the posting features, and the preview scroll. Identity is application-owned but Spotify-anchored: the visitor signs in with Spotify, and the vybe account is then created based on that Spotify account and linked to it. Protected social destinations require that linked vybe account; the interaction that establishes access to those destinations is not owned by them.
Spotify owns the sign-in interaction itself. Apple Music's public API owns the 30-second preview content that vybe renders. Supabase owns persistence of vybe accounts, favorites, posts, and friend-centered listening data. vybe owns the social surfaces, the composers, the favorites workspaces, and the preview browsing experience.
Everything described in this document is current. No future-horizon capabilities are asserted here; anything not listed in the current scope is out of scope for this generation.
2b. Source Content Inventory
Not applicable. No reference directive in this project declares content_source authority, so no source content inventory is rendered.
2c. Page Content and Component Coverage
Page 4 of 21
Landing
- Information/state: Anonymous first impression of vybe. Full-bleed near-black viewport with no centred stack. A single line of oversized Space Grotesk reads "HEAR WHAT YOUR FRIENDS HEAR" set flush-left, filling roughly nine of twelve columns and running off the right edge at desktop; the last word is intentionally cropped by the frame as decoration only, with a shorter, fully visible subline beneath it. Behind and through the type, a live waveform of the currently featured preview animates across the full width in acid lime, its bars leaning toward the pointer. Bottom-right carries a mono micro-label reading "30-SEC PREVIEWS · APPLE MUSIC · SUPABASE".
- Primary action: "Continue with Spotify" — a solid hot-red rectangle button, label flush-left, with a 1px warm off-white hairline offset 4px down-right as its shadow. This begins the Spotify sign-in interaction.
- Supporting actions: Read the subline explaining the friend-centered listening experience, the posting features, and the preview scroll. Observe the live waveform responding to pointer or thumb proximity.
- Domain entities: Featured preview (song, 30-second Apple Music preview), waveform amplitude data, Spotify sign-in entry.
- Component responsibilities: Hero type block (kinetic, flush-left, ragged-right); live waveform component (amplitude bars, 2px wide, 2px gap, pointer-reactive lean capped at ~8px displacement); Spotify entry button; mono micro-label; subline.
- States: Loading — waveform renders as static amplitude bars until preview data resolves. Empty — if no featured preview is available, the waveform renders as a flat baseline and the hero type remains fully readable. Success — waveform animates continuously and the Spotify button is available. Error — if preview data fails, the waveform falls back to static bars and the Spotify button remains fully functional. Recovery — the entry action never depends on preview availability.
Login
- Information/state: Returning access surface. States plainly that vybe sign-in happens through Spotify, and that the vybe account is linked to the Spotify account. Minimal chrome, flush-left composition, no centred card.
- Primary action: "Continue with Spotify" — begins the Spotify sign-in interaction for a returning user.
- Supporting actions: Navigate to Sign Up for a first-use visitor who has not yet created a vybe account.
- Domain entities: Spotify identity, linked vybe account.
- Component responsibilities: Spotify entry control; short explanatory copy; link to Sign Up; mono micro-labels for any status text.
- States: Loading — Spotify entry control shows a restrained in-progress state using the waveform as loading indicator. Empty — not applicable; the surface always presents the Spotify entry. Success — Spotify sign-in completes and the returning user is verified and resumed into their vybe account. Error — if Spotify sign-in fails or is cancelled, the surface states the failure plainly and keeps the Spotify entry control available. Recovery — the user can retry the Spotify sign-in immediately; if no linked vybe account exists, the user is directed to Sign Up.
Sign Up
- Information/state: First-use vybe account creation surface, reached after Spotify sign-in has completed. It presents the Spotify account that was just signed in with and collects the vybe account details that will be created based on that Spotify account.
- Primary action: Create the vybe account, linked to the signed-in Spotify account.
- Supporting actions: Review the Spotify account being linked; adjust the vybe account details before committing.
- Domain entities: Spotify account (identity source), vybe account (created record), account link between them.
- Component responsibilities: Spotify account summary; vybe account detail fields; create-account control; mono micro-labels for the linked identity.
- States: Loading — the surface shows the waveform as loading indicator while the Spotify account is resolved. Empty — if the Spotify account cannot be resolved, the surface states that Spotify sign-in must be completed first and offers the Spotify entry. Success — the vybe account is created and linked, and the user enters the protected social core. Error — if account creation fails, the surface states the failure and preserves the entered details. Recovery — the user can retry creation without repeating Spotify sign-in while the Spotify session remains valid.
Page 5 of 21
Friends
- Information/state: The friend-centered activity feed. Shows what friends are currently listening to, as a ruled, hairline-separated list with mono timestamps and a pulsing hot-red dot marking live now-playing entries — never a grid of identical hover-lift cards. On desktop this is the asymmetric three-column left rail alongside the main content; at 375px the rail collapses into a horizontal snap row of friend avatars under the top bar.
- Primary action: Open a friend's current listening entry to see the song and its 30-second preview.
- Supporting actions: Enter the previews scroll; enter friends' favorites; enter the user's own favorites; enter a song post composer; enter a quote post composer.
- Domain entities: Friend, now-playing entry, song, artist, album, timestamp, 30-second preview.
- Component responsibilities: Ruled now-playing list with mono timestamps and live pulse dot; horizontal snap avatar row at narrow widths; waveform component reused as divider and play state; entry points to Previews, Friend Favorites, Favorites, Song Post, and Quote Post.
- States: Loading — ruled list rows render with static amplitude bars as placeholders. Empty — when no friend is currently listening, the feed states that plainly and keeps the entry points to Previews and the composers available. Success — friends' now-playing entries render with live pulse dots and mono timestamps. Error — if friend listening data fails to load, the feed states the failure and offers retry. Recovery — retry reloads the ruled list without leaving the surface.
Friend Favorites
- Information/state: Browse destination for friends' favorite songs, artists, and albums. Ruled, hairline-separated presentation consistent with the Friends rail; no card grid.
- Primary action: Select a friend to browse that friend's favorite songs, artists, and albums.
- Supporting actions: Switch between the songs, artists, and albums groupings; open a favorite to see its 30-second preview where a preview exists.
- Domain entities: Friend, favorite song, favorite artist, favorite album, 30-second preview.
- Component responsibilities: Friend selector; grouped ruled lists for songs, artists, and albums; waveform component as divider and play state; mono micro-labels for counts and durations.
- States: Loading — grouped lists render with static amplitude bars as placeholders. Empty — when a friend has no favorites recorded, the surface states that plainly. Success — the friend's favorite songs, artists, and albums render in their groupings. Error — if favorites fail to load, the surface states the failure and offers retry. Recovery — retry reloads the selected friend's favorites without leaving the surface.
Favorites
- Information/state: Revisitable overview of the user's own favorite songs, artists, and albums. Ruled, hairline-separated presentation with mono micro-labels.
- Primary action: Review the user's own favorite songs, artists, and albums.
- Supporting actions: Enter Edit Favorites to add or change favorites; open a favorite to see its 30-second preview where a preview exists.
- Domain entities: Favorite song, favorite artist, favorite album, 30-second preview.
- Component responsibilities: Grouped ruled lists for songs, artists, and albums; entry control to Edit Favorites; waveform component as divider and play state; mono micro-labels for counts and durations.
- States: Loading — grouped lists render with static amplitude bars as placeholders. Empty — when the user has no favorites yet, the surface states that plainly and offers the entry to Edit Favorites. Success — the user's favorite songs, artists, and albums render in their groupings. Error — if favorites fail to load, the surface states the failure and offers retry. Recovery — retry reloads the user's favorites without leaving the surface.
Page 6 of 21
Edit Favorites
- Information/state: Focused workspace for adding and editing the user's own favorite songs, artists, and albums. Flush-left, ragged-right, hairline-structured; no dense settings-style form chrome.
- Primary action: Add a favorite song, artist, or album, or edit an existing one.
- Supporting actions: Remove a favorite; return to Favorites to review the result.
- Domain entities: Favorite song, favorite artist, favorite album, 30-second preview.
- Component responsibilities: Add controls per grouping; editable favorite rows; save and remove controls; waveform component as divider and loading indicator; mono micro-labels for durations and counts.
- States: Loading — existing favorites render with static amplitude bars as placeholders while the workspace resolves. Empty — when the user has no favorites yet, the workspace presents the add controls directly. Success — the added or edited favorite is persisted to Supabase and reflected in Favorites. Error — if a save or removal fails, the workspace states the failure and preserves the in-progress edit. Recovery — the user can retry the save or removal without re-entering the edit.
Song Post
- Information/state: Focused composer for creating a post containing a song. The song's 30-second Apple Music preview is rendered as the post's waveform signature.
- Primary action: Publish a song post to the friends feed.
- Supporting actions: Select the song; preview the 30-second preview and its generated waveform before publishing; discard the draft.
- Domain entities: Song, artist, album, 30-second Apple Music preview, generated waveform, post.
- Component responsibilities: Song selection control; waveform component derived from the actual preview data; publish control; discard control; mono micro-labels for duration and status.
- States: Loading — the waveform renders as static amplitude bars while the preview resolves. Empty — before a song is selected, the composer presents the selection control and no waveform. Success — the song post is persisted to Supabase and appears in the friends feed. Error — if the preview cannot be resolved from Apple Music's public API, the composer states the failure and keeps the draft; if publishing fails, the composer states the failure and preserves the draft. Recovery — the user can retry preview resolution or publishing without rebuilding the post.
Quote Post
- Information/state: Focused composer for creating a post containing song lyrics or a quote. Lyric and quote posts are pure typography on a flat colour block — hot red or acid lime ground with near-black or warm off-white type, checked for contrast — with oversized Space Grotesk set flush-left.
- Primary action: Publish a lyric or quote post to the friends feed.
- Supporting actions: Enter the lyric or quote text; choose the flat colour ground; preview the word-by-word kinetic type treatment; discard the draft.
- Domain entities: Lyric or quote text, flat colour ground, post.
- Component responsibilities: Text entry; colour ground selection; kinetic type preview with 28ms word stagger; publish control; discard control; mono micro-labels for status.
- States: Loading — not applicable beyond publish in progress, shown with the waveform as loading indicator. Empty — before text is entered, the composer presents the text entry and colour ground selection. Success — the lyric or quote post is persisted to Supabase and appears in the friends feed. Error — if publishing fails, the composer states the failure and preserves the draft. Recovery — the user can retry publishing without re-entering the text.
Page 7 of 21
Previews
- Information/state: TikTok-style vertical browsing destination for 30-second previews of posted songs. One post per 100dvh in a vertical snap scroll, no card chrome, the poster's handle rotated 90° flush against the left edge, and the mono timestamp pinned bottom-right. The waveform scrubber is pinned to the bottom edge and redraws in real time as the preview plays.
- Primary action: Scroll vertically through posted songs and play their 30-second previews.
- Supporting actions: Scrub within a preview using the waveform scrubber; pause and resume; move to the next or previous post.
- Domain entities: Posted song, poster handle, timestamp, 30-second Apple Music preview, waveform amplitude data.
- Component responsibilities: Vertical snap scroll container; per-post waveform scrubber pinned to the bottom edge; rotated poster handle; mono timestamp; play/pause state expressed through the waveform; pointer/thumb-reactive waveform lean.
- States: Loading — the current post's waveform renders as static amplitude bars until its preview resolves. Empty — when no posted songs exist, the destination states that plainly and offers the entry to Song Post. Success — previews play with the waveform redrawing in real time and the scrubber tracking position. Error — if a preview cannot be resolved from Apple Music's public API, that post states the failure and the scroll continues to the next post. Recovery — the user can retry the failed preview or continue scrolling; the snap position is preserved.
Page 8 of 21
3. Functional Requirements
FR-1 — Spotify sign-in for returning users (explicit)
As a returning listener, I should sign in with Spotify so that I can resume my vybe account.
- Actor: New Account Creator / Music Sharer / Friend-Feed Listener (returning).
- Trigger/input: The user activates "Continue with Spotify" on Landing or Login.
- Observable result: Spotify sign-in completes and the user is verified and resumed into their linked vybe account.
- Access state: Anonymous entry; the protected social core becomes available only after verification.
- Failure/recovery: If Spotify sign-in fails or is cancelled, the surface states the failure and keeps the Spotify entry available for immediate retry.
- Continuation: On success the user enters the protected social core; if no linked vybe account exists, the user is directed to Sign Up.
- Provenance: explicit.
FR-2 — vybe account creation based on the Spotify account (explicit)
As a first-use visitor, I should complete an account creation for the vybe app itself based on my Spotify account so that I have a vybe identity linked to my Spotify identity.
- Actor: New Account Creator.
- Trigger/input: Spotify sign-in has completed and the user reaches Sign Up.
- Observable result: A vybe account is created and linked to the signed-in Spotify account.
- Access state: Anonymous entry to Sign Up; the vybe account must exist and be linked before protected social features are available.
- Failure/recovery: If creation fails, the surface states the failure and preserves the entered details; the user can retry without repeating Spotify sign-in while the Spotify session remains valid.
- Continuation: On success the user enters the protected social core.
- Provenance: explicit.
FR-3 — Spotify sign-in precedes vybe account creation (required_inference)
As a first-use visitor, I should complete Spotify sign-in before creating my vybe account so that the vybe account is genuinely based on my Spotify account.
- Actor: New Account Creator.
- Trigger/input: The user attempts to create a vybe account.
- Observable result: Sign Up presents the resolved Spotify account and will not create a vybe account without it.
- Access state: Anonymous entry; Spotify sign-in is the prerequisite.
- Failure/recovery: If the Spotify account cannot be resolved, the surface states that Spotify sign-in must be completed first and offers the Spotify entry.
- Continuation: After Spotify sign-in resolves, the user proceeds to create the vybe account.
- Provenance: required_inference.
FR-4 — Returning verification and account resumption (required_inference)
As a returning listener, I should verify through Spotify and resume my existing vybe account so that my favorites, posts, and friend connections remain mine.
- Actor: Music Sharer / Friend-Feed Listener (returning).
- Trigger/input: The user signs in with Spotify on Login.
- Observable result: The existing vybe account linked to that Spotify account is resumed.
- Access state: Anonymous entry to Login; protected state remains unavailable until verification succeeds.
- Failure/recovery: If verification fails, the surface states the failure and keeps the Spotify entry available; if no linked vybe account exists, the user is directed to Sign Up.
- Continuation: On success the user enters the protected social core with their existing state.
- Provenance: required_inference.
FR-5 — View what friends are currently listening to (explicit)
As a Friend-Feed Listener, I should see what my friends are currently listening to so that I can keep up with their listening in one place.
- Actor: Friend-Feed Listener (initiator); friends are the materially affected participants whose listening state is surfaced.
- Trigger/input: The user opens Friends.
- Observable result: A ruled, hairline-separated list of friends' now-playing entries with mono timestamps and a pulsing hot-red dot on live entries.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If friend listening data fails to load, the feed states the failure and offers retry.
- Continuation: The user can open a friend's entry to see the song and its 30-second preview, or move to Previews, Friend Favorites, Favorites, or a composer.
- Provenance: explicit.
FR-6 — Browse friends' favorite songs, artists, and albums (explicit)
As a Friend-Feed Listener, I should browse my friends' favorite songs, artists, and albums so that I can discover what they love.
- Actor: Friend-Feed Listener (initiator); the friend is the materially affected participant whose favorites are surfaced.
- Trigger/input: The user opens Friend Favorites and selects a friend.
- Observable result: That friend's favorite songs, artists, and albums render in grouped ruled lists.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If favorites fail to load, the surface states the failure and offers retry.
- Continuation: The user can switch groupings, open a favorite's 30-second preview where one exists, or return to Friends.
- Provenance: explicit.
FR-7 — View the user's own favorites (explicit)
As a Music Sharer or Friend-Feed Listener, I should view my own favorite songs, artists, and albums so that I can review what I have saved.
- Actor: Music Sharer / Friend-Feed Listener.
- Trigger/input: The user opens Favorites.
- Observable result: The user's favorite songs, artists, and albums render in grouped ruled lists.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If favorites fail to load, the surface states the failure and offers retry.
- Continuation: The user can enter Edit Favorites or open a favorite's 30-second preview where one exists.
- Provenance: explicit.
FR-8 — Manage the user's own favorites (explicit)
As a Music Sharer or Friend-Feed Listener, I should add and edit my favorite songs, artists, and albums so that my favorites reflect what I actually love.
- Actor: Music Sharer / Friend-Feed Listener.
- Trigger/input: The user opens Edit Favorites and adds, edits, or removes a favorite.
- Observable result: The change is persisted to Supabase and reflected in Favorites.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If a save or removal fails, the workspace states the failure and preserves the in-progress edit for retry.
- Continuation: The user returns to Favorites to review the result.
- Provenance: explicit.
FR-9 — Post a song (explicit)
As a Music Sharer, I should post a song so that my friends can discover what I am sharing.
- Actor: Music Sharer (initiator); friends are the materially affected participants who receive the post in their feed.
- Trigger/input: The user opens Song Post, selects a song, and publishes.
- Observable result: The song post is persisted to Supabase and appears in the friends feed with its waveform signature derived from the actual 30-second preview data.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If the preview cannot be resolved from Apple Music's public API, the composer states the failure and keeps the draft; if publishing fails, the composer states the failure and preserves the draft for retry.
- Continuation: The user can publish again, discard the draft, or move to Previews to see posted songs.
- Provenance: explicit.
FR-10 — Post song lyrics or a quote (explicit)
As a Music Sharer, I should post song lyrics or a quote so that my friends can see the words I am sharing.
- Actor: Music Sharer (initiator); friends are the materially affected participants who receive the post in their feed.
- Trigger/input: The user opens Quote Post, enters lyric or quote text, chooses a flat colour ground, and publishes.
- Observable result: The lyric or quote post is persisted to Supabase and appears in the friends feed as pure typography on a flat colour block.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If publishing fails, the composer states the failure and preserves the draft for retry.
- Continuation: The user can publish again, discard the draft, or move to Previews.
- Provenance: explicit.
FR-11 — TikTok-style scrolling of 30-second previews (explicit)
As a Music Sharer or Friend-Feed Listener, I should scroll vertically through 30-second previews of posted songs so that I can move through shared music the way I move through short-form video.
- Actor: Music Sharer / Friend-Feed Listener.
- Trigger/input: The user opens Previews and scrolls vertically.
- Observable result: One post per 100dvh in a vertical snap scroll, with the waveform scrubber pinned to the bottom edge redrawing in real time as the preview plays.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If a preview cannot be resolved from Apple Music's public API, that post states the failure and the scroll continues to the next post; the snap position is preserved.
- Continuation: The user continues scrolling, scrubs within a preview, or pauses and resumes.
- Provenance: explicit.
FR-12 — 30-second previews sourced from Apple Music's public API (explicit)
As a listener, I should hear 30-second previews supplied by Apple Music's public API so that every posted song has a real, playable preview.
- Actor: Music Sharer / Friend-Feed Listener (consumer of the preview).
- Trigger/input: A preview is requested on Song Post, Previews, Friends, Friend Favorites, or Favorites.
- Observable result: The 30-second preview plays and its waveform is derived from the actual preview data.
- Access state: Protected for the social surfaces; the Landing featured waveform is anonymous.
- Failure/recovery: If the preview cannot be resolved, the affected surface states the failure and offers retry; the Landing waveform falls back to static bars.
- Continuation: The user retries or continues to the next item.
- Provenance: explicit.
FR-13 — Supabase persistence of accounts, favorites, posts, and friend-centered listening data (required_inference)
As a listener, I should have my vybe account, favorites, posts, and friend-centered listening data persisted so that my state survives across sessions and devices.
- Actor: Music Sharer / Friend-Feed Listener / New Account Creator.
- Trigger/input: Account creation, favorite changes, post publishing, and friend listening reads.
- Observable result: Records are written to and read from Supabase and remain bound to the correct vybe account.
- Access state: Protected; requires the linked vybe account.
- Failure/recovery: If a read or write fails, the affected surface states the failure and offers retry without losing the user's in-progress work.
- Continuation: The user retries or continues on the surface.
- Provenance: required_inference.
FR-14 — Anonymous first impression of vybe (required_inference)
As a visitor, I should understand what vybe is before signing in so that I can decide to continue with Spotify.
- Actor: New Account Creator / Music Sharer / Friend-Feed Listener (pre-identity).
- Trigger/input: The visitor opens Landing.
- Observable result: A full-bleed near-black viewport with the oversized flush-left headline, a live waveform of the currently featured preview, the "Continue with Spotify" button, and the mono micro-label "30-SEC PREVIEWS · APPLE MUSIC · SUPABASE".
- Access state: Anonymous; no protected state is exposed.
- Failure/recovery: If preview data fails, the waveform falls back to static bars and the Spotify entry remains fully functional.
- Continuation: The visitor activates "Continue with Spotify" to begin sign-in.
- Provenance: required_inference.
Page 9 of 21
4. User Personas
Music Sharer
The Music Sharer is a signed-in listener whose center of gravity is publishing. They post songs and they post lyrics and quotes, and they care that what they shared actually lands in their friends' feed where friends can discover and react to it. Their work is authorial: choosing the song, checking the 30-second preview and its generated waveform before publishing, and setting lyric or quote text on a flat colour ground where the words themselves are the image.
Their primary goal is that their posts appear in the feed and that friends can discover and react to what they shared. Their distinct accepted responsibilities are creating song posts and creating lyric or quote posts. Their relevant inputs and decisions are song selection, preview verification, lyric or quote text, and colour ground choice. They also view and manage their own favorites, browse friends' favorites, see what friends are currently listening to, and scroll the previews destination.
They interact with friends as the recipients of their posts, and with Spotify as the identity they signed in through. Their observable success is a published post persisted to Supabase and visible in the friends feed with its own waveform signature derived from the actual preview data.
Page 10 of 21
Friend-Feed Listener
The Friend-Feed Listener is a signed-in listener whose center of gravity is following. They are not primarily publishing; they are keeping up. Their work is observational and continuous: seeing what friends are currently listening to, browsing friends' favorite songs, artists, and albums, and moving through the vertical scroll of 30-second previews of posted songs.
Their primary goal is to keep up with friends' listening activity and favorites in one place. Their distinct accepted responsibilities are viewing friends' now-playing entries, browsing friends' favorites, and scrolling previews. Their relevant inputs and decisions are which friend to follow into, which grouping of favorites to browse, and when to scrub, pause, or continue in the previews scroll. They also view and manage their own favorites.
They interact with friends as the subjects of the listening and favorites they browse, and with the Music Sharer as the source of the posts they scroll. Their observable success is a ruled now-playing list with live pulse dots and mono timestamps, grouped friends' favorites, and a previews scroll that plays each post's 30-second preview with a waveform that redraws in real time.
Page 11 of 21
New Account Creator
The New Account Creator is a visitor at the identity boundary. They have not yet entered the social core, and their entire accepted responsibility is getting in correctly: signing in with Spotify and then completing a vybe account creation based on that Spotify account.
Their primary goal is that their vybe account is created and linked to their Spotify identity so they can enter the app. Their distinct accepted responsibilities are completing Spotify sign-in and completing the vybe account creation that follows it. Their relevant inputs and decisions are the Spotify account they sign in with and the vybe account details they confirm. They interact with Spotify as the identity provider and with vybe as the account owner.
Their observable success is a vybe account created and linked to the signed-in Spotify account, after which they enter the protected social core. If they are returning rather than new, their success is verification through Spotify and resumption of their existing vybe account.
5. Core User Flows
Page 12 of 21
Flow 1 — New Account Creator: first-use entry into vybe
- The visitor opens Landing anonymously. They see the full-bleed near-black viewport, the oversized flush-left headline "HEAR WHAT YOUR FRIENDS HEAR" with its shorter fully visible subline, the live waveform of the currently featured preview leaning toward their pointer, and the mono micro-label "30-SEC PREVIEWS · APPLE MUSIC · SUPABASE".
- The visitor reads the subline explaining the friend-centered listening experience, the posting features, and the preview scroll. If preview data has not resolved, the waveform shows static amplitude bars and the entry remains fully usable.
- The visitor activates "Continue with Spotify" — the solid hot-red rectangle with the offset hairline shadow. This begins the Spotify sign-in interaction, which Spotify owns.
- Spotify sign-in completes. The visitor is now a signed-in Spotify identity without a vybe account.
- The visitor arrives at Sign Up. The surface presents the resolved Spotify account and collects the vybe account details that will be created based on it. If the Spotify account cannot be resolved, the surface states that Spotify sign-in must be completed first and offers the Spotify entry.
- The visitor confirms the details and creates the vybe account. The account is created and linked to the signed-in Spotify account, and persisted to Supabase.
- Observable result: the vybe account exists and is linked. Continuation: the user enters the protected social core. If creation fails, the surface states the failure and preserves the entered details so the user can retry without repeating Spotify sign-in while the Spotify session remains valid.
Flow 2 — New Account Creator: returning verification and resumption
- The returning listener opens Login anonymously. The surface states plainly that vybe sign-in happens through Spotify and that the vybe account is linked to the Spotify account.
- The listener activates "Continue with Spotify". Spotify owns the sign-in interaction.
- Spotify sign-in completes and the listener is verified against their linked vybe account.
- Observable result: the existing vybe account is resumed with its favorites, posts, and friend connections intact. Continuation: the listener enters the protected social core.
- If verification fails or is cancelled, the surface states the failure and keeps the Spotify entry available for immediate retry. If no linked vybe account exists, the listener is directed to Sign Up and continues in Flow 1 from step 5.
Flow 3 — Friend-Feed Listener: keeping up with friends' current listening
- The signed-in listener opens Friends. On desktop this is the asymmetric three-column left rail; at 375px the rail has collapsed into a horizontal snap row of friend avatars under the top bar.
- The listener reads the ruled, hairline-separated list of friends' now-playing entries, with mono timestamps and a pulsing hot-red dot marking live entries.
- The listener selects a friend's now-playing entry.
- Observable result: the song and its 30-second preview are presented, with the waveform component acting as the play state and divider. Continuation: the listener can move to Previews, Friend Favorites, Favorites, Song Post, or Quote Post from here.
- If friend listening data fails to load, the feed states the failure and offers retry; retry reloads the ruled list without leaving the surface. If no friend is currently listening, the feed states that plainly and keeps the entry points to Previews and the composers available.
Page 13 of 21
Flow 4 — Friend-Feed Listener: browsing friends' favorites
- The signed-in listener opens Friend Favorites.
- The listener selects a friend.
- Observable result: that friend's favorite songs, artists, and albums render in grouped ruled lists with mono micro-labels for counts and durations.
- The listener switches between the songs, artists, and albums groupings, and opens a favorite to see its 30-second preview where a preview exists.
- Continuation: the listener returns to Friends or moves to Previews.
- If favorites fail to load, the surface states the failure and offers retry; retry reloads the selected friend's favorites without leaving the surface. If the friend has no favorites recorded, the surface states that plainly.
Flow 5 — Music Sharer: posting a song
- The signed-in Music Sharer opens Song Post.
- The sharer selects a song. The song's 30-second Apple Music preview is resolved and rendered as the post's waveform signature, derived from the actual preview data.
- The sharer previews the 30-second preview and its generated waveform, and confirms the post reads the way they want. If the preview cannot be resolved from Apple Music's public API, the composer states the failure and keeps the draft.
- The sharer publishes the song post.
- Observable result: the post is persisted to Supabase and appears in the friends feed with its waveform signature. Friends, as the materially affected participants, receive the post in their feed and can discover it there.
- Continuation: the sharer can move to Previews to see posted songs, or return to Friends.
- If publishing fails, the composer states the failure and preserves the draft so the sharer can retry without rebuilding the post.
Page 14 of 21
Flow 6 — Music Sharer: posting song lyrics or a quote
- The signed-in Music Sharer opens Quote Post.
- The sharer enters the lyric or quote text.
- The sharer chooses the flat colour ground — hot red or acid lime — with near-black or warm off-white type, checked for contrast.
- The sharer previews the word-by-word kinetic type treatment, with each word landing on scroll at a 28ms stagger and the whole line leaning toward the pointer as a single elastic block.
- The sharer publishes the post.
- Observable result: the post is persisted to Supabase and appears in the friends feed as pure typography on a flat colour block. Friends, as the materially affected participants, receive the post in their feed.
- Continuation: the sharer can move to Previews or return to Friends.
- If publishing fails, the composer states the failure and preserves the draft so the sharer can retry without re-entering the text.
Flow 7 — Music Sharer or Friend-Feed Listener: scrolling 30-second previews
- The signed-in listener opens Previews.
- The listener scrolls vertically. Each post occupies 100dvh in a vertical snap scroll with no card chrome; the poster's handle is rotated 90° flush against the left edge and the mono timestamp is pinned bottom-right.
- The current post's 30-second preview plays, and the waveform scrubber pinned to the bottom edge redraws in real time as the preview plays. The listener can scrub within the preview using the waveform, and pause and resume.
- Observable result: the listener moves through posted songs one snap at a time, each with its own waveform signature derived from its actual preview data.
- Continuation: the listener continues to the next post, or leaves for Friends, Friend Favorites, Favorites, or a composer.
- If a preview cannot be resolved from Apple Music's public API, that post states the failure and the scroll continues to the next post; the snap position is preserved. If no posted songs exist, the destination states that plainly and offers the entry to Song Post.
Flow 8 — Music Sharer or Friend-Feed Listener: managing own favorites
- The signed-in listener opens Favorites and reviews their own favorite songs, artists, and albums in grouped ruled lists.
- The listener enters Edit Favorites.
- The listener adds a favorite song, artist, or album, or edits an existing one, or removes one.
- Observable result: the change is persisted to Supabase and reflected in Favorites.
- Continuation: the listener returns to Favorites to review the result, or opens a favorite's 30-second preview where one exists.
- If a save or removal fails, the workspace states the failure and preserves the in-progress edit so the listener can retry without re-entering it. If the listener has no favorites yet, the workspace presents the add controls directly.
Page 15 of 21
6. Visuals Colors and Theme
The visual direction is Interaction as delight — type and waveform that respond to the thumb, after Yugo Nakamura. The headline idea: motion is the interface, not decoration. Type is set large and treated kinetically, the page is a full-viewport playground with minimal chrome, and the waveform is the universal component — divider, scrubber, play state, and loading indicator.
Palette (dark mode). Near-black ground carries everything; flat colour so motion reads clearly. No gradients, no glass, no blue anywhere.
| Role | Hex | Use |
|---|
| Background | #0B0B0C | Near-black ground for every surface |
| Surface | #151517 | Panels |
| Hairline | #26262A | 1px structural rules |
| Text | #F4F2ED | Warm off-white for all reading text (17:1 on the ground) |
| Primary | #FF3D2E | Hot red: play buttons, the live "now playing" pulse, the active rail segment |
| Accent | #C8FF3D | Acid lime: interaction accent only — cursor/thumb-following highlight, hover state, scrubber fill |
| Muted | #8A8880 | Timestamps, secondary labels, inactive tabs (5.2:1, readable) |
Hot red and acid lime are never both applied to one element.
Typography. One family, two behaviours.
- Headings: Space Grotesk 500–700, tight tracking (-0.03em), sentence case, set enormous — display sizes are the image, stacked in 2–3 flush-left lines that fill the viewport width.
- Body/UI: Space Grotesk 400–500 at 15–17px with generous 1.55 leading.
- Numerals and all data (timestamps, durations, friend counts, "0:24"): JetBrains Mono 500 uppercase micro-labels at 11px with 0.12em tracking — the machine voice under the kinetic type.
- Scale: 1.5 modular on a 4/8pt rhythm. Display
clamp(52px, 9.5vw, 132px) / 40px mobile for the hero wordmark; H1 clamp(34px, 5vw, 64px); H2 clamp(24px, 3vw, 38px); body 15px mobile → 17px desktop; micro-label 11px mono. Line-height 0.94 for display, 1.55 for body.
Shape language. Hard-edged and flat — 0–6px radii, no pills, no blobs, no soft shadows. Structure comes from 1px hairlines (#26262A), full-bleed colour blocks, and overlapping type, not from cards. The one organic shape in the system is the waveform itself: a real, generated amplitude shape (bars of varying height, 2px wide, 2px gap) used as divider, scrubber, play state, and loading indicator. Buttons are solid rectangles with the label flush-left inside them.
Layout. Full-viewport playgrounds, minimal chrome. The feed is a vertical snap scroll (one post per 100dvh) with the waveform scrubber pinned to the bottom edge and the poster's handle rotated 90° along the left edge. Desktop is an asymmetric 12-column grid with a 3-column left rail (friends' now-playing, live) that never becomes a card grid — it is a ruled list with mono timestamps. Everything is flush-left, ragged-right; no centred hero, no centred cards. At 375px the rail collapses into a horizontal snap row of friend avatars under the top bar, and all display type wraps rather than scaling off-screen.
Imagery. No stock photography of people. The imagery is the music's own surface: album art cropped hard and bled off two edges at 40–60% opacity behind the type, then a solid #0B0B0C block over the lower third where the readable text sits. Lyric and quote posts are pure typography on a flat colour block (#FF3D2E or #C8FF3D ground, #0B0B0C or #F4F2ED type — checked for contrast). The generative element is the waveform, derived from the actual 30-second Apple Music preview data, so every post's visual signature is genuinely its own song.
Readable text and controls stay whole at every viewport. Headlines, wordmarks, labels, numbers, and controls stay entirely inside the viewport and their container at 375px, 768px, and 1280px, wrapping or scaling to fit, and no other element covers any part of them. Imagery, decoration, and motion may be cropped, bled off an edge, rotated, overlapped, or cut exactly as the direction asks, as long as they cover no readable text or control. Moving and scrollable content may cross the viewport or container edge by design; every item becomes fully readable as it passes. With prefers-reduced-motion it stops and shows whole items, wrapping into rows or sitting in a horizontally scrollable row.
Page 16 of 21
7. Signature Design Concept
The public entry is a full-bleed near-black viewport with no centred stack — a playground, not a landing page.
A single line of Space Grotesk at clamp(52px, 9.5vw, 132px) reads "HEAR WHAT YOUR FRIENDS HEAR", set flush-left, filling roughly nine of twelve columns and running off the right edge of the viewport at desktop. The last word is intentionally cropped by the frame as decoration only; a shorter, fully visible subline sits beneath it and carries the meaning. Behind and through the type, a live waveform of the currently featured 30-second Apple Music preview animates across the full width in #C8FF3D, its bars leaning toward the pointer with spring damping, capped at ~8px displacement.
Bottom-left: a solid #FF3D2E rectangle button reading "Continue with Spotify", label flush-left, with a 1px #F4F2ED hairline offset 4px down-right as its shadow. Bottom-right: the mono micro-label "30-SEC PREVIEWS · APPLE MUSIC · SUPABASE" at 11px with 0.12em tracking.
Nothing is centred, nothing floats, nothing glows. The concept recomposes only accepted content and controls: the anonymous first impression, the live featured preview, and the Spotify entry that begins the accepted sign-in journey.
8. Interaction Model & Motion Direction
Interaction Model: Animated
Motion Tempo: cinematic
Hero Dimensionality: layered_2d
Page 17 of 21
Landing Hero Motion Brief
- Focal subject: the live waveform of the currently featured 30-second Apple Music preview, running full width behind and through the oversized flush-left headline.
- Input → transformation → outcome thesis: as the pointer or thumb moves across the hero, the nearest waveform bars lean and brighten toward it in
#C8FF3D with spring damping, capped at ~8px displacement; the waveform simultaneously redraws in real time as the featured preview plays. The outcome is a first frame that is already alive before any tap — the visitor feels the interface respond to them, which is the product's own promise about sound and friends moving.
- Motion vocabulary: one purposeful continuous loop (the featured preview's waveform redrawing in real time), plus direct manipulation (pointer/thumb-reactive bar lean with spring damping). Type reveals word-by-word on scroll into view at a 28ms stagger and 240ms per word, with no bounce. Post transitions in the feed are a snap, not a fade.
- Composed first frame: near-black
#0B0B0C ground; the headline set enormous and flush-left, its last word cropped by the frame as decoration only; the acid-lime waveform crossing the full width behind the type; the hot-red "Continue with Spotify" rectangle bottom-left with its offset hairline shadow; the mono micro-label bottom-right. No centred stack, no card, no glow.
- Reduced-motion state: waveforms become static amplitude bars, the pointer trail disappears, and word reveals become instant. All readable text and controls remain whole and fully visible.
Page 18 of 21
9. Non-Functional Requirements
NFR-1 — Cross-platform delivery (explicit)
vybe must be built with React Native Expo and delivered on iOS, Android, and Web. Rationale: this is an explicit hard constraint in the authoritative user evidence.
NFR-2 — Spotify-anchored identity (explicit)
Sign-in must use Spotify, and the vybe account must be created based on the Spotify account. Rationale: explicit hard constraint.
NFR-3 — Apple Music preview source (explicit)
The 30-second previews must come from Apple Music's public API. Rationale: explicit hard constraint.
NFR-4 — Supabase database (explicit)
The database must be Supabase. Rationale: explicit hard constraint.
NFR-5 — Readable text and controls at every viewport (explicit)
Headlines, wordmarks, labels, numbers, and controls must stay entirely inside the viewport and their container at 375px, 768px, and 1280px, wrapping or scaling to fit, with no other element covering any part of them. Rationale: explicit direction constraint that takes precedence over any cropping gesture for readable text and controls.
NFR-6 — Reduced-motion compliance (explicit)
All motion must respect prefers-reduced-motion: waveforms become static amplitude bars, the pointer trail disappears, and word reveals become instant. Moving and scrollable content stops and shows whole items. Rationale: explicit direction constraint.
NFR-7 — Contrast (explicit)
Warm off-white #F4F2ED on the #0B0B0C ground reads at 17:1; muted #8A8880 reads at 5.2:1 and is reserved for timestamps, secondary labels, and inactive tabs. Lyric and quote colour grounds are checked for contrast. Rationale: explicit direction constraint.
NFR-8 — Palette discipline (explicit)
No blue or indigo anywhere. Hot red #FF3D2E and acid lime #C8FF3D are never both applied to one element. No gradients, no glassmorphism, no frosted panels, no soft multicolour gradients. Rationale: explicit direction constraint.
NFR-9 — Typography discipline (explicit)
Space Grotesk for headings and body/UI; JetBrains Mono 500 uppercase at 11px with 0.12em tracking for numerals and all data. Inter, Roboto, Arial, Helvetica, Open Sans, Lato, Poppins, and system-ui are excluded for any text. Rationale: explicit direction constraint.
NFR-10 — Persistence integrity (required_inference)
vybe accounts, favorites, posts, and friend-centered listening data must persist in Supabase and remain bound to the correct vybe account. Rationale: required to make the accepted account, favorites, posting, and friend-listening journeys durable and correctly owned.
NFR-11 — Preview failure isolation (required_inference)
A failure to resolve a preview from Apple Music's public API must not block the surrounding surface: the affected item states the failure, and the user can retry or continue. Rationale: required to keep the accepted previews scroll and composers usable when an external provider fails.
Page 19 of 21
10. Tech Stack
- Client: React Native Expo, targeting iOS, Android, and Web. (explicit)
- Identity provider: Spotify sign-in. (explicit)
- Preview content provider: Apple Music public API for 30-second previews. (explicit)
- Database: Supabase. (explicit)
- Typography: Space Grotesk (headings, body/UI) and JetBrains Mono (numerals and data micro-labels). (explicit direction)
Page 20 of 21
11. Assumptions and Constraints
Assumptions
- A1 — The visitor who reaches Landing has not yet signed in with Spotify, and Landing exposes no protected state. (required_inference)
- A2 — Spotify sign-in returns an identity that vybe can resolve and link a vybe account to. (required_inference)
- A3 — Apple Music's public API returns a 30-second preview for a posted song where a preview exists; where none exists, the affected surface states that plainly. (required_inference)
- A4 — Friends are established relationships within vybe; the current scope does not include a friend-request or friend-discovery capability. (required_inference, narrow)
- A5 — The waveform is derived from the actual 30-second preview data, so a post without a resolvable preview renders a static or flat waveform rather than a fabricated one. (required_inference)
Constraints
- C1 — Sign-in must use Spotify; the vybe account is created based on the Spotify account. (explicit)
- C2 — 30-second previews must come from Apple Music's public API. (explicit)
- C3 — The database must be Supabase. (explicit)
- C4 — The app must be built with React Native Expo and target iOS, Android, and Web. (explicit)
- C5 — Spotify sign-in must complete before vybe account creation. (required_inference)
- C6 — The vybe account must be created and linked to the signed-in Spotify account before protected social features are available. (required_inference)
- C7 — No blue or indigo; hot red and acid lime are never both applied to one element. (explicit direction)
- C8 — Readable text and controls stay whole at 375px, 768px, and 1280px; this takes precedence over any cropping gesture. (explicit direction)
- C9 — No stock photography of people, no illustration-led hero, no decorative 3D objects, no confetti or particle fields. (explicit direction)
- C10 — No differentiated permission tiers or role-based visibility over shared product state is established in the current scope; access is uniform across signed-in users. (required_inference, narrow)
Page 21 of 21
12. Glossary
- vybe account — The application-owned account created based on the signed-in Spotify account and linked to it. Required before protected social features are available.
- Spotify sign-in — The external identity interaction that establishes the Spotify identity vybe links a vybe account to.
- 30-second preview — The song preview supplied by Apple Music's public API and rendered as the waveform signature of a post.
- Waveform — The generated amplitude shape (bars 2px wide with 2px gaps) derived from the actual 30-second preview data. It doubles as divider, scrubber, play/pause state, and loading indicator across the app.
- Now-playing entry — A friend's current listening item shown in the Friends ruled list with a mono timestamp and a pulsing hot-red dot when live.
- Song post — A post containing a song, published to the friends feed with its waveform signature.
- Quote post — A post containing song lyrics or a quote, set as pure typography on a flat colour block.
- Previews — The TikTok-style vertical snap scroll destination for 30-second previews of posted songs, one post per 100dvh.
- Friends feed — The friend-centered activity surface where friends' now-playing entries and posted songs appear.
- Micro-label — JetBrains Mono 500 uppercase text at 11px with 0.12em tracking, used for timestamps, durations, counts, and status.
No comments yet. Be the first!