HOW IT'S MADE

GPU Boost Adventure × Mojo 🔥

GPU Boost Adventure is a hybrid: the browser does what browsers are great at — rendering pixels, reading your taps, and playing the runner at 60 fps — while the procedural level design is precomputed in Mojo🔥, the systems language by Modular. A small Mojo program evaluates a thermal field across the entire track using SIMD (eight lanes at a time), producing three channels — heat, coolant, and flux. Hot stretches throttle the simulated die into bigger gaps and choppier terrain; cool stretches open boost pads. The result is baked to a tiny JS file the game loads at startup — deterministic, seamless, and authored in compiled Mojo.

Live Mojo output

Drawn straight from mojo_field.js — the actual data the game ships. Each strip is the real heat / coolant / flux across one full track loop.

The Mojo source

mojo/level_gen.mojo — the SIMD field generator that emits window.MOJO_FIELDS. Embedded verbatim below.

# ===========================================================================
#  GPU Boost Adventure -- Procedural Field Generator
#  Written in Mojo 🔥  (the language by Modular) -- targets Mojo 1.0 (2026).
#
#  The browser handles rendering and input; the heavy procedural-generation
#  math runs HERE, in compiled Mojo, using SIMD to evaluate the fields that
#  shape the level 8 lanes at a time.
#
#  THREE channels per field, each a sum of integer harmonics of the track
#  length (so every channel tiles seamlessly for an endless runner):
#    * heat    -- thermal load. Hot stretches = bigger gaps, more thermal vents,
#                 choppier terrain (the simulated die is throttling).
#    * coolant -- cooling headroom. Cool stretches get boost pads & glow cyan.
#    * flux    -- compute flux / density. Drives collectible & enemy density.
#
#  MULTIPLE named fields (seeds) are emitted so the game's title screen can
#  flip between distinct Mojo-authored layouts (the in-game "FIELD" selector).
#
#  Output: mojo_field.js -> window.MOJO_FIELDS = [ ...fields... ];
#                           window.MOJO = window.MOJO_FIELDS[0];
#
#  Run:   pixi run mojo level_gen.mojo
# ===========================================================================

from std.math import sin

# STEP px between samples; N samples per channel; LANES = SIMD width. N is a
# multiple of LANES so the SIMD loop has no ragged tail. span = N*STEP is the
# tiling period; only integer harmonics of span are used below -> seamless loop.
comptime STEP = 24
comptime N = 640
comptime LANES = 8
comptime TWO_PI = Float32(6.283185307179586)
comptime HALF_PI = Float32(1.5707963267948966)


def clamp01(x: Float32) -> Float32:
    if x < 0.0:
        return 0.0
    if x > 1.0:
        return 1.0
    return x


# One SIMD-evaluated channel: dc + a1*sin(f1*θ+p1) + a2*sin(f2*θ+p2) + ...
# `dc` is the baseline (a field's thermal "character"); f1..f3 must be integers
# for seamless tiling. Returns per-mille (0..1000) ints.
def build_channel(
    dc: Float32,
    a1: Float32, f1: Float32, p1: Float32,
    a2: Float32, f2: Float32, p2: Float32,
    a3: Float32, f3: Float32, p3: Float32,
    span: Float32,
) -> List[Int]:
    var out = List[Int]()
    for idx in range(0, N, LANES):
        var xs = SIMD[DType.float32, LANES](0)
        for k in range(LANES):
            xs[k] = Float32((idx + k) * STEP)
        var th = (xs / span) * TWO_PI
        var u = SIMD[DType.float32, LANES](dc)
        u += a1 * sin(th * f1 + p1)
        u += a2 * sin(th * f2 + p2)
        u += a3 * sin(th * f3 + p3)
        for k in range(LANES):
            # round (not truncate) to per-mille so peaks aren't biased low
            out.append(Int(clamp01(u[k]) * 1000.0 + 0.5))
    return out^


def arr(v: List[Int]) -> String:
    var s = String("[")
    for i in range(len(v)):
        if i > 0:
            s += ","
        s += String(v[i])
    s += "]"
    return s^


# Build one complete field (all three channels + stats) as a JS object string.
# `heat_bias` shifts a field's thermal character: +hotter / -cooler. The
# coolant baseline shifts the opposite way so hot fields also have less headroom.
def field_js(seed: Int, name: String, heat_bias: Float32) -> String:
    # deterministic phase offsets in [0, 2pi) from the seed
    var ph1 = Float32(seed % 628) / 100.0
    var ph2 = Float32((seed // 7) % 628) / 100.0
    var ph3 = Float32((seed // 13) % 628) / 100.0
    var span = Float32(N * STEP)

    var heat = build_channel(
        0.5 + heat_bias, 0.28, 3.0, ph1, 0.14, 7.0, ph2, 0.08, 13.0, ph3, span
    )
    # coolant: independent harmonics, quarter-turn out of phase (cos-like)
    var cool = build_channel(
        0.5 - heat_bias, 0.26, 2.0, ph2 + HALF_PI, 0.16, 5.0, ph3, 0.08, 11.0, ph1, span
    )
    var flux = build_channel(
        0.5, 0.22, 4.0, ph3, 0.18, 9.0, ph1, 0.10, 17.0, ph2, span
    )

    # stats from the heat channel
    var hottest = 0
    var hot_idx = 0
    var total = 0
    for i in range(len(heat)):
        total += heat[i]
        if heat[i] > hottest:
            hottest = heat[i]
            hot_idx = i

    var o = String("  {\n")
    o += '    seed: ' + String(seed) + ', name: "' + name + '",\n'
    o += "    step: " + String(STEP) + ", span: " + String(N * STEP)
    o += ", count: " + String(N) + ", lanes: " + String(LANES) + ", scale: 1000,\n"
    o += "    avg: " + String(total // N)
    o += ", peak: " + String(hottest) + ", peakX: " + String(hot_idx * STEP) + ",\n"
    o += "    heat: " + arr(heat) + ",\n"
    o += "    coolant: " + arr(cool) + ",\n"
    o += "    flux: " + arr(flux) + "\n"
    o += "  }"
    return o^


def main() raises:
    # Named fields the in-game FIELD selector cycles through. The third column
    # is the thermal bias: each field has a distinct hot/cool personality.
    var seeds = List[Int]()
    var names = List[String]()
    var bias = List[Float32]()
    seeds.append(0xC0FFEE); names.append("C0FFEE"); bias.append(0.0)
    seeds.append(0x60FA57); names.append("G0FAST"); bias.append(-0.08)
    seeds.append(0x1337);   names.append("L33T");   bias.append(0.10)
    seeds.append(0xB0057);  names.append("B00ST");  bias.append(-0.05)
    seeds.append(0xCEED);   names.append("CRY0");   bias.append(-0.16)
    seeds.append(0x3EA7);   names.append("M3LTD0WN"); bias.append(0.18)

    var js = String("// AUTO-GENERATED by Mojo (level_gen.mojo). Do not edit by hand.\n")
    js += "// GPU Boost Adventure procedural fields (heat/coolant/flux), SIMD-computed.\n"
    js += "window.MOJO_FIELDS = [\n"
    for i in range(len(seeds)):
        if i > 0:
            js += ",\n"
        js += field_js(seeds[i], names[i], bias[i])
    js += "\n];\n"
    js += "window.MOJO = window.MOJO_FIELDS[0];\n"

    with open("../mojo_field.js", "w") as f:
        f.write(js)

    print("GPU Boost Adventure -- procedural fields generated")
    print("  fields      :", len(seeds), "(selectable in-game)")
    print("  channels    : heat, coolant, flux")
    print("  per channel :", N, "samples (SIMD width", LANES, ", step", STEP, "px )")
    print("  span        :", N * STEP, "px (tiles seamlessly)")
    for i in range(len(seeds)):
        print("    -", names[i], " seed", seeds[i])
    print("  -> wrote ../mojo_field.js")
▶ Play the game