一片星海,缓缓聚拢成新世代的形状
向下滚动,星点散开成无垠星海,再重新聚拢成指针、聚成结。按住拖动可以旋转整片星域。
它是怎么工作的
这不是视频,也不是序列帧。整片星海是一个 WebGL 粒子场,每一颗粒子同时持有两套坐标:一套是散布在全屏的星点位置,另一套是从 SVG 路径上采样出来的目标位置。
滚动位置决定一个叫 disperse 的标量——原页面把它写死为 1,配 flowSpeed: 0.8 与 easing: smoothstep。在片元坐标里插值时,粒子在两套坐标之间平滑过渡:disperse → 0 时聚成形状,disperse → 1 时散成星点。缓动用 smoothstep,所以两端都是软着陆,不会突兀。
关键在于形状目标点的采样方式。下面两个形态直接取自 OpenAI 原页面的内联 SVG path——鼠标指针是 viewBox="0 0 19 19"、描边 0.8;Astra 结是 viewBox="0 0 1726 1538" 的六段三次贝塞尔、描边 80。粒子沿路径等弧长取样,再沿法线方向做高斯偏移,于是自然填满了描边带。
鼠标交互分两层:指针附近产生一个径向斥力加切向涡旋,把粒子推开的同时卷起来;命中范围内的粒子额外放大、提亮,形成一圈局部辉光。
鼠标指针
等弧长取样 + 法线高斯偏移;按 R 重播,H 收起界面。
为什么看起来像星系
聚拢态并非静止。每个粒子在顶点着色器里都有一条独立的相位轨道:angle = time × flow × (0.010 + seed × 0.030),散开时权重接近 1,聚拢时趋近 0。再叠一层极小的呼吸抖动,形状就有了生命感,同时不会糊掉边缘。
旋转用的是同一个 uRot。因为所有位移都在等比空间(先乘上宽高比再旋转)里完成,所以不管窗口多宽,旋转都是正圆而不是被拉扁的椭圆。
Astra 结
六段三次贝塞尔,粒子数按各段弧长比例分配,所以粗细完全均匀。
可以拆开看的几件事
- 形态布局:高度锁定为
0.8 × 视口高,最大宽度576px,等比缩放居中——与原页面的--astra-shape-height/--astra-shape-max-width一致。 - 冷暖双色:粒子按种子在冷白蓝与暖琥珀之间取值,模拟色温混杂的星场。
- 双通道叠加:先画一层三倍尺寸、极低透明度的辉光,再画一层锐利核心,加法混合自然形成光晕。
- 指针惯性:松手后保留角速度并按
e^(-4.2t)衰减;方向键同样可以旋转。
整页零依赖、零构建、零网络请求,全部逻辑与着色器内联在单个 HTML 文件里。