Task 5 of 5
A flow field is two numbers per pixel, and nobody can read that as a table. The
standard picture encodes it as colour: direction becomes hue, walking once
around the colour wheel as the vector turns once around the circle, and
magnitude becomes saturation, so a still pixel is white and a fast one is
vivid. Hue and saturation as an angle and a radius is the polar half of HSV — the same wheel
Colour Spaces works in — and here it costs one Math.atan2.
flow is the field task 3 produced for this scene, handed to you finished:
flow[0][y][x] is u and flow[1][y][x] is
v. The hue→RGB conversion is written for you in the starter — it is six
straight lines around a hexagon, not the lesson. Your part is the encoding.
Watch what the picture tells you: the whole scene translated by (1, 1), and
half of it comes out white. That is not a bug. Those are the pixels
task 4 scored zero, painted honestly as "no idea".
graphical: true, output: [64, 64]s = Math.min(1, magnitude / this.constants.maxFlow), where magnitude is Math.sqrt(u * u + v * v)hh = (Math.atan2(v, u) / (2 * Math.PI) + 0.5) * 6 — the sextant the direction lands in, from 0 to 6s: this.color(1 - s + s * r, 1 - s + s * g, 1 - s + s * b, 1), so a zero-length vector comes out pure whiteMath.atan2 returns an angle in −π…π. Dividing by
2π maps that to −0.5…0.5, and the + 0.5 slides it
to 0…1 without a branch or a modulo. Which direction gets which hue is
arbitrary; that the mapping is one-to-one is the part that matters.
const mag = Math.sqrt(u * u + v * v);
const s = Math.min(1, mag / this.constants.maxFlow);
const hh = (Math.atan2(v, u) / (2 * Math.PI) + 0.5) * 6;
and the last line under it is the blend: 1 - s + s * r is
r when s is 1 and white when s is 0.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.