diff --git a/spec/instagram-reel-app-spec.mjs b/spec/instagram-reel-app-spec.mjs index df143b15ba..6b3e0b9bf9 100644 --- a/spec/instagram-reel-app-spec.mjs +++ b/spec/instagram-reel-app-spec.mjs @@ -30,11 +30,12 @@ describe("Instagram Reel apps", () => { it("writes short account-specific captions", () => { const whistle = whistlegraphCaption({ desc: "hello #old https://example.com", works: ["w0w"] }, "play", REEL_APPS.whistlegraph.tags); - const aesthetic = aestheticCaption(REEL_APPS.aesthetic.recipes[0], REEL_APPS.aesthetic.tags); + const aesthetic = aestheticCaption(REEL_APPS.aesthetic.recipes[0]); expect(cleanCaption("hello #old https://example.com")).toBe("hello"); expect(whistle).toContain("aesthetic.computer/whistlegraph"); expect(whistle).not.toContain("#old"); - expect(aesthetic).toContain("aesthetic.computer/notepat"); + expect(aesthetic).toBe("notepat"); + expect(aestheticCaption({ piece: "*wibe" })).toBe("*wibe"); expect(whistle.length).toBeLessThan(2200); expect(aesthetic.length).toBeLessThan(2200); }); diff --git a/toolchain/instagram/reel-app-config.mjs b/toolchain/instagram/reel-app-config.mjs index fd006e0501..29a075bdaf 100644 --- a/toolchain/instagram/reel-app-config.mjs +++ b/toolchain/instagram/reel-app-config.mjs @@ -17,7 +17,9 @@ export const REEL_APPS = { slotsPerDay: 1, // 60 because the shared media gate wants reels authored at 60fps, and the // CDP screencast delivers ~60 anyway (30 dropped every other frame). - capture: { width: 1080, height: 1920, fps: 60 }, + // density 2 = each AC pixel is 2×2 video pixels (540×960 of piece); + // capture-av's default 3 read too chunky. + capture: { width: 1080, height: 1920, fps: 60, density: 2 }, // The piece alone: no pals side stamps or title columns, and a cursor // small enough to read as a pointer rather than a mascot. stamp: { chrome: "none", cursorSize: 56 }, @@ -44,10 +46,11 @@ export const REEL_APPS = { }, { // The most-hit stored clock (110 hits on /api/store-clock, 2026-09-23): - // four saw voices; the lead loops every ~7.75 s, so 16 s is two loops. + // four saw voices; the lead loops every ~7.75 s, so 24 s is three + // loops. Lane rule: whole loops landing in 20–30 s. id: "clock-wibe", piece: "*wibe", - duration: 16, + duration: 24, title: "clock", segment: "code", line: "The most-played clock on aesthetic.computer: four saw voices, one tiny score.", @@ -112,7 +115,9 @@ export function whistlegraphCaption(post, segment, tags) { return [opening, "", action, "", tags.map((tag) => `#${tag}`).join(" ")].join("\n"); } -export function aestheticCaption(recipe, tags) { - return [recipe.line, "", `Play it — aesthetic.computer/${recipe.title}`, "", - tags.map((tag) => `#${tag}`).join(" ")].join("\n"); +// The caption is the prompt and nothing else: exactly what you'd type into +// aesthetic.computer to get what the reel shows (`*wibe`, `notepat`). No +// link, no hashtags, no line — the prompt is the whole invitation. +export function aestheticCaption(recipe) { + return recipe.prompt || recipe.piece; } diff --git a/toolchain/instagram/reel-app.mjs b/toolchain/instagram/reel-app.mjs index f5a412632f..0bfa60b8f4 100644 --- a/toolchain/instagram/reel-app.mjs +++ b/toolchain/instagram/reel-app.mjs @@ -165,7 +165,8 @@ async function buildAesthetic({ config, day, index, slot, dir, source }) { const captureArgs = [CAPTURE_AV, source.piece, "--duration", String(source.duration), "--slug", source.title, "--out", capture, "--width", String(config.capture.width), "--height", String(config.capture.height), - "--fps", String(config.capture.fps)]; + "--fps", String(config.capture.fps), + ...(config.capture.density ? ["--density", String(config.capture.density)] : [])]; if (source.performance) captureArgs.push("--perform", source.performance); run(process.execPath, captureArgs, { inherit: true }); const base = join(capture, `base-${source.title}.mp4`); @@ -182,7 +183,7 @@ async function buildAesthetic({ config, day, index, slot, dir, source }) { format: "ac.instagram.reel", version: 1, account: config.account, id: `${day}-s${index}-${source.id}`, day, index, slot, sourceId: source.id, piece: source.piece, segment: source.segment, - caption: aestheticCaption(source, config.tags), tags: config.tags, + caption: aestheticCaption(source), tags: [], approval: { recipe: "proven-av", humanAutoGate: `${config.prefix}_IG_AUTO=1` }, files: { reel }, };