关于 avatar
将物体转化为动画角色的技能,角色由单色剪影和胶囊形眼睛构成。它指导视线、情绪、页面互动、减少动态效果处理及视觉检查。
主要功能
- 01绘制单色剪影与一对眼睛
- 02驱动视线、眨眼、呼吸和身体动作
- 03用数值化眼型定义情绪
- 04让角色响应页面输入
- 05离屏时暂停动画并遵循减少动态效果设置
- 06使用联系表检查动画
适用场景
- 01将物体设计成动画角色
- 02为页面加入由指针触发的角色反应
- 03检查角色在不同情绪与主题下的表现
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ playful-design/ router --skill avatar安装后在 Claude Code 中输入/avatar确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
face.jsLICENSEsheet.jsagents/openai.yaml详细介绍
Avatar
这项技能会把物体变成一个小小的活角色。它用两个胶囊形眼睛绘制一个扁平剪影,然后用一个循环驱动整个身体,让它环顾、眨眼、呼吸并作出反应。
经过测量的眼睛,以及永不停歇的身体
gaze、eye 和 blink 值是根据参考录像测量得出的精确值。idle 之后的情绪状态是经过调校的起始值。角色眼睛会动、身体却保持静止,这就是问题所在。
收集参考素材属于 gather。逐帧拆解参考动画属于 deconstruct。提供剪影变体属于 prototype。界面动效及其 300ms 预算属于 motion,而不是角色身体。帧成本属于 frames。打开结果属于 verify。
1. 研究参考素材
当用户指定参考角色时,打开其素材,并以 10fps 逐帧查看录像。根据画面测量眼睛大小、倾斜角度、间距和眨眼时机。从扫一眼参考素材就画出角色,属于 avatar-measure-the-reference。
测量值要保持原样。将 15.5° 的眼睛间距四舍五入为 15°,或将 180ms 的眨眼时间四舍五入为 200ms,属于 avatar-keep-the-measurements。如果用户未指定参考素材,则从 face.js 开始。
2. 绘制剪影
将物体简化为一种饱和色的单一扁平实心形状。添加描边、阴影、嘴巴或鼻子,属于 avatar-flat-silhouette。
角色在实际发布尺寸下通常为 28–40px,必须清晰可辨。将它绘制在小网格上,例如 14 × 17 的 viewBox,并将 viewBox 紧贴墨迹裁切。像眼睑这样会独立移动的部分,应使用单独的路径。
选择仅凭轮廓就能辨认物体的视角:容器和工具用侧面,设备用正面。若给出角色身份或爱好,绘制最具代表性的单个物体。如果必须依靠细节才能辨认视角,则属于 avatar-iconic-view。
承载面部的部分是主体。将该部分原地放大,直到 head 椭圆加上一个眼睛宽度的边距,能够落在平稳的实心区域内。按最宽的情绪状态来确定尺寸,因为开心时的眼睛几乎是 idle 时的两倍宽。为了容纳面部而添加区块,或缩小眼睛来适应,属于 avatar-face-part-leads。
其他部分的大小要根据轮廓(包括封闭空间)确定,而不是根据填充区域。它们应明显小于承载面部的部分,且只延伸到辨认所需的程度。把高度和杯子一样的把手环算作 avatar-size-by-outline。
保留能让物体易于辨认的少数特征,例如颈部、盖子或杯沿,并删去其他所有细节。使用一到七个柔和的基本形状构建整体轮廓,让它们相互重叠并连成一体。
每个连接处都要形成清晰的台阶或平滑的衔接。台阶至少有半个眼睛宽;平滑衔接则要让一条边直接延伸,且将内角埋入形状中。一个部分如果在两个点相连,就必须始终保持两点相连。边缘几乎对齐却留下细缝或缺口,属于 avatar-clean-joins。
只有真实的开口才切出孔洞,例如马克杯把手或戒指;并让路径方向与其轮廓相反,使填充区域留下开口。开槽、按钮或装饰性镂空属于 avatar-holes-are-openings。
保持玩具般的比例。任何部分都不能比眼睛更窄;所有角都要圆润,所有收窄处末端都要柔和。叶片或火焰等有机形状要保留其曲线和方向。细线、尖角,或被压扁成椭圆的叶片,属于 avatar-toy-proportions。
让主体居中,并落在平坦或略圆的底部。然后查看整体在 28px 下静止和倾斜到一半时的效果。如果它看起来像另一个物体或像是坏掉了,就重新调整各部分的平衡或更改视角,即使它符合以上所有规则也不例外。
颜色由 --avatar-body 和 --avatar-eyes 两个变量控制,并需在两种主题下检查。直接在路径中写入填充色,属于 avatar-colour-variables。
3. 把眼睛放在球体上
两个白色胶囊状眼睛,高约为宽的 2.2 倍,位于上方偏右的位置。它们像反斜杠一样倾斜,头部倾斜约 12°。
眼睛位于脸后方的球体上。通过偏航、俯仰和滚转来定位眼睛,因此靠近边缘时会变窄,转到后方时会逐渐淡出。眼睛平贴着脸移动,属于 avatar-eyes-on-a-sphere。face.js 中的 drawEyes 负责投影。
将两只眼睛裁剪到轮廓路径内,放在负责移动身体的组中。眼睛绘制到轮廓之外,属于 avatar-clip-to-the-body。
4. 让整个身体充满活力
任何部分都不会静止不动。视线沿着多层正弦波缓慢漂移,每隔 1.5–4s 瞥向一个新位置;大幅转移视线时会眨眼。视线在事件之间停在静止位置,属于 avatar-never-still。
眨眼持续 180ms,并在这段时间的前 45% 内闭合。每隔 1.9–4.6s 眨一次眼,其中 18% 为连续眨两次。按固定间隔眨眼,属于 avatar-irregular-blinks。
身体以 3.4s 为周期呼吸,幅度为 1.2%,略微浮动,并稍晚一拍地朝视线方向倾斜。眼睛大约 60ms 后稳定下来,身体则需要 220ms。眼睛在静止的身体内移动,属于 avatar-whole-body。
5. 通过眼睛形状塑造情绪
每种情绪对应一行数值:眼睛的宽度、高度、倾斜度、间距、睁开程度,以及视线偏移量。情绪之间用约 90ms 的指数缓出进行混合,且不会超调。每种情绪都换用单独的绘制方式,属于 avatar-moods-as-numbers。
先实现 idle、attentive、excited、happy、sleepy 和 asleep。再添加一两个只有这个对象才会做的动作,例如跳跃时略微滞后的眼睑。没有专属动作的角色,属于 avatar-object-move。
6. 接入反应
每种反应都对应页面上的一种输入:
- 指针离开 6s 后重新进入。眼睛在 1.1s 内绕到后方旋转 360°,随后跟随指针。
- 指针停在主要操作上。眼睛睁大,身体略微弹跳。
- 用户按下操作按钮或角色。角色跳跃 750ms,并伴随挤压和拉伸,然后眯起眼睛,开心地弹回原位。
- 24s 内没有任何操作。角色变得困倦,30s 后进入睡眠,缓慢深呼吸,并通过旋转醒来。
将跟随的视线限制在偏航 ±45° 范围内,让眼睛始终留在脸上;跟随时忽略触摸指针。对周围页面毫无反应的角色,属于 avatar-react-to-the-page。
当角色是页面上的主要互动对象时,也可以根据距离做出反应。进入 640px 范围内时,它会变得好奇;进入 260px 范围内时,它会变得警惕;进入 100px 范围内时,它会向后躲闪。戳一只眼睛时,这只眼睛会闭上,另一只则保持睁开。
7. 通过一个循环运行
通过一个 requestAnimationFrame 循环调用 face.js 中的 createAvatar,并通过 refs 写入 SVG 属性。每步的时间上限为 64ms,避免切回标签页时角色突然跳动。每帧状态更新应放在 frames 中。
只在角色显示于屏幕上时运行循环,并通过 IntersectionObserver 实现。角色在屏幕外时仍持续运行循环,属于 avatar-pause-offscreen。
在服务器端通过 restingEyes 渲染静止姿势,让首次绘制时就显示眼睛。水合时才突然出现脸部,属于 avatar-render-the-rest。
在 prefers-reduced-motion: reduce 下,角色保持静止姿势,不启动循环。仍会转移视线和跳跃的角色,属于 avatar-still-when-reduced。角色仅用于装饰,因此其 SVG 设置 aria-hidden="true"。
8. 在联系表上验证
单张截图无法展示动作,而隐藏的标签页会降低循环频率。通过浏览器的 evaluate 调用运行 sheet.js,然后调用 window.__avatarSheet.start({ selector })。
通过指针事件驱动每种情绪:待机、进入、悬停、按下和离开。调用 window.__avatarSheet.stop(),然后截取它排布好的联系表。可作为证明的一张静态画面是 avatar-contact-sheet。
如果结果中出现 warning,说明标签页处于隐藏状态或循环停滞,因此帧会重复或间隔会变大。让标签页保持可见,然后重新采样。进入睡眠状态需要 30s 无输入,因此请单独采样一次。
最后,在两种主题下都将角色设为发布时的尺寸,然后调用 window.__avatarSheet.clear()。
这对改动
每项检查都有一对对照:错误的做法与替代方案并列。
| 规则 | 错误做法 | 替代方案 |
|---|---|---|
avatar-measure-the-reference | 仅凭看一眼参考图来放置眼睛 | 根据 10fps 的帧测量尺寸、倾斜角度、间距和眨眼 |
avatar-keep-the-measurements | split: 15,为显得整齐而取整 | split: 15.5,按测量结果设置 |
avatar-flat-silhouette | 带轮廓、阴影和笑脸的杯子 | 一个实心形状和两只眼睛 |
avatar-iconic-view | 从正面看浇水壶,整体像个盒子 | 从侧面看,壶嘴和把手让它一眼可辨 |
avatar-face-part-leads | 在马克杯上贴一块板来放眼睛,或把眼睛缩至一半大小 | 加宽杯子,使头部和边距都能容纳其中 |
avatar-size-by-outline | 与杯子一样高的细把手环 | 紧凑的把手,明显小于杯子 |
avatar-clean-joins | 杯盖边缘超出杯身 0.3 个单位,留下一道缝 | 设置半个眼睛宽的台阶,或让边缘完全对齐 |
avatar-holes-are-openings | 为硬币或按钮挖出的槽口 | 只在物体开口处留孔,例如把手 |
avatar-toy-proportions | 细如发丝的茎和尖锐的叶尖 | 部件至少有一个眼睛宽,圆角,尖端柔和 |
avatar-colour-variables | 在路径中写入 fill="#c27a3e" | 使用 fill="var(--avatar-body)",并按主题设置 |
avatar-eyes-on-a-sphere | 对两只眼睛都使用 translate(dx, dy) | 根据偏航、俯仰和翻滚,通过 drawEyes(face, gaze, lid, head) 绘制 |
avatar-clip-to-the-body | 视线大幅偏移时,眼睛超出轮廓 | 将眼睛限制在身体路径的 clipPath 内 |
avatar-never-still | 眼睛在静止时停在原位,只会眨眼 | 叠加轻微漂移,并每隔 1.5–4s 视线扫动一次 |
avatar-irregular-blinks | animation: blink 5s infinite | 每隔 1.9–4.6s 眨眼 180ms,双重眨眼占 18% |
avatar-whole-body | 只有眼睛会动 | 身体会呼吸、漂浮并倾斜,比视线动作晚 220ms |
avatar-moods-as-numbers | {happy ? <HappyFace /> : <Face />} | happy: { eyes: pair(0.522, 0.217, 18) },在 90ms 内完成混合 |
avatar-object-move | 像任意物体一样移动的杯子 | 跳跃后延迟一拍抬起杯盖 |
avatar-react-to-the-page | 无论指针如何移动,都只有一个待机循环 | 进入时旋转、跟随指针、悬停时睁大眼睛、按下时跳跃、离开后睡眠 |
avatar-pause-offscreen | 在视口之外仍运行的循环 | 通过 IntersectionObserver 启动和停止循环 |
avatar-render-the-rest | 水合后才出现的眼睛 | 在服务器 HTML 中通过 restingEyes(head) 渲染静止状态的眼睛 |
avatar-still-when-reduced | 在减少动态效果时仍扫视和跳跃 | 保持静止姿势,不运行循环 |
avatar-contact-sheet | 只有一张待机姿势的截图 | 通过 sheet.js 遍历每种情绪制作联系表,然后展示两种主题下发布时的尺寸 |
报告
严重程度。 HIGH 表示身体完全不动、眼睛超出轮廓,或在减少动态效果时仍有动作。MEDIUM 表示眼睛平移生硬、眨眼固定、情绪表情图互换、循环动画超出屏幕、缺少反应,或仅凭一张截图作为证明。视图未说明对象、面部空间局促或次要部分过大,也属于 MEDIUM。LOW 表示测量值取整、路径中有填充、静止姿势突然出现,或角色没有自己的动作。连接处露出一小条缝、装饰性孔洞或极细的部件,也属于 LOW。
格式。 每个根本原因列出一项发现:
file:line - [rule-id] what is wrong
然后提供 Rule | Count | Severity 汇总。仍有任何 HIGH 时标记为 Block,否则标记为 Approve。将无法打开或逐步检查的参考标记为 Not verified。