
Webcam in a Favicon - MagicPropmaker
https://twitter.com/davywtf/status/1119783380734836737
======
florian_s
The source code is actually small enough to be posted here

    
    
      navigator.getUserMedia = navigator.getUserMedia || 
      navigator.mozGetUserMedia;
      
        window.onload = () => {
          // Create favicon link element
          const favicon = document.createElement('link');
          favicon.rel = 'shortcut icon';
          favicon.type = 'image/png';
          favicon.href = '../../images/favicon.ico';
          document.getElementsByTagName('head') . [0].appendChild(favicon);
          // Create hidden canvas
          const w = 32;
          const h = 32;
          const canvas = document.createElement('canvas');
          canvas.style = 'display: none';
          canvas.width = w;
          canvas.height = h;
          document.body.appendChild(canvas);
          // Grab canvas context
          const ctx = canvas.getContext('2d');
          // Create hidden video element
          const video = document.createElement('video');
          video.style = 'display: none';
          video.width = canvas.width;
          video.height = canvas.height;
          document.body.appendChild(video);
          // Assign user media to video and start loop
          navigator.getUserMedia({video: true}, stream => {
              video.srcObject = stream;
              video.play();
              loop();
          }, () => {});
          // Loop forever
          const loop = () => {
              // Copy video to canvas
              ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
              // Set canvas to favicon
              favicon.setAttribute('href', canvas.toDataURL());
              // Loop
              setTimeout(loop, 100);
          };
      };
    

From [https://github.com/wybiral/code-
art/blob/master/projects/tin...](https://github.com/wybiral/code-
art/blob/master/projects/tiny-mirror/index.js)

~~~
chipperyman573
Is there a reason that he sets a timeout of 100? Since this is all local
(because of canvas.toDataURL()), can't it just run every 16ms (60 fps) instead
of 100? I noticed in the gif that it was super choppy but I kind of assumed
there was a technical reason, but I can't think of a reason that there would
be a reason to have such a long delay.

~~~
wybiral
The browser doesn't seem to update the image any faster (at least not Chrome
on Linux) than it already does. You can try different framerates though, maybe
some platforms allow higher frequency?

------
wybiral
Another interesting (and more practical) use of the favicon is visit duration
tracking without JS:
[https://twitter.com/davywtf/status/951203191944773632](https://twitter.com/davywtf/status/951203191944773632)

Basically the favicon connection to the server stays open sending a periodic
junk-update so that the server can detect when the tab is closed. You can do
it with any asset but the favicon hides the loading indicator.

~~~
eridius
Presumably you could do the same thing with a `<script async>` tag, drip-
feeding bytes across the connection and waiting for it to close. Though now
that I've said that, it occurs to me that disabling JavaScript almost
certainly avoids loading script hrefs to begin with rather than just not
executing them.

Is there an equivalent with any other type of resource, that avoids deferring
onLoad?

~~~
wybiral
> Is there an equivalent with any other type of resource, that avoids
> deferring onLoad?

If JS is disabled the event doesn't really matter and any asset can be handled
this way. I just use the favicon because it stops the browser from showing a
loading spinner so everything looks still and nobody assumes there's anything
going on in the background.

You can use persistent connections like this in other strange ways too. For
instance this is a no-JS chat that's even able to update the connection count
by sending a bit of CSS lazily:
[https://harmless.herokuapp.com/main](https://harmless.herokuapp.com/main)

------
_bxg1
The URL equalizer further down is possibly even cooler:

[https://mobile.twitter.com/jake_albaugh/status/1118611365508...](https://mobile.twitter.com/jake_albaugh/status/1118611365508337665)

~~~
shard
Note that the link is to something that is an audio spectrum
analyzer/visualizer and not an equalizer. It's even called "Analyser" in the
code. At first I was amazed that an equalizer could be implemented into a URL,
I was wondering how one would input the gains for the frequency bands, but
alas it just displays the volume at each frequency.

~~~
_bxg1
Whoops, the person who quote-tweeted it in the original thread called it an
equalizer and I didn't give it any thought

------
vortico
See also [http://lab.ejci.net/favico.js/](http://lab.ejci.net/favico.js/)

------
Stratoscope
It would be fun to flip the image so it really looks like a Tiny Mirror. I
wonder if this would work?

In the initial setup:

    
    
      ctx.scale( -1, 1 );
    

In the drawing loop:

    
    
      ctx.drawImage( video, 0, 0, canvas.width * -1, canvas.height );
    

Something like that anyway. We have guests arriving soon, so no time to test
right now, but if anyone tries it I will be curious!

------
tamentis
That's such an awesome little hack. Next think we _need_ is to synchronize
multiple tabs and a multi-player favicon game where you get to shoot the tabs
of your opponents.

------
darkhorn
It crashes Firefox 66.0.3 (64-bit) on Windows 10.0.17763.437. [https://crash-
stats.mozilla.org/report/index/7d1ca3eb-2d06-4...](https://crash-
stats.mozilla.org/report/index/7d1ca3eb-2d06-43af-a83b-d7e510190421)

~~~
MagicPropmaker
If it crashes it, there may be an attack vector here!

~~~
wybiral
If you _really_ want to crash a Firefox browser without JS, there's this:
[https://fan-pages.herokuapp.com/](https://fan-pages.herokuapp.com/)

It basically keeps sending iframe's with data URL's for download, see code:
[https://github.com/wybiral/crash](https://github.com/wybiral/crash)

On Chrome it blocks request popups after the first but FF usually crashes
(even Tor Browser).

The interesting thing about this is that you can keep the connection open as
long as you want and then send the iframes on command.

~~~
chipperyman573
>The interesting thing about this is that you can keep the connection open as
long as you want and then send the iframes on command.

What do you mean?

~~~
wybiral
If I'm operating the server I can keep the connection open to your browser and
wait until sending the iframes to crash you.

So combined with other tracking techniques (to tell if a tab is still open)
you can crash their browser and see which other tabs close.

------
amelius
Next release: larger video image! Since it's impossible to show a larger image
in the thumbnail area, we'll show the video in the main browser window.

------
kalleboo
This fails in Safari on the use of a deprecated API
[https://developer.mozilla.org/en-
US/docs/Web/API/Navigator/g...](https://developer.mozilla.org/en-
US/docs/Web/API/Navigator/getUserMedia)

