Antti Kupila

Personal Blog, Portfolio and Online playground

View over the green room at Sid Lee, Montreal

Behind the scenes: 10 million facebook fans

It’s been forever since the last update so i figured i’d write something. Here’s a behind the scenes look at the recently launched 10 million fans celebration for adidas Originals, developed by Sid Lee Amsterdam.

The Brief

adidas Originals will hit 10 million fans on their Facebook page soon. Do something to thank these people for being part of the community. Or something in that direction, i’m paraphrasing.

The Idea

After numerous rounds of concepting with the team we come up with the idea of celebrating the fans instead the celebrities. After all; they’re the ones who made this happen. The execution of this was to create a short video that includes the fans in an interactive video mosaic style piece. The video gets overlaid with the fans’ profile pictures to build the picture. This came from an earlier internal prototype that we were able to apply to a client project.

Video mosaic

Making it work

We wanted to have good reach with this and specifically target the people on the adidas Originals page on Facebook. Because of this there wasn’t going to be a destination but instead push the video directly in the stream using the OpenGraph meta tags and build a custom video player. People on Facebook would see the video in the same way they see an embedded YouTube video, but they could also interact with it. In addition it wouldn’t be static but instead in real time pull in people who are fans.

Getting user ids

Thanks to the OpenGraph API it’s super easy to get information about people. All you need is the user id. Turns out there’s an open bug report in the Facebook bug tracker that prevents us from getting the people who are fans of a page. This worked before but there hasn’t been a response from Facebook since early December.. So, we couldn’t rely on this to get ids. We could screenscrape the insights page but this is against Facebook’s Terms of Service. Of course we could hardcode a list of ids but we didn’t want to do that. Instead the approach was to get a list of recent posts ( and then query those posts ({ postId }/likes&limit=1000) for people who like them. With this we were able to get a whole list of people who are the most active fans and interact with the content. We could get thousands and thousands of ids this way and it wasn’t against Facebook’s terms of service. In addition we get some names that add some extra spice. Perfect!

A shitload of images

With the user ids getting the profile pictures is as simple as loading{ user id }/picture. Facebook does the rest. So we load the profile pictures of the users. When the images have been loaded they’re scaled down to a 3x3px images, and the middle pixel is measured to get the average color of the image. This average color is then converted from HEX to HSV and all the data is stored in a value object in a Vector together with the original image, preprocessed (scaled down) images and some other details for quick & easy access. In addition the images that were going to be used on the grid were desaturated slightly and the contrast was turned down a bit to make them stand out a bit less.

Playing the video

The video is scaled down to a size where each pixel would respond to a profile picture. So with 5px images we scale down the video to 20%. The idea then would be to loop through each pixel of each frame of the video and replace that pixel with the closest match. These images are drawn to another BitmapData that is displayed. Seems easy enough…

Mapping color to picture

Let’s say we measure the the pixel at 0, 0 of the video and get a value of #006282. Which one is the closest match to this? As it’s highly unlikely an image would have the exact same average color we would need a lookup table that doesn’t require exact matches but instead finds the closest match. Also this had to be fast—super fast—to allow realtime playback. Looping through a vector of images to get their average color, calculating the distance to the input color and then sorting by distance seems like an obvious solution but is far too slow to process 6000+ images per frame. Instead we had to create a lookup map with some fuzzy logic to even out the images that don’t match perfectly…

Solution 1:

A Vector as a lookup table doesn’t really work as it requires exact matches so using a BitmapData seemed like a better solution. If we put consider the color a two dimensional object (x: hue, y: value) we can plot the input pictures out on an image. The previously mentioned #006282 has a HSV value of (Hue: 195°, Saturation: 100%, Value: 51%) so it would end up at x:195 y:51. The problem here though is that we end up with a lot of empty spots as not every single color is covered. We need support for these too, somehow…

A Voronoi diagram is commonly used for things like finding the closest radio tower to a cellphone. Kinda similar to what we’re doing here, right? We calculate a voronoi diagram based on the x, y coordinates mentioned above and each zone gets colored with an index to the picture. The result is rendered to a BitmapData. Then when we need to find the closest match to a picture we calculate the hue and value of it, and use that as x & y on a getPixel() on the lookup BitmapData. The result is a color that is the index to the image. Seems easy enough? :) Applying Lloyd’s algorithm a couple times to space out the data a bit helped the result even more. This allowed a match to be a bit off by either hue or value and the closest match would still be returned. This would support any number of images too, the closest one is always returned. Pefect!

The problem here though became performance. Even with the fastest (AS3 only) Voronoi algorithms calculating the diagram for the input images (1000+) was too slow and caused a hiccup after the load. In addition the algorithm didn’t scale that well as adding a new image exponentially increased the processing time. This is a bad user experience and we started looking for another solution (even if it’s a couple seconds on unresponsiveness). Sooo, killing the darling that had caused a ‘heureka!’ moment earlier… :(

Solution 2:

While a Voronoi diagram might be a fairly accurate way of finding the closest image speed was more important than accuracy here. The idea of using a BitmapData as a lookup table with hue and value mapped to X and Y still seemed like a good idea. Instead of calculating a voronoi diagram though we directly plot the colors (at 3x3px) to a BitmapData and after completion expand each zone to fill out the gaps. This is a ghetto solution but works much faster than a voronoi diagram and does the job. Judging by the visual result of both you couldn’t tell which approach was used.

Below you see an image before and after where the color was plotted to imageColorMap and then expanded. Seems pretty smooth. The imageLookupMap was used for the index.

Nothing special going on here but code for the curious:

  1. private function fillMap( ) : void {
  2.     var col : int = 0;
  3.     var row : int = 0;
  4.     var cols : int = 360; // degrees of hue
  5.     var rows : int = 100; // values (percentage)
  7.     var offset : int;
  9.     var indexes : Vector.<int>;
  10.     var colors : Vector.<int>;
  11.     var outputColors : Vector.<int>;
  13.     var iRow : int;
  14.     var iCol : int;
  15.     var iColor : int;
  16.     var oColor : int;
  17.     var overTop : Boolean;
  18.     var overBottom : Boolean;
  19.     var matchedTop : Boolean;
  20.     var matchedBottom : Boolean;
  21.     var overLeft : Boolean;
  22.     var overRight : Boolean;
  23.     var matchedLeft : Boolean;
  24.     var matchedRight : Boolean;
  25.     var i : int;
  26.     var n : int;
  27.     var color : int;
  29.     for ( col = 0; col < cols; col++ ) {
  31.         indexes = new Vector.<int>( );
  32.         colors = new Vector.<int>( );
  33.         outputColors  = new Vector.<int>( );
  35.         for ( row = 0; row < rows; row++ ) {
  36.             color = imageLookupMap.getPixel( col, row );
  37.             if ( color != 0xFFFFFF && row > 0 && row < rows - 1 ) {
  38.                 indexes.push( row );
  39.                 colors.push( color );
  40.                 outputColors.push( imageColorMap.getPixel( col, row ) );
  41.             }
  42.         }
  44.         // Fill gaps vertically
  45.         offset = 1;
  46.         while ( indexes.length > 0 ) {
  47.             n = indexes.length;
  48.             for ( i = 0; i < n; i++ ) {
  49.                 iRow = indexes&#91; i &#93;;
  50.                 iColor = colors&#91; i &#93;;
  51.                 oColor = outputColors&#91; i &#93;;
  52.                 overTop = iRow - offset < 0;
  53.                 overBottom = iRow + offset > rows - 1;
  54.                 matchedTop = false;
  55.                 matchedBottom = false;
  56.                 if ( !overTop && imageLookupMap.getPixel( col, iRow - offset ) == 0xFFFFFF ) {
  57.                     imageLookupMap.setPixel( col, iRow - offset, iColor );
  58.                     imageColorMap.setPixel( col, iRow - offset, oColor );
  59.                     matchedTop = true;
  60.                 }
  61.                 if ( !overBottom && imageLookupMap.getPixel( col, iRow + offset ) == 0xFFFFFF ) {
  62.                     imageLookupMap.setPixel( col, iRow + offset, iColor );
  63.                     imageColorMap.setPixel( col, iRow + offset, oColor );
  64.                     matchedBottom = true;
  65.                 }
  66.                 if ( ( overTop && overBottom ) || ( !matchedTop && !matchedBottom ) ) {
  67.                     indexes.splice( i, 1 );
  68.                     colors.splice( i, 1 );
  69.                     outputColors.splice( i, 1 );
  70.                     i--;
  71.                     n--;
  72.                 }
  73.             }
  74.             offset++;
  75.         }
  76.     }
  78.     // Fill gaps horizontally
  79.     for ( row = 0; row < rows; row++ ) {
  81.         indexes = new Vector.<int>( );
  82.         colors = new Vector.<int>( );
  83.         outputColors  = new Vector.<int>( );
  85.         for ( col = 0; col < cols; col++ ) {
  86.             color = imageLookupMap.getPixel( col, row );
  87.             if ( color != 0xFFFFFF && col > 0 && col < cols - 1 ) {
  88.                 indexes.push( col );
  89.                 colors.push( color );
  90.                 outputColors.push( imageColorMap.getPixel( col, row ) );
  91.             }
  92.         }
  94.         // Fill gaps vertically
  95.         offset = 1;
  96.         while ( indexes.length > 0 ) {
  97.             n = indexes.length;
  98.             for ( i = 0; i < n; i++ ) {
  99.                 iCol = indexes&#91; i &#93;;
  100.                 iColor = colors&#91; i &#93;;
  101.                 oColor = outputColors&#91; i &#93;;
  102.                 overLeft = iCol - offset < 0;
  103.                 overRight = iCol + offset > cols - 1;
  104.                 matchedLeft = false;
  105.                 matchedRight = false;
  106.                 if ( !overLeft && imageLookupMap.getPixel( iCol - offset, row ) == 0xFFFFFF ) {
  107.                     imageLookupMap.setPixel( iCol - offset, row, iColor );
  108.                     imageColorMap.setPixel( iCol - offset, row, oColor );
  109.                     matchedLeft = true;
  110.                 }
  111.                 if ( !overRight && imageLookupMap.getPixel( iCol + offset, row ) == 0xFFFFFF ) {
  112.                     imageLookupMap.setPixel( iCol + offset, row, iColor );
  113.                     imageColorMap.setPixel( iCol + offset, row, oColor );
  114.                     matchedRight = true;
  115.                 }
  116.                 if ( ( overLeft && overRight ) || ( !matchedLeft && !matchedRight ) ) {
  117.                     indexes.splice( i, 1 );
  118.                     colors.splice( i, 1 );
  119.                     outputColors.splice( i, 1 );
  120.                     i--;
  121.                     n--;
  122.                 }
  123.             }
  124.             offset++;
  125.         }
  126.     }
  127. }

Now we have a 360x100px BitmapData (imageLookupMap) that looks kinda weird but doing a getPixel on it returns a color value that is then used as an index to read out an image from a Vector. Boom. Super quick and scalable!

Putting it all together

After this it’s quite simple. We loop through each pixel of the video, query the lookup table for an index and then copy the pixels from that image to an output BitmapData. For this project we also connected the mosaic to the spectrum of the music in the video. After this is completed the original video that was stretched down is stretched up again and drawn on top with BlendMode.OVERLAY at a low alpha to cheat a bit and give a better visual effect. After some optimization of the analysis functions it runs at around 40-50fps with 6000 images. Everybody’s happy :)

Result: (cached version)

Hope this sparks somebody’s interest to do something similar :)

SoundFX, out-of-the-box audio filters with actionscript 3

We had a project where we would have needed to apply something like a lowpass filter in real time on an audio track. Doing some research for this quickly triggered even further interest in audio programming. I also realized it’s not as scary as it first seems and a whole lot of fun. We deployed on Flash player 9 so we ended up going with another approach. Still, this is what came out of that.

While all the audio stuff isn’t as hard as it looks when reading the docs it can still be intimidating to a lot of developers. Hopefully this post will help out those guys. The key focus here was to keep the syntax as similar to the one we’re familiar with from display objects, the SoundFX class does all the heavy lifting. Take a look at the following syntax:

  1. var sound : SoundFX = new SoundFX( new URLRequest( "music.mp3" ) );
  2. sound.filters = [ new CutoffFilter( 12000 ) ];
  3. );

When you don’t have to worry so much about the nitty gritty stuff of making it work you can focus on the fun creative part. You can do basically anything you can do with display object filters, animate the properties etc. It’s a lot of fun ;)

A simple demo of how this works (flash player 10 required):

Go crazy with the filters :)
A couple small shortcuts will help you too:

  • Double click: default value
  • Shift + double click: maximum value
  • Command/ctrl + double click: minimum value
  • Shift + command/ctrl + double click: middle value
  • Click on visualizer to pause/resume playback (pretty cool if you've added some echo)
  • Double click visualizer to randomize all knobs

An added bonus here is added control over audio streaming. As with NetStreams you can specify how many seconds should be loaded before playback starts.

Source (includes SoundFX and the demo)

The filters are currently ported from C source at (awesome resource!). Once i look a bit more into the math & magic behind the effects i'll try to post new effects. Of course i'm more than happy to include any other people's effects too, creating new effects is pretty simple.

Pixel Bender levels example

Pixel Bender is huge and is going to be even bigger once Flash player 10 officially is out (and spreads a bit so that we can start using it in commercial projects). I just love it when Adobe constantly lower the restrictions on creativity :)

A lot of the examples we see online for Pixel Bender (previously codenamed Hydra) are crazy visual effects. While they’re amazing for certain visual effects (mostly due to the processing speed), finding real life use is harder. I’ve had the need for a similar-to-photoshop levels filter multiple times, if nothing else for preprocessing a bitmap for further analysis. Turns out creating something like this with Pixel Bender is really simple and even better; it’s blazing fast.

If you’ve read my previous articles you know that I’ve already written a prototype for the levels filter (geesh, it’s almost a year ago!). Well, back then Pixel Bender was called Hydra and the code written isn’t compatible with today’s version anymore. I addition to that we weren’t able to export stuff, it just ran in the Hydra toolkit. Today I updated the code and exported it as a .pbj that can be used in Flash.

I’ve made a small example with a couple example images with the contrast reduced. You’ll need Flash player 10 to play with it. If all you see is white download the plugin from Adobe labs.

A couple pointers on the example: Clicking a histogram will automatically balance it. Double clicking will reset it to 0-255. Clicking the image will load a new image. In photoshop you can choose to either modify the luminosity or the individual channels. Here i enabled you to modify both at the same time, but this means that if you modify all 4, the automatic mapping won't be correct anymore (the histogram in the bottom left corner will show the result of this). I could make it understand this, but since it's just a proof of concept i think this is fine. Also gamma isn't supported at the moment.

The source is of course available:

Do you have other real life uses for Pixel Bender?

Nike lab: Technical case study

Nike sports marketing came to AKQA San Francisco with a request: Build a site to promote the innovative new products they are cooking in the Nike labs. These products are kind of like what concept cars are to the automotive industry and Nike wanted to have a way to tell it’s customers more about the technology behind the scenes. Also with the Beijing Olympics coming up some athletes who are using Nike’s new products would also be featured on the site.

Both because my part wasn’t so much in the creative/concept part of the project and also because i think most of my readers here are interested in the technical part anyway, this post will focus more on what the gears and cogs under the hood are doing.

View the site:

Nike lab homepage

Requirements into features

Nike had it’s technical requirements (the biggest ones being deep linking for flexible marketing and also support for multiple languages) but internally our goals were much higher. Fortunately we had pretty good time to build the site itself + an amazing team so we were able to put our thoughts into actions.

To support all the features we built a new as3 framework as a base and then built the site on top of it. Many (almost all) of these features are in the framework itself and developers at AKQA can easily in the future take advantage of our work in other projects as well, as these features are built in when using the new framework.

Here’s a list of some of the features right now:

* Automatic support for deeplinking to any page
* Back button functionality
* Internal sitemap
* Multiple languages/locales, each one with support for localized content (Nike Lab has 23 locales)
* Language switching on the fly without refreshing the page
* Automated support for non western characters
* Everything is driven by xml with a special workflow (more on that later)
* Special support for data models (more on that later)
* Keyboard and mouse wheel support
* several more smaller features..

Basically all the technical features are in the framework and all the features for the site are in the numerous swf components for the site. The config file config.xml defines the mapping between these.

Deeplinking and the concept of ‟pages”

People complain about flash breaking the back button. Well, that’s true, but also an animated gif doesn’t support going back to the previous frame with the back button. You may say that’s a stupid comparison but at the same time a flash site isn’t actually much more than a fancy image to the browser. If there was some standardized way for the browser to know what a ‟page” is inside a flash site it could theoretically support this automatically (Adobe?..). Still, at the time of writing this is not possible so we’ll have to build in this support ourselves.

We wanted to be able to define what a page is very easily, so that when you go to that page the framework could automatically navigate through the browser’s history. We added support for this through something we call sections. When you navigate from a section to another section a navigation event is automatically created, letting the user navigate back using the back button. Also the address bar and title are obviously updated. Of course the developer can override the browser history if it’s not suitable in some case.

Firefox address bar with a Nike Lab deeplink

Creating a site that supports the back button isn’t hard. Frankly I’m guessing that most of the readers of this have done it or at least know what goes into it. Still, you guys are a small percentage of all the developers. A part of our goal was also to spread ‟the right way”, making it so easy to do that there’s really no excuse. Unfortunately the code is proprietary so we can’t share any of it, but at least AKQA sites in the future hopefully can show the way, inspiring other people to do the same. The key is that even any junior developer can add support for this with studying some documentation and some examples for a day or so.

Since the site has an internal sitemap to keep track of the deeplinking targets the site will know if a deeplink is invalid and it will automatically fall back to the closest match (for instance: /athlete/cobe-bryant/ will fall back to /athlete/ since Kobe Bryant’s name is misspelled. The /athlete/ page will show a list of all athletes so that the user can proceed). Also because the site is aware of it’s own structure it could easily be used to generate search engine compatible sitemaps + alternate content for easy SEO..

23 custom locales, 1 custom workflow

A requirement from Nike was to have support for an at the moment undefined number of languages. They knew it was going to be many languages but didn’t know exactly how many. Because of this we had to come up with an extremely smooth and flexible workflow. One of the biggest things was the huge amount of copy localized into all these languages with several revisions. Updating stuff manually would not only be a huge waste of time but also significantly increase the risk of human errors, not to mention the added effort on QA.

What we did instead was send excel decks to the translation company. They filled in the empty gaps with the localized copy and sent the documents back to us. We then ran proprietary software to generate xml from the excel documents. After this we used an air app specifically built for this purpose by Ronnie Liew to reformat the xml into standardized xliff format. Generating ~220,000 lines of xml took about 1 minute so we could almost instantly see the updated copy in the dev build. This sped up the process a significant amount, letting us focus on the creativity instead. Awesome.

Language switcher? This is 2008, let’s do it live

Nike’s requirement was to have support for multiple languages. We wanted to go beyond that. What if you send a deeplink to a certain page to a chinese friend whose English is a bit rusty? Now he can just go to the language switcher and swap languages to Chinese. The site automatically knows what data is currently active, reloads that data from the new locale, updates the copy models and updates the site. The process takes 10 seconds or so, depending on the web connection. No need to refresh the page. Works with any combination of course, including the non-western characters. While a lot is going on under the hood, all of this is transparent to the user.

Nike Lab language switcher

Intelligent loading

This site has a lot of data, there’s no way to escape loading. We can compress assets, combine files etc but in the end there’s only so much we can do. To optimize the experience the site automatically knows what assets and data sources are required to be loaded before navigating to a certain page, meaning they can be loaded in a batch with a single preloader. If the user changes his/her mind and navigates somewhere else instead the site sets a lower priority to the files in the batch so that the files that are required now are loaded first and the other files are loaded in the background. This way the first page is instantly available if the user were to click the back button. I think there’s a lot more that still can be done with this approach but i’ll leave that for another post..

The list of files required is automatically compiled from the site’s structure. Each section can define assets (images, swf’s, fonts etc), data sources (xml files, web services etc) that are required to view the page, in addition to loading the page itself (a swf) with the possibility of having a custom loader.

A new approach to handling shared font is also built into the framework, meaning the font outlines only need to be loaded once and only when required. Automatically of course.

Put that data in the models

While the framework’s main focus is to add complex functionality with ease to the end developer, the framework also endorses use of good structure and design patterns. Loaded data is automatically linked to models that can easily be accessed. It’s simply easier to store data in consistent models than in some custom mcgyver-duct-tape-solution. These models can also easily add support for localized data (just adding $region to the path of the file is enough). Custom models are of course supported as each site’s needs differ.

The kitchen sink

Keyboard support isn’t anything new. Same goes for the mouse wheel. To be honest; I don’t think it’s a feature, i think it’s something missing if it’s not there. Super easy support for non conflicting keyboard shortcuts was built into the framework and Nikelab takes advantage of that in many places.

We couldn’t have done it alone

A lot of people worked on this project. I would mention everybody but .. to be honest I don’t even know. The people involved in the creative development part for Nike Lab (in addition to myself) were Ronnie Liew (technical manager), Tim Robles (developer), Thomas Ko (developer) and Gopi Shubhakar (quality assurance). Thanks also goes to Sallie Lippe for her project management. Other AKQA developers & tech management were also included in the concepting of the framework.

A thing to keep in mind is that this is of course the first site built on the new framework, I’m sure it’ll change and improve a lot in the coming year. This is also just a short description of what’s actually inside. Some details i can’t share, others would just make this post go on for days and days. I’m of course still open to your comments, feel free to take advantage of the box below ;)

FDT 3.0 Enterprise

The Rolls-Royce of the FDT 3.0 family, Enterprise, was released a couple days ago. This probably isn’t news to you anymore but I thought I’d mention it anyway.

I’ve got to say I’m very happy with where the Powerflasher team has taken this magnificent tool. Today I find it hard to work without FDT mostly because it makes my work so much faster and I can concentrate on what’s important instead of fixing my human errors. Just the fact that i can work for 30min and then compile without any errors (typos etc) is so nice and definitely keeps the creative process going much better than before. There’s a reason the tagline is “pure coding comfort” ;)

The newly released Enterprise version brings more advanced refactoring tools + a similar-to-Flex-builder debugger, both of which are very welcome additions.

FDT 3.0 Enterprise sets you back  599€ for the full version (roughly $950) so make sure you try the product in the 30 day trial to see if it’s worth that much to you.

Check out Carlo Blatz’ present the new features of FDT 3.0 Enterprise.

JPGSizeExtractor multi image example

I made a quick example to demonstrate the power of the JPGSizeExtractor class i wrote about a year ago. This is a demo that came up from a brief mail exchange with Richard Bacon who was looking at the class.

The example loads 10 images (one at a time), parses their SOF0 headers to get the dimensions, stops the load and draws grey boxes as backgrounds, setting the layout. This way building the layout is very quick and you don’t have to wait for the whole images to load. It’s kind of the same idea as specifying the width and height for images in html to maintain the layout even before the image has loaded.
When all sizes have been parsed the images themselves are loaded. For the demo the images are scaled down to 25% to make them fit better in the small window here. The total filesize for all 10 images is 4169kb. All images are from

Please keep in mind that this example is of the type "quick and dirty", and is only meant as a proof of concept. The code for the example was written just to make it work, not to make it pretty or flexible.

The source is available in my fresh public svn (which for some weird reason is in Chinese in Camino?! :) ): > jpgExtractorMultipleImages. The files are also available in a zip.

PureMVC 2.0.3

An architectural framework I’ve been using a lot recently has been updated to a new version.

PureMVC framework

The version (well, not the most recent one but the jump from 1 to 2) fixes a lot of small issues that existed in 1.x, most of which were inconsistencies that caused confusion. I usually downloaded the framework before a new project, fixed the stuff i wanted to fix myself and then started working. It of course always added a bit of overhead in the beginning of a project so this update is very welcome! I haven’t had a chance to verify that all I wanted to change has been fixed but if Cliff Hall has done what he talked about before, I’m happy :)

I’ve used PureMVC for most of my recent Actionscript 3 projects. It’s primarily meant for flex/air apps so building RIA’s with it is great. Flash is not as obvious since PureMVC doesn’t do any of the stuff that you might want from a flash framework (handle loading, stage manager etc) as it merely defines the architecture for the app. The strongest side i think is the fact that it encourages you to do stuff the right way, instead of quick & dirty. If you haven’t done so yet i definitely encourage you to take a look at the framework. The docs may be a bit confusing (i know they were to me in the beginning) but you should quickly get the hang of it.

PureMVC has gotten a lot of amazing buzz already. If you haven’t caught up with the nitty gritty details yet, Cliff also gives a very good description of what PureMVC is on the flex show, episode 33. Luke Bayes and Ali Mills also did a great presentation back in -07 where PureMVC came out as the “winner”; see it here.

Of course for more info there’s always

Adobe, Make some noise

I have to support this.


Thanks to all the people who have made the impossible happen with all the amazing audio stuff available but now I think it’s time for Adobe to step in. The issue with SOUND_COMPLETE is of course big (especially with backwards compatibility) but frankly Sound.loadBytes( ) is all I want. The latter would also reduce the need for SOUND_COMPLETE, which is usually used in hacks/workarounds.


Update: Adobe has requested to remove the word ‘Adobe’ from the domain because of potential legal issues. The new domain is Read more here.

The best use of 3d so far

I’ve got to say that I got this warm fuzzy feeling when I checked my RSS feeds today and saw the Red Bull Flightlab site mentioned on a couple sites. After checking out the piece myself I’ve got to say that it is hands down the best use of 3d I’ve seen online so far.

Red Bull Flugtag

The biggest thing here is that it doesn’t feel like 3d is used just because it’s 3d, but for a reason. The rest of the site holds up to the high standard it sets too. As frosting on the cake the site supports deeplinking too and has a fully functional browser history. A big hand to Lessrain.

Read their blogpost about the creation too. Good stuff :)

FDT 3.0 out — in three flavors

My tool of choice, FDT 3.0, has been officially released. No more beta! I was in the beta test program and it has been very exciting to see the progress of this wonderful tool. As I said before, if you haven’t tried it out; please do so. There’s a free 30 day trial too.

FDT Logo

FDT 3.0 packs a whole bunch of features which put the older 1.5 to shame (I won’t even try to compare it to flash, or even flex builder). Features include advanced code completion, an automatic formatter, quick fixes & assists, templates, organizing imports & automatic importign, launchers, semantic highlighting and much, much more. The biggest one though is definitely AS3 support which works like a charm. In short, it has changed the way I work. If Actionscript is the language that brings the bread to your table, go give FDT a spin.

I was kind of surprised to see the split into different versions. While I understand this step as a good “excuse” to make some extra cash (which is well deserved), i find it kind of annoyed. I own a license for FDT 1.5, which I bought when I read that the upgrade will be 99€. Now, however, I’m reading this is just for the basic version which is kind of disappointing. 599€ for the enterprise version is still quite a bit more (i definitely want the debugger and advanced refactoring tools).