Deploy JavaScript Application Using Pyjsdl

The Pyjsdl module is modelled on Pygame/SDL methods that wraps JavaScript functionality including HTML5 canvas. The module permits scripts coded in Python/Pygame to compile to JavaScript using the Pyjs compiler, allowing deployment of JavaScript applications without extensive editing of the script.

The following JavaScript application was deployed using Pyjsdl:

Pyjsdl Demo
The demo was compiled to JavaScript from a script coded in Python programming language and the Pyjsdl module.

For an example, download the Python script used to compile this application, which was derived from the Serpent Duel program in Interphase Pack. This post describes the steps required to deploy an application under the Linux environment, which should provide the fundamentals for other OS environments.

To compile the script, download the Pyjsdl module and unpack into the script folder, or on the module path. A Python script requires some modification to work with Pyjsdl and to be compatible with the JavaScript. To import the Pyjsdl module, add the following statement to the script:


import pyjsdl as pygame

The statement imports the pyjsdl module and renames it pygame to maintain the validity of the Pygame statements. To adapt the script for browser compatibility, the following statement is necessary:


pyjsdl.display.setup(run, images)

The statement takes a run argument and an optional images argument, which provides the browser with a 'run' function to execute and 'images' list to preload. The importance of this statement is due to the nature of Python scripts that usually execute repetitively from a loop statement in a main function, not possible in JavaScript since the browser is single-threaded and must have its own time to do browser routines such as display update and event processing, any continuous loop would lock the browser. Place commands to be repeated for program execution in a function, for instance 'run' function, and this function is passed to the browser to call repeatedly in a time-based manner. The preloading of images is preferred since the browser will not wait until images are downloaded, once images are retrieved the application proceeds.

Other script changes required are for Pygame methods not supported by the Pyjsdl module, check the API documentation. Additional changes may be required in Python code to work with Pyjs depending on compilation mode, or code changes that are compatible to JavaScript language structure.

To compile a Python script to JavaScript, setup a Pyjs development environment. Download Pyjs, the latest update is at Pyjs git repository and follow the installation instructions - to install git build_13-06-12, unpack in a preferred folder and run 'python bootstrap.py'. Pyjs compiles JavaScript code with inclusion of browser-specific code, tests passed for the available Pyjs version with Pyjsdl to compile for the released version of Firefox, check txt file in the Pyjsdl folder for any changes that may be required for other browsers. Pyjsdl requires browsers with HTML5 canvas functionality that is supported by newer browsers. To get information on the JavaScript-compiled script, the browser needs some JavaScript tools such as browser console, check Pyjs developing information – for instance for Firefox browser the plugins Firebug and Web Developer are useful. Another tool that can be used prior to Pyjs compilation is Pyflakes that checks Python syntax.

To compile script.py, enter the following in a command terminal:


[pyjs path]/bin/pyjsbuild script.py

This command will output compiled script. Pyjs can compile in different modes as described in Pyjs guide, for instance debug mode (-d) provides Python error messages required in program development, strict mode (-S) compiles most Python syntax, and optimized mode (-O) compiles Python omitting some language constructs for smaller JavaScript code with increased performance. The optimized mode restricted Python recognition may require further changes to the script, so preferable to develop in strict mode, and make required changes for optimized mode at a later stage of development. Other useful compiling options are --enable-print-statements to enable console print output, -P that can provide list of browsers (for instance Mozilla) targeted by Pyjs, -o to choose compiling output folder, and --dynamic-link to separate Pyjs compilation of JavaScript from Html file. A couple of examples with debug -d option enabled:


pyjsbuild -S -d script.py -P Mozilla
pyjsbuild -O -d script.py --enable-print-statements -o outputdir

Pyjs compiles only code that it detects has been modified since last called, and noticed that if Pyjs compilation mode is changed, the compiled code in the output folder should be removed or choose a different output folder. The output folder will contain script.html that can be run in the browser. The script.html that is compiled runs without change in the Firefox browser.

For site deployment, script.html may need some editing such as addition of the line at the beginning of the Html file required for some browsers, and possibly other html/style changes. For possible changes to script.html, examine the demo script archive for changes made for its deployment. For deployment, my preference is to use the following compilation command:


pyjsbuild -O script.py --dynamic-link

The --dynamic-link option separates JavaScript files in the lib folder with links from the Html files, not only reducing the application size but also allowing for sharing of Pyjs/Pyjdl JavaScript files between multiple applications. For further reduction in size of the application, before deployment the JavaScript code can be compressed with YUI Compressor with the following command executed in output lib folder:


yui-compressor -o '.js$:.js' *.js

The compressed JavaScript files will replace the original. The output folder containing Html files and linked JavaScript files in the lib folder, along with images folder containing any images, can be deployed online.

For deployment of a Pyjsdl application on a website, the following Html code can be used:


<div id="app">
<div id="pyjsdl_demo" title="App: Pyjsdl Demo"
class="jsapp_box">
<input type='button' value='Launch'
onClick='appLauncher("pyjsdl_demo")'/>
<div class="app_title">Pyjsdl Demo</div>
</div>
</div>

This code asserts a placeholder for the application on the webpage, which is within a div section with id the application name pyjsdl_demo, with a button that calls the JavaScript function appLauncher with the application id argument to launch the application, edit this name to your application. The JavaScript function code follows:


<script type="text/javascript">
function appLauncher(app) {
var appSource = "http://website.com/apps/" + app + ".html";
document.getElementById(app).innerHTML = '<pre><iframe id=' +
app + ' name=' + app + ' src=' + appSource +
'></iframe></pre>';
}
</script>

When the JavaScript function appLauncher is called from a webpage, it replaces the webpage div having the given id with an iframe containing the Pyjsdl application, adapt to your application configuration. Place this JavaScript function in an accessible location on the website, such as the webpage header or with other JavaScript functions. Further details can be found in the txt file in demo script archive. With this procedure, your Python script using the Pyjsdl module can be deployed as a JavaScript application.

This entry was posted in Programming and tagged , , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

26 Comments

  1. Ben
    Posted 2016/05/25 at 16:50 | Permalink

    Hi Jim,

    After my struggles, I have tried to create a clear guide about all this pyjsdl and pyjs stuff.
    I hope it can be useful to others.

    http://bearums.github.io/blocky/BlockyPyjsdl.html

    Thanks,

    Ben

    • Posted 2016/05/26 at 23:32 | Permalink

      Thanks for contributing your link.

  2. Ben
    Posted 2016/05/03 at 13:33 | Permalink

    I've put the pyjsdl folder into the Anaconda site-packages directory with all the other modules but when I run import pyjsdl it comes up with error;

    from display import Display
    ImportError: cannot import name 'Display'

    Where exactly are the pyjsdl files meant to go? I'm struggling to see why it won't import Display.

    Thanks

    Ben

    • Posted 2016/05/03 at 15:31 | Permalink

      The pyjsdl module should be on the path recognized by the pyjs translator, not on the python interpreter path. Place pyjsdl folder or symlink in your app folder. Alternatively, place pyjsdl in a folder on the pyjs path, which can be done with the pyjsbuild ––search-path commandline option:

      pyjsbuild script.py ––search-path=<LIB_PATH>

      • Ben
        Posted 2016/05/08 at 05:46 | Permalink

        Thanks a lot! Am battling through it. I have installed pyjs and it works correctly with the pyjs examples that they give. However when I try to import pyjsdl as pygame, I am getting an error that there is no module named pyjamas. As far as I can find pyjamas and pyjs are the same. Is this a common issue?

        Ben

        • Posted 2016/05/08 at 14:28 | Permalink

          The pyjs package includes the pyjamas module that codes wrappers for browser elements such as the HTML5 canvas element imported by pyjsdl, the error indicates that the path to pyjamas is not found. I have seen this error reported if the app using pyjsdl is run with python, the proper procedure is to use pyjsbuild to translate the pyjsdl app. If the error is being reported with pyjsbuild, perhaps pyjamas located in the pyjswidgets folder is not on the PYJSPATH. Running pyjsbuild displays the PYJSPATH in the terminal, ensure the pyjswidgets folder is in the path. Hope this resolves the issue.

          • Ben
            Posted 2016/05/09 at 12:58 | Permalink

            Thanks Jim!

          • ben
            Posted 2016/05/09 at 14:03 | Permalink

            I am almost there I think! I can build the serpent duel app fine and it all works. However when I pyjsbuild my own scripts, I get the error

            example TypeError: $m.pyjsdl is undefined

            in the browser when I open the .html.

            I'm not sure why this occuring. The pyjsdl module is definitely on the pyjs path, as you described earlier.

            I have imported pyjsdl as pygame and added the line
            pyjsdl.display.setup(run, images). But I notice the serpent duel app does not have this line?

            Sorry to be a pain. When I have it all working I hope to write a guide so similar fools will not be tricked as I have!

          • ben
            Posted 2016/05/09 at 14:23 | Permalink

            Ignore all that, I've worked it out!

          • Posted 2016/05/09 at 15:04 | Permalink

            Glad it worked. For others with a similar issue, the statement 'import pyjsdl as pygame' necessitates the use of pygame alias in subsequent pyjsdl method statements.

  3. thrall6000
    Posted 2016/01/25 at 22:31 | Permalink

    Apologies, I posted a comment earlier, but no longer see it.

    I have restructured a python script I wrote with pygame to be compatible with pyjs/pyjsdl using your helpful guides.

    I've have overcome a few issues, but now I'm stuck on an unusual error. Opening my html in firefox gives me "TypeError: self.canvas is undefined". In IE/EDGE it gives me "TypeError: Unable to get property 'set_function' of undefined or null reference. In chrome I see "TypeError: Cannot read property set_function of undefined". Any idea what's going on?

    • Posted 2016/01/25 at 23:22 | Permalink

      This issue indicates that canvas was not initiated. Make sure to use display.set_mode to initiated canvas before calling display.setup. Other than that suggestion, I will need further information to assist with the issue.

      If you have not done so already, I would also suggest doing some tests with the demo apps as described in the Guide to Pyjs and Pyjsdl post.

      • thrall6000
        Posted 2016/01/26 at 22:41 | Permalink

        Thanks, man. That was exactly it! I confused myself after having to completely rearrange the startup of my game to make it compatible with pyjsdl and the browser.

        • Posted 2016/01/26 at 23:26 | Permalink

          You're welcome.

  4. Posted 2014/08/28 at 13:03 | Permalink

    Thanks a lot for this article.
    Managed to use it to mock up a few demo apps that I've put up here http://pyjsdl-test1.herokuapp.com/

    • Posted 2014/08/28 at 20:33 | Permalink

      That's great, appreciate the link to your apps.

      • Posted 2014/08/29 at 09:15 | Permalink

        No sweat, I'll try to get a collection of different ones up on the heroku instance here http://pyjsdl-test1.herokuapp.com/ and eventually some step by step guides/explanations.

        Bumped into some folk who think the pyJSdl is really neat and want to start using it.

        • Posted 2014/08/29 at 20:31 | Permalink

          Thanks for the info. Your demo apps and any guides will be helpful as the Python to JavaScript process can seem intimidating.

  5. dave
    Posted 2014/08/06 at 08:49 | Permalink

    Hi Jim

    This is really awesome work you did. I'm trying to recompile various simulation / graphical code I've written in pygame into javascript using your setup.

    I've managed to compile your serpent game into the javascript package that runs in Safari, but it doesn't run in Chrome for some reason. Have you had this issue before? I even deliberately used the exact version of pyjs you specified above. Is it because the pyjs compiler only generates target files that only work in mozilla/opera/IE/Safari, but not Chrome? I'm wondering how your version works in Chrome.

    Many thanks

    David

    • Posted 2014/08/06 at 16:19 | Permalink

      Thanks for your interest. Pyjs compiles for the Chrome browser. The demo on this webserver worked in my test with Chrome under Win7 and Chromium under Linux. The demo script also ran using the current Pyjs build to compile. An issue experienced with Chrome is that it restricts local applications, which can be overridden by launching Chrome with the command: chrome --allow-file-access-from-files. Hope this addresses the issue.

      • dave
        Posted 2014/08/06 at 17:27 | Permalink

        You're the man, Jim! That worked!

        I use a mac, so ended up relaunching chrome in that mode with command

        open -a "Google Chrome" --args --allow-file-access-from-files

        Thanks

        Dave

        • Posted 2014/08/06 at 19:40 | Permalink

          You're welcome, Dave. Glad it worked.

  6. zero
    Posted 2014/06/03 at 18:45 | Permalink

    It's amazing. Could you give some simple example? How to preload images and how to load preloaded images?
    pyjsdl.display.setup(run,images) ---> pygame.image.load()
    I tried , but i realy don't understand.

    • Posted 2014/06/04 at 14:12 | Permalink

      The pygame.image.load method cannot work in browsers since JavaScript code cannot wait until the browser download the image. The preload function allows the browser to download the images into memory with callback function that launches the 'run' function provided, and the pygame.image.load links to these loaded images. The current version of the Pyjsdl module requires image preloading to occur before any call to load or manipulate images, which may require a little restructuring of the code.

      The revised demo script that uses images can be downloaded, check the included guide.txt for further information. This demo script can run on the desktop with Python and Pygame module, in JVM with Jython and PyJ2D module, and in the browser with Pyjs compilation and Pyjsdl module.

      Hope this information is helpful.

  7. Brendan
    Posted 2014/05/02 at 20:41 | Permalink

    Oh my god, this is awesome. Ludum Dare games tend to do better when you can run them in your browser, and this library could let me do just that while staying in my Python comfort zone.

    How much of pygame's functionality has been ported to javascript? In other words, if I port my pygame program to javascript, what percentage of the game is likely to be recognized by Pyjsdl?

    • Posted 2014/05/03 at 11:10 | Permalink

      Appreciate your interest. Agree it could have application in Ludum Dare, at least to create a browser demo of the pygame program. You can get an idea of the functionality from the API documentation linked off the pyjsdl project page. Also check the demo code link on this page. I usually get my program to run with the pyj2d module that has similar functionality but can easily run the script direct with Jython, once necessary modifications are made it is easier to transfer to work with pyjsdl. Most of my pygame programs can function using the pyjsdl module following compilation to javascript with Pyjs. Issues are lack of audio that I am currently coding, and performance that I plan to direct my focus.