├── README.md ├── chip.coffee ├── chip.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Chip 2 | 3 | http://sgentle.github.io/chip 4 | -------------------------------------------------------------------------------- /chip.coffee: -------------------------------------------------------------------------------- 1 | $ = document.querySelector.bind(document) 2 | canvas = $('#chip_canvas') 3 | ctx = canvas.getContext("2d") 4 | 5 | DATA_W = 250 6 | DATA_H = 250 7 | 8 | DATA_LENGTH = DATA_W*DATA_H 9 | 10 | data = new Uint8ClampedArray(DATA_LENGTH) 11 | newdata = new Uint8ClampedArray(DATA_LENGTH) 12 | 13 | drawdata = new Uint8ClampedArray(DATA_LENGTH*4) #RGBA 14 | 15 | setup = -> 16 | for i in [0...data.length] 17 | data[i] = Math.random() * 255 18 | for i in [0...drawdata.length] 19 | drawdata[i] = if i % 4 is 3 then 255 #Alpha channel 20 | 21 | setup() 22 | 23 | ctx.scale(canvas.width/DATA_W, canvas.height/DATA_H) 24 | ctx.globalCompositeOperation = "copy" 25 | 26 | ctx.imageSmoothingEnabled = false 27 | ctx[x+"ImageSmoothingEnabled"] = false for x in 'moz webkit ms'.split(' ') 28 | 29 | draw = -> 30 | ctx.clearRect(0, 0, canvas.width, canvas.height) 31 | for i in [0..drawdata.length] by 4 32 | drawdata[i] = drawdata[i+1] = drawdata[i+2] = data[i>>2] 33 | imageData = new ImageData(drawdata, DATA_W, DATA_H) 34 | ctx.putImageData(imageData, 0, 0) 35 | ctx.drawImage(ctx.canvas, 0, 0) 36 | 37 | rel = (n, x, y) -> 38 | i = n + x + y * DATA_W 39 | b = n % (DATA_W) + x 40 | return 0 if b > (DATA_W) or b < 0 or i >= DATA_LENGTH or i < 0 # prevent overflows 41 | data[i] 42 | 43 | window.rel = rel 44 | 45 | # CHIP 46 | SPAWN = 2.0 47 | LIVE = 2.0 48 | DIE = 3.0 49 | 50 | SPAWN_POWER = 0.5 51 | DIE_STARVE = 1/1.1 52 | DIE_CROWD = 1/1.1 53 | 54 | step = -> 55 | for i in [0...data.length] by 1 56 | neighbours = [ 57 | rel i, -1, -1 #top left 58 | rel i, 0, -1 #top 59 | rel i, +1, -1 #top right 60 | 61 | rel i, -1, 0 #left 62 | rel i, +1, 0 #right 63 | 64 | rel i, -1, +1 #bottom left 65 | rel i, 0, +1 #bottom 66 | rel i, +1, +1 #bottom right 67 | ] 68 | alive = 0 69 | sum = 0 70 | for n in neighbours 71 | alive++ if n >= 127 72 | sum += n 73 | avg = sum / neighbours.length 74 | 75 | if sum < LIVE*255 76 | newdata[i] = data[i] * DIE_STARVE 77 | else if sum > DIE*255 78 | newdata[i] = data[i] * DIE_CROWD 79 | else if sum >= SPAWN*255 80 | newdata[i] = data[i]*(1-SPAWN_POWER) + 255*SPAWN_POWER 81 | else 82 | newdata[i] = data[i] 83 | 84 | [data, newdata] = [newdata, data] 85 | 86 | started = false 87 | raf = -> 88 | started = true 89 | step() 90 | draw() 91 | requestAnimationFrame raf 92 | raf() 93 | canvas.addEventListener 'click', -> if started then setup() else raf() 94 | -------------------------------------------------------------------------------- /chip.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.9.3 2 | (function() { 3 | var $, DATA_H, DATA_LENGTH, DATA_W, DIE, DIE_CROWD, DIE_STARVE, LIVE, SPAWN, SPAWN_POWER, canvas, ctx, data, draw, drawdata, j, len, newdata, raf, ref, rel, setup, started, step, x; 4 | 5 | $ = document.querySelector.bind(document); 6 | 7 | canvas = $('#chip_canvas'); 8 | 9 | ctx = canvas.getContext("2d"); 10 | 11 | DATA_W = 250; 12 | 13 | DATA_H = 250; 14 | 15 | DATA_LENGTH = DATA_W * DATA_H; 16 | 17 | data = new Uint8ClampedArray(DATA_LENGTH); 18 | 19 | newdata = new Uint8ClampedArray(DATA_LENGTH); 20 | 21 | drawdata = new Uint8ClampedArray(DATA_LENGTH * 4); 22 | 23 | setup = function() { 24 | var i, j, k, ref, ref1, results; 25 | for (i = j = 0, ref = data.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { 26 | data[i] = Math.random() * 255; 27 | } 28 | results = []; 29 | for (i = k = 0, ref1 = drawdata.length; 0 <= ref1 ? k < ref1 : k > ref1; i = 0 <= ref1 ? ++k : --k) { 30 | results.push(drawdata[i] = i % 4 === 3 ? 255 : void 0); 31 | } 32 | return results; 33 | }; 34 | 35 | setup(); 36 | 37 | ctx.scale(canvas.width / DATA_W, canvas.height / DATA_H); 38 | 39 | ctx.globalCompositeOperation = "copy"; 40 | 41 | ctx.imageSmoothingEnabled = false; 42 | 43 | ref = 'moz webkit ms'.split(' '); 44 | for (j = 0, len = ref.length; j < len; j++) { 45 | x = ref[j]; 46 | ctx[x + "ImageSmoothingEnabled"] = false; 47 | } 48 | 49 | draw = function() { 50 | var i, imageData, k, ref1; 51 | ctx.clearRect(0, 0, canvas.width, canvas.height); 52 | for (i = k = 0, ref1 = drawdata.length; k <= ref1; i = k += 4) { 53 | drawdata[i] = drawdata[i + 1] = drawdata[i + 2] = data[i >> 2]; 54 | } 55 | imageData = new ImageData(drawdata, DATA_W, DATA_H); 56 | ctx.putImageData(imageData, 0, 0); 57 | return ctx.drawImage(ctx.canvas, 0, 0); 58 | }; 59 | 60 | rel = function(n, x, y) { 61 | var b, i; 62 | i = n + x + y * DATA_W; 63 | b = n % DATA_W + x; 64 | if (b > DATA_W || b < 0 || i >= DATA_LENGTH || i < 0) { 65 | return 0; 66 | } 67 | return data[i]; 68 | }; 69 | 70 | window.rel = rel; 71 | 72 | SPAWN = 2.0; 73 | 74 | LIVE = 2.0; 75 | 76 | DIE = 3.0; 77 | 78 | SPAWN_POWER = 0.5; 79 | 80 | DIE_STARVE = 1 / 1.1; 81 | 82 | DIE_CROWD = 1 / 1.1; 83 | 84 | step = function() { 85 | var alive, avg, i, k, l, len1, n, neighbours, ref1, ref2, sum; 86 | for (i = k = 0, ref1 = data.length; k < ref1; i = k += 1) { 87 | neighbours = [rel(i, -1, -1), rel(i, 0, -1), rel(i, +1, -1), rel(i, -1, 0), rel(i, +1, 0), rel(i, -1, +1), rel(i, 0, +1), rel(i, +1, +1)]; 88 | alive = 0; 89 | sum = 0; 90 | for (l = 0, len1 = neighbours.length; l < len1; l++) { 91 | n = neighbours[l]; 92 | if (n >= 127) { 93 | alive++; 94 | } 95 | sum += n; 96 | } 97 | avg = sum / neighbours.length; 98 | if (sum < LIVE * 255) { 99 | newdata[i] = data[i] * DIE_STARVE; 100 | } else if (sum > DIE * 255) { 101 | newdata[i] = data[i] * DIE_CROWD; 102 | } else if (sum >= SPAWN * 255) { 103 | newdata[i] = data[i] * (1 - SPAWN_POWER) + 255 * SPAWN_POWER; 104 | } else { 105 | newdata[i] = data[i]; 106 | } 107 | } 108 | return ref2 = [newdata, data], data = ref2[0], newdata = ref2[1], ref2; 109 | }; 110 | 111 | started = false; 112 | 113 | raf = function() { 114 | started = true; 115 | step(); 116 | draw(); 117 | return requestAnimationFrame(raf); 118 | }; 119 | 120 | raf(); 121 | 122 | canvas.addEventListener('click', function() { 123 | if (started) { 124 | return setup(); 125 | } else { 126 | return raf(); 127 | } 128 | }); 129 | 130 | }).call(this); 131 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------