Paywalled music player where every feature costs money — pause, resume, skip, volume, even closing the app. Built with React 18 and Tone.js via CDN, zero build step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
Pay2Play! is a satirical music player where every interaction is paywalled. It's part of donothireus.com. The humor comes from absurd micro-charges for basic actions (pause, resume, volume, skip, etc.).
Development
There is no build step, no package manager, and no dependencies to install. A static file server is required (Babel standalone fetches app.js via XHR).
Run locally:
cd public/ && python3 -m http.server 8080
Any static file server works (Caddy, nginx, etc.).
Architecture
The app is split across three files in public/:
index.html— HTML shell with CDN script tags and meta/OG tagsstyle.css— animations, range input styling, hover/focus/active statesapp.js— all React components and logic (JSX compiled in-browser by Babel standalone)
CDN dependencies (no local install):
- React 18 + ReactDOM (production UMD builds)
- Tone.js 14.8 (procedural synth audio)
- Babel standalone 7.26 (in-browser JSX → JS)
Key data structures:
SONGS[]— track definitions. Each song is either procedural (hasgen,wave,bpmfields) or MP3-based (hasurlfield). The two modes use different playback engines.SUBS{}— defines every paywalled feature (pause,resume,skip,volume,lyrics, etc.) with subscription price, one-time micro-transaction price, and description.LYRICS_DATA[][]— word arrays per song, shown redacted (every 3rd word visible) unless the user pays for the lyrics subscription.AD_COPY[]— rotating fake ad strings shown during the unskippable exit countdown.
Audio playback has two modes:
- Procedural (default): Tone.js synth loops driven by each song's
gen()callback. No audio files needed. - MP3: When a song has a
urlproperty, HTML5Audiois used instead. Songs can mix modes.
Core component: PayPlay is the single top-level React component containing all state and logic. Sub-components are WelcomeBanner (onboarding overlay), Modal (3-phase paywall: choose/insufficient/success), ExitAd (unskippable countdown with rotating ad copy), and CBtn (icon button with aria-label).
Paywall flow: User clicks a feature → tryAct(key, fn) checks if subscribed → if not, opens Modal → user chooses subscribe (full price) or one-time micro-payment → balance is deducted with cha-ching sound → success celebration → action executes. If insufficient funds, the modal stays open with a top-up button. The 3-second free listening limit is enforced via a useEffect watching prog, with audio degradation at 2s and a visual countdown badge.
Theme toggling: The "Dark Mode" button is a joke — paying for it toggles the app to a painfully bright light mode. All colors are derived from bright state via local variables (bg, card, text, muted, accent), so the theme affects the entire player.
Deployment
Serve the public/ directory. See README.md for Caddy config examples, including subpath mounting at /payplay.
Adding songs
- Procedural: Add entry to
SONGS[]withgen(synth, time)callback,wavetype,bpm,duration, andcolor. - MP3: Put file in
public/audio/, add entry withurl: "/audio/filename.mp3"andduration(in seconds). Useffprobeto get duration.