Communitygithub.com

pisakhov/x-motion-prism

与核心 x-motion 技能配合使用,当影片主题应为光线、玻璃和色彩在静止状态下的表现(折射、色散、焦散、透镜),并在明亮的纸白色摄影棚中确定性渲染,配以合成的玻璃质感配乐。

x-motion-prism 是什么?

X Motion: Prism 是核心 x-motion 方法的一个主题,它将艺术指导、物理模拟和声音设计整合为一个高度专业化的风格。该技能强制实现严格的、基于物理的管线:渲染采用线性光,光谱颜色通过波长到 RGB 的函数计算(而非手动选取),声音则通过模态合成和确定性音频图生成。它明确规定了一种视觉语言,以浅色、无彩色的环境(纸、石、石墨)为基础,光谱色仅出现在色散发生处,例如棱镜后或焦散边缘。整个制作过程需遵循 9–10 秒的脚本节拍(静止、到达、现象、稳定、释放),并使用确定的函数(如 mulberry32 和解析波方程)确保可重复的渲染。X Motion: Prism 支持在任何能够运行 JavaScript 和 WebGL2 的浏览器环境中使用,并包含一个确定性渲染清单,确保帧精确的可重复性、无网络依赖以及青春永久性输出。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pisakhov/x-motion/tree/HEAD/skills/x-motion-prism

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

X Motion: Prism

Prism 是核心 x-motion 方法的一个主题。请遵循该方法(简介、主题、故事板、动态分镜、制作、有限批评)。该文件增加了使其主题可识别并保持诚实的艺术指导、物理和声音内容。

视觉主题

让一种光学现象显得精准且安静地奇妙,将其像静物般在苍白的工作室中拍摄,让观众注意到光线的实际行为。

  • 每部电影一个主角现象。 色散、焦散、透镜成像、全内反射、菲涅尔边缘。其他一切都是它落脚的平静表面。
  • 物理决定颜色的去向。 世界是无彩色的:纸、石、石墨。光谱色仅出现在波长分离的地方(棱镜形成的扇形、透镜的边缘、焦散的边缘),而不在其他任何地方。
  • 亮度即是情绪。 这与暗色空间主题相反。阴影是柔和的石墨色,永不黑色;高光是一种光感,永不霓虹。
  • 相机是三脚架。 锁定或几乎不可察觉的推进。现象移动;观察者不动。

调色板

角色十六进制用途
纸#f2efe9主表面,环境日光
阴影中的纸#d9d4cb主光区域之外的区域
苍白石头#e6e1d8地板、水池、基座(使用低频噪声在 ±3% 范围内变化)
石墨#5d5b57印刷线条、接触阴影(透明度 20–60%)
深石墨#3a3936允许的最深值,仅在接触折痕中使用
水色#d8e6e4在石头上方以“正片叠底”模式叠加用于表示浅层清水
光谱计算得出仅通过波长到 RGB 函数生成,绝不用手动选取的彩虹

在线性光中工作,叠加光能量,然后进行一次色调映射并转换为 sRGB。在明亮背景上的叠加光谱色会发白,因此需要局部降低背景亮度(在主角周围创建柔和的阴影区域,约 45–60% 线性亮度),以使颜色看起来饱和,并保持画面的其余部分通透。

灯光和材质

  • 主光: 一个来自左上方的柔光日光源,与画面轴成约 30–45° 角。阴影长、柔和且略带暖灰色。
  • 玻璃: 透明、无色、无瑕。其存在通过四件事来体现:后面物体的折射、一条细菲涅尔边缘、一个柔和的窗户反射以及它投射的焦散或光谱光。不要用倒角发光、有色玻璃或光晕。
  • 折射率: Cauchy 色散公式 n(λ) = A + B/λ²,λ 以 µm 为单位。普通玻璃:A = 1.5046, B = 0.0042。当色散需要在屏幕上可读时,将 B 放大至多约 3 倍,并在你的备注中说明。
  • 纸和石头: 哑光,对比度极低的纹理(亮度变化 2–4%),静态。精细的印刷线条是具有柔和衰减的石墨色,线宽 1.2–2 px。
  • 接触: 每个接触表面的物体都有一个紧密、更深的接触阴影加一个宽而软的阴影。这是让玻璃看起来“搁置”而非“漂浮”的关键。

构图

  • 充足的留白:主角约占画面的三分之一;其余部分为带有柔和渐变光照的纸或石头。
  • 将事件放在三分之一线或黄金分割点上,除非影片是关于对称性,否则绝不放在正中心。
  • 用光引导视线:光束、滚动方向或涟漪应朝向将要发生高潮的地方。
  • 保持画面边缘安静且稍暗(来自照明而非黑圈的 6–10% 晕影)。
  • 无文字、UI、标志或装饰性粒子。如果现象需要比例参考,请使用印刷网格、石头接缝或阴影。

运动词汇与节奏

动词:进入,弯曲,展开,扫描,聚焦,涟漪,稳定。 移动的名词:光、水、单个物体。相机和主体绝不能同时移动。

节拍在 9–10 秒影片中的典型占比行为
静止10–15%空旷且灯光就绪的场景。让观众阅读表面。
到达15–20%光或物体沿着清晰路径以减速缓和曲线进入。
现象35–45%主角效果缓慢发展和变化(旋转几度、滚动、涟漪)。
稳定20–25%运动被物理减振(摩擦力、阻尼、波扩散)并停止。
释放5–8%光线变暗或图像静止,以便循环和音频尾部能闭合。
  • 使用物理闭合运动:滚动用恒定减速,稳定用阻尼余弦,展开的环用 1/sqrt(r) 幅度,旋转用缓和角度。
  • 当动画化光束头部时,玻璃内的光线明显比空气中慢 (v_玻璃 = v_空气 / n)。这是一个微小但观众能感受到的真实细节。
  • 优先使用一个长姿势而不是几个短姿势。完整旋转太多;4–10° 足以扫出光谱。

声音调色板与混音

声音是玻璃、空气和水,经过调谐。它应该让人感觉像一个有坚硬、干净表面的房间。

  • 玻璃泛音: 模态合成,带有几个非谐泛音(对于敲击的玻璃,接近 1, 2.32, 4.25, 6.63 的比例),每个都有自己的指数衰减;高频泛音衰减更快。
  • 手指在玻璃上: 一个或两个正弦波,具有缓慢的 0.3–0.6 秒膨胀、4–5 Hz 颤音(±0.15%)和一丝同音高的带通噪声。
  • 空气: 粉红偏置种子噪声通过带通 (300–2500 Hz),非常低,缓慢呼吸。它是房间本身,而非风声。
  • 水: 气泡“噗通”声是频率在 30–80 毫秒内指数上升约 30–60% 的正弦波;柔和的冲刷声是低通噪声。
  • 和声: 选择一个调性并坚持使用(开放五度、加九和弦、利底亚色彩)。将现象映射到音高:光谱位置对应音级,速度对应滤波器截止,暂停对应解和弦的钟声。
  • 空间: 一个种子合成卷积混响 (2.5–4.5 秒,尾部变暗),所有声音共享,干/湿约 60/40。
  • 目标: 集成响度约 -18 LUFS,真峰值低于或等于 -1.5 dBFS,0.3 秒淡入,每个尾部在结束前衰减 0.4 秒。

技术方案

纯粹的关于时间的函数。 每一帧都从 t 重新计算整个场景:物体姿态、光束头部、波相位。仅使用种子随机性。

const mulberry32 = s => () => { s |= 0; s = s + 0x6D2B79F5 | 0;
  let t = Math.imul(s ^ s >>> 15, 1 | s); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
  return ((t ^ t >>> 14) >>> 0) / 4294967296; };

分析场景,少量渲染通道。 使用少量分析形状(平面、球体、作为一组平面的凸棱镜)进行求交,而不是光线行进。将在 JavaScript 中计算的随时间变化的状态(角度、位置、光线路径)作为 uniforms 传递。将帧拆分为小的单用途通道(地面、半分辨率下的光场到 RGBA16F 目标、顶部的玻璃),而不是一个包含分支的着色器。

从波长生成光谱色。 使用平滑的分析拟合,使扇形看起来像光,而不是渐变色条。对多个波长样本求和并进行归一化,使总亮度为中性白色。

float gauss(float x, float m, float s) { float u = (x - m) / s; return exp(-u * u); }
vec3 spectral(float nm) {             // 平滑拟合,线性 RGB,可见窗口 372-712 nm
  float w = smoothstep(372., 392., nm) * (1. - smoothstep(690., 712., nm));
  return w * vec3(gauss(nm, 606., 46.) + 0.14 * gauss(nm, 420., 22.),  // 红色在紫色部分仍有贡献
                  gauss(nm, 543., 44.),
                  gauss(nm, 452., 34.));
}

在明亮背景上,紫色端看起来是淡薰衣草色;这是诚实的,所以给它一个更暗的局部区域来取代强行提亮它。

每波长折射。 使用不同折射率(红、绿、蓝或更多)对同一条光线追踪两到三次。结果一致的地方,获得清晰的中性细节;结果偏离的地方,恰好获得物理规律所放置的色边。

vec3 col;
for (int k = 0; k < 3; k++) {
  float n = 1.5046 + B * 3.0 / pow(LAMBDA[k], 2.0);
  col[k] = traceThroughGlass(ro, rd, n)[k];  // 折射进入,折射离开,采样地面
}

无需模拟的焦散。 对于一个由几个解析波构建的水面 h(x, t),到达其下方地板上一点的光线强度与 1 / |det(I + d · Hess h)| 成比例,其中 d 是深度除以折射率。以解析形式计算 Hessian 矩阵(正弦波和径向环束均有闭合形式),用 1 / sqrt(det² + ε²) 软化奇点,并用三个略有不同的 d 值计算,以获得细薄的光谱边缘。

平面上的光线。 掠过纸张的光束是其轴线上的 1D 高斯函数 exp(-(dist/w)²),外加一个更宽、更淡的光晕。光束头部沿路径以缓和距离前进;用短的 smoothstep 截断,而非硬边。

带限印刷。 从点到最近线条的距离(使用碰撞点的 fwidth)绘制网格线,使得线条在任何放大倍数下保持 1.5–2 px 柔和,包括在透镜内部。当单元格缩小到几个像素以下时,淡出到印刷的平均色调,而非空白纸张。对放大的墨水给予最小柔和度(约其宽度的一半),否则球透镜下的线条会变成剃刀般锋利的楔形。

float lines(vec2 p, float s, float w, vec2 fw) {
  vec2 d = abs(fract(p / s + .5) - .5) * s, a = max(fw * .8, vec2(w * .55)), wd = max(vec2(w), a);
  vec2 l = (1. - smoothstep(wd - a, wd + a, d)) * clamp(vec2(w) / wd, 0., 1.);
  return mix(max(l.x, l.y), 4. * w / s, smoothstep(.18, .42, max(fw.x, fw.y) / s));
}

玻璃需要有足够暗的东西来折射。 在白色工作室中,完美的球体看起来会呈现乳白色。在环境地平线附近设置灰色墙壁、一个紧凑的柔光箱和一个黑色挡板;球内部的倒置地平线和窗口将描绘出其形状。计算所有路径时不使用分支,以便 fwidth 保持有效,并输出解析覆盖率(光线到中心距离与半径之比,以像素为单位)作为 alpha。

色调与收尾。 指数型肩部 1 - exp(-1.85 x) 使纸张保持在 #f2efe9 附近,而焦散峰值柔和地滚降;然后转换到 sRGB。每个通道的肩部会将明亮的光谱带漂白成柔和色,因此对于彩色光,大约一半向保色调曲线混合(对最大通道进行色调映射并缩放),由色度门控,以便纸张不受影响。完全保色调或锐化带间颜色会将橙、黄、青压平成扁平的红色、绿色和蓝色条纹。以数值方式检查扇形:在其上采样一列,确认色相仅上升一次,从红色 (约 10°) 到紫色 (约 270°),无环绕。仅添加一个静态的亚单位抖色(±0.6/255)以打破浅色渐变中的条纹;永不逐帧动画化。

速度。 SwiftShader 使用软件渲染,并且对着色器中的每条指令(包括任何像素都不执行的分支)都进行计费。保持每个通道单一用途,以半分辨率渲染柔和光场,并将昂贵的通道(玻璃、棱镜内部)剪刀到对象的投影包围盒,使用 SRC_ALPHA, ONE_MINUS_SRC_ALPHA 与地面进行混合。在调整精修前,测量 1920×1080 下的每帧秒数;fbm 最多 5 个八度。

确定性音频图。 Chromium 以未指定的顺序将三个或更多连接合并到一个 AudioNode 中,因此两次渲染会相差约 1e-6 并失败字节检查。在 JavaScript 中将每个声音合成为一个立体声 Float32 混音(相位累加的正弦波、基于种子噪声的 RBJ 双二阶滤波器、采样精确的包络),然后仅将图形用于一个源到干增益和卷积器的路由,两者进入一个高通(两个输入可交换),然后是一个温和的压缩器(约 2.5:1,-20 dB 阈值)和一个线性淡出。

const M = A.mix(sr, D);                                   // { L, R } Float32Arrays
A.glass(M, 6.6, hz(81), 0.15, { decay: 2.8, pan: 0.2 }); // 模态泛音,在 JS 中求和
const buf = await A.render(M, { seed: 31, room: 3.4, wet: 0.45, fade: [8.25, 8.8] });
return A.master(buf, { lufs: -18, ceiling: -1.7 });

在页面中完成后期母带处理。 在 startRendering() 之后,测量缓冲区(K 加权,门控集成响度和 4 倍过采样峰值),应用一个增益以达到目标,如果峰值天花板要求,则应用较低增益。确定且简单。

确定性渲染检查表

  • window.motion 声明宽度、高度、时长、帧率以及一个关于最美丽帧的海报时间。
  • renderFrame(t) 仅从 t 设置每个 uniform;在渲染模式下不允许使用 Date、performance.now、Math.random、计时器或累计状态。
  • 先寻址到较晚时间再回到较早时间能产生相同的像素;第一个和最后一个捕获的帧是有效的。
  • 预览模式(无 ?render=1)使用 requestAnimationFrame 循环;点击播放同一个渲染的音频缓冲区并同步播放。
  • renderAudio 在 JavaScript 中混合声音,然后在 OfflineAudioContext 中通过一个种子卷积器渲染一个源;两次调用返回字节相同的样本(没有节点具有三个或更多输入)。
  • 提示映射表是一个在画面和声音之间共享的时间代码表格(撞击、停止、释放),并且在最后 0.3 秒内,混响尾部低于 -45 dB。
  • 无网络、字体、图片或样本;每个纹理和声音都是程序化的。

避免

  • 穿过画面的彩虹渐变、彩虹文字、彩虹色“全息”表面。
  • 霓虹灯、紫蓝色“AI”渐变、黑色背景、镜头光晕和变形拉丝。
  • 光泽 3D 渲染玻璃:厚而亮的倒角、有色玻璃、HDRI 镀铬反射、一切物体上的泛光。
  • 无接触阴影的漂浮物体;颜色非来自物理原因。
  • 相机轨道、快速剪辑、粒子、闪光、嗖嗖声和上升音调。
  • 逐帧随机颗粒和单像素线条(在 H.264 压缩后闪烁)。
  • 削波的声音、与调性冲突的和弦堆栈、过早结束的混响尾部。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

相关技能