function Shape(game, orientations, symmetrical, blockType) {

        $.extend(this, {
          x: 0,
          y: 0,
          symmetrical: symmetrical,
          init: function() {
            $.extend(this, {
              orientation: 0,
              x: Math.floor(game._BLOCK_WIDTH / 2) - 1,
              y: -1
            });
            return this;
          },

          blockType: blockType,
          blockVariation: null,
          blocksLen: orientations[0].length,
          orientations: orientations,
          orientation: 0, // 4 possible

          rotate: function(direction) {
            var orientation =
              (this.orientation + (direction === "left" ? 1 : -1) + 4) % 4;

            if (!game._checkCollisions(
                this.x,
                this.y,
                this.getBlocks(orientation)
              )) {
              this.orientation = orientation;
              game._board.renderChanged = true;
            } else {
              var ogOrientation = this.orientation;
              var ogX = this.x;
              var ogY = this.y;

              this.orientation = orientation;

              while (this.x >= game._BLOCK_WIDTH - 2) {
                this.x--;
              }
              while (this.x < 0) {
                this.x++;
              }

              if (this.blockType === "line" && this.x === 0) this.x++;

              if ( game._checkCollisions(
                  this.x,
                  this.y,
                  this.getBlocks(orientation)
                )
              ) {
                this.y--;
                if (
                    game._checkCollisions(
                      this.x,
                      this.y,
                      this.getBlocks(orientation)
                    )
                ) {
                    this.x = ogX;
                    this.y = ogY;
                    this.orientation = ogOrientation;
                }
              }
              game._board.renderChanged = true;
            }
          },

          moveRight: function() {
            if (!game._checkCollisions(this.x + 1, this.y, this.getBlocks())) {
              this.x++;
              game._board.renderChanged = true;
            }
          },
          moveLeft: function() {
            if (!game._checkCollisions(this.x - 1, this.y, this.getBlocks())) {
              this.x--;
              game._board.renderChanged = true;
            }
          },
          drop: function() {
            if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) {
              this.y++;
              // Reset the drop count, as we dropped the block sooner
              game._board.dropCount = -1;
              game._board.animate();
              game._board.renderChanged = true;
            }
          },

          getBlocks: function(orientation) { // optional param
            return this.orientations[orientation !== undefined ? orientation : this.orientation];
          },
          draw: function(_x, _y, _orientation) {
            var blocks = this.getBlocks(_orientation),
                x = _x === undefined ? this.x : _x,
                y = _y === undefined ? this.y : _y,
                i = 0,
                index = 0;

            for (; i<this.blocksLen; i += 2) {
              game._board.drawBlock(x + blocks[i], y + blocks[i+1], this.blockType, this.blockVariation, index, this.orientation, true);
              index++;
            }
          },
          getBounds: function(_blocks) { // _blocks can be an array of blocks, an orientation index, or undefined
            var blocks = $.isArray(_blocks) ? _blocks : this.getBlocks(_blocks),
                i=0, len=blocks.length, minx=999, maxx=-999, miny=999, maxy=-999;
            for (; i<len; i+=2) {
              if (blocks[i] < minx) { minx = blocks[i]; }
              if (blocks[i] > maxx) { maxx = blocks[i]; }
              if (blocks[i+1] < miny) { miny = blocks[i+1]; }
              if (blocks[i+1] > maxy) { maxy = blocks[i+1]; }
            }
            return {
              left: minx,
              right: maxx,
              top: miny,
              bottom: maxy,
              width: maxx - minx,
              height: maxy - miny
            };
          }
        });

        return this.init();
      }
The shapes have a reference point (the dot) and always rotate left.
Keep in mind that the blocks should keep in the same relative position when rotating,
to allow for custom per-block themes.