Live data from Hacker News

Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

p01.org

41–50 of 131 posts

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#41
post #39

People love to bash developers who put up "Chrome recommended" banners, dismissing them as lazy, but when making games and such there are real issues that are impossible to circumvent. This bug is a prime example of that.

I sympathize with developers dealing with browser bugs, but a majority of "Chrome recommended" banners are not. For many cases they are used as a cheap excuse not to care about or even deter non-Chrome browsers at all, even when they do work mostly or completely fine. Demos, in comparison, tend to have much narrower requirements due to various constraints (many D3D demos only worked with specific graphic cards at least in the initial release, for example).

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#42
post #32

I, for one, liked the "firefox version" of the demo. No way to close, mute or go back. And after a minute someone starts talking to you. Pretty cool.

Yeah Firefox Mobile also has some serious issues with that.it was fun though ;)

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#43
post #39

People love to bash developers who put up "Chrome recommended" banners, dismissing them as lazy, but when making games and such there are real issues that are impossible to circumvent. This bug is a prime example of that.

The point is that if shadowBlur performed poorly in Chrome, people would either find a way to circumvent it, or wouldn't use it. Chrome gets a free pass for its failings, while Firefox attracts "Chrome Preferred" banners, and this is based on market share rather than software quality.

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#44
post #2

It was hard to get to a working demo and here it is: http://www.p01.org/MONOSPACE/monospace-compatible.htm

Pretty interesting that even though I mute the tab it still speaks. The music does get muted, but not the TTS

It's using https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynth... which probably isn't affected by the "mute toggle" for accessibility reason.

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#45
post #39

People love to bash developers who put up "Chrome recommended" banners, dismissing them as lazy, but when making games and such there are real issues that are impossible to circumvent. This bug is a prime example of that.

I sympathize with developers dealing with browser bugs, but a majority of "Chrome recommended" banners are not. For many cases they are used as a cheap excuse not to care about or even deter non-Chrome browsers at all, even when they do work mostly or completely fine. Demos, in comparison, tend to have much narrower requirements due to various constraints (many D3D demos only worked with specific graphic cards at lea…

Now CypressJS has a Firefox backend it's less forgiveable.

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#46

The video was lost on me whereas the demo made me think how cool it was. I expected the video to explain what it was but alas no. The video is just the demo running. The demo was brilliant, but, the video of the demo, although practically the same had me wondering quite negative thoughts. I wasn't thinking 'how do they do that', I was thinking 'this is a bit pretentious'. It is amazing the difference context makes.

> I wasn't thinking 'how do they do that', I was thinking 'this is a bit pretentious'.

Everyone experiences things differently. Some people see a sports car and think, "Wow, I wonder how it works?" Others, "Wow, I hate that colour." Doesn't really matter.

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#47
Here are other visual JS Demos created by p01 and others using just 140 characters of code (or less!): https://www.dwitter.net/top/year

Dwitter is a collection of amazing short JavaScript codes that can be explored, remixed and voted "awesome". It works like a living portfolio of short code/graphic creations where one can learn by exploring other people's code.

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#48
It is amazing how much one can achieve with so little code. I would dare to say that such demos are a kind of...indie art?

Can you give us some pointers, which APIs and algorithms did you use to generate the demo? I bet it will be an interesting lesson on math and web

Re: Monospace: A JavaScript demo in 1021 bytes, winner of the demo competition

#49

Amazing! Very impressive how you got all the details in. I'd be interested in hearing what the development process is like. Do you work directly in the minified code, or do you create the demo in normal code first then look for ways to minimize it?

I'm not the author but I've done this before [1], so here's what I can quickly make up (EDIT: updated using informations gathered from p01's comment below):

    // c is a canvas created outside
    d = [ // 2 times audio frequencies used, I think
      2280,
      1280,
      1520,
      c.width = 1920,
      // d[4] is not used, not sure why this stmt was stuffed into d
      // required to hide the PNG bootstrap; the bare minimum would be `0'`, probably this compresses better though?
      document.body.style.font = "0px MONOSPACE"
    ],
    g = new AudioContext,
    o = g.createScriptProcessor(4096,
                                // clears the margin and initializes vars
                                // (t: time in seconds, n: last t when speak occurred)
                                document.body.style.margin = t = n = 0,
                                1),
    o.connect(g.destination),
    o.onaudioprocess = o => { // periodically called to fill the audio buffer, used in place of setInterval
      o = o.outputBuffer.getChannelData(
        e = Math.sin(
          t / 16 % 1, // this is the only arg to sin, others are for shoving exprs into a single stmt
          m = Math.sin(Math.min(1, y = t / 128) * Math.PI) ** .5 + .1,
          c.height = 1080, // setting canvas.width/height clears the canvas
          b.shadowOffsetY = 32420,
          // results in `radial-gradient(#222,black` or so, reinterpreting decimal number as hex, the last `)` is not required
          c.style.background = "radial-gradient(#" + [222, 222, 222, 222, 155, 155, 102, 102][t / 16 & 7] + ",black",
          b.font = "920 32px MONOSPACE",
          // each function determines the dot size for 16 seconds, also sometimes used as a display text
          f = [
            (x, y, t) => x / y * 2 - t,
            (x, y, t) => (x ** 2 + y ** 2) ** .5 - t,
            (x, y, t) => x / 4 ^ y / 4 - t,
            (x, y, t) => y % x - t
          ][t / 16 & 3],
          // determines a string to print and speaks it every 16 second
          // the inner [...][t/16|0] can return undefined, which gets coerced to an empty string by `""+[...]`
          u = "" + [[, f, f, " CAN YOU HEAR ME", f, f, , "MONOSPACE", "THE END"][t / 16 | 0]],
          t > n && speechSynthesis.speak(new SpeechSynthesisUtterance(u, n += 16)))
      );
      for (i = 0; 4096 > 4 * i; i++) // for each dot; `4096>4*i` probably compresses better than `1024>i`
        // calculate the dot size and mix with the radius in the previous frame for easing
        // f and g are objects (function and AudioContext), so can be abused as a generic store
        g[i] = r = (f(x = 16 - i % 32, a = 16 - (i / 32 | 0), t) / 2 & 1) + (g[i] || 0) / 2,
        x += o[0] / 4 + 4 * (1 - m ** .3) * Math.sin(i + t + 8),
        a += o[64] / 4 + 4 * (1 - m ** .3) * Math.sin(i + t),
        h = x * Math.sin(y * 2 + 8) + a * Math.sin(y * 2),
        p = 4096 / (m * 32 + 4 * h * Math.sin(e) + t % 16),
        b.beginPath(f[i] = r / p),
        b.arc(h * Math.sin(e + 8) * p + 1280,
              x * Math.sin(y * 2) * p - a * Math.sin(y * 2 + 8) * p - 31920,
              p > 0 && p / (2 + 32 - r * 16),
              0,
              8), // anything larger than `2*Math.PI` will draw a full circle
        b.shadowBlur = o[0] ** 2 * 32 + 32 - m * 32 + 4 + h * h / 2,
        // `[a,b,c]` coerces into a string `a,b,c`
        b.shadowColor = "hsl(" + [f(x, y, t) & 2 ? t - a * 8 : 180, (t & 64) * m + "%", (t & 64) * m + "%"],
        b.fill();
      b.shadowBlur = o[0] ** 2 * 32,
      b.shadowColor = "#fee";
      for (i = 0; 4096 > i; i++) // generate each sample, also prints the glitched text
        o[i] = o[i] / 2 + (
          (
            Math.sin(t * d[t / [4, 4, 4, 4, 1/4, 1/4, 16, 4][t / 16 & 7] & 3] * Math.PI) * 8 +
            (t * d[t / 8 & 3] / 2 & 6) + t * d[t / 16 & 3] / 4 % 6
          ) / 64 + f[i / 4 | 0] // f[0..1023] is the visual data, reused as a noise
        ) * m,
        // prints at most 64 characters of u;
        // 0th and 64th samples (o[0] & o[64]) of the prev/current buffer act as x/y jitter,
        // first 64 samples also displaces the char offset for the glitched text effect
        64 > i & t % 16 * 6 > i &&
          b.fillText([u[i + (o[i] * 2 & 1)]], // again, [undefined] coerces into an empty string
                     i % 9 * 32 + o[0] * 16 + 180,
                     (i / 9 | 0) * 64 + o[64] * 16 - t - 31920),
        t += 1 / g.sampleRate // so t increments by 1 per second
    }
While the obfuscation itself is fairly standard, I think the real magic here is the carefully selected motion and jitters---which I can't easily figure out from a glance.

> Do you work directly in the minified code, or do you create the demo in normal code first then look for ways to minimize it?

Also, in my experience you end up structuring everything so that it can be easily minifiable (by hand or using something like terser-online [2]). This doesn't necessarily mean that the code is unreadable (variables can be renamed, statements can be converted to comma expressions and so on), but the resulting code would be very unorthodox. See the source code of my JS1024 entry for example.

[1] https://www.js1024.fun/demos/2020#46

[2] https://xem.github.io/terser-online/

Post reply on HN