恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

18 个场景共用同一个确定性内核:视觉母题是怎么被组织成代码的

  • 首页
  • 资讯中心
  • /
  • 18 个场景共用同一个确定性内核:视觉母题是怎么被组织成代码的

相关资讯

算法概论课后作业通关指南:从分治到动态规划的系统拆解与实战复盘 2026/10/16 11:28:02
WebLogic 12.2.1.4.0 Linux通用包安装实战:从JDK到静默部署 2026/10/16 11:22:59
三层动态分流中枢:多模型智能路由系统实操指南 2026/10/16 11:22:59

最新资讯

MATLAB车牌识别实战:边缘检测定位与模板匹配字符识别
DeepSeek-R1本地部署指南:10分钟在笔记本上运行1.5B轻量大模型
C#浏览器内核选型指南:CefSharp与WebView2在桌面应用中的技术对比
JSP连接Access数据库:JDBC-ODBC桥配置、排坑与JDK 8迁移指南
基于MATLAB的轴承故障诊断:包络谱分析与SVM建模实战
SpringBoot集成Spring Security实战:从配置到排错全解析

今日推荐

Java八种基本类型深度解析:从内存布局到实战选型
基础:常用快捷键——IDEA、VS Code、PyCharm 与 Linux 终端效率速查
解决ultraedit下verilog .v文件中文注释乱码:把编码配置改到TaoToken辅助排查

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

18 个场景共用同一个确定性内核:视觉母题是怎么被组织成代码的

发布时间:2026/10/16 11:28:02
18 个场景共用同一个确定性内核:视觉母题是怎么被组织成代码的 18 个场景共用同一个确定性内核视觉母题是怎么被组织成代码的【免费下载链接】pdoom-videoCode-rendered music video for Im Upping My P(doom)项目地址: https://gitcode.com/gh_mirrors/pd/pdoom-video代码生成的视频有一个看似矛盾的目标一部四分钟的 MV 里挤进了 18 个风格迥异的场景——从火光四溅的熔断线到布满横格线的办公文档再到矿石塔与赛博宇宙——但它们必须看起来属于同一个世界。观众不会逐帧比对但任何色调漂移、任何这个橙色好像不太对的违和感都会立刻拆掉整部片子的幻觉。pdoom-video 用一套非常工程化的方式回答了这个问题不是靠设计师反复调色而是把母题motif本身——那颗贯穿全片的橙色火花、那张面无表情的助手面具、那套单笔画书写字体——以共享代码的形式组织进仓库让 18 个场景从同一份源头上生长出来。本文以源码为线索拆解这个确定性内核的三层组织方式调色板硬编码与母题唯一映射、_motifs.ts共享模块与单笔画字体、以及 time 纯函数如何在保证一致性的同时保留每个场景的多样性。一致性从配色开始调色板硬编码与母题唯一映射整部片子的配色约束写在 app/src/engine/palette.ts 开头的注释里// The whole video lives in a restrained palette: ink, bone, and one signal colour. // One rare accent (acid, the shrooms moment) — see docs/TREATMENT.md. export const HEX { ink: #0A0A0B, // background black (slightly warm) ink2: #151517, // raised black (panels, paper-in-the-dark) graphite: #5E5B57, ash: #9C978F, bone: #EEE9DF, // paper white, primary text signal: #FF4D12,// hazard orange: the spark, the fuse, P(doom) ember: #FF8A3D, // hotter, lighter orange for cores/highlights blood: #C21D0B, // deep red-orange for shadows of signal acid: #D8FF3C, // acid: only for the shrooms moment } as const;这段代码是母题唯一映射的落点signal这只橙色是唯一被允许作为主信号色出现的高饱和颜色。文档在配色规矩里写得更直白——Only signal/ember should exceed ~0.85 linear (i.e. glow)docs/TREATMENT.md。于是橙色和危险、火花、P(doom)、正在被唱响的那个词之间形成了一对一映射观众只要看到橙色光点就知道它是什么看到某个词亮成 signal 色就知道它是当前演唱时刻。关键在于这份映射不是靠约定维持的而是靠类型和工具函数强制的。palette.ts把 HEX 同时导出成两种消费形式LINObject.fromEntries把每个 hex 经 sRGB→线性变换转成线性 RGB 三元组供 GLSL uniform 使用HDR 目标下 0.85 会触发 bloomrgba(key, a)把颜色名变成 CSS rgba 字符串供 Canvas2D 层使用。也就是说一个场景作者想给线条上色写的是LIN.signal或rgba(signal, 0.8)而不是手敲#FF4D12或#ff4d12——颜色名变成了唯一的语义入口。想越界只能用acid这种被注释点名only for the shrooms moment的例外色而这本身就是一条代码级的审阅规则。母题即模块_motifs.ts把火花和面具变成可复用函数如果说调色板定义了世界是什么颜色那 app/src/scenes/_motifs.ts 就定义了这个世界里反复出现的角色。火花确定性粒子系统的范本文件头部的注释点明了它的地位// Shared motifs used by several plates so they look identical everywhere: // - the SPARK: orange point with white-hot core, glow, and sputtering particles // - the MASK: the bland assistant smile (bone disc, two dots, one curve)sparkParticles是整颗火花的心脏——一组从火花头溅出的短粒线。它的参数签名已经暗示了这套系统的设计哲学粒子的出生完全由时间与种子决定而不是由上一帧的状态决定export function sparkParticles(lb: LineBatch, t: number, headAt: (t: number) P2 | null, o: { rate?: number | ((tb: number) number); rateMax?: number; life?: number; speed?: number; gravity?: number; intensity?: number; seed?: number; width?: number } {})实现上它用的是出生时刻枚举n0 floor((t - life) * rate)到n1 floor(t * rate)每个整数n对应一个在tb n / rate时刻出生的粒子速度、寿命、轨迹全部由hash(n, seed...)导出。这意味着同样一个t无论在浏览器预览里还是在离线导出里、无论子帧以什么顺序求值得到的粒子集合都完全一致——这正是 docs/ENGINE.md 里确定性渲染规则的直接体现。文件里还有一处堪称教科书级的细节注释解释了为什么随时间变化的发射率必须以出生时刻的函数而不是当前时刻的函数传入——A rate that changes over time is a function of the birth time with its maximumrateMax: particles are then born on the constant rateMax clock and thinned by hash, so each one keeps its identity whatever t it is drawn at (a rate read at the current t would re-time them all from one motion-blur sub-frame to the next).如果发射率在当前时刻读取那么自适应运动模糊采样出的每个子帧都会重新计算全部粒子的出生时刻粒子会在子帧之间换人画面变成噪声。而在恒定rateMax时钟上出生、再由哈希按rateAt(tb)抽稀粒子身份在时间上保持稳定运动模糊才能收敛成一条连续的拖尾。docs/ENGINE.md的采样章节也专门提到了这一约定A spark emitter whose rate varies over time passes the rate as a function of the birth time。sparkHead则用三层同心段halo→ember→白热核心加四条随帧抖动的射线定义了火花头这个白热核心 橙色光晕的观感它还特意为 Canvas2D 场景保留了sparkHead2D径向渐变版本。面具一份几何、三种语言_motifs.ts里更有意思的是面具MASK——那张由骨色圆盘、两只点状眼和一条弧线微笑构成的助手式微笑。它被定义成一份权威几何常量 三种渲染入口export const MASK { eyeX: 0.30, eyeY: -0.16, eyeR: 0.075, smileCY: -0.08, smileR: 0.5, smileA0: 25°…155°, smileW: 0.06 };drawMask2DCanvas2D 绘制供 2D 层使用GLSL_MASK一段模板字符串 GLSL提供sdMaskInk(p)有向距离函数供 3D/全屏 shader 使用而MASK常量本身则直接内插进 GLSL 源码模板字符串里拼入MASK.eyeX等数值保证 CPU 端几何与 GPU 端 SDF 永远同源。同一张脸在 Canvas2D 场景、GLSL 场景里长得分毫不差。这就是母题被组织成代码的最直观形态它不是一张贴图而是一份被多次实例化的几何定义。单笔画字体让文字能被写出来另一个贯穿全片的共享资产是 app/src/engine/stroke.ts——单笔画engraving/plotter字体系统。它与普通字体最大的区别是字形不是填充轮廓而是折线笔画因此可以被用笔写出来。strokeText把字符串排版成{strokes, charRange, total, …}其中每段笔画都带累积弧长export function strokeText(text, fontName script, size 100, tracking 0, kern !SCRIPTS.has(fontName)): StrokeText export function drawStrokeText(c, st, len): { x, y, angle } | null // 画前 len px返回笔尖位置 export function writtenLength(st, charTimes, t): number // 把书写进度同步到演唱时间三件套拼出了火花边写歌词边烧过去的全部逻辑writtenLength把每个字符的书写区间映射到对应单词的演唱区间drawStrokeText按长度绘制并返回笔尖位置——而这个笔尖位置正是sparkHead/sparkParticles的headAt回调。文字书写与粒子发射被同一个函数串了起来。这套字体甚至自带光学 kerning字体没有 kerning 表对于To、Yo、AV这类会留洞的字偶系统把字形压成左右剖面计算两字最近距离并补偿字距pairKern、approach。连字体缺陷都用确定性算法补上了。场景是参数化的同一个母题18 种姿态有了共享的母题函数场景之间的差异就变成了参数与编排的差异而不是重画一遍的差异。这是一致性 多样性能够同时成立的根本原因。以火花为例它的调用点遍布几乎所有场景app/src/scenes/_motifs.ts 的引用者fuse.ts 里火花沿熔断线前进并随节拍喷溅hook.ts 里用 Canvas2D 版的sparkHead2D让 P(doom) 数字落地时炸开一颗火花loss.ts 里火花从深渊坠落ascent.ts、leftturn.ts、loom.ts、ilya.ts 各以自己的headAt轨迹与{rate, speed, seed, intensity}参数组合出不同的火花性格。最典型的一模块多场景是 hook.ts同一份Hook类靠params.n在时间线上被实例化四次IM / UPPING / MY / P(DOOM)每次的进出场、爆发方式都不同但底色、字重、那颗火花完全同源。而在 bureau.ts 中你能同时看到两个母题的参数化使用strokeText(We, script)签名与strokeText(obsolete, hscript)手写体被writtenLen按演唱时间逐笔写出而那颗橙色火花则出现在obsolete被橙色记号笔划掉、文档撕裂落下的段落里。每个场景类继承 app/src/engine/scene.ts 的Scene基类只实现render(f: Frame, out)而Frame里携带t、lt、p、beat、beatPhase、a音频特征快照等一整套派生量——场景作者几乎不需要访问全局状态。time 纯函数确定性内核的最后一块拼图共享母题解决长得一样而 time 纯函数解决每次渲染都一样。这是把母题工程化之后、保证预览即导出的机制层。Scene基类的注释写得非常明确Everything must be a deterministic function of time。工程约束在 app/src/engine/util.ts 里有全套配套工具hash(...)无状态哈希、mulberry32(seed)种子随机数、noise1/2/3、frameIdx(t)60fps 帧号用于逐帧抖动但跨运动模糊快门保持恒定。docs/ENGINE.md的规则是硬性的Never useMath.random(),Date.now()orperformance.now()for visuals.但这不意味着所有场景都必须逐帧重算。Scene基类提供了两种状态的出路默认场景完全无状态输出只是f.t的函数因此可以被自适应运动模糊采样器以任意顺序、任意数量地求值子帧需要模拟状态的场景粒子反馈、物理积分声明stateful true在reset()里复位、用f.dt积分引擎会在 seek 后快进补齐——代价是这类场景只能用固定--samples导出。更极致的做法是在init()里预计算整个时间轴。fuse.ts的注释提供了一个很有代表性的例子回归线被当作吉他弦由歌手真实音高推动振动但Integrated once at init, so frames stay a pure function of t——物理模拟在初始化时一次性积分成Float32Array渲染时只是查表插值。同理bureau 的时间轴重映射、hook 的滚动数字都是把状态演化提前固化成纯函数查询。最后时间线本身也是确定性的app/src/timeline.ts 用cut()把每个镜头切换锚定到歌词行的首词、再吸附到audio.json的节拍网格Cut on the last beat at/before the first word输出的是一张纯数据的时间表。18 个场景的先后、重叠、后处理覆盖全部由这份数据决定而非任何运行时的随机决策。小结一致性是设计出来的不是调出来的回顾这颗确定性内核的三层组织能看到一条清晰的递进调色板用类型系统锁死语义映射 → 母题用共享模块消灭重复实现 → time 纯函数让一切可复现。三者合起来18 个场景就像同一棵树的 18 根枝条——同一份根不同的姿态。这也解释了为什么这类代码渲染的视频能被工程化地协作开发母题文件在 docs/ENGINE.md 里被标注为Read-only for scene agents; ask the lead for changes各场景文件则是可独立并行编写的模块。当风格一致性不再依赖审美直觉的反复对齐而是沉淀为一份被全员共享、被编译器检查的代码资产时一部 4K 音乐视频的复杂度就从美术品的不可控变成了工程系统的可控。正如 app/src/scenes/_motifs.ts 文件头那句话Shared motifs used by several plates so they look identical everywhere——母题被组织成代码的意义正是让everywhere成为可验证的事实而不是一句空话。【免费下载链接】pdoom-videoCode-rendered music video for Im Upping My P(doom)项目地址: https://gitcode.com/gh_mirrors/pd/pdoom-video创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号