Skip to main content

Bidirectional Python to Scratch 3.0 transpiler

Project description

Py2SB3

PyPI version License: MIT Python 3.8+

A bidirectional Python to Scratch 3.0 transpiler. Write Scratch projects in Python, or convert existing Scratch projects to Python code.

Features

  • Python → Scratch: Write Python code and compile to .sb3 files
  • Scratch → Python: Convert existing .sb3 projects to readable Python
  • Round-trip: Convert Scratch → Python → Scratch while preserving all sprites and sounds
  • IDE Support: Full autocomplete and type hints for all Scratch blocks
  • 339 Official Sprites: Access to the complete Scratch sprite library
  • Sound Library: All official Scratch sounds available

Installation

pip install py2sb3

Or install from source:

git clone https://github.com/Samuelicjones/Py2SB3.git
cd Py2SB3
pip install -e .

Quick Start

Writing Scratch in Python

from scratch import transpile_to_json, save_sb3
from scratch.dsl import *  # IDE autocomplete for all blocks

class Cat:
    def when_flag_clicked(self):
        say("Hello!")
        for i in range(10):
            move(10)
            turn_right(15)
            wait(0.1)

    def when_key_space(self):
        play_sound("Meow")

# Compile to .sb3
code = open("my_game.py").read()
json_str = transpile_to_json(code)
save_sb3(json_str, "my_game.sb3")

Converting Scratch to Python

from scratch import convert_sb3_to_py

# Convert any .sb3 file to Python
convert_sb3_to_py("existing_project.sb3", "output.py")

Round-trip Conversion

from scratch import roundtrip_sb3

# Convert .sb3 → Python → .sb3 (preserves all sprites/sounds)
roundtrip_sb3("input.sb3", "output.sb3", py_path="intermediate.py")

CLI Commands

# Python to Scratch
scratch py2sb3 game.py game.sb3

# Scratch to Python
scratch sb32py project.sb3 project.py

# Round-trip (preserves assets)
scratch roundtrip input.sb3 output.sb3 --py intermediate.py

# Show project info
scratch info project.sb3

Sprite Classes

Each Python class becomes a Scratch sprite. The class name determines the sprite:

class Cat:        # Uses official Cat sprite
    pass

class Dog1:       # Uses Dog1 sprite
    pass

class MySprite:   # Uses default sprite
    pass

Event Handlers

Methods starting with when_ become Scratch event handlers:

Python Method Scratch Block
when_flag_clicked() Green flag clicked
when_key_space() When space key pressed
when_key_up() When up arrow pressed
when_key_a() When 'a' key pressed
when_clicked() When this sprite clicked
when_broadcast_message1() When I receive "message1"
when_i_start_as_clone() When I start as a clone

Supported Blocks

Motion

move(10)                    # Move 10 steps
turn_right(15)              # Turn right 15 degrees
turn_left(15)               # Turn left 15 degrees
go_to("random")             # Go to random position
go_to("mouse")              # Go to mouse pointer
go_to_xy(0, 0)              # Go to x, y
glide_to_xy(1, 100, 100)    # Glide to x, y in 1 second
point_in_direction(90)      # Point in direction
point_towards("mouse")      # Point towards mouse
change_x(10)                # Change x by 10
set_x(0)                    # Set x to 0
change_y(10)                # Change y by 10
set_y(0)                    # Set y to 0
if_on_edge_bounce()         # If on edge, bounce
set_rotation_style("left-right")
x_position()                # Reporter: x position
y_position()                # Reporter: y position
direction()                 # Reporter: direction

Looks

say("Hello!")               # Say
say_for_secs("Hi!", 2)      # Say for 2 seconds
think("Hmm...")             # Think
think_for_secs("...", 2)    # Think for 2 seconds
switch_costume("costume2")  # Switch costume
next_costume()              # Next costume
switch_backdrop("backdrop2")
next_backdrop()
change_size(10)             # Change size by 10
set_size(100)               # Set size to 100%
change_effect("color", 25)  # Change color effect
set_effect("ghost", 50)     # Set ghost effect
clear_effects()             # Clear graphic effects
show()                      # Show sprite
hide()                      # Hide sprite
go_to_layer("front")        # Go to front layer
change_layer("forward", 1)  # Go forward 1 layer
costume_number()            # Reporter
backdrop_name()             # Reporter
size()                      # Reporter

Sound

play_sound("Meow")          # Start sound
play_sound_until_done("Pop")# Play until done
stop_all_sounds()           # Stop all sounds
change_volume(-10)          # Change volume
set_volume(100)             # Set volume
volume()                    # Reporter

Control

wait(1)                     # Wait 1 second
for i in range(10):         # Repeat 10 times
    move(10)
while True:                 # Forever loop
    move(1)
if touching("edge"):        # If-then
    turn_right(180)
if x_position() > 0:        # If-else
    move(10)
else:
    move(-10)
wait_until(touching("edge"))# Wait until
while not touching("edge"): # Repeat until
    move(1)
stop("all")                 # Stop all/this script
create_clone("myself")      # Create clone
delete_this_clone()         # Delete this clone

Sensing

touching("mouse")           # Touching mouse pointer?
touching("edge")            # Touching edge?
touching("Sprite1")         # Touching sprite?
touching_color("#FF0000")   # Touching color?
color_touching_color("#FF0000", "#00FF00")
distance_to("mouse")        # Distance to
ask("What's your name?")    # Ask and wait
answer()                    # Answer reporter
key_pressed("space")        # Key pressed?
mouse_down()                # Mouse down?
mouse_x()                   # Mouse x
mouse_y()                   # Mouse y
timer()                     # Timer
reset_timer()               # Reset timer
property_of("x position", "Sprite1")
current("year")             # Current year/month/etc
days_since_2000()           # Days since 2000
username()                  # Username

Operators

pick_random(1, 10)          # Random number
join("hello", "world")      # Join strings
letter_of(1, "hello")       # Letter 1 of "hello"
length_of("hello")          # Length of string
contains("hello", "ell")    # Contains substring?
x % y                       # Modulo (use mod())
round_num(3.7)              # Round
math_op("abs", -5)          # abs/floor/ceiling/sqrt/sin/cos/tan/etc

Variables

my_var = 0                  # Create variable
my_var = 10                 # Set variable
my_var += 5                 # Change variable
show_variable("my_var")     # Show variable
hide_variable("my_var")     # Hide variable

Lists

my_list = []                # Create list
add_to_list("apple", "my_list")
delete_of_list(1, "my_list")
delete_all_of_list("my_list")
insert_at_list("banana", 1, "my_list")
replace_item_of_list(1, "my_list", "cherry")
item_of_list(1, "my_list")  # Reporter
index_in_list("apple", "my_list")
length_of_list("my_list")
list_contains("my_list", "apple")

Custom Blocks

def define_jump(self, height):
    """Custom block with argument"""
    change_y(height)
    wait(0.5)
    change_y(-height)

def when_flag_clicked(self):
    self.jump(50)  # Call custom block

Using Official Sprites

The transpiler includes all 339 official Scratch sprites:

from scratch import list_sprites, get_sprite_data

# List all available sprites
print(list_sprites())  # ['Abby', 'Amon', 'Andie', ...]

# Get sprite info
sprite = get_sprite_data("Cat")
print(f"Costumes: {len(sprite['costumes'])}")
print(f"Sounds: {len(sprite['sounds'])}")

Using Sounds

from scratch import list_sounds, get_library_sound_for_project

# List all sounds
print(list_sounds())  # ['A Bass', 'A Elec Bass', ...]

# Sounds are auto-detected from play_sound() calls
class Cat:
    def when_flag_clicked(self):
        play_sound("Meow")  # Auto-included in project

Project Structure

Py2SB3/
├── src/scratch/
│   ├── __init__.py      # Package exports
│   ├── transpiler.py    # Core transpiler (Python ↔ Scratch)
│   ├── dsl.py           # IDE stubs for autocomplete
│   ├── library.py       # Sprite/sound library access
│   ├── cli.py           # Command-line interface
│   └── data/
│       ├── sprites_library.json
│       └── sounds_library.json
├── tests/
│   └── test_transpiler.py
├── pyproject.toml
└── README.md

License

MIT License - see LICENSE file for details.

Contributing

Contributions welcome! Please feel free to submit a Pull Request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py2sb3-1.0.1.tar.gz (109.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

py2sb3-1.0.1-py3-none-any.whl (110.0 kB view details)

Uploaded Python 3

File details

Details for the file py2sb3-1.0.1.tar.gz.

File metadata

  • Download URL: py2sb3-1.0.1.tar.gz
  • Upload date:
  • Size: 109.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for py2sb3-1.0.1.tar.gz
Algorithm Hash digest
SHA256 fdca3ec63cb39584037bc46b72f6efc9e517886d1b608dd9bf675e095d235076
MD5 316b3ef3e86c3661d48be44f0c66bcba
BLAKE2b-256 3860ca19717d70d83358ca0d7f29c44f2763661a3d62e569c002ed2c6f117407

See more details on using hashes here.

File details

Details for the file py2sb3-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: py2sb3-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 110.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for py2sb3-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 33e89aba3cc19d4330edde08417192d8abe9399237ea032908d82d6e36134564
MD5 0628cdace984363b114aa3e217424c9d
BLAKE2b-256 9175396c9733a756d9c9bb9e5072534d87899f997ecc728d3ac2ffd1321fa532

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page