DEV Community

Hasan Aflatoon
Hasan Aflatoon

Posted on

I Built a Python IDE That Runs Entirely in Your Browser Using WebAssembly

I Built a Python IDE That Runs Entirely in Your Browser Using WebAssembly

"Your Browser. Your Rules. Your Python."

If you've ever thought "I just want to run this one Python snippet" and then spent the next 15 minutes arguing with your environment instead β€” this post is for you.

I built PythCode: a browser-native Python playground that runs CPython 3.11 directly inside your browser tab using WebAssembly. No install. No server. No account. No code leaves your machine.

Let me walk you through what I built, how it works under the hood, and some of the tricky technical problems I had to solve along the way.


🐍 What Is PythCode?

PythCode is a single-page application that gives you a full Python development environment inside your browser. It looks and feels like a lightweight IDE β€” syntax highlighting, line numbers, error detection, a console with coloured output, and even interactive plots.

The key difference from most browser-based Python tools: everything executes locally. Your Python code never leaves your device.

Here's what the stack looks like from 10,000 feet:

Browser Tab
β”œβ”€β”€ HTML/CSS/JS (no framework, no build step)
β”œβ”€β”€ Pyodide 0.25 (CPython 3.11 β†’ WebAssembly)
β”‚   β”œβ”€β”€ NumPy
β”‚   β”œβ”€β”€ Pandas
β”‚   β”œβ”€β”€ Matplotlib
β”‚   └── Seaborn (via micropip)
└── Custom editor engine
    β”œβ”€β”€ Syntax highlighter (vanilla JS)
    β”œβ”€β”€ Live error overlay
    └── Async input() bridge
Enter fullscreen mode Exit fullscreen mode

Link: PythCode: Unleash your Code!

✨ Features at a Glance

Before I get into the technical bits, here's a quick rundown of what PythCode can do:

  • Real Python 3.11 β€” not a transpiler, not a subset, actual CPython in WASM
  • NumPy, Pandas, Matplotlib, Seaborn preloaded and ready
  • Live syntax highlighting with per-token coloring
  • Red squiggly underlines on syntax errors as you type
  • input() that actually works β€” execution pauses, user types, execution resumes
  • Inline plot viewer β€” matplotlib/seaborn charts render inside a modal
  • Auto-saves to localStorage β€” code persists across sessions
  • Share via URL β€” code is base64-encoded into the link, no backend needed
  • Three themes β€” Tokyo Night, Dark, White
  • Zero tracking. Zero ads. Zero accounts.

Code is auto-saved with a 400ms debounce. Theme, font, and zoom levels are saved on change. Everything is restored synchronously on init() before Pyodide even starts loading β€” so the editor has your last session visible before the Python runtime is ready.


πŸ€” Challenges and Lessons Learned

1. color: transparent kills text-decoration in Chromium.
The squiggly underlines simply didn't appear. Spent longer than I'd like to admit on this. Solution: rgba(0,0,0,0) instead of transparent.

2. run_sync doesn't exist in Pyodide 0.25.
Early versions of my async input() implementation used pyodide.ffi.run_sync, which doesn't exist in this version. The correct solution was the async def _run() wrapper combined with Pyodide's native runPythonAsync.

3. exec() returns values as Python proxies.
When I first ran user code with exec(user_code), the last expression's value would appear as [object Object] in the console because Pyodide returned a Python proxy. Wrapping everything in async def _run(): ... means the function returns None, and nothing unexpected appears in the output.

4. Seaborn isn't bundled in Pyodide.
loadPackage('seaborn') throws. The solution is micropip.install('seaborn', keep_going=True) β€” but this needs network access from inside WASM, which works in modern browsers but can fail in restrictive environments. I handle this gracefully: seaborn failing doesn't block the rest of the app from loading.


πŸš€ What's Next

  • Mobile layout β€” vertical split with a touch-friendly drag divider
  • File upload β€” drag a CSV directly into the Python environment
  • More libraries β€” SciPy, Sympy, Statsmodels
  • Code history β€” timeline of past runs per session
  • Export to Jupyter β€” download your code as a .ipynb

πŸ› οΈ The Stack Summary

Thing How
Python runtime Pyodide 0.25 (CPython 3.11 β†’ WASM)
UI framework None (vanilla HTML/CSS/JS)
Syntax highlighting Custom tokeniser, ~150 lines of JS
Package manager micropip (for packages not bundled in Pyodide)
Storage localStorage only
Build step None β€” single .html file
Bundle size ~1.8 MB HTML + Pyodide loads on demand

Final Thoughts

PythCode started as a solution to my own frustration. It turned into a genuinely interesting engineering challenge β€” threading together WebAssembly, async JavaScript, Python coroutines, and CSS rendering quirks into something that just feels like an IDE.

The thing I'm most proud of isn't any individual feature. It's that the whole thing is a single HTML file you can save to your desktop and open offline, and it still works.

If you try it, I'd love to hear what you think β€” especially if you break something.


Built by **Hasan Aflatoon**

Tags: python webassembly opensource programming javascript tutorial devtools

Top comments (9)

Collapse
Β 
embernoglow profile image
EmberNoGlow β€’

link?!

Collapse
Β 
hasan_53_52 profile image
Hasan Aflatoon β€’ β€’ Edited

Link: PythCode
Currently it's PC only, Working on Mobile responsiveness.
Also feedbacks are appreciated!

Collapse
Β 
embernoglow profile image
EmberNoGlow β€’

Na, it takes too long to load. I'd suggest adding a loading bar or at least console logging. I don't know, but I think downloading Python itself to your computer would be faster than that, not to mention the ability to use Github Codespaces.

Thread Thread
Β 
hasan_53_52 profile image
Hasan Aflatoon β€’

The first code takes a while to load, then it works perfectly fine.

Thread Thread
Β 
embernoglow profile image
EmberNoGlow β€’

idk, 15 mins - no... don't working for me.

Thread Thread
Β 
hasan_53_52 profile image
Hasan Aflatoon β€’

Oh 15 mins?
Can you share your code?
I will look into it.

Thread Thread
Β 
embernoglow profile image
EmberNoGlow β€’

I'm talking about the fact that the site has been writing initializing python for 15 minutes, and apparently it's not working, no matter

Thread Thread
Β 
hasan_53_52 profile image
Hasan Aflatoon β€’

Can you help me out?
Its perfectly working for me

Thread Thread
Β 
vickrant_selvendran profile image
Vickrant Selvendran β€’

He is right but it's not bad as 15 mins. It took me around 1min. I do understand that initial time is always high but then your code editor itself has some major issues when it comes to "undo" and "redo". It's kinda glitchy and buggy where undo and redo aren't working as expected.

Thats what I have to say for using it for 5mins. Thank you!