Scena
Creative graphics and 2D games in Python, made for learning to program.
Easy to begin. Space to grow.
Tutorial · API Guide · Examples · Changelog
Scena is a Python framework for drawing, animating and making games, written for people who are learning to program. You write what is on the screen and what should happen; Scena runs the loop, draws every frame, moves the animations, checks the collisions and cleans up after you. It draws with Skia (the engine behind Chrome and Android), so even a first program looks good.
A whole game, one screen of code
from random import uniform
from scena import *
init(width=800, height=600, title="Catch the stars")
Wallpaper("dark navy")
st.score = 0
label = Text(text="", top_left=(20, 580), font_size=22)
label["text"] @= lambda: f"Stars: {st.score}"
paddle = Sprite("k-rolling-ball/button_blue.png", width=90, center=(400, 50), group="paddle")
@every(0.5)
def drop_star():
star = Sprite("k-rolling-ball/star.png", size=36, center=(uniform(40, 760), 580), group="stars")
star.glow = True
def update(dt):
if keyp("LEFT"):
paddle.move_by(-420 * dt, 0)
if keyp("RIGHT"):
paddle.move_by(420 * dt, 0)
group["stars"].move_by(0, -180 * dt)
@collide("paddle", "stars")
def catch(paddle, star):
star.destroy()
st.score += 1
paddle.pop(scale=1.25)
@leave_playfield("stars")
def missed(star):
star.destroy()
run()
No game loop to write, no event queue to poll, no list of objects to draw or to
clean up. The label is a formula (@=): it keeps up with the score by itself.
Why Scena
- Made for learning. The first program is a few lines; the concepts arrive one at a time, in the order a learner needs them. Speed is the framework's job, not the beginner's.
- Simple things are simple.
Circle()draws a circle.Sprite("ship.png")shows a ship. No setup, no boilerplate, no classes to inherit before anything appears. - Easy to begin, space to grow. Parameters are gradual: start with
Circle(), thenCircle(center=(200, 150), radius=40), thencircle.visual = Neon("cyan"). Add detail only when you want it. - Say what should happen.
@collide,@when,@everyand@clickread like the rules of the game. A formula (label["text"] @= lambda: ...) is written once and stays true. - No magic. Code does what it looks like it does. Scena never adds behavior or content you did not ask for: it gives you rich vocabulary, and the scene is yours.
- Mistakes explain themselves. A misspelled key, color or parameter gets a message that says what was wrong and suggests the closest right name.
- Batteries included. Collision, animation, effects, camera, layers, UI widgets, sound and a level editor are in the box, and they work together.
What's in the box
Shapes and sprites. Circles, rectangles, polygons, lines, text, images and sprite sheets. Every one draws with nothing but defaults, and takes more when you want more.
ball = Circle() # a circle in the middle of the window
ball.color = "coral"
ball.visual = Neon("cyan") # one of 30+ looks
ship = Sprite("space/playerShip1_red.png", height=45, center=(400, 60))
ship.glow = True
Events that read like rules. Collisions, timers, clicks, conditions and objects leaving the screen, each one a decorator.
@collide("shots", "enemies")
def hit(shot, enemy):
canvas.burst_at(enemy, radius=40)
shot.destroy()
enemy.destroy()
@when(lambda: st.score >= 10)
def level_up():
st.speed *= 1.5
Formulas. Link a value to others once; Scena keeps it up to date.
a = Circle(center=(200, 300), radius=8)
b = Circle(center=(600, 300), radius=8)
bridge = Line(p1=lambda: a.center, p2=lambda: b.center) # follows a and b
Animation in one line. Move, turn, scale and fade over time, with easing,
loops and yoyo. Effects such as pop, flash, dissolve_out and explosion_at
clean up after themselves.
ship.move_to(400, 300, time=1.5, ease="ease_in_out")
enemy.scale_to(1.08, time=0.45, loops="forever", yoyo=True)
Looks, effects and backgrounds. Visuals for shapes, screen effects, animated backgrounds and one-shot explosions, all composable.
visual = Flame() |
visual = ElectricField() |
Portal() |
canvas.fireworks_at(x, y) |
Borealis() |
ship.dissolve_out(0.5) |
And more. A camera, layers and endless scrolling worlds; boxes, grids and
geometry (intersections, midpoints, tangents); sliders, buttons, menus and
check boxes; sound effects, music and the microphone; acts for menus and levels;
and scena-editor, a level editor whose files a game reads with Level.
Gallery
Every clip below is a program from examples/,
played and recorded by the computer (nothing is edited by hand). Each one is the
last step of a tutorial.
Install
Scena needs Python 3.12 or newer, on Windows, macOS or Linux.
pip install scena
To try the examples, get a copy of this repository and run one:
git clone https://github.com/accmota/Scena.git
cd Scena
pip install -e .
python examples/naves_escudo.py
Then, in any script: from scena import *.
Learn
- Tutorial: from the first
shapes to a space shooter, bouncing balls, a side-scrolling plane, a ninja
platformer built in the level editor, a board game, a voice-driven music
studio and an endless runner. Each one ends in a file in
examples/. - API Guide: every class, function and effect, with a live picture of each look.
The tutorial and the Guide are in Portuguese today; the English version is in progress. The API itself (every name you type) is in English.
Is Scena for you?
Scena is a good fit for learning to program, small 2D games and creative coding. It is not trying to be a professional engine: it is 2D only, runs on the desktop (not in the browser or on phones), and is made for scenes with tens to hundreds of objects. Simple games stay simple, even if that means less power for very large ones.
License
Scena's code and documentation are under the MIT license.
The images and sounds in examples/media/ come from other artists under their own
licenses (mostly CC0). A few sounds ask for credit; the lines to copy are in
examples/media/CREDITS.md.
Contributions are welcome under the same license: see CONTRIBUTING.md.
By André Mota. For my sons, with much love.
Metadata
Release files for scena 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| scena-0.8.0.tar.gz | 2.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| scena-0.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.4 MB
Release files / scena-0.8.0.tar.gz
| Download URL | scena-0.8.0.tar.gz |
|---|---|
| Size | 2.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4628db1b707fc75a1d169570372899df9cd735e2e623b5f1e5c335c7bea9ff0c
|
|
BLAKE2b-256 checksum How to use checksums |
d48c2873303b62fc8ca6f59c949d35fa0fa460339964ea7b4cc83b5b9844750b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / scena-0.8.0-py3-none-any.whl
| Download URL | scena-0.8.0-py3-none-any.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
375a5f85c96c89d70845af5d6848805cc33cf504c7c823e625cee98db69ebf7d
|
|
BLAKE2b-256 checksum How to use checksums |
3db6d4c8eb131470a799c8a71c9f865d22c90e952e5bdf4ed8867f3bbcb8c3a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log