Hey so I’ve seen a bunch of old forum posts about running playcanvas engine headless, and using old tools like playcanvas-mock or headless-gl, but nothing seems to be up to date from what I’ve seen. I’m trying to render and screenshot a single frame.
Currently I’m using puppeteer but it’s relatively slow. I want to avoid running the browser at all if possible, and run the project directly through node or some other runtime engine. I have a framebuffer-screenshot system working currently.
TL;DR
I want to render and store a screenshot of a PlayCanvas scene as fast as possible. Been stuck for some time so direction is much appreciated.
The issue is that you would need to have something that can handle a WebGL canvas and usually, the easiest is to have headless browser on hardware that can handle 3D rendering natively instead of using the Swift software renderer on Chrome.
Unfortunately I think headless-gl is struggling with age as it only supports WebGL 1 plans for webgl 2 support? · Issue #109 · stackgl/headless-gl · GitHub and I believe PlayCanvas is deprecating WebGL 1 in the near future(?). In any case I got a lot of ‘function not implemented’ errors when trying to work with it. Not sure if anyone else has had better success
And from digging into the build target engine/examples/scripts/build-thumbnails.mjs at main · playcanvas/engine · GitHub “This file spawns a pool of puppeteer instances to take screenshots of each example for thumbnail.” so they’re still using puppeteer for doing it. Makes sense for thumbnails that only run on build, but we need it running fast and often.
For context, we’re trying to actively render and save screenshots of user generated characters using a cheap VPS. Works great and takes about 10 seconds per character with puppeteer. But we need to cut that down to <1 second to scale it for our purposes
If it’s known what is taking the time, perhaps there are other ways to bring down that time
Eg, could you have the browser and app already loaded and all it has to do is load the custom character asset, render and deliver the file. That bypasses the initial browser spin up time and app load
You may need to cycle the app/browser every now and then to potentially clear memory or whatever but see how that goes for you
You could also customise the app a bit so you can stop the update and render loop when it’s not in use so you aren’t spinning cycles/using the CPU unnecessarily
Yep, so that ended up working fantastically. I do an npm run serve for my actual project, and alongside that host an esm module running express on localhost that manages a puppeteer instance.
Then I just do little post requests to send commands and auto close/open the browser every X screenshots just in case of leaks. Runs in <1s on the cheapest VPS instance available.
FYI, and for future readers, there are a few IaaS platforms that offer this. Notably Cloudflare have a scalable solution using browser instrumentation, similar to Puppeteer Browser Rendering · Browser Rendering docs
I know you’re interested in rendering, but I did just write this new user manual page which you might find interesting:
As @mvaligursky suggests, headless WebGPU is probably the future for rendering in Node.js, but as of today, there isn’t yet an official/popular NPM package for this. Although something might grow from this one day: