My new and improved server-error page
I saw an excellent article recently describing how to implement the fire effect seen in the trailer for the N64/PlayStation ports of the DooM game. I figured this would be neat to put on the page displayed whenever there's a server error. I already have an awesome 404 page, and now I'm equally happy with the 500 page.
I made a few small modifications to the code presented in the article. I'm using a back-buffer that is half the size of the canvas, then relying on canvas APIs to scale-up the resulting image. I'm also using the canvas fillText
API to add text to the foreground of the canvas.
Check out the effect:
And here is the code:
function Fire(canvas_id, width, height, scale_factor) {
var scale_factor = (scale_factor ? scale_factor : 2),
width = (width ? width : 800) / scale_factor,
height = (height ? height : 600) / scale_factor,
canvas_id = canvas_id,
fire_data = [],
palette = [];
var fire_colors = [
0x07,0x07,0x07,
0x1F,0x1F,0x1F,
0x2F,0x0F,0x07,
0x47,0x0F,0x07,
0x57,0x17,0x07,
0x67,0x1F,0x07,
0x77,0x1F,0x07,
0x8F,0x27,0x07,
0x9F,0x2F,0x07,
0xAF,0x3F,0x07,
0xBF,0x47,0x07,
0xC7,0x47,0x07,
0xDF,0x4F,0x07,
0xDF,0x57,0x07,
0xDF,0x57,0x07,
0xD7,0x5F,0x07,
0xD7,0x5F,0x07,
0xD7,0x67,0x0F,
0xCF,0x6F,0x0F,
0xCF,0x77,0x0F,
0xCF,0x7F,0x0F,
0xCF,0x87,0x17,
0xC7,0x87,0x17,
0xC7,0x8F,0x17,
0xC7,0x97,0x1F,
0xBF,0x9F,0x1F,
0xBF,0x9F,0x1F,
0xBF,0xA7,0x27,
0xBF,0xA7,0x27,
0xBF,0xAF,0x2F,
0xB7,0xAF,0x2F,
0xB7,0xB7,0x2F,
0xB7,0xB7,0x37,
0xCF,0xCF,0x6F,
0xDF,0xDF,0x9F,
0xEF,0xEF,0xC7,
0xFF,0xFF,0xFF
];
// Seed palette with fire colors.
for (var i = 0, l = fire_colors.length / 3; i < l; i++) {
palette[i] = {
r: fire_colors[i * 3 + 0],
g: fire_colors[i * 3 + 1],
b: fire_colors[i * 3 + 2]
};
}
function init() {
// Initialize array representing the entire canvas.
// Set all pixels to palette index 0 (0x07, 0x07, 0x07).
for (var i = 0; i < width * height; i++) {
fire_data[i] = 0;
}
// Set bottom line to index 36, white.
for (var i = 0; i < width; i++) {
fire_data[(height - 1) * width + i] = 36;
}
}
function spread_fire(src) {
var pixel = fire_data[src];
if (pixel == 0) {
// Set pixel above to black.
fire_data[src - width] = 0;
} else {
var randIdx = Math.round(Math.random() * 3.0) & 3;
var dst = src - randIdx + 1;
var decrement = (Math.round(Math.random() * 2) < 1) ? 1 : 0;
fire_data[dst - width] = pixel - decrement;
}
}
function generate_fire() {
for (var x = 0; x < width; x++) {
for (var y = 1; y < height; y++) {
spread_fire(y * width + x);
}
}
}
// drawing routine
this.draw = function() {
// Step the fire.
generate_fire();
color = ctx.getImageData(0, 0, width, height);
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var idx = fire_data[y * width + x];
var pixel = palette[idx];
var offset = ((width * y) + x) * 4;
color.data[offset + 0] = pixel.r;
color.data[offset + 1] = pixel.g;
color.data[offset + 2] = pixel.b;
}
}
ctx.putImageData(color, 0, 0);
canvas_ctx.drawImage(buffer, 0, 0);
canvas_ctx.fillStyle = "#b7b737";
canvas_ctx.textAlign = "center";
canvas_ctx.font = "30px sans";
canvas_ctx.fillText("internal server error", width / 2, height / 2);
// calculate timeout using level
t = setTimeout("draw()", 30);
}
var buffer = document.createElement("canvas");
buffer.width = width;
buffer.height = height;
var ctx = buffer.getContext('2d');
var canvas = document.getElementById(canvas_id);
var canvas_ctx = canvas.getContext('2d');
// Fill canvas with black pixels.
canvas_ctx.scale(scale_factor, scale_factor);
canvas_ctx.imageSmoothingEnabled = false;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, width, height);
init();
return this;
}
Comments (0)
Commenting has been closed.