Three.js From Zero · Article s8-10
S8-10 Shipping Checklist
Season 8 · Article 10 · Finale
The Shipping Checklist
From 90% done to actually shipped. 8 categories, 40-ish items. The production punch list every 3D app should pass before hitting "Deploy."
🏁 Season 8 finale — Production Architecture concludes
Assets (S6)
- All models passed
gltf-transform validate - Geometries compressed (Draco or Meshopt)
- Textures compressed (KTX2 with UASTC for normals, ETC1S for rest)
- Textures no larger than needed (2K mobile max, 4K desktop max)
- LOD levels authored for any mesh appearing at varying distances
- Texture atlases built where ≥10 similar assets
- Assets served with
immutable, max-age=31536000cache headers - CDN with Brotli compression on .json/.gltf
Rendering quality
- Color management set:
outputColorSpace = SRGBColorSpace, textures flagged correctly - Tone mapping picked (
ACESFilmicToneMapping) and exposure tuned - PMREM environment set for PBR materials to have specular IBL
- Shadow map size appropriate (1024 or 2048, not 4096 default)
- Pixel ratio clamped:
renderer.setPixelRatio(Math.min(devicePixelRatio, 2)) - Post-processing gated by device tier (skip bloom/DOF/SSAO on low)
Performance
- Named imports from 'three' — no
* as THREE - GLTFLoader / DRACOLoader / KTX2Loader lazy-imported
- Bundle analyzer run, nothing > 200KB surprise
- Total JS bundle < 300KB (first paint)
- FPS p10 ≥ 30 on low-tier device (tested)
- Frustum culling enabled on Meshes (default, verify)
- Instancing (InstancedMesh/BatchedMesh) for repeated geometry
- Animation mixer paused when tab inactive
UI & UX (S7)
- Loading state shown — never blank canvas on load
- Error states messaged — never silent failure
- Touch gestures work on mobile (
touch-action: none) - Keyboard alternative for every gesture (arrow keys, Tab)
- aria-label on canvas container
- Screen reader announcements via aria-live
- prefers-reduced-motion respected
- Text uses MSDF or sharp HTML overlay (not blurry canvas)
Reliability
webglcontextlosthandler withpreventDefault()webglcontextrestoredhandler that reinit's- GLTFLoader error callback handles failures with fallback
- Network requests have timeouts (10s or less)
- Capability tiers detected, rendering adjusted
- No-WebGL fallback (static image + message)
Observability
- web-vitals LCP/CLS/INP reporting
- Custom "3D ready" metric
- FPS p10/p50/p90 reporting (not just avg)
- Long Task Observer hooked
- Error tracking (window.error + unhandledrejection)
- Device tier segmentation on all metrics
- Alerting on p10 FPS regression
Security & privacy
- CSP headers set (allow unpkg/CDN you actually use, nothing more)
- Self-hosted Draco + Basis decoders (not gstatic in prod)
- No PII in telemetry events
- GDPR: telemetry requires consent (or anonymous)
- User-generated 3D content validated (size, format, malicious glTF)
Launch day
- Feature flag ready (Launch Darkly, GrowthBook, manual) to disable 3D if something breaks
- Rollback plan: previous deploy tagged and ready
- On-call engineer identified
- Dashboards bookmarked and tested
- 10% gradual rollout, not 100% big bang
- Cross-device smoke test: Quest, iPhone, Chromebook, modern Mac
- Lighthouse score >= 90
Season 8 recap
State → ECS → loops → authoring → debug → testing → errors → build → telemetry → checklist.
The engineering scaffolding that turns a demo into a product. Every item here either catches or prevents a production outage.
Season 9 next
Real-time Systems & Audio. WebRTC for voice/video streams. Web Audio API deep dive. Spatial audio. Convolution reverb. Audio-reactive visuals. Multiplayer sync. The sound half of "3D experience."