EktuPy API Reference
Complete reference for all EktuPy classes, methods, and functions.
Table of Contents
- Stage Class
- Sprite Class
- Global Event Decorators
- Control Functions
- Input Functions
- Sensing Functions
- Messaging
- Sound Functions
- Asset Map
Stage Class
The Stage is the canvas where all sprites live and move. The stage has a fixed size of 960x720 pixels.
Constructor
Stage(background_color="#ffffff")
| Parameter | Type | Default | Description |
|---|---|---|---|
background_color | str | “#ffffff” | Background color (CSS color) |
# Create a stage with default white background
stage = Stage()
# Create a stage with a custom background color
stage = Stage("#1a1a2e")
Properties
| Property | Type | Description |
|---|---|---|
width | int | Stage width (always 960) |
height | int | Stage height (always 720) |
Coordinate System
EktuPy uses a Scratch-like coordinate system with the origin at the center:
(0, 360) Top
|
|
(-480, 0) Left -----(0, 0)-----> (480, 0) Right
|
|
(0, -360) Bottom
| Axis | Range | Description |
|---|---|---|
| X | -480 to 480 | Horizontal position (negative = left, positive = right) |
| Y | -360 to 360 | Vertical position (negative = down, positive = up) |
Direction angles:
0= Up90= Right180(or-180) = Down-90= Left
Methods
set_background(color)
Set the stage background color.
stage.set_background("#87CEEB") # Sky blue
stage.set_background("red") # Named color
set_background_image(name_or_path)
Set a background image by asset name or path.
# Using an asset name
stage.set_background_image("sky-and-clouds")
# Using a path
stage.set_background_image("/static/assets/backdrops/jungle.svg")
Available backdrops:
jungle- Dense jungle forest scenemountain-sunrise- Mountains with rising sunpaddy-field- Sun over rice paddy fieldsrace-track- Racing track scenesky-and-clouds- Blue sky with fluffy clouds
add_sprite(sprite)
Add a sprite to the stage.
cat = Sprite("cat")
stage.add_sprite(cat)
start()
Start the game loop. Usually called automatically.
stop()
Stop the game loop.
Sprite Class
Sprites are the visual objects that move and interact on the stage.
Constructor
Sprite(image_path=None)
| Parameter | Type | Default | Description |
|---|---|---|---|
image_path | str | None | Asset name or path to sprite image (SVG, PNG, etc.) |
You can create sprites using either an asset name (simpler) or a full path:
# Using asset name (recommended)
snake = Sprite("snake") # Looks up "snake" in the asset map
paddle = Sprite("paddle") # Looks up "paddle" in the asset map
# Using full path (also works)
snake = Sprite("/static/assets/sprites/snake.svg")
Asset names are easier to use and will show a warning in the editor if the name doesn’t exist. See Asset Map for more details.
Sprite Properties
All properties can be read and written:
| Property | Type | Description |
|---|---|---|
x | float | X position (0 = center) |
y | float | Y position (0 = center) |
direction | float | Direction in degrees (0=up, 90=right) |
size | float | Size as percentage (100 = normal) |
costume_number | int | Current costume number (read-only) |
costume_name | str | Current costume name (read-only) |
is_clone | bool | True if this sprite is a clone (read-only) |
sprite.x = 100
sprite.y = -50
sprite.direction = 90 # Face right
sprite.size = 150 # 150% size
print(sprite.x) # Read position
Motion Methods
move(steps)
Move in the current direction.
sprite.move(10) # Move 10 steps forward
turn_right(degrees) / turn_left(degrees)
Rotate the sprite.
sprite.turn_right(90) # Turn 90 degrees clockwise
sprite.turn_left(45) # Turn 45 degrees counter-clockwise
go_to(x, y)
Instantly move to a position.
sprite.go_to(0, 0) # Go to center
sprite.go_to(-100, 50) # Go to specific position
set_x(x) / set_y(y)
Set just the x or y position.
sprite.set_x(100)
sprite.set_y(-50)
change_x(amount) / change_y(amount)
Change position by an amount.
sprite.change_x(10) # Move 10 pixels right
sprite.change_y(-5) # Move 5 pixels down
go_to_random_position()
Move to a random position on the stage.
sprite.go_to_random_position()
go_to_mouse()
Move to the mouse pointer position.
sprite.go_to_mouse()
go_to_sprite(other)
Move to another sprite’s position.
cat.go_to_sprite(dog)
glide_to(x, y, seconds)
Smoothly glide to a position over time.
sprite.glide_to(100, 50, 2) # Glide over 2 seconds
glide_to_random_position(seconds)
Glide to a random position.
sprite.glide_to_random_position(1.5)
glide_to_mouse(seconds)
Glide to the mouse pointer.
sprite.glide_to_mouse(1)
glide_to_sprite(other, seconds)
Glide to another sprite.
cat.glide_to_sprite(dog, 2)
point_towards(x, y)
Point toward a position.
sprite.point_towards(100, 100)
point_towards_mouse()
Point toward the mouse pointer.
sprite.point_towards_mouse()
point_towards_sprite(other)
Point toward another sprite.
cat.point_towards_sprite(dog)
set_rotation_style(style)
Set how the sprite rotates visually.
| Style | Description |
|---|---|
"all around" | Rotate freely in all directions |
"left-right" | Only flip horizontally (default) |
"don't rotate" | Never rotate visually |
sprite.set_rotation_style("all around")
bounce_if_on_edge()
If touching edge, bounce (reverse direction).
@on_forever
def move():
sprite.move(5)
sprite.bounce_if_on_edge()
Looks Methods
say(text, seconds=None)
Show a speech bubble.
sprite.say("Hello!") # Show until changed
sprite.say("Hi!", 2) # Show for 2 seconds
sprite.say("") # Clear bubble
think(text, seconds=None)
Show a thought bubble (cloud shape).
sprite.think("Hmm...")
sprite.think("I wonder...", 3)
show() / hide()
Show or hide the sprite.
sprite.hide()
wait(1)
sprite.show()
change_size(amount)
Change size by amount.
sprite.change_size(10) # Grow by 10%
sprite.change_size(-20) # Shrink by 20%
set_ghost_effect(value)
Set transparency (0=visible, 100=invisible).
sprite.set_ghost_effect(50) # 50% transparent
change_ghost_effect(amount)
Change transparency by amount.
sprite.change_ghost_effect(10) # More transparent
clear_graphic_effects()
Reset all visual effects.
sprite.clear_graphic_effects()
switch_costume(name_or_index)
Switch to a different costume.
sprite.switch_costume(0) # By index
sprite.switch_costume("walk1") # By name
next_costume()
Switch to the next costume (wraps around).
sprite.next_costume()
add_costume(image_path, name)
Add a new costume from an image.
sprite.add_costume("/static/assets/walk2.png", "walk2")
Layer Methods
sprite.go_to_front_layer() # Move to front
sprite.go_to_back_layer() # Move to back
sprite.go_forward_layers(2) # Move forward 2 layers
sprite.go_backward_layers(1) # Move backward 1 layer
Pen Methods
Draw lines on the stage as the sprite moves.
pen_down() / pen_up()
Start or stop drawing.
sprite.pen_down()
sprite.move(100) # Draws a line
sprite.pen_up()
sprite.move(50) # No line drawn
set_pen_color(color)
Set the pen color.
sprite.set_pen_color("red")
sprite.set_pen_color("#FF5500")
sprite.set_pen_color("rgb(255, 100, 0)")
set_pen_size(size)
Set the pen width in pixels.
sprite.set_pen_size(5)
stamp()
Stamp the sprite’s image onto the stage.
sprite.stamp()
clear()
Erase all pen drawings.
sprite.clear()
Sensing Methods
touching(other)
Check if touching another sprite.
if cat.touching(dog):
cat.say("Ouch!")
touching_edge()
Check if touching the stage edge.
if sprite.touching_edge():
sprite.bounce_if_on_edge()
touching_mouse()
Check if touching the mouse pointer.
if sprite.touching_mouse():
sprite.say("You're on me!")
distance_to(other)
Get distance to another sprite.
dist = cat.distance_to(dog)
if dist < 50:
cat.say("Too close!")
distance_to_mouse()
Get distance to the mouse pointer.
dist = sprite.distance_to_mouse()
if dist < 100:
sprite.say("Getting close!")
Clone Methods
Create copies of sprites at runtime.
clone()
Create a clone of this sprite.
new_clone = sprite.clone()
on_clone_start(callback)
Register a function to run when this sprite is cloned.
def on_cloned():
# 'sprite' here refers to the new clone
sprite.go_to_random_position()
sprite.on_clone_start(on_cloned)
delete_clone()
Delete this clone (only works on clones).
if sprite.is_clone:
sprite.delete_clone()
Per-Sprite Event Decorators
Each sprite can have its own event handlers, just like Scratch.
@sprite.on_start
Runs when the program starts (for this sprite only).
@cat.on_start
def cat_setup():
cat.go_to(-100, 0)
cat.say("I'm the cat!")
@sprite.on_forever
Runs every frame (for this sprite only).
@cat.on_forever
def cat_loop():
cat.turn_right(1)
@sprite.on_key_press(key)
Runs when a key is pressed (for this sprite only).
@cat.on_key_press("space")
def cat_jump():
cat.change_y(50)
@sprite.on_message(message)
Runs when a broadcast is received (for this sprite only).
@cat.on_message("game_over")
def cat_dies():
cat.say("Oh no!")
cat.hide()
sprite.on_clicked(callback)
Runs when this sprite is clicked.
def on_cat_click():
cat.say("You clicked me!")
cat.on_clicked(on_cat_click)
Global Event Decorators
These decorators register handlers that aren’t tied to a specific sprite.
@on_start
Runs once when the program starts.
@on_start
def setup():
print("Game started!")
@on_forever
Runs every frame (approximately 60 times per second).
@on_forever
def game_loop():
# Update game state
pass
@on_key_press(key)
Runs when a specific key is pressed.
Key names: "a" to "z", "0" to "9", "space", "up arrow", "down arrow", "left arrow", "right arrow", "any" (any key)
@on_key_press("space")
def jump():
player.change_y(50)
@on_key_press("any")
def any_key(key):
print(f"Pressed: {key}")
@on_mouse_click
Runs when the mouse is clicked on the stage.
@on_mouse_click
def click_handler(x, y):
print(f"Clicked at ({x}, {y})")
sprite.go_to(x, y)
@on_message(message)
Runs when a broadcast message is received.
@on_message("level_complete")
def next_level():
print("Loading next level...")
Control Functions
wait(seconds)
Pause execution without freezing the program.
@on_start
def setup():
sprite.say("Hello!")
wait(2)
sprite.say("Goodbye!")
wait_until(condition)
Wait until a condition becomes true.
@on_start
def setup():
sprite.say("Waiting for you to press space...")
wait_until(lambda: key_pressed("space"))
sprite.say("Thanks!")
stop() / stop_all()
Stop the game/program.
if game_over:
stop()
Input Functions
key_pressed(key)
Check if a key is currently held down.
if key_pressed("right arrow"):
sprite.change_x(5)
mouse_x() / mouse_y()
Get the mouse position on the stage.
x = mouse_x()
y = mouse_y()
sprite.go_to(x, y)
mouse_down()
Check if the mouse button is pressed.
if mouse_down():
sprite.stamp()
Sensing Functions
Global functions for sensing time, date, and environment.
Timer
timer()
Get the time in seconds since the program started (or since the last reset).
t = timer()
if t > 30:
sprite.say("30 seconds passed!")
reset_timer()
Reset the timer back to 0.
reset_timer()
# timer() now returns 0
Date and Time
current_year()
Get the current year.
year = current_year() # e.g., 2025
current_month()
Get the current month (1-12).
month = current_month() # 1=January, 12=December
current_date()
Get the current day of the month (1-31).
day = current_date()
current_day_of_week()
Get the current day of the week (1-7, where 1=Sunday).
day_of_week = current_day_of_week()
if day_of_week == 1:
sprite.say("It's Sunday!")
current_hour()
Get the current hour (0-23).
hour = current_hour()
if hour < 12:
sprite.say("Good morning!")
current_minute()
Get the current minute (0-59).
minute = current_minute()
current_second()
Get the current second (0-59).
second = current_second()
days_since_2000()
Get the number of days since January 1, 2000 (including fractional days).
days = days_since_2000()
sprite.say(f"{int(days)} days since Y2K!")
Ask and Answer
Get user input through an on-screen text box, just like Scratch’s “ask [] and wait” block.
ask(prompt)
Show a text input box at the bottom of the stage with a prompt, wait for the user to type and submit an answer, then return the answer as a string.
@on_start
def setup():
name = ask("What is your name?")
sprite.say(f"Hello, {name}!")
The input box appears at the bottom of the stage with:
- The prompt text displayed above the input field
- A text input where the user can type
- A submit button (or press Enter to submit)
The program pauses until the user submits their answer.
answer()
Get the most recent answer from ask(). This is useful when you need to access the last answer later in your code.
@on_start
def setup():
ask("What is your name?")
name = answer() # Get the answer that was just entered
ask("How old are you?")
age = answer() # Get this new answer
sprite.say(f"Hi {name}, you are {age} years old!")
Example: Multiple questions
@on_start
def quiz():
score = 0
ask("What is 5 + 3?")
if answer() == "8":
score += 1
sprite.say("Correct!")
else:
sprite.say("Wrong! It's 8")
wait(1)
ask("What color is the sky?")
if answer().lower() == "blue":
score += 1
sprite.say("Correct!")
else:
sprite.say("Wrong!")
wait(1)
sprite.say(f"You scored {score}/2!")
Messaging
broadcast(message, data=None)
Send a message to all listeners.
broadcast("game_over")
broadcast("score_changed", {"score": 100})
Receive with @on_message or @sprite.on_message:
@on_message("score_changed")
def update_score(data):
print(f"New score: {data['score']}")
broadcast_and_wait(message, data=None)
Send a message and wait for all handlers to complete before continuing.
# Send message and wait for all handlers to finish
broadcast_and_wait("prepare_level")
# This line runs after ALL @on_message("prepare_level") handlers complete
print("Level ready!")
Useful for synchronization:
@cat.on_key_press("space")
def start_animation():
cat.say("Ready...")
broadcast_and_wait("all_sprites_ready") # Wait for everyone
cat.say("Go!") # Only runs after all handlers finish
@dog.on_message("all_sprites_ready")
def dog_prepare():
dog.go_to(0, 0)
wait(1) # This delay is waited for by broadcast_and_wait
Console Output
Use standard Python print() for debugging:
print("Hello!") # Appears in white
print(f"Position: {x}") # String formatting works
import sys
sys.stderr.write("Error!\n") # Appears in red
Sound Functions
Play sounds and music in your projects, just like Scratch’s Sound blocks.
Loading and Playing Sounds
load_sound(name, src=None)
Load a sound file and give it a name. Can be called two ways:
Using asset name (recommended):
# Single argument - name is looked up in the asset map
load_sound("sfx_sound_neutral1") # Loads from asset map
Using explicit path:
# Two arguments - provide alias and path
load_sound("hit", "/static/assets/sounds/hit.mp3")
load_sound("pop", "/static/assets/sounds/pop.wav")
| Parameter | Type | Description |
|---|---|---|
name | str | Asset name (if single arg) or alias to reference this sound |
src | str | Optional. Path or asset name for the sound file (MP3, WAV, OGG) |
Asset names are easier to use and will show a warning in the editor if the name doesn’t exist. See Asset Map for more details.
start_sound(name)
Start playing a sound (like Scratch’s “play sound” block). The sound plays in the background while your code continues running.
start_sound("meow") # Plays and continues immediately
sprite.say("Meow!") # Runs right away
play_sound_until_done(name)
Play a sound and wait until it finishes (like Scratch’s “play sound until done” block).
@on_start
def setup():
sprite.say("Listen...")
play_sound_until_done("meow") # Waits for sound to finish
sprite.say("Done!") # Only runs after sound ends
stop_all_sounds()
Stop all currently playing sounds.
stop_all_sounds()
Volume Control
Control the global volume of all sounds (0-100, like Scratch).
set_volume(value)
Set the volume (0-100).
set_volume(50) # 50% volume
set_volume(100) # Full volume
set_volume(0) # Muted
change_volume(amount)
Change the volume by an amount.
change_volume(10) # Volume up by 10
change_volume(-20) # Volume down by 20
get_volume()
Get the current volume level (0-100).
vol = get_volume()
sprite.say(f"Volume: {vol}%")
Sound Effects
Apply effects to sounds like pitch and stereo panning.
set_pitch_effect(value)
Set the pitch effect (like Scratch). Range is approximately -360 to 360.
0= normal pitch- Positive values = higher pitch (faster playback)
- Negative values = lower pitch (slower playback)
set_pitch_effect(60) # Higher pitch
set_pitch_effect(-60) # Lower pitch
set_pitch_effect(0) # Normal
change_pitch_effect(amount)
Change the pitch effect by an amount.
change_pitch_effect(10) # Increase pitch
change_pitch_effect(-20) # Decrease pitch
set_pan_effect(value)
Set the stereo pan (like Scratch’s “set pan left/right” effect).
-100= full left speaker0= center (both speakers)100= full right speaker
set_pan_effect(-100) # Full left
set_pan_effect(0) # Center
set_pan_effect(100) # Full right
change_pan_effect(amount)
Change the pan effect by an amount.
change_pan_effect(50) # Pan more to the right
clear_sound_effects()
Reset all sound effects (pitch and pan) to normal.
clear_sound_effects() # Reset to normal pitch and center pan
Example: Playing Sounds with Effects
stage = Stage()
cat = Sprite("cat")
stage.add_sprite(cat)
# Load sounds using asset names
load_sound("sfx_coin_single1")
load_sound("sfx_sounds_fanfare1")
@on_start
def setup():
set_volume(70) # 70% volume
start_sound("sfx_sounds_fanfare1") # Play a fanfare
@on_key_press("space")
def coin():
cat.say("Coin!")
start_sound("sfx_coin_single1")
@on_key_press("up arrow")
def volume_up():
change_volume(10)
cat.say(f"Volume: {get_volume()}%")
@on_key_press("down arrow")
def volume_down():
change_volume(-10)
cat.say(f"Volume: {get_volume()}%")
@on_key_press("s")
def stop_sounds():
stop_all_sounds()
cat.say("Stopped!")
Asset Map
EktuPy includes an asset map that makes it easy to use sprites and sounds by name instead of remembering full paths.
How It Works
The asset map is a JSON file (asset_map.json) that maps asset names to their full paths. This is generated from the static/assets/sprites and static/assets/sounds directories.
When you use an asset name (without slashes), EktuPy automatically looks it up in the asset map and uses the full path.
Using Asset Names
Sprites:
# Instead of using the full path:
snake = Sprite("/static/assets/sprites/snake.svg")
# You can use the asset name:
snake = Sprite("snake")
Sounds:
# Instead of:
load_sound("hit", "/static/assets/sounds/essential_retro/General_Sounds/Neutral_Sounds/sfx_sound_neutral1.wav")
# You can use:
load_sound("sfx_sound_neutral1") # Single argument - looked up by name
# or
load_sound("hit", "sfx_sound_neutral1") # Named alias with asset name
Benefits
- Shorter code: No need to type long paths
- Editor validation: The editor shows a warning if you use a name that doesn’t exist
- Easier to remember: Use descriptive names instead of file paths
Helper Functions
get_available_sprites()
Get a list of all available sprite asset names.
sprites = get_available_sprites()
print(sprites) # ['snake', 'paddle', 'ball-solid', ...]
get_available_sounds()
Get a list of all available sound asset names.
sounds = get_available_sounds()
print(sounds) # ['sfx_sound_neutral1', 'sfx_sound_neutral2', ...]
get_available_backdrops()
Get a list of all available backdrop asset names.
backdrops = get_available_backdrops()
print(backdrops) # ['jungle', 'mountain-sunrise', 'paddy-field', 'race-track', 'sky-and-clouds']
Naming Conflicts
If two files have the same basename but different extensions (e.g., ball.svg and ball.png), they are differentiated by adding the extension to the name:
ball-svgforball.svgball-pngforball.png