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:
soroush.asadi
2026-06-22 18:59:03 +03:30
parent a3152ee84f
commit cb6512fee3
38 changed files with 1298 additions and 1 deletions
@@ -0,0 +1,38 @@
import React from "react";
import { AbsoluteFill, Img, staticFile } from "remotion";
import { FONT } from "../lib/fonts";
// Dev/preview composition (NOT a customer template — registered standalone in Root,
// never seeded). Renders a contact-sheet of the vendored CC0 Open-Peeps characters
// to verify the public/illustrations -> staticFile() -> render pipeline works.
const COUNT = 30;
export const AssetSheet: React.FC = () => {
const items = Array.from({ length: COUNT }, (_, i) =>
`illustrations/dicebear/openpeeps-${String(i + 1).padStart(2, "0")}.svg`
);
return (
<AbsoluteFill style={{ background: "#ece4d6", fontFamily: FONT, padding: 44 }}>
<div style={{ fontSize: 34, fontWeight: 800, color: "#2b3a55", marginBottom: 22, direction: "rtl" }}>
کتابخانهٔ شخصیتها Open Peeps (CC0) ۳۰ نمونه
</div>
<div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gridAutoRows: "1fr", gap: 16, flex: 1 }}>
{items.map((src, i) => (
<div
key={i}
style={{
background: "#ffffff",
borderRadius: 18,
display: "flex",
alignItems: "center",
justifyContent: "center",
boxShadow: "0 10px 26px rgba(43,58,85,0.10)",
}}
>
<Img src={staticFile(src)} style={{ width: "84%", height: "84%", objectFit: "contain" }} />
</div>
))}
</div>
</AbsoluteFill>
);
};