这个网站没有一张“直接显示”的照片。你看到的每一张图,都由几万个字符颗粒拼成:它们先在安全灯下以红色潜影出现,再像相纸在显影液里那样,一点一点变成彩色。这篇记录它是怎么做的。
颗粒是字符
页面背后只有一个固定的 WebGL 画布,上面铺着一张网格:桌面端每 3.6 像素一个点,大约十万个。每个点在着色器里从照片取色,同时记着自己在一段代码里的位置——首页用的是一行“显影”的代码。显影之前,点被画成那个字符;显影之后,它变成一颗圆形的银盐颗粒。
float shape = mix(glyph, disc, vDev);vec3 latent = uSafe * (0.18 + vLuma * 1.25);gl_FragColor = vec4(mix(latent, vColor, vDev), shape * vAlpha);暗部先显影
真实的相纸在显影液里,最先出现的是阴影:银盐最密的地方先变黑。所以每个颗粒的显影进度都减去了它自己的亮度,再加一点随机。画面从暗处开始浮出来,而不是整张一起淡入。
float dev = clamp((uDevelop * 1.7 - luma * 0.5 - aRand * 0.35) / 0.85, 0.0, 1.0);药水是一个波动方程
鼠标划过时的涟漪,是在一张四分之一分辨率的浮点纹理上解二维波动方程:每一帧,新的高度等于四个邻居之和的一半,减去上一帧的高度,再乘一点阻尼。颗粒按液面的坡度偏移,看起来就像隔着一层晃动的药水看照片。没人碰的时候,它也会每隔几秒自己滴下一滴。
float h = (sum * 0.5 - s.g) * 0.982;h += uDrop.z * exp(-dot(d, d) / (uRadius * uRadius));反相与转场
影像区用的不是 WebGL,而是 CSS:invert() 把照片反相,再叠一层安全灯的红色。离屏幕中心越近,反相越少,滑到正中间时就显影出原本的颜色。页面之间的转场是两条电影遮幅黑条,中间留一道安全灯的红缝。
克制
所有的花样都放在画面里,文字反而很小:界面 11 像素,正文 15 像素。慢的设备会被自动降级:前 60 帧平均超过 24 毫秒,颗粒就变少、变大;系统开了“减弱动效”,所有位移都会关掉,内容依然完整。
