{ "measured": "2026-08-29 (foreground window, M2, Metal, vsync off)", "method": "per-frame CPU LBS + full ArrayMesh rebuild (current default)", "caveats": [ "frame_ms is the trustworthy signal; cpu_process_ms (Performance.TIME_PROCESS) reads inconsistent (drops as N rises) \u2014 do not use.", "per-frame cpu_mesh->clear_surfaces()+add_surface_from_arrays is the likely bottleneck, not the LBS math.", "build ~170ms/char is single-threaded, no cross-model texture/mesh cache.", "Phase 2 needs: (1) custom GPU skinning shader (full bone matrices) so this path is not on the CPU, (2) multithreaded build + eterpack shared assets, (3) a proper bench harness." ], "runs": [ { "characters": 1, "build_ms_per_char": 171.7, "frame_ms_avg": 21.8, "fps_avg": 46.0 }, { "characters": 10, "build_ms_per_char": 171.1, "frame_ms_avg": 27.5, "fps_avg": 36.3 }, { "characters": 30, "build_ms_per_char": 168.7, "frame_ms_avg": 41.2, "fps_avg": 24.3 } ] }