diff --git a/marketing/podcast/bin/cover.mjs b/marketing/podcast/bin/cover.mjs --- a/marketing/podcast/bin/cover.mjs +++ b/marketing/podcast/bin/cover.mjs @@ -10,13 +10,14 @@ // Usage: // import { renderCover } from "./cover.mjs" // renderCover({ title, author, date, slug }, outDir) → { full, embed } -import { writeFileSync, mkdirSync, rmSync, existsSync } from "node:fs"; +import { writeFileSync, mkdirSync, rmSync, existsSync, readdirSync } from "node:fs"; import { resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { execFileSync } from "node:child_process"; const HERE = dirname(fileURLToPath(import.meta.url)); const REPO = resolve(HERE, "..", "..", ".."); // repo root (absolute) +const PALS = resolve(HERE, "..", "out", "pals"); // generated PALS logos const FONTS = resolve(REPO, "system/public/type/webfonts") + "/"; const MONO = resolve(REPO, "bills/invoices") + "/"; @@ -87,8 +88,39 @@ \end{document} `; } +// Every AC Readings cover is a generated PALS logo (the paper-doll trio) — +// picked deterministically from the tray by slug, so each episode gets its own +// distinct material (felt / glass / chrome / …) but the same one every re-run. +// Hi-res .x4 preferred. Falls back to the typographic card if the tray is empty. +function pickPals(slug) { + let files = []; + try { + files = readdirSync(PALS) + .filter((f) => f.endsWith(".png") && !f.includes("contact") && !f.includes(".x4.")) + .sort(); + } catch { return null; } + if (!files.length) return null; + let h = 2166136261; + for (const ch of slug) h = (h ^ ch.charCodeAt(0)) * 16777619 >>> 0; + const name = files[h % files.length].replace(/\.png$/, ""); + const x4 = resolve(PALS, `${name}.x4.png`); + return existsSync(x4) ? x4 : resolve(PALS, `${name}.png`); +} + export function renderCover(script, outDir) { mkdirSync(outDir, { recursive: true }); + const full = resolve(outDir, `${script.slug}-cover.png`); // ~3000px, archival + const embed = resolve(outDir, `${script.slug}-cover-1400.png`); // podcast art + + // PALS-logo cover (the house style for every episode) + const pals = pickPals(script.slug); + if (pals) { + execFileSync("magick", [pals, "-resize", "3000x3000", full], { stdio: "ignore" }); + execFileSync("magick", [pals, "-resize", "1400x1400", embed], { stdio: "ignore" }); + return { full, embed }; + } + + // fallback: the typographic title card (xelatex) if no PALS tray is present const build = resolve(outDir, `.cover-build-${script.slug}`); mkdirSync(build, { recursive: true }); const tex = resolve(build, "cover.tex"); @@ -100,8 +132,6 @@ }); const pdf = resolve(build, "cover.pdf"); if (!existsSync(pdf)) throw new Error("cover xelatex produced no pdf"); - const full = resolve(outDir, `${script.slug}-cover.png`); // ~3000px, archival - const embed = resolve(outDir, `${script.slug}-cover-1400.png`); // podcast art execFileSync("mutool", ["draw", "-o", full, "-r", "500", pdf, "1"], { stdio: "ignore" }); execFileSync("ffmpeg", ["-y", "-i", full, "-vf", "scale=1400:1400", embed], { stdio: "ignore" }); diff --git a/marketing/podcast/weekend-2026-07-13.md b/marketing/podcast/weekend-2026-07-13.md new file mode 100644 --- /dev/null +++ b/marketing/podcast/weekend-2026-07-13.md @@ -0,0 +1,21 @@ +--- +title: "Weekend Build Log — a juke, a bag of pads, and a launch" +author: "@jeffrey" +date: 2026-07-13 +--- + +This was a weekend spent close to the machine. No single giant announcement to point at — well, one, but I'll get there — mostly a lot of small rooms getting furnished. Let me walk you through the house. + +It started with the juke. There's a little app called JukeWizard that holds the whole pop catalog — every track I've been making, released and unreleased, over a hundred of them now. All weekend it slowly turned from a plain list into something you'd actually want to open. First it learned to sort, newest rendered on top, so I can see what I made last. Then it started showing the album art, with little buttons to open each song on Spotify or Apple or YouTube. Then, because a juke should look like a juke, I gave it a compact disc for an icon — a real shiny translucent one, not a rainbow sticker — and I put that disc up in the menu bar, where it spins while a song plays, faster or slower to match the track's tempo. And then the whole window got a Winamp-style redesign: playback up top with the album art big, or the music video streaming right there if the song's been released, and the track list underneath, every row dressed in its own color. By Sunday it was running on two machines at once. + +While that was happening, a new idea got a name. Pads. In the prompt you type a caret and a word, ^pads, and you get a bag — a curated little container of pieces. The pads themselves are instruments you play by tapping and dragging, and each one is a marriage: a visual generator crossed with a synth voice. A reaction-diffusion pattern that sounds like a bell. An L-system fern that plays a flute. Lightning wired to a zap, caustics to a steel pan, a polyrhythm clock to a drum. By the end of the weekend there were forty-seven of them, all sharing one engine, all holding sixty frames a second on the little native machine, because they learned to watch their own performance and back off when they got greedy. + +There were reels, too. Short audiovisual pieces that run themselves, synced to real synth audio, drawing as they sound. Prism, lull, emberdrift, molten, lavabath, bloomwell. And a set of button instruments that keep time against the actual clock, so two of them started in two different rooms stay in step. + +The one thing I can actually point at: menuband shipped. Version one-five-three is live on the Mac App Store. The App Store is the front door now; the direct download moved to a back room called advanced. It took a couple of rejections and a dropped Bluetooth permission to get there, but it's out. + +Then there's whistlegraph dot org, which had a strange and wonderful weekend. Fifteen hundred old videos came out of hiding — clips that had been private for years — and folding them back in brought the song count from around two-sixty to six hundred. The hard part was the un-merging: some songs had been glued together across video bridges, and teaching the site to split them cleanly, each anchored to its own seed, took most of a day. + +And under all of it, the plumbing. The memory system learned to search my whole prompt history across the fleet, right from a menu. The released music finally all lives on our own network now — the covers, the audio, the little canvas videos — nothing borrowed. There's a tool that drops a file onto my phone with zero taps. The desktop app answers to its own web address. Little pipes, but they're the ones you feel every day. + +That's the weekend. A juke you want to open, a bag of forty-seven instruments, a launch, six hundred songs pulled out of the dark, and a lot of quiet plumbing. Back to it.