A single page · 2026

·

你脚下的这片流动极光,是一枚实时光线步进的 WebGL2 片元着色器。
而这一页里所有的滚动魔法,几乎全部由 CSS 独立完成——没有一行滚动监听。
向下滚动,页面的色相会随你的位置环游整个色轮。

SCROLL ↓

第一章 · GPU 上的诗

背景不是视频,
是每帧现算的数学。

你看到的极光由 fbm(分形布朗运动)噪声场驱动:六个八度的值噪声互相叠加、扭曲, 再按滚动深度改变流速与色相,按鼠标位置弯曲流场。全部计算发生在 GPU 上, 每一帧、每一个像素、并行完成——这是任何视频素材都做不到的:它永不重复,且只有几 KB。

// 片元着色器核心:域扭曲的分形噪声
float fbm(vec2 p) {
  float v = 0.0, a = 0.5;
  for (int i = 0; i < 6; i++) {
    v += a * noise(p);
    p = p * 2.03 + vec2(1.7, 9.2);  // 旋转+平移打破网格感
    a *= 0.5;
  }
  return v;
}
// q 与 r:两层域扭曲,让噪声"流动"起来
vec2 q = vec2(fbm(p), fbm(p + vec2(5.2, 1.3)));
vec2 r = vec2(fbm(p + 4.0*q + u_time*0.15), fbm(p + 4.0*q + u_mouse));
float f = fbm(p + 4.0 * r);   // ← 你眼前的极光

第二章 · 滚动即时间线

这些动画,
一行 JavaScript 都没有。

2024 年落地、2026 年已可放心使用的 animation-timeline: scroll()view(), 把"滚动位置"变成了 CSS 动画的时间轴。右上角的进度环、章节的浮现、 全页色相的旋转、下方的横向画廊——统统跑在浏览器合成线程上,与主线程无关,永不掉帧。

scroll(root)

以整页滚动为时间轴。本页用它驱动进度环的 conic-gradient 角度,以及 --hue 从 260° 环游到 330° 的全局色相之旅。

view()

以"元素在视口中的位置"为时间轴。你看到的每一段文字浮现、每一张卡片上升,都是 view() + animation-range 的声明式产物。

@property

把 CSS 变量注册为可插值类型。本页用它让渐变角度、色相数字、甚至整数计数器都能被动画驱动——请看下面的统计数字。

本页滚动监听器
合成线程动画
噪声八度 / 帧
色相旅程

↑ 这些数字在滚入视口时从 0 计数到目标值——用的是 @property 注册的整数变量 + counter(),同样零 JS。

第三章 · 会呼吸的文字

文字随滚动
聚拢又散开

上面这行字的 letter-spacing、模糊与透明度被绑定到它自己穿越视口的进度上: 滚入时从雾中聚拢,滚出时重新散去。排版不再是静态的版面,而是与阅读节奏同步的乐器。 text-wrap: balance 则在你没注意的地方,悄悄让每个标题的断行两侧均衡。

终章

网页的极限
不在引擎里,
想象力里。

一个 HTML 文件。没有框架,没有构建,没有依赖。
一枚着色器、一组滚动时间线、一个色彩空间——以及把它们编成一次旅程的耐心。
Home 键回到开头,再走一遍:极光每一次都不一样。