All docs

VPy Language

Syntax, types, control flow, functions, arrays and built-in calls — the complete VPy reference.

VPy is a Python-inspired language that compiles to MC6809 assembly for the Vectrex console. All values are 16-bit integers. No floats, no booleans, no runtime exceptions.

Program Structure

Every VPy program has two special functions:

def main():
    # Called once at startup — initialization only
    SET_INTENSITY(127)
 
def loop():
    # Called every frame — game logic goes here
    draw_player()
  • main() runs once when the cartridge starts.
  • loop() runs every frame (~50 fps). All drawing and input goes here.
  • WAIT_RECAL() is automatically injected at the start of loop() by the compiler — do not write it yourself.

Minimal example

META TITLE = "HELLO"
 
def main():
    SET_INTENSITY(100)
 
def loop():
    PRINT_TEXT(-50, 0, "HELLO WORLD")

Variables and Constants

Global variables

Declared at the top level, persisted across frames:

player_x = 0
player_y = 0
score = 0

Local variables

Declared inside a function, scoped to that call:

def update_player():
    dx = joy_x * 2        # local
    player_x = player_x + dx  # player_x is global

Constants

const declares a compile-time constant stored in ROM, not RAM:

const MAX_ENEMIES = 8
const GROUND_Y = -70
const LEVEL_NAMES = ["LEVEL 1", "LEVEL 2", "LEVEL 3"]

Types and Values

VPy supports variable-sized types (⚠️ Experimental Phase) and defaults to 16-bit integers.

Default type: 16-bit integer

Untyped variables default to 16-bit signed (i16):

x = 0              # i16: range -32768 to +32767
counter += 1
  • All arithmetic is 16-bit (values wrap modulo 65536).
  • 0 is false, any non-zero value is true.
  • No floating point. No booleans — use 1 and 0.

⚠️ Experimental: Variable-Sized Types

VPy now supports explicit type declarations using Python's type hint syntax:

health: u8 = 100          # 8-bit unsigned (0–255)
direction: i8 = 1         # 8-bit signed (-128 to +127)
score: u16 = 1000         # 16-bit unsigned (0–65535)
position: i16 = -100      # 16-bit signed (-32768 to +32767)

Status: 🔧 Experimental — fully implemented but not all edge cases tested. Use with caution.

Benefit: Saves ~20% RAM (~200 bytes per game) while remaining backward compatible (untyped variables default to 16-bit i16).

x = 42        # decimal
x = 0xFF      # hexadecimal
x = 0b1010    # binary
x = -7        # negative (compiled as 0 - 7)

Operators

CategoryOperators
Arithmetic+ - * / %
Bitwise& | ^ ~ << >>
Comparison== != < <= > >=
Logicaland or not
Compound+= -= *=

Chained comparisons work: 0 < x < 100 expands to (0 < x) and (x < 100).


Control Flow

# if / elif / else
if score > 100:
    level = 2
elif score > 50:
    level = 1
else:
    level = 0
 
# while loop
while lives > 0:
    lives -= 1
 
# for loop
for i in range(8):
    draw_enemy(i)
 
# switch / case
switch state:
    case 0:
        draw_title()
    case 1:
        draw_game()
 
# break, continue, return work as expected

Functions

def fire_bullet(x, y, direction):
    bullet_x = x
    bullet_y = y
    bullet_dir = direction
  • Up to 4 positional parameters.
  • Variables declared in main() are not accessible in loop() and vice versa — each function has separate scope.

Arrays

Arrays are declared with const (stored in ROM) or as globals (stored in RAM):

const coords = [10, 20, 30, 40]
val = coords[1]             # read by index
 
scores = [0, 0, 0]          # mutable array in RAM
scores[0] = 999

META Directives

META TITLE = "PANG"          # ROM header title (max 16 chars)
META MUSIC = music1          # background music asset
META ROM_TOTAL_SIZE = 65536  # enable multibank (optional)
META ROM_BANK_SIZE  = 16384  # bank size (optional, default 16KB)

Key Built-in Functions

Frame Control & Drawing

FunctionDescription
SET_INTENSITY(n)Set beam brightness (0–127)
MOVE(x, y)Move beam to position without drawing
DRAW_LINE(x0, y0, x1, y1, intensity)Draw a line segment
DRAW_CIRCLE(cx, cy, diam, intensity)Draw a circle (16 segments)
DRAW_CIRCLE_SEG(segs, cx, cy, diam, intensity)Draw a circle with custom segment count
DRAW_POLYGON(x0, y0, x1, y1, ..., intensity)Draw a polygon
DRAW_VECTOR("name", x, y)Draw a .vec vector asset at position (x, y)
DRAW_VECTOR_EX("name", x, y, mirror, intensity)Draw a .vec asset with mirror and intensity override
DRAW_RECT(x, y, w, h, intensity)Draw a rectangle outline
DRAW_FILLED_RECT(x, y, w, h, intensity)Draw a filled rectangle

Input

FunctionDescription
J1_X() / J1_Y()Joystick 1 axes (-128 to 127)
J1_BUTTON_1() / J1_BUTTON_2() / J1_BUTTON_3() / J1_BUTTON_4()Joystick 1 buttons
J2_X() / J2_Y()Joystick 2 axes
J2_BUTTON_1() / J2_BUTTON_2() / J2_BUTTON_3() / J2_BUTTON_4()Joystick 2 buttons
J2_ANALOG_X() / J2_ANALOG_Y()Raw analog joystick 2 input
J2_DIGITAL_X() / J2_DIGITAL_Y()Digital direction input (-1, 0, +1)
UPDATE_BUTTONS()Poll and update button states

Text & Debug

FunctionDescription
PRINT_TEXT(x, y, "text")Print text on screen
PRINT_NUMBER(x, y, number)Print a 16-bit integer
DEBUG_PRINT(val)Print value to IDE debug panel
DEBUG_PRINT_LABELED("label", val)Debug output with label

Audio

FunctionDescription
PLAY_MUSIC("name")Start playing a .vmus asset
STOP_MUSIC()Stop current music
PLAY_SFX("name")Play a .vsfx sound effect
AUDIO_UPDATE()Update audio engine state
MUSIC_UPDATE()Update music playback

Level System

FunctionDescription
LOAD_LEVEL("name")Load a .vplay level file
SHOW_LEVEL()Render the current level
UPDATE_LEVEL()Update level state
GET_LEVEL_WIDTH() / GET_LEVEL_HEIGHT()Get level dimensions
GET_LEVEL_TILE(x, y)Get tile value at position

Math Functions

FunctionDescription
abs(x)Absolute value
min(a, b) / max(a, b)Min/max of two values
clamp(v, lo, hi)Clamp value between bounds
sin(a) / cos(a) / tan(a)Trigonometric (angle 0..127)
sqrt(x) / pow(x, y)Square root and power
atan2(y, x)Two-argument arctangent
rand() / rand_range(min, max)Random number generation

Utilities

FunctionDescription
wait(frames)Wait for N frame cycles
beep()Emit a beep sound
fade_in() / fade_out()Fade display in/out
peek(addr) / poke(addr, val)Memory read/write (constant addresses only)
asm("code")Inline MC6809 assembly

Known Limitations

  • Structs: Parsed but not compiled. Use parallel arrays instead.
  • Enums: Not supported. Use named constants.
  • len(array): Returns 0. Track array sizes manually.
  • Recursion: Unsafe — no stack overflow protection.
  • DRAW_TO(x, y): Not implemented. Use MOVE() + DRAW_LINE() instead.