Recently in a little experiment, i made a rather cool demo which makes use of CSS Transforms, combined with CSS Transitions.
Note: Examples only work in Safari 4+, or other recent webkit-based browsers.
“Cool?” you say. Well admittedly i could have gone for something a bit more elaborate, however as it stands it pretty much serves its purpose – that is to demonstrate that using the magic of CSS Transitions you can create fast, useful web effects which run at acceptable framerates on an iPhone, and even on the desktop (since the tweening of properties is done by the browser).
However to get this admittedly simple demo working, i had to battle through a few odd issues with how these transitions operate.
The problems
To start off, resetting transitions is a bit tricky. Since properties are not processed immediately, you need to wait for the browser to detect you have reset transition values before you transition to any new values.
Thankfully a nice event called webkitTransitionEnd is provided which is fired as soon as a transition is complete, so you could conceivably use it to handle resetting the transition.
The only problem? webkitTransitionEnd seems to only fire when it feels like it.
The above example demonstrates the peculiarity of webkitTransitionEnd. The green/pink circle is meant to change colour every time the event is fired. Since there is an interval running every 100ms which changes the rotation of the circles, what typically happens 99.9% of the time is the transition never really ends, thus no event.
In general, the transition event seems to behave as follows:
Setting…
Result
Initial transition (element just created)
FAIL
Transition continuously (during transition)
MOSTLY FAIL
Transition after a sufficient undefined delay
PASS
So safe to say, unless you’ve got a transition you aren’t going to mess about with then don’t rely on webkitTransitionEnd.
Onto quirky platforms…
Finally, with regard to the iPhone platform there are even more quirks. Compared to desktop Safari, the tweening acts quite differently.
One notable quirk is if you make a new element with a transition on Desktop safari, it performs that transition. If however you do the same thing on Mobile Safari, the transition starts at the end. Whether or not this is some bizarre timing issue, i have no idea.
So safe to say, while CSS Transitions are a powerful tool to use, beware of the quirks.
Which led me to this rather interesting mailing list post by Douglas Crockford:
I apologize for my ultrablunt comment. Let me be clear about what I
meant. It was decided at the Oslo meeting that the project formerly
known as ES4 is no more. Instead, there will be a new project,
Harmony, which will be the work of a unified working group. We have
not yet agreed on a set of goals for Harmony.
I recommend that we close the ES4 list and open a harmony list to
support this new effort.
Looks like nobody can agree on any set goals for JavaScript 2 (i.e. ES4). Which leads me to think that as with a lot of web standards, JavaScript 2 is just a pipe dream.
Fortunately though, the real world has a solution which already works. Its called haXe, and it implements a lot of what JavaScript 2 should be.
So instead of waiting about for some standards crackpots trying to cobble together a standard, you can write some real code.
The HTML5 Canvas. Great, isn’t it? You can draw pretty much anything you want in a pre-defined area. In more recent browsers, you can even get & set pixel data too, so you pretty much have full control over how things look.
The problem
Unfortunately, the Canvas suffers from a pretty brain-dead design flaw. That is while you can get and set pixels, you cannot control when the pixel data you grab with getPixelData() will be freed from memory. This is exacerbated by the fact that the whole interface runs on top of JavaScript.
“Now wait a minute“, you might think “doesn’t JavaScript have garbage collection for this sort of stuff?”. Well, yes. The trouble is, JavaScript has no standardized garbage collection system, so depending on which browser you happen to be using it’s pot luck whether or not your pixel data will get freed on time.
Now lets use a real example here. A while back, you might recall i was writing a SCUMM interpreter in haXe that just so happened to compile to JavaScript as well. For the SCUMM runtime, i am required to display room graphics overlaid with various objects. The graphics are 8bit and use a palette, and that palette can be changed at runtime.
For performance reasons, i decode the graphics and store them in Canvas elements using only the red channel. In fact, throughout the graphics processing pipeline, the red channel is the only part of the pixel data i use. I also make heavy use of the native blitting functions (e.g. fillRect).
It’s not until i come to display the graphics that i re-map the pixels from the red channel into the final colours using the current palette. This requires me to getImageData() the current pixels in the canvas, iterate through and set the data[], and then putImageData() back to the Canvas for the final result.
The trouble is since i am re-mapping the pixels every frame, memory usage on certain browsers (Opera, Firefox) skyrockets up to a certain threshold – anything up to 2gb depending on what is happening.
For the test case running on OS X, Opera> tops out at ~600mb. Webkit and Firefox both top out at around 1.25gb (honestly though, i just stopped looking as it was getting stupid). It’s not until i either suspend re-draw and wait several seconds, or simply close the browser window that memory usage returns to normal.
Oddly enough when re-mapping the pixels in my SCUMM interpreter (not in the test case), Webkit’s memory usage stays constant. This flies in the face of what one would expect to happen based on the test case. As for why, it could be anything. The smaller canvas size, assignment of variables – who knows.
Workarounds?
Realistic workarounds include:
Perform all graphics operations manually on a single set of pixel data (too slow!)
Use drawImage() as opposed to getImageData() & putImageData()
Limit the amount of screen updates
When working with palletised image data that needs re-mapping, store it as RGB, and re-calculate it only when the palette changes
Don’t use getImageData() at all, especially considering it doesn’t seem to work in Safari at the moment.
Either that, or simply implement everything which needs pixel-level graphics manipulation in Flash or a Java Applet, foregoing the pure Javascript ethic.
For those of you have read my blog previously, you may have noticed i bumped in a fewlinuxrelatedposts here and there. This was mainly due to the fact that i was experimenting with using linux as a desktop operating system (something which i have tried in the past), as i wasn’t too confident of where Mac OS X was going. This ultimately included installing it via BootCamp on my Macbook.
Unfortunately i have now reached the end of my teather with regards to using Linux as a Desktop operating system. Quite simply i kept bumping into too many issues which required manual workarounds, if there was even a solution at all.
<!-more->
I started off by trying one of the release candidates for the latest release of Ubuntu, version 7.10. This initially impressed me as when i booted off the installation CD, almost everything appeared to work out-of-the-box. However upon installing it on my Macbook, the novelty wore off as i realised that crucial features of the Macbook – the camera, the IR, even the trackpad either didn’t work properly, or didn’t work at all.
For example:
The default trackpad configuration was abysmal, and i couldn’t find any configuration tool which gave me the same amount of customizability as the one in Mac OS X in order to fix it.
I never got the iSight working – though then again this wasn’t much of a problem as Skype for Linux doesn’t even support video cameras.
Whilst the sound worked, configuring it was a pain in the ass as there were too many confusing options to choose from.
I tried to get the DVI out to work. I ended up breaking the X server and spent ages trying to fix it. Safe to say i never got it to work.
OpenGL support on the Macbook was sub-par.
Intergration between applications varied from being good to abysmal.
( It should be stressed that all of these issues persisted through to the stable release of Ubuntu 7.10 )
In fact, you can see a nice list of all the problems you have to fix out of the box here.
A week or two ago, Ubuntu 7.10 became officially stable, so i decided to try out one of its variants to see if it fared any better on my Macbook. I chose Kubuntu as i had previous experience with using KDE from using SuSE Linux and figured it might turn out to be a better desktop experience.
On the contrary, Kubuntu was anything but a better desktop experience when compared to Ubuntu. A lot of the killer features present in Ubuntu – Compiz Fusion, simple administration tools, even mappings for the brightness controls were not present in Kubuntu. It was also more difficult to configure as there were simply too many configuration options to choose from, as is illustrated by the comparison of the “Keyboard Shortcuts” dialog in Kubuntu (which uses KDE) and Ubuntu (which uses Gnome) bellow:
I even tried the beta KDE4 packages, in the hope that maybe KDE4 had improved on KDE3. I was sorely dissapointed, as instead of this i got this.
Safe to say i have come to the conclusion that currently neither Ubuntu or Kubuntu are quite up to scratch when compared to the standards set by Mac OS X. In fact if suddenly all copies of Mac OS X were obliterated, i’d probably take a risk and use Haiku.
As for the future, who knows? But as for now, i think i’ll stick to what i like best – Mac OS X.
After reading Mechanic #031 on the Three Hundred game ideas blog, i got thinking. Specifically, i asked myself “How easy would it be to write a web-based tool for encoding and decoding data to 2d images as pixels?”.
Luckily, this mechanism has been implemented before. The simplest example would be a barcode. However, i wanted something a bit more advanced in order to pack as much data as possible into the image, as i would imagine quite a bit of information would have to be present in each “game image”. After much scouring the web, i found two promising solutions: QRCode and Semacode. Sadly though, Semacode appeared to have pretty dodgy licensing, so i decided to steer clear of it and see what i could make of QRcode.
QRCode was interesting, as in it was very easy to find an encoder, such as libqrencode. Unfortunately, it was very difficult finding a decoder that didn’t just run on a mobile phone (which seems to be a popular way of decoding QRCode’s). The only standalone library that could decode was written in java, oddly enough also called qrcode.
To be honest, i’m a bit put off of proceeding any further trying to get this question answered, mainly because everything seems to be written in Java, – which is fair enough, but considering my skills in programming Java are minimal, i might end up with a rather dodgy botched together solution.
Regardless, i think the concept of deciphering data from 2d images is neat. I’ll just have to find the elusive c-based decoder for QCode, or perhaps even better, find a better supported alternative system.