Is there a way to use pygame in Panel?

Would be cool to create games in Panel!

I think that for any game to perform in the browser it needs to run inside the browser. The next question is really if you want to code the game in python or js. If its Python then probably your best option is to find a python game framework that works on pyodide or use PyScript with a js game engine.

According to my google searches pygame has not been ported to pyodide as of 2023-06-11. But there it can run on something called pybag.

You could also search for python game engines that can run on pyodide. For example pyxel, enpyre

To get that working with Panel my approach would be creating a ReactiveHTML component. Alternatively panel convert your Panel application to pyodide.

You can also look at how game development has been described in Jupyter Games. Ipycanvas

Here is a proof of concept with PIXI JS.

We create a new Panel component called PixiJS. The component will let you provide an object which is the python code implementing the game.

The code in the object can refer to the

  • PIXI: the PIXI js object
  • app: A PIXI app that has already been created and shown in the component.
  • data, state, model, view: The values exposed by reactive html

The component is built using Panels ReactiveHTML and pyodide.

pixi

The code looks like.

import param
import panel as pn
from panel.reactive import ReactiveHTML

pn.extension()

RENDER_SCRIPT = """
async function main(){
    let pyodide = await loadPyodide();
    
    app = new PIXI.Application({
        "autoResize": true,
    })
    canvas.appendChild(app.view)
    resize = ()=>{app.renderer.resize(canvas.offsetWidth, canvas.offsetHeight)}
    addEventListener("resize", resize);
    resize()
    state.app=app
    window._panel_pixie_objects = {
        "canvas": canvas,
        "app": app,
        "data": data,
        "state": state,
        "model": model,
        "view": view,
        "state": state,
    }
    import_panel_pixie_objects = `
from js import _panel_pixie_objects, PIXI
canvas = _panel_pixie_objects.canvas
app = _panel_pixie_objects.app
data = _panel_pixie_objects.data
state=_panel_pixie_objects.state
model=_panel_pixie_objects.model
`
    script = import_panel_pixie_objects + data.object
    pyodide.runPython(script);
}
main();
"""

TEMPLATE = f"""
<div id="canvas" style="height:100%;width:100%;overflow:hidden"></div>
"""

class PixiJS(ReactiveHTML):
    object = param.String()
    
    js_to_py_event = param.Parameter()
    py_to_js_event = param.Parameter()
    
    _template = TEMPLATE

    __javascript__=[
        "https://pixijs.download/release/pixi.js",
        "https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"
    ]

    _scripts = {
        "render": RENDER_SCRIPT
    }


GAME_SCRIPT = """
from js import document, console, Object, window
from pyodide.ffi import create_proxy, to_js

import math
import random

sprite = PIXI.Sprite.from_("https://panel.holoviz.org/_images/logo_horizontal_light_theme.png")

app.stage.addChild(sprite);

elapsed = 0.0;
def update(delta):   
    global elapsed
    
    elapsed += delta
    
    py_event = data.py_to_js_event
    x=y=0
    if py_event:
        py_event=py_event.to_py()
        x=py_event.get("x", x)
        y=py_event.get("y", y)
    
    sprite.x = 100.0 + math.cos(elapsed/50.0) * 100.0 + x
    sprite.y = 100.0 + math.cos(elapsed/50.0) * 100.0 + y
    
    event = {"x": sprite.x, "y": sprite.y}
    event = to_js(event)
    event = Object.fromEntries(event)
    data.js_to_py_event=event

update_proxy = create_proxy(update)
app.ticker.add(update_proxy);
"""

game = PixiJS(object=GAME_SCRIPT, py_to_js_event={"x": 0, "y": 0}, sizing_mode="stretch_width", height=500, styles={"background": "gray"})

pn.template.FastListTemplate(
    title="Who is playing games with Panel and PIXI js?",
    main=[pn.Column(game, game.param.py_to_js_event, game.param.js_to_py_event)],
).servable()

Serve the app with

panel serve script.py

Please note, I cannot get the communication from the client to the server (via js_to_py_event) working and I can find no error message indicating why.

Next Steps

  • Get communication from client to server working. The js_to_py_event parameter does not seem to get a dictionary with the sprite x and y values.
  • Understand what are python and what are js objects and learn how to use/ convert them.
  • Figure out if its better to use pyscript for this use case than pyodide. Maybe use micropython instead of pyodide to load faster.
  • Implement real game. Maybe use ChatGPT to convert some PIXI js examples to Python.
  • Improve the developer experience
1 Like

Thank you so much for exploring this!

I’ve been teaching my little cousin how to code in Python with pygame and we ended up creating a pretty cool game that I’d love to share somehow; maybe we can translate it to PixiJS.

1 Like