Layers 工程团队成功将 103,802 个手工放置的点文件大小从巨大的 175 MB Illustrator 导出文件缩减至仅 82 KB。这一优化对于确保复杂的交互式插图能够在低端设备上平滑渲染且不出现抖动或延迟至关重要。

一组由手工放置的点渲染出的 13 个不同插图,包括商品和类别图标。
13 个由 Layers 从其手工放置的点渲染出的插图,展示了各种产品标记和类别图标。layers.engineering

这张图片展示了用于 Layers 界面的手工放置点的最终输出。

一个对数比例柱状图,比较 Illustrator SVG 导出、Float32 导出、未压缩的 DOT2 和压缩后的 DOT2 的文件大小。
一个对数比例柱状图,比较不同导出格式的文件大小,显示从 175 MB 到 82 KB 的缩减。layers.engineering

该图表直观展示了工程团队实现的几何数据传输的巨大缩减。

识别数据冗余

原始作品由图案设计师 Alberto Larizza 创建,包含超过 100,000 个点。当作为 SVG 导出时,这些点被表示为圆形、椭圆和路径的混合体,导致产生了高达 175 MB 的源数据。

对数据的分析揭示了一个显著的结构模式:由于艺术家是按行构建图案的,78% 到 99% 的点拥有完全相同的 Y 坐标。相反,X 坐标保持高熵状态,几乎每个值都是小数。

商品插图的裁剪图,显示连接在同一行中的点上的微弱线条,以及显示零 Y 增量的数据条。
点数据的视觉分析显示,由于艺术家的按行工作流程,90% 的 Y 增量为零。layers.engineering

此视觉效果解释了数据结构模式,即点共享相同的 Y 坐标。

“实际上,‘平面’结构完成了大部分工作(超过一半)。一旦它变成独立的流,Brotli 就能看到连续成千上万个重复的行值。”

— Shipping 103,802 Dots in 82 KB

DOT2 二进制格式

为了缩小数据,团队开发了 'DOT2',这是一种自定义的二进制格式。该过程包括将坐标量化为 uint16,将半径缩放为 uint8,并将数值作为相对于前一个点的增量(deltas)进行存储。至关重要的是,数据是按“平面”存储的——即所有的 X 增量、然后所有的 Y 增量、最后所有的半径——而不是交错存储。

这种平面布局允许 Brotli 压缩算法在单个流中看到成千上万个重复的行值。虽然增量提供了少量的收益,但平面组织贡献了超过一半的总尺寸缩减,使最终压缩后的尺寸降至 82 KB。

一个显示商品插图 DOT2 布局的图表,分解为标头、X 增量、Y 增量和半径。
DOT2 布局结构,展示了如何将数据组织成平面以最大化 Brotli 压缩效率。layers.engineering

此图表说明了自定义二进制格式的平面组织。

插图尺寸缩减步骤: Float32 源文件 1.25 MB; Float32 + Brotli 224 KB; Quantized interleaved 227 KB; Quantized sorted interleaved 240 KB; Quantized sorted planar 83 KB; DOT2 82 KB
插图尺寸缩减步骤layers.engineering

HN Digest 根据 layers.engineering 报告的数据绘制的图表;数值按源文件所示。

该格式是有损的,但团队验证了最大坐标误差仍低于 0.011px,半径误差小于 0.0065px,这对用户来说是不可察觉的。

运行时和渲染优化

除了减少传输格式外,团队还优化了浏览器处理这些点的方式。他们从基于对象系统(其中每个点都是包含 11 个字段的 JavaScript 对象)转向了十个扁平化的类型化数组(Float64Array)。这确保了弹簧物理计算与原始原型保持位对位的完全一致。

团队还彻底重构了背景网格的渲染。旧的循环在每一帧中访问网格中的每个单元格;新的循环仅访问活动单元格以及用户光标所在的特定边界框。这一变化允许页面在网格闲置时完全停止请求动画帧。