| name | product-motion-gif |
|---|---|
| description | 把一张产品图/场景图/人像图变成可循环的动图。原理是让 GPT-Image 2.5 一次性生成 4x4 多格帧图,再切帧、修循环缝、按节奏合成 GIF/WebP/MP4。四类动效:A 相机环绕(默认「左→右 60°」)、B 相机锁死+角色自己做动作(可无参考图从零画游戏人物招式)、C 相机锁死+背景后掠的速度型动作、D 机位锁死+只变表情(人像表情包)。触发词:产品动图、产品 GIF、环绕动图、旋转动图、多格图、frame sheet、turntable gif、product animation、动作 GIF、游戏人物 GIF、角色动图、表情包、表情 GIF、夸张表情、让图动起来。 |
| agent_created | True |
product-motion-gif
产品图/场景图 → 可循环动图。核心是 GPT-Image 2.5 的一致性:一次生成 4x4=16 帧多格图, 再切帧合成。不要一帧一次生成——那样漂移严重且贵。
什么时候用
- 用户给产品图或场景图,要"动起来"的展示素材(环绕、旋转、悬浮)。
- 用户不给参考图,只说"生成一个 XX 在做 XX 的动图"(角色招式 / 游戏人物动作)——
apiz_image.py的--ref是可选的,纯文本生成也支持(见下"四类动效")。 - 用户给人像/人脸图,要做"表情包"(同一个人做一整套夸张表情,如"周星驰那种夸张")
—— 用 D 类模板
prompts/face-expression-loop-4x4.txt,参见"四类动效"。 - 输出目标:微信/详情页可用的 GIF、现代平台用的 WebP、投放用的 MP4。
不适合:多主体互动、复杂剧情动作、刁钻运镜、需要 48 帧以上的长动画。
四类动效,别抄错对方的写法
| A. 相机绕场景(orbit 系列) | B. 相机锁死、角色做动作(char-action-fixed-4x4.txt) | C. 相机锁死、背景后掠、角色做动作(char-action-scroll,待固化) | D. 机位锁死、只变表情(face-expression-loop-4x4.txt) | |
|---|---|---|---|---|
| 参考图 | 必须给 | 不用给,从零画 | 不用给,从零画 | 必须给——脸就是身份 |
| 相机 | 绕主体扫 60° | 完全不动(no orbit / zoom / dolly / pan) | 完全不动 | 完全不动,且锁得最死 |
| 背景 | 必须横移——转动的唯一线索(硬规则 17) | 纹丝不动 | 必须向后掠——速度感的唯一来源(近快远慢视差) | 纹丝不动(纯黑底最稳) |
| 主体 | 居中不动,转动由背景承载 | 居中,动作全在它身上 | 居中,动作在它身上,它不横穿画面 | 一张脸(头肩),居中等大,只有面部肌肉在变 |
| 循环 | --loop pingpong(硬规则 3) | --loop cycle,cell 16 收回起手式闭环 | --loop cycle,整圈动作(如空翻 360°)首尾同姿 | --loop cycle,cell 16 收回 cell 1 的中性脸 |
| 适用 | 产品/场景展示 | 招式、技能、站立动作 | 飞行、奔跑、冲刺这类有速度的动作 | 表情包、面部情绪演出 |
A 的"背景必须横移"照抄进 B 会把平涂底搅花;B 的"背景纹丝不动"照抄进 C 就没有速度感; C 的"背景后掠"照抄进 A 会让环绕读成推轨;把 B/C 的全身动作写法抄进 D 会让脸在画面里乱跑。
D 类三条专属写法(照抄自模板,别删):
- 机位锁得比 B/C 更死。 脸对平移的敏感度远高于全身——全身横移 1% 看不出来, 脸横移 1% 就已经像在点头晃脑。所以模板里那句 "nothing in the picture changes except the expression on it" 是核心约束。
- 允许点名"节拍",但接缝要写成过渡。 硬规则 5 禁止分段描述是针对连续量(角度、位移) 的;表情是离散状态(中性 / 坏笑 / 震惊 / 大笑),本来就该分节拍。写法:节拍只落在 具体格号的 ANCHORS 上(cell 1 / 5 / 9 / 12 / 16),并加一句 "the face never snaps instantly from one extreme to another"。
- 所有不对称特征必须显式给方位,且统一用观众视角。 只写 "a crooked smile" 不写左右,
模型会逐格随机镜像,观感就是脸在抖。用
the corner of the mouth on the viewer's left, 不要用his left(模型常算反)。
D 类首个实例:m1.jpg 低多边形人像做夸张表情包(中性→挑眉坏笑→瞪眼震惊→咧嘴大笑→回中性),
2K / 3:4(单格 384×512)/ Flare,prompt 5305 字符 → D:/image25/gif-lab/out/face-expr/。
尚未经用户验收,暂不并入硬规则。
C 类提示语要点:把"角速度"写成可数的整数步(如 15 equal steps of 24 degrees = 整圈 360°),
并明写"背景每格后掠相同的量、近处比远处走得远";同时保留 B 类的身份锁与人口线。
C 类首个实例:孙行者翻筋斗云飞速前进(任天堂 3D 卡通渲染 + 蓝天绿丘后掠 + 完整前空翻),
prompt 5975 字符 → D:/image25/gif-lab/out/monkeyking/。尚未经用户验收。
稳定性最好的区间是「纯色 / 影棚背景 + 单主体 + 简单动作」。平涂底的全出血插画 (整幅就是纯色底、没有道具,如 k1)实测主体一致性同样很好、可以放心用——难点不在画得像不像, 而在转动读不读得出来:背景没东西可横移时只能靠主体剪影承载,必须按硬规则 17 把 "该变的部件"逐个写清。真正的雷区是背景杂乱 + 多主体:越界会随机抖动、画面漂移, 甚至出现生物/物理准确性错误。
前置条件
apizCLI 已安装并登录(apiz auth status)。模型见下"模型选择"。- Python 需
Pillow、numpy;MP4 需要ffmpeg。 - Windows 上若
bash报head/ls: command not found,先补 PATH:export PATH="/c/Windows/System32:/c/Windows:/c/Users/49707/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin:$PATH"
模型选择(省钱技巧)
| 模型 | 用途 | 实测成本(high/2K) |
|---|---|---|
apiz/gpt-image-2.5-flare | 试 prompt 阶段默认用这个 | 16:9 → 39 points;4:3 → 53 points |
apiz/gpt-image-2.5-sunburst | 定稿出正式版 | 约为 Flare 的 2 倍(16:9 → 78 points) |
两者参数完全相同,改 --model 即可切换。试错一律走 Flare。
尺寸档位:默认 2K;用户要"更清晰/4K"时才上 4K
默认一律 --size 2K。 用户明确说"不清晰""来个 4K"时才用 --size 4K
(那是授权花钱,否则算擅自重跑——见「验收」一节)。
要分清两件事,别只记住"4K 是假的":
一、4K 不是原生 4K 生成。 实测(Flare / high / 4:3 / 4K)元数据:
"upstream_width": 2048, "upstream_height": 1536 ← 上游其实只生成 2K
"target_width": 3264, "target_height": 2448 ← 放大 1.59 倍交差
"scale": 1.5938
"price": 133 ← 2K 是 53
二、在"固定输出尺寸"下比锐度,4K 白花钱。 同一素材、同样输出 640×480:
| 素材来源 | 拉普拉斯锐度 | 高频能量占比 |
|---|---|---|
| 2K → 640 | 22.35 | 51.4% |
| 4K → 640 | 23.08(+3.3%) | 52.9% |
差异在噪声量级,肉眼不可辨。
三、但 4K 真正的价值是"可用的原生输出上限"——这才是它该用的场合:
| 生成尺寸 | 单格像素 | 能原生输出的长边 |
|---|---|---|
| 2K | 384×512(4:3) | 512,拉到 640 已经在放大 1.25 倍,发软 |
| 4K | 612×816(4:3) | 816,零放大 |
→ 成品长边 ≤ 512px:用 2K,省 2.5 倍钱。
→ 成品长边要做到 800px 左右:2K 在物理上供给不了像素,必须用 4K
(j1 的 816×594 原生版就是这么来的;i1 用户说"不清晰"的根因也是这个,
不是合成参数问题)。
→ 想再大只能改网格(3×3 → 2K 下单格 682px),代价是帧数变少、流畅度下降。
→ 跨版本比清晰度用 scripts/compare_clear.py(同格归一化到同一显示尺寸 + 2x 局部放大),
别凭感觉说"更清晰了"。
透明底 + 像素风:五条链路硬约束(已实测)
这一节的每一条都是踩出来的,不是猜的。
一、透明底走 --transparency,返回的是 PNG。
apiz_image.py --transparency → params.transparency = true,实测返回 content_type: image/png,
带 alpha 通道。make_gif.py --bg transparent 配合使用(--bg auto 也会自动识别出 alpha)。
二、模型给的 alpha 是"柔边"的,而 GIF 只有 1-bit 透明。
实测一张透明底像素图:alpha 有 255 种取值,alpha == 0 占 50.7%,
其余从 1 连续过渡到 254,没有任何一个像素是 255。
giflab.quantize_frames 用 > 128 阈值二值化,后果是:
- 轮廓上 1–2px 的羽化被切掉或补上 → 边缘变硬(像素画正合要求,无害);
- "半透明残影 / 柔光拖尾"会被阈值化成实心色块,观感是脏污而不是残影。 → 要干净的残影/拖尾,必须在 prompt 里要求"用实心像素画残影,不许半透明"。 → WebP 支持真 alpha,是透明素材的正确载体,必须同时交付 WebP。
三、像素风必须 --resample nearest --no-dither。
默认 LANCZOS 会把硬边糊掉;Floyd 抖动会在平色区撒噪点,并在透明轮廓上造出成片半透明像素。
两个开关都是为像素风加的(resize_all(resample=...) / quantize_frames(dither=...))。
四、--size 只能取"源单格长边"或它的整数分之一,否则像素块大小不均匀。
resize_all 按"长边 = --size"等比缩放。用 NEAREST 做非整数倍缩放 = 像素块一大一小
(1px、2px、1px、2px…),这是像素画最显眼的硬伤。
→ 2K 4:3 单格是 512×384,所以 --size 用 512(不缩放) 或 128(精确 1/4)。
→ 坑:--trim union 会改变帧尺寸(实测 512×384 裁成 460×384),
此时按 512 输出等于 NEAREST 放大 1.11 倍,正好踩中上一条。
像素风请用 --trim none(顺带白送一个好处:16 格画框完全一致,对游戏素材是加分项),
或先看日志 global crop ... -> WxH 再定 --size。
五、透明底 + WebP(method=6) 很慢,别用前台跑;失败先查真实原因。
- 透明 512px × 16 帧导出 WebP 实测 > 3 分钟,前台默认 120s 超时会把它 SIGTERM 掉,
且输出走管道是块缓冲的,日志全丢——现象是"exit 1 / SIGTERM / 无任何输出"。
→ 长任务一律
run_in_background;python -u关缓冲看实时日志。 - 透明素材跳过 MP4(
--no-mp4):export_mp4把帧合成到白底,透明信息本就不存在。 - apiz 生成失败时别猜:
apiz tasks get <task-id>能拿到result.error。 实测一次失败的真实原因是Your request did not meet content safety guidelines. Your tokens have been credited back——疑似被run-and-gun(含 "gun")触发,改成action platformer后同一份 prompt 一次通过。 内容安全被拒不扣 points(已退回),可以直接改词重试。
标准流程
SK="D:/image25/.workbuddy/skills/product-motion-gif"
PY="C:/Users/49707/.workbuddy/binaries/python/versions/3.13.12/python.exe"
# 1. 参考图入库,拿公网 URL(apiz 只吃 URL,不吃本地路径)
apiz upload ./product.jpg --folder myproj
# -> https://cdn-hk.51sux.com/storage/myproj/....jpg
# 外链图可直接转存:apiz transfer "<url>"
# 2. 生成 4x4 多格图(prompt 用 prompts/ 下的模板,按主体改前两段)
# 默认模板 prompts/orbit60-l2r-4x4.txt = 左 30° → 右 30°(见硬规则 1)
# 画幅跟随原图:方形→1:1,4:3→4:3,16:9→16:9,竖构图(如 1024×1598)→2:3
# 默认 --size 2K;只有用户要求"更清晰/4K"时才改 4K(见「尺寸档位」)
# ⚠ 整份 prompt 必须 ≤6000 字符:实测 6449 可用、9213 被接口拒收
# (HTTP 400 "prompt 必填且长度为 1-4000 字符")。
# 注释/变更记录写进同名 .notes.md,不要混在 prompt 文件里;
# apiz_image.py 会自动截掉单独成行 "---" 之后的全部内容(TO OPERATOR / CHANGE LOG)。
# 它会打印 "[apiz_image] prompt chars: N",超限直接本地报错,不浪费请求。
"$PY" "$SK/scripts/apiz_image.py" \
--ref "<上一步的 URL>" \
--prompt-file "$SK/prompts/orbit60-l2r-4x4.txt" \
--out out/sheet.json --model apiz/gpt-image-2.5-flare \
--quality high --size 2K --ratio 4:3
# 3. 切帧编号 → 立刻给人看多格图(不能省、不能拖,也别忘了给人"怎么看")
"$PY" "$SK/scripts/contact_sheet.py" out/sheet.jpg out/contact.png 4 4 480
"$PY" "$SK/scripts/ab_frames.py" out/sheet.jpg out/ab-01-16.png 1 16 4 4 620
"$PY" "$SK/scripts/motion_smooth.py" out/sheet.jpg 4 4 # 量化数字,仅作参考
# 4. 切帧 + 合成
"$PY" "$SK/scripts/make_gif.py" --sheet out/sheet.jpg --outdir out/run1 \
--rows 4 --cols 4 --canvas tight --bg auto --loop pingpong \
--keep-frames --quality-report out/run1/qa.json
产物:animation.gif、animation.webp、animation.mp4,加 frames/ 和 qa.json。
(--size 640 --timing ramp --duration 70 --ramp 2.6,0.7,1.8 --max-kb 3000 都已是默认值,
不用重复写。)
硬规则
前两条是已验收的效果标准,改动前先问用户。
展示类环绕默认「左 → 右 60°」,不要 180°、也不要用 90°。(已验收) 准确指:cell 1 = 参考视角左 30°、cell 8 = 正好是参考视角、cell 16 = 参考视角右 30°, 相机从左往右扫过 60°,参考视角落在整张表的正中间。 模板:
prompts/orbit60-l2r-4x4.txt(默认)。验收历程:180° 太大(依次看到正面→侧面→背面,那是"转圈圈"不是"产品展示")→ 90° 仍偏大 → 60° 通过 → 方向从"单向 0°→60°"改成"左 30°→右 30°"后转角明显更好读 (j1 实测花树/瀑布/木船相对峰体大幅换位,比此前各版都明显),故定为默认。
prompt 里必须写死这一句,否则模型会把 cell 1 当成参考视角、整段扫描偏 30°:
Do not start the sheet at the reference viewpoint - cell 8 is the reference viewpoint.注:"环绕"指相机绕场景转,不是模型自转(要明写 "it is the CAMERA that orbits"); 边界仍是不越过正侧面、绝不露背面。要右→左扫就镜像 LEFT/RIGHT 与锚点描述。
合成默认用"前慢后快"节奏(
--timing ramp,已是默认)。 用户要求:开头慢、逐渐加快,让观众看清起始画面。 默认形状--ramp 2.6,0.7,1.8+--duration 70,实测 30 帧停留时长:180×6 → 170×4 → 160×2 → 150×3 ... → 70×2 → 60×2,总约 4.0 秒。--timing even是备选(按每格实际变化量分配时间,追求恒定速度感时才用)。旋转/环绕类必须
--loop pingpong。 16 帧只覆盖单程角度,正向播完再镜像回退才无缝(共 30 帧)。用auto会退化成cycle,接缝处硬跳。原因:旋转被判为pose-change,而halfloop只在kind == "translation"时生效,loopcut找不到匹配姿态。默认不要逐帧稳像(
--stabilize off,已是默认值)。 这是最容易踩的坑:逐帧稳像给每一帧算一个不同的位移量,"漂移估计误差"直接变成 帧间抖动。实测一张真实环绕图:pose jitter 指数 1.87(原始)→ 2.22(开稳像)→ 1.88(关掉)。它非但没让画面更稳,反而制造了抖动。 注意:环绕时主体本来就会横向位移,这是真实视差,不要拿稳像去抹平它。 只需要整体重新居中时用--stabilize anchor——一次性常量偏移,帧间关系完全保留。prompt 里禁止分阶段描述镜头,要用"线性插值 + 每格增量相同"。 写成"第 1–4 格近景、第 5–11 格后拉、第 12–16 格全景",模型就会在阶段交界处猛变 (实测第 3→4 格明显跳变)。正确写法是把 16 格定义成一次连续运动的 16 个等时间采样: "cell 1 是起点,cell 16 是终点,中间的每一格恰好落在同一条线性插值的等比位置上; 任意相邻两格之间的变化量完全相同;全程没有加速、停顿、快段或慢段"。
prompt 必须写明"是相机在环绕,不是模型在自转",并用数字封顶。 否则模型会去转模型本身,几何会崩。同时钉死:固定距离/高度/焦距、地平线不漂、 全程恰好 N 度、分成等步、每格主体完整不出格、场景内每个物体的形状位置颜色不变、 纯色无缝背景、无文字水印边框。 量化封顶比定性描述有效得多,例如:
apparent size changes by less than 5%、max 8% horizontal travel。稳像若真的开启,填充色必须是不透明画布色,否则出黑边。
shift_frame默认fill=(255,255,255,255)。若填透明(0,0,0,0), 后续convert("RGB")会把透明像素压成纯黑——这就是 GIF 边缘那道黑边。 只有真正的透明底素材才传(0,0,0,0)。 同理quantize_frames/export_webp走flatten_rgb()合成到画布色,不要直接 convert。只做 4x4 / 16 帧;GIF 体积上限 3MB。 帧数越多漂移和抖动越明显,成本还翻倍。体积上用户明确 3MB 可接受 (
--max-kb 3000)。超出预算时阶梯会先降尺寸再降色数,最低不要跌破 460px/96 色 (那个档位明显发糊);宁可放宽预算,也不要用糊的档位交付。 注意 2K 生成 + 4x4 时单格只有 512px,所以 640px 是放大得来的;细节密集的素材 在 3MB 内通常只能保住 544px 左右,交付时把实际尺寸说清楚。多张参考图时,在 prompt 里写清每张的职责。 实测「外观图 + 剖面图」一起喂时, 模型会默认把剖面图也画进画面。必须显式分工:
Image 1 (exterior) is the MAIN VIEW/Image 2 (cutaway) is the STRUCTURE REFERENCE ONLY - do NOT draw the cutaway, do NOT open up the walls。"锁构图"会直接抹掉旋转——大主体/全出血素材必须放开。(已验收) 环绕之所以"看起来在转",靠的是背景视差(近处划过、远处慢移)+ 主体相对画面自然移动。prompt 里写
every cell shows the whole subject, complete and uncropped/consistent margins/背景元素形状位置固定,等于把仅有的两条旋转线索封死 —— 模型会走最安全路径:几乎照抄原图 + 微小抖动,观感是"抖/呼吸"而不是"转"。实测(同素材、同模型、同角度,只改这三条写法,g1.jpg):
| 写法 | motion 判定 | area_cv | 15 步总变化量 | |---|---|---|---| | 锁构图(主体不出格 + 背景不动) |
translation| 1.3% | 2.225 | | 放开(漂移 + 视差 + 角度锚点) |pose-change| 5.1% | 3.315 |放开写法三件套(模板见
prompts/orbit60-drift-4x4.txt):- 要求主体在画格里漂移,允许跑出画格边界,明写"不许逐格重新居中、不许保持边距不变"。 ⚠️ 这一条后来被用户改掉了:默认应改为主体居中、由背景横移体现转动 (硬规则 17)——因为"相机始终瞄准主体"本身就和"主体必须漂移"冲突。 只有主体大到居中会让画面呆住时才回退到漂移版。
- 要求背景视差,明写"背景元素不许钉死在原位置";
- 给三个具体视觉锚点:cell 1 = 参考图原视角、cell 8 ≈ 28°(哪一侧开始转出视线)、
cell 16 = 60°(哪一侧转到画面中央、谁进入画面、谁被遮住)。
再加一句失败判据:
A sheet in which the subject is in the same orientation in every cell is a FAILED sheet.
适用边界(重要):主体小、居中、四周有留白的静物摆件(乐高摆件那类)可以继续锁构图, 60° 已经验证有效;主体大 / 全出血插画 / 特写构图则必须放开,否则转不动。 代价是姿态一致性下降(马腿、披风形状会漂)——这是取舍,不是 bug。
复合运动(环绕 + 推近/拉远)时,QA 的
area_cv阈值是误报。area_cv > 12%会触发verdict: REVIEW / silhouette area varies 47.9% - subject may be reshaping。但只要 prompt 里刻意要求了 dolly,面积大幅变化就是设计要求,不是缺陷。 实测 i1.jpg(60° 环绕 + 推近 30%):area_cv = 49.4%→ QA 报 REVIEW, 而检查表上"由远到近"正是用户想要的效果。 → 遇到 dolly 时不看area_cv的绝对值,改看它是否单调增长(不允许中途缩回去)。 → 同理,prompt 里"apparent size < 5%"这条封顶必须删掉并改成"面积匀速单调增长约 N%", 否则和 dolly 直接冲突。 → 复合运动的代价:帧间步长容易忽大忽小(i1 实测0.213 0.335 0.276 0.303 0.335 0.336 0.768 0.767 0.188 0.330 0.296 0.652 0.606 0.593 0.144,step_cv 1.175), 比单一环绕(step_cv 0.446~0.7)差。追求平顺就做单一运动,追求冲击力才叠复合运动。素材形态决定交付格式和体积档位——插画类必须放宽或改走 WebP。 实测同参数下 GIF 的表现差异极大:
| 素材 | 默认 3MB 预算 | 放开后 | WebP 同帧 | |---|---|---|---| | 纯色背景静物(i1 乐高山峰) | 480×640 / 255 色 / 3.8MB | 同左(已到上限) | 651KB 满分辨率 | | 全出血插画(g1 武将) | 345×460 / 96 色 / 2.9MB(发糊档) | 408×544 / 192 色 / 4.7MB | 1576KB 满分辨率 |
原因:GIF 调色板对大面积平坦色块很省(纯色背景素材 3MB 就能给到 480×640), 对全出血画作极不划算(没有平坦区,3MB 直接把画面打到 345px/96 色, 就是硬规则 8 里标"明显发糊、不要交付"的那一档)。 → 静物/纯色背景:GIF 3MB 够用,照常交付。 → 全出血插画/照片:
--max-kb 6000起步,并必须同时交付 WebP—— WebP 满分辨率只要 GIF 的 1/3 体积,是这类素材的正确载体,GIF 只留作兼容。参考图自带水印时,必须在 prompt 里显式禁止复现。 实测有效(g1 武将右下角小红书水印、h1 骑士右下角小红书水印,两版都清干净): 在 REFERENCE 段说明"参考图带水印",并在 OUTPUT 段写
do NOT reproduce it, and do not reproduce any other logo, handle or overlaid image。 只写笼统的no watermarks不够——要把它点名到"参考图右下角那一个"。主体自身带强运动趋势时,转向会被抵消。(待验证) 实测 h1.jpg(马朝左下方奔驰奔跑)用同一套 v2 写法,只拿到
translation / area_cv 1.5% / 总变化 1.755,明显弱于 g1(静止昂扬姿态,pose-change / 5.1% / 3.315)。推测模型把"相机绕行"与"主体奔行"混在一起, 两个运动互相抵消。样本数 1,尚未定论;遇到"主体正在飞奔/冲刺"的素材时, 预期转向会打折,可考虑改用"推近"这类不依赖旋转的动效(见硬规则 11)。场景内角色动作("镜头之外还有个东西要动一下")要单开一段,并配双失败判据。(已验收) 用户可以在环绕之外要求"画面里的某个角色动一下"(j1.jpg:猴子沿山脊走路)。写法:
- 单开一段
THE <ROLE> - the only moving thing in the whole scene,写清四件事: 动作方式(如"四条腿交替、一组前摆另一组支撑、尾巴轻摆、头保持平视朝行进方向")、 总位移(如"全程约 1.5 倍身长")、匀速不停、保持同一比例与颜色; 再列出禁止项(不跳、不爬、不站起、不转身、不跑、不变大变小、不换位置、不出画、 不消失、不许出现第二只)。 - 其余段落改成
WHAT MUST NOT CHANGE - everything EXCEPT the <role>:所有道具/建筑/ 液体锁死(瀑布不流、船不漂不摇、水面不荡)。 - 失败判据从一条扩成两条:①16 格视角相同 = 失败;②16 格角色姿态相同 = 失败。
- 验证方法:整格对比看不出小角色动没动,必须用
scripts/cell_zoom.py把同一区域 跨格放大并排看(j1 实测猴子从山脊左端走到右峰下,一眼可见)。 - 一个能自证方向的现象:相机往右转会让画面内容向左移,如果小角色在画面里往 相反方向移动,就证明是它自己走的,不是被镜头带过去的。
- 单开一段
提示语必须先指名"绕的是谁"(
SUBJECT段),且整份 prompt ≤6000 字符。- 不指名主体,模型就不知道角度绕哪个轴量,容易退化成平移或原地微动。
默认模板已加
SUBJECT - the pivot the camera circles段,且必须放在REFERENCE之前(先指名,再描述)。三个模板(旧版)此前全无此段, 只在相机行里以 "the scene / the subject" 抽象带过——这是被用户点出来的真实缺口。 - 长度上限:实测 6449 字符可用、9213 字符被接口拒收,报
HTTP 400 … prompt 必填且长度为 1—4000 字符。 → 整份 prompt 控制在 6000 字符以内。 → 注释 / 变更记录 / 操作说明写进同名.notes.md,不要混进 prompt 文件。 →scripts/apiz_image.py已加两道保护:单独成行的---之后全部截断 (TO OPERATOR / CHANGE LOG 不再发给模型);超限直接本地报错, 并打印[apiz_image] prompt chars: N。
- 不指名主体,模型就不知道角度绕哪个轴量,容易退化成平移或原地微动。
默认模板已加
主体居中、由背景横移体现转动(已验收)。(用户决定,替换旧的"主体必须漂移"写法)
always aimed at the subject与the subject must DRIFT … may run off the frame edge互相冲突:始终瞄准轴心的相机,会把主体稳在画面中部,由背景横移体现转动。 所以 prompt 里写的是:主体保持在画面中部、不逐格重新构图、不左右滑动、不变尺寸。- 背景是平涂无特征场时(纯色底、暗色底、无道具,如 k1 的青色场):没有东西可横移 → 转动只能由主体剪影承载。必须逐个写出"该变的地方"(哪一侧躯干朝前、腰带结与 侧缝落点、近侧肩膀遮住多少、飘带投射到画面哪一处),并写上一句 "a frozen pose seen from a new angle is not the same picture"。 只写一句 "silhouette must change" 不够——k1 验收版正是把 3–5 处逐项列出才成立的。
- 模板
prompts/orbit60-l2r-4x4.txt的SUBJECT段与HOW TO MAKE THE ORBIT VISIBLE第 2 条已按此重写,含金句与占位提示,不要改回去; 填写要点见orbit60-l2r-4x4.notes.md。 - 反例(重要):对同一素材,**"主体必须漂移、可以跑出画格"**的旧写法(k1 第一版) 被用户否决("很小的动,根本没有旋转");改成主体居中之后才通过。
验收(最重要的一条)
质检数据只是参考,不是标准;出图了就要尽快给用户自己看。 流程必须是:
- 出图即交付,不要拖。 多格图生成完 → 立刻跑
contact_sheet.py出带帧号检查表; 合成完 → 立刻把 GIF / WebP 交给用户。不要为了"先自己判一遍"而延后交付, 也不要拿量化数字当结论。 - QA /
motion_smooth等一切量化数字只作参考,用途是提示"哪里可能有问题" (比如某一步跳变、边缘不干净),不能用来判定效果好坏:area_cv、pose在轮廓近似的宽扁场景上会失灵(见「判读 QA 报告」最后一条), 数字说"平移"而肉眼明明在转的情况真实发生过。 - 人是唯一验收标准,AI 自查不算数。 用户看了一眼说"行",才算过。
- 不要在用户验收前就把"经验"写进本文件——没验收的优化是瞎优化。
- 交付时带上"怎么看":给首尾帧对比图(
ab_frames.py)、动作特写(cell_zoom.py), 让用户一眼能判断,而不是丢一个 GIF 让他自己猜。 - 交付时不写效果判断。 不要写"这次转得很明显""效果比上一版好"这类结论——用户明确
批评过 AI 乱下判断。可以说的只有中性事实(帧数、尺寸、体积、某格有跳变这类客观观察)
和中性的"怎么看"(哪张对比图看哪两格)。尤其不要把 QA 的判定转述给用户:
pose-change/translation在这类素材上会整体反报(见「判读 QA 报告」的 k1 反例)。 - 重新生成多格图(花 points 的调用)必须先经用户同意;用户主动说"来个 4K / 重跑" 即视为授权。本地合成(切帧、合成、导出)不花钱,可以直接做。
判读 QA 报告
先记住:这一节的数字全部只是参考,不是结论。 用它们找"哪里可能有问题", 效果好不好由用户看图和 GIF 判。数字与肉眼冲突时,以肉眼为准。
{
"motion": {"kind": "pose-change", "area_cv": 0.06}, // 环绕=pose-change
"loop": "pingpong",
"border": {"mean_rgb": [139.5, 208.9, 253.0], "near_black_fraction": 0.0},
"output": {"timing": "ramp", "dwell_ms": [180, 180, ...]},
"verdict": "PASS | REVIEW"
}
黑边只认
near_black_fraction(接近纯黑的像素占比),不要用亮度判定。 稳像填充透明的特征是 RGBA→RGB 压成(0,0,0),真实主体/阴影/彩色背景三个通道 不会同时全黑。之前的版本按"外圈亮度 < 235"判暗带,遇到蓝色影棚背景(RGB 约140,209,253,亮度天然只有 200)会 100% 误报,也会把"主体故意出画"误判成黑边。 判定:near_black_fraction > 2%才算真黑边。mean_rgb是给人看的,用来确认外圈 是不是背景色本身。 例外(已实测):素材背景本身就是纯黑时(如 m1 人像表情包,背景是刻意的纯黑底),near_black_fraction会报到 93.7% 并给出verdict: REVIEW+pure-black band on the canvas border ... the stabiliser filled with transparent—— 这是预期值,不是黑边(该条判据默认"外圈非黑才算正常",黑底素材天然违反它)。 此时改看两点确认:darkest_channel≈ 0 且mean_rgb就是设定背景色 → 忽略该 issue。 注意--bg auto也会报同一类误判:auto从四角采样背景色,剪影式深色头发容易把 采样带偏、主体框跟着飘。背景是纯黑/纯色时直接写死--bg 0,0,0(或对应 RGB),不要用 auto。area_cv超过 12% → 主体在"变形"而不只是"移动",多半是多主体或复杂动作。 (60° 环绕实测 6% 左右;180° 全环绕会到 50%+,属正常。) 例外:prompt 里刻意要求 dolly(推近/拉远)时,area_cv大是设计要求,不是缺陷 —— 见硬规则 11,此时改看面积是否单调变化。"到底转没转"——四步判定,顺序不要乱:
motion.kind:translation= 只有平移没有换角度;pose-change= 真的换了姿态/视角。 环绕类通常应当拿到pose-change。但它会误报,不要当铁证。- 先看步长序列的形态,再看总量。
pose step per frame如果是高低交替 (0.117 0.166 0.082 0.168 0.077...),说明在原地来回摆,观感是抖不是转; 应该是平稳推进(缓慢递减、末段收一下也算正常)。 - 总量只作辅助参考,绝不能单独下结论。 实测 g1 同素材同角度:锁构图写法
translation / 1.3% / 总变化 2.225→ 放开写法pose-change / 5.1% / 3.315。 但 k1 给出了完全相反的结果(下一条),总量大 ≠ 转得好——摆动同样能把总量堆大。 - 最后用
scripts/ab_frames.py把 cell 1 和 cell 16 并排放大看一眼确认。
k1 反例:QA 的结论可能与人工验收完全相反——一切以肉眼为准。 同一素材(全出血平涂底单主体)先后两版:
| 版本 | QA
kind| pose 总量 | 步长形态 | 用户结论 | |---|---|---|---|---| | 第一版 |pose-change| 3.81(更大) | 高低交替0.098 0.095 0.195 0.190 0.230 0.423 0.199 0.449…| 否决("很小的动,根本没有旋转") | | 验收版 |translation| 1.53(更小) | 平稳0.236 0.151 0.060 0.119 0.088 0.051 0.036 0.138 0.106 0.057 0.050 0.062 0.049 0.062 0.270| 通过 |原因:这两个指标测的是整幅轮廓。平涂背景的单主体素材,剪影在 16 格里高度相似, 于是"原地来回摆"被判成
pose-change、"真正绕轴扫过"被判成translation——判定整体反了。 同类还有 j1:QA 报translation / area_cv 2.8%,而宽扁景观 + 纯白背景从任何角度看轮廓 都差不多,内部结构(瀑布、花树、木船)其实已经大幅换位。 → 结论:平涂底 / 全出血 / 宽扁轮廓近似 这三类素材,kind、area_cv、pose 总量全部不可用, 只能靠scripts/ab_frames.py(首尾帧)+scripts/cell_zoom.py(局部)+ 人眼判。 交付时不要把 QA 结论说给用户听(会误导),只给图和 GIF。dwell_ms在 ramp 模式下应当单调递减;若成片顶在下限 60ms,说明收尾偏慢。判断"抖"来自模型还是合成:
motion_smooth.py跑多格图得jitter_idx(模型的责任), 再跑合成后的 frames/ 得另一个值。后者明显更高 = 合成环节在恶化,先查--stabilize。输出尺寸会被体积预算反推。
--max-kb是硬预算:阶梯会从--size起逐级降尺寸、 再降色数,直到塞进预算。所以 3MB 预算下不一定能拿到 640px —— 细节密集的素材 (樱花树、砖墙纹理)压缩率低,可能落到 544px。日志里gif ... (WxH ...)报的是实际 落地尺寸,要以它为准(曾有个 bug 把尺寸静默压回源单格宽度,导致 GIF 比同帧的 WebP 还小)。
文件
scripts/apiz_image.py— apiz CLI 包装,生成多格图并落 JSON(--model可切 flare/sunburst)。scripts/giflab.py— 库:切帧、遮罩、稳像(含 anchor)、节奏曲线(even_durations/ramp_durations)、循环修复、调色板、导出。scripts/make_gif.py— CLI:多格图进,GIF/WebP/MP4/QA 出。scripts/contact_sheet.py— 把多格图切成带帧号的检查表,交给用户逐帧验收。scripts/motion_smooth.py— 量化帧间均匀度(jitter_idx)。scripts/verify_edges.py— 按播放器合成方式量 GIF 边缘,验证黑边是否清净。scripts/ab_frames.py— 抽任意两帧并排 2x 放大,用来肉眼确认"到底转没转" (判定流程第 4 步;python ab_frames.py sheet.jpg out.png 1 16 4 4 460)。scripts/cell_zoom.py— 跨格放大同一小块区域并排,用来确认场景里的小角色/小物件 是否真的动了(整格对比看不出来的,它一眼就能看)。见硬规则 15。 用法:python cell_zoom.py sheet.jpg out.png "1,5,9,13,16" 0.40,0.12,1.0,0.55 4 4 2.2 monkey(第 4 个参数是格内相对坐标 x0,y0,x1,y1,取值 0–1)。scripts/compare_clear.py— 跨版本清晰度对照:把两张多格图的同一格归一化到 同一显示尺寸并排,再叠加 2x 局部放大。比"2K vs 4K"这类差异靠它,别凭感觉。python compare_clear.py A.jpg B.jpg out.png 16 4 4 816 "2K->640" "4K->816"。prompts/char-action-fixed-4x4.txt— 无参考图 / 单角色动作模板(B 类):相机锁死、 角色自己完成一套连续动作、特效为唯一可变元素。含CHARACTER/LOOK/THE ACTION/CAMERA - LOCKED/WHAT MUST NOT CHANGE/FAILURE段与<<< >>>占位。 本体 5800 字符(贴近 6000 上限,填充后必须复测)。填写要点与防坑清单在char-action-fixed-4x4.notes.md。首个实例:唐僧 + 九环锡杖聚气挥出金光, 4:3 / 2K / Flare,prompt 5204 字符 →D:/image25/gif-lab/out/tangmonk/。 效果尚未经用户验收,暂不并入硬规则。prompts/char-action-fixed-4x4.notes.md— 上者的填写说明(怎么指名角色、道具怎么当刚体 写、动作为什么要写成"一条弧 + 三锚点"、为什么用cycle而不是pingpong)。不进 prompt。prompts/face-expression-loop-4x4.txt— 有参考图 / 机位锁死 / 只变表情模板(D 类): 头肩特写,用于表情包。含SUBJECT/CAMERA - LOCKED/LOOK/THE EXPRESSION ARC(5 个 ANCHORS)/WHAT MAY CHANGE / WHAT MUST NOT/FAILURE段与<<< >>>占位。 本体 5917 字符(贴近 6000 上限,填充后必须复测)。填写要点在face-expression-loop-4x4.notes.md。首个实例:m1.jpg 夸张表情包, 3:4 / 2K / Flare,prompt 5305 字符 →D:/image25/gif-lab/out/face-expr/。 效果尚未经用户验收,暂不并入硬规则。prompts/face-expression-loop-4x4.notes.md— 上者的填写说明:四类动效对照、 为什么 D 类机位要锁得最死、为什么 D 类允许分节拍(与硬规则 5 的关系)、 左右方位为什么必须用viewer's left、以及两个必须记住的坑 (--trim必须用none、黑底用--bg 0,0,0不要用auto)。不进 prompt。prompts/orbit60-l2r-4x4.txt— 默认模板:左 30° → 右 30°(60° 相机环绕, 参考视角在表中间),见硬规则 1。含SUBJECT段(硬规则 16)、HOW TO MAKE THE ORBIT VISIBLE四条(硬规则 10 / 17)、动作段(硬规则 15)的<<< >>>占位,共 9 组。模板本体 5886 字符(限 6000,见硬规则 16)。 填写要点与操作说明在orbit60-l2r-4x4.notes.md(不进 prompt)。prompts/orbit60-4x4.txt— 旧默认:单向 0° → 60° 相机环绕(历史版本, 转角不如"左→右"好读,除特殊需要否则用 l2r 那版)。prompts/orbit60-drift-4x4.txt— 主体漂移版(历史版本,别默认用):60° 环绕 + 放开 构图锁(主体漂移 + 背景视差 + 角度锚点)。硬规则 10 的实测对照就是它跑出来的(g1 已验收)。 用户后续已把默认改成主体居中、背景横移(硬规则 17),默认请用 l2r 那版; 仅当"主体极大、居中会让画面呆住"时才回退到它。文件末尾有---之后的操作说明。prompts/orbit60-dollyin-4x4.txt— 复合运动:60° 环绕 + 由远到近推近约 30%, 见硬规则 11。注意它没有"尺度变化 <5%"封顶,改成"面积匀速单调增长"。prompts/orbit60-two-ref-4x4.txt— 双参考图版(外观主视角 + 结构参考),见硬规则 9。prompts/turntable-180-4x4.txt— 180° 环绕(单主体产品,历史版本)。prompts/orbit-reveal-180-16x9.txt— 宽幅场景 180° 环绕 + 后拉揭示,16:9(历史版本)。README.md— 面向非技术使用者的白话说明(无命令、无参数),第二节是五类效果的 案例集(A 环绕 / B 角色动作 / C 速度型 / C2 像素透明 / D 表情包),每类一张真实成品的 GIF + "你会提供什么 / 你可以这么说 / 适合什么"。用户是要"发给朋友/同事看"的场合, 给这份,不要给 SKILL.md。cases/— README 案例集用的成品动图(约 7.5MB,纯展示用,不是素材):A-orbit-60-l2r.gif(218×320/30 帧,原README-demo.gif)、B-character-action.gif(640×480,唐僧锡杖聚气)、C-scroll-flight.gif(640×480,孙行者翻筋斗云)、C2-arcade-transparent.gif+.webp(512×384,街机像素透明底,webp 是真 alpha 版)、C2-arcade-pixel128.gif(128×96 老街机颗粒)、D-expression-loop.gif(180×240 表情包)。 新增案例就往这里放并同步 README 第二节的表格;A 类那张就是早期的README-demo.gif, 不要在原位置重复放一份。
