Telling you how we see the world.
One of the issues we have had with Cadmus is that the first time you sign in or if you sign in after a while you would need to wait a bit before we show you your updates. On an average it takes around a minute to process your Twitter stream. We are working on ways to improve that but in the meanwhile we wanted to do something to improve the user experience during that delay.
We decided to add in a game that users could play around with while they waited for the process to complete. Inspired by the pong preloaders on some of the console games and the Highrise Tic-Tac-Toe setup game we set out to build one of our own. I looked at the various options and settled on the Sliding Puzzles since it was moderately difficult to play, relatively simple to build and easy to brand! The result is a fun to play 9-piece sliding puzzle that uses the Cadmus logo as the image.

The puzzle was intended only for new users and users that have been inactive for a while but it was so fun to test/play; I decided to make it available for existing users as well. You can check it out @ http://thecadmus.com/?puzzle. You need to be logged in before visiting that URL.
Lets dive right into some the things that I used to build the puzzle. Firstly the puzzle image which is a single image of the Cadmus logo. I wanted each of the pieces in the puzzle to seem like a piece on a board. Meaning it needed to have a shadow to give a feel that it is sitting on top of the board. I did this by using the CSS3 box-shadow property and the rgba properties to give the effect of a shadow.
div.puzzle div.piece { width: 100px; height: 100px; background: transparent url(puzzle-image.png) no-repeat top left; position: absolute; cursor: pointer; box-shadow: 1px 1px rgba(0, 0, 0, 0.26); -moz-box-shadow: 1px 1px rgba(0, 0, 0, 0.26); -webkit-box-shadow: 1px 1px rgba(0, 0, 0, 0.26); } div.puzzle div.piece-0 { background-position: 0 0; } div.puzzle div.piece-1 { background-position: -100px 0; } ...
The second part of creating the puzzle was the board itself. As with all the other elements it is important that it fits in with the rest of the application. I went with the look where the board is cut into the canvas because it reminds me of how most sliding puzzles are in reality. They are usually set into the surface so the pieces don’t slide off the board.

The grid within the board are also cutting further into the board to give a really crisp feel to the whole thing. Lets look at the effects used to create the board in a little more detail.

The final part of creating the puzzle is the JS portion of it. Most of it is really straight forward; I have an array representation of the board, an array of possible moves for each position and an array of CSS left and top values for each position. And so every time a piece is clicked the following function runs.
'onPieceClick': function(e, el, args) { var from = this.getPositionForPiece(args.position), to = this.getAvailableMove(from); return (to === null) ? this : this .stopMoveAnimation() .setCurrentPieceEl(args.el) .movePiece(args.position, args.el, from, to) .checkStatus(); },
We find the position given the piece number (pieces are numbered 0-8) and find the available moves given the current position. If there is a move then we stop any current animations (the last piece could still be sliding into place), save a reference to the current piece, move the piece and check the status of the board to see if the puzzle has been solved.
To start the game we need to randomize the board. But a number of possible positions for this puzzle are unsolvable. So I wrote up this function that shuffles the pieces along in a similar manner a user would click around the board to shuffle it up.
'shufflePiece': function(i, position, lastPosition) { if (i > 0) { var from = this.getRandomExcept( this.movesList[position], this.getExcludeList(lastPosition) ), piece = this.getPieceForPosition(from); return this.movePiece( piece, this.getPieceEl(piece), from, position, function() { return this.shufflePiece(i - 1, from, position); } ); } return (this.isSolved()) ? this.shufflePiece(this.shuffleCount, 9, null) : this.startGame(); }, ... this.shufflePiece(this.shuffleCount, 9, null); ...
I get the available moves for the given empty position in the board and I also exclude the previous empty position since I don’t want the randomizer to pick the previous move. This function calls itself as it shuffles every move. I start it off by passing in the number of times I want it shuffled and the first empty position on the board. Now at the end of all the shuffling I might end up right where I started so I have a simple check that restarts the shuffling if that happens. A better approach would be to calculate the distance of the shuffled state from the solved state and set a lower limit on that.
The entire code for the game is actually quite small and it was relatively simple to implement (not to mention fun to test). We will keep an eye on how this impacts the experience for a new user and see if it actually helps.
By going into the different aspects (CSS, Photoshop and JS) of building this feature, I am hoping it would help others venture out into areas that they have been previously shying away from.
If you have any questions or would like me to go into further detail; just let me know on Twitter.
Also, check out the 37signals post about the Tic-Tac-Toe game in their Highrise iPhone app.
Please do share this on .
Just wanted to make a quick post about the press Cadmus has gotten recently.
The Tweet House panel at SXSW with @brian_wong, @scobleizer, @markmilian, @dom – Link (around 13:07)
Opening up opportunity with Twitter at Mix10 by @rsarver and @raffi – Link (around 20:39)
A Cinchcast with @louisgray – Link
With @scobleizer at the Palo Alto Apple Store – Link
Thanks guys!