Appearance
「群蜂重建」:让 18 个 AI 光标把首页重新造一遍
标签
AI
动画
Vue.js
进度
创建时间
1 天前
更新时间
1 天前
字数
2992 字
阅读时间
12 分钟
首页视频播完,页面被擦成一块画布。一群彩色设计光标飞进来,拉框、量尺寸、打字、复制,把整页重新「施工」出来——最后交还给真实的页面。
这套东西不是画的假图,而是真的对着当前页面的 DOM 扫一遍,再按元素逐个重画。下面从提示词、最终效果、实现细节三部分完整记录一遍。
一、需求提示词
原始诉求(保留了当时的措辞):
复制后发给 Agent
一句话里有四个硬指标:自主光标群、边界框 + 实时测量、打字机字体、程序化声音,落点是「逐个元素重建网页」。
二、把一句话拆成可执行的提示词
真正写代码前,先把它拆成八条可以验收的约束(相当于给自己写的系统提示词):
- 接管整页:覆盖层瞬间铺满,底色从页面真实背景取色;视口套一圈深色细边框,页面内容隐藏但不销毁。
- 光标要像人:28×28 多形态(箭头 / 复制 / 十字 / I 形),带真实热点、按压缩放、随移动方向转向;不是一张静态 PNG。
- 扫描真实 DOM:遍历页面元素建节点树,按「同父级、同长相」找可复用组;产出条目上限兜底,隐藏元素跳过。
- 建造语法是 Figma 的:十字光标拉框 → 右下角
W × H徽章实时跳动 → 灰色占位 → 交叉淡入真身 → 文字用 I 形光标逐字打出。 - 同构块复制:母块建完才允许复制;复制要「块内抓取 → 1:1 跟手拖动 → 两红框 + 间距读数 → 弹性落位 → 选中框停留」。
- 声音全部程序化:Web Audio 现场合成振荡器、噪声、泛音,不加载任何 MP3。
- 镜头自己游览:施工前沿走到哪,镜头跟到哪;收工后精确交接,不能出现两份页脚叠在一起。
- 可中断、可重播、可降级:Esc 随时退出;「开始」每次重播;
prefers-reduced-motion直接退回原来的下滑一屏。
三、最终效果(分镜)
分镜一:开场 · 扫描中
- 画布铺满,颜色取自当前主题背景,四周一圈深色内描边。
- 中央浮着一个小立方体,HUD 左侧显示「扫描中…」。
- 18 个光标从屏幕两侧飞入,围着立方体聚成一个圈;HUD 左下角最多露 6 个色点,代表在场光标。
分镜二:开工
- 扫描结束,HUD 变成
18 个光标 · N 层,随即切到「游览中」。 - 光标散开,按「施工前沿」分配任务,页面从顶部开始一层层重建。
分镜三:建造
- 容器:十字光标飞到左上角 → 按住拖到右下角,拉出选框,四角白方块手柄 + 下方
W × H徽章随拖拽实时变化 → 拉完先出现灰色占位 → 180~300ms 后真身交叉淡入。 - 文字:I 形光标点进元素,逐字打出;新出现的字短暂带蓝色底,光标尾部有一根闪烁的插入符。
- 图片:占位先出,随后
clip-path自上而下揭开真图。 - 导航 / 固定元素:单独一层,不随镜头滚动。
分镜四:复制(整套里最难的部分)
- 发现同构行(比如「推荐文章」列表的
.group/item),先留白。 - 母块完成后,复制光标飞到块内偏左上的位置(不是角上),按下、进入复制态。
- 拖拽体与光标 1:1 跟手,原位置红框 + 目标红框同时存在,两框之间实时显示间距读数。
- 松手后弹性落位(
cubic-bezier(.2,.9,.25,1.2),300ms),目标位置换成带手柄与W × H的选中框,停留 350ms 再淡出。 - 若副本里的文案和母块不同,会追加一次「双击全选 → 清空 → 重新逐字打出」。
分镜五:收尾
- HUD 变成
N 个光标 · X.Xs 完成 · 重播 · 关闭。 viewY先平滑对齐真实页面能滚到的位置,再把真实滚动位置对齐,然后揭开覆盖层——避免两份页脚错位。- 光标聚成蜂群在页面上方盘旋,可以跟真实鼠标互动;350ms 后覆盖层清空,页面滚回开播前的位置。
四、实现架构
| 文件 | 职责 |
|---|---|
components/swarm/SwarmRebuild.vue | 全流程编排:光标、任务调度、绘制、复制、镜头、HUD、收尾 |
components/swarm/capture.ts | 扫描 DOM、建节点树、移植原版 findGroups 分组规则 |
components/swarm/sound.ts | 程序化音源:钢琴泛音、噪声敲击、落位和弦 |
components/HomeContent.vue | 两个触发口:点「开始」每次重播;滚走视频首屏自动接一次 |
三个文件之外没有额外依赖,也不引入任何音频/图片素材。
五、关键技术细节
5.1 光标:28×28,四种形态
ts
const HOT = { arrow: [5, 3.5], dup: [5, 3.5], cross: [12, 12], ibeam: [12, 12] }arrow:原版那支箭头路径,白色描边 + 品牌色填充。dup:白色阴影箭头 + 彩色箭头叠一起,表示「按住复制」。cross:先白 3.6px 再彩 1.5px 的双线十字——就是满屏看到的「+」。ibeam:同样双线,打字时用。
每帧只改一个 transform:translate(-hx,-hy) rotate(angle) scale(1 - press*0.12);方向随速度旋转,速度低于 30px/s 不更新,空闲时角度向 0 衰减。
5.2 扫描与分组:照搬原版而不是「看着像」
capture.ts 的常量就是验收线:
| 常量 | 值 | 含义 |
|---|---|---|
MAX_TEXT | 260 | 单条文本最多取多长 |
MAX_ITEMS | 420 | 最多产出多少条目,超量按深度裁剪 |
MIN_SIZE | 2 | 小于 2px 不是元素 |
MIN_VISIBLE | 3 | 完全不可见就跳过(含隐藏子树) |
MAX_GROUP | 48 | 一个组最多多少成员 |
分组判定(findGroups):
- 子节点按签名分桶:
tagName + 归一化 className + fixed + 子树 kind 序列。 - 桶内两两相近:高矮比 < 1.8、宽窄比 < 1.6。
- 排除「只有一段长文本(>40 字)」和「子树条目 < 2」的节点。
- 成员 ≥ 2 即成组——这条是
.group/item每屏两行能成组的关键,旧逻辑要求 ≥3 所以永远复制不到。 - 副本条目从任务集里摘除,只保留一个 dup 任务,依赖母块子树里的全部工单。
5.3 三种任务
boxTask:拉框 + 占位 + 淡入。textTask:短文本直接点进去打;长文本先拉 ghost 框(4 手柄 + 徽章 + 两条测量线)再打。dupTask:抓取 → 复制态 → 跟手拖拽 → 落位 → 选中框 → 可选改字。
调度按「施工前沿(frontier)」取任务,母块没完成的 dup 会被 deps 卡住;空闲光标会去做 assistTask(帮别人收尾)或 roam(随便晃)。
5.4 打字机
- 每个字
12~40ms;空格额外0~30ms;换行+100ms;2.5% 概率卡顿80~200ms。 - 新字包进
.sa(rgba(13,153,255,.28))短暂高亮。 - 插入符 1.5px 宽、
1.1em高、steps(1)1s 闪烁。
5.5 程序化声音
SwarmSound 用 AudioContext + 压缩器 + 混响总线,全部现场合成:
| 方法 | 用在哪 |
|---|---|
swell | 开场扫描的低频涌动 |
arp | 光标聚拢时的琶音 |
piano(midi, vel, pan) | 落位/完成的正弦泛音(五声音阶,按面积定八度、按横坐标取音级) |
clack / space | 打字与空格的噪声敲击 |
press / snap | 按下与吸附 |
place(area, x) | 元素落位 |
dup(pan) | 复制落位(带立体声偏移) |
chord | 全部完成的和弦 |
ensure() / resume() 在「开始」按钮的点击手势里调用——这也正是把触发口设计成按钮的原因:自动播放策略只认用户手势。
5.6 镜头与交接
- 覆盖层有自己的滚动量
viewY,不依赖真实页面滚到底。 - 可走距离取
max(真实可滚距离, 内容底部 − 视口 85%),页面不够长也能一路推下去。 - 收工前若
viewY超过真实可滚距离,先 280ms 缓动对齐,再写真实scrollY,最后才揭开覆盖层。 - 揭开 350ms 后清空覆盖层,并平滑滚回开播前的位置。
5.7 HUD 与交互
- 覆盖层
pointer-events: none,只有 HUD 按钮可点;否则整页交互会被吃掉。 - 进度条按「已完成层数 / 总层数」推进。
- Esc 退出,滚轮/触摸/方向键在播放期间被拦下。
- 静音开关直接
setEnabled(false)。
六、踩过的坑
- 扫描必须在隐藏页面之前。
walk会跳过visibility:hidden的子树,先加swarm-lock就什么都扫不到。 - 两份页脚。覆盖层能滚得比真实页面更远,交接前不对齐就会同时看到两个页脚,像卡了一下。
- 分组阈值。原逻辑要求 ≥3 个同构节点,
RecommendedCard的列表行只有两行,永远复制不到;改成 ≥2 才复刻出视频里的「留白 → 复制」。 - 光标不是贴图。用一张静态箭头加文字名牌,和原版的多形态、热点、旋转、压缩放差得很远;最终全部改成 SVG 路径 + 每帧 transform。
- 复制不是 tween。固定时长平移看起来像「飞过去」;改成按光标实际位置
onStep同步偏移,才有 1:1 跟手的拖拽感。 - 声音不能等页面加载完再建。
AudioContext必须在用户手势里ensure()+resume(),否则被自动播放策略静音。 - 降级要彻底。
prefers-reduced-motion下两个触发口都不启动,直接退回「下滑一屏」。
七、验收清单
- [x] 点「开始」→ 扫描 → 建造 → 游览 → 收尾,全流程可完整播完。
- [x] 18 个光标从屏外聚拢,形态/热点/旋转/压缩放与原版一致。
- [x] 每个块都有
W × H徽章与四角手柄;文字逐字打出且带蓝色高亮。 - [x] 同构行出现「留白 → 1:1 跟手复制 → 两红框 + 间距 → 弹性落位」。
- [x] 声音全部为 Web Audio 合成,无外部音频文件。
- [x] Esc 可中断;「开始」可反复重播;
prefers-reduced-motion自动降级。 - [x] 收尾交接无跳变,清场后滚回原位;控制台零报错。
