The contract has only one external payable function:
function setColors(uint8 x, uint8 y, bytes32[chunk_height] clr) external payable withinBounds(x,y) hasTheMoneys(x,y)
This function claims a 32x32 8-bit pixel chunk in the 32x32 grid and the image data. In order to claim it, the amount paid needs to exceed the amount that was last paid on the chunk (starting at 0). If another user takes control of this chunk, the last user will be refunded the ether they staked. The contract owns all staked ether and the only way to get it back is if someone posts a larger stake :).
The main viewing function is:
function getChunk(uint8 x, uint8 y) external view withinBounds(x,y) returns(bytes32[chunk_height], address, uint, uint)
This returns the image data as well as the owner, how much they staked, and the block number this transaction happened. There are also some viewing functions for checking timestamps so the image generator does not need to poll the entire image every time.
The image is generated using the Haskell web3 package. Please see this README for a walkthrough on how it's done. tldr; Thanks to the awesom ABI interfaces generated with Template Haskell, the web3 package for Haskell is a fantastic choice for writing dapps. We have a server that runs the generator every 10 minutes and serves the image as well as additional meta data.
We wrote a js web3 app for interacting with the smart contract. The app displays the image made by the image generator and overlays a hoverable grid displaying meta data of each chunk. Clicking on the square takes you to the setter page. It also refreshes the tile locally if you don't want to wait 10 minutes.