shrinkgod/README.md
type-two c8c37dc0c5 Draco input support + headless CLI
- Shared pipeline extracted to src/pipeline.js (browser + node run identical logic)
- Draco: vendored decoder WASM in public/draco/, lazy-registered by peeking the
  GLB JSON chunk before read (gltf-transform fails cryptically on a mid-read
  missing dependency); DRACOLoader wired into the viewer; extension stripped on
  write so output is standard GLB
- bin/cli.js: NodeIO + draco3dgltf + sharp textures, presets/flag overrides,
  batch with --outdir, per-file report

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 23:37:02 +10:00

60 lines
2.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🗜️ SHRINKGOD — local GLB optimizer
Drop in a heavy GLB, pick a target, compare original vs optimized side-by-side (synced camera, animation playback, wireframe), export. **Everything runs client-side in the browser** — gltf-transform + meshoptimizer WASM. No uploads, files never leave the machine.
## Run
```bash
npm install
npm run dev # http://localhost:5173
npm run build # static build in dist/ — host anywhere, still fully local
```
Dev test hook: `?test=<file-in-public>.glb&run=1` auto-loads and optimizes.
## CLI (batch / farm use)
Same pipeline, headless — sharp for textures (faster than the browser canvas path):
```bash
node bin/cli.js model.glb # -> model.opt.glb (balanced)
node bin/cli.js --preset crunch *.glb --outdir out/
node bin/cli.js model.glb --ratio 0.15 --max-tex 512 -o small.glb
node bin/cli.js --help # all flags
```
`npm link` (or install from the repo) puts a `shrinkgod` command on PATH. Rig protection applies identically.
## Pipeline
dedup → flatten+join (static models only) → weld → per-primitive meshopt simplify → animation resample → prune → texture resize/re-encode → quantize → (optional) meshopt compression.
### Rig protection (automatic)
- Skinned meshes never go below **50% kept geometry** and error is capped at 0.5% — vertex collapse near joints wrecks skin weights in motion.
- Morph-target (blendshape) primitives are left untouched.
- Mesh joining is disabled for rigged/animated models (would break node animation).
- Best results: **optimize before rigging** — static geometry can be crunched far harder.
### Textures
- Longest side clamped to the chosen max (canvas re-encode).
- Color/emissive maps optionally converted to WebP (quality slider); normal/roughness/occlusion maps always stay lossless PNG.
- Re-encode is skipped if it wouldn't shrink the file.
### Presets
| | geometry kept | error | max texture | webp |
|---|---|---|---|---|
| Light | 50% | 0.5% | 2048 | no |
| Balanced | 25% | 1% | 1024 | yes |
| Crunch | 10% | 5% | 512 | yes |
## Draco input
Draco-compressed GLBs are decoded on load (decoder WASM is vendored in `public/draco/` — still fully local, no CDN) and written back out as standard uncompressed GLB. Draco *output* is intentionally not supported; use meshopt compression for web targets instead.
## Known limits
- Meshopt compression output (`EXT_meshopt_compression`) reads fine in three.js but **not in Blender** — leave it off for assets going back into a DCC.
- KTX2/basis textures pass through untouched.
## Bench (M5 MacBook Pro, Balanced preset)
- 15.8 MB photogrammetry room scan (151k tris, 13 MB textures) → **1.5 MB** (90%) in 5 s.
- 3.5 MB rigged character (18.6k tris, 20 clips) → **2.7 MB** (24%), clips + skinning intact (rig clamp limits geometry reduction by design).