ENZH
和 AI 讨论这篇文章
ChatGPTClaude

我给网站塞了一只会开枪的螃蟹

前段时间朋友给我发了个链接,pretext,一个不碰 DOM 就能量文本布局的库。我点进 demo 看了一眼,挺震撼的:十万个文字方块在做瀑布流排版,120fps;文字能绕着移动的障碍物实时排版;还有人拿它做了个物理引擎,每个字符变成粒子,点哪里哪里爆炸。

我自己的作品集网站 xiax.xyz 本来就是终端风格的,整个界面全是文字,看完第一反应就是这套东西太适合搬过来了。反正折腾了六个小时,两个网站都有了粒子物理、弹跳子弹,还有一只会开机枪的像素螃蟹。这篇讲一下具体是怎么做的,中间翻了四次车,也一起讲。

终端网站这边比较顺

xiax.xyz 是个 macOS 终端模拟器,纯 vanilla JS,零依赖,文字就是整个界面,做文字特效基本是最理想的场地。

第一个特效是切标签页的爆炸:点一个新标签页,屏幕上每个可见字符都变成一个物理粒子,从点击位置往外散射。用的是反平方力,跟真实爆炸一个原理,再加上重力、空气阻力、旋转,每个粒子飞着飞着就淡出了。物理公式很简单:

力 = 爆炸常数 / 距离²
速度 *= 空气阻力    // 每帧 × 0.965
速度.y += 重力 × dt  // 580 像素/秒²

公式简单,手感是真的好。爆炸完之后,终端的打字机效果接着一个字一个字敲出新标签的内容。前面刚炸完、后面慢慢敲,这个节奏我自己还挺喜欢的。

然后是螃蟹。我找到了 clawd-tank,一个全是 claude 吉祥物(就是那只螃蟹)动画 SVG 的仓库。走路动画是纯 CSS 关键帧做的:身体上下晃,腿交替迈步,钳子摆动,眼睛还会眨。一共 24 种动画,打字的、睡觉的、丢球的都有。

我给它设计的交互大概是这样的:

  1. 终端区域双击,螃蟹出现,鼠标指针消失
  2. 移动鼠标,螃蟹跟着走,朝移动方向转身,完整 360 度
  3. 长按鼠标,朝面对的方向扫射子弹;按得越久射速越快,从 6 发/秒一路飙到 40 发/秒,散布角也越来越大
  4. 子弹打到字符,字符获得一个速度冲量,直接被推飞;打到墙壁就弹跳,保留 55% 的能量,继续乱弹
  5. 松开鼠标,字符靠弹簧物理慢慢回到原位
  6. 鼠标移出或者按 Escape,螃蟹淡出,一切恢复原样

字符回弹用的是弹簧-阻尼模型:

速度 += (家 - 当前位置) × 弹力系数
速度 *= 阻尼
位置 += 速度

字符在原位置附近振荡几下就自然稳定了。整个过程 60fps,零 reflow,全部在 canvas 上渲染。

字符特效的物理回路:反平方力把字符炸开散射、受重力和空气阻力下落,再由弹簧力拉回原位振荡到稳定字符特效的物理回路:反平方力把字符炸开散射、受重力和空气阻力下落,再由弹簧力拉回原位振荡到稳定

搬到博客,开始翻车

博客 nlog.xiax.xyz 跑的是 Next.js,比终端那个单容器 vanilla JS 复杂太多了。我一开始的思路是把终端那套直接搬过去:把页面上的文字提取出来,画到 canvas 上。讲道理这个思路在终端上是成立的——单个可滚动的 div,等宽字体,文字不重叠。但博客不是这样,它有 sticky 头部、会折叠的 <details>、absolute 定位的 UI、可变字体,还有好几个 z 层级。把所有文字平铺到一个 canvas 上,出来就是一团糊,文字全叠在一起,根本没法看。

隐藏原始 DOM 这一步我一共试了四种方案,四种全翻:

  1. visibility: hidden——失败,CSS 优先级问题
  2. opacity: 0——失败,canvas 也是 body 的子元素,跟着一起被隐掉了
  3. color: transparent——失败,文字是透明了,但图片、边框、背景色全都还在
  4. 把 canvas 挂到 <html> 上——好一点,文字还是重叠

翻到第四次我才反应过来,问题不在怎么隐藏 DOM,是根本就不该在 canvas 上画文字。最后的方案完全换了个思路:canvas 是透明的,只画子弹粒子,就是一些橙色小点;Clawd 本体是一个 fixed 定位的 <img>,CSS 动画原生播放;子弹打到 DOM 元素的时候,用 CSS transform 把元素推开,元素自己再弹回来。

这样页面从头到尾都是浏览器正常渲染的,链接能点,图片能看,布局是对的。螃蟹和子弹只是叠在上面的一层视觉效果,但冲击波是在真实的 DOM 里传的。感觉这个教训挺通用的:把文字提取出来画到 canvas 这条路,只在简单布局上走得通,页面一复杂就不行了。

把文字提取到 Canvas 在复杂布局上翻车,改成透明 Canvas 只画子弹、用 CSS transform 去推真实 DOM 才成立把文字提取到 Canvas 在复杂布局上翻车,改成透明 Canvas 只画子弹、用 CSS transform 去推真实 DOM 才成立

博客上的全部特效

除了 Clawd,博客还塞了 6 个彩蛋:

特效触发方式
Clawd 机枪螃蟹任何页面双击
文章卡片爆炸点击首页的文章 → 卡片文字炸开,然后跳转
标签云物理点一个标签 → 其他标签弹射散开
代码块爆炸双击代码块 → 字符炸开然后重组
阅读奖励滚到文章最底部 → 五彩纸屑爆发
科乐美密码↑↑↓↓←→←→BA → 永久 Clawd 模式(跨页面保持)

所有特效都用 dynamic import 避免 SSR 问题,尊重 prefers-reduced-motion 设置,加载失败也不影响正常浏览。

claude code 实际写了什么

整个特效引擎——900 多行 canvas 物理、字符提取、粒子系统、Clawd 交互——是 claude code 在一个 session 里写完的。两个网站加起来 2000 多行新代码,改了 10 多个文件。

物理这块反而好写,反平方力、弹簧阻尼都是经典算法,到处有现成的讲解。花时间的是浏览器集成这些杂事:canvas 怎么定位、隐藏元素上的事件代理、移动端触摸事件怎么协调,还有上面那场 DOM 隐藏的拉锯。这种东西人来写可能要一周。让 AI 写的话,实现量基本不是问题,我要做的就剩判断了,比如翻了四次车之后说别再折腾隐藏 DOM 了,换思路,就是这种决定。

想玩的话:

  • 终端网站 xiax.xyz:终端区域双击,移动鼠标,长按射击,拖动瞄准,能看子弹到处弹
  • 博客 nlog.xiax.xyz:任何页面双击,子弹会把真实的 DOM 元素推开
  • 科乐美密码:在博客任意页面按 ↑↑↓↓←→←→BA,进入永久 Clawd 模式,跨页面都不会消失

特效引擎源码:terminal-site/effects.js。螃蟹 SVG 来自 clawd-tank。灵感来自 pretextpretext-explosive

和 AI 讨论这篇文章
ChatGPTClaude

订阅更新

新文章发布时发到你的邮箱,不发别的。


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0