text: 
  var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { create: create });
  
  //  Dimensions
  var previewSize = 6;
  var spriteWidth = 8;
  var spriteHeight = 8;
  
  //  UI
  var ui;
  var paletteArrow;
  var coords;
  var widthText;
  var widthUp;
  var widthDown;
  var heightText;
  var heightUp;
  var heightDown;
  var previewSizeUp;
  var previewSizeDown;
  var previewSizeText;
  var nextFrameButton;
  var prevFrameButton;
  var frameText;
  var saveIcon;
  var saveText;
  var rightCol = 532;
  
  //  Drawing Area
  var canvas;
  var canvasBG;
  var canvasGrid;
  var canvasSprite;
  var canvasZoom = 32;
  
  //  Sprite Preview
  var preview;
  var previewBG;
  
  //  Keys + Mouse
  var keys;
  var isDown = false;
  var isErase = false;
  
  //  Palette
  var ci = 0;
  var color = 0;
  var palette = 0;
  var pmap = [0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'];
  
  //  Data
  var frame = 1;
  var frames = [[]];
  
  var data;
  
  function resetData() {
  
      data = [];
  
      for (var y = 0; y < spriteHeight; y++)
      {
          var a = [];
  
          for (var x = 0; x < spriteWidth; x++)
          {
              a.push('.');
          }
  
          data.push(a);
      }
  
  }
  
  function copyToData(src) {
  
      data = [];
  
      for (var y = 0; y < src.length; y++)
      {
          var a = [];
  
          for (var x = 0; x < src[y].length; x++)
          {
              a.push(src[y][x]);
          }
  
          data.push(a);
      }
  
  }
  
  function cloneData() {
  
      var clone = [];
  
      for (var y = 0; y < data.length; y++)
      {
          var a = [];
  
          for (var x = 0; x < data[y].length; x++)
          {
              var v = data[y][x];
              a.push(v);
          }
  
          clone.push(a);
      }
  
      return clone;
  
  }
  
  function createUI() {
  
      game.create.grid('uiGrid', 32 * 16, 32, 32, 32, 'rgba(255,255,255,0.5)');
  
      //  Create some icons
      var arrow = [
          '  22  ',
          ' 2222 ',
          '222222',
          '  22  ',
          '  22  '
      ];
  
      var plus = [
          '2222222',
          '2.....2',
          '2..2..2',
          '2.222.2',
          '2..2..2',
          '2.....2',
          '2222222'
      ];
  
      var minus = [
          '2222222',
          '2.....2',
          '2.....2',
          '2.222.2',
          '2.....2',
          '2.....2',
          '2222222'
      ];
  
      var disk = [
          'DDDDDDDDDD',
          'DED1111DED',
          'DED1111DDD',
          'DEDDDDDDED',
          'DEEEEEEEED',
          'DEFFFFFFED',
          'DEFF222FED',
          'DEFF222FED',
          'DEFF222FED',
          'DDDDDDDDDD'
      ];
  
      game.create.texture('arrow', arrow, 2);
      game.create.texture('plus', plus, 3);
      game.create.texture('minus', minus, 3);
      game.create.texture('save', disk, 4);
  
      ui = game.make.bitmapData(800, 32);
  
      drawPalette();
  
      ui.addToWorld();
  
      var style = { font: "20px Courier", fill: "#fff", tabs: 80 };
  
      coords = game.add.text(rightCol, 8, "X: 0\tY: 0", style);
  
      game.add.text(12, 9, pmap.join("\t"), { font: "14px Courier", fill: "#000", tabs: 32 });
      game.add.text(11, 8, pmap.join("\t"), { font: "14px Courier", fill: "#ffff00", tabs: 32 });
  
      paletteArrow = game.add.sprite(8, 36, 'arrow');
  
      //  Change width
  
      widthText = game.add.text(rightCol, 60, "Width: " + spriteWidth, style);
  
      widthUp = game.add.sprite(rightCol + 180, 60, 'plus');
      widthUp.name = 'width';
      widthUp.inputEnabled = true;
      widthUp.input.useHandCursor = true;
      widthUp.events.onInputDown.add(increaseSize, this);
  
      widthDown = game.add.sprite(rightCol + 220, 60, 'minus');
      widthDown.name = 'width';
      widthDown.inputEnabled = true;
      widthDown.input.useHandCursor = true;
      widthDown.events.onInputDown.add(decreaseSize, this);
  
      //  Change height
  
      heightText = game.add.text(rightCol, 100, "Height: " + spriteHeight, style);
  
      heightUp = game.add.sprite(rightCol + 180, 100, 'plus');
      heightUp.name = 'height';
      heightUp.inputEnabled = true;
      heightUp.input.useHandCursor = true;
      heightUp.events.onInputDown.add(increaseSize, this);
  
      heightDown = game.add.sprite(rightCol + 220, 100, 'minus');
      heightDown.name = 'height';
      heightDown.inputEnabled = true;
      heightDown.input.useHandCursor = true;
      heightDown.events.onInputDown.add(decreaseSize, this);
  
      //  Change frame
  
      frameText = game.add.text(rightCol, 160, "Frame: " + frame + " / " + frames.length, style);
  
      nextFrameButton = game.add.sprite(rightCol + 180, 160, 'plus');
      nextFrameButton.inputEnabled = true;
      nextFrameButton.input.useHandCursor = true;
      nextFrameButton.events.onInputDown.add(nextFrame, this);
  
      prevFrameButton = game.add.sprite(rightCol + 220, 160, 'minus');
      prevFrameButton.inputEnabled = true;
      prevFrameButton.input.useHandCursor = true;
      prevFrameButton.events.onInputDown.add(prevFrame, this);
  
      //  Change preview
  
      previewSizeText = game.add.text(rightCol, 220, "Size: " + previewSize, style);
  
      previewSizeUp = game.add.sprite(rightCol + 180, 220, 'plus');
      previewSizeUp.inputEnabled = true;
      previewSizeUp.input.useHandCursor = true;
      previewSizeUp.events.onInputDown.add(increasePreviewSize, this);
  
      previewSizeDown = game.add.sprite(rightCol + 220, 220, 'minus');
      previewSizeDown.inputEnabled = true;
      previewSizeDown.input.useHandCursor = true;
      previewSizeDown.events.onInputDown.add(decreasePreviewSize, this);
  
      //  Save Icon
  
      saveText = game.add.text(rightCol, 520, "Saved to console.log", style);
      saveText.alpha = 0;
  
      saveIcon = game.add.sprite(750, 550, 'save');
      saveIcon.inputEnabled = true;
      saveIcon.input.useHandCursor = true;
      saveIcon.events.onInputDown.add(save, this);
  
  }
  
  function createDrawingArea() {
  
      game.create.grid('drawingGrid', 16 * canvasZoom, 16 * canvasZoom, canvasZoom, canvasZoom, 'rgba(0,191,243,0.8)');
  
      canvas = game.make.bitmapData(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
      canvasBG = game.make.bitmapData(canvas.width + 2, canvas.height + 2);
  
      canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
      canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');
  
      var x = 10;
      var y = 64;
  
      canvasBG.addToWorld(x, y);
      canvasSprite = canvas.addToWorld(x + 1, y + 1);
      canvasGrid = game.add.sprite(x + 1, y + 1, 'drawingGrid');
      canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));
  
  }
  
  function resizeCanvas() {
  
      canvas.resize(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
      canvasBG.resize(canvas.width + 2, canvas.height + 2);
  
      canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
      canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');
  
      canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));
      
  }
  
  function createPreview() {
  
      preview = game.make.bitmapData(spriteWidth * previewSize, spriteHeight * previewSize);
      previewBG = game.make.bitmapData(preview.width + 2, preview.height + 2);
  
      previewBG.rect(0, 0, previewBG.width, previewBG.height, '#fff');
      previewBG.rect(1, 1, previewBG.width - 2, previewBG.height - 2, '#3f5c67');
  
      var x = rightCol;
      var y = 250;
  
      previewBG.addToWorld(x, y);
      preview.addToWorld(x + 1, y + 1);
  
  }
  
  function resizePreview() {
  
      preview.resize(spriteWidth * previewSize, spriteHeight * previewSize);
      previewBG.resize(preview.width + 2, preview.height + 2);
  
      previewBG.rect(0, 0, previewBG.width, previewBG.height, '#fff');
      previewBG.rect(1, 1, previewBG.width - 2, previewBG.height - 2, '#3f5c67');
      
  }
  
  function refresh() {
  
      //  Update both the Canvas and Preview
      canvas.clear();
      preview.clear();
  
      for (var y = 0; y < spriteHeight; y++)
      {
          for (var x = 0; x < spriteWidth; x++)
          {
              var i = data[y][x];
  
              if (i !== '.' && i !== ' ')
              {
                  color = game.create.palettes[palette][i];
                  canvas.rect(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
                  preview.rect(x * previewSize, y * previewSize, previewSize, previewSize, color);
              }
          }
      }
  
  }
  
  function createEventListeners() {
  
      keys = game.input.keyboard.addKeys(
          {
              'erase': Phaser.Keyboard.X,
              'save': Phaser.Keyboard.S,
              'up': Phaser.Keyboard.UP,
              'down': Phaser.Keyboard.DOWN,
              'left': Phaser.Keyboard.LEFT,
              'right': Phaser.Keyboard.RIGHT,
              'changePalette': Phaser.Keyboard.P,
              'nextFrame': Phaser.Keyboard.PERIOD,
              'prevFrame': Phaser.Keyboard.COMMA,
              'color0': Phaser.Keyboard.ZERO,
              'color1': Phaser.Keyboard.ONE,
              'color2': Phaser.Keyboard.TWO,
              'color3': Phaser.Keyboard.THREE,
              'color4': Phaser.Keyboard.FOUR,
              'color5': Phaser.Keyboard.FIVE,
              'color6': Phaser.Keyboard.SIX,
              'color7': Phaser.Keyboard.SEVEN,
              'color8': Phaser.Keyboard.EIGHT,
              'color9': Phaser.Keyboard.NINE,
              'color10': Phaser.Keyboard.A,
              'color11': Phaser.Keyboard.B,
              'color12': Phaser.Keyboard.C,
              'color13': Phaser.Keyboard.D,
              'color14': Phaser.Keyboard.E,
              'color15': Phaser.Keyboard.F
          }
      );
  
      keys.erase.onDown.add(cls, this);
      keys.save.onDown.add(save, this);
      keys.up.onDown.add(shiftUp, this);
      keys.down.onDown.add(shiftDown, this);
      keys.left.onDown.add(shiftLeft, this);
      keys.right.onDown.add(shiftRight, this);
      keys.changePalette.onDown.add(changePalette, this);
      keys.nextFrame.onDown.add(nextFrame, this);
      keys.prevFrame.onDown.add(prevFrame, this);
  
      for (var i = 0; i < 16; i++)
      {
          keys['color' + i].onDown.add(setColor, this, 0, i);
      }
  
      game.input.mouse.capture = true;
      game.input.onDown.add(onDown, this);
      game.input.onUp.add(onUp, this);
      game.input.addMoveCallback(paint, this);
  
  }
  
  function cls() {
  
      resetData();
      refresh();
  
  }
  
  function nextFrame() {
  
      //  Save current frame
      frames[frame - 1] = cloneData();
  
      frame++;
  
      if (frames[frame - 1])
      {
          copyToData(frames[frame - 1]);
      }
      else
      {
          frames.push(null);
          resetData();
      }
  
      refresh();
  
      frameText.text = "Frame: " + frame + " / " + frames.length;
  
  }
  
  function prevFrame() {
  
      if (frame === 1)
      {
          return;
      }
  
      //  Save current frame
      frames[frame - 1] = cloneData();
  
      frame--;
  
      //  Load old frame
      copyToData(frames[frame - 1]);
  
      refresh();
  
      frameText.text = "Frame: " + frame + " / " + frames.length;
      
  }
  
  function drawPalette() {
  
      //  Draw the palette to the UI bmd
      ui.clear(0, 0, 32 * 16, 32);
  
      var x = 0;
  
      for (var clr in game.create.palettes[palette])
      {
          ui.rect(x, 0, 32, 32, game.create.palettes[palette][clr]);
          x += 32;
      }
  
      ui.copy('uiGrid');
  
  }
  
  function changePalette() {
  
      palette++;
  
      if (!game.create.palettes[palette])
      {
          palette = 0;
      }
  
      drawPalette();
      refresh();
  
  }
  
  function setColor(i, p) {
  
      if (typeof p !== 'undefined')
      {
          //  It came from a Keyboard Event, in which case the color index is in p, not i.
          i = p;
      }
  
      if (i < 0)
      {
          i = 15;
      }
      else if (i >= 16)
      {
          i = 0;
      }
  
      colorIndex = i;
      color = game.create.palettes[palette][pmap[colorIndex]];
  
      paletteArrow.x = (i * 32) + 8;
  
  }
  
  function nextColor() {
  
      var i = colorIndex + 1;
      setColor(i);
  
  }
  
  function prevColor() {
  
      var i = colorIndex - 1;
      setColor(i);
  
  }
  
  function increaseSize(sprite) {
  
      if (sprite.name === 'width')
      {
          if (spriteWidth === 16)
          {
              return;
          }
  
          spriteWidth++;
      }
      else if (sprite.name === 'height')
      {
          if (spriteHeight === 16)
          {
              return;
          }
  
          spriteHeight++;
      }
  
      resetData();
      resizeCanvas();
      resizePreview();
  
      widthText.text = "Width: " + spriteWidth;
      heightText.text = "Height: " + spriteHeight;
  
  }
  
  function decreaseSize(sprite) {
  
      if (sprite.name === 'width')
      {
          if (spriteWidth === 4)
          {
              return;
          }
  
          spriteWidth--;
      }
      else if (sprite.name === 'height')
      {
          if (spriteHeight === 4)
          {
              return;
          }
  
          spriteHeight--;
      }
  
      resetData();
      resizeCanvas();
      resizePreview();
  
      widthText.text = "Width: " + spriteWidth;
      heightText.text = "Height: " + spriteHeight;
  
  }
  
  function increasePreviewSize() {
  
      if (previewSize === 16)
      {
          return;
      }
  
      previewSize++;
      previewSizeText.text = "Size: " + previewSize;
  
      resizePreview();
      refresh();
  
  }
  
  function decreasePreviewSize() {
  
      if (previewSize === 1)
      {
          return;
      }
  
      previewSize--;
      previewSizeText.text = "Size: " + previewSize;
  
      resizePreview();
      refresh();
  
  }
  
  function create() {
  
      //   So we can right-click to erase
      document.body.oncontextmenu = function() { return false; };
  
      Phaser.Canvas.setUserSelect(game.canvas, 'none');
      Phaser.Canvas.setTouchAction(game.canvas, 'none');
  
      game.stage.backgroundColor = '#505050';
  
      createUI();
      createDrawingArea();
      createPreview();
      createEventListeners();
  
      resetData();
      setColor(2);
  
  }
  
  function save() {
  
      //  Save current frame
      frames[frame - 1] = cloneData();
  
      var output = "";
  
      for (var f = 0; f < frames.length; f++)
      {
          var src = frames[f];
  
          if (src === null)
          {
              continue;
          }
  
          output = output.concat("var frame" + f + " = [\n");
  
          for (var y = 0; y < src.length; y++)
          {
              output = output.concat("\t'");
              output = output.concat(src[y].join(''));
  
              if (y < src.length - 1)
              {
                  output = output.concat("',\n");
              }
              else
              {
                  output = output.concat("'\n");
              }
          }
          
          output = output.concat("];\n");
          output = output.concat("game.create.texture('yourKey', frame" + f + ", " + previewSize + ", " + previewSize + ", " + palette + ");\n");
  
      }
  
      console.log(output);
  
      saveText.alpha = 1;
      game.add.tween(saveText).to( { alpha: 0 }, 2000, "Linear", true);
  
  }
  
  function shiftLeft() {
  
      canvas.moveH(-canvasZoom);
      preview.moveH(-previewSize);
  
      for (var y = 0; y < spriteHeight; y++)
      {
          var r = data[y].shift();
          data[y].push(r);
      }
  
  }
  
  function shiftRight() {
  
      canvas.moveH(canvasZoom);
      preview.moveH(previewSize);
  
      for (var y = 0; y < spriteHeight; y++)
      {
          var r = data[y].pop();
          data[y].splice(0, 0, r);
      }
  
  }
  
  function shiftUp() {
  
      canvas.moveV(-canvasZoom);
      preview.moveV(-previewSize);
  
      var top = data.shift();
      data.push(top);
  
  }
  
  function shiftDown() {
  
      canvas.moveV(canvasZoom);
      preview.moveV(previewSize);
  
      var bottom = data.pop();
      data.splice(0, 0, bottom);
  
  }
  
  function onDown(pointer) {
  
      if (pointer.y <= 32)
      {
          setColor(game.math.snapToFloor(pointer.x, 32) / 32);
      }
      else
      {
          isDown = true;
  
          if (pointer.rightButton.isDown)
          {
              isErase = true;
          }
          else
          {
              isErase = false;
          }
  
          paint(pointer);
      }
  
  }
  
  function onUp() {
      isDown = false;
  }
  
  function paint(pointer) {
  
      //  Get the grid loc from the pointer
      var x = game.math.snapToFloor(pointer.x - canvasSprite.x, canvasZoom) / canvasZoom;
      var y = game.math.snapToFloor(pointer.y - canvasSprite.y, canvasZoom) / canvasZoom;
  
      if (x < 0 || x >= spriteWidth || y < 0 || y >= spriteHeight)
      {
          return;
      }
  
      coords.text = "X: " + x + "\tY: " + y;
  
      if (!isDown)
      {
          return;
      }
  
      if (isErase)
      {
          data[y][x] = '.';
          canvas.clear(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
          preview.clear(x * previewSize, y * previewSize, previewSize, previewSize, color);
      }
      else
      {
          data[y][x] = pmap[colorIndex];
          canvas.rect(x * canvasZoom, y * canvasZoom, canvasZoom, canvasZoom, color);
          preview.rect(x * previewSize, y * previewSize, previewSize, previewSize, color);
      }
  
  }
  