Taos Engine · Agent Tutorials

Agent Tutorials · Step 8

Measurement & Plots

▶ Live demo: run this tutorial — built from src/08_measurement.ts.

A model isn't much use if you can't measure it. AgentScript plots populations and exports datasets; Taos Engine does the same by reading GPU state back to the CPU. Here we run the Lotka-Volterra ecosystem from tutorial 6 and draw a live predator/prey population plot from the readback.

The two readback calls#

On the ParticleFeature:

Both are async and synchronizing (they copy to a staging buffer and map it), so call them a few times a second — never every frame.

Counting a population#

The 16-float record: [0..2] position, [3] life (< 0 = dead slot — skip it), [4..6] velocity, [7] max_life, [8..11] color (color.a = species/state), [12] size, [13] rotation, [14] flags, [15] pad. Counting live prey vs. predators:

TypeScript
const a = await particles.readAgents();          // full capacity
let prey = 0, pred = 0;
for (let i = 0; i < a.length; i += 16) {
  if (a[i + 3] >= 0 && a[i + 12] > 0) {           // alive & active
    if (a[i + 11] > 0.7) { pred++; } else { prey++; }   // color.a = species
  }
}

Driving it from the frame loop#

Throttle the readback with a delta-time accumulator and push the counts into a scrolling 2D-canvas plot:

TypeScript
let measureAccum = 0;
engine.beforeFrame((frame) => {
  measureAccum += frame.dt;
  if (measureAccum >= 0.4) { measureAccum = 0; void measure(); }   // ~2.5×/s
});

measure reads the agents, counts species, and strokes two lines on a <canvas> overlay — the classic out-of-phase predator/prey oscillation, measured live.

Don't poll the buffer every frame. Each readback stalls until the GPU catches up. A few times a second is plenty for a plot and costs nothing visible.

Next#