Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions skills-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"files": 138
},
"faceless-explainer": {
"hash": "1eb3772e62dd71bb",
"hash": "00c69344cc72865f",
"files": 24
},
"figma": {
Expand Down Expand Up @@ -62,12 +62,12 @@
"files": 132
},
"pr-to-video": {
"hash": "01f46da1e17577ea",
"hash": "009da14494977a0b",
"files": 30
},
"product-launch-video": {
"hash": "d562efe00647c14b",
"files": 28
"hash": "dd0b772610abb3ca",
"files": 29
},
"remotion-to-hyperframes": {
"hash": "bf184a65059b95e8",
Expand Down
5 changes: 3 additions & 2 deletions skills/faceless-explainer/scripts/lib/assets.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export function basenamesFromCandidates(value) {
}

// Copy each frame's asset_candidates from capture/{assets,assets/videos,
// screenshots} into assets/. Already-staged files are left as is (first-wins),
// so calling this twice is safe. Returns { staged, wanted, anomalies }.
// assets/svgs, screenshots} into assets/. Already-staged files are left as is
// (first-wins), so calling this twice is safe. Returns { staged, wanted, anomalies }.
export function stageAssets({ hyperframesDir, frames }) {
const wanted = new Set();
for (const f of frames) {
Expand All @@ -27,6 +27,7 @@ export function stageAssets({ hyperframesDir, frames }) {
const captureDirs = [
join(hyperframesDir, "capture/assets"),
join(hyperframesDir, "capture/assets/videos"), // videos download into a subdir
join(hyperframesDir, "capture/assets/svgs"), // inline SVGs extract into a subdir
join(hyperframesDir, "capture/screenshots"),
];
const assetsDir = join(hyperframesDir, "assets");
Expand Down
5 changes: 3 additions & 2 deletions skills/pr-to-video/scripts/lib/assets.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export function basenamesFromCandidates(value) {
}

// Copy each frame's asset_candidates from capture/{assets,assets/videos,
// screenshots} into assets/. Already-staged files are left as is (first-wins),
// so calling this twice is safe. Returns { staged, wanted, anomalies }.
// assets/svgs, screenshots} into assets/. Already-staged files are left as is
// (first-wins), so calling this twice is safe. Returns { staged, wanted, anomalies }.
export function stageAssets({ hyperframesDir, frames }) {
const wanted = new Set();
for (const f of frames) {
Expand All @@ -27,6 +27,7 @@ export function stageAssets({ hyperframesDir, frames }) {
const captureDirs = [
join(hyperframesDir, "capture/assets"),
join(hyperframesDir, "capture/assets/videos"), // videos download into a subdir
join(hyperframesDir, "capture/assets/svgs"), // inline SVGs extract into a subdir
join(hyperframesDir, "capture/screenshots"),
];
const assetsDir = join(hyperframesDir, "assets");
Expand Down
5 changes: 3 additions & 2 deletions skills/product-launch-video/scripts/lib/assets.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export function basenamesFromCandidates(value) {
}

// Copy each frame's asset_candidates from capture/{assets,assets/videos,
// screenshots} into assets/. Already-staged files are left as is (first-wins),
// so calling this twice is safe. Returns { staged, wanted, anomalies }.
// assets/svgs, screenshots} into assets/. Already-staged files are left as is
// (first-wins), so calling this twice is safe. Returns { staged, wanted, anomalies }.
export function stageAssets({ hyperframesDir, frames }) {
const wanted = new Set();
for (const f of frames) {
Expand All @@ -27,6 +27,7 @@ export function stageAssets({ hyperframesDir, frames }) {
const captureDirs = [
join(hyperframesDir, "capture/assets"),
join(hyperframesDir, "capture/assets/videos"), // videos download into a subdir
join(hyperframesDir, "capture/assets/svgs"), // inline SVGs extract into a subdir
join(hyperframesDir, "capture/screenshots"),
];
const assetsDir = join(hyperframesDir, "assets");
Expand Down
52 changes: 52 additions & 0 deletions skills/product-launch-video/scripts/stage-assets.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import assert from "node:assert/strict";
import { existsSync, mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import { stageAssets } from "./lib/assets.mjs";

// ── captured SVGs are stageable ──────────────────────────────────────────────
// Regression: `hyperframes capture` extracts inline SVGs into capture/assets/svgs/
// (assetDownloader.ts), and the capture manifest advertises them to the agent as
// `assets/svgs/<name>.svg`, so a frame names one in `asset_candidates` exactly as
// it names a screenshot. stageAssets only searched capture/{assets,assets/videos,
// screenshots}, so every captured SVG resolved to nothing — reported as a
// non-fatal anomaly, and the frame 404'd the logo it had been told to use.

function projectWithCapturedSvg() {
const dir = mkdtempSync(join(tmpdir(), "product-launch-stage-assets-"));
mkdirSync(join(dir, "capture/assets/svgs"), { recursive: true });
mkdirSync(join(dir, "capture/screenshots"), { recursive: true });
writeFileSync(join(dir, "capture/assets/svgs/brand-mark.svg"), "<svg/>");
writeFileSync(join(dir, "capture/screenshots/hero.png"), "png");
return dir;
}

const frames = [
{ extra: { asset_candidates: "assets/svgs/brand-mark.svg — the mark; assets/hero.png — hero" } },
];

test("stages an SVG that capture wrote into capture/assets/svgs/", () => {
const dir = projectWithCapturedSvg();

const { staged, wanted, anomalies } = stageAssets({ hyperframesDir: dir, frames });

assert.equal(wanted.size, 2);
assert.equal(staged, 2, `expected both assets staged, got anomalies: ${anomalies.join("; ")}`);
assert.deepEqual(anomalies, []);
assert.ok(existsSync(join(dir, "assets/brand-mark.svg")));
assert.ok(existsSync(join(dir, "assets/hero.png")));
});

test("still reports an asset that exists nowhere under capture/", () => {
const dir = projectWithCapturedSvg();

const { staged, anomalies } = stageAssets({
hyperframesDir: dir,
frames: [{ extra: { asset_candidates: "assets/svgs/absent.svg — never captured" } }],
});

assert.equal(staged, 0);
assert.equal(anomalies.length, 1);
assert.match(anomalies[0], /absent\.svg/);
});
Loading