用 Grok Bot 搭一个多 Bot 的动效视频工作室:五个 Bot 分工、渲染队列和审片闭环
根据 @0xCarnagee 的长文整理并对照官方文档核对:在 Grok Bot 的云电脑上搭一条做动效视频的流水线。五个 Bot 各管一段,用文件夹里的文件记录进度,一个渲染队列排队出片,独立的审片 Bot 打分,定时任务让它夜里自己跑。
本文根据公开分享整理,本站尚未实测。操作前请对照文末的原始来源。
本页目录(12 节)
这篇教程解决一个问题:不是让 Grok Bot 做一条视频,而是搭一条能反复出片的流水线:你交一份需求、批准分镜,剩下的由几个 Bot 接力完成,夜里渲染,早上交片。
方法来自 X 用户 @0xCarnagee 的一篇英文长文,原文有 15 步、31 段提示词。本文按“先搭环境、再定分工、再装引擎、最后让它自己跑”重新整理,脚本取自原文,说明性的提示词译成了中文,并逐条对照了 Grok Bot 的官方文档。
动手之前有三件事要先知道:
- 原文的脚本没有在 Grok Bot 里实际跑过。 作者自己写明:所有脚本是在一台同类的 Linux 沙盒里从头到尾跑通的,不是在 Grok Bot 里;到他发文时,也还没有人公开展示过在 Grok Bot 里用一组 Bot 夜里渲染出片。所以把它当成一份设计方案,照着做的时候预期要调。
- 原文有几处说法和官方文档不一致,本文都按官方的写了,见下一节的表。
- 用代码渲染视频的原理(
seek(t)、逐帧截图、ffmpeg 合成),本站另一篇讲得更细:用 Grok Bot 做视频:让 AI 写代码渲染成片的八步流程。这一篇讲的是怎么把它做成多个 Bot 协作的流水线。
先弄清:这台电脑和这个模型
模型你选不了。 官方帮助中心写明,Grok Bot 没有模型选择器,每个任务由系统选用它认为最合适的模型,其中包括 Claude Opus 5.5。原文据此得出一个设计原则:既然调不了模型和思考力度,就靠结构来保证质量:写清楚的规格、一道道关卡、一个独立的审片员。
所有 Bot 共用一台云电脑。 这一点官方文档说得很明确,它决定了整个方案的形状:
| 事实(官方文档) | 对工作室意味着什么 |
|---|---|
| 账户里所有 Bot 共用一台电脑,文件对每个 Bot 可见 | 审片 Bot 读到的就是动画 Bot 写的那份文件,可以用文件来交接 |
共享工作区在 /workspace |
要留下来的东西都放在这里 |
| 电脑更新、Recover、Reset 会移除手动安装的应用和软件包 | 安装步骤要写成脚本,随时能重跑 |
| 合上笔记本或关掉应用,云端的工作不会停 | 长时间渲染可以放心交给它 |
| 命令行凭据在各个 Bot 之间共享 | 客户的登录信息和密钥不要放在这个账户上 |
原文和官方文档对不上的地方:
| 原文的说法 | 官方文档的说法 |
|---|---|
Python 虚拟环境放在 /workspace 里,所以重建电脑后还在 |
node_modules 和 Python 虚拟环境这类项目文件夹不会被保存,电脑更新、Recover 或 Reset 之后要重新安装 |
| 用量分析里能看到每个请求是哪个模型处理的 | Grok Bot 不显示处理请求的模型,用量统一记为“Grok Bot 用量”,不按模型区分 |
| 计费跟着实际使用的模型走,Opus 5.5 更贵 | 把任务交给 Opus 5.5 不会改变每个 token 的消耗 |
第一条不影响使用,因为下面的安装脚本本来就设计成可以重跑;只是别指望那个环境能留住。
原文还列了这台电脑的配置(8 核、约 16 GB 内存、约 128 GB 磁盘、没有显卡)。这是用户自己量出来的,官方没有公布,你的可能不一样。让任意一个 Bot 运行下面这段,看看自己的:
# GrokBot: run this in your terminal and show me the output.
nproc; free -h | head -2; df -h /workspace | tail -1
nvidia-smi -L 2>/dev/null || echo "no GPU"
head -n1 /etc/os-release
没有显卡这一条最要紧:用代码渲染的动效(HTML、CSS、Canvas、SVG)没问题;需要显卡的三维渲染不要当默认方案。瓶颈在逐帧截图,不在模型。
1一条提示词装好环境
把下面这段发给任意一个 Bot。它会把安装脚本写进 /workspace/studio/bootstrap.sh 并运行。以后电脑被重建了,再发一遍同样的内容就行。
# GrokBot: run this in your terminal exactly as written, then show me the last line.
mkdir -p /workspace/studio && cat > /workspace/studio/bootstrap.sh <<'STUDIO'
#!/usr/bin/env bash
# /workspace/studio/bootstrap.sh
# Safe to re-run: anything already installed is skipped.
set -euo pipefail
mkdir -p /workspace/studio/{projects,queue} && cd /workspace/studio
# 1. ffmpeg lives outside /workspace, so a rebuild can wipe it
command -v ffmpeg >/dev/null || { sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg; }
# 2. Python for the beat grid, inside /workspace so it survives rebuilds
if [ ! -x .venv/bin/pip ]; then
python3 -m venv --clear .venv 2>/dev/null || {
sudo apt-get update -qq && sudo apt-get install -y -qq python3-venv
python3 -m venv --clear .venv
}
fi
.venv/bin/pip install -q numpy librosa soundfile
# 3. headless Chromium: if it can't launch, install it with its system libraries
[ -f package.json ] || npm init -y >/dev/null
[ -d node_modules/playwright ] || npm i -D --no-fund --no-audit --loglevel=error playwright
node -e "require('playwright').chromium.launch().then(b => b.close())" 2>/dev/null \
|| npx playwright install --with-deps chromium
# 4. fonts as files, never from a CDN (Geist ships under the SIL Open Font License)
[ -d node_modules/geist ] || npm i -D --no-fund --no-audit --loglevel=error geist
echo "studio ready | $(ffmpeg -version | head -n1 | cut -d' ' -f1-3) | node $(node -v)"
STUDIO
bash /workspace/studio/bootstrap.sh
脚本做了四件事:装 ffmpeg;建一个 Python 环境并装上分析音乐节拍用的库;装无头浏览器 Chromium,装之前先试着启动一次,能启动就跳过;把字体当作文件装进来,不依赖网络。
两点提醒:
- 脚本里用了
sudo。作者说明这台电脑上能用sudo是用户反馈的,官方文档没有写。某一步失败的话,Bot 会告诉你,再调整。 - 按官方的说法,电脑重建后 Python 环境和
node_modules都会没有。脚本每一步都先检查再安装,所以重跑一遍就能恢复。
2把做事的规矩存成技能
技能是一份可复用的做事说明。官方文档说,技能存一次,你所有的 Bot 都能用。工作室需要这几份:
| 技能 | 给谁用 | 内容 |
|---|---|---|
| house-style | 所有 Bot | 渲染的硬规定、画面风格、禁用的套路 |
| direct-film | 导演 | 接到需求后怎么建项目、切音乐、出分镜表,等你批准 |
| build-film | 动画 | 按分镜写出影片的代码,每个节拍先出一张静帧自查 |
| render-film | 渲染 | 运行渲染队列,把审片用的图发给审片 Bot |
| critique-pass | 审片 | 看图打分,不过关就把问题发回动画 Bot |
存技能的方法是对 Bot 说“把下面的内容存成一个私有技能,名字叫某某”。最核心的 house-style 是这样的(译自原文,命令和路径保持原样):
【渲染的硬规定】
每一帧都只由时间决定:window.seek(t) 画出第 t 秒的画面。
渲染模式下不用 CSS 过渡,不用 setTimeout,不用 requestAnimationFrame。
帧与帧之间不保留状态。随机数只用带种子的,绝不用 Math.random。
字体从文件加载,绝不从 CDN 加载。Geist 字体在
/workspace/studio/node_modules/geist/dist/fonts/
【画面】
一种标题字体,一种界面字体,一种强调色。
每 2 到 4 秒屏幕上要有新东西。
大胆的设计只用在一个地方。
关掉声音也要能看懂。X 上的视频默认静音播放。
【禁用】
渐变背景上居中的标题。所有东西同时淡入。
角落的标签和画面边框。界面元素上的发光。
粒子爆发。弹来弹去的缓动。没有内容的停顿。
“禁用”要一条条写出具体的套路。只写一句“不要有 AI 味”没用,模型只会从一个默认样式换到另一个。这张清单要一直加:每出一条看起来很套路的片子,就把它用的套路补进去。
审片的技能 critique-pass(译自原文):
什么时候用:渲染 Bot 把一个项目的图发给你时。在那个项目的文件夹里工作。
1. 看 contact.png 和 phone.png。只有循环播放的片子才看 seam.png。
2. 对某一刻拿不准?从那一秒连续取 4 帧:
ffmpeg -v error -y -ss <秒数> -i out/final.mp4 -vf "scale=540:-1,tile=4x1" -frames:v 1 out/zoom.png
3. 按 1 到 10 分打分:前 2 秒的钩子、手机上的可读性、动效、变化、构图、品牌。
4. 把分数和最严重的 3 个问题(带时间点)追加到 review_log.md。
5. 每一项都在 8 分以上:创建 PASSED 文件。
否则把这 3 个问题发给动画 Bot。
6. 三轮还没过:停下来问我。
你是严厉的动效导演,不是得意的作者。不要夸奖。
最后一句不是可有可无的。让写代码的那个 Bot 对自己的作品挑剔很难,单独调一个只负责挑毛病的审片员要容易得多。“三轮不过就找人”这个上限也很重要,它防止一个改不好的镜头把你一周的用量耗光。
另外三份技能(direct-film、build-film、render-film)和两份影片规格(界面变形循环、产品发布片)篇幅较长,原文里有全文。
3五个 Bot,一人一件事

新建五个 Bot,把各自的角色说明作为第一条消息发给它(译自原文):
【导演 Director】
你是导演,/workspace/studio 这个动效工作室的负责人。
每一条片子从需求到交付都归你管。遵守 /workspace/studio/STATES.md 和 direct-film 技能。
你从不写影片的代码。记住这个角色。
【动画 Animator】
你是 /workspace/studio 这个动效工作室的动画。
你用 house-style 和 build-film 技能把影片写成代码。遵守 /workspace/studio/STATES.md。
只处理有 APPROVED 文件的项目。记住这个角色。
【渲染 Render】
你是 /workspace/studio 这个动效工作室的渲染。
你是唯一负责渲染的 Bot,使用 render-film 技能。
你从不修改影片的代码。记住这个角色。
【审片 Critic】
你是 /workspace/studio 这个动效工作室的审片。
你从不写影片的代码。你用 critique-pass 和 house-style 技能评判每一次渲染,对任何片子都不手软。
记住这个角色。
【交付 Delivery】
你是 /workspace/studio 这个动效工作室的交付。
项目里有 PASSED 文件,片子才算完成。你把完成的片子交给我。
没有我的批准,绝不公开发布或发送任何东西。记住这个角色。
然后把五个 Bot 拉进一个群。官方文档规定一个群可以放 2 到 6 个 Bot,五个正好还空一个位置。
为什么这样分:
- 只有一个 Bot 负责渲染。 所有 Bot 共用一台电脑,两个渲染同时跑会平分处理器,两边都很慢。一个渲染员,一个队列。
- 写代码的和审片的分开。 自己写的代码,自己审会手软。
- 导演负责到底,群聊用来看交接。 这也是官方文档的建议:让一个 Bot 对一件事从头负责到尾;交接过程需要所有人看得见时,才用群聊。
4用文件夹里的文件记录进度
Bot 会忘事,聊天记录会被冲走,文件不会。所以交接的规矩写在一个文件里,每个角色说明都指向它。把下面这段发给任意一个 Bot:
# GrokBot: run this in your terminal exactly as written.
cat > /workspace/studio/STATES.md <<'STUDIO'
Every project is a folder: /workspace/studio/projects/<slug>/
Each file is a state. Move a project forward only when the state before it exists.
FILE MEANS WRITTEN BY
brief.md the ask (SPEC = unpaid) the human, Scout or Director
song.mp3 the cut, faded track Director
beats.json the beat grid Director
shotlist.md states on the beat grid Director
RENDER render.mjs flags Director
APPROVED the human said yes Director, on the human's word
index.html the film, as code Animator
READY stills checked Animator
out/final.mp4 the render Render
out/SENT frames sent to Critic Render
review_log.md scores, every round Critic
PASSED every score 8 or higher Critic
DELIVERED handed to the human Delivery
PITCHED DM drafted (SPEC only) Delivery
RENDER is one line of flags, for example:
--dur 20 --fps 60 --sub 4 --audio song.mp3
After any fix, Animator deletes out/ so the film renders again.
After a client change, also delete PASSED and DELIVERED.
Images go bot to bot, never through the group chat.
STUDIO
mkdir -p /workspace/studio/music && echo "STATES.md written"
这张表的意思是:每个项目是一个文件夹,文件夹里有哪些文件,就代表它走到了哪一步;前一步的文件不存在,就不能往下走。
| 文件 | 含义 | 谁写 |
|---|---|---|
brief.md |
需求 | 你,或者导演 |
song.mp3、beats.json |
切好的音乐和节拍表 | 导演 |
shotlist.md |
落在节拍上的分镜表 | 导演 |
APPROVED |
你批准了分镜 | 导演,在你说了“批准”之后 |
index.html |
影片本身,一份代码 | 动画 |
READY |
静帧已经自查过 | 动画 |
out/final.mp4 |
渲染出的成片 | 渲染 |
review_log.md |
每一轮的打分 | 审片 |
PASSED |
每一项都在 8 分以上 | 审片 |
DELIVERED |
已经交给你 | 交付 |
这样设计的好处:
- Bot 忘了,或者电脑重建了,看一眼文件夹就知道每个项目在哪一步。
- 重新渲染只是一次删除。 动画 Bot 改完之后删掉
out/文件夹,渲染 Bot 下一轮就会重新渲染,审片 Bot 拿到的是新图。 - 图片要 Bot 对 Bot 直接发,不能发到群里。 官方文档写明,Bot 发到群里的交接消息目前只支持文字。把审片用的图发到群里,审片 Bot 什么也看不到。
5装上渲染器
每一帧只由时间决定,所以页面可以画出你要的任何一刻。下面的脚本按时间一步步走,每一帧截一张图,直接送进 ffmpeg。这段提示词同时会跑一个小测试(一张卡片弹起、变圆、落回),让你先看到它能工作:
# GrokBot: run this in your terminal exactly as written, then show me the output.
cat > /workspace/studio/render.mjs <<'STUDIO'
// /workspace/studio/render.mjs
// Run it from inside a project folder:
// node ../../render.mjs --dur 15 draft, 30 fps
// node ../../render.mjs --dur 15 --fps 60 --sub 4 final, with motion blur
// node ../../render.mjs --at 0.5,1,1.5 stills only, for quick checks
// more: --w 1080 --h 1920 --audio song.mp3
import { chromium } from 'playwright';
import { spawn } from 'node:child_process';
import { mkdirSync, renameSync } from 'node:fs';
const opt = (k, d) => {
const i = process.argv.indexOf('--' + k);
return i > 0 ? process.argv[i + 1] : d;
};
const DUR = +opt('dur', 15), FPS = +opt('fps', 30), SUB = +opt('sub', 1);
const W = +opt('w', 1080), H = +opt('h', 1920), AUDIO = opt('audio', ''), AT = opt('at', '');
const RATE = FPS * SUB, TOTAL = Math.round(DUR * RATE);
mkdirSync('out', { recursive: true });
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: W, height: H } });
await page.goto('file://' + process.cwd() + '/index.html');
await page.evaluate(async () => { await document.fonts.ready; }); // text needs its fonts loaded
const ok = await page.evaluate(() => typeof window.seek === 'function');
if (!ok) throw new Error('index.html must define window.seek(t)');
if (AT) { // stills mode: one PNG per timestamp
for (const t of AT.split(',').map(Number)) {
await page.evaluate((t) => window.seek(t), t);
await page.screenshot({ path: `out/still-${t}.png` });
}
await browser.close();
process.exit(0);
}
const args = ['-y', '-loglevel', 'error',
'-f', 'image2pipe', '-framerate', String(RATE), '-i', '-'];
if (AUDIO) args.push('-i', AUDIO, '-map', '0:v', '-map', '1:a',
'-c:a', 'aac', '-b:a', '192k', '-shortest');
// motion blur: average SUB subframes into one, keep every SUB-th result
if (SUB > 1) args.push('-vf', `tmix=frames=${SUB},framestep=${SUB}`);
args.push('-r', String(FPS), '-c:v', 'libx264', '-crf', '16', '-pix_fmt', 'yuv420p', 'out/tmp.mp4');
const ff = spawn('ffmpeg', args, { stdio: ['pipe', 'inherit', 'inherit'] });
for (let i = 0; i < TOTAL; i++) {
await page.evaluate((t) => window.seek(t), i / RATE);
const png = await page.screenshot({ type: 'png' });
if (!ff.stdin.write(png)) await new Promise((r) => ff.stdin.once('drain', r));
if (i % RATE === 0) console.log(`${i / RATE}s / ${DUR}s`);
}
ff.stdin.end();
const code = await new Promise((r) => ff.on('close', r));
await browser.close();
if (code !== 0) throw new Error(`ffmpeg exited with code ${code}`);
renameSync('out/tmp.mp4', 'out/final.mp4'); // final.mp4 never exists half-written
console.log('done: out/final.mp4');
STUDIO
mkdir -p /workspace/studio/projects/smoke && cat > /workspace/studio/projects/smoke/index.html <<'STUDIO'
<!-- one card springs up, morphs into a circle, and lands back home -->
<style>
body { margin: 0; background: #111 }
#card { position: absolute; left: 390px; top: 810px;
width: 300px; height: 300px; background: #f2f0e9 }
</style>
<div id="card"></div>
<script>
const card = document.getElementById('card');
const spring = (t, k = 170, d = 20) => { // closed-form spring, 0 to 1, tiny overshoot
if (t <= 0) return 0;
const w = Math.sqrt(k), z = d / (2 * w), wd = w * Math.sqrt(1 - z * z);
return 1 - Math.exp(-z * w * t) * (Math.cos(wd * t) + (z * w / wd) * Math.sin(wd * t));
};
window.seek = (t) => { // pure function of time: no timers, no state
const s = spring(t - 0.3) - spring(t - 1.6); // up at 0.3s, back down at 1.6s
card.style.transform = `translateY(${-480 * s}px) scale(${1 + 0.35 * s})`;
card.style.borderRadius = `${24 + 126 * s}px`;
};
</script>
STUDIO
cd /workspace/studio/projects/smoke
node ../../render.mjs --dur 3 # 90 frames at 30 fps
node ../../render.mjs --dur 3 --fps 60 --sub 4 # 180 frames at 60 fps, motion blur
这样设计的原因:
- 不是实时播放。 某一帧慢了只是多花点时间,不会丢帧。所以没有显卡也没关系。
- 运动模糊是顺带得到的。
--sub 4每一帧取 4 个时刻,再平均成一帧。 final.mp4只在完整渲染完之后才出现(先写到临时文件再改名),队列不会把一次崩溃误当成一条完成的片子。- 日志很少。 Bot 会读脚本打印的每一行,每一行都要消耗用量。
速度方面,作者在一台 2 核、没有显卡的 Linux 机器上量过:15 秒的片子,草稿渲染 48 秒,带运动模糊的 60 帧终版大约 6 分钟。迭代时用草稿,定稿时才渲终版。
6让每一次变化都落在节拍上
自带一首有商用授权的音乐,用脚本把节拍量出来:
# GrokBot: run this in your terminal exactly as written.
cat > /workspace/studio/beats.py <<'STUDIO'
# /workspace/studio/beats.py
# usage: /workspace/studio/.venv/bin/python /workspace/studio/beats.py song.mp3 [clicks.wav] > beats.json
import sys, json
import numpy as np, librosa
y, sr = librosa.load(sys.argv[1], sr=None, mono=True)
tempo, frames = librosa.beat.beat_track(y=y, sr=sr)
beats = librosa.frames_to_time(frames, sr=sr).round(3).tolist()
if len(sys.argv) > 2: # the song with a click on every beat, to check the grid by ear
import soundfile as sf
clicks = librosa.clicks(times=beats, sr=sr, length=len(y))
sf.write(sys.argv[2], 0.7 * y + 0.5 * clicks, sr)
json.dump({
"bpm": round(float(np.atleast_1d(tempo)[0]), 1),
"beats": beats, # every state change lands on one of these
"downbeats": beats[::4], # the big moments (assumes 4/4, first beat = downbeat)
}, sys.stdout)
STUDIO
/workspace/studio/.venv/bin/python -c "import librosa; print('beats.py ready')"
它输出节拍表,还可以另外生成一个 clicks.wav:原曲加上每一拍一声“嗒”,用来靠耳朵检查。
- 先切音乐,再做计划。 3 分钟的曲子有几百拍,切到影片的长度,动画 Bot 只要检查几十张静帧。
- 节拍表要你亲耳确认。 节拍检测有时会锁到反拍上,作者的测试曲目就出现过。嗒声没落在鼓点上,就先修节拍表,再让别人往下做。
- 审片 Bot 听不见。 所以音画同步在渲染之前要过两道:你听
clicks.wav,动画 Bot 每一拍出一张静帧自查。
7审片闭环
流程是:渲染 → 生成审片用的图 → 审片 Bot 打分 → 动画 Bot 修改 → 静帧自查 → 再渲染。

模型不能像人一样看视频,但能看图。下面的脚本把成片变成三张图:
# GrokBot: run this in your terminal exactly as written, then show me the files.
cat > /workspace/studio/qa.sh <<'STUDIO'
#!/usr/bin/env bash
# /workspace/studio/qa.sh projects/<slug>
# Turns final.mp4 into images the Critic can actually look at.
set -euo pipefail
cd "$1/out"
d=$(ffprobe -v error -show_entries format=duration -of csv=p=0 final.mp4)
# contact sheet: 30 frames spread over the whole video, 6 across
ffmpeg -v error -y -i final.mp4 -vf "fps=30/$d,scale=270:-1,tile=6x5" -frames:v 1 contact.png
# phone test: 15 frames at the width a thumb-scroller sees
ffmpeg -v error -y -i final.mp4 -vf "fps=15/$d,scale=360:-1,tile=5x3" -frames:v 1 phone.png
# loop seam: last frame next to the first. if they don't match, the loop stutters
ffmpeg -v error -y -i final.mp4 -frames:v 1 first.png
ffmpeg -v error -y -i final.mp4 -update 1 last.png
ffmpeg -v error -y -i last.png -i first.png -filter_complex hstack seam.png
STUDIO
bash /workspace/studio/qa.sh /workspace/studio/projects/smoke
ls /workspace/studio/projects/smoke/out
| 图 | 内容 | 用来查什么 |
|---|---|---|
contact.png |
全片均匀取 30 帧 | 节奏、变化、有没有空白的停顿 |
phone.png |
15 帧,缩到 360 像素宽 | 手机上还看不看得清字 |
seam.png |
最后一帧和第一帧并排 | 只对循环的片子:两帧不一样,循环处就会卡一下 |
联系表看不出快速动作里的问题,所以审片技能里还有一步:对拿不准的那一秒连取 4 帧。
8定时任务和渲染队列
先是渲染 Bot 要运行的队列脚本,发给渲染 Bot:
# GrokBot: run this in your terminal exactly as written, then show me what it prints.
cat > /workspace/studio/render-queue.sh <<'STUDIO'
#!/usr/bin/env bash
# /workspace/studio/render-queue.sh
# Render's routine runs this. One project per run, one render at a time,
# and never a half-written final.mp4.
set -uo pipefail
cd /workspace/studio
exec 9>.render.lock
flock -n 9 || { echo "BUSY: a render is already running"; exit 0; }
command -v ffmpeg >/dev/null || bash bootstrap.sh # no ffmpeg = the computer was rebuilt
for p in projects/*/; do
p=${p%/}
[ -f "$p/APPROVED" ] && [ -f "$p/READY" ] && [ ! -f "$p/out/final.mp4" ] || continue
fails=$(cat "$p/FAILS" 2>/dev/null || echo 0)
[ "$fails" -ge 2 ] && { echo "STUCK $p: failed twice, needs you"; continue; }
args=$(cat "$p/RENDER" 2>/dev/null || echo "--dur 15 --fps 60 --sub 4")
mkdir -p "$p/out"
if (cd "$p" && node ../../render.mjs $args > out/render.log 2>&1); then
rm -f "$p/FAILS"; bash qa.sh "$p"; echo "DONE $p"
else
echo $((fails + 1)) > "$p/FAILS"
echo "FAIL $p: $(grep -m1 'Error: ' "$p/out/render.log")"
fi
exit 0 # one render per run
done
echo "IDLE: nothing to render"
STUDIO
bash /workspace/studio/render-queue.sh
它保证四件事:
- 同一时间只有一个渲染。 上一个没跑完时再触发,会打印
BUSY并退出。 - 不会无限重试。 失败两次就标为
STUCK,等你来看。 - 电脑重建后能自己恢复。 发现没有 ffmpeg,就先重跑安装脚本。
- 渲染一结束,审片用的图就准备好了。
然后设三个定时任务(官方叫“例程”)。做法是在聊天里告诉对应的 Bot 做什么、什么时候做(译自原文):
【导演,每天 21:00】
检查 /workspace/studio/queue/ 里有没有新的需求。每一份都用 direct-film 技能建好项目,
把分镜表发在这里等我批准。队列是空的就说一声,然后停下。
【渲染,每小时一次】
使用 render-film 技能。如果脚本只打印了 IDLE 或 BUSY,就安静地停下。
【交付,每天 08:00】
对每一个有 PASSED、还没有 DELIVERED 的项目:把 out/final.mp4 和 out/contact.png 附在这里,
加一行说明,然后创建 DELIVERED。
没有我的批准,绝不在任何公开的地方发布。
渲染为什么是每小时而不是每五分钟:动画 Bot 做好之后会直接通知渲染 Bot,定时任务只是兜底。每次运行都消耗用量,空跑也算。 官方帮助中心专门提醒过:每小时一次的计划、过短的间隔,都可能一天就用掉一周的用量;用量下降太快时,先从例程的运行频率入手。
官方文档里和这一步有关的几点:
- 新建的例程要等到下一个计划时间才运行,创建时不会立刻跑。
- 想马上试,用例程里的 Test。测试会执行真实的操作,可能改动文件。先用一个假项目试。
- 时区在设置里,默认跟随本机。
- 长时间不用之后,Grok Bot 可能会问你是否继续运行例程,你不回应它就会暂停。出门回来发现夜班停了,多半是这个原因。
原文还提到每个 Bot 最多 50 个例程、计划之间至少间隔 5 分钟。这两个数字本站没有在官方页面上核对到。
9做第一条片子
三句话,都发给导演。方括号里换成你自己的(译自原文):
【开工】
新片子。使用 launch-spec。
产品:[名称],[网址]。一句话卖点:[一句话]。
功能:[两三个,带真实的数字]。
三张截图、一张参考画面和音乐已经附上。
写代码之前,先给我看落在节拍上的分镜表。
【分镜表和 clicks.wav 都没问题之后】
批准。创建 APPROVED,交给动画。
【随时可以问】
状态检查:列出 /workspace/studio/projects 里的每个项目和它在 STATES.md 里的当前状态,
每个一行。有 FAILS 文件的项目标出来。
之后就是它们自己接力:动画写好并标记 READY,渲染出片并把图发给审片,审片打分,交付在早上 8 点把片子交给你。
一条容易漏的建议:每份需求都附一个参考画面或参考视频。 没有参考,模型会退回到它的默认样子:居中的文字、渐变背景、所有东西一起淡入。官方文档说一条消息最多带 6 个附件,视频最大 200 MB。
常见的问题和处理
| 情况 | 处理 |
|---|---|
| 客户交片后要改 | 把修改意见发给动画 Bot,让它改完后删掉 out/、PASSED 和 DELIVERED,片子会重新走一遍审片 |
| 用量在一周中途用完 | 没开按需用量时 Grok Bot 会停下。开不开,先看用量再决定 |
| 长时间的渲染被中断 | 让渲染 Bot 把队列放到后台运行(见下) |
| 出门几天回来,定时任务不跑了 | 长时间不用后它会询问是否继续,没回应就暂停了。回复它 |
| 片子看起来很套路 | 把它用的默认套路加进 house-style 的“禁用”,并附一张参考画面 |
| 在共用的电脑上做客户的项目 | 文件对每个 Bot 可见,命令行凭据是共享的。客户的登录信息和密钥不要放在这个账户上 |
把队列放到后台运行:
# GrokBot: run this in your terminal.
nohup bash /workspace/studio/render-queue.sh >> /workspace/studio/queue.log 2>&1 &
关于“靠它接单赚钱”
原文的后三分之一讲怎么把这个工作室变成生意:定价、毛利测算,以及加第六个 Bot(Scout)去整理潜在客户的产品信息、先替对方做一条样片再去联系。
这部分本站只转述要点,不照搬其中的价格和收入数字,因为那些是作者引用的第三方报价和个人估算,本站核对不了:
- 卖的是结果,不是“AI 视频”。 用客户真实的界面、交三种画幅、先让客户确认分镜。
- 只用真实的界面和数字。 编出来的界面和数据,客户用不了。
- 音乐要有商用授权,每一首都要看授权条款。
- 先算清自己的成本再定价。 关掉按需用量,完整做一条片子,看它用掉你一周用量的多少。
- 联系客户这一步由人来做。 原文的设计里,Bot 只起草私信,不发送;没有对方同意,不公开发布用别人品牌做的样片。
最后再强调一次开头说过的话:这套流程到作者发文时还没有人公开跑通过。先用那个小测试和一条自己的短片把链路走一遍,再考虑往上加东西。