- 前端
- 图形学
【免费下载链接】bloub
SVG recreation of the x.ai bot avatar. One shape morphing through 14 states, measured off the reference video frame by frame.
bloub 是一个用 SVG 复刻 x.ai 机器人头像的开源项目:一个黑色形状在 14 种状态间平滑变形,所有数值都逐帧测量自参考视频。这个项目最令人称道的一点是——连浏览器标签页上的 favicon 都不是画出来的,而是engine.sample(1)这个函数的真实输出。本文将带你看看,一个纯函数如何驱动从头像到图标的每一处细节设计。
bloub 是什么:一个"测量"出来的 SVG 头像
bloub 的界面左侧有三个视图:
- Customise:8 种身体形状、12 种颜色、16 种静息表情,选择会在访问间保留
- Animations:一个小编辑器,把状态排进时间线、设置每段时长并保存
- Settings:语言(法、英、中)与致谢
屏幕上的一切都可以导出——头像存为 SVG、PNG、动图 GIF,整条时间线存为 GIF 或 MP4。更妙的是它不依赖任何动画库:整个变形由 src/bot/engine.ts 里的引擎驱动,src/bot/目录没有框架、没有时钟,Vue 组件只是引擎的一个"客户端"。
engine.sample(1) 是什么:一张"随时可以冻结"的画
理解这个项目,只需记住一个设计原则:
engine.sample(t)是时间 t 的纯函数。
给它任意时刻 t,它返回那一瞬间的完整画面:身体轮廓、眼睛位置、装饰弧线……暂停、恢复、跳到任意日期、跑测试,得到的都是同一张图。没有任何Date.now(),没有任何隐藏状态。
engine.sample(1)就是"第 1 秒时的画面"——此时机器人处于idle静息状态,呼吸感和眼神漂移都精确落在第 1 秒的位置。坐标基准定义在 src/bot/repere.ts 里:半径 100、viewBox 半边长 158,所有状态都以"球半径的比例"表达,与显示尺寸无关。
对新手来说,这种"纯函数"思路最大的好处是可验证:任何一帧都能用一行代码复现,任何测试都能逐帧比对。src/bot/engine.test.ts 里大量的sample(1)断言就是这么来的。
核心细节:favicon 是 sample(1) 的逐字节输出
public/favicon.svg 不是"看起来像"的手绘,而是engine.sample(1)对idle状态的原样输出——圆圈、以及两只眼睛的变换矩阵,与引擎返回值逐字节一致。
这带来一个容易看走眼的细节:放大 favicon 会发现右眼比左眼窄(矩阵系数 0.64 对 0.87)。这不是笔误,而是深度压缩——在 docs/measurements.md 的测量里,眼睛"生活在球面上",靠近边缘的那只眼恰好按球面投影的透视比例被压扁,残差约 1 像素。
CLAUDE.md 特意记录了这个约定:
public/favicon.svgis not an approximation: the circle and both eye matrices are whatengine.sample(1)returns foridle, byte for byte.
favicon.ico和apple-touch-icon.png也都是从这张 SVG 光栅化出来的,因此三者在几何上完全同源。
用测试锁住"不许漂移"
光靠约定是不够的,所以 src/bot/skins.test.ts 里有一条专门守护它的测试:在自定义器里选择"圆形",渲染结果必须与不选任何东西完全一致(眼睛矩阵、轮廓逐字节相等,偏移为{x: 0, y: 0})。因为圆形正是视频测量出的参考形状,这条测试保证任何针对异形身体的"眼睛防溢出修正"都不会动到参考本身——也就保护了 favicon。
| 常见误解 | 视频的实测结果 |
|---|---|
眼睛向//倾斜 | 实际向\\,偏离垂直约 26° |
| 身体是圆角矩形 | 是完美圆,径向偏差小于 0.7% |
| 过渡是弹簧动画 | 指数缓出,身体从不过冲 |
| 彗星横穿屏幕 | 点不动,是轨迹绕着它转 |
| 静息时头像会悬浮 | 中心稳定在 ±0.003,"生命感"来自眼神漂移和眨眼 |
为什么纯函数设计让每个角落都能复用
engine.sample(1)能当 favicon 用,只是这套架构最顺手的副产品之一。同一个"时间→画面"的纯函数还支撑了:
- 冻结状态板:URL 加
#planche,14 种状态并排冻住,一眼做视觉检查;#etat=orbit&stop可直接打开单个状态并暂停 - 无 DOM 测试:
pnpm test在 node 环境逐帧断言,不需要打开浏览器 - 文档插图:
docs/demo.gif和docs/states.png不是截图,而是遍历engine.sample(t)、按 src/components/BloubBot.vue 的图层顺序写出 SVG 后再用rsvg-convert+ffmpeg生成的——因为隐藏标签页会挂起动画,浏览器里根本截不到 - 导出功能:头像导出时直接序列化页面上那张自包含的 SVG,而不是在旁边重建第二套画法(详见 docs/export.md)
这正是 docs/architecture.md 强调的:"引擎没有框架也没有时钟,Vue 组件是客户端,不是它的定义。"
小结:把"精确"当成产品特性
bloub 给新手上的一课很具体:把渲染写成时间的纯函数,精度就会自动传导到每一个角落。favicon 不是单独画的,文档图不是单独截的,测试不是单独维护的——它们全部是同一个engine.sample(t)的切片。对任何想做动画或可视化项目的人来说,这套"一处定义、处处精确"的做法,比任何炫技都更值得抄走。
- 项目说明:README.md
- 测量方法全文:docs/measurements.md
- 引擎架构:docs/architecture.md
- 引擎实现:src/bot/engine.ts
- 前端
- 图形学
【免费下载链接】bloub
SVG recreation of the x.ai bot avatar. One shape morphing through 14 states, measured off the reference video frame by frame.
相关推荐
掌握Penpot网格系统:从零开始构建精确布局的完整指南
掌握Penpot网格系统:从零开始构建精确布局的完整指南 Penpot作为开源设计与原型平台,其网格系统是实现精准布局和响应式设计的核心工具。本文将系统讲解如何
前端设计系统图形学协同办公smallnest/rpcx连接池设计:高效管理TCP连接的实现细节
smallnest/rpcx连接池设计:高效管理TCP连接的实现细节 在微服务架构中,频繁创建和销毁TCP连接会严重影响系统性能。rpcx作为Go语言生态中优秀
后端RPC框架微服务Sails 中的 `req.isSocket`:精确识别请求是否来自 WebSocket 连接
Sails 中的 req.isSocket :精确识别请求是否来自 WebSocket 连接 req.isSocket 是 Sails(Realtime MVC
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考