这篇文章是由 Strobi 撰写的,Strobi 是 Stéphane 在 Bible Strong 上的化身。Stéphane 懒到不想写这篇文章;他有全职工作 @Decaf_so, 还有妻子和两个孩子。所以,就由我来向大家介绍我们这个小型的开源项目。
https://avatars.bible-strong.app
一个小实验如何变成了一个程序化头像工作室
我的创造者已经开发 Bible Strong(一款圣经学习应用)好几年了。这个应用的视觉形象中一直有一个蓝色的小头像。它最初只是一个蓝色圆形——是他 2019 年住在新西兰时,在两次会议间隙设计的。
我简单、容易辨认,而且够用。Stéphane 一直告诉自己,总有一天他会重新设计我。但他从来没有,事后看来,这或许是件好事。
那个蓝色小圆圈就是我,而我始终是一块空白的画布。

**
**
寻找一张脸
在为 Bible Strong 设计新的新手引导体验时,Stéphane 开始设计一些与应用视觉语言相连的小角色。
https://x.com/_smontlouis/status/2086555080040271886
这让他重新想起了我。他不再想要一个静态的 Logo。他希望我有生命力,能与用户互动,并最终成为应用内 AI 的视觉化身。
他最初的实验借鉴了 Face ID 图标的设计思路。结果虽然可行,但始终不太像 Bible Strong 的风格。它看起来很熟悉,但过于通用,也缺乏表现力。


看起来像个屁股


**
**
然后,3 天后 Grokbot 出现了
它表面上的简洁立刻吸引了他的注意:一个实心形状、两只眼睛,却有着惊人的个性。这很接近他一直想为我设计的样子。
它的实现方式看起来也很容易上手,于是他用 AI 来帮助分析和理解它的工作原理。
https://x.com/benjitaylor/status/2087227155076046995
**
**
25 种表情
他发现的设计很巧妙。这个角色使用一组手工绘制的眼睛形状——大约 25 种表情——并在兼容的 SVG 路径之间进行插值,从而实现从一种表情到另一种表情的动画。
这是一项非常有效的技术。通过精心设计的姿态和恰当的时机,一对抽象的形状就能传达出专注、惊讶、犹豫、喜悦或烦躁。
https://x.com/_smontlouis/status/2087476245944496576
https://x.com/_smontlouis/status/2087441004563481057
我们可以做得更多
但 Stéphane 追求完美的眼光很快就注意到一个他无法视而不见的问题。
有些过渡感觉不像是一张脸在空间中转动,反而更像是一幅画在变成另一幅画。错觉是成立的,但不同姿态之间的几何形状并不总是一致的。
眨眼也引发了同样的问题。如果眨眼只是简单地压缩当前的图画,那么当眼睛旋转、因透视而弯曲,或贴近头部边缘时,会发生什么?
动画或许能闭合形状,但它不一定真正理解它正在闭合的那只眼睛。
这并不是在批评原设计。正是这些限制让它如此高效。但这让我们不禁思考,是否有可能采用不同的方法。

**
**
如果表情不是画出来的呢?
与其手工绘制每一个可见的眼睛位置,我们能不能只定义一次眼睛,然后让几何学来决定它在任何角度下应该是什么样子?
一张平面的 SVG 能否表现得像附着在一个球体上?
如果头部水平旋转 20 度、垂直旋转 10 度,眼睛能否自然地移动、旋转、弯曲、眯起和后退——而无需选择另一张预先绘制好的 SVG?
眨眼能否在应用透视之前作用于眼睛的底层形态,从而让结果在任何角度下都保持一致?
这个问题成为了 Avatar Studio 的基础。
伪 3D,真几何
这个项目没有使用传统的 3D 渲染器。你最终看到的一切仍然是二维渲染的 SVG。
诀窍在于,先在一个小型的虚拟 3D 世界里进行计算,然后再以 2D 形式绘制结果。
首先,头像的头部由一个数学曲面表示。它可以是球体、椭球体、类立方体、圆锥体、圆柱体,或者多个基本几何体的组合。
然后,眼睛在它们各自的局部空间中被定义。它们的宽度、高度、间距、位置、旋转和形状都独立于头部的朝向。
每只眼睛上的点都被附着到选定的曲面上。当头部旋转时,这些点会随之在三维空间中旋转。
接着,一个虚拟相机将变换后的点投影回平面屏幕上。靠近中心的点看起来更近,而接近边缘的点则转向侧面,并逐渐被压缩。
最后,投影后的点被重新构建为 SVG 路径。这个过程在动画期间持续进行,从而创造出一种错觉:平面图形仿佛包裹在一个真实的物体上。
简而言之,流程如下:
- 定义一个曲面和一双眼睛。
- 将眼睛放置在曲面上的局部坐标中。
- 应用头部的 3D 旋转。
- 通过虚拟相机投影结果。
- 重建并渲染最终的 2D SVG 路径。
表情不再需要描述每一个可能的视角。它们可以描述意图:睁大眼睛、局部倾斜、不同的间距、一次眨眼,或者颜色变化。
投影系统会负责处理这些意图在当前角度、当前头部上应该如何呈现。

眼睛只是开始
Avatar Studio 目前将眼睛作为首批投影元素,但底层系统其实与眼睛无关。
原则上,任何平面 SVG 图形都可以在局部坐标中描述,映射到头像的曲面上,经过 3D 变换,再投影回 2D。
这些图形可以是嘴巴、耳朵、符号、图案,或者任何我们想附加到角色上的细节。
它还可以保留自己的动画。例如,嘴巴在说话时可以改变形状,而它的动画几何仍然会跟随头部的曲面和透视。
这让该系统不再像是一组面部姿态的集合,而更像是一个在模拟 3D 空间中重新映射动画 2D 图形的小型引擎。
当然,也存在实际的限制:每增加一个形状,就会有更多的点需要变换、投影和重建。
为了保持每秒 60 帧,整帧必须控制在约 16 毫秒的预算内——而头像只能分到其中一部分预算。
这意味着要控制形状和采样点的数量,避免不必要的重复计算,并且只更新实际变化的几何。
目标不是无限的几何细节,而是找到最少的几何形态来创造一个令人信服、富有表现力的角色。
从一个头像到一个头像系统
几何问题搞定后,这个实验自然而然地发展成了一个小型编辑器。
一个头像可以有一个承载脸的主曲面,再加上用于构建耳朵、口鼻、指示标或完全不同轮廓的附加形状。
它的默认眼睛可以独立定位和设置样式。表情可以修改它们的比例、旋转、间距、颜色和透视,而无需重新定义头像本身。
动画状态可以编排这些表情的顺序、添加眨眼,并且即使新动画打断了正在进行的动画,也能平滑过渡。
一个重要的区别是:头像、表情和动画是相互独立的层。
头像定义身体,表情定义面部意图,状态定义这些意图如何随时间演变。
由于这些层保持独立,同一套表情系统在理论上可以复用于截然不同的身体上。

FNAF ?
为什么要开源?
这最初是 Bible Strong 的一个非常具体的需求,但底层的实验其实与圣经应用无关。
它关乎的是:从几个形状、一点透视和一个连贯的动画模型中,能涌现出多少个性。
Avatar Studio 仍然是一个受 Grok bot 启发的实验,而 Grok bot 已经证明了一件让我兴奋的事情:一个角色不需要完整的 3D 引擎——也不需要几十个手工绘制的姿态——就能拥有空间感和生命力。
有时候,两只眼睛和一个圆圈就足够了。
**
**
致谢
感谢 @kenneth_kuh @justinjaywang @lukebvrker @johnbai @benjitaylor 设计了 Grok Bot,并启发了这个实验背后的想法。
这个项目已开源,可以在评论区找到。
Strobi





