Mozilla

Demos

Sort by:

View:

  1. Creating thumbnails with drag and drop and HTML5 canvas

    HTML5 Canvas is a very cool feature. Seemingly just an opportunity to paint inside the browser with a very low-level API you can use it to heavily convert and change image and video content in the document. Today, let’s take a quick look at how you can use Canvas and the FileReader API to create thumbnails from images dropped into a browser document.

    The final code is available on GitHub and you can see an online demo here. There is also a screencast available on YouTube:

    Step 1: Getting the files into the browser

    The first step to resize images in the browser is to somehow get them. For this, we can just add an element in the page and assign drag and drop event handlers to it:

    s.addEventListener( 'dragover', function ( evt ) {
      evt.preventDefault();
    }, false );
    s.addEventListener( 'drop', getfiles, false );

    Notice that we only prevent the default behaviour when we drag things over the element. This is to prevent the browser from just showing the images when we drag them in.

    The getfiles() function then does the hard work of reading all the files in and sending them on to the functions that do the resizing and image generation:

    function getfiles( ev ) {
      var files = ev.dataTransfer.files;
      if ( files.length > 0 ) {
        var i = files.length;
        while ( i-- ) {
          var file = files[ i ];
          if ( file.type.indexOf( 'image' ) === -1 ) { continue; }
          var reader = new FileReader();
          reader.readAsDataURL( file );
          reader.onload = function ( ev ) {
            var img = new Image();
            img.src = ev.target.result;
            img.onload = function() {
            imagetocanvas( this, thumbwidth, thumbheight, crop, background );
            };
          };
        }
      }
      ev.preventDefault();
    };

    The drop event gives us a property called dataTransfer which contains a list of all the files that have been dropped. We make sure that there was at least one file in the drop and then iterate over them.

    If the file type was not an image (or in other words the type property of the file does not contain the string “image”) we don’t do anything with the file and continue the loop.

    If the file is an image we instantiate a new FileReader and tell it to read the file as a Data URL. When the reader successfully loaded the file it fires its onload handler.

    In this handler we create a new image and set its src attribute to the result of the file transfer. We then send this image to the imagetocanvas() function with the parameters to resize (in the demo these come from the form):

    function imagetocanvas( img, thumbwidth, thumbheight, crop, background ) {
      c.width = thumbwidth;
      c.height = thumbheight;
      var dimensions = resize( img.width, img.height, thumbwidth, thumbheight );
      if ( crop ) {
        c.width = dimensions.w;
        c.height = dimensions.h;
        dimensions.x = 0;
        dimensions.y = 0;
      }
      if ( background !== 'transparent' ) {
        cx.fillStyle = background;
        cx.fillRect ( 0, 0, thumbwidth, thumbheight );
      }
      cx.drawImage(
        img, dimensions.x, dimensions.y, dimensions.w, dimensions.h
      );
      addtothumbslist( jpeg, quality );
    };

    This function gets the desired thumbnail size and resizes the canvas to these dimensions. This has the added benefit of wiping the canvas so that no old image data would be added to our thumbnail. We then resize the image to fit into the thumbnail using a resize() function. You can see for yourself what this one does in the source code, it just means the image gets resized to fit. The function returns an object with the width and the height of the new image and the x and y position where it should be positioned onto the canvas.

    If we don’t want the full-size thumbnail but instead crop it we resize the canvas accordingly and reset x and y to 0.

    If the user requested a background we fill the canvas with the colour. After that we put the image on the canvas with the x and y coordinates and the new width and height.

    This takes care of creating a new thumbnail on the canvas, but we haven’t got it as an image in the document yet. To this end, we call addtothumbslist():

    function addtothumbslist( jpeg, quality ) {
      var thumb = new Image(),
          url = jpeg ? c.toDataURL( 'image/jpeg' , quality ) : c.toDataURL();
      thumb.src = url;
      thumb.title = Math.round( url.length / 1000 * 100 ) / 100 + ' KB';
      o.appendChild( thumb );
    };

    This one creates a new image and checks if the users wanted a JPG or PNG image to be created. PNG images tend to be better quality but also bigger in file size. If a JPG was requested we call the canvas’ toDataURL() method with two parameters: the requested JPEG mime type and the quality of the image (ranging between 0 and 1 with 1 being best quality). If a PNG is wanted, we can just call toDataURL() without any parameters as this is the default.

    We set the src of the image to the generated url string and add a title showing the size of the image in KB (rounded to two decimals). All that is left then is to add the thumb to the output element on the page.

    That’s it, you can now drag and drop images into the browser to generate thumbnails. Right now, we can only save them one at a time (or if you have some download add-ons all at once). Would be fun to add Zip.js to the mix to offer them as a zip. I dare you! :)

    More reading:

  2. Screencast: 3D CSS rollovers and 3D CSS tester

    CSS 3D transforms as supported in the latest Aurora allow us to do some nice effects that in the past were only possible in Flash or with a lot of trickery using skewing and filters. I was asked to show a small demo the other day and thought it would be fun to spice up the classic image rollover:

    You can see this in action using Chrome, Safari or Firefox Aurora/Nightly. Older browsers should just show a normal roll-over (and yes, the first example looks weird due to the logo transparency but it makes the effect much cooler in supporting browsers).

    As people asked how this is done I thought it easiest to create a testing tool where you can play with 3D CSS yourself. Here’s a screencast where I explain how to use it and how the roll-over effects were done.

    I found a few interesting bugs while creating this and will file them now. This is the benefit of playing with new tech. Enjoy!

    More reading on this:

  3. Making the wait for the holidays easier – the MDN advent calendar

    Tomorrow we will release the MDN advent calendar at http://thewebrocks.com/calendar with a daily link on a web technology product, a MDN wiki page or a great demo collected by us over the last few days. You can get a preview of how the calendar will look and work here:

    As an extra bonus, we thought it would be fun to document the step-by-step development of the calendar and release it for you to re-use or get inspired by.

    You can get a white-labeled version of the calendar on GitHub and there is a two-part step-by-step instruction how it was built available: Part 1Part 2.

    It is an example of how to build something server-side (so you can’t cheat by setting your operating system calendar ahead), enhance it with JavaScript and make it smooth by using CSS transitions. This should work for everybody and by playing each technology to its strengths, the code is very small indeed.

    Enjoy, and see you tomorrow and the day after, and the day after that and…

  4. HTML5 context menus in Firefox (Screencast and Code)

    You may not know it, but the HTML5 specifications go beyond what we put in the pages and also define how parts of the browser should become available to developers with HTML, CSS and JavaScript. One of these parts of the specs are context menus, or “right click menus”. Using HTML5 and a menu element you can add new options to these without having to write a browser add-on. In Firefox 8 (the current one) we have support for those. See the following screencast for a context menu demo.

    The image example is pretty simple and was actually written by Paul Rouget as a demo in the original Firefox bug request. The main core is the HTML of it:

    <section id="noninteractive" contextmenu="imagemenu">
     
      <img src="html5.png" alt="HTML5" id="menudemo">
     
        <menu type="context" id="imagemenu">
          <menuitem label="rotate" onclick="rotate()"
                    icon="arrow_rotate_clockwise.png">
          </menuitem>
          <menuitem label="resize" onclick="resize()"
                    icon="image-resize.png">
          </menuitem>
          <menu label="share">
            <menuitem label="twitter" onclick="alert('not yet')"></menuitem>
            <menuitem label="facebook" onclick="alert('not yet')"></menuitem>
          </menu>
        </menu>
     
    </section>

    As you can see you link the menu element to an element via its ID. The contextmenu attribute then points to this one. Each menu can have several menuitems. Each of those gets a textual label and a possible icon. You can also nest menu elements to create multiple layer menus. Here, we add inline onclick handlers to point to different JavaScript functions to call when the menu item gets activated. The resulting context menu looks like this:

    image with a context menu

    The functionality is simple, all the rotate() and resize() functions do is add class names to the image using querySelector and classList:

    function rotate() {
      document.querySelector('#menudemo').classList.toggle('rotate');
    }
    function resize() {
      document.querySelector('#menudemo').classList.toggle('resize');
    }

    The real effect is in CSS transforms and transitions. As the image has an ID of menudemo here is what is needed in CSS to rotate and resize:

    #menudemo {
      -moz-transition: 0.2s;
      width:200px;
    }
    #menudemo.rotate {
      -moz-transform: rotate(90deg);
    }
    #menudemo.resize {
      -moz-transform: scale(0.7);
    }
    #menudemo.resize.rotate {
      -moz-transform: scale(0.7) rotate(90deg);
    }

    Notice that in a real product we should of course add the other browser prefixes and go prefix-less but as the functionality now only works in Firefox, this is enough for this demo.

    Detecting support and visual hinting

    Now, as this is extending the normal user offerings in the browser we need to make it obvious that there is a right-click menu available. In CSS3, there is a context-menu cursor available to us. When context menus are available, this should be shown:

    .contextmenu #menudemo, .contextmenu .demo {
      cursor: context-menu;
    }

    We test the browser for support by checking for contextmenu on the body element and for HTMLMenuItemElement in the window (this has been added as a pull request to Modernizr, too).

    if ('contextMenu' in document.body && 'HTMLMenuItemElement' in window) {
      document.documentElement.classList.add('contextmenu');
    } else {
      return;
    }

    Wouldn’t HTMLMenuItemElement be enough? Yes, but a real context menu should only offer functionality when it is sensible, and that is where contextMenu comes in.

    Turning menuitems on and off depending on functionality

    As a slightly more complex example, let’s add a “count words” functionality to the document. For this, we generate a counter element that will become a tooltip when the words were counted:

    var counter = document.createElement('span');
    counter.id = 'counter';
    counter.className = 'hide';
    document.body.appendChild(counter);
     
    counter.addEventListener('click', function(ev){
      this.className = 'hide';
    },false);

    This one is hidden by default and becomes visible when the hide class is removed. To make it smooth, we use a transition:

    #counter{
      position: absolute;
      background: rgba(0,0,0,0.7);
      padding:.5em 1em;
      color: #fff;
      font-weight:bold;
      border-radius: 5px;
      -moz-transition: opacity 0.4s;
    }
    #counter.hide{
      opacity: 0;
    }

    We start with two sections with context menus:

    <section id="noninteractive" contextmenu="countmenu">
      <menu type="context" id="countmenu">
          <menuitem class="wordcount" label="count words"></menuitem>
      </menu>
    </section>
     
    <section id="interactive" contextmenu="countmenuinteractive">
      <menu type="context" id="countmenuinteractive">
          <menuitem class="wordcount" label="count words"></menuitem>
      </menu>
    </section>

    We then loop through all the menuitems with the class wordcount and apply the functionality.

    var wordcountmenus = document.querySelectorAll('.wordcount'),
        i = wordcountmenus.length;
     
    while (i--) {
      wordcountmenus[i].addEventListener('click', function(ev){
        // add functionality
      }, false);
    }

    We need to find out what has been selected in the page. We do this by using getSelection() and splitting its string version at whitespace. We then show the counter by removing the hide class name.

    var wordcountmenus = document.querySelectorAll('.wordcount'),
        i = wordcountmenus.length;
     
    while (i--) {
      wordcountmenus[i].addEventListener('click', function(ev){
        var text = document.getSelection(),
            count = text.toString().split(/s/).length;
        counter.innerHTML = count + ' words';
        counter.className = '';
      }, false);
    }

    You can see this in action in the second context menu demo. Now, the issue with this (as explained in the screencast) is that it always counts the words, regardless of the user having selected some text. What we want is the menu only to be active when there is text selected.

    context menu item available or not available depending on selection

    So in order to make our menu only become available when it makes sense we check if there is a selection in the document. Every context menu fires an event called contextmenu when it opens. So all we need to do is to subscribe to this event.

    When something is selected in the document document.getSelection().isCollapsed is true. Otherwise it is false, so all we need to do is to enable or disable the menu item accordingly:

    document.querySelector('#interactive').addEventListener(
      'contextmenu', function(ev) {
        this.querySelector('.wordcount').disabled =
        document.getSelection().isCollapsed;
      },
    false);

    The last thing to solve is the position of the mouse to position the counter element. As the menu selection event doesn’t give us the mouse position we need to add a contextmenu handler to the whole document that positions the counter invisibly behind the menu when it is opened:

    document.body.addEventListener(
      'contextmenu', function(ev) {
        counter.style.left = ev.pageX + 'px';
        counter.style.top = ev.pageY + 'px';
        counter.className = 'hide';
      },
    false);

    Further reading and resources

  5. Screencast: CSS 3D rollover with fallback for older browsers

    Here’s a quick screencast how to create a 3D image rollover and still give a useful interface to browsers that do not support 3D transforms. If you want to see the effect in Firefox get the latest Aurora or Nightly. Check the following video to see what it looks like (first with a browser without CSS 3D transport, then with a newer one):

    The screencast is on YouTube:

    The main procedure to achieve the effect is simple. First we need a semantically valuable way to show these images, in our case a HTML list with figures and figcaptions. Notice that images still need an alternative text as the figcaption can apply to several images:

    <ul>
      <li class="image3d">
        <figure>
          <img src="mittens.jpg" alt="Mittens the cat">
          <figcaption>
            <p>
              <strong>Mittens</strong> loves to play with yarn and stuff.
            </p>
          </figcaption>
        </figure>
      </li>
    <!-- repeated -->
    </ul>

    We then position the caption absolutely inside the list item, give the list item dimensions and an overflow of hidden and move the caption outside of the visible space. When the user hovers over the list item (or focuses it with a keyboard) we move the caption to the right place and lower the opacity of the image.

    .positioned {
      list-style: none;
      width: 300px;
      height: 200px;
      position: relative;
    }
    .positioned figcaption {
      position: absolute;
      background: rgba( 0, 0, 0, 0.7 );
      color: #fff;
      border-radius: 5px;
      left: 65px;
      bottom: 10px;
      width: 230px;
    }
    .positioned img {
      opacity:0.4 ;
    }
    .positioned figcaption strong {
      display: block;
      color: lime;
      font-weight: normal;
      font-size:22px;
      padding: 5px 0;
    }
    .positioned figcaption p {
      display: block;
      color: white;
      padding: 5px;
    }
    .interactive {
      overflow: hidden;
    }
    .interactive img {
      opacity: 1;
    }
    .interactive figcaption {
      left: 300px;
    }
    .interactive:hover img, .interactive:focus img {
      opacity: 0.4;
    }
    .interactive:hover figcaption, .interactive:focus figcaption {
      left: 75px;
    }

    We make the effect smooth by adding transitions. Notice that it makes sense to list all the browser prefixes and set a prefix-less fallback. That way we don’t need to re-write code when a new browser supports them.

    .smooth img {
      -webkit-transition: all 1s;
      -moz-transition:    all 1s;
      -o-transition:      all 1s;
      -ms-transition:     all 1s;
      transition:         all 1s;
    }
    .smooth figcaption {
      -webkit-transition: all 1s;
      -moz-transition:    all 1s;
      -ms-transition:     all 1s;
      -o-transition:      all 1s;
      transition:         all 1s;
    }

    In order to rotate the kitty in 3D space, we need to give the list item a perspective and rotate the image and shift it in 3D space with translate3D to avoid clipping:

    .threed {
      -webkit-perspective: 800px;
      -moz-perspective:    800px;
      -ms-perspective:     800px;
      -o-perspective:      800px;
      perspective:         800px;
    }
    .threed:hover img, .threed:focus img {
      -webkit-transform: rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -moz-transform:    rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -o-transform:      rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -ms-transform:     rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      transform:         rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
    }

    That’s it. By adding all the browser prefixes, falling back to a simple rollover and by making sure you do the effect on hover and on focus you support all the browsers and bring the cool to the newest ones.

    More reading and resources:

  6. Screencast: BrowserID login flow on OpenPhoto.me

    BrowserID is an initiative to provide the web with a better way to sign in. The web is a connected collection of resources and you should not have to have a user name and password for each of them when you could use the web instead.

    Today we show you a screencast of how easy BrowserID makes it to login to a web site. For this, we’ll look at how the login flow for an existing BrowserID user works the first time they log in on a new website. Our example website is OpenPhoto, a hot new photo sharing app that keeps users in control of their data.

    Screencast of logging into OpenPhoto with BrowserID

    Get involved:

    BrowserID needs your help to grow and become a weapon of choice in the fight against insecure and annoying login systems. The great thing is that now is the time where you can be part of this.

  7. CSS 3D transformations in Firefox Nightly

    When the first 3D transformations in CSS got support on Webkit browsers people got incredibly excited about them. Now that they have matured we also support 3D CSS in Firefox. To see it for yourself, check out one of the latest nightly builds.

    You can see them in action in this demo of a rotating HTML5 logo and the screencast below:

    This means now that we need your support in trying out CSS 3D examples in Firefox and add other extensions than -webkit- to your CSS 3D products and demos. To show that this is possible, we took the well-known webkit-only “poster circle” demo and made it work with Firefox nightly by adding the -moz- (and of course the other prefixes and one set of instructions without browser prefixes). Here is a slight excerpt:

    -webkit-transform-style: preserve-3d;
    -moz-transform-style: preserve-3d;
    -o-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
    transform-style: preserve-3d;

    You can see this in action in the screencast below alongside Chrome and you try the demo out yourself. The slight jerkiness is actually my MacBook Air impersonating a starting jet every time I use ScreenFlow and not the browser.

    To celebrate the release and to show how CSS 3D can be applied as subtle effect, have a game of pairs using your favourite browsers (and a cat) :

    browser pairs

    Oleg Romashin also spent some time to convert a few CSS 3D demos to work with Mozilla and you can check the 3D city for more “wow”.

    If you are new to CSS 3D transformations here’s a good beginner course and a tool to create them.

    The rotating HTML5 logo demo also shows how you can check if the currently used browser supports 3D transforms. Instead of repeating the animation frames for all the prefixes we test in JavaScript and create the CSS on the fly:

    function checksupport() {
      var props = ['perspectiveProperty', 'WebkitPerspective',
                   'MozPerspective', 'OPerspective', 'msPerspective'],
          i = 0,
          support = false;
      while (props[i]) {
        if (props[i] in form.style) {
          support = true;
          pfx = props[i].replace('Perspective','');
          pfx = pfx.toLowerCase();
          break;
        }
        i++;
      }
      return support;
    }
    if (checksupport()) {
      var s = '';
      styles = document.createElement('style');
      s += '#stage{-'+ pfx +'-perspective: 300px;}'+
           '#logo{-'+ pfx +'-transform-style: preserve-3d;position:relative;}'+
           '#logo.spin{-'+ pfx +'-animation: spin 3s infinite linear;}'+
           '@-'+ pfx +'-keyframes spin {'+
           '0% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);'+
           '}'+
           '100% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(360deg)'+
           ' rotateZ(360deg);'+
           '}}';
      styles.innerHTML = s;
      document.querySelector('head').appendChild(styles);
    }

    For more information on creating your own pages that use 3D transformations, take a look at the draft specification

    As always, If you find any bugs, please report them at bugzilla.mozilla.org!

    So please reward our hard work bringing the third dimension to Firefox’s CSS engine by supporting and testing. Cheers!

  8. Debugging and editing webpages in 3D

    Tilt is a Firefox addon that lets you visualize any web page in 3D. A new update is available, coming with more developer-oriented features. Try the addon.

    Since the first alpha version of Tilt was announced (a Firefox extension focused on creating a 3D visualization of a webpage), a lot of work has been done to add a great number of developer-oriented features. These focus on debugging the structure of a webpage, inspecting styling and attributes for each node and seamlessly refreshing the visualization when the DOM structure changes or after contents of document are repainted.

    Solve nesting problems

    Tilt is useful when searching problems in the HTML structure (like finding unclosed DIV elements for example) by providing the extra third dimension, layering each node based on nesting in the DOM tree. Stacks of elements visually represent branches in the DOM, and each node can be inspected for the inner HTML contents, its computed CSS style and the attributes.

    Clicking anywhere on the visualization highlights a color-coded rectangle surrounding the corresponding node. Double click shows up the source preview for that node. Tilt also tries to show the most relevant information when needed (one is most likely to inspect the attributes of an input, button or image element, for example, but can easily switch between HTML, CSS and attributes view at any time).

    Minidom map

    The “minidom” is a tree view representation showing a minimalistic snapshot of the document object model. Each node is assigned a color associated by tag name (blue for div, green for span etc.) and represented as a strip, along with visual markers for the id and/or class if available. Each one of these strips also has a width relative to the type, id and class name length for the respective element, and the corresponding 3D stack in the visualization has color-coded margins. The coloring for individual elements is easily changeable using the color picker near to the minidom legend.

    Clicking a strip in the tree view (or directly a stack on the 3D document visualization mesh) also highlights the node with a colored quad. This behavior is a good way to relate with the Style Inspector, and a more unified interaction between Tilt and other Developer Tools is planned in the future. All of these additions make it easier to analyze the bounds of each node, along with the HTML, computed CSS and attributes.

    Realtime editing

    Because Tilt is able to detect when a webpage’s DOM structure changes or when a repaint is necessary, integration is seamless with existing Developer Tools. Using Tilt and Firebug or Style Editor at the same time is easy. One can enable or disable CSS properties, changing the style of a node, and the visualization changes accordingly.

    To enable realtime updates for the 3D webpage, go to the Options menu and check “Refresh visualization”.

    Useful for learning

    Developer tools such as “view source” have always been used to help people learn about web development. The 3D view highlights the structure of a page better than a flat view, thus anyone can immediately understand the parent-child relationship between nodes in a webpage, their positioning and how the layout is influenced.

    One use case for this is the Hackasaurus mashup. The X-Ray Goggles is a nice and fun tool designed to make it easier to learn about the different document node types, the “building blocks” which create a webpage.

    Export

    A requested feature was the ability to export the visualization as a 3D mesh, to be used in games or other 3D editors. Tilt adds the ability to export to .obj, along with a material .mtl file and a .png texture (a screenshot of the entire webpage). The open .obj format ensures the fact that the mesh can be opened with almost any editor. Here’s a ray-traced rendering of hacks.mozilla.org in Blender:

    Fun with experiments

    As soon as it was released, many people found clever and interesting alternative ways to interact with Tilt. One experiment was creating a 3D visualization of an image, by exporting chunks of pixels to a HTML representation. The result was a voxel-like representation, with node blocks and stacks instead of pixels. A simple Image2Tilt converter was written in JavaScript, and you can try it directly in the browser.

    Accelerometer support was another addition based on community request. This shows how easy it is to add functionality that wasn’t originally planned.

    You can view the source code, fork it and also contribute to the addon with ideas or feature requests on Github, at github.com/victorporof/Tilt.

    Available as an addon

    The latest version of Tilt can be found on Github, but you can also download Tilt as an addon from addons.mozilla.org.

    For compatibility, Tilt requires WebGL capabilities. Go to get.webgl.org to check availability and troubleshoot any issues. The current version works with Firefox 6.0 to latest 10.0 Nightly releases (latest Nightly builds now also support WebGL anti-aliasing, working great with Tilt).

    To start Tilt, hit Control+Shift+M (or Command+Shift+M if you’re on Mac OS), or go to Web Developer -> Tilt, available in the Firefox application menu (or the Tools menu on Mac OS). You can modify this hotkey (and other properties) from the Options menu after starting Tilt.

    More information about Tilt, the development process and milestone updates can be found on blog.mozilla.com/tilt.

    Future

    Tilt has become an active Developer Tools project, and an ongoing effort is made to integrate it with other existing tools like Style Inspector and Style Editor (source code and latest builds). As the 3D view of a webpage has proven to be useful for debugging, this main functionality will gradually become part of Firefox in future releases.

  9. Geolocation explained – a quick screencast

    If you’ve been here last week, you might have seen the webinar and geolocation Q&A with Remy Sharp. Sadly enough, we had a problem recording the screen so we recorded this replacement screencast yesterday night to give you a quick introduction to the Geolocation API.

    Once you are up to speed (or refreshed your memory) why not go and build something for this month’s Developer Derby?

    You can see the video on any HTML5 enabled device here (courtesy of vid.ly).

  10. Mozilla demoparty winners announced

    The Demoparty Online Competition 2011 is part of the Mozilla Labs Demoparty Project, an initiative to foster artful exploration of open web technologies.

    We asked people from the demo scene to have a go at web technologies and (with WebGL being the absolute winner of course) managed to collect over 100 submissions. Now the judges have spoken and we picked the winners in the categories of Main Demo, Single Effect, Audio Demo, Animated GIF and pure CSS demo.

    Amongst other great examples of using technology in a purely creative way unhindered by real life application needs here are the winners of Demo and Single Effect:

    Main Demo: Akemi

    Single Effect: WebGL Water Simulation

    Demo Link or screen capture:

    We congratulate all the winners and thank all those who contributed. Playing with technology is a big part of making it interesting for everyone to use.