Files
flatrender/.claude/skills/flat-artist/asset-sourcing/SKILL.md
T
soroush.asadi f83d657844
CI/CD / CI · Web (tsc) (push) Successful in 1m19s
CI/CD / Deploy · full stack (push) Failing after 12s
chore(skills+remotion): add flat-artist skill bundle; register 3D templates
- .claude/skills/flat-artist: the bundled FlatRender template-creation suite
  (orchestrator + 16 sub-skills + design/motion R&D), mirrors the Gitea AISkills repo.
- services/remotion Root.tsx/templates.tsx: register the 3D templates + Three3DTest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 19:39:25 +03:30

96 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: asset-sourcing
description: How to source, license, AI-generate, prepare, and organize royalty-free assets (footage, images, textures, HDRIs, GLTF/GLB, icons, illustrations) for FlatRender Remotion templates — Iran-aware (geo-blocks), vendored-only, license-firewalled. Use when a template needs real media, when downloading/committing assets into public/, when grading/masking/looping footage or compositing it via Video/OffthreadVideo/Img/staticFile + Ken-Burns, or when generating bespoke assets with local AI models.
---
# Asset sourcing for templates
Project: `services/remotion/`. Helpers: `src/lib/anim.ts` (`hexToRgba`, `mixHex`, `rand`), `src/lib/aspect.ts` (`useLayout``isWide/isSquare/isTall`, `vmin`, `unit`), `src/lib/branding.ts` (`colorSchema`, `BRAND`), `src/lib/fonts.ts` (`FONT` = Vazirmatn, RTL), `src/lib/three-kit.tsx` (`StudioEnv/Lights/Floor/Effects`, `Confetti3D`). Render is **headless Chrome in Docker** — every value derives from `useCurrentFrame()` (never `Math.random`/`Date.now`/`useFrame`; use `rand(i)`).
## The Iron Rule — vendor everything
The Iran environment punishes runtime dependencies. **Download once (VPN if needed), commit into `public/`, reference with `staticFile()`.** Never put `https://…` in a shipped template — a geo-block or flaky tunnel kills the render mid-frame. Mirror npm/NuGet/Docker via Nexus (`mirror.soroushasadi.com`); asset *binaries* are sourced by hand. **Record the license at acquisition time, not later.** `public/` today holds only `fonts/` — you build the rest.
## License taxonomy (know cold — this is the firewall)
| Class | Examples | Ship? |
|---|---|---|
| CC0 / Public Domain / Pixabay / Pexels / Unsplash | Poly Haven, ambientCG, Kenney, Mixkit | ✅ free, no credit — **default target** |
| CC-BY | many Sketchfab, Bensound | ⚠️ ship only with a tracked on-screen/end-card credit |
| CC-BY-SA | some Wikimedia | ❌ share-alike can infect our proprietary template |
| CC-BY-NC | "free for personal" tiers | ❌ we are a **paid** product = commercial |
| Editorial / rights-managed | news/celebrity stock | ❌ |
| Paid stock | Envato, Adobe, Shutterstock | ✅ per license — **keep the receipt/PDF** |
No license row = unknown license = **do not ship**.
## Sourcing map (CC0 / no-attribution first) + Iran access
| Type | Best CC0 sources | Commit to | Iran access |
|---|---|---|---|
| Footage (H.264 MP4, right-sized) | Pexels Video, Pixabay Video, Mixkit, Coverr, Videvo (filter CC0) | `public/footage/{nature,business,abstract}/` | Pixabay/Mixkit/Coverr OK; Pexels VPN-ish |
| Images | Pexels, Pixabay, Unsplash, StockSnap, Burst | `public/images/` | Pixabay OK; Pexels/Unsplash VPN-ish |
| Textures / overlays | Poly Haven, ambientCG; grain/light-leak/dust CC0 clips | `public/textures/`, `public/overlays/` | OK |
| HDRIs (1k2k for render speed) | Poly Haven, ambientCG | `public/hdri/` | OK |
| 3D (**prefer GLB** over glTF+textures) | Poly Haven Models, Kenney, Khronos glTF samples, Sketchfab (check each) | `public/models/` | Poly Haven OK; Sketchfab VPN-ish |
| Icons (bundle via Nexus npm, **never CDN**) | Lucide, Tabler, Heroicons, Phosphor | npm dep | npm via Nexus OK |
| Illustrations (recolorable **SVG**) | unDraw, Open Peeps, Humaaans | `public/illustrations/` | OK |
For Persian/Iran imagery search English terms ("Tehran", "Iranian food") + self-shot/local stock. **Sanction-blocked at account/payment: Adobe Stock, Envato** — use a foreign account/partner or skip. **Mitigation: do one batched "asset run" over a stable tunnel, commit binaries, render never touches the open internet again.** Draco-compress GLBs (`gltf-pipeline -i in.glb -o out.glb -d`), keep low-poly for headless render speed.
## AI-generated assets — when it's right
- **Use when:** the asset doesn't exist as stock (specific Persian cultural scene, branded mascot), you need consistency across a template set (reference-image control), or it beats a 5-site license hunt.
- **Don't when:** clean CC0 already exists, you need photographic authenticity, or a free tier's **commercial license is unclear** (watermarks / non-commercial = legal landmine for a paid product).
- **Iran-pragmatic:** self-host open models — **HunyuanVideo 1.5** (~RTX 4090, no geo-block/payment/watermark) for video; **FLUX/SDXL** locally for image/texture/illustration. Hosted SaaS (Runway, Kling) only when local quality falls short and a VPN+foreign-account path exists. **Always record prompt + tool + plan-tier + date** in the asset's `.license.txt` sidecar.
## Preparing footage in Remotion (composite, grade, mask, loop)
**Primitives:** `<OffthreadVideo>` = default for **all** video in a render (FFmpeg extraction, deterministic, no seek drift). `<Video>` = preview only. `<Img>` over raw `<img>` (waits for load → no half-loaded frames). `staticFile()` for every vendored asset.
```tsx
import { OffthreadVideo, Img, staticFile, useCurrentFrame, interpolate, Easing } from "remotion";
import { useLayout } from "./lib/aspect";
const frame = useCurrentFrame();
const L = useLayout();
// Ken-Burns: overscan ≥1 so no edges reveal; cover + center crops cleanly in all 3 aspects.
const scale = interpolate(frame, [0, 150], [1.08, 1.2], { extrapolateRight: "clamp" });
const ty = interpolate(frame, [0, 150], [0, L.vmin(-30)], { easing: Easing.out(Easing.cubic), extrapolateRight: "clamp" });
<OffthreadVideo
src={staticFile("footage/nature/forest-loop.mp4")}
style={{ width: "100%", height: "100%", objectFit: "cover",
transform: `scale(${scale}) translateY(${ty}px)`,
filter: "contrast(1.08) saturate(1.15) brightness(0.96)" }} // grade
/>
```
| Job | Pattern |
|---|---|
| **Color grade** | per-layer CSS `filter` (`contrast/saturate/brightness/hue-rotate`); build a shared `lib/grades.ts` (`warm`, `teal-orange`, `mono`, `filmic`) so palette can drive `hue-rotate`/`saturate`. Heavy grade → pre-grade in DaVinci Resolve (free), then commit. |
| **Masking / keying** | no native keyer — pre-key in Resolve/AE, export **alpha** (ProRes 4444 or WebM/VP9 alpha), then `<OffthreadVideo>`. Shape masks via CSS `maskImage`/`clipPath` + `hexToRgba` gradients, or SVG `<mask>`. |
| **Seamless loop** | source loop-designed clips (Coverr/Mixkit) or mirror-pingpong; `<OffthreadVideo loop>` once first/last frames match; crossfade-to-self with overlapping `<Sequence>` for imperfect footage. |
| **Overlays (cheap "authentic" layer)** | stack grayscale-on-black/white clips: **screen** for light-leaks/bokeh/dust, **overlay/soft-light** for grain, **multiply** for vignettes/paper. Keep palette-independent. **Animated grain must move** — offset `background-position` per frame or jitter SVG `feTurbulence` `seed`. |
| **Per-aspect crop** | `objectFit:"cover"` + center-safe framing; branch focal point on `L.isWide/isSquare/isTall` (or the proposed `L.pick(wide,square,tall)`) so the subject never crops out. |
HDRIs/GLBs: feed `staticFile("hdri/…")` into `three-kit`'s `StudioEnv`; load models with `useGLTF(staticFile("models/…glb"))`, idle-bob with `Math.sin(frame/fps)` (driven by `useCurrentFrame`, **not** `useFrame`).
## Library structure + attribution firewall
Create under `public/`: `footage/{nature,business,abstract}/`, `overlays/`, `images/`, `textures/`, `hdri/`, `models/`, `icons/`, `illustrations/`, plus **`assets.json`** + **`ASSETS.md`**. Lowercase-kebab names, no spaces. Every asset gets one `assets.json` row **at download time**:
```json
{ "file": "footage/nature/forest-loop.mp4", "source": "Pexels",
"url": "https://www.pexels.com/video/...", "author": "Name",
"license": "Pexels", "attribution_required": false, "commercial_ok": true,
"acquired": "2026-06-21", "notes": "1080p H.264, loops clean" }
```
Sidecar `.license.txt` next to AI assets (prompt + tool + date) and paid receipts. A **CI validation script** asserts every file in the media folders has a matching row with `commercial_ok:true`, else fails the build — this is the firewall. `ASSETS.md` is the generated human/legal-readable table. `attribution_required:true` must surface a credit on a shippable surface (end-card/footer). If the repo bloats, move large media to MinIO (already in stack) with a `predeploy` sync into `public/` — but present at render time.
## Checklist (before committing an asset / shipping a template)
- [ ] Vendored in `public/…` and referenced via `staticFile()`**no external URL** anywhere in the template.
- [ ] `assets.json` row added with `commercial_ok:true`; `.license.txt`/receipt for AI/paid; CC-BY credits surfaced.
- [ ] Right-sized (don't ship 4K into a 1080p comp); video is H.264 MP4 played via `<OffthreadVideo>`; images via `<Img>`.
- [ ] GLB (not glTF+loose textures), Draco-compressed, low-poly; HDRI 1k2k.
- [ ] Footage graded through `lib/grades.ts`; overlay grain/light-leak **moves** per frame; loops are seamless.
- [ ] Ken-Burns overscans (start scale ≥ 1.05) and `objectFit:cover` crops cleanly in 16:9 / 1:1 / 9:16 with subject in frame.
- [ ] Re-render twice → identical (deterministic; nothing pulled from network/random/date).
Related: `../remotion-design-styles/SKILL.md`, `../remotion-template-composition/SKILL.md`, `../remotion-aspect-ratios/SKILL.md`, `../remotion-character-design/SKILL.md`, `../remotion-svg-colors/SKILL.md`, `../remotion-music-picker/SKILL.md`, `../remotion-sound-effects/SKILL.md`, `../persian-fonts/SKILL.md`, `../flatrender-template-seo/SKILL.md`.