Skip to content

Instantly share code, notes, and snippets.

@bubach
Created April 16, 2020 21:26
Show Gist options
  • Save bubach/4b677d4fcbdb33477cb5419f83adec3f to your computer and use it in GitHub Desktop.
Save bubach/4b677d4fcbdb33477cb5419f83adec3f to your computer and use it in GitHub Desktop.
Fire!
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="/js/lib/dummy.js"></script>
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<style id="compiled-css" type="text/css">
body {
background-color: black;
color: white;
}
body, #game {
display: block;
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
padding: 0;
border: 0;
margin: auto;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="game" width="80" height="48" style="height: 278px; width: 444px;"></canvas>
<!-- TODO: Missing CoffeeScript 2 -->
<script type="text/javascript">//<![CDATA[
var FirePalette = (function() {
var pal = [
0, 0, 0, 0, 1, 1, 0, 4, 5, 0, 7, 9,
0, 8, 11, 0, 9, 12, 15, 6, 8, 25, 4, 4,
33, 3, 3, 40, 2, 2, 48, 2, 2, 55, 1, 1,
63, 0, 0, 63, 0, 0, 63, 3, 0, 63, 7, 0,
63, 10, 0, 63, 13, 0, 63, 16, 0, 63, 20, 0,
63, 23, 0, 63, 26, 0, 63, 29, 0, 63, 33, 0,
63, 36, 0, 63, 39, 0, 63, 39, 0, 63, 40, 0,
63, 40, 0, 63, 41, 0, 63, 42, 0, 63, 42, 0,
63, 43, 0, 63, 44, 0, 63, 44, 0, 63, 45, 0,
63, 45, 0, 63, 46, 0, 63, 47, 0, 63, 47, 0,
63, 48, 0, 63, 49, 0, 63, 49, 0, 63, 50, 0,
63, 51, 0, 63, 51, 0, 63, 52, 0, 63, 53, 0,
63, 53, 0, 63, 54, 0, 63, 55, 0, 63, 55, 0,
63, 56, 0, 63, 57, 0, 63, 57, 0, 63, 58, 0,
63, 58, 0, 63, 59, 0, 63, 60, 0, 63, 60, 0,
63, 61, 0, 63, 62, 0, 63, 62, 0, 63, 63, 0];
var realPalette = new Array(256*3);
var i = 0;
for (; i < pal.length; ++i) {
realPalette[i] = Math.floor(pal[i]*255/63);
}
// Fill the upper 192 entries with pure white
for (; i < realPalette.length; ++i) {
realPalette[i] = 255;
}
return realPalette;
})();
var Fire = function() {
this.w = 80;
this.h = 50;
this.Reset();
}
Fire.prototype.Reset = function() {
var s = this.w * this.h;
function makeBuf() {
var g = new Array(s);
for (var j = 0; j < s; ++j) {
g[j] = 0;
}
return g;
}
this.backbuffer = makeBuf();
this.tempbuffer = makeBuf();
}
Fire.prototype.tick = function() {
var src = this.backbuffer;
var temp = this.tempbuffer;
var w = this.w;
var h = this.h;
// Transform backbuffer spreading the heat, cooling down and randomly creating sparks below
var max = w * (h - 1) - 1;
var coolmax = w * (h - 4);
for (var i = w + 1; i < max; ++i) {
// Average neighbours - this spreads the heat
var v = src[i - 1 - w] +
src[i - w] +
src[i + 1 - w] +
src[i - 1] +
src[i + 1] +
src[i - 1 + w] +
src[i + w] +
src[i + 1 + w];
var finalv = Math.floor(v / 8);
// 25% of cells in a more or less random selection will be cooled
var bcool = v & 3;
// We cool cells only if they are not zero already - *except* in the lower lines of the buffer
// Cooling zero pixels in the lower area will 'wrap around' into random hot pixels
// Incidentally, in the beginning all pixels wrap, meaning a big explosion
if (!bcool && (i >= coolmax || finalv > 0)) {
finalv = (255 + finalv) % 256;
}
temp[i] = finalv;
}
// Scroll up & copy back the results
max = w * (h - 2);
for (var x = 0; x < max; ++x) {
src[x] = temp[x + w];
}
// Smooth bottom rows - just for rendering
max = w * (h - 1);
for (var x = w * (h - 6); x < max; ++x) {
if (temp[x] < 15) {
temp[x] = (255 - temp[x] + 22) % 256;
}
}
}
Fire.prototype.render = function(dest, offset) {
var s = this.w * (this.h - offset);
var g = this.tempbuffer;
for (var j = 0, i = 0; j < s; ++j, i += 4) {
dest[i] = FirePalette[g[j] * 3];
dest[i + 1] = FirePalette[g[j] * 3 + 1];
dest[i + 2] = FirePalette[g[j] * 3 + 2];
dest[i + 3] = 255;
}
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 );
};
})();
}
window.onload = function() {
var fire = new Fire();
var offset = 2; // Skip the bottom 2 lines when blitting to screen - too noisy and ugly
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
canvas.width = fire.w;
canvas.height = fire.h - offset;
// Resizing support
function resizeCanvas() {
var wr = document.body.clientWidth / document.body.clientHeight;
var fr = fire.w / fire.h;
if (wr < fr) {
canvas.style.width = document.body.clientWidth + 'px';
canvas.style.height = Math.floor(document.body.clientWidth / fr) + 'px';
} else {
canvas.style.height = document.body.clientHeight+"px";
canvas.style.width = Math.floor(document.body.clientHeight * fr) + 'px';
}
}
window.addEventListener('resize', resizeCanvas);
document.addEventListener('orientationChanged', resizeCanvas);
resizeCanvas();
// Prevent panning & make canvas clickable
document.addEventListener('touchmove', function(e) {
e.preventDefault();
});
var id = ctx.createImageData(canvas.width, canvas.height);
// Main loop
var tick = function() {
fire.tick();
fire.render(id.data, offset);
ctx.putImageData(id, 0, 0);
requestAnimationFrame(tick);
}
tick(); // Go!
}
//]]></script>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: ""
}], "*")
}
// always overwrite window.name, in case users try to set it manually
window.name = "result"
</script>
</body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment