Browser build in any plans?

out of memory. Haven’t found yet where to specify that.

Use the help to find out what options are available.

python makepanda/makepanda.py --help

For OGG files, perhaps: --use-vorbis or --use-opus.

You don’t need --use-jpeg to load jpg files, and if you did, you would need a thirdparty build of libjpeg for emscripten. But again, you don’t need it, because Panda falls back to stb_image.

You do need to preload the assets. Or, you need to get it via some other source, such as some way via the virtual file system, but in absence of that you just need to add it to your preload.

I seem to recall that emscripten does have a way to load assets via HTTP requests, described here. In the future, I want to make a native VFS mount in Panda to be able to mount assets from a web folder, but I don’t think we have it right now.

–use-opus is unrelated to .ogg files. If you want to support ogg files, the flag is --use-vorbis. That does work with emscripten since it just opts-in to the emscripten-ports version of vorbis.

Please note that my updated freezify files also include the required changes, feel free to use them as a reference. If you run out of memory, just increase the memory limit specified via -s TOTAL_MEMORY=.

    SmartPkgEnable("VORBIS",    "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
    SmartPkgEnable("OPUS",      "opusfile",  ("opusfile", "opus", "ogg"), ("ogg/ogg.h", "opus/opusfile.h", "opus"))

Then this information is misleading.

No, it’s not. Ogg is a container format, used by various codecs, including FLAC, Opus, Ogg Theora, and Ogg Vorbis. A .flac file is also an Ogg file, and so is an .opus file. This is why Opus relies on libogg.

If anything is misleading, it is the fact that Ogg Vorbis files have the “.ogg” extension instead of “.vorbis”. When people mention “Ogg files”, they are usually talking about “.ogg files”, specifically, “Ogg Vorbis” files.

To get this thread back onto topic: on the desktop, there is a mechanism called vfs-mount-url where you can mount a URL to Panda’s virtual file system, allowing you to download files from a server on the fly as though they were part of the filesystem.

However, the current implementation just won’t work on the web, because it uses a much more low-level socket library that isn’t available in emscripten. I think we need a new implementation that uses this family of functions to fetch the resources:
https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_async_wget_data

In the meantime, I think preloading is the only way, or you could perhaps try to interact with these emscripten APIs (or with the JavaScript fetch API) yourself.

Note that you could also use multify to create a .mf file and preload that, then mount it into the Panda VFS. It is perhaps more convenient than specifying every file separately, but perhaps not.

Thank you, I will preload them all before trying the alternatives.

Before going to your freezify, I am trying to edit the changes myself to understand and remember them better. But will check.

Bumped TOTAL_MEMORY to 393MB but it still says out of memory when loading wasm (21.4MB; data is 34.3MB). Is that possible? I will keep going, but worried something is not right.

Is it possibly caused by the arrayBuffer instantiation instead of using application/wasm?

My server also isn’t configured to serve application/wasm properly, yet my demos still work.

However, all of the preload gets loaded into memory, so perhaps your assets really are 400+ MB when decompressed from jpg, etc.?

Emscripten has a configuration option to grow memory automatically, perhaps you could look into that.

EDIT: Actually, I just loaded your editor.html, and I don’t get an OOM error. I just get the error Couldn't load file models/floor.bam: not found on model path

Interesting. My server has been having troubles this afternoon, so I am not sure how reliable. And there might be caching issues, so I am trying to reload everything.

No way the assets are 400MB. The entire directory is 35MB on disk. I downsample all my images for faster loads – at least until I get everything working.

But thanks for the bug! Turns out my asset listing program forgot models! Sorry, dumb mistake.

Much farther, but now no module named _socket. Interesting because I do not import socket, though I do import requests – is it from that? The only ‘socket’ in any file in my directory is in the .wasm file.

There is a socket.py in the thirdparty…lib/python3.8/ so I guess I need a switch to ensure it is compiled into libpython3.8.a? I don’t see an argument that looks even close to enabling requests,sockets,or any networking.

I removed the reference to requests and that got rid of the error. So now, no errors, but no application either. I get a large black screen, and the console print statements (identical to running the app in python and correct), but nothing visual.

I will have to get requests to work, else all for naught, but it seems something else is amiss. Maybe it is the html file? I am using the one created by emcc. Using editor.html from the thirdparty kit seems to load fine, and my main.py shows up on the right, but the run button is grey and does nothing.

Sockets are not available in the browser (WebSockets are, but they are not compatible).

I think you will have to write a shim version of the “requests” module which uses the emscripten wget or JavaScript Fetch API to make the requests. I’d be happy to be of assistance; such a module would be greatly useful for other Panda users as well.

When I run your game I get a black screen as well. I think it might be something in your application; it’s hard for me to say without looking at your code or having a Python shell to poke around in your application, or adding some extra debugging (print statements, etc.). It’s either not rendering (ie. task manager is not getting run properly) or there is something about the way your application renders that obscures everything. I suspect the former. Do you still have the code in the .c file that schedules task_manager_poll?

One additional note to point out: if you have a non-standard way to invoke the task manager run loop in your program, that might be a problem. Currently, run() will return right away, the main module will finish running, and the code in freezify.py schedules the Panda task manager to run via the JavaScript event loop which takes over execution. For most application this won’t be a problem, but if you have a custom main loop, this will need to be revised.

For what it’s worth, I’ve been investigating ways we can use emscripten’s asyncify feature to improve this system.

Task_manager_poll was still commented out in runPythonCode, I should have noticed that, but it did not make any difference. I put a Module.setStatus right after that statement and I don’t see that status.

I put my main.py on my server if you want to look at it. I think the only thing unusual I do is use signals (messages) a lot to coordinate among modules, but that seems to be working fine, I am getting the print statements that result from the signals.

That looks fine in principle, can I see your freezify.py or the generated C code?

here

The emscripten_set_main_loop call is put in runPythonCode, but you are no longer calling runPythonCode anywhere, so it never gets run.

You want to just move the emscripten_set_main_loop line to right above the PyImport_ImportFrozenModule line. The runPythonCode (and stopPythonCode) functions can be removed entirely then, they were only there to support my editor app.

I will later check in a change to Panda that obviates the need for the emscripten_set_main_loop line.

That makes much more sense, thanks, will update when it finishes. I tried several different ways to comment out the run/stopPythonCode but couldn’t get it to work. I assumed they were there for the editor app but getting rid of them didn’t work. I should have noticed the set_main_loop.

!! [screen shot]

Now, my real work begins. Apparently ESC is trapped by the browser, I need an alternative. And requests – it has been 10 years since I made a shim from lua to js, I will have a lot to relearn.

I will also try to follow my script (the copy in this thread has been updated as we went along) on a linux machine, see if edits are needed for clarity. What do you think about the python compile? Should we leave that in, or will you just provide versions of thirdparty with different python versions?

Thank you for all the help. Sorry it was so much work, but now maybe others can put their apps in browsers? Thank you again.

Success, cool! :slight_smile: This will certainly make it easier for others as well.

I think it’s easiest for people if we provide the Python thirdparty package like we do for the other platforms.

I’ve been thinking about how we could create a drop-in replacement for requests. One challenge is that the requests module has a synchronous API; ie. requests.get() is supposed to block Python execution until the download is done. The problem with that is that we’re not allowed to block the JavaScript main loop (the emscripten_wget APIs are asynchronous for that reason).

One option would be to build something like requests, but that has an asynchronous interface (using callbacks, or coroutines and async/await). If this is an option for you, this would probably be the most efficient, but it would require refactoring your code.

The other option would be to enable emscripten’s ASYNCIFY option, which (at the cost of a ~50% code size overhead) allows writing synchronous code that nonetheless doesn’t block the JavaScript event loop. I’ve been toying with that in the meantime with some good results; the neat thing about this approach is that it also offers us the use of fibers (ie. lightweight threads) for asynchronous load operations.

I’m also thinking about creating a Python wrapper around the emscripten API which would make it easier to write such a requests module (and anything else that might use the emscripten API) in pure Python code.