Half the head, same face
My point-cloud head was 3.2MB over the wire. Sorting the points and dropping precision nobody can see took it to 1.5MB.
The head on my home page is a point cloud: 150,000 dots, each with a position, a colour and a few values the shader uses to make it breathe and blink.
It took about 14 seconds to appear on a slow connection. The file was the same size as the one on the site I based mine on, so I assumed size was not the problem. It was.
The points were in random order
Compression works by finding repetition. My points were stored in the order the scan produced them, which is close to random. Neighbouring bytes had nothing in common, so brotli could barely shrink the file.
I sorted the points along a Morton curve. Points that sit close together in 3D now sit close together in the file, so their coordinates share most of their bits. Same data, same file format, but it compresses far better.
Precision nobody can see
Each coordinate was stored as 16 bits. On screen the head is about 900 pixels tall, so 12 bits (4,096 steps) is already finer than a pixel. Colour went from 256 levels to 64. The random seed each point uses for its shimmer went from a 32-bit float to one byte.
I compared screenshots side by side and could not tell them apart.
The numbers
| Before | After | |
|---|---|---|
| Full head | 3.24MB | 1.50MB |
| Preview head | 0.48MB | 0.34MB |
| Depth mesh | 0.61MB | 0.48MB |
On a throttled 5Mbit connection the head now lands in about 5.5 seconds instead of 14. On a second visit it is instant, because the files are cached for a year and versioned by URL.
One trap: mobile only draws the first 45,000 points. A plain sort would have given phones one corner of my face, so I sorted the first 45,000 and the rest as two separate runs.