Media
vgame
A fixed timestep game loop and entities, drawn offscreen frame by frame.
Released v1.0.0 · 2026-09-28use "stdlib/game.ven"
A headless, fixed time step game loop and entity system, built on top of the standard library's own software rasterizer for drawing each frame. It runs with no window and no display of its own: a program using it renders frames to memory or to a file rather than to a screen.
print Entity("ball", 1, 1, 2, 2, 3, 4, (255, 0, 0))
Reference (12 functions)
API reference
entity_new(id, x, y, width, height, vx, vy, color)
e = entity_new("ball", 1, 1, 2, 2, 3, 4, (255, 0, 0))
print e.id
print e.vx
:: prints: ball
:: 3world_new(width, height)
Builds one new, empty World with the given bounds.
w = world_new(10, 10)
print w.width
print length(w.entities)
:: prints: 10
:: 0world_add_entity(world, entity)
Adds entity to world.entities and returns the same World.
w = world_add_entity(world_new(10, 10), entity_new("ball", 0, 0, 1, 1, 0, 0, (1, 2, 3)))
print length(w.entities)
:: prints: 1find_entity(world, id)
Gives back the Entity in world whose id field equals id.
w = world_add_entity(world_new(10, 10), entity_new("ball", 0, 0, 1, 1, 0, 0, (1, 2, 3)))
print find_entity(w, "ball").id
:: prints: ballSimulation step
integrate_entity(e, dt)
Advances es position by its own velocity over one timestep dt.
e = integrate_entity(entity_new("ball", 1, 1, 2, 2, 3, 4, (255, 0, 0)), 1)
print e.x
print e.y
:: prints: 4
:: 5clamp_to_bounds(world, e)
Reflects e off any world edge it has crossed, clamping it back inside the bounds.
e = clamp_to_bounds(world_new(5, 5), entity_new("edge", 4, 0, 2, 2, 1, 0, (0, 255, 0)))
print e.x
print e.vx
:: prints: 3
:: -1aabb_overlap(a, b)
Tests whether a and bs bounding boxes overlap.
print aabb_overlap(entity_new("a", 0, 0, 2, 2, 0, 0, (0, 0, 0)), entity_new("b", 1, 1, 2, 2, 0, 0, (0, 0, 0)))
:: prints: yesresolve_collision(a, b)
Resolves an overlap between a and b by swapping their full velocity vectors.
a = entity_new("a", 0, 0, 1, 1, 5, 0, (0, 0, 0))
b = entity_new("b", 1, 1, 1, 1, -5, 0, (0, 0, 0))
resolve_collision(a, b)
print a.vx
print b.vx
:: prints: -5
:: 5world_step(world, dt)
Advances the simulation by exactly one fixed timestep dt.
w = world_add_entity(world_new(10, 10), entity_new("p", 0, 0, 1, 1, 1, 0, (10, 20, 30)))
w = world_step(w, 1)
print w.tick
print w.entities[0].x
:: prints: 1
:: 1world_run(world, dt, steps)
Runs the simulation forward by calling world_step exactly steps times, in order.
w = world_add_entity(world_new(10, 10), entity_new("r", 0, 0, 1, 1, 1, 0, (1, 2, 3)))
w = world_run(w, 1, 3)
print w.tick
print w.entities[0].x
:: prints: 3
:: 3render_world(world, scale, bg_color)
Rasterizes worlds current state onto a fresh raster.ven Canvas.
w = world_add_entity(world_new(3, 3), entity_new("s", 0, 0, 1, 1, 0, 0, (9, 8, 7)))
canvas = render_world(w, 2, (0, 0, 0))
print canvas_get_pixel(canvas, 0, 0)
:: prints: (9, 8, 7)render_world_to_ppm(world, scale, bg_color, path)
Renders world exactly as render_world does, then writes it as a PPM image file to path.
w = world_add_entity(world_new(3, 3), entity_new("s", 0, 0, 1, 1, 0, 0, (9, 8, 7)))
render_world_to_ppm(w, 2, (0, 0, 0), "probe_render.ppm")
lines = split_text(read_file("probe_render.ppm"), "\n")
print lines[0]
print lines[1]
:: prints: P3
:: 6 6