‹ Building SuperCollider for piCore Linux Keyboard Shortcuts ›

Motion Induced Blindness

2020-01-27 21:16 visuals

A fascinating illusion. Stare at the green dot for a bit.

More info here en.wikipedia.org/wiki/Motion-induced_blindness.

This is just a remake of the wikipedia GIF animation, but this JavaScript code and its variables/settings opens up for experimentation.

<div style="background-color:black;">
<canvas id="canvas" width="600" height="600"></canvas>
<script>
// motion-induced blindness after en.wikipedia.org/wiki/Motion-induced_blindness
(function () {
  const UPDATERATE = 1000.0 / 60.0 // 60fps
  const rotationRate = 0.1 // rps
  const blinkRate = 2.5 // Hz
  const numCrosses = 7
  const numDots = 3
  const dotRadius = 5
  const crossWidth = 0.1 // percent
  const crossWeight = 3
  const colorBackground = '#000'
  const colorCrosses = '#00F'
  const colorCenter = '#0F0'
  const colorDots = '#FF0'
  let lastTime = -1
  const can = document.getElementById('canvas') // EDIT name of canvas to draw to

  function draw () {
    const currTime = Date.now()
    if (currTime >= (lastTime + UPDATERATE)) {
      lastTime = currTime
      const bottom = can.getBoundingClientRect().bottom
      if (bottom >= 0 && bottom <= (innerHeight + can.height)) { // only draw when visible in browser
        const w2 = can.width * 0.5
        const h2 = can.height * 0.5
        const uw = can.width / 3

        const ctx = can.getContext('2d')
        ctx.fillStyle = colorBackground
        ctx.fillRect(0, 0, can.width, can.height)

        // --crosses
        ctx.save()
        ctx.translate(w2, h2)
        ctx.lineWidth = crossWeight
        ctx.strokeStyle = colorCrosses
        ctx.rotate(Date.now() / 1000 * Math.PI * 2 * rotationRate % (Math.PI * 2))
        ctx.beginPath()
        for (let i = 0; i < numCrosses; i++) {
          const y = i * (uw * 2) / (numCrosses - 1) - uw
          for (let j = 0; j < numCrosses; j++) {
            const x = j * (uw * 2) / (numCrosses - 1) - uw
            ctx.moveTo(x - (crossWidth * uw), y)
            ctx.lineTo(x + (crossWidth * uw), y)
            ctx.moveTo(x, y - (crossWidth * uw))
            ctx.lineTo(x, y + (crossWidth * uw))
          }
        }
        ctx.stroke()
        ctx.restore()

        // --center
        if ((Date.now() / 1000 * blinkRate) % 1 > 0.5) {
          ctx.beginPath()
          ctx.fillStyle = colorCenter
          ctx.ellipse(w2, h2, dotRadius, dotRadius, 0, 0, Math.PI * 2)
          ctx.fill()
        }

        // --dots
        ctx.save()
        ctx.translate(w2, h2)
        ctx.fillStyle = colorDots
        ctx.rotate(0.5 * Math.PI)
        for (let i = 0; i < numDots; i++) {
          ctx.beginPath()
          ctx.ellipse(can.width / 4, 0, dotRadius, dotRadius, 0, 0, Math.PI * 2)
          ctx.fill()
          ctx.rotate(Math.PI * 2 / numDots)
        }
        ctx.restore()
      }
    }
    window.requestAnimationFrame(draw)
  }
  draw()
})()
</script>
</div>

Also attached is the same code ported to Processing and SuperCollider.


‹ Building SuperCollider for piCore Linux Keyboard Shortcuts ›