picogame — quick reference
A one-page cheat sheet of everything the engine exposes: the native picogame C module
and the pure-Python picogame_* helper libraries in lib/. Signatures show parameter
names and defaults; * marks keyword-only arguments. Colours are wire-order RGB565 ints
(build them with rgb565). For longer explanations see PICOGAME.md.
Native module: picogame (import picogame as pg)
Section titled “Native module: picogame (import picogame as pg)”Constants & colour
Section titled “Constants & colour”RGB565,PAL8— bitmap pixel formats.rgb565(r, g, b) -> int— wire-order colour from 8-bit channels.collide(x1, y1, x2, y2, ax1, ay1, ax2, ay2) -> bool— AABB overlap (8 args = box vs box) or point-in-box (6 args:collide(x1, y1, x2, y2, px, py)). Inclusive AABB — boxes collide when they touch (pass sprite boxes as(x, y, x+w, y+h); fires on contact). Note:collideis inclusive, unlike render’s half-open pixel ranges — different domains (hitboxes vs pixels).
Bitmap(data, width, height, *, format=RGB565, palette=None, frames=1, stride=0, transparent=None)
Section titled “Bitmap(data, width, height, *, format=RGB565, palette=None, frames=1, stride=0, transparent=None)”An image atlas of equal-size frames (any size). data is a buffer; palette (array of wire colours) is required for PAL8. transparent = the index/colour skipped when blitting.
- Read-only props:
width,height,frames,format,stride,palette(the PAL8 palette buffer orNone),transparent(the transparent value orNone).
Sprite(bitmap, x=0, y=0, *, frame=0, visible=True, flip_x=False, flip_y=False)
Section titled “Sprite(bitmap, x=0, y=0, *, frame=0, visible=True, flip_x=False, flip_y=False)”A positioned, animatable instance of a Bitmap.
- Position/anim props:
x,y(int px) ·fx,fy(float sub-pixel) ·frame·visible·flip_x,flip_y·bitmap(swap) ·data(your payload). - Transform props (nearest-neighbour, about the anchor):
scale— float draw scale;1.0= native (fast path),2.0= double size, fractional allowed (e.g. a pulse).angle— rotation in degrees;0= none (fast path). Combines withscale.transpose— bool; swap X/Y axes → a cheap 90° rotation (withflip_x/flip_y= all 8 orientations), crisp, no shimmer. Fast path only (scale 1, angle 0); footprint swaps w/h.anchor=(fx, fy)— pivot as fractions of the bitmap (0..1):(0.5, 0.5)= centre,(0.5, 1.0)= bottom-centre.x/yand rotation are about this point.
- Blit-effect props (one at a time; setting one clears the others; cheap, no extra bitmaps):
shadow— bool; opaque pixels darken the destination (drop-shadow / dim overlay).flash— wire-RGB565 colour (or0/None= off); opaque pixels drawn as that flat colour (hit-flash). Pulse 1–3 frames.tint— wire-RGB565 colour (or0= off); opaque pixels multiplied by it — colours the sprite while keeping its shading (damage-red, freeze-blue, glow).dither—0(opaque) ..16(invisible); Bayer-stipple translucency, no alpha (ghosts, fog, fade-in/out).
move(x, y)— set position. ·touch()— mark dirty after an in-place bitmap/palette edit.
Display(busdisplay)
Section titled “Display(busdisplay)”Fast DMA backend wrapping a board’s busdisplay (FourWire SPI). Pass to Scene.
Scene(display, buffer_a, buffer_b, *, background=0, top=0, bottom=0, left=0, right=0)
Section titled “Scene(display, buffer_a, buffer_b, *, background=0, top=0, bottom=0, left=0, right=0)”Retained-mode scene with dirty-rectangle rendering; buffer_a/b are strip buffers.
add(item, *, fixed=False) -> item— add a Sprite/Tilemap/Particles/Canvas/StripDraw (insertion order = bottom→top) and return it (sospr = scene.add(Sprite(...))works).fixed=True(keyword-only) pins it to the screen (ignores the camera) for HUD/dialog.add_all(items)— add several (bottom→top).set_view(ox, oy)— camera offset (screen position of the scene origin); changing it repaints all.view— read-only(ox, oy)camera offset.invalidate()— force a full repaint next refresh.refresh() -> list | None— diff & repaint changed regions; returns the dirty rect[x1,y1,x2,y2](reused) or None.
Tilemap(tileset, cols, rows)
Section titled “Tilemap(tileset, cols, rows)”A grid of tile indices into a tileset Bitmap (each frame = one tile); a Scene layer.
tile(tx, ty, value=None, *, flip_x=False, flip_y=False, transpose=False) -> int— get tile, or set it (with optional keyword-only per-cell orientation:flip_x/flip_y/transposegive all 8 orientations of a tile — pair with a deduplicated tileset, seepng2picogame.py --dedup). Out-of-range ignored. The orientation plane is allocated lazily (RAM only if a map uses it).fill(value)— set every tile (clears orientation).move(x, y)— position the map.- Read-only props:
x,y,cols,rows.
Particles(capacity, size=1, gravity=0.0, fade=False)
Section titled “Particles(capacity, size=1, gravity=0.0, fade=False)”A pooled particle layer (small moving dots) drawn as one Scene layer.
emit(x, y, count, speed=1, life=30, color=0xFFFF)— burstcountdots, random velocity ≤speedpx/tick, livinglifeticks.tick()— advance one step (move, gravity, ageing). Call each frame.clear()— remove all.
Canvas(width, height, transparent=None, buffer=None)
Section titled “Canvas(width, height, transparent=None, buffer=None)”A RAM RGB565 drawing surface composited as a Scene layer (width*height*2 bytes). transparent makes it a shaped overlay; buffer backs it with external memory (e.g. an arena slice). For animated full-frame surfaces prefer StripDraw (no buffer).
clear(color)·pixel(x, y, color)·fill_rect(x, y, w, h, color)·rect(x, y, w, h, color)line(x0, y0, x1, y1, color)·circle(cx, cy, r, color)·fill_circle(cx, cy, r, color)·ring(cx, cy, r, thickness, color)triangle(x0,y0, x1,y1, x2,y2, color)·fill_triangle(...)·ellipse(cx, cy, rx, ry, color)·fill_ellipse(...)fill_round_rect(x, y, w, h, r, color)·frame3d(x, y, w, h, light, dark)(beveled box) ·move(x, y)- Read-only props:
x,y,width,height.
StripDraw(callback, x=0, y=0, width=0, height=0)
Section titled “StripDraw(callback, x=0, y=0, width=0, height=0)”Immediate-mode layer with no pixel buffer: each refresh it calls callback(view, vx, vy, vw, vh) once per render strip inside its rect. view is a Canvas pointing at the live strip (use Canvas primitives); view-local (0,0) = screen (vx, vy). Repaints every frame → for animated/scanline content (pseudo-3D, gradients). In a scrolling scene add it fixed.
- Read/write props:
x,y,width,height— move or resize the layer (after shrinking, callscene.invalidate()).
Procedural noise (coherent value noise, 0..1)
Section titled “Procedural noise (coherent value noise, 0..1)”value2d(x, y, *, seed=0) -> float·value1d(x, *, seed=0) -> floatfbm2d(x, y, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float·fbm1d(x, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float— fractal (summed octaves).
Helper libraries (lib/picogame_*.py, pure Python)
Section titled “Helper libraries (lib/picogame_*.py, pure Python)”picogame_game — one-call boot
Section titled “picogame_game — one-call boot”setup(display=None, strip_h=24, background=0, fast=True) -> (scene, buffer_a, buffer_b)— take over the display, build a Scene + two strip buffers.
picogame_clock — frame pacing
Section titled “picogame_clock — frame pacing”Clock(fps=30, max_dt=0.1)·.set_fps(fps)·.tick() -> dt(sleep to frame, return seconds) ·.tick_async().FixedStep(step_fps=60, max_steps=5)·.steps()— generator yielding a constant dt per fixed step.
picogame_input — buttons
Section titled “picogame_input — buttons”- Masks:
UP DOWN LEFT RIGHT A B X Y ALL; profilePICOPAD. Buttons(profile=None, pull=None)·.poll() -> mask·.is_pressed(mask=ALL)·.just_pressed(mask=ALL)·.just_released(mask=ALL)·.repeat(button, delay=15, interval=4)— PICO-8btnpauto-repeat (menus / grid move).Timer(frames)— input-leniency window (coyote time / jump buffering):.feed(cond)(recharge while true, else decay) ·.charge()·.is_active·.consume()(true once, then clears).
picogame_font — text bitmaps
Section titled “picogame_font — text bitmaps”render_text(pg, font, text, fg, bg=None) -> (bitmap, w, h)— render a string to a PAL8 Bitmap (bg=None→ transparent).render_text_pal(pg, font, text, fg, bg=None) -> (bitmap, w, h, palette)— same, plus the palette array; mutatepalette[1]to recolour the text in place (no rebuild).Label(pg, font, x, y, fg, bg)·.move(x, y)·.set(text) -> changed·.draw(display, buffer).
picogame_ui — HUD widgets (LINE_H = 12)
Section titled “picogame_ui — HUD widgets (LINE_H = 12)”SceneLabel(scene, pg, font, x, y, fg, bg)·.set(text)— camera-independent text label (a fixed Scene layer).TextBox(pg, font, x, y, w, h, fg, bg, maxlines=6)·.draw(display, buffer, lines).Menu(pg, font, x, y, items, fg, bg, title=None)·.tick(btn) -> index | -1·.draw(display, buffer).
picogame_shapes — single-colour bitmap generators
Section titled “picogame_shapes — single-colour bitmap generators”rect(w, h, color)·circle(d, color)·ring(d, color, thickness=2)from_mask(mask, color)— Bitmap from a string mask ('#'= set).atlas(frames_data, w, h, color)— pack w×h buffers into a multi-frame Bitmap.color_frames(w, h, colors)— frame i = solidcolors[i].tileset_colors(w, h, colors)— tileset: frame 0 empty, frames 1..N coloured.poly_frames(size, points, nframes, color, fill=True)— bakenframesrotations of a polygon.
picogame_pool — reusable sprite pool
Section titled “picogame_pool — reusable sprite pool”Pool(scene, bitmap, capacity, anchor=None, fixed=False)·.spawn() -> sprite | None·.free(s)·.free_all()·.count() -> int. (.items= all sprites.)
picogame_collide — zero-alloc collision
Section titled “picogame_collide — zero-alloc collision”hit(a, b, hw=None, hh=None)— AABB overlap of two sprites.hit_point(a, px, py, hw=None, hh=None)— point in a sprite.is_within(a, b, r)— circular distance test (no sqrt).
picogame_math — vector math (in picogame_math)
Section titled “picogame_math — vector math (in picogame_math)”length(dx, dy)·distance(x1, y1, x2, y2)·normalize(dx, dy)·angle_rad(dx, dy)(radians) ·from_angle_rad(a, mag=1.0)·clamp(v, lo, hi).
picogame_math — numeric helpers + turn-based trig
Section titled “picogame_math — numeric helpers + turn-based trig”clamp(v, lo, hi)·mid(a, b, c)·lerp(a, b, t)·inv_lerp(a, b, v)·remap(v, a, b, c, d)·sgn(x)·approach(v, target, step)·wrap(v, lo, hi).sin_t(turns)·cos_t(turns)·atan2_t(dy, dx) -> turns— angles as 0..1 turns (standard, not PICO-8’s inverted sin).
picogame_tiles — per-tile metadata flags (PICO-8 fget/fset)
Section titled “picogame_tiles — per-tile metadata flags (PICO-8 fget/fset)”- Bits/masks:
B_SOLID B_HAZARD B_LADDER …(indices) andSOLID HAZARD LADDER …(masks). TileFlags(flags=None, tile_px=8)—flags={tile_index: bitfield}or a list..get(tile, bit=None)·.set(tile, bit, value=True)·.at(tilemap, cx, cy, bit)·.at_px(tilemap, px, py, bit)(collision one-liner). Keyed by tile index (shared by all cells using it).
picogame_seq — generator-driven sequences (coroutine pattern)
Section titled “picogame_seq — generator-driven sequences (coroutine pattern)”wait(frames)·over(frames, fn)(fn(t), t 0..1) ·move_over(sprite, x, y, frames)— all are generators; compose withyield from.Seq(gen=None)·.start(gen)·.tick() -> done·.done— advance one step per frame (cutscenes, “do X over N frames”).
picogame_anim — frame animation over time
Section titled “picogame_anim — frame animation over time”FrameAnim(sprite, frames, fps=8, loop=True)·.reset()·.tick(dt).AnimatedSprite(sprite, anims)·.play(name)·.tick(dt).
picogame_fx — juice & raster effects
Section titled “picogame_fx — juice & raster effects”Shake(scene, max_offset=6, decay=0.03)·.add(amount)(0.6 hit, 0.15 bump) ·.tick(cam_x=0, cam_y=0)— trauma screen shake composed on top of the camera.Fade(scene, w, h, x=0, y=0, color=0, cell=8)·.out()/.into()/.set(level)/.dim(level)/.pulse()·.tick() -> done— dither fade / dim / flash, full-screen or a region. 0-byte StripDraw overlay.Tween(value=0.0, speed=0.2)·.to(target)·.set(v)·.tick() -> value·.is_done— ease a scalar (UI/pop-ups).Camera(scene, w, h, lerp=0.18, world_w=0, world_h=0)·.follow(tx, ty, snap=False)·.offset() -> (ox,oy)·.apply()— smoothed follow + world clamp (compose withShakeviashake.tick(*cam.offset())).Sky(scene, x, y, w, h, top, bottom)— vertical gradient (per-scanline, 0 RAM). ·Scanlines(scene, x, y, w, h, step=2, dark=0)— CRT overlay.
picogame_palette — Game-Boy palette tricks on PAL8 art (call sprite.touch() after)
Section titled “picogame_palette — Game-Boy palette tricks on PAL8 art (call sprite.touch() after)”cycle(palette, lo, hi, step=1)— rotate entries (animated water/lava/portals; ~0 extra art).swap(dst_palette, src_palette)— recolour a shared bitmap (GBC-style; cheaper than a 2nd bitmap).fade(palette, base, t, target=0, skip=None)— lerp toward a colour (smooth brightness fade;base=snapshot()of the original).snapshot(palette)/restore(palette, base).
picogame_rand — seedable RNG
Section titled “picogame_rand — seedable RNG”Rand(seed=None)(deterministic xorshift;None= time-seeded) ·.below(n)·.randint(a, b)·.random()·.chance(p)·.choice(seq)·.shuffle(lst)·.weighted(weights) -> index·.seed(s).Bag(items, rng)·.next()— shuffle-bag (7-bag) anti-streak randomizer.
Noise — native picogame functions (pg.*)
Section titled “Noise — native picogame functions (pg.*)”value2d,value1d,fbm2d,fbm1dare functions on the nativepicogamemodule itself (call aspg.value2d,pg.value1d,pg.fbm2d,pg.fbm1d); there is no separatepicogame_noisemodule.
picogame_save — NVM persistence
Section titled “picogame_save — NVM persistence”Save(key, schema, *, offset=0)·.defaults()·.load() -> dict·.save(values)·.reset(). Survives reboot/filesystem wipe.
picogame_audio — PWM audio
Section titled “picogame_audio — PWM audio”Audio(pin=None, voices=4, sample_rate=22050, channels=1, bits=16, signed=True)·.load(path)·.play(sample, *, voice=None, loop=False, volume=1.0)·.sfx(sample, volume=1.0)·.music(sample, loop=True, volume=1.0)·.stop(voice=None)·.stop_music()·.is_playing.tone(frequency=440, ms=120, sample_rate=22050, volume=0.6)— square-wave beep sample.
picogame_arena — anti-fragmentation buffer
Section titled “picogame_arena — anti-fragmentation buffer”Arena(pixels)·.alloc(nbytes) -> memoryview·.canvas(w, h, transparent=None) -> Canvas·.reset()·.free() -> int. Grab one big buffer up front, hand out slices. See MEMORY.md.
picogame_scene — declarative level loader
Section titled “picogame_scene — declarative level loader”load(pg, scene, display=None, strip_h=24, font=None, bank=None) -> View— build a scene from a baked SCENE dict.load_bank(pg, bank)— build a shared asset bank once (reuse across levels).View:.tile_xy(px, py)·.group(tag)·.point(name)·.in_zone(x, y, tag=None)·.is_solid(tx, ty)·.tile_has(tx, ty, prop)·.play(sound_id)·.tick(dt). See SCENE_FORMAT.md.