Showing posts with label css. Show all posts
Showing posts with label css. Show all posts

Sunday, December 11, 2011

Chamber of the Painted Table


Click Here to interact (Works in Chrome, works better in Safari).

This is the second of my "A Song of Ice and Fire" webkit experiments. The first was a simple animation built using a pretty sweet WYSIWYG. This one is a little more complex. I wanted to experiment with manipulating 3d objects, but didn't want to get bogged down with complicated framework. Webkit-3d transforms seemed like the ticket.

I've create a scene inspired by Aegon the Conqueror's Painted Table. There is a map of westeros on a large table with a spinning dice. Each face has the sigil of a major house on it (all of them involved in Aegon's War of Conquest). I attempted to add floors and walls, but the browser just couldn't handle it. It could be possible to reduce the size of the objects and simply create a smaller scene.

Transforms

To create the objects in the scene square divs are rotated and translated into position, adjusting transform origin where necessary. When transforming shapes within other transformed shapes the -webkit-transform-style attribute must be set to 'preserve-3d', otherwise the transforms will be projected onto the 'surface' of the container as 2d objects. Three containers serve as examples for the different attributes used to position the shapes.

#dice{
 -webkit-transform-style: preserve-3d;
 -webkit-transform-origin: 200px 200px;
 -webkit-transform: rotateX(45deg) rotateY(45deg);
}
#dice_tilt{
 -webkit-transform-style: preserve-3d;
 -webkit-transform-origin: 200px 200px;
 -webkit-transform: rotateY(15deg);
}
#dice_wrapper{
-webkit-transform-origin: 200px 200px;
 -webkit-transform: scaleX(0.3) scaleY(0.3) scaleZ(0.3) translateZ(335px);
}

The dice is rotated on is X and Y axis to make it stand on it point. The dice tilt rotates the dice to one side slightly to allow for a wobbly look, and the dice wrapper is moved above the table and is scaled down to 1/3 normal size.

The animation is based on a ~30 hz timer that updates the rotation of the Dice, and the dice tilt, to create the  the wobbling dice look. The dice_tilt has the inner rotation and the dice wrapper has the wobble (half speed rotation speed) applied to it.

Sprite3d and Matrix Transforms

The Sprite3d class allows the rotation, scale and translation of a div to be set; adjust the transform center, and the transform matrix to be recalculated on request. The class uses the sylvester.js http://sylvester.jcoglan.com/ library to combine the transforms before applying them to the -webkit-transform atribute.

View Change

The rest is simply capturing keyboard input and updating the transform values of the objects. I split rotation x, rotation z, and translation divs, the rotation axis are a little strange if all the transformations are applied to the same function.

Sunday, February 13, 2011

What 9000!

If this isn't the wackiest piece of code I've ever written, then it is pretty close. There are three components to the page: a randomly generated grid, the changing letter sizes, and the "awesome song" in the background.

Random Grid

The toughest part was generating the random grid. The grid is made up of two types of components. The grid itself, and the blocks. Each the grids and blocks are have a visual and a data component. The visual components is handled by css,

Grid size

The first step is to determine the number of rows and columns that the grid will have. This is done by taking the ceiling of the quotient of the width or height of the container divided by the height or width of the cell. In this case the cells are 50x50 (40px with 10px of padding). I used the ceiling function rather than the floor because I wanted to fill the screen. Also the number of cells is recalculated on window resize.
$(window).resize(function(){
     hcells = Math.ceil($grid.width()/50); //collumns
     vcells = Math.ceil($grid.height()/50); //rows
}).resize();

Representing grid and shapes

Both the grid and the shapes are represented by 2-dimensional boolean matrices. The grid is initialized so that every cell contains a false value (meaning that grid position is not occupied).
for(i = 0; i < hcells; i++){
     grid.push([]);
     for(j = 0; j < vcells; j++){
          grid[i].push(false);                    
     }
}
Likewise, each of the block shapes has a shape array where the positions occupied by the shape are represented by a true value.
//default shape, single square block 
     oneSquare = {
        shape: [ [true] ],
        className: "oneSquare"
    };
    //three wide by one tall 
    threeXOne = {
        className: "threeXone",            
        shape: [ [true], [true], [true] ]
    };

Placing Blocks

After the grid is initialized, each position is looped through and a block shape is chosen at random. Then the shape array of the block is compared the the grid starting at the current position. The block is placed into the grid if all the positions that will be take up by this shape are unoccupied.
function placeBlock(i, j, shape){              
        //loop over space checking for occupation
        for(x = 0; x < shape.length; x++){
            for(y = 0; y < shape[x].length; y++){
                 if (grid[x + i][y + j] || x+i >= grid.length || y+j >= grid[x+i].length) {                             
                      return false;                              
                  }                                          
            }                                      
        }
        //go back and mark spots as taken up
        for (x = 0; x < shape.length; x++) {
            for (y = 0; y < shape[x].length; y++) {
                grid[x + i][y + j] = true;
            }
        }              
        return true;       
    }
If the function returns true then the block is placed absolutely in the grid using the cell size and i,j coordinates. The process of emptying the grid and filling it with random block is set to repeat 10 times a second. This makes the grid a pretty interesting browser benchmark.

Title

To spice up the title a little bit. I use the lettering.js a jQuery plugin to wrap each of the letters in there own div. Then on an interval the letters are looped through and a random size (within bounds) is chosen for each letter, and it is assigned one of 4 colors;
var colors = ["#0099FF", "#800080", "#0FF000", "#FF0000"];
     function logoDance(){
        $logo.children("span").each(function(){
            randy = Math.random();                 
            $(this).css({
                fontSize: Math.round(randy*150)+75,
                color: colors[Math.floor(4 * randy)]
            });
        });
    }

Audio

The music is played through an HTML audio tag.To get the OGG version of the file I used Firefogg.

Summary

That pretty much covers it. Some arrays operations to create and fill the grid, lettering.js to jazz up the title page, and some quick html audio for the background music.