A browser-based Python IDE that runs entirely client-side — no server, no installation, no Python runtime required on the host machine. Built for use in Further Education classrooms where students need an immediate, zero-friction Python environment.
| Feature | Details |
|---|---|
| Monaco Editor | VS Code-quality editor with Python syntax highlighting, bracket colouring, and autocompletion |
| Pyodide (CPython in WASM) | Full CPython 3.x interpreter compiled to WebAssembly — code runs in the browser tab |
| Multi-file Workspace | VS Code-style file tabs; add .py, .csv, and .json files alongside the main script |
| ZIP Load / Save | Load a ZIP to restore a full project; Save bundles all workspace files into a ZIP automatically |
| Module & Data File Support | All workspace files are written to /workspace/ before each run — import helpers and open('data.csv') work out of the box |
| Turtle Graphics | Custom canvas-based turtle backend; import turtle works out of the box |
| Matplotlib | Charts rendered to PNG and displayed in the Graphics tab after plt.show() |
| Package Manager | One-click install of scientific packages (NumPy, Pandas, SciPy, scikit-learn, and more) via micropip |
| Auto-install on Load | Opening a .py file automatically detects and installs any required curated packages |
input() modal |
Python's input() opens a styled modal dialog; no native browser prompt |
| Tabbed output | Separate Console and Graphics tabs; auto-switches to Graphics when turtle or matplotlib output is produced |
| Algorithms Drawer | Sliding reference panel with searchable index and full-detail modal for each algorithm, from The Little Book of Algorithms 2.0 by William Lau (CC BY-NC-SA 4.0) |
| Playground Reset | One-click reset clears all workspace files, restores Hello World, and fully reinitialises the Python environment |
- React 19 + Vite 8 — UI framework and build tool
- @monaco-editor/react — Monaco Editor integration
- Pyodide 0.26.4 — CPython compiled to WebAssembly (loaded from CDN)
- JSZip — ZIP archive creation and extraction
- HTML5 Canvas API — Turtle graphics rendering
- Node.js 18 or later
- npm (bundled with Node.js)
# Clone or download the repository
git clone <repo-url>
cd pythonPlayground
# Install dependencies
npm installnpm run devOpen http://localhost:5173 in a browser. The first page load downloads the Pyodide WASM bundle (~10 MB) from the jsDelivr CDN; subsequent loads use the browser cache.
npm run build
# Output is in the dist/ folder — serve as a static site
npm run preview # preview the production build locallyWrite Python in the editor and click ▶ Run or press Ctrl+Enter.
turtle is always available — no installation needed:
import turtle
t = turtle.Turtle()
for _ in range(4):
t.forward(100)
t.right(90)Output appears in the Graphics tab automatically. The turtle canvas is hidden until drawing commands are issued.
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4])
plt.title("My Chart")
plt.show()The chart is rendered to PNG and shown in the Graphics tab. Install Matplotlib first via 📦 Packages if it is not already loaded.
Click 📦 Packages in the toolbar and select the packages your program needs. Packages are downloaded once per browser session. When a .py file is loaded from disk, any recognised imports are installed automatically.
The editor supports multiple files simultaneously via a VS Code-style tab bar directly above the editor:
+button — opens a file picker to add a.py,.csv, or.jsonfile to the workspace without replacing existing files.- 📂 Load — loads a single file or a ZIP archive. A ZIP unpacks all its text files into the workspace at once.
- 💾 Save — with one file open saves as
.py; with multiple files open prompts for a project name and downloads a.zipcontaining every workspace file. - Closing a tab — click the
×on any tab to remove that file from the workspace (only available when two or more files are open).
All workspace files are written to /workspace/ in Pyodide's virtual filesystem before each run and the working directory is set to /workspace/. This means:
# Import another .py file from the workspace
import helpers # if helpers.py is open in a tab
# Read a CSV or JSON data file from the workspace
import pandas as pd
df = pd.read_csv('students.csv') # if students.csv is open in a tabAny curated packages required by loaded .py files are installed automatically.
Python's input() opens a styled modal dialog pre-filled with the prompt text from your program. Type a value and press OK (or Enter) to continue; Cancel returns an empty string. Standard Python code works unchanged — no await keywords required in student scripts.
Click 📚 Algorithm Challenges in the toolbar to open a sliding drawer containing teaching examples and student challenges drawn from The Little Book of Algorithms 2.0 by William Lau (CC BY-NC-SA 4.0). Each entry includes:
- A description and teaching notes
- Annotated example code
- One or more challenges with starter code
Click Load into Editor → on any example or challenge to transfer the code directly into the editor. Use the search box or category filter chips to navigate the content.
Click 🔄 Reset to restore the Hello World starter code and fully reinitialise the Python environment. All installed packages are removed and Pyodide is restarted (the WASM bundle is browser-cached so reinitialisation takes only a few seconds).
src/
App.jsx # Root component — layout, workspace state, and modal wiring
App.css # Application styles
components/
Toolbar.jsx # Run / Load / Save / Packages / Reset / Algorithms bar
FileTabs.jsx # VS Code-style workspace file tab bar
CodeEditor.jsx # Monaco editor wrapper (language-aware)
OutputPanel.jsx # Tabbed Console + Graphics output panel
LibraryManager.jsx # Package installation modal
SaveAsModal.jsx # Save As filename dialog (single file or ZIP)
ConfirmModal.jsx # Generic confirmation dialog (used by Reset)
InputModal.jsx # Modal dialog for Python input() calls
AlgorithmsDrawer.jsx # Algorithms index drawer + full detail modal
cmFloatAd.jsx # College branding component
hooks/
usePyodide.js # React hook managing the Pyodide instance
utils/
turtleApi.js # Canvas-based turtle graphics backend
fileHandling.js # Multi-file load / ZIP save helpers (JSZip)
packages.js # Curated package list + auto-detect helpers
algorithms.js # Algorithm data (William Lau CC BY-NC-SA 4.0)
public/
py_modules/
turtle.py # Python turtle module (calls JS canvas API via Pyodide bridge)
scripts/
test_builtins.py # Standard library functionality test
test_turtle.py # Turtle graphics test
test_matplotlib.py # Matplotlib chart rendering test
test_numpy.py # NumPy test
test_pandas.py # Pandas test
test_scipy.py # SciPy test
test_sklearn.py # scikit-learn test
test_sympy.py # SymPy test
test_networkx.py # NetworkX test
test_pillow.py # Pillow image processing test
test_openpyxl.py # OpenPyXL in-memory workbook test
demo_csv_pandas.py # Multi-file workspace demo — reads students.csv with Pandas
students.csv # Sample dataset used by demo_csv_pandas.py
The turtle implementation is a two-layer canvas architecture:
- Offscreen canvas — permanent strokes are drawn here so they persist across frames.
- Visible canvas — composites the offscreen drawing and the live turtle cursor on every update.
turtle.py (in public/py_modules/) is a Python module injected into Pyodide's virtual filesystem. It calls JavaScript functions (window._turtle_draw_line, window._turtle_update_turtle, etc.) via Pyodide's JS bridge. This means full Python turtle semantics work without any server-side rendering.
The turtle canvas is hidden when no drawing has taken place in the current run, so matplotlib-only scripts do not show an empty canvas above their charts.
Matplotlib is configured to use the Agg (non-GUI) backend via os.environ['MPLBACKEND'] = 'Agg' at Pyodide initialisation time. Before each run, plt.show() is replaced with a capture function that saves every open figure to a base64-encoded PNG buffer. After the run, any figures not explicitly shown are also captured. The resulting images are passed back to React and rendered in the Graphics tab.
The return value from Pyodide's runPythonAsync is only captured when the last top-level statement in the code string is a bare expression — not a try/except block. All harvest code is structured accordingly.
| Package | Import name | Category |
|---|---|---|
| NumPy | numpy |
Science |
| Pandas | pandas |
Science |
| Matplotlib | matplotlib |
Science |
| SciPy | scipy |
Science |
| scikit-learn | sklearn |
Science |
| NetworkX | networkx |
Science |
| SymPy | sympy |
Maths |
| OpenPyXL | openpyxl |
Data |
| Pillow | PIL |
Media |
Additional packages can be installed via micropip if not listed above.
File I/O in the workspace: Upload
.csvor.jsonfiles using the+tab button. They are written to/workspace/before each run, soopen('data.csv')works without any path prefix. OpenPyXL scripts that need to create.xlsxfiles should useio.BytesIOfor in-memory workbooks rather than writing to disk. Pillow images should be displayed via Matplotlib rather than saved to disk.
npm run lintUses ESLint with the eslint-plugin-react-hooks and eslint-plugin-react-refresh plugins.
New features
- Multi-file workspace — VS Code-style file tab bar above the editor. Students can open multiple
.py,.csv, and.jsonfiles simultaneously. The+button adds a file without replacing the current workspace; individual tabs can be closed when no longer needed. - ZIP load / save — loading a
.zipfile unpacks all text files into the workspace in one step. Saving with multiple files open prompts for a project name and downloads a single.ziparchive containing every workspace file (powered by JSZip). - Module and data file support — all workspace files are written to
/workspace/in Pyodide's MEMFS before each run;/workspace/is added tosys.pathand set as the working directory. Students can writeimport helpersoropen('data.csv')using standard Python syntax with no extra setup. input()modal — Python'sinput()now opens a styled React modal dialog instead of the browser's nativewindow.prompt(). An AST transformer automatically rewritesinput(...)calls toawait input(...)in user code, and promotes any student-defined function containing aninput()call toasync def, so standard Python code works unchanged.- Algorithms drawer redesign — replaced the accordion pattern with a master-detail layout: the drawer shows a compact searchable index; clicking any entry opens a full-width modal displaying the complete description, teaching notes, example code, and all challenges without any hidden scrolling.
- Demo scripts —
demo_csv_pandas.pyandstudents.csvadded topublic/scripts/demonstrating the multi-file workspace with a full Pandas analysis and Matplotlib visualisation.
Changes
SaveAsModalno longer forces a.pyextension — extension handling moved toApp.jsxso both.py(single file) and.zip(multi-file) cases are handled correctly.CodeEditoraccepts alanguageprop so.jsonand plain-text files render with appropriate Monaco syntax highlighting.- Reset now clears all workspace files in addition to reinstalling Pyodide and removing packages.
New features
- Algorithms drawer — sliding right-hand panel containing teaching examples and challenges from The Little Book of Algorithms 2.0 by William Lau (CC BY-NC-SA 4.0). Includes search, category filter chips, expandable cards with teaching notes, annotated code, and student challenges. Code loads directly into the editor.
- Save As modal — replaces the browser
prompt()with a proper dialog; pre-fills the current filename with the stem selected for easy overtyping; appends.pyautomatically. - Playground Reset — confirmation modal then full Pyodide reinitialisation, clearing all installed packages and restoring the Hello World starter.
- Auto-install on file load — detects
importstatements in a loaded.pyfile, cross-references the curated package list, and installs any missing packages automatically. Run is disabled until installation completes; progress is shown in the toolbar. turtle.window_width()/turtle.window_height()— added to the custom turtle module andScreenclass.- Test scripts — eleven
.pyscripts inpublic/scripts/covering every curated library and the Python standard library.
Bug fixes
- Matplotlib graphics not rendering — two root causes fixed: (1) the Agg backend was not being set when Matplotlib was installed after Pyodide initialised; resolved by setting
os.environ['MPLBACKEND'] = 'Agg'at startup. (2)plt.show()with Agg closes figures before the post-run harvest; resolved by patchingplt.showbefore each run to capture figures at call time. (3) Pyodide'srunPythonAsynconly returns a value when the last top-level statement is a bare expression — harvest code restructured accordingly. - Turtle canvas always visible — canvas wrapper is now hidden when no turtle drawing occurred in the current run.
- Bokeh removed — Bokeh requires a live server or Selenium for PNG export, neither of which is available in a browser Pyodide environment; removed from the curated package list.
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International — see LICENCE.
© 2026 Simon Rundell