Skip to main content

Pyctures

Pyctures ("Python pictures") gives Python the full set of JavaScript graphics functions: the web's 2D canvas for 2D, and three.js for 3D. Write a short Python program and it draws in your web browser: shapes, text, moving sprites, games, animations, live charts and lit 3D scenes. The names are the ones JavaScript uses, so any JavaScript graphics example can be brought across easily. Run a scene with your own Python while you write it, then build it into a folder that runs in any browser, on any website.

A 3D Pyctures scene: Python code beside its live preview

Install

pip install pyctures

Python 3.9 or newer. Nothing else is installed.

A first scene

Save this as hello.py:

import math

def draw():
    ctx.fill_style = "midnightblue"
    ctx.fill_rect(0, 0, width, height)
    for i in range(12):
        ctx.fill_style = f"hsl({i * 30}, 80%, 60%)"
        ctx.begin_path()
        ctx.arc(width / 2 + 120 * math.cos(i / 1.91), height / 2 + 120 * math.sin(i / 1.91), 20, 0, math.tau)
        ctx.fill()

draw() is called every frame, ctx is the 2D drawing surface, and width and height are the size of the canvas. There is nothing to import.

Run it

pyctures run hello.py

Your browser opens on the scene. The program runs in your own Python, so numpy and anything else you have installed works. Save the file and the scene runs again. Errors are shown on the page with the line they happened on.

Options: --port 9000, --no-browser.

Share it

pyctures build hello.py -o site/

site/ is a folder of plain files that runs the scene entirely in the browser, with Pyodide loaded from its official CDN. Put it on any static host. Every path in it is relative.

Or make one file:

pyctures build hello.py -o hello.html

hello.html holds the scene and everything it needs (three.js too, if the scene is 3D), so you can email it, put it on any website, or open it straight from your disk. Python still loads from Pyodide's CDN.

Either way, images the scene loads by a relative path, such as load_image("textures/brick.png") or THREE.TextureLoader().load("textures/brick.png"), are included automatically: copied into the folder, or packed into the one file. A named image that is missing is reported as a warning.

Python runs in a background thread of the browser (a Web Worker), and the page only draws. A slow frame or a stuck loop cannot hold up the page, so scenes play smoothly on phones and tablets too. Add ?measure=1 to the address to see the frame rate and where each frame's time goes.

Use it on your website

Either put a built scene in an iframe:

<iframe src="hello/index.html" style="width: 100%; aspect-ratio: 16 / 9; border: 0"></iframe>

or put scenes straight into your page, as many as you like:

<div data-pyctures-src="balls.py"></div>
<div data-pyctures-src="knot.py" style="height: 420px"></div>
<script type="module" src="pyctures/pyctures.js"></script>

Each canvas fills its box, starts when it scrolls into view, and pauses when it is out of view or the tab is hidden. All the scenes on a page share one copy of Python, in a background thread. pyctures build my-page/ -o site/ copies your page and adds the pyctures/ folder. See Use it on your website, and the two-scene page in examples/website.

Bringing a JavaScript example across

The calls are the same; a few things are written the Python way.

JavaScript Python
new THREE.Mesh(g, m) THREE.Mesh(g, m)
{ color: 0x44aaff, roughness: 0.4 } color=0x44aaff, roughness=0.4
const x = 1; let y = 2; x = 1 y = 2
ctx.fillStyle = "red" the same, or ctx.fill_style = "red"
a requestAnimationFrame loop def draw(): and def update(dt):
canvas.addEventListener("click", (e) => …) canvas.add_event_listener("click", clicked) with def clicked(e):
const w = ctx.measureText("Hi").width w = await ctx.measure_text("Hi").width
Math.PI math.pi
// JavaScript
const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1),
                            new THREE.MeshStandardMaterial({ color: 0x44aaff }));
scene.add(cube);
function animate() {
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}
animate();
# Python
cube = THREE.Mesh(THREE.BoxGeometry(1, 1, 1),
                  THREE.MeshStandardMaterial(color=0x44aaff))
scene.add(cube)

def draw():
    cube.rotation.y += 0.01
    renderer.render(scene, camera)

The full guide, with a 2D and a 3D example side by side: Bringing a JavaScript example across.

Examples

In examples/, each with a comment at the top saying what it shows:

File What it is
star_catcher.py A 2D game with sprites, a score and lives
cube_dodge.py A 3D game: dodge the oncoming blocks
lit_scene.py Shapes on a floor with a spotlight and shadows
bouncing_balls.py A 2D animation with trails; click to add balls
solar_system.py Planets, a moon and 2,000 stars in 3D
live_chart.py A live line chart with a readout under the mouse
type_and_measure.py Keyboard input, and reading a value back with await
from_javascript_2d.py, from_javascript_3d.py JavaScript examples brought across
website/ A web page with two scenes on it
pyctures run examples/star_catcher.py
pyctures run examples            # a list of them all

Docs

Start with Getting started, then how a program is shaped, drawing in 2D, 3D scenes, colours, and tips. The 2D functions and 3D functions pages list everything, one line each. Seven tutorials are in docs/tutorials.

Pyctures in Circuitry Studio

Pyctures comes from Circuitry Studio, where Python scenes run in a code editor with a live preview beside the code, with a debugger and ready-made examples. It runs on phones, iPad, the web and desktop, and no subscription is needed to use it. Scenes written with this library run there unchanged, and the other way round.

A 3D Pyctures scene running in Circuitry Studio on iPad, with the Python code beside its live preview

Its help pages: Pyctures help · 2D functions · 3D functions · Colours · Bringing a JavaScript example across

Licence

MIT. See LICENSE. Pyctures includes three.js (MIT) and loads Pyodide (MPL 2.0) from its CDN; see THIRD-PARTY-NOTICES.

Author: John Wylie

Metadata

Release files for pyctures 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyctures 0.1.0
File Size Uploaded
pyctures-0.1.0.tar.gz 248.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyctures 0.1.0
File Interpreter ABI Platform
pyctures-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 483.7 kB

Release files / pyctures-0.1.0.tar.gz

Download URL pyctures-0.1.0.tar.gz
Size 248.3 kB
Tags Source
SHA-256 checksum
How to use checksums
360625c7274ddbc164f6bda03d499a5706b4a82573480b39415f6563aef1d565
BLAKE2b-256 checksum
How to use checksums
aa4f69e3e6eacfce67a873b3fb52b7c959c82a04c200d2d7b4432f72e6311302
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / pyctures-0.1.0-py3-none-any.whl

Download URL pyctures-0.1.0-py3-none-any.whl
Size 235.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0eba2e2dcbf739a041a9f5e8309e1634307c2e1a3a63ee4038977d51ce0957dc
BLAKE2b-256 checksum
How to use checksums
ed77b33947b2d5f781b9c76cce0cdd898a4c8d0270326aa18beca16d0ebceccd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page