Brainfuck

HTML

<div id="controls">
    <textarea id="source">+++++++++++++++++++</textarea>
</div>
<canvas id="view"></canvas>

CSS

#controls {
    position: absolute;
    left:0;
    top:0;
    right:0;
    z-index: 3;
}
#controls textarea {
    width: 90%;
    margin-left: 30px;
}
#view {
    background: #fff;
}
body, html {
    background: #444;
    width: 100%;
    height: 100%;
    margin: 0px;
}

JavaScript

var view = document.getElementById("view");
var context = view.getContext("2d");
var slider = document.getElementById("slider");

var area = {
    top: 0,
    left: 0,
    right: 640,
    bottom: 480
};

function hsla(step) {
    return 'hsla(' + ((step * 30) | 0) + ',70%,70%,1)';
}

function Brainfuck() {
    this.ip = 0;
    this.source = "";
    this.jmp = [];
    this.jmpz = [];
    this.ptr = 0;
    this.memory = new Uint8Array(256);
    this.output = "";
    this.time = 0;
}

function sanitize(code){
    return code.replace(/[^<>+-\[\],\.]/g, "");
}

Brainfuck.prototype = {
    compile: function (source) {
        this.time = 0;
        this.finished = false;
        this.jmp = [];
        this.jmpz = [];
        this.source = sanitize(source);
        var jmps = [];
        for (var ip = 0; ip < this.source.length; ip += 1) {
            switch (this.source[ip]) {
                case "[":
                    jmps.push(ip);
                    this.jmp[ip] = ip + 1;
                    break;
                case "]":
                    var ret = jmps.pop();
                    this.jmp[ip] = ret;
                    this.jmpz[ret] = ip + 1;
                    break;
                default:
                    this.jmp[ip] = ip + 1;
            }
        }
        if (jmps.length !== 0) {
            throw "Unmatched loop.";
        }
    },
    step: function () {
        this.time += 1;
        if (this.ip >= this.source.length) {
            this.finished = true;
            return;
        }
        switch (this.source[this.ip]) {
            case ">":
                this.ptr = (this.ptr + 1) % 256;
                break;
            case "<":
                this.ptr = (this.ptr - 1 + 256) % 256;
                break;
            case "+":
                this.memory[this.ptr] += 1;
                break;
            case "-":
                this.memory[this.ptr] -= 1;
                break;
            case "]":
                this.ip =...