camera-language.md 23 KB

Camera Language · 运镜导演体系

何时读本文件:画面里出现任何「镜头级」运动之前——zoom / pan / orbit / parallax / 转场 / 定场谢幕,只要动的是「镜头」而不是「元素」,先读这里再写 timeline。 元素怎么动(入场/stagger/物理感)归 animation-best-practices.md; 本文件回答的是镜头什么时候动、动多大、动多久、镜头之间怎么接。 GSAP 侧的可运行实现(rig 容器、PageCam 翻译、对数时长 helper)见 gsap-recipes.md 的「Camera Rig 配方」节,本文只给设计判断和公式。

参数出处标注约定:(HuaRec) = 花录 Studio 运镜导演系统实测参数; (shotcraft) = video-shotcraft 106 卡镜头体系;(实测) = 本 skill 项目实战; (推测) = 通用电影语汇借鉴,参数待实测校准。


§0 · 立论 · 运镜是预算制,不是特效制

大多数 AI 生成动画的运镜是「特效制」思维:哪里能加 zoom 就加 zoom,镜头动得越多越「高级」。 这是晕和廉价感的共同来源。正确的心智模型来自两条公理 (HuaRec):

  • A1 可见性不变量:任意时刻,观众该看的东西必须在可视区内(含 8% 安全边距)。 违反的镜头宁可降倍率、并镜或不拍。
  • A2 舒适预算:每次镜头变化都是一笔注意力消费,必须预算化管理。 预算花完了,再好的镜头也不拍。
预算项 典型值 调节手感
相邻镜头变化间隔 ≥2.6-3.0s(克制档 5.0s) 低于 2.6s 观众开始晕;MTV 式快剪不适用于产品演示 (HuaRec)
任意 15s 窗口内镜头变化 ≤4-5 次(克制档 3 次) 超了就砍最弱动机的那一镜,不是压缩间隔 (HuaRec)
推进倍率下限 1.25x 低于 1.25x 的 zoom 视觉变化感知不足,纯属晃动,不拍(定场 1.06x 是唯一例外)(HuaRec)
推进倍率上限 2.3x(克制档 1.8x) 再高像素密度撑不住,先换素材再谈倍率 (HuaRec)
每分钟镜头数 克制 ≤4 镜/分,常规 ≤6 镜/分 「留呼吸,不是 MTV」(HuaRec)

再叠两条风格公理 (shotcraft):

  1. 电影感 = 运镜 × 光影 × 节奏 × 声音,不等于炫技动画。四个维度各自及格,胜过一个维度拉满。
  2. 节奏偏好单向:宁慢勿快。历史用户反馈全部指向「放慢/停留」,没有一条指向「加快」。 拿不准时长时,选长的那个;拿不准要不要动镜时,选不动。

这两条与 best-practices §0.2 的「礼让观众」同源:镜头是替观众的眼睛做决定, 决定做得越少、越准,观众越信任你。


§1 · 镜头语言词汇表 · 运镜动机决策表

每个镜头动作先问动机:这一镜替观众回答了什么问题? 答不上来就不动。

镜头 动机(什么时候给) 参数区间 禁忌
push in 推近 「接下来看这里」:聚焦一个具体 UI 元素 / 数据 / 关键词;紧张度爬升 倍率 1.3 / 1.45 / 1.8 / 2.3 档(见 §4);时长走对数公式;提前 0.15s 进镜 (HuaRec) <1.25x 不推;滚动 / 切页 / 播视频等全屏级变化期间不推(「滚动时推近会晕」);旁白中段不动镜(见 §6 move on pause)(HuaRec)
pull out 拉远 揭示全貌与上下文:「原来它属于一个更大的系统」;收尾谢幕 时长同对数公式;谢幕拉出 0.55s + ≥0.8s 全景停顿 (HuaRec) 禁「出-进-出」泵动:镜间空隙小于过渡时长时直接接下一镜,不回 1x(见 §5)(HuaRec)
pan 平移 两个中距焦点之间转移(归一化距离 0.22-0.45);一镜扫过多个并列元素 联合倍率 ≥1.25 才值得平移;斜向 pan 用双频正弦(X/Y 频率比 0.22:0.35,振幅 30-40px)(HuaRec / 本 skill 既有) 焦点距离 >0.45 不平移(对角横跳),弃镜;纯单轴 pan 有机械感,优先斜向
orbit 环绕 单主角质感特写,「实体感」最强的一镜;hero 元素立传 rotY 主导 + persp 1100-1200px;实测机位 rotX46/rotY−30/rotZ9 → rotX42/rotY26/rotZ−7 (shotcraft) 一种手法全片只当一次主角 (shotcraft);信息密集画面禁用(机位服务可读性,文字多就正视)
dolly zoom 「世界观反转」的揭示瞬间:主体不变、语境剧变 伪配方见 §8:主体钉死,背景 scale 1→2.0-2.5 + opacity ≤0.6 (shotcraft) 全片最多一次;无叙事落差时用它 = 纯炫技
静止 文字阅读、真人速度交互演示、信息密集镜头;预算不足时的默认答案 品牌字标落定 hold ≥1s;批量动效收尾 0.5s 静止;开场主体动作弧 ≥3s (shotcraft) 无。静止不动永远是合法选择,「不给镜头」本身就是导演决定

两条横向规则:

  • 速度感来自加速度,不是匀速快 (shotcraft)。匀速运动读作廉价 PPT; 想要「快」的感觉,用短促的加速段 + 长缓冲,不是把整段 duration 砍半。
  • 机位服务可读性 (shotcraft):信息密集镜头正视;文字特写用侧向水平机位 (rotY 主导、rotX 很小);禁全局一刀切倾斜;产品宣传片默认不加手持抖动。

§2 · zoom vs dolly 选型 · 3D 真假裁决

「推近」有两种实现,观感完全不同,先选型再写代码:

维度 zoom(scale 缩放) dolly(perspective + translateZ 前移)
视差 无。所有层等比放大,画面是「一张图被放大」 有。近层快、远层慢,画面是「镜头在空间里前进」
观感 干净、信息型,适合 UI 特写 / 数据聚焦 空间感、电影感,适合 hero 展示 / 氛围段落
成本 低:单个 transform 高:需要分层结构 + preserve-3d,且有栅格化发糊问题(§3.4)
选型规则 内容是平面信息(界面、文档、图表)→ zoom 内容有明确的「前景/主体/背景」层次,且这层次值得被看见 → dolly

3D 真假裁决(化解本 skill 两处旧文矛盾的边界线):

  • 参与 3D 的元素 ≤8 个 → 用真 translateZ 分层(best-practices §4.7 的黄金角配方照用)
  • 元素 ≥20 个 → 放弃真 3D,用 shadow / blur / 明度差做假深度(hero-case-study 的立场)
  • 8-20 之间 → 问一个问题:这段镜头需要视差吗?需要才上真 3D,不需要就假深度。 真 3D 的成本不在写,在调:每加一层就多一组「透视失真 + 文字发糊 + 层级穿插」要排查。

§3 · Camera Rig 实现约定

镜头运动和元素动画不许抢同一个 transform。所有镜头级运动收口到一个专职容器上。

3.1 分层容器结构

<div id="viewport">          <!-- 固定视口,overflow: hidden,持有 perspective -->
  <div id="camera">          <!-- 镜头层:只承载相机 transform,别的什么都不干 -->
    <div id="world">         <!-- 世界层:所有画面内容住这里,元素动画只动 world 内部 -->
      ...场景内容...
    </div>
  </div>
  <div id="hud">             <!-- 字幕 / 角标 / chrome:与 #camera 平级,天然不跟镜头动 -->
  </div>
</div>

分工铁律:

  • #camera 上只出现镜头 tween(translate / scale / rotate / zoom 属性),元素入场、stagger、 hover 态一律写在 #world 内部的元素上。两层互不知晓,镜头随时可以整体重排而不碰元素动画
  • 字幕和 chrome 首选放 #hud,零成本保持静止;只有「必须跟着 world 里某元素走、 但字号要恒定」的标注(如跟随 tooltip),才在该元素上做 counter-transform: scale(1/zoom) 反向抵消镜头缩放,每帧与相机同步更新
  • transform-origin 就是推进目标点:平面 zoom 把 origin 设到目标元素中心再 scale, 等价于「镜头对准它推近」。PageCam 模式下由 cx/cy 承担同一职责

3.2 PageCam 关键帧模型(shotcraft,2.5D 相机数学)

把镜头状态定义成关键帧对象,镜头运动 = 关键帧之间插值:

{ frame, cx, cy, zoom, rotX, rotY, rotZ, persp }

cx/cy 是世界坐标系里镜头对准的点,zoom 是倍率。以 1920×1080 画布为例 (其他尺寸把 960/540 换成 W/2、H/2):

平面模式(无旋转,纯 zoom + pan):

transform: translate(960 − cx·zoom, 540 − cy·zoom) scale(zoom)
transform-origin: 0 0

3D 模式(有 rotX/rotY/rotZ):

外层(#camera): perspective: persp·zoom;  perspective-origin: 960px 540px
内层(#world):  zoom: {zoom};                        /* 注意是 CSS zoom 属性,见 §3.4 */
                Tx = 960/zoom − cx;  Ty = 540/zoom − cy
                transform: translate(Tx, Ty) rotateY() rotateX() rotateZ()
                transform-origin: cx cy
                transform-style: preserve-3d

典型机位参数 (shotcraft 实测):全页 zoom 0.78 → 特写 2.6; 侧拍 rotY34 / rotX8 / persp1200(侧拍优于俯拍,rotY 主导 + rotX 只给一点); orbit 起止机位见 §1 表。

3.3 rig 施工注意(镜头专属坑)

  • pan 露边#world 必须比视口大(四周外扩 bleed ≥ 最大 pan 振幅 + 8% 边距), 否则平移时露出画布外的空白。这是 A1 可见性公理的反面:不该看的也不能看见
  • perspective 被打断#camera#world 之间的任何中间层加了 overflow: hiddenfilteropacity <1 都会创建新 stacking context, 杀掉 preserve-3d,3D 分层瞬间变平。3D 模式下滤镜效果只加在最内层元素上
  • 逐帧越界兜底 (HuaRec):镜头焦点跟随动点时,每帧检查目标是否越出可视区, 越出则保持倍率、只沿越界轴做最小修正拉回边界。宁可镜头「让一步」,不许目标出画

3.4 CSS zoom 栅格化技法 · 根治 3D 文字发糊(全库最贵知识,shotcraft)

问题:3D 模式下用 transform: scale() 放大页面,Chromium 按元素的布局尺寸栅格化, 再把位图放大,文字必糊。倍率越高糊得越狠,2x 以上不可交付。

解法:放大不走 transform: scale,走 CSS zoom 属性zoom 是布局级缩放, Chromium 按放大后的尺寸重新 layout 并栅格化,文字在任意倍率下保持矢量级锐利。 §3.2 的 3D 模式公式里内层写 zoom: {zoom} 而不是 scale({zoom}),正是为此。

配套要点:

要点 做法 出处
坐标补偿 zoom 改变布局坐标系,translate 量要除以 zoom:Tx = 960/zoom − cx(§3.2 公式已含) (shotcraft)
与 reflow 禁令的关系 gsap-recipes §6.2 禁 tween 布局属性是因为整数 snap 抖动;zoom 是整页级缩放,snap 量不可感,且文字锐利收益远大于。此技法是 §6.2 的唯一合法例外,只用于 #world 相机层 (实测)
渲染环境 HyperFrames / Playwright 离线逐帧 seek 渲染下完全适用:每帧重 layout 的耗时不影响产物,只影响渲染时长。实时浏览器 preview 可能掉帧,属正常,以渲染产物为准 (shotcraft)
位图素材增强 全页截图用 2x 采样;特写元素另备 4x 单独截图,在推进期用 6f 交叉淡入盖住低倍纹理 (shotcraft)
景深氛围 DoF 只做氛围:顶部渐变带 blur + mask,不做逐层真实景深 (shotcraft)

§4 · 镜头缓动与时长

4.1 缓动词汇

场景 easing 调节手感
主动运镜(推近/拉远,有明确起止点) cubic-bezier(0.65,0,0.35,1) = GSAP power3.inOut 两端都稳,「导演给镜头」的感觉;绝不线性、绝不弹簧过冲 (HuaRec)
跟随式运镜(镜头追一个已开始的动作) cubic-bezier(0.33,0,0.15,1) 出发轻快、刹车极长,镜头像「跟上去」而不是「切过去」;shotcraft 相机默认
持续漂移(idle drift、匀速巡览) sine.inOut yoyo 或 none 唯一允许相机匀速的场景(gsap-recipes §1 既有规则);有起止点的动作禁用
光标/焦点跟随平滑 quickTo + ~0.15s 平滑;路径插值 Catmull-Rom 前向+后向 EMA 的零相位思路:跟得紧但不抖 (HuaRec)

两套默认冲突时的裁决:单次推拉信 HuaRec(power3.inOut),复合移动、 多段连续镜头信 shotcraft(0.33,0,0.15,1)。

4.2 zoom 时长对数公式(固定 duration 是业余感的来源)

所有推拉时长由倍率变化量决定,保证任何幅度的 zoom「视觉速度」一致:

duration = 0.55 × |ln(zoom₂ / zoom₁)| / ln 2      clamp 到 [0.30, 0.94] 秒

1→2x 推近正好 0.55s;1→1.3x 约 0.30s(触底);0.78→2.6x 触顶 0.94s。(HuaRec) 大景别过渡更久、小景别更短,防「一蹿到位」也防「拖沓」。

4.3 zoom 档位表

档位 倍率 用途 调节手感
定场微推 1.06x 仅用于开场定场(§6),观众感知不到 zoom、只感知到「画面活着」 唯一允许低于 1.25x 的档位 (HuaRec)
轻推 1.3x 提示性聚焦:不打断全局阅读,只是「注意这一片」
中推 1.45x 标准 UI 特写:一个面板 / 一段代码
重推 1.8x 单元素特写:一个按钮 / 一个数字 克制档的上限 (HuaRec)
上限 2.3x 极限特写,素材必须扛得住(2x 截图 / 4x 切片,§3.4) 超过就换素材,不硬推 (HuaRec)

定景公式 (HuaRec):scale = 0.8 / max(目标包围盒归一化宽, 高),再夹到档位区间。 内容占可视区 80%,留 20% 呼吸,不顶格。

4.4 节奏预算(与 §0 预算表联动)

  • 相邻镜头变化间隔 ≥2.6-3.0s;15s 窗口 ≤4-5 次 (HuaRec)
  • 动作前 0.15s 进镜(镜头先到,动作后发生),动作结束后停留 1.2s 再走 (HuaRec)
  • 时长 <1.2s 的孤立小动作不值得单独给镜头,防「点一下泵一下」(HuaRec)

§5 · 镜间语法 · 防晕核心

晕不是单个镜头造成的,是镜头之间的接法造成的。 「出-进-出」泵动和远焦点连续横跳 贡献了绝大多数眩晕感 (HuaRec)。对相邻两镜(间隔 <1.5s),按焦点距离三分:

焦点归一化距离 接法 说明
<0.22(近) 并镜 合并为一镜:取两目标的联合包围盒重算倍率,一镜看完
0.22-0.45(中) 改平移 宁可倍率广一点(联合倍率 ≥1.25),一镜平移过去,不做「出再进」
>0.45(远/对角) 弃镜 砍掉动机更弱的那一镜。绝不连拍两个远焦点,对角横跳是最晕的一种接法

补两条时序规则 (HuaRec):

  • 间隙短则直接对接:相邻镜头空隙小于过渡时长时,不回 1.0x,直接从当前倍率过渡到 下一镜的倍率和焦点。回 1x 再推是「泵动感」的直接来源
  • 间隙 ≥1.5s 才允许「拉出再推进」:观众有足够时间在全景里重新定位,出-进才不晕

§6 · 电影开闭幕 · 定场、谢幕、move on pause

三条语法成本极低,作品感提升明显 (HuaRec):

  1. 定场(establishing shot):片长 >14s 且首个正式镜头在 7s 之后时, 开场插入 [0, 3.0s] 的 1.06x 中心微推:开机即处于轻推近态,3 秒内缓出落回全景。 观众的第一感受是「镜头是活的」,而不是「PPT 开始播放了」
  2. 全景谢幕铁律:末镜提前收口,留出 0.55s 拉出过渡 + ≥0.8s 全景停顿。 成片永远以全景静止收尾,绝不在推近态戛然而止。与 best-practices「戛然而止 + hold」 收尾完全兼容:hold 的那一帧必须是全景
  3. Move on pause:cut on action, move on pause。有旁白的动画里,镜头移动如果撞在 说话中段,向早处吸附到最近的语音静默点(最多前移 0.8s,只提前不推后)。 观众在听觉空档移动视线的认知成本最低。解说 pipeline(voiceover-pipeline.md)排镜头时 直接拿 narration 的分句间隙当吸附点

§7 · 转场语法表 · 三层词汇

转场是独立层:接缝按能量落差选型,一个接缝只用一式,转场帧从相邻镜头预算里划走。 「公认优秀的发布片全程没有一次裸切」(shotcraft)。

7.1 shot-transitions 六式(有存在感的转场,用于能量落差大的接缝)

适用能量落差 参数
流白 flash-wash 高→高,段落强转 白场 2-4f 峰值,两侧各 5f 渐变 白闪只盖切点,不当装饰反复用
穿暗场 dip-to-dark 高→低,情绪降档 压暗到 rgba(20,20,20,0.9) 量级,总长 ≤0.6s 暗场里别停留,观众以为片子结束
虚焦接力 defocus-handoff 中→中,平级话题切换 出镜 blur 0→8px 与入镜 blur 8px→0 交叠 ≥8f blur 大面积 ≤24px(DoF 性能约束)
黑场字卡 title-card 章节级分隔 字卡 hold ≥1s,前后各 0.3s 过渡 全片 ≤2 张,多了像幻灯片
whip-pan 甩镜 低→高,能量急升 两端 hold ≥20f → 8f 甩 1.5 屏,峰值 ≥300px/f 才糊得透 (shotcraft) 慢了就是普通 pan,糊不透反而露拙
mask-wipe 穿窗 空间转移,「穿过一个界面进入另一个」 遮罩缘 easing (0.4,0,0.6,1) (shotcraft) 遮罩形状必须来自画面内已有元素(窗口/卡片圆角),凭空的形状是 slop

7.2 hidden-cut 三式(观众察觉不到切过的转场)

做法 出处
flash-cut 白闪跨切 白闪跨骑硬切点,两侧各 5f,只盖切点 (shotcraft,实证参数)
前景遮挡切 一个前景元素(卡片/面板/光标手)扫过全屏的瞬间换景 (推测:通用电影语汇,参数待实测)
运动糊切 高速运动峰值帧上硬切,两侧运动方向一致,motion blur 吞掉切点 (推测:通用电影语汇,参数待实测)

7.3 travel 两式(空间连续的转场,能量不落差、场景在移动)

做法
共享元素归位 前镜的某元素(logo/卡片)连续运动到后镜中它的新位置,FLIP 思路的镜头版 元素在两镜中必须同一身份,形变过大就断了「同一个东西」的认知
字腔穿越 镜头推进穿过大字的字腔(O/口/0 的空洞)进入下一场景 字腔尺寸要够(≥1/3 屏高),穿越段 zoom 走对数时长上限 0.94s

选型速查:能量落差大 → 六式挑一;不想被察觉 → hidden-cut;两个场景空间上连续 → travel。 硬切不是禁用,是「必须被上述任意一层包装过」。


§8 · 多层 parallax 配方 · 伪 dolly-zoom

8.1 parallax 层速度系数 (shotcraft)

参数 典型值 调节手感
层速度系数 远景 0.35 / 中景 0.7 / 近景 1.4(相机位移的倍数) 相邻层速比 ≥2 倍才可辨,1.2 倍的差异观众读不出来
层数 ≤4 层 超过 4 层的视差没人看得出来,纯浪费预算
实现 各层根据同一个相机 x/y 乘各自系数 translate 全部由相机状态推导,seek-safe;别给每层独立 tween

8.2 伪 dolly-zoom(纯 CSS,无需真 3D)

主体:钉死不动(或只做 ≤1.02x 的呼吸)
背景:scale 1 → 2.0-2.5,同时 opacity 降到 ≤0.6

主体不变、背景涌向观众,产生「世界在逼近而主角凝固」的反转感 (shotcraft)。 时长给足(≥1.2s),用途见 §1:全片最多一次,留给真正的揭示瞬间。


§9 · 运动派生信号 · blur / 跟随 / 余震

镜头的「速度感」不靠更快的 duration,靠从速度派生出来的次级信号 (shotcraft / HuaRec):

信号 公式 参数
速度驱动 blur v = velocityAt(f)(中央差分:(pos(f+1)−pos(f−1))/2),blur 强度 ∝ v zoom 速度 >0.6/s 才触发,强度 min(10, v×5)px。只在动的瞬间有模糊,静止帧永远锐利 (HuaRec)
lagged 跟随层 跟随层 = 主体在 f − delay 处采样 阴影滞后 2f、残影滞后 4f (shotcraft)。残影平替 motion blur:5% 路径滞后 + blur(6px) + opacity 0.25·(1−t)
dampedSettle 余震 e^(−d·t) · sin(2π·f·t),f≈0.1、damping≈0.15 镜头急停后的 1-2 个微小残摆,幅度 ≤3px;主动运镜(§4.1 inOut 族)不加,只给 whip-pan / 急刹类

三者全部是时间的纯函数(差分、延迟采样、闭式衰减),天然 seek-safe, 符合 gsap-recipes §6 的确定性要求。


§10 · 运镜自检清单(写完 timeline 后 60 秒)

  • 每个镜头动作都答得出「替观众回答了什么问题」?答不出的删了吗?
  • 没有 <1.25x 的 zoom(定场 1.06x 除外)?
  • 相邻镜头间隔 ≥2.6s,15s 窗口 ≤4-5 次?
  • 所有推拉时长走对数公式,没有拍脑袋的固定 duration?
  • 推拉 easing 是 power3.inOut,没有 linear / 弹簧过冲?
  • 相邻镜头按焦点距离做过三分裁决(并镜/平移/弃镜)?没有两连远焦点横跳?
  • 间隙短的镜头直接对接,没有回 1x 的泵动?
  • 片长 >14s 且首镜晚于 7s:加了 1.06x 定场微推?
  • 结尾是全景静止 ≥0.8s,不在推近态收尾?
  • 有旁白:镜头移动吸附到了语音间隙(只提前 ≤0.8s)?
  • 镜头运动全部收口在 #camera 层,没和元素动画抢 transform?
  • 3D 文字特写走了 CSS zoom 栅格化,没有 scale 放大发糊?
  • 每个转场接缝只用一式,全片没有裸切?
  • parallax 相邻层速比 ≥2 倍、≤4 层?
  • blur 只出现在运动瞬态,静止帧全部锐利?

§11 · 与其他 reference 的关系

reference 分工 边界
animation-best-practices.md 元素怎么动、叙事节奏、品味标准 它管「演员」,本文件管「摄影机」;S4 爆发段的「镜头拉远」按本文件 §4 定参数
gsap-recipes.md 本文件所有规则的 GSAP 可运行实现 「Camera Rig 配方」节:rig 容器、PageCam 翻译、对数时长 helper、counter-transform
animation-pitfalls.md 踩坑清单 镜头专属坑(scale 发糊 / perspective 被打断 / pan 露边)§3.3-3.4 已覆盖设计侧,pitfalls 收技术侧复现
hyperframes-backend.md 渲染后端契约 CSS zoom 技法在离线逐帧渲染下的适用性见 §3.4
voiceover-pipeline.md 解说驱动长视频 move on pause(§6.3)的静默点数据从 narration 分句间隙来
ai-video-review.md 成片评审 评审 checklist 的转场分类按 §7 三层词汇扩展

调用顺序:导演稿 / 分镜阶段读 §0-§2 定预算和词汇 → 写 timeline 前读 §3-§7 定实现约定 与接缝 → 交付前过 §10 清单。