WE DON'T MAKE MISTAKES AT DEVONE 2019

1007 words ~ 5-10 mins

Giving the closing keynote DEV ONE 2019, held on April 11 in Linz, Austria was absolutely fantastic. The conference was very well organized with one track, 11 talks about "scale" and 600 wonderful delegates. I learnt so much that day, got confirmation for some good practices but also learnt about many opportunities to improve our work. Also it was a pleasure to see familiar faces among the organizers and attendees from Script 17, in Linz

We don't make mistakes

For this keynote named after the adage from Bob Ross and the Joy of painting, I wanted to talk about three aspects of my life as a developer: work at Microsoft, some demoscene projects and the Code Club I run with children aged 7-12. And highlight how important it is to give yourself a space where there are no mistakes; only happy accidents. Illustrating this idea with a LIVE coding session recreating a demoscene project and some lessons I learnt from this and applied directly at work.

Source

Video, slides and LIVE coding

Here are the video recordings of all the talks, my slides and a slightly polished version of the LIVE coding I did during the talk.

LIVE coding and notes

You can see the result of the LIVE coding session, the entire code but also the notes I wrote for this session since a few folks curious about that aspect of the talk.

Code

<!DOCTYPE html>
<link rel="stylesheet" href="style.css" />
<body>
  <img src="stars1.png" />
  <img src="stars2.png" />
  <img src="stars3.png" />
  <img src="stars4.png" />
  <img src="stars5.png" />
  <img src="stars6.png" />
  <img src="stars7.png" />
  <img src="stars8.png" />
  <canvas></canvas>
</body>
<script>
  const c = document.querySelector("canvas");
  const ctx = c.getContext("2d");

  const cols = 64;
  const rows = 32;
  const colors = ["transparent", "#f0c3", "#0fc6", "#fff"];

  // create cells
  const cellsCount = rows * cols;
  const cells = new Array(cellsCount).fill(0);
  let cellCurrentIndex = cellsCount;

  let chars = "";
  for (let i = 0; i < 64; i++) {
    chars += String.fromCharCode(0x2580 + i);
  }

  const renderFrame = timeNow => {
    requestAnimationFrame(renderFrame);
    c.width = (cols + 2) * 10;
    c.height = (rows + 2) * 10;

    ctx.textBaseline = "top";
    ctx.textAlign = "center";

    // prepare for the rotozoom
    const zoom = 16 + 4 * Math.sin(timeNow / 2329);
    const angle = timeNow / 9999;
    const cos = Math.cos(angle) / zoom;
    const sin = Math.sin(angle) / zoom;

    // cellular automaton
    let rule = timeNow / 270; // change rule every few ms
    rule &= 52 | 30; // limit the set of rules

    // move to the next row every few ms
    const cellNextIndex = timeNow / 70 * cols;
    for (; cellCurrentIndex < cellNextIndex; cellCurrentIndex++) {
      const glitch = Math.random() * 1.01;

      // check the neighbors
      const neighbors =
        cells[(cellCurrentIndex - 1) % cellsCount] +
        2 * cells[cellCurrentIndex % cellsCount] +
        4 * cells[(cellCurrentIndex + 1) % cellsCount];

      // compute the state of the cell for the next generation / row
      const something = ((rule >> neighbors) & 1) ^ glitch;
      cells[(cellCurrentIndex + cols) % cellsCount] = something;
    }

    // draw all the characters on our canvas
    for (let y = 0; y < rows; y++) {
      for (let x = 0; x < cols; x++) {
        const index = x + y * cols;
        const glitch = Math.random() * 1.01;

        // base charIndex
        let charIndex = x / 4 + timeNow / 300 + glitch;

        // rotated x,y coordinates
        const x2 = x * cos - y * sin + 5;
        const y2 = x * sin + y * cos + 5;

        // set of patterns
        const patterns = [x2 ^ y2, x2 % y2, x2 | y2, x2 & y2];
        // pick one every few ms
        const pattern = patterns[(timeNow / 1978) & 3];

        // base color index
        let colorIndex = pattern & 1;

        // use the cellular automat to change the colorIndex & charIndex
        colorIndex += 2 * cells[index];
        charIndex += 16 * cells[index];

        // render the character
        ctx.fillStyle = colors[colorIndex];
        const char = chars[charIndex & 63];
        ctx.fillText(char, (x + 1) * 10, (y + 1) * 10);
      }
    }

    // bloom
    ctx.filter = "blur(4px)";
    ctx.drawImage(c, 0, 0);
    ctx.filter = "blur(0px)";
  };

  renderFrame(0);
</script>

Notes

This is all the notes I had for this session. These are mostly to get an idea of the pacing and some small things that I shouldn't forget. You can imagine that it is easy to lose track when pair programming with 600 people.

show the images

zoom animation

add the animation delays

tilt animation

remove the outlines

start code

querySelector, getContext renderFrame = timeNow => {} requestAnimationFrame

draw the time to check it works

cols=64 rows=32 -> width and height

ctx.textBaseline = "top" ctx.textAlign = "center"

for (let y = 0; y < rows; y++) {
  for (let x = 0; x < cols; x++) {
    char = String.fromCharCoded(Math.random()*256);
    ctx.fillText(char, (1+x)*10,(1+y)*10);
  }
}
build list of chars from 0x2580 because it looks cool
let charIndex = (x / 8 + glitch + timeNow / 599) & 31;

Let's start the rotozoom

first a pattern x^y&1

zoom = 8

colorIndex = (x/zoom)^(y/zoom) & 1

colors = ["transparent", "#f0c", "#c0f6", "#fcf", "#f0c", "#fff"];

Introduce multiple patterns

[x^y, x%y, x|y, x&y]

rotozoom time

Add little glitch

add bloom

ctx.filter = "blur(4px)";
ctx.drawImage(c, 0, 0);
ctx.filter = "blur(0px)";
cellular automaton

const life = new Array(cols * rows).fill(0);
let lifeCurrentIndex = 0;
let lifeCurrentRule = 17;
lifeCurrentNextIndex = timeNow * rows / 12942
for(;lifeCurrentIndex<lifeNextIndex; lifeCurrentIndex++){
 life[(lifeCurrentIndex + rows) % life.length] = ...
}
colorIndex += 2*life[i];
charIndex |= life[i]*16

Feedback

The feedback right after the keynote was great. Several delegates and speakers, shared their inspiration from this session, and I hope you will appreciate this talk. In any case, let me know what you think on Twitter, email or in the video.


Other recent experiments

There are many experiments and projects like WE DON'T MAKE MISTAKES AT DEVONE 2019 to discover other here.


Let's talk

Don't be shy; get in touch by mail, twitter, github, linkedin or pouet if you have any questions, feedback, speaking, workshop or performance opportunity.