The question this spike answers
How realistic can the trainer game look on the owner's Pixel Tablet, at a sustained frame rate, with three.js as it is? Measured on the device — not argued. #431 (the ADR that takes the world realistic) rests on this, so it is written from numbers rather than from research alone.
A spike: a dated measurement that decides nothing (CLAUDE.md §7). Write-up in docs/spikes/NNNN-realism-on-the-device-floor.md. Refs epic #429.
What is already known (read 2026-09-21)
Device, read over adb and from inside the app's WebView with apps/mobile/tools/webview-probe.mjs:
|
|
| Device |
Pixel Tablet, Google Tensor G2 (GS201), Mali-G710, 7.6 GB, Android 17, WebView 151.0.7922.199 |
| WebGL2 |
yes — MAX_TEXTURE_SIZE 8192, WEBGL_compressed_texture_astc and _etc present, EXT_color_buffer_float present |
| WebGPU |
navigator.gpu present and requestAdapter() returns an adapter (arm / valhall, max 2D texture 16384) |
| Viewport |
800 × 1280 CSS px at DPR 2 → 1600 × 2560 physical |
| Frame budget today |
the only device ride measured: frame 13 ms, GPU 6 ms at the 50th percentile (validation 0002 §"The baseline") — about 10 ms of GPU headroom at 60 fps |
Research (tavily, 2026-09-21; sources in the write-up): the highest realism per millisecond on Mali-class GPUs is image-based lighting from an HDRI + filmic tone mapping, compressed PBR textures (KTX2/ASTC), lighting baked into instanced models, impostor billboards for distant trees, cheap distance/height haze and bloom (~0.3 ms). Expensive at 2560 × 1600: SSAO (~3 ms+), cascaded shadows (~1–3 ms), volumetric clouds, dynamic GI. WebGPURenderer reports on Mali are mixed (driver issues; slower than WebGL for non-instanced scenes) — so the spike measures on WebGLRenderer first, and WebGPU as one extra column only.
Build
A harness page (a new entry in vite.browser.config.ts, and reachable on the tablet — e.g. a debug-only route or a page in the APK's debug build; decide which and record why) rendering one stretch of a real route with:
- An HDRI sky (Poly Haven, CC0) used both as background and as PMREM environment lighting; ACES or AgX tone mapping (measure both).
- Photographic road and ground: Poly Haven / ambientCG CC0 asphalt, grass, gravel — KTX2/ASTC compressed, 1K–2K, with a distance blend.
- Three photoscanned tree species, simplified, with ambient occlusion baked into the vertex colours or texture, plus an impostor for the far band.
- A placeholder realistic rider: a MakeHuman (CC0 export) body on a CC0/CC-BY-4.0 road bike, skinned, pedalling from
bicycle.ts's crank angle. Record its triangle, bone and draw-call count.
- Distance/height haze and a cheap bloom.
- Every item a toggle, so each one's cost is read on its own.
All processing through the headless Blender pipeline of #430 (Blender 4.4.3 is available on the developer machine and runs headless with bpy); nothing hand-edited.
⚠️ Licensing. Every asset CC0 or CC-BY-4.0 (ADR 0023), one ASSETS.toml row each (ASSET001–006). ⚠️ #431 has not landed, and it blocks committing realistic assets to the product. So the spike's assets live only on the spike branch (or are fetched by a script at build time and never committed) — the write-up says which. The spike is never merged into the product path.
Measure on the tablet
For each configuration (baseline game; + each item alone; all on; all on at render scale 0.75 and 0.5; all on under WebGPURenderer):
- frame time and GPU time 50th/90th/99th (
dumpsys gfxinfo and the harness's own performance.now + EXT_disjoint_timer_query_webgl2 where available);
- draw calls, triangles, texture memory;
- a 20-minute run of "all on" with frame time sampled each minute and the device temperature (
dumpsys thermalservice) — the throttling curve nobody has published for this chip;
- a screenshot of each configuration from the device, committed to the write-up (screenshots of our own renderer; ADR 0009 forbids a reference image from another product, not a picture of this one).
Acceptance criteria
Refs #429 · Refs #430 · Refs #431 · Refs #433 · Refs #434 · Refs #247
The question this spike answers
How realistic can the trainer game look on the owner's Pixel Tablet, at a sustained frame rate, with three.js as it is? Measured on the device — not argued. #431 (the ADR that takes the world realistic) rests on this, so it is written from numbers rather than from research alone.
A spike: a dated measurement that decides nothing (CLAUDE.md §7). Write-up in
docs/spikes/NNNN-realism-on-the-device-floor.md. Refs epic #429.What is already known (read 2026-09-21)
Device, read over adb and from inside the app's WebView with
apps/mobile/tools/webview-probe.mjs:MAX_TEXTURE_SIZE8192,WEBGL_compressed_texture_astcand_etcpresent,EXT_color_buffer_floatpresentnavigator.gpupresent andrequestAdapter()returns an adapter (arm / valhall, max 2D texture 16384)Research (tavily, 2026-09-21; sources in the write-up): the highest realism per millisecond on Mali-class GPUs is image-based lighting from an HDRI + filmic tone mapping, compressed PBR textures (KTX2/ASTC), lighting baked into instanced models, impostor billboards for distant trees, cheap distance/height haze and bloom (~0.3 ms). Expensive at 2560 × 1600: SSAO (~3 ms+), cascaded shadows (~1–3 ms), volumetric clouds, dynamic GI. WebGPURenderer reports on Mali are mixed (driver issues; slower than WebGL for non-instanced scenes) — so the spike measures on WebGLRenderer first, and WebGPU as one extra column only.
Build
A harness page (a new entry in
vite.browser.config.ts, and reachable on the tablet — e.g. a debug-only route or a page in the APK's debug build; decide which and record why) rendering one stretch of a real route with:bicycle.ts's crank angle. Record its triangle, bone and draw-call count.All processing through the headless Blender pipeline of #430 (Blender 4.4.3 is available on the developer machine and runs headless with
bpy); nothing hand-edited.ASSETS.tomlrow each (ASSET001–006).Measure on the tablet
For each configuration (baseline game; + each item alone; all on; all on at render scale 0.75 and 0.5; all on under WebGPURenderer):
dumpsys gfxinfoand the harness's ownperformance.now+EXT_disjoint_timer_query_webgl2where available);dumpsys thermalservice) — the throttling curve nobody has published for this chip;Acceptance criteria
Refs #429 · Refs #430 · Refs #431 · Refs #433 · Refs #434 · Refs #247