lofivor/docs/plans/2025-12-14-sandbox-design.md

3.2 KiB

lofivor sandbox - stress test design

a minimal harness for finding entity count ceilings on weak hardware before designing game systems.

goals

purpose: answer "how many simple entities can we update and render at 60fps?"

target hardware:

  • primary: intel i5-6500T + HD 530 (thinkcentre m900) @ 1280x1024
  • secondary: windows laptop for dev iteration

what it does:

  • spawns colored circles that drift toward screen center
  • manual controls to add/remove entities in real-time
  • on-screen metrics: entity count, frame time (ms), update time, render time
  • circles respawn at random edge when reaching center

what it doesn't do (yet):

  • no collision detection
  • no player input beyond entity count controls
  • no game logic, damage, spawning waves
  • no particles or visual effects

success criteria:

  • locked 60fps with some meaningful entity count (finding that number is the goal)
  • clear breakdown of where frame time goes (CPU update vs GPU render)
  • stable enough to leave running while tweaking counts

data structures

const Entity = struct {
    x: f32,
    y: f32,
    vx: f32,
    vy: f32,
    color: u32,
};

simple flat array of entities. no ECS, no spatial partitioning, no indirection. measuring the baseline - fancy structures come later.

memory budget: 20 bytes per entity. 10k entities = 200KB (fits in L2 cache on skylake).

update loop

for each entity:
    x += vx
    y += vy
    if distance_to_center < threshold:
        respawn at random edge
        recalculate vx, vy toward center

~5 float ops per entity per frame. no collision, no branching beyond respawn check.

velocity: on spawn, compute normalized direction to center, multiply by constant speed, store vx/vy.

rendering

each frame:

  1. clear screen (dark background #0a0a12)
  2. draw all entities as filled circles (4px radius)
  3. draw metrics overlay

entity color: cyan (#00ffff) - bright against dark background

metrics overlay (top-left):

entities: 5000
frame:    12.4ms
update:   8.2ms
render:   4.1ms

controls

key action
= / + add 100 entities
- remove 100 entities
shift + = add 1000 entities
shift + - remove 1000 entities
space pause update loop (render continues)
r reset to 0 entities

pause isolates render cost from update cost.

what we're measuring

key questions:

  1. what's the entity ceiling at 60fps? (where frame time crosses 16.6ms)
  2. is it CPU-bound or GPU-bound? (compare update vs render time)
  3. where does it fall apart? (gradual degradation or sudden cliff?)

hypotheses to test:

  • HD 530 might struggle with thousands of individual draw calls (GPU-bound)
  • if CPU-bound, update loop needs SIMD or better memory access
  • skylake's 4 cores are untouched - parallelism is a future lever

next steps based on results

bottleneck next experiment
render (draw calls) batch rendering - instancing, sprite batches
update (CPU) SIMD, struct-of-arrays layout, multithreading
both equally optimize either for gains

stretch measurements

  • memory bandwidth (cache-bound?)
  • draw call count vs batched draws
  • fixed-point vs float update cost comparison