pay2play/CLAUDE.md
Ole-Morten Duesund 96b1ecf7e6 Initial commit: Pay2Play! satirical music player
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>
2026-03-17 16:54:31 +01:00

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 tags
  • style.css — animations, range input styling, hover/focus/active states
  • app.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 (has gen, wave, bpm fields) or MP3-based (has url field). 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:

  1. Procedural (default): Tone.js synth loops driven by each song's gen() callback. No audio files needed.
  2. MP3: When a song has a url property, HTML5 Audio is 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[] with gen(synth, time) callback, wave type, bpm, duration, and color.
  • MP3: Put file in public/audio/, add entry with url: "/audio/filename.mp3" and duration (in seconds). Use ffprobe to get duration.