cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              <canvas id = "canvas"></canvas>
            
          
!
            
              
body { margin: 0; overflow: hidden; background: #111; color: #ccc; }
#canvas {
  position: absolute;
  top:0;
  bottom: 0;
  left: 0;
  right: 0;

  width: 100%;
  height: 100%;

  image-rendering: optimizeSpeed;
  image-rendering: -moz-crisp-edges;
  image-rendering: -webkit-optimize-contrast;
  image-rendering: -o-crisp-edges;
  image-rendering: pixelated;
  -ms-interpolation-mode: nearest-neighbor;

  cursor: none;

  margin: auto;


}

            
          
!
            
              // stats.js - http://github.com/mrdoob/stats.js
var Stats=function(){function h(a){c.appendChild(a.dom);return a}function k(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?"block":"none";l=a}var l=0,c=document.createElement("div");c.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";c.addEventListener("click",function(a){a.preventDefault();k(++l%c.children.length)},!1);var g=(performance||Date).now(),e=g,a=0,r=h(new Stats.Panel("FPS","#0ff","#002")),f=h(new Stats.Panel("MS","#0f0","#020"));
    if(self.performance&&self.performance.memory)var t=h(new Stats.Panel("MB","#f08","#201"));k(0);return{REVISION:16,dom:c,addPanel:h,showPanel:k,begin:function(){g=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();f.update(c-g,200);if(c>e+1E3&&(r.update(1E3*a/(c-e),100),e=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){g=this.end()},domElement:c,setMode:k}};
Stats.Panel=function(h,k,l){var c=Infinity,g=0,e=Math.round,a=e(window.devicePixelRatio||1),r=80*a,f=48*a,t=3*a,u=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=f;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,f);b.fillStyle=k;b.fillText(h,t,u);b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(f,
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         v){c=Math.min(c,f);g=Math.max(g,f);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=k;b.fillText(e(f)+" "+h+" ("+e(c)+"-"+e(g)+")",t,u);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,e((1-f/v)*p))}}};"object"===typeof module&&(module.exports=Stats);
ENGINE = {
    E: this,


    /*
     screen memory

     each px:

     000 /flags? 00000 /color -32 color index
     */

    screen: 0x00000,
    page1: 0x10000,
    page2: 0x20000,
    page3: 0x30000,
    page4: 0x40000,
    page5: 0x50000,
    page6: 0x60000,
    page7: 0x70000,

    //DB32 Palette
    colors: [0xff000000, 0xff342022, 0xff3c2845, 0xff313966, 0xff3b568f, 0xff2671df, 0xff66a0d9, 0xff9ac3ee, 0xff36f2fb,
        0xff50e599, 0xff30be6a, 0xff6e9437, 0xff2f694b, 0xff244b52, 0xff393c32, 0xff743f3f, 0xff826030, 0xffe16e5b,
        0xffff9b63, 0xffe4cd5f, 0xfffcdbcb, 0xffffffff, 0xffb7ad9b, 0xff877e84, 0xff6a6a69, 0xff525659, 0xff8a4276,
        0xff3232ac, 0xff6357d9, 0xffba7bd7, 0xff4a978f, 0xff306f8a],

    brightness: [0,1,2,14,3,15,13,27,26,25,16,4,12,24,31,28,17,23,11,5,30,29,18,6,10,22,19,7,9,20,8,21],

    palDefault: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],

    pal: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],

    renderTarget: 0x00000,

    renderSource: 0x10000,

    currentState: 0,

    //col enum
    // col: {
    //     Black: 0,
    //     Valhalla: 1,
    //     LouLou: 2,
    //     OiledCedar: 3,
    //     Rope: 4,
    //     TahitiGold: 5,
    //     Twine: 6,
    //     Pancho: 7,
    //     GoldenFizz: 8,
    //     Atlantis: 9,
    //     Christi: 10,
    //     ElfGreen: 11,
    //     Dell: 12,
    //     Verdigris: 13,
    //     Opal: 14,
    //     DeepKoamaru: 15,
    //     VeniceBlue: 16,
    //     RoyalBlue: 17,
    //     Cornflower: 18,
    //     Viking: 19,
    //     LightSteelBlue: 20,
    //     White: 21,
    //     Heather: 22,
    //     Topaz: 23,
    //     DimGray: 24,
    //     SmokeyAsh: 25,
    //     Clairvoyant: 26,
    //     Red: 27,
    //     Mandy: 28,
    //     PinkPlum: 29,
    //     RainForest: 30,
    //     Stinger: 31
    // },

    gfx: {

        clear: function(color){
            E.ram.fill(color, E.renderTarget, E.renderTarget + 0x10000);
        },

        pset: function (x, y, color) { //from colors array, 0-31
            x = x|0; y = y|0;
            //color = Math.max(0, Math.min(color, 31))|0;

            if (x > -1 && x < 256 && y > -1 && y < 256) {
                E.ram[E.renderTarget + (y * 256 + x)] = color;
            }
        },

        line: function (x1, y1, x2, y2, color) {

            x1 = x1|0;
            x2 = x2|0;
            y1 = y1|0;
            y2 = y2|0;

            var dy = (y2 - y1);
            var dx = (x2 - x1);
            var stepx, stepy;

            if (dy < 0) {
                dy = -dy;
                stepy = -1;
            } else {
                stepy = 1;
            }
            if (dx < 0) {
                dx = -dx;
                stepx = -1;
            } else {
                stepx = 1;
            }
            dy <<= 1;        // dy is now 2*dy
            dx <<= 1;        // dx is now 2*dx

            this.pset(x1, y1, color);
            if (dx > dy) {
                var fraction = dy - (dx >> 1);  // same as 2*dy - dx
                while (x1 != x2) {
                    if (fraction >= 0) {
                        y1 += stepy;
                        fraction -= dx;          // same as fraction -= 2*dx
                    }
                    x1 += stepx;
                    fraction += dy;              // same as fraction -= 2*dy
                    this.pset(x1, y1, color);
                }
                ;
            } else {
                fraction = dx - (dy >> 1);
                while (y1 != y2) {
                    if (fraction >= 0) {
                        x1 += stepx;
                        fraction -= dy;
                    }
                    y1 += stepy;
                    fraction += dx;
                    this.pset(x1, y1, color);
                }
            }

        },

        circle: function (xm, ym, r, color) {
            var x = -r, y = 0, err = 2 - 2 * r;
            /* II. Quadrant */
            do {

                this.pset(xm - x, ym + y, color);
                /*   I. Quadrant */
                this.pset(xm - y, ym - x, color);
                /*  II. Quadrant */
                this.pset(xm + x, ym - y, color);
                /* III. Quadrant */
                this.pset(xm + y, ym + x, color);
                /*  IV. Quadrant */
                r = err;
                if (r <= y) err += ++y * 2 + 1;
                /* e_xy+e_y < 0 */
                if (r > x || err > y) err += ++x * 2 + 1;
                /* e_xy+e_x > 0 or no 2nd y-step */

            } while (x < 0);
        },

        fillCircle: function (xm, ym, r, color) {
            xm = xm|0; ym = ym|0, r = r|0; color = color|0;
            var x = -r, y = 0, err = 2 - 2 * r;
            /* II. Quadrant */
            do {
                this.line(xm-x, ym-y, xm+x, ym-y, color);
                this.line(xm-x, ym+y, xm+x, ym+y, color);
                r = err;
                if (r <= y) err += ++y * 2 + 1;
                if (r > x || err > y) err += ++x * 2 + 1;
            } while (x < 0);
        },

        rect: function (x1, y1, x2, y2, color) {
            x1 = x1|0;
            x2 = x2|0;
            y1 = y1|0;
            y2 = y2|0;


            this.line(x1,y1, x2, y1, color);
            this.line(x2, y1, x2, y2, color);
            this.line(x1, y2, x2, y2, color);
            this.line(x1, y1, x1, y2, color);
        },

        fillRect: function (x1, y1, x2, y2, color) {

            x1 = x1|0;
            x2 = x2|0;
            y1 = y1|0;
            y2 = y2|0;

            var i = Math.abs(y2 - y1);
            E.gfx.line(x1, y1, x2, y1, color);

            if(i > 0){
                while (--i) {
                    E.gfx.line(x1, y1+i, x2, y1+i, color);
                }
            }

            E.gfx.line(x1,y2, x2, y2, color);
        },

        triangle: function (x1, y1, x2, y2, x3, y3, color) {
          E.gfx.line(x1,y1, x2,y2, color);
          E.gfx.line(x2,y2, x3,y3, color);
          E.gfx.line(x3,y3, x1,y1, color);
        },

        fillTriangle: function( x1, y1, x2, y2, x3, y3, color ) {

          var canvasWidth = 256;
          // http://devmaster.net/forums/topic/1145-advanced-rasterization/
          // 28.4 fixed-point coordinates
          var x1 = Math.round( 16 * x1 );
          var x2 = Math.round( 16 * x2 );
          var x3 = Math.round( 16 * x3 );
          var y1 = Math.round( 16 * y1 );
          var y2 = Math.round( 16 * y2 );
          var y3 = Math.round( 16 * y3 );
          // Deltas
          var dx12 = x1 - x2, dy12 = y2 - y1;
          var dx23 = x2 - x3, dy23 = y3 - y2;
          var dx31 = x3 - x1, dy31 = y1 - y3;
          // Bounding rectangle
          var minx = Math.max( ( Math.min( x1, x2, x3 ) + 0xf ) >> 4, 0 );
          var maxx = Math.min( ( Math.max( x1, x2, x3 ) + 0xf ) >> 4, 256 );
          var miny = Math.max( ( Math.min( y1, y2, y3 ) + 0xf ) >> 4, 0 );
          var maxy = Math.min( ( Math.max( y1, y2, y3 ) + 0xf ) >> 4, 256 );
          // Block size, standard 8x8 (must be power of two)
          var q = 8;
          // Start in corner of 8x8 block
          minx &= ~(q - 1);
          miny &= ~(q - 1);
          // Constant part of half-edge functions
          var c1 = -dy12 * x1 - dx12 * y1;
          var c2 = -dy23 * x2 - dx23 * y2;
          var c3 = -dy31 * x3 - dx31 * y3;
          // Correct for fill convention
          if ( dy12 > 0 || ( dy12 == 0 && dx12 > 0 ) ) c1 ++;
          if ( dy23 > 0 || ( dy23 == 0 && dx23 > 0 ) ) c2 ++;
          if ( dy31 > 0 || ( dy31 == 0 && dx31 > 0 ) ) c3 ++;
          // Note this doesn't kill subpixel precision, but only because we test for >=0 (not >0).
          // It's a bit subtle. :)
          c1 = (c1 - 1) >> 4;
          c2 = (c2 - 1) >> 4;
          c3 = (c3 - 1) >> 4;
          // Set up min/max corners
          var qm1 = q - 1; // for convenience
          var nmin1 = 0, nmax1 = 0;
          var nmin2 = 0, nmax2 = 0;
          var nmin3 = 0, nmax3 = 0;
          if (dx12 >= 0) nmax1 -= qm1*dx12; else nmin1 -= qm1*dx12;
          if (dy12 >= 0) nmax1 -= qm1*dy12; else nmin1 -= qm1*dy12;
          if (dx23 >= 0) nmax2 -= qm1*dx23; else nmin2 -= qm1*dx23;
          if (dy23 >= 0) nmax2 -= qm1*dy23; else nmin2 -= qm1*dy23;
          if (dx31 >= 0) nmax3 -= qm1*dx31; else nmin3 -= qm1*dx31;
          if (dy31 >= 0) nmax3 -= qm1*dy31; else nmin3 -= qm1*dy31;
          // Loop through blocks
          var linestep = (canvasWidth-q);
          for ( var y0 = miny; y0 < maxy; y0 += q ) {
            for ( var x0 = minx; x0 < maxx; x0 += q ) {
              // Edge functions at top-left corner
              var cy1 = c1 + dx12 * y0 + dy12 * x0;
              var cy2 = c2 + dx23 * y0 + dy23 * x0;
              var cy3 = c3 + dx31 * y0 + dy31 * x0;
              // Skip block when at least one edge completely out
              if (cy1 < nmax1 || cy2 < nmax2 || cy3 < nmax3) continue;
              // Offset at top-left corner
              var offset = (x0 + y0 * canvasWidth);
              // Accept whole block when fully covered
              if (cy1 >= nmin1 && cy2 >= nmin2 && cy3 >= nmin3) {
                for ( var iy = 0; iy < q; iy ++ ) {
                  for ( var ix = 0; ix < q; ix ++, offset ++ ) {
                    E.ram[E.renderTarget + offset] = color;
                  }
                  offset += linestep;
                }
              } else { // Partially covered block
                for ( var iy = 0; iy < q; iy ++ ) {
                  var cx1 = cy1;
                  var cx2 = cy2;
                  var cx3 = cy3;
                  for ( var ix = 0; ix < q; ix ++ ) {
                    if ( (cx1 | cx2 | cx3) >= 0 ) {
                      E.ram[E.renderTarget + offset] = color;
                    }
                    cx1 += dy12;
                    cx2 += dy23;
                    cx3 += dy31;
                    offset ++;
                  }
                  cy1 += dx12;
                  cy2 += dx23;
                  cy3 += dx31;
                  offset += linestep;
                }
              }
            }
          }
        },

        spr: function(sx = 0, sy = 0, sw = 16, sh = 16, x=0, y=0, flipx = false, flipy = false){


                for(var i = 0; i < sh; i++){

                    for(var j = 0; j < sw; j++){

                        if(y+i < 255 && x+j < 255 && y+i > -1 && x+j > -1){
                            if(flipx & flipy){

                                if(E.ram[(E.renderSource + ( ( sy + (sh-i) )*256+sx+(sw-j)))] > 0) {

                                //E.ram[ (E.renderTarget + ((y+i)*256+x+j)) ] = 21;

                                E.ram[ (E.renderTarget + ((y+i)*256+x+j)) ] = E.pal[ E.ram[(E.renderSource + ((sy+(sh-i))*256+sx+(sw-j)))] ];

                                }

                            }
                            else if(flipy && !flipx){

                                if(E.ram[(E.renderSource + ( ( sy + (sh-i) )*256+sx+j))] > 0) {

                                E.ram[ (E.renderTarget + ((y+i)*256+x+j)) ] = E.ram[(E.renderSource + ((sy+(sh-i))*256+sx+j))];

                                }

                            }
                            else if(flipx && !flipy){

                                if(E.ram[(E.renderSource + ((sy+i)*256+sx+(sw-j)))] > 0) {

                                E.ram[ (E.renderTarget + ((y+i)*256+x+j)) ] = E.ram[(E.renderSource + ((sy+i)*256+sx+(sw-j)))];

                                }

                            }
                            else if(!flipx && !flipy){

                                if(E.ram[(E.renderSource + ((sy+i)*256+sx+j))] > 0) {

                                E.ram[ (E.renderTarget + ((y+i)*256+x+j)) ] = E.pal[ E.ram[(E.renderSource + ((sy+i)*256+sx+j))] ];

                                }

                            }
                        }
                    }
                }
        },

        sspr: function(sx = 0, sy = 0, sw = 16, sh = 16, x=0, y=0, dw=16, dh=16, flipx = false, flipy = false){

            var xratio = sw / dw;
            var yratio = sh / dh;

            for(var i = 0; i < dh; i++){
                for(var j = 0; j < dw; j++){

                    px = (j*xratio)|0;
                    py = (i*yratio)|0;

                    if(y+i < 255 && x+j < 255 && y+i > -1 && x+j > -1) {
                        if (E.ram[(E.renderSource + ((sy + py) * 256 + sx + px))] > 0) {
                            E.ram[(E.renderTarget + ((y + i) * 256 + x + j))] = E.ram[(E.renderSource + ((sy + py) * 256 + sx + px))]
                        }
                    }

                }
            }


        },

        checker: function(nRow, nCol, color) {
          var w = 256;
          var h = 256;
          var x = 0;
          var y = 0;

          nRow = nRow || 8;    // default number of rows
          nCol = nCol || 8;    // default number of columns

          w /= nCol;            // width of a block
          h /= nRow;            // height of a block

          for (var i = 0; i < nRow; ++i) {
              for (var j = 0, col = nCol / 2; j < col; ++j) {
                x = 2 * j * w + (i % 2 ? 0 : w);
                y = i * h;
                  E.gfx.fillRect(x, y, x+w, y+h, color);
              }
          }
        }
    },

    UIObject: {
        intersects: function(obj, mouse) {
            var t = 5; //tolerance
            var xIntersect = (mouse.x + t) > obj.x && (mouse.x - t) < obj.x + obj.width;
            var yIntersect = (mouse.y + t) > obj.y && (mouse.y - t) < obj.y + obj.height;
            return  xIntersect && yIntersect;
        },
        updateStats: function(canvas){
            if (this.intersects(this, canvas.mouse)) {
                this.hovered = true;
                if (canvas.mouse.clicked) {
                    this.clicked = true;
                }
            } else {
                this.hovered = false;
            }

            if (!canvas.mouse.down) {
                this.clicked = false;
            }
        }
    },

    imagetoRam: function(image, address) {

        let tempCanvas = document.createElement('canvas');
        tempCanvas.width = 256;
        tempCanvas.height = 256;
        let context = tempCanvas.getContext('2d');
        //draw image to canvas
        context.drawImage(image, 0, 0);

        //get image data
        var imageData = context.getImageData(0,0, 256, 256);

        //set up 32bit view of buffer
        let data = new Uint32Array(imageData.data.buffer);

        //compare buffer to palette (loop)
        for(var i = 0; i < data.length; i++) {
            //set ram to color index
            E.ram[address + i] = E.colors.indexOf(data[i]);
            //console.log(data[i]);
        }


    },

    screenCapture: function (canvas) {

        var image = canvas.toDataURL("image/png");

        window.open(image);

    },

    memoryCapture: function () {

        console.log(E.ram);

        //var tmpcanvas = document.createElement('canvas');
        //var ctx = tmpcanvas.getContext('2d');
        //tmpcanvas.width = 256;
        //tmpcanvas.height = 256;
        //var ramimage = ctx.getImageData(0,0, 256, 256);
        //
        //
        //var buf = new ArrayBuffer(ramimage.data.length);
        //console.log(ramimage.data.length, E.ram.length);
        ////var buf8 = new Uint8ClampedArray(buf);
        //var data = new Uint32Array(buf);
        //
        //ramimage.data.set(E.ram);
        //ctx.putImageData(ramimage, 0,0);
        //console.log(ramimage);
        //var ramcapture = tmpcanvas.toDataURL("image/png");
        //window.open(ramcapture);

    },

    canvasInit: function () {

        E.canvas = document.getElementById('canvas');
        E.ctx = canvas.getContext('2d');
        E.canvas.width = window.innerWidth;
        E.canvas.height = window.innerHeight;
        E.ctx.imageSmoothingEnabled = false;
        E.ctx.mozImageSmoothingEnabled = false;

        E.smallcanvas = document.createElement('canvas');
        E.smallctx = E.smallcanvas.getContext('2d');
        E.smallcanvas.width = 256;
        E.smallcanvas.height = 256;
        E.canvasHeight = E.smallcanvas.height;
        E.canvasWidth = E.smallcanvas.width;
        E.imageData = E.smallctx.getImageData(0, 0, E.canvasWidth, E.canvasHeight);

        E.buf = new ArrayBuffer(E.imageData.data.length);
        E.buf8 = new Uint8ClampedArray(E.buf);
        E.data = new Uint32Array(E.buf);
       // console.log(E.buf.length, E.buf8.length, E.data.length);
        E.ram = new Uint8ClampedArray(0x80000);

        E.renderTarget = E.screen;



    },

    render: function () {

        var i = 0x10000;  // display is first 0x10000 bytes of ram

        while (i--) {
            E.data[i] = E.colors[E.pal[E.ram[i]]]; //data is 32bit view of final screen buffer

        }

        E.imageData.data.set(E.buf8);

        E.smallctx.putImageData(E.imageData, 0, 0);
        //E.ctx.putImageData(E.imageData, 0, 0);

        //E.ctx.drawImage(E.smallcanvas, 0, 0);
        E.compositeSize = window.innerWidth < window.innerHeight ? window.innerWidth : window.innerHeight;
        E.compositeOrigin = ( (window.innerWidth - E.compositeSize)/2)|0;
        E.ctx.imageSmoothingEnabled = false;
        E.ctx.mozImageSmoothingEnabled = false;

        E.ctx.drawImage(E.smallcanvas, 0, 0, 255, 255, E.compositeOrigin, 0, E.compositeSize, E.compositeSize);



    },

    switchState: function(state) {
            if(arguments.length > 0){app.setState(E.states[state])}
            else{

              E.currentState += 1;
              if(E.currentState > E.states.length-1){
                  E.currentState = 0;
              }
              app.setState(E.states[E.currentState]);

            }



    }


}

var E = ENGINE;

Number.prototype.map = function (in_min, in_max, out_min, out_max) {
    return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//---------SONANT-X---------
/*
// Sonant-X
//
// Copyright (c) 2014 Nicolas Vanhoren
//
// Sonant-X is a fork of js-sonant by Marcus Geelnard and Jake Taylor. It is
// still published using the same license (zlib license, see below).
//
// Copyright (c) 2011 Marcus Geelnard
// Copyright (c) 2008-2009 Jake Taylor
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
*/

var sonantx = {};

var WAVE_SPS = 44100;                    // Samples per second
var WAVE_CHAN = 2;                       // Channels
var MAX_TIME = 33; // maximum time, in millis, that the generator can use consecutively

var audioCtx = null;

// Oscillators
function osc_sin(value)
{
    return Math.sin(value * 6.283184);
}

function osc_square(value)
{
    if(osc_sin(value) < 0) return -1;
    return 1;
}

function osc_saw(value)
{
    return (value % 1) - 0.5;
}

function osc_tri(value)
{
    var v2 = (value % 1) * 4;
    if(v2 < 2) return v2 - 1;
    return 3 - v2;
}

// Array of oscillator functions
var oscillators =
[
    osc_sin,
    osc_square,
    osc_saw,
    osc_tri
];

function getnotefreq(n)
{
    return 0.00390625 * Math.pow(1.059463094, n - 128);
}

function genBuffer(waveSize, callBack) {
    setTimeout(function() {
        // Create the channel work buffer
        var buf = new Uint8Array(waveSize * WAVE_CHAN * 2);
        var b = buf.length - 2;
        var iterate = function() {
            var begin = new Date();
            var count = 0;
            while(b >= 0)
            {
                buf[b] = 0;
                buf[b + 1] = 128;
                b -= 2;
                count += 1;
                if (count % 1000 === 0 && (new Date() - begin) > MAX_TIME) {
                    setTimeout(iterate, 0);
                    return;
                }
            }
            setTimeout(function() {callBack(buf);}, 0);
        };
        setTimeout(iterate, 0);
    }, 0);
}

function applyDelay(chnBuf, waveSamples, instr, rowLen, callBack) {
    var p1 = (instr.fx_delay_time * rowLen) >> 1;
    var t1 = instr.fx_delay_amt / 255;

    var n1 = 0;
    var iterate = function() {
        var beginning = new Date();
        var count = 0;
        while(n1 < waveSamples - p1)
        {
            var b1 = 4 * n1;
            var l = 4 * (n1 + p1);

            // Left channel = left + right[-p1] * t1
            var x1 = chnBuf[l] + (chnBuf[l+1] << 8) +
                (chnBuf[b1+2] + (chnBuf[b1+3] << 8) - 32768) * t1;
            chnBuf[l] = x1 & 255;
            chnBuf[l+1] = (x1 >> 8) & 255;

            // Right channel = right + left[-p1] * t1
            x1 = chnBuf[l+2] + (chnBuf[l+3] << 8) +
                (chnBuf[b1] + (chnBuf[b1+1] << 8) - 32768) * t1;
            chnBuf[l+2] = x1 & 255;
            chnBuf[l+3] = (x1 >> 8) & 255;
            ++n1;
            count += 1;
            if (count % 1000 === 0 && (new Date() - beginning) > MAX_TIME) {
                setTimeout(iterate, 0);
                return;
            }
        }
        setTimeout(callBack, 0);
    };
    setTimeout(iterate, 0);
}

sonantx.AudioGenerator = function(mixBuf) {
    this.mixBuf = mixBuf;
    this.waveSize = mixBuf.length / WAVE_CHAN / 2;
};
sonantx.AudioGenerator.prototype.getWave = function() {
    var mixBuf = this.mixBuf;
    var waveSize = this.waveSize;
    // Local variables
    var b, k, x, wave, l1, l2, s, y;

    // Turn critical object properties into local variables (performance)
    var waveBytes = waveSize * WAVE_CHAN * 2;

    // Convert to a WAVE file (in a binary string)
    l1 = waveBytes - 8;
    l2 = l1 - 36;
    wave = String.fromCharCode(82,73,70,70,
                               l1 & 255,(l1 >> 8) & 255,(l1 >> 16) & 255,(l1 >> 24) & 255,
                               87,65,86,69,102,109,116,32,16,0,0,0,1,0,2,0,
                               68,172,0,0,16,177,2,0,4,0,16,0,100,97,116,97,
                               l2 & 255,(l2 >> 8) & 255,(l2 >> 16) & 255,(l2 >> 24) & 255);
    b = 0;
    while(b < waveBytes)
    {
        // This is a GC & speed trick: don't add one char at a time - batch up
        // larger partial strings
        x = "";
        for (k = 0; k < 256 && b < waveBytes; ++k, b += 2)
        {
            // Note: We amplify and clamp here
            y = 4 * (mixBuf[b] + (mixBuf[b+1] << 8) - 32768);
            y = y < -32768 ? -32768 : (y > 32767 ? 32767 : y);
            x += String.fromCharCode(y & 255, (y >> 8) & 255);
        }
        wave += x;
    }
    return wave;
};
sonantx.AudioGenerator.prototype.getAudio = function() {
    var wave = this.getWave();
    var a = new Audio("data:audio/wav;base64," + btoa(wave));
    a.preload = "none";
    a.load();
    return a;
};
sonantx.AudioGenerator.prototype.getAudioBuffer = function(callBack) {
    if (audioCtx === null)
        audioCtx = new AudioContext();
    var mixBuf = this.mixBuf;
    var waveSize = this.waveSize;

    var waveBytes = waveSize * WAVE_CHAN * 2;
    var buffer = audioCtx.createBuffer(WAVE_CHAN, this.waveSize, WAVE_SPS); // Create Mono Source Buffer from Raw Binary
    var lchan = buffer.getChannelData(0);
    var rchan = buffer.getChannelData(1);
    var b = 0;
    var iterate = function() {
        var beginning = new Date();
        var count = 0;
        while (b < (waveBytes / 2)) {
            var y = 4 * (mixBuf[b * 4] + (mixBuf[(b * 4) + 1] << 8) - 32768);
            y = y < -32768 ? -32768 : (y > 32767 ? 32767 : y);
            lchan[b] = y / 32768;
            y = 4 * (mixBuf[(b * 4) + 2] + (mixBuf[(b * 4) + 3] << 8) - 32768);
            y = y < -32768 ? -32768 : (y > 32767 ? 32767 : y);
            rchan[b] = y / 32768;
            b += 1;
            count += 1;
            if (count % 1000 === 0 && new Date() - beginning > MAX_TIME) {
                setTimeout(iterate, 0);
                return;
            }
        }
        setTimeout(function() {callBack(buffer);}, 0);
    };
    setTimeout(iterate, 0);
};

sonantx.SoundGenerator = function(instr, rowLen) {
    this.instr = instr;
    this.rowLen = rowLen || 5605;

    this.osc_lfo = oscillators[instr.lfo_waveform];
    this.osc1 = oscillators[instr.osc1_waveform];
    this.osc2 = oscillators[instr.osc2_waveform];
    this.attack = instr.env_attack;
    this.sustain = instr.env_sustain;
    this.release = instr.env_release;
    this.panFreq = Math.pow(2, instr.fx_pan_freq - 8) / this.rowLen;
    this.lfoFreq = Math.pow(2, instr.lfo_freq - 8) / this.rowLen;
};
sonantx.SoundGenerator.prototype.genSound = function(n, chnBuf, currentpos) {
    var marker = new Date();
    var c1 = 0;
    var c2 = 0;

    // Precalculate frequencues
    var o1t = getnotefreq(n + (this.instr.osc1_oct - 8) * 12 + this.instr.osc1_det) * (1 + 0.0008 * this.instr.osc1_detune);
    var o2t = getnotefreq(n + (this.instr.osc2_oct - 8) * 12 + this.instr.osc2_det) * (1 + 0.0008 * this.instr.osc2_detune);

    // State variable init
    var q = this.instr.fx_resonance / 255;
    var low = 0;
    var band = 0;
    for (var j = this.attack + this.sustain + this.release - 1; j >= 0; --j)
    {
        var k = j + currentpos;

        // LFO
        var lfor = this.osc_lfo(k * this.lfoFreq) * this.instr.lfo_amt / 512 + 0.5;

        // Envelope
        var e = 1;
        if(j < this.attack)
            e = j / this.attack;
        else if(j >= this.attack + this.sustain)
            e -= (j - this.attack - this.sustain) / this.release;

        // Oscillator 1
        var t = o1t;
        if(this.instr.lfo_osc1_freq) t += lfor;
        if(this.instr.osc1_xenv) t *= e * e;
        c1 += t;
        var rsample = this.osc1(c1) * this.instr.osc1_vol;

        // Oscillator 2
        t = o2t;
        if(this.instr.osc2_xenv) t *= e * e;
        c2 += t;
        rsample += this.osc2(c2) * this.instr.osc2_vol;

        // Noise oscillator
        if(this.instr.noise_fader) rsample += (2*Math.random()-1) * this.instr.noise_fader * e;

        rsample *= e / 255;

        // State variable filter
        var f = this.instr.fx_freq;
        if(this.instr.lfo_fx_freq) f *= lfor;
        f = 1.5 * Math.sin(f * 3.141592 / WAVE_SPS);
        low += f * band;
        var high = q * (rsample - band) - low;
        band += f * high;
        switch(this.instr.fx_filter)
        {
            case 1: // Hipass
                rsample = high;
                break;
            case 2: // Lopass
                rsample = low;
                break;
            case 3: // Bandpass
                rsample = band;
                break;
            case 4: // Notch
                rsample = low + high;
                break;
            default:
        }

        // Panning & master volume
        t = osc_sin(k * this.panFreq) * this.instr.fx_pan_amt / 512 + 0.5;
        rsample *= 39 * this.instr.env_master;

        // Add to 16-bit channel buffer
        k = k * 4;
        if (k + 3 < chnBuf.length) {
            var x = chnBuf[k] + (chnBuf[k+1] << 8) + rsample * (1 - t);
            chnBuf[k] = x & 255;
            chnBuf[k+1] = (x >> 8) & 255;
            x = chnBuf[k+2] + (chnBuf[k+3] << 8) + rsample * t;
            chnBuf[k+2] = x & 255;
            chnBuf[k+3] = (x >> 8) & 255;
        }
    }
};
sonantx.SoundGenerator.prototype.getAudioGenerator = function(n, callBack) {
    var bufferSize = (this.attack + this.sustain + this.release - 1) + (32 * this.rowLen);
    var self = this;
    genBuffer(bufferSize, function(buffer) {
        self.genSound(n, buffer, 0);
        applyDelay(buffer, bufferSize, self.instr, self.rowLen, function() {
            callBack(new sonantx.AudioGenerator(buffer));
        });
    });
};
sonantx.SoundGenerator.prototype.createAudio = function(n, callBack) {
    this.getAudioGenerator(n, function(ag) {
        callBack(ag.getAudio());
    });
};
sonantx.SoundGenerator.prototype.createAudioBuffer = function(n, callBack) {
    this.getAudioGenerator(n, function(ag) {
        ag.getAudioBuffer(callBack);
    });
};

sonantx.MusicGenerator = function(song) {
    this.song = song;
    // Wave data configuration
    this.waveSize = WAVE_SPS * song.songLen; // Total song size (in samples)
};
sonantx.MusicGenerator.prototype.generateTrack = function (instr, mixBuf, callBack) {
    var self = this;
    genBuffer(this.waveSize, function(chnBuf) {
        // Preload/precalc some properties/expressions (for improved performance)
        var waveSamples = self.waveSize,
            waveBytes = self.waveSize * WAVE_CHAN * 2,
            rowLen = self.song.rowLen,
            endPattern = self.song.endPattern,
            soundGen = new sonantx.SoundGenerator(instr, rowLen);

        var currentpos = 0;
        var p = 0;
        var row = 0;
        var recordSounds = function() {
            var beginning = new Date();
            while (true) {
                if (row === 32) {
                    row = 0;
                    p += 1;
                    continue;
                }
                if (p === endPattern - 1) {
                    setTimeout(delay, 0);
                    return;
                }
                var cp = instr.p[p];
                if (cp) {
                    var n = instr.c[cp - 1].n[row];
                    if (n) {
                        soundGen.genSound(n, chnBuf, currentpos);
                    }
                }
                currentpos += rowLen;
                row += 1;
                if (new Date() - beginning > MAX_TIME) {
                    setTimeout(recordSounds, 0);
                    return;
                }
            }
        };

        var delay = function() {
            applyDelay(chnBuf, waveSamples, instr, rowLen, finalize);
        };

        var b2 = 0;
        var finalize = function() {
            var beginning = new Date();
            var count = 0;
            // Add to mix buffer
            while(b2 < waveBytes)
            {
                var x2 = mixBuf[b2] + (mixBuf[b2+1] << 8) + chnBuf[b2] + (chnBuf[b2+1] << 8) - 32768;
                mixBuf[b2] = x2 & 255;
                mixBuf[b2+1] = (x2 >> 8) & 255;
                b2 += 2;
                count += 1;
                if (count % 1000 === 0 && (new Date() - beginning) > MAX_TIME) {
                    setTimeout(finalize, 0);
                    return;
                }
            }
            setTimeout(callBack, 0);
        };
        setTimeout(recordSounds, 0);
    });
};
sonantx.MusicGenerator.prototype.getAudioGenerator = function(callBack) {
    var self = this;
    genBuffer(this.waveSize, function(mixBuf) {
        var t = 0;
        var recu = function() {
            if (t < self.song.songData.length) {
                t += 1;
                self.generateTrack(self.song.songData[t - 1], mixBuf, recu);
            } else {
                callBack(new sonantx.AudioGenerator(mixBuf));
            }
        };
        recu();
    });
};
sonantx.MusicGenerator.prototype.createAudio = function(callBack) {
    this.getAudioGenerator(function(ag) {
        callBack(ag.getAudio());
    });
};
sonantx.MusicGenerator.prototype.createAudioBuffer = function(callBack) {
    this.getAudioGenerator(function(ag) {
        ag.getAudioBuffer(callBack);
    });
};

//---------END SONANT-X-----
    Key = {

        _pressed: {},
        _released: {},

        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40,
        SPACE: 32,
        a: 65,
        w: 87,
        s: 83,
        d: 68,
        z: 90,
        x: 88,
        f: 70,
        p: 80,
        r: 82,

        isDown: function (keyCode) {
            return this._pressed[keyCode];
        },

        justReleased: function (keyCode) {
            return this._released[keyCode];
        },

        onKeydown: function (event) {
            this._pressed[event.keyCode] = true;
        },

        onKeyup: function (event) {
            this._released[event.keyCode] = true;
            delete this._pressed[event.keyCode];

        },

        update: function () {
            this._released = {};
        }
    };

E.game = {

    create: function() {

      E.triangles = [];
      for(var i = 0; i < 2000; i++){
        let ox = (Math.random() * 255)|0;
        let oy = (Math.random() * 255)|0;
        let rad = 15;
        E.triangles.push({
          x1: ox + (Math.random() * rad * 2) - rad,
          y1: oy + (Math.random() * rad * 2) - rad,
          x2: ox + (Math.random() * rad * 2) - rad,
          y2: oy + (Math.random() * rad * 2) - rad,
          x3: ox + (Math.random() * rad * 2) - rad,
          y3: oy + (Math.random() * rad * 2) - rad,
          color: (Math.random() * 31)|0,
        })
      }
      console.log(E.triangles.length);

      E.twoColorPalette = [0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1];
      E.inversePalette = E.palDefault.slice().reverse();
      E.warmPalette = [14,0,14,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7];


        E.bgColor = 0;
        E.fgColor = 21;
        E.t = 0;
        E.moveX = 0;

        E.renderTarget = E.page2;
        E.gfx.fillRect(0,0,256,256,2);
        E.gfx.checker(16,16,1);
        //E.gfx.fillCircle(64,64,17,21);


        // E.renderTarget = E.page3;
        // E.gfx.fillRect(64,0,90,256,5);
        // E.gfx.fillRect(66,0,88,256,3);


        //E.gfx.fillRect(0,0,256,256,2);

        E.player = {
          x: 128,
          y: 128,
          radius: 10,
          xvel: 0,
          yvel: 0,
          speed: 6

        }

        E.drag = .97;

        E.cursor = {
            x: 0,
            y: 0
        };
    },

    resize: function() {
      E.canvas.width = window.innerWidth;
      E.canvas.height = window.innerHeight;
    },

    step: function(dt) {
        E.t += dt;

        E.cos = Math.cos(dt);
        E.sin = Math.sin(dt);

        for(var i = 0; i < E.triangles.length; i++){

            var tri = E.triangles[i],

            dx1 = tri.x1 + -128,
            dx2 = tri.x2 + -128,
            dx3 = tri.x3 + -128,
            dy1 = tri.y1 + -128,
            dy2 = tri.y2 + -128,
            dy3 = tri.y3 + -128;

            E.triangles[i].x1 = E.cos * dx1 - E.sin * dy1 + 128;
            E.triangles[i].y1 = E.sin * dx1 + E.cos * dy1 + 128;
            E.triangles[i].x2 = E.cos * dx2 - E.sin * dy2 + 128;
            E.triangles[i].y2 = E.sin * dx2 + E.cos * dy2 + 128;
            E.triangles[i].x3 = E.cos * dx3 - E.sin * dy3 + 128;
            E.triangles[i].y3 = E.sin * dx3 + E.cos * dy3 + 128;
        };

        E.player.x += dt * E.player.xvel;
        E.player.y += dt * E.player.yvel;
        E.player.xvel *= E.drag;
        E.player.yvel *= E.drag;

        //player movement
        if (Key.isDown(Key.a)) {
            E.player.xvel -=E.player.speed;
        }
        if (Key.isDown(Key.d)){
            E.player.xvel +=E.player.speed;
        }
        if(Key.isDown(Key.w)){
          E.player.yvel -=E.player.speed;
        }
        if(Key.isDown(Key.s)) {
          E.player.yvel +=E.player.speed;
        }
        //end player movement

        //world wrap for player
        if(E.player.x > 256+E.player.radius*2){
          E.player.x = -E.player.radius
        }
        if(E.player.x < 0-E.player.radius*2){
          E.player.x = 256+E.player.radius
        }
        if(E.player.y > 256+E.player.radius*2){
          E.player.y = -E.player.radius
        }
        if(E.player.y < 0-E.player.radius*2){
          E.player.y = 256+E.player.radius
        }
        //end world wrap for player
    },

    render: function(dt) {

        E.renderTarget = E.page1;
        E.gfx.fillRect(0,0,256,256,0);
        for(var i = 0; i < E.triangles.length; i++){

            E.gfx.fillTriangle(
              E.triangles[i].x1,
              E.triangles[i].y1,
              E.triangles[i].x2,
              E.triangles[i].y2,
              E.triangles[i].x3,
              E.triangles[i].y3,
              E.triangles[i].color
            )
          }
        //E.pal = [0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0]

        E.gfx.circle(E.player.x, E.player.y, E.player.radius, 21);

        // var i = 5000;
        // while(i--){
        //     var x = (Math.random()*256)|0;
        //     var y = (Math.random()*256)|0;
        //     var color = E.ram[E.page1 + (y*256+x)];
        //     E.gfx.circle(x, y, 1, color-1);
        // }
        //composite

        //our background was drawn to page2 in create()
        E.renderSource = E.page2;
        //reset the render target to screen
        E.renderTarget = E.page4;
        //draw it!
        E.gfx.spr(0,0,256,256,0,0);

        //our foreground stuff is on page1
        E.renderSource = E.page1;
        E.gfx.spr(0,0,256,256,0,0);

        E.renderSource = E.page4;
        E.renderTarget = E.screen;
        E.gfx.spr(0,0,256,256);


        E.pal = E.warmPalette;
        E.moveX = (Math.sin(E.t)*64)|0;
        E.gfx.spr(64,64, 128,128, 64,64);

        E.pal = E.twoColorPalette;
        E.gfx.spr(0,0,64,64);
        E.gfx.spr(0,64*3, 64, 256, 0, 64*3);
        E.gfx.spr(64*3, 64*3, 256, 256, 64*3, 64*3);
        E.gfx.spr(127+64,0, 256,64, 127+64,0)

        E.pal = E.palDefault;

        E.render();

    },



},

(function(){
var E = ENGINE;
/**
 * Created by ryan on 3/6/17.
 */
/**
 * Created by ryan on 3/3/17.
 */
E.last = 0;
E.dt = 0;
E.now = 0;
stats = new Stats();
document.body.appendChild( stats.dom );
E.canvasInit();
E.game.create();

    //initialize keypress event listeners
    window.addEventListener('keyup', function (event) {
        Key.onKeyup(event);
    }, false);
    window.addEventListener('keydown', function (event) {
        Key.onKeydown(event);
        // console.log('key pressed');
    }, false);
    window.addEventListener('blur', function (event) {
        paused = true;
    }, false);
    window.addEventListener('focus', function (event) {
        paused = false;
    }, false);
    window.addEventListener('resize', E.game.resize );

function loop(){
  stats.begin();
  //game timer
  let now = new Date().getTime();
  E.dt = Math.min(1, (now - E.last) / 1000);

  //update
  E.game.step(E.dt);
  E.last = now;

  //draw
  E.game.render();

  stats.end();
  requestAnimationFrame(loop);
}
loop();

})();

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console