This is a simple Web GUI for puppeteer[0]. The interesting things about it are:

- It works like a very basic (circa 1994 ?) web browser.

- It runs in your normal web browser, even with JavaScript switched off.

If it became popular I would consider expanding the puppeteer API capabilities. Currently it only supports things that enable interaction with the embedded page (the web page running in the headless Chromium instance that puppeteer is connected to).

I achieved the no-client-side JS requirement by solving the following problems:

1. How to transmit clicks without capturing click events?

The button[type="image"] HTML tag transmits X, and Y coordinates when you click it on form submit. Making a full width and full height image button solves the requirement of transmitting pointer position (on click at least, and that limitation is good enough for our simple use case) without JS.

2. How to dynamically update the viewport (the image of the web page running in the headless browser) without client-side JavaScript?

The image/mjpeg MIME type is supported by browsers and implements a simple "server push" type of streaming using a HTTP keep-alive connection. It is not a new feature. I think I've heard MJPEG is how many web-viewers for CCTV or security cameras have been created for a long time.

3. How to combine sending pointer coordinates on a viewport, with a viewport that continually updates with any changes from the server (in other words, a client-side image that updates when the server side headless browser's page changes)?

Well, I combined them together in a way I find pretty cool, beautiful and elegant. And it's basically all thanks to how cool HTML is. The crucial line is:

<image type=button src=viewport.mjpeg>

So in that crazy way, a combination of two old-school HTML technologies (rarely used in the mainstream these days): button images, and MJPEG -- gives us a foundation for basic application virtualization. I love that. I love that the 'old web' can do something so cool and powerful, as well as loving that these two old-school (relatively) neglected (again, in the mainstream of current web dev) technologies can be combined together in one line of code to do something really cool and powerful.

Also, for bonus points, can anyone guess how I solved the, following challenge:

4. "Yes, but how do you know, how big the client's screen is without any client-side JavaScript?"

This was probably the most difficult one. Tho I'm sure some of you (hello, designers) will probably immediately see the result and answer, perhaps. What I figured out was I could use a stylesheet functioning as basically a giant "switch" statement by using media-queries "screen dimension breakpoints" to wrap an image request to the server. What that means is that only the matching media-query is executed, and then information is transmitted to the server by way of the request for an image that contains the approximate screen dimensions in the request URL. So the server can know how big the clients screen is, and it can then instruct puppeteer to set the browser screen dimension to be the same.

The relevant line (on the server, to generate the CSS stylsheet)[1] looks like:

function ViewportProbes(state) {
const BP = [];
for( let w = 300; w <= 1920; w+= 32) {
for( let h = 300; h <= 1080; h+= 32) {
BP.push({w, h});
}
}
const MR = BP.map(({w,h}) => `
@media screen and (min-width: ${w}px) and (min-height: ${h}px) {
body {
background-image: url("/set-viewport-dimensions/width/${w}/height/${h}/set.png")
}
}
`);
return MR.join('\n');
}

So all in all that's how I combined MJPEG, button images, and CSS media queries to do a very basic application virtualization, remote browser, web GUI for puppeteer that doesn't run any client-side JS on your browser.

[0]: https://github.com/puppeteer/puppeteer

[1]: https://github.com/i5ik/puppetromium/blob/36eebe692e031fa3cb...