55 lines
3.4 KiB
Markdown
55 lines
3.4 KiB
Markdown
|
|
# 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](https://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:**
|
||
|
|
```bash
|
||
|
|
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.
|