Branching is fun.

November 29th 2009

It all started with this animated gif I found lurking on the internets some months ago...



I saved it for the day I was inspired enough to make the effect with Javascript. That day was yesterday...



I know I know, this isn't really branching, it's just a disgusting worms kind of effect, that was something I got while playing with it. The code is simple, a bunch of particles and you generate a random value that apply to the direction of each particle (aka random walk). To get branching now you need to randomly generate more particles on the position of these particles. Here it's the result:



I posted the effects over twitter and minutes later @thespite emailed me a modified version of this last iteration.



That was interesting! I didn't know <canvas> had a method for blitting. It gave an effect as if it was algae continuously growing while the camera was moving back. To enhance the effect I changed the path drawing to thicker circles.



That looked nice but was starting to be too visually complex (and cpu intensive). I like the 2D version better and then I wondered how could it work if I wired some of the values to the sound amplitude of a tune and then using <audio> again. Here it's the result.



I spent 10x more time looking for a track that suited the effect than doing the effect itself. In the end I found a nice track at the always-interesting enoughrecords netlabel.

And... that is all for today... as usual, with Javascript, the source code is one right click and one left click away. Have fun!

PS: It was nice to see that most of the effects worked on my Android phone. I guess they also work on iPhone? :D

74 comments

Eaze

November 25th 2009

Thanks to HIDIHO! blog I found out about a new Tween library developed by Philippe Elsass.

Yes, yet another Tween library. My favourite at the moment is BetweenAS3 and I though no library could change that. But this one brings a fresh syntax.

eaze(target).to(duration, { x:dx, y:dy })
    .onUpdate(handler, param1, etc)
    .onComplete(handler, param1, param2, etc);

I really missed the (not so old) Zeh Fernando's Tweener days. When everything was simple and clear, without twists and clubs... BetweenAS3 gave me back these days, but it was good to read that Phillipe shared my thoughts.

Now, lets end the drama and start to have fun again!
http://code.google.com/p/eaze-tween/

no comments

svg tag + audio tag = 3D Waveform

November 9th 2009



As always, you just need a bit of practice with a language to start using it in nice ways. Now that I had that little 3D engine working and with the <audio> around, it was time to produce an idea I always had in mine. A 3D interpretation of a waveform.

I'm sure the first thing you would think after checking this experiment would be... What? I didn't know I could analyse the sound signal with the <audio> tag?! ... Well, you can't, if you check the source code (*hint* right click -> view source) you'll see an array of numbers (deltas in fact). These are all the sound level values of the waveform at 30 fps.

I got these values using the library BASS for linux. Unfortunately, my C skills aren't so good (example) and I can't seem to control how to get the values exactly at the fps I want without getting desyncronisations. The first part of the visualisation is spot on, but by the end things aren't that impressive. I'll keep researching on this and update a new array of values whenever I crack it.

Dean McNamee showed me the way. Forget C and BASS. All you need is python, the tune in .wav and 23 lines of magic.

import math
import struct
import wave
import sys

w = wave.open(sys.argv[1], 'rb')
# We assume 44.1k @ 16-bit, can test with getframerate() and getsampwidth().
sum = 0
value = 0;
delta = 0;
amps = [ ]

for i in xrange(0, w.getnframes()):
	# Assume stereo, mix the channels.
	data = struct.unpack('<hh', w.readframes(1))
	sum += (data[0]*data[0] + data[1]*data[1]) / 2
	# 44100 / 30 = 1470
	if (i != 0 and (i % 1470) == 0):
		value = int(math.sqrt(sum / 1470.0) / 10)
		amps.append(value - delta)
		delta = value
		sum = 0

print amps

I've updated the experiment with the new values; now is perfectly in sync all the time. Which makes you appreciate the little sounds at the end much more. Thanks Dean!

As you'll see on the source code, the rest is very simple. Create a couple of cubes, place them one in from on each other, and modify their scaleY depending on the waveform they are related to in that step.

The end result is quite interesting I think and I hope doing more like these. Hopefully more interactive next time.

The factor that turned this from just a nice experiment to an awesome was the fact that the eedl guys allowed me to use their (great) tunes for my experimentation.

Thanks once again!

38 comments

More and more Javascript

November 4th 2009

Seems like I'm still hooked to Javascript. For the last few months, on my spare time I've been toying more and more with it, creating little pieces that will serve as personal benchmarks for browser performance improvements.

For the next few links I recommend using a WebKit based browser otherwise your browser may crash.

The first idea I wanted to try was creating a canvas using checkboxes as pixels. Then display animations with it. Similar to textmode renderers.



I posted the link over twitter and minutes later Aaron was sending me a drawing done with the checkboxes by Valdean Klump. On firefox, the experiment didn't worked correctly and it just created a grid where anyone could pixelate in. Because this, I created drawing tool out of it. I though it would be fun if I could also generate links on-the-fly so people could share their checkbox based drawings easily. This is how it ended up:



(Press Shift for the eraser tool)

Some days after, Joa Ebert ported a Strange Attractor code to Silverlight to compare performance with Flash. I knew that Javascript <canvas> was going to be way slower than these but I was curious how much.



I believe the code can get some performance optimisations for the platform but my interests were to compare exactly the same code. 7 F/S seemed a good start.

At this point I felt it was about time to go back to toying with 3D worlds. Many people were working on engines using <canvas> as the renderer. But I though I could try using <svg> as renderer instead.

Differences between <canvas> and <svg> are pretty much the same as BitmapData and Graphics. With <canvas>, performance decreases exponentially by the size of the viewport. It's easier to fill the pixels of a triangle at 10x10 than 1000x1000. With <svg> the bottle neck is the amount of vectors being drawn. Because they don't get rastered on a bitmap the nodes stay in memory and exponentially gets slower. However, viewport size isn't a much of a problem here, which ticks my fullscreen action requirement.

How do you draw with <svg>?

Good question. A <svg> is basically a XML. Every frame you fill it with nodes for each polygon with their properties. Then, on the next frame, you delete all the nodes and repeat the process. Sounds crazy, but it works. Here is the proof.



As you've probably ovserved, a benefit of <svg> that you can disable antialiasing (which you can't with <canvas>). This thing alone makes <svg> outperform <canvas>.

Now, don't get the wrong impression. At the moment I don't even know if texturing is possible with <svg>, I haven't investigated that yet. Something tells me that, if possible, it'll go horribly slow.

While working on all these I came up with some things I wanted to do that flat colors were good enough. One of these was a QR code in 3D. Now that I own an Android phone I keep seeing more and more QR codes. The shape of a QR code seemed like a little city and extruding it was something that excited my mind (yes, I'm weird).



I've learn quite a bit just for doing this piece. Inkscape for vectorising, Blender for extruding and colorising, Python for exporting from Blender and refactored my engine once again. Performance wise, its like going back to the Actionscript 2 days. But, hopefully, WebGL will arrive soon and I'll be able to play with more polygons. Until then, I can create a bunch of things just with these.

Feel free to study the sources for each piece if you are interested. If you find something wrong or that can be improved, please, let me know.

5 comments

Mr.doob left Hi-ReS!

September 17th 2009

As I posted on Twitter I'm no longer commuting from Victoria to Old St every day, nor having Franco's Fruit Salad every morning, nor randomly enjoying Franco's Spaghetti Carbonara, nor randomly enjoying BLT's Caesar Wrap, nor randomly enjoying Kick's Goat Cheese Salad, nor playing foosball matches at the end of the day, nor having beers and Brick Lane Bagels on Fridays and, most importantly, I'm no longer working on a studio with many talented and passionate people.

It's hard to believe that it's been already 2 years since I joined them. When you're having fun time goes really fast.

Thanks to everyone there, and specially to Theo and Mike for their constant support. It has been a great experience. :')

20 comments

Anatoly Zenkov's Portrait of Mr.Doob

August 31st 2009

Some months ago, the fact that the Hi-ReS! Stats seemed to be all over the internet made me come up with the idea of doing a A1 poster for the developers room in the office. Unfortunately, the idea got forgotten at some point.

This morning, while checking Twitter, I got intrigued by a Anatoly Zenkov tweet.



If discovering eedl yesterday made my day, I think this just made my month.

Now, what can I say? Thanks batch!! :'D

4 comments

Realtime 3D stuff with Javascript

June 10th 2009

Some weeks ago I did yet another chrome experiment for Instrument. In fact, it was a experiment I half started when I realised that with the css property -webkit-transform (and MozTransform) I could scale elements. So I ported my basic 3D engine to Javascript and I got it working in a few hours. But in the end I didn't finish that one.

So for this "second phase" I finished it, but this time using Google Image API. The end result looks like this:



Realtime version: Google Sphere.

Once I had this one done I got totally addicted to Javascript and wondered what else could I try. I have to say that the fact of being able to change the code from anywhere without having to recompile anything is priceless. I keep modifying the Google Sphere every week whenever I find new Javascript tricks, and to improve the movements a bit. The first iteration of the experiment used jsTween but found some problems with it (I actually don't remember what were the problems) and luckily I found JSTweener which with some modifications performed flawlessly.

Then I though about my good old DOF experiment with Papervision3D, and though how could achieve the same effect with Javascript. The trick is background offset. Just check this image and you'll understand :)

While working on this one I really missed the Hi-ReS! Stats because at the beginning it was going a bit slow with only 100 balls. So I ported the Stats to Javascript and thanks to this I ended up having 300 balls runing quite decently. This is how it looks like:



Realtime version: Depth of Field, 100% Javascript (debug).

Of course, you'll need Google Chrome (win/linux/mac) to see all this in full glory.

So, apparently, Javascript is able to move a bunch of pixels these days. Next thing will be to render a actual polygon.

PS: Should I say that the sources are available? ;)

10 comments

Windosill

June 9th 2009



Some weeks ago Vectorpark released a incredibly cute little game called Windosill. At first you had to download the game and play it on the desktop, paying $3 to play the second half of the game. Which I happily paid as I'm a big fan of this guy.

Now the game can be played online. It's one of those games with not too hard puzzles that make you feel good (aka clever) at the end of every stage. Also, technically, there are so many thing I don't know how were done. There is still magic on the flash world :)

What are you still reading this? You should be playing the game already.

EDIT: As vectorpark himself pointed out on the comments, for the online version it's still $3 to play the second part, it didn't pop up at me because I already paid for the desktop version. Anyway, it's well worth it!

12 comments

Optimising Asian fonts for Multi-language flash sites

April 23rd 2009

So I'm sure you've done a website that needed to be on 1,238 different languages. And every time you reached Chinese, Japanese, Korean... you got surprised that just the embeded font made your swf 9,000kbytes big.

For this project we're working on I'm mainly doing little tools with PHP. One of them is a translations manager, so you have a little SQL database with all the keywords and languages and someone fills it with data. At any point you can export it as .xml ready to be used in the website.

Having this set up, Theo came up with the idea that, as we had control on the text that was going to be needed for each language, we could do a script to output the list of characters needed for each font.

The PHP script goes down to this:

// In this case $lines is a associative array that comes from MySQL.

$list = array();

foreach($lines as $line)
{
	$string = $line["text"];
	$string = strip_tags($string);
	$string = str_replace('\n','',$string);

	preg_match_all('/./u', $string, $chars);

	foreach($chars[0] as $char)
	{
		$found = false;

		foreach($list as $listchar)
			if ($listchar == $char)
				$found = true;

		if ($found == false)
			$list[] = $char;
	}
}

foreach($list as $item)
{
	echo "U+" . zeropad( strtoupper( dechex( substr( mb_encode_numericentity ( $item, array (0x0, 0xffff, 0, 0xffff), 'UTF-8'), 2, -1 ) ) ), 4 ) . ",";
}

You'll also need this:

function zeropad($num, $lim)
{
   return (strlen($num) >= $lim) ? $num : zeropad("0" . $num, $lim);
}

What this code does (properly setted up in yours) is split the whole string into characters and check one by one if has been added to the list of characters used, if it's a new it just adds it. Then it writes a unicode list formated as U+XXXX. The output looks something like this:

U+0043, U+0048, U+0041, U+004E, U+0045, U+004C, U+002E, U+004F, U+004D, U+0052, U+0044, U+0049, U+0054, U+0053, U+5168, U+5C4F, U+89C2, U+770B, U+5176, U+5B83, U+8BED, U+8A00, U+6CD5, U+5F8B, U+58F0, U+660E, U+97F3, U+91CF, U+5E55, U+540E, U+82B1, U+7D6E, U+5965, U+9EDB, U+4E3D, U+2022, U+5854, U+56FE, U+0020, U+4E0E, U+8BA9, U+002D, U+76AE, U+8036, U+5C14, U+70ED, U+5185, U+62CD, U+6444, U+8BB0, U+5F55, U+73B0, U+573A, U+5F71, U+7247, U+0032, U+5206, U+0030, U+79D2, U+0036, U+00B0, U+0035, U+4F20, U+5947, U+4E3A, U+4EC0, U+4E48, U+9009, U+5851, U+9020, U+5973, U+795E, U+642D, U+4E58, U+591C, U+95F4, U+5217, U+8F66, U+7684, U+4EBA, U+6027, U+611F, U+8BF1, U+60D1, U+4F60, U+6700, U+559C, U+7231, U+955C, U+5934, U+7B2C, U+4E00, U+6B21, U+7EED, U+5199, U+8F89, U+714C, U+4EE3, U+00BA, U+9999, U+6C34, U+6C1B, U+5FC6, U+6211, U+53F7, U+2014, U+79D8, U+6570, U+5B57, U+0039, U+5948, U+513F, U+4E4B, U+5E74, U+7537, U+4E3B, U+89D2, U+5D14, U+7EF4, U+65AF, U+0660, U+8FBE, U+6587, U+6CE2, U+7279, U+8FC7, U+7A0B, U+4E2D, U+7F8E, U+597D, U+56DE, U+5609, U+4F2F, U+8389, U+5212, U+65F6, U+521B, U+4F5C, U+73CD, U+8D35, U+6735, U+539F, U+6599, U+5999, U+8C03, U+548C, U+5242, U+7A7F, U+8D8A, U+5149, U+7ECF, U+5178, U+56DB, U+79CD, U+6F14, U+7ECE

What's this for you'll ask. Well, just look at this:

[Embed(source="yourfont.ttf", fontFamily="YourFont", fontWeight= "bold", fontStyle = "normal",advancedAntiAliasing="true", mimeType="application/x-font-truetype", 
unicodeRange="U+0043, U+0048, U+0041, U+004E, U+0045, U+004C, U+002E, U+004F, U+004D, U+0052, U+0044, U+0049, U+0054, U+0053, U+5168, U+5C4F, U+89C2, U+770B, U+5176, U+5B83, U+8BED, U+8A00, U+6CD5, U+5F8B, U+58F0, U+660E, U+97F3, U+91CF, U+5E55, U+540E, U+82B1, U+7D6E, U+5965, U+9EDB, U+4E3D, U+2022, U+5854, U+56FE, U+0020, U+4E0E, U+8BA9, U+002D, U+76AE, U+8036, U+5C14, U+70ED, U+5185, U+62CD, U+6444, U+8BB0, U+5F55, U+73B0, U+573A, U+5F71, U+7247, U+0032, U+5206, U+0030, U+79D2, U+0036, U+00B0, U+0035, U+4F20, U+5947, U+4E3A, U+4EC0, U+4E48, U+9009, U+5851, U+9020, U+5973, U+795E, U+642D, U+4E58, U+591C, U+95F4, U+5217, U+8F66, U+7684, U+4EBA, U+6027, U+611F, U+8BF1, U+60D1, U+4F60, U+6700, U+559C, U+7231, U+955C, U+5934, U+7B2C, U+4E00, U+6B21, U+7EED, U+5199, U+8F89, U+714C, U+4EE3, U+00BA, U+9999, U+6C34, U+6C1B, U+5FC6, U+6211, U+53F7, U+2014, U+79D8, U+6570, U+5B57, U+0039, U+5948, U+513F, U+4E4B, U+5E74, U+7537, U+4E3B, U+89D2, U+5D14, U+7EF4, U+65AF, U+0660, U+8FBE, U+6587, U+6CE2, U+7279, U+8FC7, U+7A0B, U+4E2D, U+7F8E, U+597D, U+56DE, U+5609, U+4F2F, U+8389, U+5212, U+65F6, U+521B, U+4F5C, U+73CD, U+8D35, U+6735, U+539F, U+6599, U+5999, U+8C03, U+548C, U+5242, U+7A7F, U+8D8A, U+5149, U+7ECF, U+5178, U+56DB, U+79CD, U+6F14, U+7ECE")]
public var FontClass:Class;

In this way, you're going to import on the .swf only the characters you're using from the .ttf.

In our case, Chinese went down from 9,554kbytes to 45kbytes. That's a 99.6% reduction. Pretty cool!.

Hopefully this will save some sleepless nights to someone.

23 comments

Speaking at IED Madrid

April 21st 2009

Following the "a speech per year" tradition, here are the details for this year's one. It'll be open for anyone, so feel free to come around if you happen to be in town.

IED Master Madrid
May 13th, 2009 - 19.00h.

c/ Larra nÂș14, Madrid. [Metro Tribunal]

6 comments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Some of the projects that I worked on.



Some of the HTML5 and Actionscript experiments I've done.