PlayCanvas and Puppeteer Headless Chromium

Does anyone knows why my Playcanvas app won’t load on Chromium with Puppeteer?

We created a product configurator and we need to take some photos with a server (for creating PDF) and playcanvas is always stuck on loading screen on 0%.

I did introduce setTimeout function and it works (checked with different websites), but the PC app is always stuck and not loading. I also tried different PC apps from the site, but all of them won’t load.

I tried loading times from 5 seconds up to 5 minutes, and it’s always returning images of loader screen with 0 progress.

Is there some WebGL dependency or what it might be?

My app is developed on Gadget.dev which is a Fastify/Node.js framework. And everything works, just this won’t load :slight_smile:

Help is appreciated, it’s quite urgent!

This might be interesting, it says that my browser supports WebGL, but it’s not turned on or unavailable.

I’m not sure what the problem could be, but our engine examples use Puppeteer to generate thumbnails here, in case it gives you some ideas: engine/examples/scripts/thumbnails.mjs at main · playcanvas/engine · GitHub

1 Like

Try the solutions in this thread: [Bug]: puppeteer v20 doesn't support WebGL · Issue #10175 · puppeteer/puppeteer · GitHub (which points to docs: update gpu docs by OrKoN · Pull Request #10562 · puppeteer/puppeteer · GitHub)

I don’t know if this helps as well, this is my conversation with people from Gadget.dev (where my app is hosted).

Here is my PlayCanvas app for reference: Norqain_WatchConfig - PLAYCANVAS

What I am trying to do is to open the playcanvas, load it, wait for event that says it’s loaded, then I send some postMessages to the playcanvas to setup configuration (there is an event listener that does this), then I take 3 screenshots with 3 different camera angles (also have listener for camera change).

And that’s it. Just I can’t move on from loading. And my serverless backend doesn’t have any GPU. Is it possible to run WebGL without a GPU? Or this is the problem?

Chrome provides a software gpu called Swift Shader. I would have thought that would be available to use

Have you tried using the options mentioned in the GitHub threads I linked to?

Maybe this also gives more insight:

“puppeteer”: “^22.8.0”

That’s the version I am using. But I am not using it’s chromium, but the one Gadget team installed for me, so I can use puppetteer-core as well for that matter.

Here is my script:

  let browser, page;

  try {
    // Initialize Puppeteer browser and page
    browser = await puppeteer.launch({
      headless: true, // Set to false if you want to see the browser UI
      executablePath: "/usr/bin/chromium",
      arg: ["--no-sandbox", "--headless", "--enable-gpu"],
    });
    page = await browser.newPage();

    // Setup a promise to wait for a specific console message
    const waitForConsoleMessage = new Promise((resolve) => {
      page.on("console", (msg) => {
        if (msg.text().includes("PlayCanvas App Started!")) {
          // Adjust the message text as needed
          logger.info("Detected PlayCanvas load completion in console.");
          resolve();
        }
      });
    });

    // Navigate to the page
    // await page.goto("https://playcanv.as/p/93709109/", { waitUntil: 'networkidle0' });

    await page.goto("https://get.webgl.org/", { waitUntil: "networkidle0" });

    // Wait for the specific console message
    // await waitForConsoleMessage;

    //    await new Promise(resolve => setTimeout(resolve, 10000));

    // Send SKU details and configurations to PlayCanvas
    for (const spec of orderSpecifications) {
      const details = {
        type: "SKU_details",
        sku: spec.sku,
      };

      if (spec.properties) {
        if (spec.properties.font) {
          details.font = spec.properties.font;
        }
        if (spec.properties.engravingText) {
          details.engravingText = spec.properties.engravingText;
        }
        if (spec.properties.printImage) {
          details.printImage = spec.properties.printImage;
        }
      }

      // Send the details to PlayCanvas
      await page.evaluate((details) => {
        window.postMessage(details, "*");
      }, details);
    }

    const screenshots = [];
    // Define camera angles and take screenshots from specified angles
    const cameraAngles = [7, 5, 8]; // Example camera angles: Front, Side, and Back
    for (let index of cameraAngles) {
      await page.evaluate((index) => {
        window.postMessage({ type: "CameraChange", index }, "*");
      }, index);

      // Wait a moment for the camera to settle
      await new Promise((resolve) => setTimeout(resolve, 1000));

      // Take a screenshot and store it
      const buffer = await page.screenshot();
      screenshots.push(buffer.toString("base64"));
    }

    // Close the browser once done
    await browser.close();

    // Return or handle the screenshots as needed
    return screenshots;
  } catch (error) {
    console.error("Error during image generation:", error);
    await browser.close();
    throw error; // Rethrow or handle error as needed
  }
};

type or paste code here

What are they using?

Have you managed to get this working locally? If so, it sounds like an issue on Gadget’s side

I went through them, but didn’t quite understand what I need to do except that proposal for --enable-gpu which I added, but I guess that since I don’t have GPU on server I need a different command.

I didn’t even try, not sure how, as my CLI for Gadget doesn’t pull full app from my understanding, so I can’t run the entire app in localhost.

I will see if I can do it. But on my end, I have a GPU and it will probably work, also I don’t know which chromium they installed for me, so I also guess that the entire setup on my side would not represent the same environment as online.

They say it should work, and they think it’s a problem due to some drivers and installations, which they will provide.

What I would do in this situation is to get it working locally so you can be sure it’s not your Puppeteer or PlayCanvas code that is the issue. Once you have a known working solution, you can use that with Gadget to try to debug their side

I will try to see how to do this, and then let you know if I have any progress!

I don’t know about gadget.dev, but serverless architectures tend to have heavily constrained runtimes without a graphics API. This may be what you’re likely facing.

I have one question.

From my understanding if WebGL is not supported for any reason, wouldn’t the app load and then canvas go blank?

I am concerned as our loading bar is always at 0. Is there any engine related code that does this if WebGL support is not active?

Why is it at 0% no matter how long we wait?

If WebGL is not support, it can’t load anything into textures etc

It is true, but Chromium should run WebGL without GPU anyway. So there might be solution. As for runtimes, I am pretty sure that Gadget’s team can help with those as they are really receptive and already installed Chromium for me (as I was not able to install it with all the dependencies, due to a size and other limitations)

1 Like

Ok, so that is the problem. I suspected it’s something like that.

Also if you know you do not want to render anything consider using the null graphics device engine/src/platform/graphics/null/null-graphics-device.js at main · playcanvas/engine · GitHub

I need to render my watch configuration, and then take screenshots from it with different camera angles.

So I can’t use null-graphics-device :slight_smile: