Experiments
This is my creative lab and interactive playground. It's focused on exploring
interaction, visual effects and technologies. Right now, my experiments are
primarily built in HTML but that is likely to change down the line.
Please don't use this as HTML vs Flash firewood. I do it because it's fun.
Not because it's HTML.
Recap 2011
It's that time of the year again! In late 2010, having spent five great years working at
Fi, I was determined to change up my professional life. After
interviewing with Qwiki and accepting the position of Lead
Interactive Developer it was decided; I was moving to San Francisco! It took a good few months of
hard work to sort out all of the practicalities but it was definitely worth it now that I'm here.
Fortunately I've still been able to keep this site updated and worked on a variety of projects
and experiments throughout the year.
The first project to see the light of day was Sketch,
a drawing tool that mimics the style of old cartoons. It was refreshing to build something that allows
others to be creative. Now – almost a year later – over 78,000 sketches have been saved.
Sketch was followed by a short freelance project which involved building an interactive and animated
logo for a Canadian media production company called Meru. Try it out on their site;
http://meru.ca/.
Next I stumbled into the land of CSS3 3D transforms and ended up trying them out on two projects;
Holobox and CSS3 3D Slideshow (later renamed
reveal.js). A few weeks ago, in mid December, I resumed
my CSS 3D pursuits by creating a rolling effect
for links and building a Christmas tree out of form elements.
Being far from tired of working with <canvas> I also created a new game called
Coil, it's similar in design to Sinuous
but adds a touch of WebGL and perhaps an element of stress to the gameplay. Shortly thereafter I worked on a
tool called Textify.it which allows you to recreate images using thousands
of letters of text. Using Phonegap, I was able to easily port Textify.it to iOS.
It's been really encouraging to see that there's still a lot of activity on sinuousgame.com
even though it's been out since 2010 – meaning ancient, in internet-time. In the past year it saw more than 2,000,000 visits.
Now the new year is approaching and with it new adventures. 2012 will start with relocating to NYC and
opening up Qwiki's new office. Can't wait to see where it goes from there!
DOM Tree
Happy holidays! I didn't get a pine tree for Christmas this year so I decided
to compensate by creating a digital counterpart out of HTML form elements.
The DOM tree is generated via JavaScript every time you visit the page so you'll
never see the same one twice. All of the forms are filled with holiday greetings
in a variety of languages. CSS3 3D transforms are used to position and rotate, via
translate3d() and rotate3d() respectively, the elements
when the page loads. The infinitely looping rotation on the tree is controlled by
an infinitely looping CSS3 animation.
All of the form inputs are interactive so I challenge you to try and select some of
those <input type="radio"> snow flakes!
zoom.js
zoom.js is a small proof of concept JavaScript library for zooming in on DOM
elements or points in a document. It uses CSS3 transitions and 2D transforms (scaling, translation, transform origin)
on the <body> element to achieve animated magnification.
The API is very minimal;
zoom.in({
element: <HTMLElement>
});
zoom.in({
x: 150,
y: 50,
width: 300,
height: 300
});
zoom.out();
reveal.js
Reveal.js, formerly CSS 3D Slideshow, is a
tool which allows you to quickly create good looking HTML presentations. Beyond the changed name, the updated
slideshow includes a fair amount of new features:
- New and improved style.
- Added controls in bottom right which indicate where you can navigate.
- Reveal views in iteratively by giving them the
.fragment class.
- Code sample syntax highlighting thanks to highlight.js.
- Transition themes (available via init options) default/concave/linear.
- Initialization options (toggling controls, toggling rolling links, transition theme).
Sphere: Revisited
The next js1k is still ways off but I felt like crunching some
JavaScript so I revisited my Sphere experiment.
I was able to squeeze it down into 309 bytes and that includes the code for creating
and appending the <canvas> element to the body. Here's the full thing:
var a=document,b=a.body.appendChild(a.createElement("canvas")),c=b.getContext("2d"),d=0,e=b.width=a.width,f=b.height=a.height,g=Math.cos,h=Math.sin,j=Math.PI;setInterval(function(){b.width=b.width,d+=.1;for(i=1e4;i--;)r=(e+f)/2*(g((d+i)*(.05+.2*(h(d/1e5)/j)))/j),c.fillRect(h(i)*r+e/2,g(i)*r+f/2,1.5,1.5)},16)
Leave a comment if you can think of more ways to reduce the size!
UPDATE 1:
Mathieu 'P01' Henri was able to squeeze it down to 247 bytes http://jsfiddle.net/LBBmM/1/
UPDATE 2:
As if 247 wasn't enough, P01's latest update drops the canvas element and hits 222 bytes! http://jsfiddle.net/LBBmM/32/
Rolling Links
Decided to spice up the text links throughout my site by reviving an old Flash classic – the 3D roll!
You'll only be able to see the new style if your browser supports CSS 3D transforms,
at the time of writing that means Firefox Nightly, Chrome or Safari.
The only HTML required for this effect is a <span> wrapper around the inner HTML of the target anchor node. The :after
pseudo-element, and its content: attr(...) property, is used to create the flip side. The 3D transformation is carried out
on the <span> wrapper since transitions are not possible on pseudo-elements.
If you're interested in the code, it's availalable over at jsFiddle.net for all your forking pleasure.
Origami
Simply a colorful folding doodle on <canvas>. Click anywhere
on the drawing -- or use your keyboard -- to activate different layouts.
Interview: TechRant
I was interviewed by Ben Hutton of TechRant
and shared some of my thoughts about the open web, personal projects and professional life.
404
The folks over at .net magazine have decided
to spruce up their 404 page with the help of a few guest artists. For my slot I
decided to go for a creepy theme inspired by one of my
earlier experiments.
The animation is entirely code generated and drawn on an HTML5 canvas element.
If you're interested in how this was created, have a look at the
source code on GitHub.
Sphere
When bored, I sometimes open a blank JavaScript file and start writing
without any clear objective of where I want to take it. This is the result
of one such coding session.
The sphere -- actually more of a spiral -- is built out of 10,000 particles
and the structure changes over time.
AppView
AppView was created to help iOS app developers track recent reviews in all markets
of the App Store without having to use iTunes Connect's cumbersome UI. Reviews can be
sorted on date, rating or store and are automatically translated to English via the
Google Translate API.
Textify.it for iOS
I was really happy with how the Textify.it web app turned
out and decided it was worthwhile creating a version targeted at iOS. I've been curious
about the potential of building iOS apps using the standard array of open web technologies.
With the help of PhoneGap, a framework which bridges
JavaScript to native functionality, it was incredibly easy to get going. The iOS version of
Textify.it is based on the same JavaScript core as the online version. Some code was added to
fire up the camera/library as well as for saving images onto the device.
One challenge with any HTML app targeted at iOS and Mobile Safari is rendering performance,
particularly so when using the HTML5 canvas element. The mobile version of Textify.it maintains
the original resolution of images and those images may well be 2048x1536 pixels large (iPhone 3GS).
The most fruitful optimization for this was to use a CSS transform to scale the canvas rather
than doing so via its width/height properties. This seems to force the browser to apply a different, faster,
image scaling method. Jonas Wagner has written a post about a similar technique for improved
performance here.
Textify.it is available for both iPhone and iPad
with a $0.99 price tag.
Textify.it
Browser for or drag an image onto the page and watch it be reconstructed purely out
of text. The markup for the resulting textual image can be copied and used elsewhere.
There are a lot of settings which allow you to control the characteristics of the text.
Even the smallest tweak to the settings can result in a very different output. Beware that
using very large amounts of text will cause heavy browser lag.
WebGL Particles
Was curious about how to efficiently render particles with WebGL so
I built a tiny demo. Move your mouse to generate particles.
Canvas Optimization
Building Coil presented me with a few interesting technical
challenges. Primarily I had a hard time making the game operate at a reasonable framerate since it uses both
2D Canvas and WebGL. Double whammy. Even though I am still not fully satisfied with how the game performs,
I wanted to share some of the optimization techniques used.
Redraw Regions
The best canvas optimization technique for animations is to limit the amount of pixels
that get cleared/painted on each frame. The easiest solution to implement is resetting the entire canvas element
and drawing everything anew but that is an expensive operation for your browser to process.
To limit the areas which are cleared in Coil, I keep track of exactly which rectangular regions are being painted in
so that I can then clearRect(x,y,w,h) only those. This results in the following flow:
1. Clear pixels of all redraw regions
2. Reset redraw region list
3. Paint all elements and store their individual redraw regions
Coil has a debug mode in which these redraw regions are displayed as green rectangles,
try it out.
Procedural Sprites
Even though I'm an advocate for generating graphics procedurally, sometimes that's not the most efficient
approach. If you're drawing simple shapes with solid fills then by all means drawing them procedurally
is the way to go. But if you're drawing more detailed entities with strokes, gradient fills and other
performance sensitive make-up you'd be better off using image sprites.
In Coil I use a hybrid approach. Graphical entities are generated procedurally on canvas, but
only once as the game starts up. For the rest of the game's lifespan I paint copies of those sprites rather
than repeatedly generate the same drop-shadow, gradient and strokes.
One final tip when working with image sprites is to always draw them on integer x/y coordinates for better
performance on OS X browsers. You can read about this in greater detail
here.
Computation Distribution
The Chrome Developer Tools profiler is
very useful for finding out what your performance bottlenecks are. In my case, for Coil, the two heaviest operations
were the discovery of enclosures and rendering of WebGL. Both of these operations were being executed on every frame.
To distribute the processing for these two operations I changed it so that enclosure discovery only occurs on even
frames while WebGL only gets rendered on odd frames.
Performance Based Scoring
From a scoring point of view, bad performance can be beneficial when playing a reflex based game since it
gives you more time to react. To combat this unfair advantage I scale down the scores by a factor of the
current FPS divided by the target FPS.
Another, perhaps more elegant, solution to this problem is to base all game mechanics on time rather than
frames.
Coil
While working on Sinuous I had an idea for a gameplay feature
that involved drawing circles around your enemies to destroy them. Trying not to add too many
features in one game I decided not to implement it at that point and instead revisit it as a separate
game.
Much like Sinuous, Coil is a very straight forward game with as few features and gameplay elements as
possible.
The objective is to defeat enemies by enclosing them in the trail formed by your tail. Enemies found
within those closures are obliterated. There are two types of enemies; the blue
kind explodes after time and causes you damage, red enemies on the other
hand are obstacles which should never be drawn into the enclosed area as that will also cause you damage.
Determining how to isolate enclosed areas, and enemies therein, was a very interesting challenge.
The final implementation is a three-step process. First I check all line segments in the tail for
intersections with each other. Once an intersection is discovered, that enclosed area is filled with
a unique color. Finally, collisions are found by checking if the color underneath an enemy matches the
closure's unique fill color.
CSS3 3D Hologram
After seeing a video demonstration
of a holographic effect created with HTML/CSS I was inspired to build something similar. I ended up creating a
3D box which alters perspective depending on device orientation.
CSS3 3D transforms are used to distort HTML elements and create the walls of the box. JavaScript then tracks
the deviceorientation and devicemotion events and updates the 3D perspective
accordingly. The only property that is being changed via JavaScript is the perspective origin, or
-webkit-perspective-origin to be exact.
Note that this requires a webkit browser and has only been tested on iPhone.
WebGL Shaders
WebGL's introduction is very exciting due to the powerful graphical capabilities it enables in the
browser context. This power originates from the ability to run highly optimized programs on the GPU
via shaders written in the
OpenGL Shading Language – or
GLSL for short.
There are two types of shaders; vertex shaders which are used to calculate
transformations of vertices and fragment shaders which are used to process
indiviual pixels.
Aiming to start learning more about the GLSL language I wrote a few abstract fragment shaders.
To avoid some of the rudimentary work I used three.js
to compile and run my shaders. I've also been referencing the wonderful
Shader Toy for learning examples.
CSS3 3D Slideshow
While preparing a presentation on SVG for an upcoming Stockholm Web Monkeys
meetup I needed to construct a simple slideshow. Since this would only ever be presented in a
controlled environment, I decided to take the opportunity and experiment with CSS 3D transforms.
The transition between slides is made possible by a combination of CSS 3D transforms and
transitions. JavaScript is in charge of updating the class names of all slides depending user
input and CSS takes it from there. Thanks to the limited logic involved I was also able to
avoid using any third party libraries.
Each slide can contain a nested slideshow. The top level slideshow is navigated via
keyboard left/right and the nested slideshows are then reached by using the up/down arrows.
Tip: you can improve the rendering performance of transitions/animations in mobile Safari by
applying a dummy CSS 3D transform. For example: -webkit-transform: translate3d(0,0,0).
Note that this requires a browser with support for CSS3 3D transforms, such as
Chromium or mobile Safari.
02-08-2011: The slideshow now provides unique URL's per slide which in turn
enables support for internal links.
BreakDOM
Ever wondered what it would feel like to attack a bunch of checkboxes
with a radio button that's being steered by a scrollbar?
This is a remix of the classic Breakout
game except all game elements have been replaced with HTML user interface
elements.
Meru Logo Animation
In early 2011 I collaborated with Canadian media production company
Meru on a small but very interesting project.
The objective was to "...produce a code generated logo that reacts to various inputs..."
and works on all platforms. Having looked at the fluid shape in the logo design I felt this
would be a lot of fun to take on – and so I did.
I animated the logo using the HTML <canvas> element and created a fallback
with rotating images for sans <canvas> browsers. The animtion consists of a
few core properties of the logo, such as shape and color, changing slowly using a fine
combination of randomness and control. Realizing that it would take some value tweaking for
everyone involved to be satisfied with the look and feel, I provided an easy way for Meru to
configure the logo. If you're curious about how this looks you can view the source of
this page and look for MeruLogo.initialize.
The animation also works with touch input and runs smoothly on most mobile devices. That latter
part is somewhat of a surprise since everything I've done with <canvas> up
till this point has always been dissapointingly slow in those environments. The primary reason
for why it works so well in this case is that it's rendered at a relatively small resolution.
I'm really happy with how this turned out in the end. The organic nature of the animation
compliments the logo design very well without sacrificing any of its core visual principles.
Spring Cleaning
Out with the old, in with the new! I finally got around to creating a new site for myself.
Even though it hadn't grown very old, my previous portfolio
ended up being a limitation in what type of content I could publish so I decided it was
time for a revamp.
I Joined the Qwiki team!
Translating information from a format aimed at computers into a presentation tailored for human beings is
an incredibly powerful concept. That is what Qwiki does.
And does incredibly well. After first discovering the product late last year I couldn't stop playing around
with it. Coincidentally I received an email a few weeks late from Doug Imbruce, founder and CEO of Qwiki, asking
for a meeting. After that meeting – and many interviews – I was offered a job and accepted straight away.
Having worked many years in the advertisment industry I'm excited about the move to a product oriented
environment. Mainly because I want to invest my time and effort in one product that I personally believe in.
I also want to broaden my scope and what better way to do so than diving into the San Francisco startup scene.
Qwiki is truly a great company to be a part of. Everyone working there is genuinely talented at what they do and
passionate about the future of the product. Besides that, the office is also ridiculously well equipped, including:
catered breakfast/lunch/dinner every day, top of the line hardware, ping pong table, basketball hoop, beer tap,
wine fridge and a turtle.
Want to join me in improving the way people experience information? Check out the
job listings and
benefits.
20 Things - Page Flip
Following the launch of 20 Things I Learned About Browsers And The Web
there was a lot of interest regarding some of the HTML5 techniques empowering the site. In particular,
the page flip transition was a hot topic.
To explain how the page flip works, and how to create one of your own, I wrote a tutorial
which was published in .net Magazine (issue #211). This tutorial later went on to be available
on Google's HTML5Rocks.com as well.
Sketch
Remember those old cartoons where hand drawn lines appeared to vibrate because of
differences between frames? That's what this experiment simulates. It also adds a
third dimension to your drawings by allowing you to rotate the canvas.
Drawings can be saved and shared in the gallery.
Hakim El Hattab
I'm a web developer and creative programmer from Sweden that is as passionate about working
with animation and interactivity as I am technical implementation. My work experience
is broad and includes campaign sites in Flash, web apps in HTML, desktop apps in AIR,
experimental HTML5 and CSS3 projects as well as mobile development. I used to work at Fi,
a digital production agency in Stockholm, but recently moved to San Francisco to take
on the role of Lead Interactive Developer at a well known startup; Qwiki.
During my time with Fi I lead the development of both small and large-scale projects for
brands such as Google, BBC, Nintendo, Wacom and SAS.
My personal projects and experiments with HTML5, CSS3 and JavaScript have received a resounding
amount appreciation and recognition. They have been served to over 4,000,000 people
around the globe in the past year alone.
I am also an active part of the web development community and share the source code for most of my work on
GitHub.
Here's a list of some selected projects that I've had the pleasure to work on:
Where To Find Me
- Mail:
-
- Twitter:
- @hakimel
- Google+:
- hakim.se/+
- LinkedIn:
- http://linkedin.com/in/elhattab
- github:
- https://github.com/hakimel
- jsdo.it:
- http://jsdo.it/hakim
Pool
This is my first experiment with WebGL. Even though I am very much for the idea of using
librares to abstract away some of the rudimentary work involved in programming, I
believe it is crucial to understand what happens behind the curtains. With that
reasoning in mind, I set off to create this very basic example only so that I would
gain an understanding of what makes WebGL tick.
Interested in getting started with WebGL? I highly recommend going through
The Lessons on learningwebgl.com.
HTML5 Canvas Tips
As the HTML5 spec is slowly making its way from working draft to recommendation and browser implementations
are solidifying – the urge to make use of these new features grows strong.
Coming from a Flash background, and being a sucker for anything that moves or can be interacted with, I am
most excited about the introduction of the <canvas> element which allows for
bitmap drawing through JavaScript. I started creating some visual experiments
using canvas a few months back and have gathered some tips for anyone dabbling in this neck of the woods.
Performance
When working with animation on canvas, performance can be a challenge since bitmap operations are very
processing expensive, especially at high resolutions. One important optimization rule to follow is to reuse
as many pixels as possible between frames. What I mean by that is the fewer pixels that need to be processed
each frame, the faster your program will run. For example, when erasing pixels with the
clearRect(x,y,w,h) method, it is very beneficial to clear and redraw only the pixels
that have changed and not the full canvas. Unlike the Flash Player’s redraw
regions, this management of “dirty rectangles” needs to be done manually for canvas.
State Stack & Transformation
The canvas can be manipulated via transformations such as rotation and scaling, resulting in a change to the
canvas coordinate system. This is where it’s important to know about the state stack for which two methods are
available: context.save() (pushes the current state to the stack) and
context.restore() (reverts to the previous state). This enables you to apply
transformation to a drawing and then restore back to the previous state to make sure the next shape is not
affected by any earlier transformation. The states also include properties such as the fill and stroke colors.
Compositing
A very powerful tool at hand when working with canvas is compositing modes which, amongst other things, allow
for masking and layering. As an example you can check out Bakemono, where composite modes are used to mask
the eye and mouth. There's a wide array of available composite modes and they are all set through the canvas
context's globalCompositeOperation property.
Anti-Aliasing
To allow for sub-pixel drawings, all browser implementations of canvas employ anti-aliasing (although this
does not seem to be a requirement in the HTML5 spec). Anti-aliasing can be important to keep in mind if you
want to draw crisp lines and notice the result looks blurred. To work around this you will need to either
round to integer values or offset by half a pixel depending on if you’re drawing fills or strokes.
Clearing the Canvas
To clear the entire canvas of any existing pixels context.clearRect(x,y,w,h) is
typically used – but there is another option available. Whenever the width/height of the canvas are set, even if they
are set to the same value repeatedly, the canvas is reset. This is good to know when working with a
dynamically sized canvas as you will notice drawings disappearing.
Next Steps
If you’re interested in learning more about canvas, I would suggest getting started by reading through Mark
Pilgrim's wonderful
Dive Into HTML5 chapter.
Once you're up and going this cheat sheet
is a great point of reference.
Conclusion
Canvas has been around for quite a while already and is supported by all modern, and some not so modern, browsers.
This being the case, I think it’s very much ready to be used for real production. Some suitable places to utilize
canvas would be to enrich buttons, charts/data visualization and navigational elements such as a list of thumbnails
for an image gallery.
Sinuous on the Google Chrome Web Store
Preceding the release of the Chrome Web Store (CWS) I collaborated with Google
to prepare Sinuous as a launch title app. Following the launch in early
December 2010, Sinuous saw a major increase in activity and players. In
fact, sinuousgame.com has
seen over 900,000 visits since its launch and traffic is now
resting at about 5k visits/day.
There are two different ways to deploy apps on the CWS:
- Offline apps that are downloaded to the client.
- Online apps that open an existing app URL.
The latter has raised some discussion – and complaints – because it essentially
means that the "app" is no more than a bookmark. In some ways I agree with
this, but I still picked this route to avoid having to maintain and update separate
versions of the game.
If my app is merely a link to the original game, why do I bother
to use the CWS at all? One reason: exposure. The CWS is a very powerful
promotional channel for finding an audience.
Bacterium
An interactive experiment with bacteria in a playful and dynamic physics world.
20 Things I Learned About Browsers and the Web / Fi
An online book that aims to better people's understanding about the inner workings
of browsers and the web. This project was created for the Google Chrome Team while
I was working at Fi and my primary responsibility was building the HTML5 front end.
Collaborating with the Google Chrome team on this project was a great experience.
The expertise they brought to the table, both in terms of technology but also
in general project process and structure, was invaluable.
I'm really proud of the end result. It demonstrates a use of HTML5 that
can not be found in many other applications and has therefore shed light on what can
actually be accomplished using these technologies.
Created as part of a team while working at
Fi.
Core
Sinuous' sibling game. More evil red dots!
Sinuous Won 10k Apart
The 10k Apart competition, organized by MIX Online
together with An Event Apart, challenged
developers to build web apps in HTML5 using less than 10kb.
In the end 367 applications had been submitted and out of those my game, Sinuous,
ended up taking home the grand prize!
BBC - Life Is... / Fi
This site, built entirely in Flash, is used to showcase some of BBC Earth's
stunning nature photography. It's centered around a fluid interface that blends
organically into the edges of the page so that you can focus on what matters; the content.
Created as part of a team while working at
Fi.
Sinuous
A game built on the HTMLCanvas element which will test your mouse pointer reflexes. The
objective is to stay clear of the evil red dots and stay alive as long as possible. Even
though the game play is linear sinusoidal and the graphics are minimalist it can get quite addictive.
Sinuous is the grand prize winner of the 10k Apart
competition for best HTML application in under 10 kb and has seen close to one million plays
to date. The game was also released, and featured on the
Google Chrome Web Store.
Sinuous
A game built on the HTMLCanvas element which will test your mouse pointer reflexes. The
objective is to stay clear of the evil red dots and stay alive as long as possible. Even
though the game play is linear sinusoidal and the graphics are minimalist it can get quite addictive.
Sinuous is the grand prize winner of the 10k Apart
competition for best HTML application in under 10 kb and has seen close to one million plays
to date. The game was also released, and featured on the
Google Chrome Web Store.
Bakemono
A little monster that I brought to life with JavaScript. Bakemono is Japanese for monster.
Keylight
A playhead travels between keys which resonate in sound depending on where they are placed in the room.
Blob
Soft blobby physics. It's like, you know... jelly?
Magnetic
Control and create currents of particles which react to magnetic nodes.
Trail
Particle movement patterns that generate smooth trails.
Particle Depth
Particle positioning patterns using depth.
Wave
A wave with bubbles floating on the surface, the bubbles each represent a tweet with the word "water" in it.
Particles
Particles slide across the screen and grow as they get close to the mouse.
And then?
There's much more to put in here but as it turns out – it takes time to write up descriptions
and collect old material. To be continued...