A Multi-Runtime, Browser-Native IDE for Code Education and Creative Development
CodeScapes is an A zero-setup, browser-based playground for learning, teaching and sharing code.
Before diving into architecture, let's establish what "works" means in practice. These are real programs running in the browser, unchanged from their desktop versions.
Pong: Two-player game with keyboard controls (W/S and Arrow keys), ball physics, paddle collision detection and live scoring.
Brick Breaker: Paddle-controlled ball bouncing through destructible bricks. Requires onkeypress(), collision detection, and tracer(0)/update() for smooth animation.
Both games use the standard game loop pattern:
- Disable automatic screen updates with
tracer(0) - Process input events
- Update game state
- Redraw everything
- Call
update()to display the frame - Sleep briefly to control framerate
This pattern requires blocking operations, event handling and flicker-free rendering, all of which fail in browser-based Python environments like Skulpt, Brython, and previous Pyodide turtle implementations.
Animated Spirograph: A spiral that rotates continuously in real-time.
GIF only shows 15 fps, view original project at https://www.codescapes.io/view/71622718-fe46-4c80-a27c-d172585ce6c0
Pattern Playlist: Distinct geometric patterns (spirographs, mandalas, kaleidoscopes) cycling automatically with one-second intervals.
These demonstrate sustained animation loops with time.sleep() for pacing. This is another operation that typically breaks in Pyodide without special handling.
3D Spiral with Mouse Control: A golden spiral rendered in 3D space. Click and drag to rotate the view around the Y-axis.
This example combines onscreenclick(), onrelease(), and ondrag() for continuous position updates. The full mouse event API working correctly is rare in browser implementations.
Live Weather Dashboard: A three-file application that prompts for a city name, fetches weather data from an API and displays results using turtle graphics as the UI layer.
This demonstrates Python's input() function working correctly, blocking execution until the user responds without freezing the browser—a critical feature for educational scripts.
![]() |
![]() |
| View Project | View Project |
![]() |
![]() |
| View Project | View Project |
The fundamental challenge of running Turtle in the browser is the mismatch between Python's synchronous, blocking execution model and the browser's asynchronous, event-driven nature.
In Python, time.sleep(1) blocks the thread. In the browser's main thread, blocking freezes the UI. To solve this, we run Pyodide in a Web Worker, isolating it from the UI thread. However, the Worker cannot access the DOM or Canvas directly.
Our solution bridges these two worlds through a message-passing protocol.
- Python (Web Worker): Runs the user's code. We shim the
turtlemodule to capture commands (e.g.,forward,penup) and send them to the main thread. It maintains its own internal state so queries likexcor()return immediately. - Renderer (Main Thread): A React component that receives commands and updates the HTML5 Canvas.
- Synchronization: The Worker waits for the Renderer when necessary (e.g., during
sleeporinput), ensuring the timing matches the user's expectations.
Flicker-free animation is critical for games. We improved upon standard canvas drawing by implementing a double-buffered rendering pipeline.
We maintain multiple off-screen canvases:
- Background Buffer: For static background colors or images.
- Ink Buffer: For permanent drawings (lines, stamps, fills).
- Sprite Buffer: For moving turtles.
When running animations with tracer(0), we draw to these off-screen buffers and only composite them to the visible display when update() is called. This eliminates the flickering often seen in other implementations where every single drawing command triggers a repaint.
Perhaps the most interesting technical challenge was handling synchronous events. How do you implement a blocking input() or wait for a keypress in a Web Worker without freezing the browser?
We use a Service Worker combined with synchronous XHR.
- Python needs to wait for an event (like a keypress).
- It makes a Synchronous XHR request to a special URL intercepted by our Service Worker.
- This blocks the Worker thread (pausing execution), which is exactly what we want.
- The Main Thread continues to run, listening for user input (keyboard/mouse).
- When input occurs, the Main Thread sends the data to the Service Worker.
- The Service Worker responds to the pending XHR request, unblocking the Python Worker.
This allows Python to feel "blocked" while the browser UI remains completely responsive.
This implementation demonstrates that we don't have to compromise on the educational integrity of Python when bringing it to the browser. By staying true to the CPython execution model, we empower students to use standard learning resources and build real, improved applications.
None of this would be possible without Pyodide. This turtle shim runs directly in the browser on Pyodide.
This software is licensed for NON-COMMERCIAL use only.
You may:
- Use this software for personal, educational, or research purposes
- Modify and fork the code for non-commercial projects
- Reference this architecture in academic papers (with attribution)
You may NOT:
- Use this software or derivatives in commercial products
- Sell or monetize applications built with this codebase
- Deploy this software as a paid service
For commercial licensing inquiries, please contact:
We welcome contributions from the open-source community! Whether you're interested in:
- Adding new runtime environments
- Improving the execution sandbox
- Enhancing the block-based FlowScape editor
- Documentation and research papers
Get in touch:











