SplatRs: The Week the Gap Closed
SplatRs is a 3D Gaussian Splatting trainer and renderer written in Rust — GPU compute in WGSL via wgpu, running on a single Mac Studio. The benchmark discipline: every quality number is measured on held-out views of the Tanks & Temples “train” scene, on the exact 38-view split nerfstudio’s splatfacto uses, so the two systems are directly comparable.
A week ago the honest gap to splatfacto was 6.45 dB. Today it’s 5.30 — and the week taught us more than the delta suggests.

Left: our engine rendering a camera view it was never trained on, 30k iterations, 1.5 hours. Right: the photo.
One plot to redirect a roadmap
We’d assumed the gap was mostly capacity — splatfacto trains ~300k gaussians, our GPU budget capped us near 60–150k. So we measured it: quality vs gaussian count for both systems on the same test set.

The curves touch at ~150k. Then splatfacto adds +6 dB at essentially constant count, through pure optimization. Measured capacity yield: under 0.8 dB per count doubling. The gap was recipe, not capacity. Everything else this week followed from this plot.
Recipe, part 1: opacity floors
Our reset/prune opacity thresholds were 20× lower than splatfacto’s — 90%+ of our population sat below visible opacity, unprunable, memorizing training views. Raising the pair 5× flipped the late training phase from decaying to climbing: +1.07 dB, with half the gaussians. The dose-response curve peaked cleanly — 20× overshoots, because aggressive culling eats useful dim mass.
Recipe, part 2: the loss split
Re-testing L1+DSSIM (an old refutation from a buggier era) produced a puzzle: PSNR got worse, but renders looked unmistakably better and LPIPS agreed. Our harness was PSNR-blind — so we made SSIM a first-class eval column and batch-scored LPIPS.
Then the settle-phase decay under DSSIM turned out to be our own anisotropy pruner: tuned for L2, it was culling exactly the long skinny gaussians DSSIM uses to hug edges, ~1,000 per pass, in a cull-regrow treadmill. One flag (needle prune off) and DSSIM won every metric simultaneously.

Same data, same budget, same schedule. The only difference between left and middle is the loss function: 15.76 → 16.91 dB, and perceptual error (LPIPS) nearly halved, 0.556 → 0.240.
Throughput: the tile rasterizer
With the recipe settled, quality experiments were bottlenecked on a naive O(pixels × gaussians) rasterizer: 12.5 hours per 30k-iteration run. We built a tile-binned rasterizer in WGSL — project, count, emit, sort, range, blend — each stage behind a flag and gated bit-exact against the naive renderer as an oracle.
Forward up to 25.7× faster, backward up to 36.5×, and the only acceptable training-equivalence number: 0.0000 dB divergence over 500 iterations. The same showcase run now takes 1.5 hours and scored slightly higher. Every experiment is now a lunch break instead of an overnight.

The bugs you only find by looking
While assembling a report we noticed magenta smudges in a saved training target. The original photo was clean. The culprit: the JPEG decoder our image library is version-locked to corrupts the chroma plane in patches — ~0.2% of every image’s pixels, in every training and eval image, for weeks. Three other decoders read the same files perfectly.

One loader swap later, training data is clean. Weeks of A/B verdicts survived — both arms saw identical corruption — but it’s a lesson in actually looking at your data.
Full-resolution training then found two more: our GPU device was silently created with a 128 MiB buffer-binding cap (the hardware supports 4 GiB), and fixing that exposed a compute dispatch that needed 65,536 workgroups against a hard API limit of 65,535. Both fixed, both now guarded by pre-flight checks; the GPU pipeline then ran 30k full-res iterations at 400k gaussians without a fault.
Negative results are results
Absgrad densification — the reference’s own detail-growth heuristic — lost its A/B here by 0.45 dB. Reset-schedule levers refused to stack. And the first healthy full-res run produced fog: the standard periodic opacity reset, harmless at half resolution, is a 17× cut to a DSSIM-trained population that full-res optimization rates can never recover from.

Sharp at iteration 3,000; fog by 30,000. The telemetry pinned the mechanism in an evening, and the fix arm was running the same night. Negative results get recorded so they never get re-run.
What’s next
Full-resolution training with a survivable reset schedule — the model literally cannot learn detail it’s never seen:

Then re-measuring the capacity/recipe split with clean data.
5.3 dB to go. We know where it lives.