启动与加载
两种等待:即将到达的记录,和时长未知的启动。
先看效果
左边:三个先加载再登场的头像槽。LoadingMark 在 ready 之前一直显示轮廓;下面真正的角色始终挂载着、处于暂停,所以切换是交叉淡入,而不是第一帧对着一片空白。右边:一个已经持续到该说点什么的启动。
loadingloadingloading
正在启动正在把一切准备就绪。
槽只拿到 state="spawning",别的什么都没给:真正的角色在 ready 之前处于暂停,所以它的状态时钟从交叉淡入那一刻开始走,gather 腰带播放,两秒后渲染器自己转到 idle。LoadingMark 不转发 onSettle;需要知道这一刻的宿主,在记录到手之后直接用 CharacterMark。BootLoop 从 effect 而不是从计时器里上报周期数,这样在回调里重渲染的宿主也不会让计时器在周期中途重启。
什么时候用
两种不同的等待。第一种是智能体自己的记录正在到达——几百毫秒里头像槽是空的,版面即将跳动。第二种是某个东西在启动,时长未知,进度条在这里只会撒谎。角色两种都能接:先是一个即将到来的脸的轮廓,然后是一次登场;或者是一种诚实地不知道何时结束的持续活动。
用到的组件
LoadingMark——角色自己的轮廓做成闪动的遮罩,ready时交叉淡入真正的角色。BootLoop——设备边框里的不定时长等待;onCycle让宿主逐步升级提示。CharacterMark——loading、spawning、onSettle。MarkStageProvider——一页占位符一起翻转时应该共用一个引擎。HudPlate——启动用sync表盘,它表达的是一个生命周期而不是一个分数:尝试连接前是idle,连接中是syncing,落地时是done或error。只有宿主手里有真实分数时才用progress;按编造速率填满的环,只是绕了一圈的撒谎进度条。
状态怎么走
spawning 是一个瞬间,不是一种状况。宿主否则都要写同一个离开它的超时,所以由渲染器掌握时钟,并通过 onSettle(from, to) 通报这次转移。减少动态效果会跳过花活,但收束照样触发。
每个状态的样子
| 状态 | 眼睛 | 嘴 | 特效 | 编号 | HUD | |
|---|---|---|---|---|---|---|
loading加载 | dot → dotLook | none | spinner | 0536 | — | |
spawning启动 | dotWide → dot | dot | gather | 08 | — | |
working工作 | dotDown → dot → dotDown | none | arc | 1632 | gauge | |
thinking思考 | dotLook → dotUp → dotLook | flat | dots | 30 | context | |
idle空闲 | dot → dot → dot → dotLeft → dot → dotRight | none | — | 02 | — |
whirl 在每个轴上叠两条频率互不相关的正弦波,所以在任何人等待的时间内漂移都不会重复。gather 用两秒把五个粒子螺旋收进来,然后表现得像 progress。working 完全没有腰带——它只是眯眼、身体前倾——这正是 BootLoop 把它和 thinking 配对的原因:有腰带和没腰带之间的交替本身就是活动。