// Audience config: fia (jas's girlfriend, non-technical).
// Voice: jeffrey-pvc (default in /api/say). Style: lowercase, warm, ends in a rhyme.
//
// `narration` is the verbatim text POSTed to /api/say.
// `segments` anchor each slide to a phrase in the narration; whisper word-level
// timestamps determine real durations. The marker is matched case-insensitively
// against the transcript with punctuation stripped, so it must appear in the
// audio (not be a paraphrase of it).
export const PALETTE = {
bg: "#201040",
accent: "#ff69b4",
cyan: "#70f0e0",
lime: "#a0f070",
magenta: "#ff70d0",
yellow: "#ffd860",
cream: "#fcf7c5",
off: "#ffffffcc",
dim: "#9080c0",
};
export const audience = {
name: "fia",
handle: "@fifi",
voice: { provider: "jeffrey", voice: "neutral:0" },
// Narration as one paragraph for clean TTS. Lowercase house-voice for jas.
// The voice says "fifi" (her handle, sans @ — easier to pronounce) instead
// of the nickname "fi", since she goes by @fifi on AC.
narration: `hey fifi, here's the last two days at the keyboard for you. the big one — notepat finally has a little remote that lives inside ableton, so when i'm playing, anyone can pop a tiny keyboard panel right into their session. the keys glow in piano colors, octaves stack, and the whole thing feels like a real instrument now. the multiplayer arena got dressed up too — a minimap in the top right, plain english labels instead of jargon, and every spectator gets their own quiet color. the camera piece, the one we call cap, learned to hold-to-record like baktok, so a tap doesn't startle it anymore. on the side, i wrote a little paper for parag about why audio feels late on linux — mostly love letters to interrupts — retranslated sucking on the complex into spanish, danish, chinese, and japanese, and rebuilt the menubar slab in proper swift so the mail submenu actually works. and through it all the oven kept its rhythm, baking pdfs in the background. fifi, you make the keystrokes kinder — every quiet line of code is a little you-reminder.`,
// Each slide is anchored to a phrase that appears in the narration.
// align.mjs finds the phrase in the whisper transcript and uses the start
// timestamp of its first word as the slide start. The slide ends when the
// next slide starts (or at audio end + trailingSilenceSec for the last).
// Whisper substitutions for the displayed subtitle text. Match is
// case-insensitive; replacement is verbatim. Use these to fix word forms
// that whisper renders dictionary-style ("Notepad" for the AC piece
// "notepat", "menu bar" → "menubar", etc.) or to correct mishears.
transcriptFixes: {
"Notepad": "notepat",
"mini-map": "minimap",
"Backtalk": "baktok",
"menu bar": "menubar",
"sub-menu": "submenu",
"laid on Linux": "late on Linux",
"you reminder": "you-reminder",
"CAP": "cap",
},
segments: [
{ name: "01_title", marker: "hey fifi" },
{ name: "02_notepat", marker: "the big one" },
{ name: "03_arena", marker: "the multiplayer arena" },
{ name: "04_cap", marker: "the camera piece" },
{ name: "05_paper", marker: "i wrote a little paper" },
{ name: "06_translations", marker: "retranslated" },
{ name: "07_slab", marker: "rebuilt the" },
{ name: "08_oven", marker: "and through it all" },
{ name: "09_outro", marker: "fifi you make" },
// End card runs after the audio ends; pipeline pads the audio with silence.
{ name: "10_end", marker: "__END__", trailingSilenceSec: 3 },
],
// Each slide's HTML body. Rendered into a 1080x1920 frame by slides.mjs.
// Use ${PALETTE.x} colors. CSS in slides.mjs handles font fallback.
slides: {
"01_title": `
aesthetic computer
@fifi
last 48 hours @ the keyboard
2026·04·24 → 2026·04·25
`,
"02_notepat": {
queries: {
icon: { glob: "ac-electron/build/icon.png" },
paper: { glob: "system/public/papers.aesthetic.computer/notepat-26-arxiv-cards.pdf", pdfPage: 1, pdfWidth: 600 },
// Match commits whose subject *starts with* notepat-related prefix so
// we don't pick up unrelated commits that mention notepat in passing.
commits: { commits: "^notepat|^build-notepat", since: "48 hours ago", limit: 5 },
},
body: ({ icon, paper, commits }) => `
01 / 08 · notepat
${icon ? `

` : ""}
notepat × ableton
a little remote that lives inside your DAW.
piano colors, stacked octaves, square pads.
${(commits || []).map((c) => `
${c.hash.slice(0, 4)}${(c.subject.split(":").slice(1).join(":").trim() || c.subject).slice(0, 56)}
`).join("")}
${paper ? `

` : ""}
"feels like a real instrument now."
`,
},
"03_arena": `
02 / 08 · arena
arena, dressed up
minimap, top-right.
plain english instead of jargon.
every spectator gets their own quiet color.
dfa8minimap top-right + plain-English HUD
2fedcool per-handle specColor + 'specs' label
06dafix UDP snap drops + telemetry
`,
"04_cap": `
03 / 08 · cap
hold to record
the camera piece learned baktok manners.
a tap doesn't startle it anymore.
6839cap + video: hold-to-record (BakTok-style)
a6b8slide-up-to-zoom while holding record
6f54portrait-native camera + drawn mic glyph
`,
"05_paper": `
04 / 08 · papers
a paper for parag
why audio feels late on linux —
mostly love letters to interrupts.
arxiv-latency
IRQ + audio/input latency analysis
7-phase commit archaeology
`,
"06_translations": {
queries: {
es: { glob: "system/public/papers.aesthetic.computer/sucking-on-the-complex-26-arxiv-es.pdf", pdfPage: 1, pdfWidth: 400 },
da: { glob: "system/public/papers.aesthetic.computer/sucking-on-the-complex-26-arxiv-da.pdf", pdfPage: 1, pdfWidth: 400 },
zh: { glob: "system/public/papers.aesthetic.computer/sucking-on-the-complex-26-arxiv-zh.pdf", pdfPage: 1, pdfWidth: 400 },
ja: { glob: "system/public/papers.aesthetic.computer/sucking-on-the-complex-26-arxiv-ja.pdf", pdfPage: 1, pdfWidth: 400 },
},
body: ({ es, da, zh, ja }) => `
05 / 08 · translations
sucking on the complex
${[["es", "español", PALETTE.cyan, es], ["da", "dansk", PALETTE.lime, da], ["zh", "中文", PALETTE.yellow, zh], ["ja", "日本語", PALETTE.accent, ja]].map(([code, label, color, src]) => `
${src ? `

` : `
`}
${code} ${label}
`).join("")}
reframed as engine, not adversary.
`,
},
"07_slab": `
06 / 08 · slab
menubar in swift
native appkit rewrite.
sf-symbol icons, passphrase modal,
mail submenu wired to mbsync + mu.
826dnative appkit rewrite with sf-symbol icons
585dNotification hook fades ambient + TTS
`,
"08_oven": {
queries: {
ovenCommits: { commits: "oven", since: "48 hours ago", limit: 6 },
recentPdfs: { files: "system/public/papers.aesthetic.computer/*.pdf", sinceHours: 48, limit: 60 },
},
body: ({ ovenCommits, recentPdfs }) => {
// Dedupe by paper stem (drop -26-arxiv-{cards,da,es,zh,ja}.pdf) so
// the chip strip lists distinct papers, not translation duplicates.
const stems = new Set();
for (const p of recentPdfs || []) {
stems.add(p.split("/").pop().replace(/-26-arxiv(-cards|-da|-es|-zh|-ja)?\.pdf$/, ""));
}
const distinct = [...stems];
return `
07 / 08 · oven
the oven, baking
pdfs compiled while we sleep —
${distinct.length} distinct papers refreshed,
${(recentPdfs || []).length} files in 48 hrs.
${(ovenCommits || []).slice(0, 4).map((c) => `
${c.hash.slice(0, 4)} ${c.subject.replace(/^\[?papers\]?[\s:]*/i, "").slice(0, 60)}
`).join("")}
${distinct.slice(0, 12).map((s) => `
${s.replace(/-/g, " ")}
`).join("")}
`;
},
},
"09_outro": `
08 / 08 · outro
@fifi, you make the
keystrokes kinder —
every quiet line of code
is a little you-reminder.
`,
"10_end": `
aesthetic·computer
narrated by jeffrey-pvc · @jeffrey
made with love · 2026·04·25
`,
},
};
export default audience;