Proof of concept of pyp5js running on top of pyodide #123
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #73
This PR adds the file
draft/index.html
as a working proof of concept of pyp5js running on top of pyodide instead of using transpiled javascript code by transcrypt. I'll be a little verbose in this PR because there's a lot of knowledge and assumptions on it. So, I want do document my approach with care so people can help on a future real integration between pyp5js + pyodide.The original code
As I said in the issue, I based this PR on @Luxapodular code (supported by COSA (The Clinic for Open Source Arts) at the University of Denver College of Arts and Sciences) where he was able to integrate p5.js with pyodide. His code was also a proof of concept and, because of that, it only supported a few methods from p5.js API, such as
square
,ellipse
etc and that's done via awrapper
variable, a string to hold the code to integrate p5.js + pyodide.On this code, he defined 2 functions to inject the python code into the p5 instance which holds the sketch. The first one, responsible to update p5.js variables, is called
updateVariable
and, the second one is thesketch
.This second function has 2 responsibilities: to inject python implementations of p5.js functions (
setup
,draw
and event handlers such askeyPressed
) and to expose the p5.js API as Python callables (arc
,rect
,ellipse
etc)The wrapper ends with the initialization of a p5 sketch which is stored in the global JS
window
. The initialization gets thesketch
function the same way as the docs does withconst s
.Finally, the sketch is executed in the
runCode
function where the final code is a combination from the real sketch code plus the wrapper one and it is passed to apyodide.runPython
call.The pyp5js wrapper
This PR is strongly based on @Luxapodular high-level approach of concatenating the sketch code with the wrapper code and then passing it to be executed by pyodide. The differences relies on how pyp5js implements the wrapper and how it initializes the sketch and they exist because of how pyp5js was initially designed to be integrated with Transcrypt. All of the pyp5js' wrapper logic is implemented in
pyp5js/pyp5js.py
.The most important thing to notice is that
pyp5js
holds a global variable for the current p5 sketch instance and, due to complexities on howTranscrypt
deals with global variables, the code is a little bit confusing, I know. But, the entrypoint for pyp5js is thestart_p5
mehotd which receives 3 parameters: asetup
implementation, adraw
implementation and a dictionary with implementation for the event functions.This function implements a inner method called
sketch_setup
which has the same purpose of enabling the Python code from accessing the sketch's variables (more precisely via thepre_draw
method). The p5.js API is already enabled because pyp5js implements proxy methods to the global p5 instance variables.So the
sketch_setup
uses Transcrytp's__new__
function to initialize a new p5.js Sjetch and then it iterates through the event functions dictionary to inject the respective implementations as the function handlers.Integrating pyp5js with pyodide
My main goal was to, without introducing to many changes to this architecture, use the same code with pyodide. For the proof of concept, I've used the same code from pyp5js' example 001:
And I was able to do so with the following steps:
wrapper
variable to hold the sketch code + all the code frompyp5js/pyp5js.py
;__new__
method from Transcrypt and, instead, directly call thep5()
;start_p5(setup, draw, {})
;Running the example
You'll have to follow this:
cd draft
;python -m http.sever
http://localhost:8000
on your browser and open the console;Python initialization complete
be printed on your console output);runCode()
Results
The sketch worked from the very first try and this proves that the way pyp5js wraps p5.js to Python with Transcrypt will also work with pyodide with minor changes.
The downside comes to the performance. While the same sketch with the Transcrypt version was running on an average of 60 fps on my computer, the pyodide version was on 35~30fps.
Although this is a performance issue, I don't think it's a blocker for integrating pyodide with pyp5js because of the many issues Transcrypt also have when it comes to fully supporting a Python syntax.
So the next step is to open an issue proposing the integration of pyodide with pyp5js =)