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.
Attachments: | |
---|---|
motion_induced_blindness.pde | |
motion_induced_blindness.scd |