# marketing/podcast — essays → jeffrey-voiced readings
A production lane that turns written essays (`papers/essay-*/*.tex`, `opinion/*.md`)
into spoken-word podcast episodes in @jeffrey's ElevenLabs voice, framed like a
liturgical reading.
## The shape of an episode
```
[intro jingle] → "A reading of the essay:
, by @jeffrey.
Approximately minutes." → [the essay, read
paragraph by paragraph with breath between] →
"Here ends the reading." → [outro jingle]
```
The framing is deliberately churchy — a *reading of the essay*, an announced
length, a fixed closing ("here ends the reading") — so the catalog feels like a
lectionary of AC writing rather than a talk show.
## Voice
ElevenLabs **jeffrey-pvc** via the production `/api/say` proxy — the same voice as
the pop lane and the 24h recap (`provider="jeffrey"`, `voice="neutral:0"`).
Stability held ≥ 0.5 to keep identity intact. Synthesis costs real money but is
content-hash cached (`out/cache/`), so re-runs are free.
## Pipeline (all in `bin/`)
1. **`essay-to-script.mjs`** — strips LaTeX/Markdown to clean spoken prose.
Drops footnotes, section headings, colophon, URLs; keeps the argument. Emits
`{ title, author, date, paragraphs[], wordCount }`.
2. **`jingle.mjs`** — synthesizes `intro.wav` / `outro.wav`: a short pentatonic
bell motif (ascending in, resolving out). Deterministic, $0, no samples.
3. **`cover.mjs`** — one canonical PALS-mark cover identity for the series and
every episode (`system/public/purple-pals.svg`). Episode titles live in
metadata rather than being expressed as substitute/generated logo variants.
The cover is embedded as ID3 album art and kept as `out/-cover.png`.
4. **`produce.mjs`** — the orchestrator. Narrates intro + each paragraph + outro
via `/api/say`, measures the real body duration with ffprobe to fill in the
announced length, assembles jingle + VO + paragraph breaths with ffmpeg
(loudnorm → mp3), embeds the cover, and writes a metadata sidecar
`out/.json`. Output: `out/.mp3`.
5. **`feed.mjs`** — aggregates the sidecars into `out/index.json` (catalog) +
`out/feed.xml` (RSS 2.0 + iTunes), and renders the series cover `out/cover.png`.
Filtered by the shared publish allowlist `lib/hosted.mjs`.
6. **`ship.mjs`** — the one-command publish: guardrail (allowlist) → Buzzsprout
→ CDN (mp3 + cover under the hosted name, which backs the papers podcast
link) → feed regen → verify. `--papers` also runs papers deploy+index;
`--private` stages on Buzzsprout. Stops before git (prints the finish block).
7. **`publish.mjs`** *(legacy)* — stages `publish/` + syncs the self-hosted CDN
feed. Superseded by `ship.mjs` + Buzzsprout; kept for the retired RSS path.
**Allowlist:** `lib/hosted.mjs` maps each cleared `slug → siteName` and is the
single source of truth for what may publish. A slug absent from it never goes
public — `ship.mjs` refuses it and `feed.mjs` drops it.
## Feed / hosting
**Canonical podcast URL: `https://pod.prompt.ac`** — Buzzsprout custom domain
(CNAME `pod.prompt.ac → app.buzzsprout.com`, DNS-only, in the prompt.ac
Cloudflare zone). `https://podcast.aesthetic.computer` 301-redirects there
(proxied CNAME + redirect rule in the aesthetic.computer zone). The
subscribable RSS is Buzzsprout's: `https://feeds.buzzsprout.com/2628235.rss`.
Legacy self-hosted feed (pre-Buzzsprout): DO Spaces
(`assets-aesthetic-computer`) at `https://assets.aesthetic.computer/podcast/`,
feed at `/podcast/feed.xml`, pushed with `publish.mjs --push`. **Retired as a
subscription target** — it was never submitted to directories and shouldn't
be; Buzzsprout is the distribution path.
## Usage
```bash
cd marketing/podcast
node bin/produce.mjs ../../papers/essay-/.tex --open # → out/.mp3
node bin/ship.mjs # publish: Buzzsprout + CDN + feed + verify
node bin/ship.mjs --papers # also deploy the papers PDF + index
# then commit the episode's files + `fish lith/deploy.fish` (ship prints the block)
```
Legacy self-hosted feed: `node bin/feed.mjs && node bin/publish.mjs --push`.
Flags: `--open` (slab-afplay the result), `--force` (bypass say cache),
`--stability 0.55 --similarity 0.8 --speed 0.98` (voice tuning),
`--base ` on `feed.mjs` (override the asset host).
## Reused from /pop
- `/api/say` invocation pattern + content-hash caching — lifted from `pop/bin/say.mjs`.
- Jingle synthesis follows the pop DSP posture (phase-increment sines, exp-decay
bells) but is self-contained here.