HTML5 Rocks

HTML5 Rocks

Interactive Globe with CSS shaders & Google Maps

By Paul Irish at

Recently, I have read news on Webmonkey that Adobe’s CSS Shaders proposal, which will bring high-quality cinematic effects to the web through some new CSS tools, has been accepted by the W3C. If you haven't seen it yet, watch the video below:

Google Chrome's latest Canary added support for CSS shaders, so I decided to experiment with them.

In this experiment, I used custom vertex shader (spherify.vs) and fragment shader (spherify.fs) to create a globe with Google Maps.

<iframe
  class="globe"
  src="http://maps.google.com/?ie=UTF8&amp;ll=14.597042,-15.625&amp;spn=158.47027,316.054688&amp;t=h&amp;z=2&amp;output=embed"
  scrolling="no"></iframe>
.globe {
  width: 550px;
  height: 550px;
  border: 0;
  -webkit-filter: contrast(1.4) custom(url(shaders/spherify.vs) mix(url(shaders/spherify.fs) multiply source-atop),
    50 50 border-box,
    amount 1,
    sphereRadius 0.5,
    sphereAxis -0.41 1 0.19,
    sphereRotation 43.5,
    ambientLight 0.15,
    lightPosition 1 0.87 0.25,
    lightColor 1 1 1 1,
    transform perspective(500));
}

Here, we're applying a vertex shader (spherify.vs) which will operate on a mesh that has 50 lines and 50 columns (50 50 border-box). Feel free to read the source of the vertex shader: spherify.vs. It's written in GLSL but you can probably follow along.

The mix() function provides basic functionalities for color manipulation like blending and alpha compositing on a fragment shader.

We can change the shere's radius, axis, rotation right in the CSS. In this example we set the value of the sphereRadius: 0.5 and it gives original sphere size.

Enjoy the demo!

Below is a video of the effect. If you've got shaders enabled you can play with the real thing right below!

If you just see a flat google maps above, you can enable it with the instructions below

Browsers support: CSS shaders

This is currently cutting-edge, so it's only available in the latest Google Chrome Canary and WebKit nightly. To enjoy the full experience you'll need to turn a few knobs.

Chrome Canary steps:

  • Type about:flags in the browser's navigation bar
  • Find "Enable CSS Shaders". Enable it
  • Relaunch the browser

WebKit nightly steps

  • Download and install WebKit nightly for Mac OSX
  • Open the browser's preferences panel. Go to Advanced tab and tick to show Develop > Enable WebGL menu in the menu bar.
  • In the browser's menu bar select Develop

Writing a flippable book using CSS Regions and 3D transforms

By Ilmari Heikkinen at

So. The day has come. You have finally grown bored of long scrolls of text and are looking for a new format. Something elegant. Something compact. Something that takes the long scroll, cuts it into neat little rectangles and binds them together. I call this invention the “book”.

With the power of CSS regions (CanIUse, go to chrome://flags and enable CSS Regions) and CSS 3D transformations, cutting-edge book technology is finally available on modern browsers. All you need is a few lines of JavaScript and a whole lot of CSS.

Let’s start off by defining our book structure. The book consists of pages and the pages consists of two sides. The sides contain the book content:

<div class="book">
        <div> <!-- first page -->
          <div> <!-- front cover -->
            <h1>My Fancy Book</h1>
          </div>
          <div> <!-- backside of cover -->
            <h1>By Me I. Myself</h1>
            <h2>2012 Bogus HTML Publishing Ltd</h2>
          </div>
        </div>
        <!-- content pages -->        
        <div>
          <!-- front side of page -->
          <div class="book-pages"></div>
          <!-- back side of page -->
          <div class="book-pages"></div>
        </div>
       <div>
          <div class="book-pages"></div>
          <div class="book-pages"></div>
        </div>
        <div>
          <div class="book-pages"></div>
          <div class="book-pages"></div>
        </div>
</div>

We’re going to use CSS regions to flow the book text into the book pages. But first we need the book text.

<span id="book-content">
  blah blah blah ...
</span>

Now that we have written our book, let’s define the flow CSS. I’m using the + character as a vendor prefix placeholder, replace it with -webkit- for WebKit browsers, -moz- for Firefox, and so on:

#book-content {
  +flow-into: book-text-flow;
}
.book-pages {
  +flow-from: book-text-flow;
}

Now the content from the #book-content span will go into the .book-pages divs instead. This is a rather poor book though. For a more bookish book we must embark on a quest. Our journey shall lead over the rainbow bridge of CSS transforms to the clockwork kingdom of JavaScript. In the halls of the mechanist fairylords we shall unleash epic transition magicks and obtain the fabled three keys that control the overworld interface.

The guardian of the rainbow bridge imparts on us the wisdom of stylish structural selectors so that we may turn our HTML book structure into a more book-shaped form:

html {
  width: 100%;
  height: 100%;
}
body {
  /* The entire body is clickable area. Let the visitor know that. */
  cursor: pointer;
  width: 100%;
  height: 100%;
  /* Set the perspective transform for the page so that our book looks 3D. */
  +perspective: 800px;
  /* Use 3D for body, the book itself and the page containers. */
  +transform-style: preserve-3d;
}
.book {
  +transform-style: preserve-3d;
  position: absolute;
}
/* Page containers, contain the two sides of the page as children. */
.book > div {
  +transform-style: preserve-3d;
  position: absolute;
}
/* Both sides of a page. These are flat inside the page container, so no preserve-3d. */
.book > div > div {
  /* Fake some lighting with a gradient. */
  background: +linear-gradient(-45deg, #ffffff 0%, #e5e5e5 100%);
  width: 600px;
  height: 400px;
  overflow: hidden;
  /* Pad the page text a bit. */
  padding: 30px;
  padding-bottom: 80px;
}
/* Front of a page */
.book > div > div:first-child {
  /* The front side of a page should be slightly above the back of the page. */
  +transform: translate3d(0px, 0px, 0.02px);
  /* Add some extra padding for the gutter. */
  padding-left: 40px;
  /* Stylish border in the gutter for visual effect. */
  border-left: 2px solid #000;
}
/* Back of a page */
.book > div > div:last-child {
  /* The back side of a page is flipped. */
  +transform: rotateY(180deg);
  padding-right: 40px;
  border-right: 2px solid #000;
}
/* Front cover of the book */
.book > div:first-child > div:first-child {
  /* The covers have a different color. */
  background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
  /* Put a border around the cover to make it cover the pages. */
  border: 2px solid #000;
  /* And center the cover. */
  margin-left: -1px;
  margin-top: -1px;
}
/* Back cover of the book */
.book > div:last-child > div:last-child {
  background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
  border: 2px solid #000;
  margin-left: -1px;
  margin-top: -1px;
}

In thus creating a somewhat paper-shaped style for our HTML, we arrive at the trillion-geared gates of the JavaScript kingdom. To pass through the gate, we must turn our flat book into a proper volume. To add some volume to the book, we offset each page slightly on the z-axis.

(function() {
var books = document.querySelectorAll('.book');
for (var i = 0; i < books.length; i++) {
  var book = books[i];
  var pages = book.childNodes;
  for (var j = 0; j < pages.length; j++) {
    if (pages[j].tagName == "DIV") {
      setTransform(pages[j], 'translate3d(0px, 0px, ' + (-j) + 'px)');
    }
  }
}
})();

Casting transition magic to impress the fairylords is not the most difficult of invocations. Yet, the results make the pages of our book animate their turning in a smooth fashion.

.book > div {
  +transition: 1s ease-in-out;
}

Finally, to make the pages actually turn, we need to bind the events themselves to our cause.

(function(){
	// Get all the pages.
	var pages = document.querySelectorAll('.book > div');
	var currentPage = 0;
	// Go to previous page when clicking on left side of window.
	// Go to the next page when clicking on the right side.
	window.onclick = function(ev) {
	  if (ev.clientX < window.innerWidth/2) {
	    previousPage();
	  } else {
	    nextPage();
	  }
	  ev.preventDefault();
	};
	var previousPage = function() {
	  if (currentPage > 0) {
	    currentPage--;
            // Rotate the page to closed position and move it to its place in the closed page stack.
	    setTransform(pages[currentPage], 'translate3d(0px,0px,' + (-currentPage) + 'px) rotateY(0deg)');
	  }
	};
	var nextPage = function() {
	  if (currentPage < pages.length) {
            // Rotate the page to open position and move it to its place in the opened stack.
	    setTransform(pages[currentPage], 'translate3d(0px,0px,' + currentPage + 'px) rotateY(-150deg)');
	    currentPage++;
	  }
	};
})();

With that, we have acquired the “book” technology and can evacuate the overworld crystal towers and leave behind their blinding glare and the fierce nuclear fires of Achenar, the great blue star of the overworld nexus. We triumphantly return to our homes, brandishing our books high above our heads, ready for the inevitable cascade of parades and celebrations in our honor.

You can see an example online here and get the full source for the examples. If you don’t have CSS Regions in your browser, the example will look quite broken. In which case you can try this example instead.

SwiftShader brings software 3D rendering to Chrome

By Ilmari Heikkinen at

SwiftShader is a software 3D renderer used in Chrome 18 that lets you use CSS 3D and WebGL even on blacklisted GPUs. SwiftShader is available only on Windows and kicks in when you visit a site that uses 3D graphics features.

The first time you run Chrome, it checks if your GPU is blacklisted. In the unfortunate case that it is, Chrome downloads and installs the SwiftShader component in the background. After the component is installed, you can view 3D content. If you visit a 3D site before the component has finished installing, you may need to close and re-open the tab to view the site.

The performance of SwiftShader should be good enough to view simple 3D content.

To force-enable SwiftShader for testing purposes, start Chrome from the command line with the —blacklist-accelerated-compositing and —blacklist-webgl flags.

You can read more about Chrome 18’s new graphics features (including GPU-accelerated 2D canvas) at the Chromium Blog

WebGL demo roundup

By Ilmari Heikkinen at

Developers keep pushing the boundaries of what's possible to do in the browser. Here are some awesome new WebGL demos from around the web to showcase what your browser can really do. First off, have a gander at this impressive three.js dynamic terrain rendering demo from AlteredQualia. The second demo is Nouvelle Vague from the French web design agency Ultranoir, and it shows a very particular way to read tweets. Mr.doob comes back with another three.js demo, this time using data captured by a Kinect. Also using three.js is One Millionth Tower, a documentary funded by the Canadian National Film Board. And last, these guys got WebGL running on an iPad 2 through a WebView hack.

In other news, the Google Data Arts Team launched a workshop page to share the technology they've used to build some amazing demos. The page has a great tutorial on using dat.GUI, go check it out!

Having a ride with Three.js

By Ernest Delgado at

If your browser supports WebGL try this awesome demo so you can drive a car in 3D with no plugins at all. We are seeing more and more developers coming up with new 3D demos whether they were OpenGL experts already or new adventurers that started playing with it.

To make developer’s life easier there is the well known Three.js library, that abstracts the native methods to increase your productivity. The aforementioned demo is obviously using it too.
Our in-house expert, Ilmari Heikkinen, has built some interactive slides to guide you through the creation process step by step. Enjoy!

[Screenshot from creativeJS]