cinefoundry-ad-film · diff
v0.2.0 to v0.3.0
25 added, 32 removed. Audit A to A.
---
name: cinefoundry-ad-film
- version: "0.2.0"
- description: Produce a finished short advertising film (visuals, voiceover, music, typeset titles, compliance-checked copy) from one sentence of creative brief, locally on a DGX Spark, by running the Cinefoundry Harness. Use when the user asks for an ad, a product video, a 10/15/20-second commercial, "给某个产品做条广告", or wants to re-cut or re-voice an existing Cinefoundry project.
+ version: "0.3.0"
+ description: Produce a finished advertising film - a 30-second master by default, with an English announcer cast from the voice library, Chinese subtitles over the English line, typeset Chinese titles, a generated score and compliance-checked copy - from one sentence of creative brief, locally on a DGX Spark, by running the Cinefoundry ad pipeline (`cinefoundry ad`). Use when the user asks for an ad, a commercial, a product video, a 30-second spot or a shorter one, "给某个产品做条广告", or wants to re-cut or re-voice an existing Cinefoundry ad project.
license: BUSL-1.1
metadata:
author: 贺家豪 (Jiahao He)
category: production
tags:
- advertising
- video-generation
- dgx-spark
- harness
---
# Cinefoundry ad film
- This is the entry point for any agent - Claude Code, Codex, Gemini CLI, or Cinefoundry's own director -
- that wants a finished ad. It does not do the stages itself: it calls the Cinefoundry Harness, which runs
- brief, script, compliance, storyboard, frames, quality gate, clips, cut, cutdowns and delivery QC, each with its own stage
- skill, and checks every result before the next stage starts.
+ This is the entry point for any agent - Claude Code, Codex, Gemini CLI, or Cinefoundry's own director - that wants a finished ad. It does not do the stages itself: it runs the ad pipeline, which goes brief -> creative -> script -> compliance -> storyboard -> frames + quality gate -> clips -> cut -> versions (15 s and 6 s) -> delivery QC, each stage an agent with its own skill, and checks every result before the next stage starts.
+ What comes out: a 16:9, native-1080p, 60 fps film of `duration + 3 - 0.5` seconds (32.5 s for the 30-second master): six 5-second shots, hard cuts, a dissolve into a 3-second end card on the product; an English voiceover read by the announcer the creative director cast; the Chinese subtitle large over the English line; a Chinese title per beat; a generated score mixed to -16 LUFS; the explicit AI label and the AIGC metadata. The 15- and 6-second cutdowns are cut from the master afterwards (`editing-and-versioning`).
+
## Before you start
Run this one check first, before anything else:
```bash
- pgrep -af "cli.js harness"; curl -sf 127.0.0.1:8001/v1/models >/dev/null && curl -sf 127.0.0.1:8002/v1/models >/dev/null && curl -sf 127.0.0.1:8188/system_stats >/dev/null && echo "stack up"; cinefoundry mem status
+ pgrep -af "cli.js (ad|short|drama|harness)"; curl -sf 127.0.0.1:8001/v1/models >/dev/null && curl -sf 127.0.0.1:8002/v1/models >/dev/null && curl -sf 127.0.0.1:8188/system_stats >/dev/null && echo "stack up"; cinefoundry mem status
```
- - Any `cli.js harness` line means another film is generating: stop and tell the user. One film at a time; two runs on one GPU make both slow and can fail a model load. The harness also refuses to start while another run holds its lock.
+ - Any `cli.js` line means another film is generating: stop and tell the user. One film at a time; two runs on one GPU make both slow and can fail a model load. The pipeline also refuses to start while another run holds `projects/.harness.lock`.
- No `stack up`: run `scripts/spark-up.sh`.
- - Memory: see `spark-model-scheduler`. About 45 GB available with the three services idle is normal.
+ - Memory: see `spark-model-scheduler`, including the page-cache eviction before the GPU phases.
## Workflow
- 1. Take the user's brief as written, in the user's language. Never translate, summarise or rephrase it: a Chinese brief passed on in English lost its quoted closing line ("DGX Spark,把 AI 超算放上你的桌面") and turned "千亿参数" into "billion-parameter". Keep its quotation marks too (put the brief in single quotes on the command line so “…” survive). Keep their words about the product's look (container, colours, label), the aspect ratio and the duration: the harness enforces them against what its agents write.
- 2. Ask only if the product, the audience or the one message is missing. Decide everything else.
+ 1. Take the user's brief as written, in the user's language. Never translate, summarise or rephrase it: a Chinese brief passed on in English once lost its quoted closing line and turned 千亿 into "billion". Keep its quotation marks too (put the brief in single quotes on the command line so “…” survive). Keep their words about the product's look (container, colours, label), the aspect ratio and the duration: the pipeline enforces them against what its agents write.
+ 2. Ask only if the product, the audience or the one message is missing. Decide everything else and state your choice.
3. Run, from the repository root:
```bash
- node dist/cli.js harness "<the brief, verbatim>" [--id <project-id>] [--ratio 16:9|9:16|1:1] [--duration 10|15|20] [--resolution 1080p|2k|4k|6k] [--fps 60|24|30|120] [--product-image <photo>] [--proof "<facts>"]
+ node dist/cli.js ad '<the brief, verbatim>' [--id <project-id>] [--duration 30] [--ratio 16:9|9:16|1:1] [--resolution 1080p|2k|4k|6k] [--fps 60|24|30|120] [--product-image <photo>] [--proof "<facts>"]
```
- When the user gives facts the brand can back (specs, figures, a source), pass them with `--proof`.
- They are the only claims the copy may make; without them the compliance reviewer strips every number.
+ `node dist/cli.js harness` is the same command and still works.
- If the user gives a photo of the real product, pass it as `--product-image`. It replaces the
- generated hero still, so every shot shows the real shape and logo instead of the image model's
- guess. Only use a photo the user took or has rights to.
+ - `--duration` defaults to 30 (the master); any multiple of 5 from 5 to 30 is accepted, one 5-second clip per beat. A duration stated in the brief ("15 秒") wins over the default.
+ - When the user gives facts the brand can back (specs, figures, a source), pass them with `--proof`. They are the only claims the copy may make; without them the copy carries no figures, specs or comparisons.
+ - If the user gives a photo of the real product, pass it as `--product-image`. It replaces the generated hero still, so every shot shows the real shape and logo instead of the image model's guess. Only use a photo the user took or has rights to.
+ - The default film is 16:9, native 1080p, 60 fps. Leave `--ratio` out unless the user asked for vertical or square (a brief saying 竖版 or naming a vertical platform is read as 9:16 anyway), and leave `--resolution` / `--fps` out unless they asked.
- The default film is 16:9, native 1080p, 60 fps. Leave `--ratio` out unless the user asked for vertical or square, and leave `--resolution` / `--fps` out unless they asked. Generation time on one DGX Spark is dominated by the three native-1080p clips (about 4 minutes each) and their interpolation (under a minute each); the delivery report records the measured total. Run it in the background and report progress from the `▸` lines it prints, or point the user at the Studio (`node dist/cli.js studio`, port 3090) where the same run is visible.
- 4. Use `--plan-only` when the user wants the script and storyboard to approve before any GPU time is spent.
- 5. When it finishes, read `projects/<id>/reports/delivery.md` and tell the user: where the film is (`projects/<id>/cut/final.mp4`, and the cutdowns `cut/final_15s.mp4` and `cut/final_06s.mp4` when the master is long enough), what each shot's gate said, the QC verdict per file (`reports/qc.json`), total seconds, and every open item the report lists (a shot kept after failing the gate, for example). Do not describe the film as flawless if the report says otherwise.
+ Generation time is dominated by the clips: measured on this machine, 247 s per native-1080p LTX-2.5 clip and 49 s per RIFE interpolation, six of each for the master. The delivery report records the measured total; do not quote one before it exists. Run it in the background and report progress from the `▸` lines it prints, or point the user at the Studio (`node dist/cli.js studio`, port 3090) where the same run is visible.
+ 4. Use `--plan-only` when the user wants the treatment, script and storyboard to approve before any GPU time is spent.
+ 5. When it finishes, read `projects/<id>/reports/delivery.md` and tell the user: where the film is (`projects/<id>/cut/final.mp4`, and the cutdowns `cut/final_15s.mp4` and `cut/final_06s.mp4` when the master is long enough), what each shot's gate said, the measured total, and every open item the report lists (a shot kept after failing the gate, a compliance item for human confirmation). Do not describe the film as flawless if the report says otherwise.
## Voice
- The default voice engine is Kokoro. For a broadcast narrator, set before running:
-
- ```bash
- export CINEFOUNDRY_TTS_ENGINE=qwen-tts \
- CINEFOUNDRY_TTS_REF_WAV=runtime-data/step-audio/voices/male-2.wav \
- CINEFOUNDRY_TTS_REF_TEXT="$(python3 -c "import json;print(json.load(open('runtime-data/step-audio/voices/voices.json'))['male-2']['text'])")"
- ```
+ Nothing to set for a normal run. The creative director casts the announcer from the English announcers in the casting library (`deploy/voices/library.json`) that passed voice QC on this machine, and the cut clones every line from that voice with Qwen3-TTS and checks it with Whisper (`dialogue-and-voice`).
- The reference voices were designed from a written description (`scripts/voice-design.py`). Only use a
- reference recording of a real person with that person's consent.
+ A fresh machine has no QC-passed voices; then the only option is the configured default narrator, which is not an English announcer. Design and QC the library first (`scripts/voice-design.py --language English`, then `scripts/voice-qc.py`, both inside their containers; see `dialogue-and-voice`). Every voice is designed from a written description; never use a recording of a real person.
- To re-voice or re-cut a finished project without regenerating pictures:
- `node dist/cli.js cut --project <id> --audio projects/<id>/audio/music.mp3`.
+ To re-cut a finished project without regenerating pictures: `node dist/cli.js cut --project <id>` (titles, subtitles, end card, sound and grade), or with a supplied score `--audio projects/<id>/audio/music.mp3`.
## Common failures
- `product hero still never passed the gate`: the storyboard's product description contradicts the brief or carries text the image model paints onto the product. Read the gate's issues in `reports/run.jsonl`, fix the brief wording, run again.
+ - `script still fails its checks after 6 attempts`: usually a subtitle over the ratio's limit (16 characters on 16:9, 12 on 9:16) or an English line outside 4-13 words; the message lists the failures. Rerun; if it repeats, simplify the brief's message.
+ - `Compliance blocked the script`: a `block` finding survived the reviewer. Nothing was generated; rewrite the brief's claim or supply `--proof`.
- A run that sits for many minutes on one frame: the reviewer is reasoning; each call is bounded, and an inconclusive verdict counts as a rejection.
- - Out-of-memory at a model load: another GPU job is running, or ComfyUI is holding cached weights; `cinefoundry mem free`, then retry.
+ - Out-of-memory at a model load: another GPU job is running, ComfyUI is holding cached weights, or the page cache holds the memory CUDA needs; `cinefoundry mem free`, evict the page cache (`spark-model-scheduler`), then retry.