QAT-Scaffold preset (Scaffold-GS PLY)
The splatforge-qat-scaffold preset is a
post-training Quant-Aware codec for Scaffold-GS PLYs.
It has two tiers with different inputs and different deliverables.
What the live single-PLY endpoint delivers
The default endpoint takes a single Scaffold-GS PLY (no GT cameras) and returns a smaller Scaffold-GS PLY using the lossless constant-strip prefix only. Measured on bonsai 30k:
- ~10.13% PLY-size save, lossless (deterministic dequant)
- Δ PSNR / SSIM / LPIPS = 0 by construction — codec asserts byte-exact attribute round-trip
- Encode wall ≈ 1.3 s on Modal; total round-trip ≈ 25 s including upload/download
Stripped fields are the eight Scaffold-GS columns the trainer
initialises and never updates (nx, ny, nz, opacity,
rot_0..rot_3). Bench data lives in
benches/encoders/qat-scaffold-gs/.
Full QAT recipe — premium tier (requires GT cameras)
The bench numbers below come from the full QAT recipe: constant-strip
plus int8 quant-aware retrain of f_anchor_feat plus int4
per-anchor quant of f_offset. The retrain pass needs
the original training images + COLMAP cameras to evaluate against,
so it ships as a separate
QAT-Bundle preset
(~$0.50/scene, ~10 min on A100). Pick QAT-Bundle (premium)
in the Try-it preset picker and drop a Scaffold-GS bundle archive —
see /docs/qat-bundle for the exact
layout and the per-scene expectations table.
Tier-1 of QAT-Bundle ships the int8 f_anchor_feat
finetune + lossless constant-strip; int4 offset stacking (the
extra ~7 percentage points to hit the headline 37% aggregate)
lands in a follow-up. Each job returns honest per-scene numbers
in the callback, so the customer always sees the actual ΔPSNR
their capture earned.
Bench numbers — full recipe, 6 scenes, 2026-05-16
Aggregate 37.25% PLY-size save across the six trained Mip-NeRF 360 scenes, with a positive PSNR delta on every scene (6/6). Per-scene breakdown:
| Scene | PLY save | Delta PSNR (dB) |
|---|---|---|
| bonsai | 40.51% | +0.581 |
| bicycle | 40.51% | +0.087 |
| garden | 40.51% | +0.198 |
| stump | 33.80% | +0.076 |
| treehill | 33.80% | +0.056 |
| flowers | 33.80% | +0.032 |
| Aggregate (6 scenes) | 37.25% | +0.172 (mean) |
Raw bench column lives at
benches/encoders/qat-scaffold-gs/ and the per-scene
cells are in benches/reports/splatbench-v0.json under
qatScaffoldGs. SSIM and LPIPS improve on every scene
too — see the leaderboard page for the full matrix.
Endpoint
POST https://api.splatforge.dev/v1/jobs
Authorization: Bearer <api_key>
Content-Type: application/json
{
"preset": "splatforge-qat-scaffold",
"blob_url": "https://blob.vercel-storage.com/uploads/<sha>-scaffold.ply",
"filename": "scaffold.ply"
} Auth
Every request needs Authorization: Bearer <api_key>.
New accounts get a free-tier key via the existing self-serve flow at
sales@splatforge.dev: Stripe Checkout submits the
email, the webhook issues an API key, and the key shows up in both
the receipt email and the account dashboard. No separate
QAT-Scaffold signup; the same key gates every preset.
Request / response
Same job shape as every other preset — only preset
changes. The API returns a job_id immediately and POSTs
the terminal result to your registered callback (or you can poll
GET /v1/jobs/<job_id>).
// 202 Accepted
{
"job_id": "01HZ9X2P8E4QXM6R0M3T7G1K8C",
"preset": "splatforge-qat-scaffold",
"status": "queued",
"estimated_compute_seconds": 360,
"estimated_cost_usd_cents": 18
}
// terminal callback (or GET /v1/jobs/<id>)
{
"job_id": "01HZ9X2P8E4QXM6R0M3T7G1K8C",
"status": "done",
"output_url": "https://blob.vercel-storage.com/outputs/<sha>-qat.ply",
"size_bytes_in": 136847392,
"size_bytes_out": 85946720,
"ply_save_pct": 37.2,
"delta_psnr_db": 0.17
} Input shapes
-
A Scaffold-GS PLY (single file). The encoder
reads the standard Scaffold attribute layout and rejects vanilla
3DGS PLYs with a clear error. Use the
hacpp-lzmapreset if you have a Scaffold bundle (PLY + MLP weights) instead of a flat PLY.
Output shape
A single Scaffold-GS PLY, smaller than the input. The file is self-contained — any Scaffold-GS-aware decoder can render it because the quantized streams are stored in standard PLY-attribute slots with documented quant scales in the header comment.
Rate limits
| Tier | Per-key request budget | Per-input size |
|---|---|---|
| Free | 1 scene / 24 h | <= 100 MB Scaffold PLY |
| Paid | No daily cap | No size cap (subject to Modal-side timeouts on enormous captures — talk to us if you have a >5 GB Scaffold) |
Rate limits are enforced per-key by the existing
splatforge_rate_limit middleware (PR #33). Free-tier
overage returns HTTP 429 with an
X-Free-Tier-Reset header pointing at the next
midnight UTC window.
Pricing
- Free tier: 1 scene/day, <= 100 MB input. No card required. Sign up at sales@splatforge.dev.
- Paid tier:
$0.50 / GB processed. Billed monthly via Stripe. No flat fee, no minimum, no daily cap. A typical 130 MB Scaffold PLY costs ~$0.065 / scene.
Use POST /v1/pricing/preview with
{ "size_bytes": <n>, "preset": "splatforge-qat-scaffold" }
to get a quote before submitting the job.
Worker dispatch
The public worker forwards every splatforge-qat-scaffold
enqueue to a private Modal app. The operator sets
SPLATFORGE_QAT_SCAFFOLD_URL in the
splatforge-preset-urls Modal secret to wire the route;
GET /healthz on the worker exposes a
preset_dispatch_configured.splatforge-qat-scaffold
bool so deploys are verifiable without inspecting secrets.
Anti-claims
- Not a vanilla 3DGS codec. The compression only
works on Scaffold-GS PLYs because it leans on Scaffold's
anchor-feature + offset structure. Use
fcgs-instantorhacpp-lzmafor non-Scaffold inputs. - Lossless in the codec sense != "pixel-identical". Dequant is deterministic, so the codec round-trip is reproducible and zero-error in attribute space. Render PSNR improves because the QAT pass nudges the Scaffold parameters toward a configuration that the quantized representation re-renders slightly better than the source.
- N=1 per scene today. All six scenes cleared the P2 gate at N=1 (minimum delta +0.032 dB > 0). N>=3 multi-seed runs are scheduled and will replace these cells when they land.
See also
The on-disk format produced by this preset is documented in the QAT-PLY v1 specification, with a zero-dependency C99 reference decoder and a 10-fixture conformance suite so any third-party renderer can decode SplatForge PLYs bit-exactly without a runtime SplatForge dependency.