1

I'm trying to take a screenshot of a website (in which I control) using puppeteer in headless mode.

The problem is, there is a WebGL canvas on my website that won't get rendered in a headless mode screenshot (but works in headful mode).

All I get in headless mode is a black PNG.

I've tried changing the WebGL context parameters to multiple combinations but nothing works.

I'm using puppeteer version 5.5.0 and chromium version 88.0.4298.0

Here is my puppeteer crawler code:

const puppeteer = require("puppeteer");

const url = "https://phcs93.github.io/genesis/";

async function crawl () {
    const browser = await puppeteer.launch({
        headless: true,
        args: [
            '--no-sandbox', 
            '--disable-setuid-sandbox', 
            '--mute-audio'
        ]
    });
    const page = await browser.newPage();
    await page.goto(url, {
        "waitUntil": "networkidle0",
        "timeout": 0
    });
    await page.screenshot({ path: "screenshot.png" });
    await browser.close();
}

(async () => await crawl())();

And these are the current parameters I'm using on the WebGL context of my website:

const gl = canvas.getContext("webgl2", {
    preserveDrawingBuffer: true,
    alpha: false,
    antialias: true,
    premultipliedAlpha: true
});
Pedro Henrique
  • 680
  • 7
  • 22
  • Just as a sanity check have you tried adding a wait before taking the screenshot. Example `await new Promise(resolve => setTimeout(resolve, 5000));` – gman Jan 30 '21 at 00:02

1 Answers1

2

After a lot of debugging, I found out the problem:

In one of my shaders (gradient.glsl), I had this:

uniform float[256] breakpoints;
uniform vec4[256] colors;

Changing it to this, solved the problem:

uniform float[122] breakpoints;
uniform vec4[122] colors;

Any value above 122 for both arrays wont work.

Now here comes the even weirder part, this works:

uniform float[244] breakpoints; // 245 or more wont work
// uniform vec4[122] colors;

This doesn't work:

// uniform float[122] breakpoints;
uniform vec4[244] colors; // only 243 or less

I haven't tested any further than that, looks like some kind of memory limit on the headless mode?

TIP: It is possible to capture all console messages from the page with puppeteer, just add this before page.goto:

page.on('console', message => console.log(`${message.type().substr(0, 3).toUpperCase()} ${message.text()}`));
page.on('pageerror', ({ message }) => console.log(message));
page.on('response', response => console.log(`${response.status()} ${response.url()}`));
page.on('requestfailed', request => console.log(`${request.failure().errorText} ${request.url()}`));

Doing so would have spared me a lot of debugging time.

Pedro Henrique
  • 680
  • 7
  • 22
  • 3
    There are limits to different webgl implementations. You can query the max uniform vectors with `gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)` or `gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)`. In WebGL for fragment shaders only 16 are required. For vertex shaders 128. That means your shader potentially won't run on lots of devices. If you want large arrays of data you should be using [textures](https://webglfundamentals.org/webgl/lessons/webgl-gpgpu.html) – gman Jan 30 '21 at 01:19
  • 3
    As for the the 122/244 issue see [this](https://stackoverflow.com/questions/26682631/webgl-shaders-maximum-number-of-varying-variables/26683122#26683122) and [this](https://webglfundamentals.org/webgl/lessons/webgl-cross-platform-issues.html) – gman Jan 30 '21 at 01:24