Kowloon Knockout — WebGPU/TSL Graphics Overhaul¶
Date: 2026-06-25
Status: Design approved, pending implementation plan
Branch: kowloon-graphics-overhaul
Goal¶
Revamp the rendering of Kowloon Knockout from its current deliberately-low-res
procedural look into a full high-fidelity, modern real-time presentation —
“pushing to the edge of the graphics we can achieve” — built on WebGPURenderer
TSL with automatic WebGL2 fallback, desktop-first with graceful degradation tiers down to mobile.
Current state (baseline)¶
Stack: React Three Fiber
^9.6.1+ three.js^0.183.2,WebGLRendereronly. No WebGPU, no post-processing pipeline today.Art style: “3D pixel-art” = 100% procedural primitive geometry (cylinders, spheres, boxes, flat shading) rendered at half resolution (
dpr={0.5}) and nearest-neighbour upscaled (image-rendering: pixelated). Zero asset files — no models, textures, or sprites.Lighting: flat ambient + hemisphere + one 1024² shadow-casting directional
two neon point lights.
Animation: fully procedural / imperative limb rotations in
useFrame; no skeletal rig or clips.Particles: a 260-instance CPU-driven
InstancedMeshpool (Fx.tsx).Sim/net: deterministic fixed-timestep sim (
lib/kowloon-knockout/game/world.ts), host-authoritative over Socket.IO. Rendering reads a per-frameframesRefsnapshot — rendering is a pure cosmetic layer; nothing visual feeds the sim.Entry points:
components/kowloon-knockout/arena/GameView.tsx:91(Canvas),arena/Arena3D.tsx:28(scene/lights),arena/StickFighter.tsx(fighter + procedural anim),arena/Environment.tsx(procedural arena),arena/Fx.tsx(particles),vite.config.ts:138(three bundling).
Locked decisions¶
Art direction: Full high-fidelity (abandon the low-res pixelation).
Target hardware: Desktop-first, scale down via quality tiers; mobile stays playable but is not the showcase.
Renderer:
three/webgpuWebGPURenderer+ TSL node materials, relying on its automatic WebGL2-backend fallback (single material/shader graph for both).Assets / characters: Real skeletal characters via a shared humanoid rig
CC0/Mixamo animation clips; the 9 fighter classes are differentiated by PBR material params + procedural accessories, not bespoke per-fighter meshes. User sources Mixamo/CC0 files; the runtime (loading, mixer, state machine, materials) is built here. Fighters we can’t source well fall back to upgraded procedural geometry.
Architecture principles¶
The combat sim, networking, and input are untouched.
world.ts,net/*, and input handling stay exactly as-is. The entire overhaul lives incomponents/kowloon-knockout/arena/plus a new material/post/tier layer.Multiplayer determinism is unaffected by construction — the visual layer only ever reads the sim snapshot. Host/guest smoke tests run after each phase regardless.
Quality tiers, not one renderer. A
Ultra / High / Medium / Lowtier system gates expensive techniques, auto-detected from WebGPU availability + a GPU heuristic + an adaptive FPS governor.Low≈ today’s look and doubles as the mobile/WebGL fallback. The existing proceduralStickFighter/Environmentpath is kept as theLowtier, not deleted.Rollout behind a flag. The new rendering path lives alongside the old one, toggled by a feature flag + the tier system, so work ships and is compared incrementally without breaking the live game.
Phased plan (each phase independently shippable)¶
Phase 0 — WebGPU foundation (parity)¶
Swap
<Canvas>to a customglfactory returningnew WebGPURenderer(props)fromthree/webgpu, awaitinginit()(R3F v9 async/promise path; holdframeloopuntil ready).extend(THREE)from the webgpu build.Migrate all materials:
meshStandardMaterial → MeshStandardNodeMaterial; thetoneMapped={false}neon basics →MeshBasicNodeMaterialwith emissive nodes. Centralize in a<KKMaterials>/ material-factory helper so per-class colors flow through one place.Drop
dpr={0.5}andimage-rendering: pixelated; render native res (DPR capped ~2).Exit criteria: visual parity with today on both WebGPU and the WebGL2 fallback backend.
Phase 1 — Lighting + PBR + post-processing (the payoff)¶
Lighting rebuild in
Arena3D: keyed directional with 2048–4096 shadow map, neon point/area lights as real PBR emitters, and IBL from an HDRI environment (night-city HDR or a procedurally-built env map) for real reflections/ambient. Replaces flat ambient+hemisphere.PBR materials: real metalness/roughness on the procedural meshes + subtle procedural normal/roughness detail via TSL (no texture files required yet). Neon stays emissive.
Post-processing via the WebGPU
PostProcessingnode pipeline (TSL passes), WebGL fallback via equivalent passes:Bloom on emissives — headline effect; the neon finally glows.
Tonemapping (ACES or AgX) + color grading (LUT) for the noir palette.
GTAO/SSAO for contact shadows / grounding.
Optional tier-gated toggles: vignette, chromatic aberration, film grain.
This phase delivers the biggest visual jump on the existing procedural geometry.
Phase 2 — Environment overhaul¶
Wet PBR rooftop with SSR reflections catching the neon.
Volumetric fog (raymarched / froxel-lite, tier-gated) for atmosphere.
Animated emissive signage (TSL flicker/scroll).
Parallax / instanced skyline depth. Mix of procedural + optional CC0 modular props.
Phase 3 — GPU compute particles¶
Port the 260-instance CPU pool (
Fx.tsx) to a TSL compute particle system — hit sparks, embers, ambient rain/dust, KO bursts at thousands of particles.WebGL fallback keeps the instanced CPU pool. Driven by the same FX event stream.
Phase 4 — Skeletal characters¶
New fighter renderer: load shared rigged GLB,
AnimationMixer, a state machine mapping sim state (idle / walk / punch / block / hit / stun / KO) → clips with crossfade blending; root motion stripped (sim owns position/facing).Per-class identity via PBR material params + procedural accessories (the existing headband concept, extended).
Falls back to procedural
StickFighteratLowtier. User sources Mixamo/CC0 clips; runtime is built here.
Phase 5 — Tiers, scaling, settings, validation¶
Implement the tier table below with an adaptive governor (rolling frametime average; step tier down if it exceeds budget for N frames; settings toggle to lock the tier).
Detection: WebGPU presence +
WEBGL_debug_renderer_infoGPU-string heuristic + optional quick first-load benchmark.New settings panel for manual tier override.
Validate mobile/WebGL2 fallback path.
Quality tiers¶
Tier |
Target |
Post |
Shadows |
Particles |
Characters |
|---|---|---|---|---|---|
Ultra |
Desktop WebGPU |
Bloom + GTAO + SSR + volumetrics |
4096 |
GPU compute |
Skeletal |
High |
Capable desktop |
Bloom + GTAO |
2048 |
GPU compute |
Skeletal |
Medium |
Laptop / iGPU |
Bloom only |
1024 |
Instanced |
Skeletal (or procedural) |
Low |
Mobile / WebGL2 |
none |
1024 |
Instanced |
Procedural (today’s look) |
Risks & mitigations¶
R3F v9 + WebGPU maturity (async init, suspense edge cases) — Phase 0 is the renderer swap at parity, isolating this risk before any visual work.
Material-migration regressions (every mesh changes) — centralized material helper + parity screenshots.
Bundle size (skinned meshes, clips, HDRIs vs. today’s zero-asset game) — keep the existing lazy-load; load HDRI/models per-tier; compress with Draco/KTX2.
Mobile WebGPU is spotty — the
Lowtier IS the WebGL2/procedural path, so mobile keeps something close to today.Asset sourcing / licensing (Mixamo/CC0) — user fetches, licenses vetted; Phase 4 is last so it never blocks the visual win.
Multiplayer — unaffected by design (cosmetic layer only); host+guest smoke-tested after each phase anyway.
Testing per phase¶
Visual parity / screenshot checks (especially Phase 0).
FPS on a desktop profile + a throttled/mobile profile.
Host + guest multiplayer smoke test to confirm sim/net untouched.
Out of scope¶
Changes to combat sim, balance, networking protocol, lobby/matchmaking.
Bespoke artist-authored per-fighter models (shared rig + materials instead).
New game modes or gameplay features.
Notes / cleanup opportunities¶
@react-three/rapieris bundled intovendor-threebut unused by this game — candidate for removal from the chunk to trim the bundle.