feat(remotion): asset-library catalog + Phase 0 (license firewall, @remotion/lottie, 30 CC0 characters)
- docs/ASSET_LIBRARY.md: curated catalog from the asset sweep (91 sources -> 62 usable) + completeness-critic reality check; clean CC0/MIT tier, license/geo traps, and the 2.5D layered-scene plan (sky->room->furniture->device->character ->grain) to fix the "naked scene". - deps: add @remotion/lottie@4.0.290 (runtime) + DiceBear (build-time devDep). - scripts/gen-dicebear.mjs: generate 30 CC0 Open-Peeps characters OFFLINE (no runtime CDN) into public/illustrations/dicebear/ + a per-file assets.json ledger. - scripts/check-assets.mjs: license-firewall CI guard — fails on any un-ledgered vendored asset. - AssetSheet dev composition: proves vendored SVG -> staticFile() -> Remotion render (30 real characters render cleanly). - NOTE: GitHub (Open Peeps/IRA/Notion git clones) + Gumroad (Lukasz) are geo-blocked headless here; those + Humaaans (Figma export) need a manual/mirror fetch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// License-firewall CI guard.
|
||||
//
|
||||
// Every vendored asset under public/illustrations/ (and public/lottie/) MUST have a
|
||||
// row in public/illustrations/assets.json. No row -> the asset may not ship. Fails
|
||||
// the build (exit 1) on any un-ledgered file. Run: npm run check:assets
|
||||
import { readFileSync, readdirSync, statSync, existsSync } from "node:fs";
|
||||
import { join, dirname, relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PUBLIC = join(__dirname, "..", "public");
|
||||
const ILLUS = join(PUBLIC, "illustrations");
|
||||
const ledgerPath = join(ILLUS, "assets.json");
|
||||
|
||||
if (!existsSync(ledgerPath)) {
|
||||
console.error(`MISSING license ledger: ${ledgerPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const ledger = JSON.parse(readFileSync(ledgerPath, "utf8"));
|
||||
|
||||
function walk(dir) {
|
||||
if (!existsSync(dir)) return [];
|
||||
let out = [];
|
||||
for (const e of readdirSync(dir)) {
|
||||
const p = join(dir, e);
|
||||
if (statSync(p).isDirectory()) out = out.concat(walk(p));
|
||||
else if (/\.(svg|json)$/i.test(e) && e !== "assets.json") out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Asset files live under illustrations/<source>/ and lottie/.
|
||||
const files = [...walk(ILLUS), ...walk(join(PUBLIC, "lottie"))]
|
||||
.map((p) => relative(ILLUS, p).split("\\").join("/"));
|
||||
|
||||
const missing = files.filter((f) => !ledger[f]);
|
||||
if (missing.length) {
|
||||
console.error(`Un-ledgered assets (add a row to assets.json):\n ${missing.join("\n ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`assets.json OK — ${files.length} vendored asset(s), all ledgered.`);
|
||||
Reference in New Issue
Block a user