Tips and Limits
A few things that are good to know once your programs grow: what keeps them fast, what makes a preview freeze, and why a drawing can disappear.
Keep reads rare
Your drawing calls are sent to the preview in one batch per frame, which is what makes them fast. Reading a value back with await is different: the program has to wait for the preview to answer, which takes a whole frame.
- Read once at the start, or when something happens (a click), not every frame.
- Keep the numbers you need in Python. Track a sprite's position, a cube's angle or a score in your own variables, change them in
update(), and set them on the preview. You then always know them without asking. - A value you set from Python (
mesh.position.x = 2) is remembered, so reading it straight back needs noawait. A value worked out in the preview (aftermesh.position.x += 0.1, or anything three.js changes by itself) needsawait. - Using a preview value as if it were a Python number, as in
if mesh.position.x > 3:, stops with an error that tells you to read it withawait.
Preview frozen? A loop must wait for the next frame
The preview draws between frames. A loop that runs forever without waiting never gives it the chance, and the preview looks frozen:
# The preview freezes: this loop never waits.
x = 0
while True:
x += 1
ctx.fill_rect(x % width, 50, 10, 10)
Put await frame() at the end of the loop, and each pass becomes one frame:
x = 0
while True:
ctx.fill_style = "white"
ctx.fill_rect(0, 0, width, height)
ctx.fill_style = "black"
ctx.fill_rect(x % width, 50, 10, 10)
x += 2
await frame()
Or use update() and draw(), which can never freeze the preview this way.
If a program does get stuck, the preview stays blank or stops changing (when draw() or update() is the one stuck, it also says so under the picture after three seconds). Press Stop:
- On iPhone and iPad, Stop interrupts the stuck loop.
- Elsewhere, Stop may not be able to interrupt a loop that never waits. If the preview stays stuck, reload the app to free it, then add the missing
await frame().
When the preview changes size
The preview changes size when you drag the split, rotate a tablet or turn a phone, switch views, and when the output area under it opens or closes.
- A drawing made once, at the top level, is kept. It stays the size it was drawn, so make it again (press Run) to fit the new size.
- A program with
draw()redraws every frame using the newwidthandheight. - 3D scenes are refitted to the new size automatically, as long as you call
renderer.render(...)indraw().
Make it look right in light and dark
The preview's own background is white in the light theme and near-black in the dark theme. Start draw() by painting your own background (ctx.fill_rect(0, 0, width, height), or scene.background in 3D), so your picture looks the same whichever theme is on.
Fit any screen
The preview can be a tall, narrow phone or a wide desktop pane. Work out positions from width and height (width / 2 for the middle, height - 50 for near the bottom) rather than fixed numbers, and read them inside draw() and update() so they follow a resize.
Speed
- Most devices draw 60 frames a second, and some 120. Turn on Frame rate in the footer to see yours.
- Move things by
speed * dtinupdate(dt), so they move at the same speed whatever the frame rate. - Thousands of shapes a frame are fine. For tens of thousands, draw fewer, bigger things, or join lines into one path and stroke it once. In 3D, one
Pointsobject with thousands of positions is far quicker than thousands of separate meshes. - Do heavy Python work once, at the start, and keep the results.
Keyboard focus
Key presses go to the preview only after you click or tap it. If the arrow keys do nothing, click the preview first.
Libraries
You can import the usual Python libraries. On iPhone and iPad your file runs on Circuitry's built-in Python when the libraries it imports are included (numpy, matplotlib and Pillow are). In the desktop app, Circuit runs the same built-in Python, with pandas and scipy as well. Anything else runs on the Python inside the page, which has a large set of common libraries and loads them the first time a file imports them. Numbers from numpy can be passed straight to drawing calls.
Files
To read and save files next to your script, such as data, settings or a high score, put import files at the top. See Using your files.