Video tag user to Apple: Get your act together.

Wednesday, June 24, 2009

I'm currently trying to get a video of the last demo online and all things considered, it has been a good experience... except for Apple's Safari browser. It's nice that they support the video tag, but their implementation is pretty much useless:

  • Don't say that you support a feature when you really don't.

    Apple's implementation lacks support for the controls attribute, which tells the browser to display a native interface for video playback. I don't really have a problem with this, but why the heck does Safari tell me that it does support it?

    The controls attribute is treated as if it was supported with the controls property mirroring the value of the controls attribute. So myVideoElement.controls is true or false instead of the undefined I'd expect for an unknown attribute.

    In the end, that means that I have to do browser sniffing to load my own interface for Safari and I thought that we had all agreed by now that this is a bad thing

  • Don't say that you support h.264 when you really only support is your own special flavour.

    There's a lot discussion going on over which codec to use for video, but something that's often overlooked is that Apple's h.264 decoder is a proprietary mess that will only accept Quicktime created MP4s. Since video in Safari uses the Quicktime backend that means that you won't be able to actually use h.264 unless you fork some cash over to Apple for Quicktime Pro, even when there are many better and cheaper alternatives. This is exactly the lock-in that shouldn't happen with video.

    The only real alternative for now is using the MPEG-4 Advanced Simple Profile (better known as DivX or XviD) and suddenly all the better quality you were promised in exchange for having to use a proprietary format is gone.

Labels: , , , ,

Blogger Formating nightmare

As you may have noted, the formatting on my older posts has been lost, because Blogger wouldn't let me edit my HTML without adding additional linebreaks unless I disabled them in both HTML and Compose view, which also effected existing posts (which I didn't notice until it was too late). I'll try to rebuild the posts ASAP.

Labels:

Fake Voxels with filters

Click the image above to get to the demo

Video

Voxels are a way to display 3D data that dates back to the days before 3D accelerators became popular. Voxels (VOLume piXELS) don't store models as triangles or polygons, but instead function much like a traditional bitmap, only these bitmaps have 3 dimensions, much like a video (where the third dimension is time). Today you find them mostly in medical scanners.

This demo however doesn't use real voxel data (we get to the rendering in a second, this is just about the data itself), but a variant where there is only a two dimensional bitmap and a third channel that contains the Z position of the pixel. The benefit is that there's a lot less data, but there can only be one color for each pixel at all depths, which makes it well suited for terrains, but not so much for anything else. This is the way most games used voxels and it even has found its way into modern games as "parallax mapping" for textures, which is really just voxel rendering implemented as a shader.

The rendering itself isn't real voxel rendering either. That would require a 3D buffer that's currently not available to filters. Instead, a series of perspective renderings is just put on top of each other, so these voxels don't have any side surfaces, just the top. At steep angles this would pose a problem, but since we're looking at it from (roughly) a 45 degree angle, it works well enough.

Code-wise this is really just a simple evolution of the MarioKart demo and if you want to know how the perspective rendering is done you should look there.

The only real difference is that this uses 5 different perspective renderings, stacked upon each other. Then there's a bit of fairly simple brightness/contrast adjustments: The bottom layers are made a little darker and the alpha channel gets higher contrast and a brightness adjustments depending on its height. The top ones are made to display only where the alpha channel is entirely opaque/very bright, while the bottom ones pretty much ignore the alpha channel.

Frankly, I didn't expect this to work, primarily because the filter is very, very long. It needs to process around 30 operations to generate each frame (4 operations for each of the 5 layers + 5 for the texture + 3 for the texture transformation) , and that's with a 768x512 surface. It's not very difficult to understand, but there's simply a lot of processing needed and the speed at which Firefox renders this is nothing short of amazing.

Labels: , ,

Font work: schmucker-sans-nothrills-rev0

Saturday, June 20, 2009

Click to get to the SVG.

When font-face made it's appearance in all major browsers I was really, really excited. Until I learned that I wouldn't be able to use any commercial fonts and even most free fonts. So I've started working on my own. It's terribly basic and isn't even complete yet, but I thought that maybe some people could even have use for an incomplete font. It is currently available as an SVG containing the letters A-Z, a-z and the numbers 0-9.

schmucker-sans-nothrills-rev0 is built from first principles: Lay out a grid for your letters, create one arc for the round parts and try to assemble all letters from these parts. It's not exciting, but it should be easily readable so you can also use it for longer text paragraphs, not just headlines.

The most interesting thing is probably the license, which allows for pretty much anything. I'm putting this into the public domain.

So, create fonts or use it in your logos or basically do whatever you like. Would be nice if you sent me a mail though.

Labels: ,

Dynamically textured animations in the browser

Friday, June 19, 2009

It's probably best to let you play with this little demo first. The animation is stored only once and the texture is applied dynamically. Keep in mind that this is only a techdemo. Somebody more familiar with animation could use this technique for something truely great (think along the lines of you uploading an image of yourself and suddenly you're appearing in a movie, thanks to the combined power of the video tag and this).

The technology is not the limiting factor here, just my artistic skills.

The concept

.. .is actually pretty simple. An animation is rendered with a placeholder, instead of a real texture. This placeholder contains the position in the texture (encoded as color). Specifically, the model was rendered with this texture, using a planar projection for UV coordinates.

When the animation is shown, the pixels get replaced again with pixels from some texture that the user or the developer specifies.

All this can be done with SVG filters, specifically feDisplacementMap. If you want to know in detail how it's done, have a look here. The only real difference here is that instead of a static map, a series of images is composed into an animation. You may also want to look at the source of the demo. Everything needed to recreate the effect shown here is marked with the keyword IMPORTANT.

Can only Firefox 3.5 do this? And why aren't you using the video tag?

Most modern browsers can do this, but there are a few differences that you should be aware of: To make this work, your video has to be stored in a lossless format.

For Gecko based browsers that's usually APNG in an IMG or maybe at a later time Theora (the current encoders don't allow for for lossless YUV compression, but that's likely a limitation of the current tools, not the format, as we've seen with JPEG or h.264) via VIDEO. For Webkit it's lossless h.264 and for legacy browsers it may be a greyscale GIF containing the color channels side by side, so they can be recombined by the filter.

Older browsers also need the filter applied inside an SVG document, so you'll have to load an SVG in an iframe to do the rendering.

To sum it up: This demo only works in Firefox 3.5 because I didn't want to spend more time optimizing it. I wanted to show you what can be done and Firefox 3.5 made it easiest for me. But you can make it work. For a few pointers, see this file, which implements a similar solution in pure SVG.

Labels: , ,

Smooth image filtering for MSIE6+ and Firefox 2+

Wednesday, June 3, 2009

Sometimes working on a production website reminds you of problems you thought that were long gone. In this case, I needed smooth image scaling for the majority of browsers and yes, that sadly still includes MSIE6 and Firefox2.

The solution for MSIE6 is pretty well known, so I'll keep this short: You need to apply the AlphaImageLoader with sizingMethod scale:

<img src="blank.gif"
   style="
      filter:
         progid:DXImageTransform.Microsoft.AlphaImageLoader(
            src='myImage.jpg',
            sizingMethod='scale'
      );
   "
/>

Firefox2 is actually more difficult here. There are no hidden properties or anything that will magically render your image smoothly. But there's another way to do it. Namely, the SVG renderer, which uses smooth image rendering by default. So you simply need to link in an SVG via the object tag instead of the image:

<?xml?>
<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
>
   <image xlink:href="myImage.jpg"
     width="100%" height="100%"
     preserveAspectRatio="none"
   />
</svg>

If you want to automate the whole thing, the easiest way is using data urls, because it means that you don't have to create separate documents. Instead you just let a script run over the page and replace the imgs with objects. The only real difference with data urls is that you have to urlencode the characters, which makes the final object tag something like this (without any linebreaks):

<object data="data:image/svg+xml,%3C?xml%20?%3E%3Csvg%20
xmlns=%22http://www.w3.org/2000/svg%22%20
xmlns:xlink=%22http://www.w3.org/1999/xlink%22%3E
%3Cimage%20xlink:href=%22test.jpg%22%20
width=%22100%25%22%20height=%22100%25%22
%20preserveAspectRatio=%22none%22%20/%3E
%3C/svg%3E" type="image/svg+xml" />

That's pretty much it. Now I'm off to investigate Safari and Opera.

Labels: , , ,

SVG makes the world go round

Tuesday, June 2, 2009

I just had to play with SVG filters a little more.

You'll find instructions on how to do this in the previous post, but this is maybe a better example for what you can do with it:

A spinning world

enough said.

Labels: , , ,

Perspective texture with 6 lines of SVG

Tuesday, May 26, 2009

SVG filters in HTML

In modern browsers there's lots of functionality that's rarely used, because it's either hard to understand and/or hard to use. One such thing is SVG, and especially filters. For use on the web they were too unreliable in the past and most importantly, they required you to use SVG (although you could link your original HTML back in through use of foreignObject). Well, no more.

With Firefox 3.5 we get stable filters support (at least nothing's missing that I wanted to use) and we can now use them in our HTML through CSS.

But there's still a problem with the documentation. Try to type a filter name into Google, like "feDisplacementMap" and you get not even 3000 results. And two thirds of those are either bug reports for engines implementing them or pages trying to sum up the spec. The spec itself is also often hard to understand and in desperate need of some clarification and more complex examples.

So I'm going to do my share about it and explain a bit about the before mentioned feDisplacementMap and how to use it to do cool stuff.

Let's look at the cool demo first

If you just came here because somebody who linked here mentioned Mario Kart, I think I should have the decency to give you a link to the demo straight away. Go here. But be aware that this is not actually a game, just a demo showing what you can do with feDisplacementMap. There's no colission detection, no enemies, no goals.

All the rendering is done through an SVG filter, except the controls and the initial 2D transformation, which is done with Canvas (however you can also do this with pure SVG as well like I did here, it's just a bit faster with Canvas).

If you want to know how it's done and how you can use the same technique to do other cool effects, read on.

What's fedisplacementMap and why should you care?

feDisplacementMap is an SVG filter for pixel mapping. Basically you provide a source image and a map which pixel goes where and that's it.  And if you have to warp pixels around there's nothing you can do in a browser that would be faster. It's also probably the most versatile filter you'll find in SVG.

What you can do with it

Basically everything where you have to transform different images the same way over and over again. That could be anything, like a lense effect, mirroring, or a perspective deformation.

How it works

The first little thing to look out for is that the displacement filter does not actually allow you to "push" pixels around. If it did that then you'd typically end up with a lot of empty spots because nothing was pushed there and the color that was initially there was pushed away.

Instead, it works the other way around: Each pixel contains information which pixel of the source image it should show. using the distance to the current pixel to specify it. In other words, each pixel of the map contains an instruction like "show the pixel from the source image that's 12 pixels to the left and 4 pixels up from the current one", not "move this pixel 12 pixels to the right and 4 pixels down". It's a subtle difference, but one you should be aware of.

Turning the raw offsets into a displacement map

This information is encoded into a color in order to save the displacement map as an image. The encoding is actually quite simple. The distance to the source pixels is split into an X distance and a Y distance. That distance is then spread across the color range (0-255) where 0 means a lot (we'll talk about how much in a second) to the left/up and 255 a lot to the right/down. Then each one is saved to a color channel, for example red for X and green for Y (you can later specify in the filter which channel you used for what).

The actual distance is lateron calculated in the filter by multiplying the color value with a multiplier you specify, so how long the distance to the source pixel actually is depends on what multiplier you use. Set it to 255 and you'll mostly get what you expect (0 meaning 127 to the left/up and 255 to the right/down).

Things to watch out for

There are mainly two things that can cause you a lot of headaches if you're not aware of them:

  1. SVG by default uses a strange colorspace that will lead to unexpected results. Why they did that when they wrote SVG I'll never understand, sufficient to say that you better set the colorspace to sRGB if you want to retain your sanity.
  2. The source image isn't automatically wrapped, so if your displacement map pulls in a pixel that is outside the source image, it will appear transparent.

The good stuff: absolute mapping

The thing that limits feDisplacementMap most is that it can only use relative offsets. There is no way to say that you want the pixel at 10,12 to appear at a certain point, just the one 3 pixels to the left and 2 pixels up... but with a little trickery you can still do it:

The trick is to tile the source image so that every pixel is in the reach of every target pixel. In other words: resize it to 256x256 and tile it across the size of your destination surface. Then all you have to do is substract the current position from each absolute position you have in your mapping and finally put it into 0-255 range (modulo 256).

Adding filters to your HTML

Applying a filter is really easy in Firefox 3.5. Just add a filter CSS rule to any element, like this:

filter:url(#myFilterId);

Specifying the actual filter is a bit more difficult, but still doable. You can either put it into a separate SVG and link it in with

filter:url(mySvgFilters.svg#myFilterId);

or, if you want to add it inline, you have to include the SVG namespace in your HTML declaration and add a SVG element to your body.You'll have to put "svg:" in front of the SVG elements to tell the browser that it's not some unknown HTML element, but a SVG element instead.

<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:svg="http://www.w3.org/2000/svg"
 xmlns:xlink="http://www.w3.org/1999/xlink">
  <body>
    <svg:svg height="0">
    </svg:svg>
  </body>
</html>

Chose whichever way you want, as long as you've got the filter inside a SVG element somewhere, you'll be fine.

Now, for the actual filter. This will add a filter with sane settings.

<svg:filter
 id="myFilterId"
 color-interpolation-filters="sRGB" 
 filterUnits="userSpaceOnUse"
 x="0" y="0" width="768" height="512">
</svg:filter>

That's an awful lot of strange settings I know, but you'll get the hang of it:

  • color-interpolation-filters="sRGB" makes sure that the filter will use normal RGB colors instead of some other strange format.
  • filterUnits="userSpaceOnUse" tells the filter to use pixels as default unit which usually is a lot easier to understand. You can still use percentages like "100%" but pixels will be the default unit.
  • x="0" y="0" width="768" height="512" specify the dimensions. Naturally, this should fit your element's dimensions. Make sure to not forget the x/y declaration, because otherwise the filter will default to a position of -10%,-10%.
  • id="myFilterId" I think this is pretty self-explanatory.

Writing a filter

A filter consists of one or more filter operations, which are basically mini-filters that do simple operations like bluring. A filter combines these operations into one big processing chain.

The basic format for a single operation is always like this:

<svg:feSomeOperation in="someInput" result="someOutput" x="0" y="0" width="256" height="256" />

If an operation takes an input, you can specify an "in" attribute (some operations also need a second input, in which case you also specify an "in2" attribute). If you don't specify it, the operation will simply use the output from the previous one. There are also some special inputs like SourceGraphic, which contains an image of the element to which the filter was applied.

If you want to reuse the output and not just use it directly afterwards by not specifying an "in" attribute, you have to provide a "result" attribute. Just give it any name and you'll be able to reuse the output by specifying it as another operation's "in" attribute.

And lastly you need to specify the rectangle to which the filter is applied.

That's pretty much it. So let's look at an actual filter, like the one I used in the Mario Kart demo.

The Perspective Texturing Demo filter

Note that the element that you apply the filter to should be 256 pixels bigger (on each axis) than the output. This is necessary so that the displacement at the very edge can reach "beyond" the souce image.

<svg:feOffset width="256" height="256" />

First we need to crop the image. We only want the top-left 256x256 image. feOffset filters are actually meant to move the image around, but since we didn't specify any offsets via the "dx"/"dy" attributes, it will just crop the image to the given dimensions.

<svg:feTile width="100%" height="100%"  result="source" />

Now we create an image the size of our element which is filled with the output from our previous cropping operation. The next operation will deal with the actual displacement map, so we'll have to save the output as "source".

<svg:feImage x="128" y="128" width="512" height="256"
 xlink:href="fdisplacement512.png" result ="displacement"/>

Then we load the actual displacement map. Since the displacement can go 128 pixels to the top/left and 128 pixels to the right/bottom, this should be 256 pixels smaller than our element and placed at 128,128. That way no displacement will reach outside of the source image.

<svg:feDisplacementMap   x="128" y="128" width="512" height="256"
 color-interpolation-filters="sRGB"  in="source"  in2="displacement"
 scale="255" xChannelSelector="R" yChannelSelector="G"  result ="out" />

This is the actual displacement. Nothing special here, except that we set the scale to 255 to get a mapping where a color difference of 1 actual means a one pixel shift.

<svg:feComposite in2="displacement"  operator="in" />

The composite filter is used to apply the alpha map of the displacement map to the final image.

<svg:feOffset x="0" y="0" width="512" height="256"  dx="-128" dy="-128" />

Since we placed our displacement map at 128,128 we have to move it back to 0,0

How to create the an absolute map with your favourite image editing application

Step one: Creating the neutral image.

The neutral image simply maps each pixel to the same one in the source image. It's want you always start with and it never changes.

You can simply use this image, but if you want to create it yourself (which is a good idea if your image editor supports more than 8bit per channel, since you can use dithering to create a bilinear-filtering like effect), here's how to do it.

Just fire up your favorite photo editor and create two grayscale images with the dimensions that you want the output to be: Fill both with a gradient from black to white. One vertically, one horizontally. Also create a solid black image with the same dimensions.

Then combine them into one color image with each grayscale image being one color. For example you could make the horizontal one red and the vertical one green. If you now check the colors and positions in the image they should match. The pixel at x:10%,y:20% should have the color red:10%,green:20%,blue:0%.

Step two: Deforming the image.

You can use any deformation filter you want. Obviously, for the demo I used the perspective deformation tool, but you can use anything that doesn't alter the color of the image, like lens, wave, barrel deformations.

Step three: Changing the absolute source values to relative values.

That one is a little more complicated. Since feDisplacementMap doesn't really allow you to map a source pixel directly to a target pixel we have to subtract the position of the pixel to convert the absolute position we have so far into a relative position. So basically, you have to load the image we created into something that can run a bit of code on each pixel and run something like the following code on each (you can just save this script and exchange the source image path for yours):

offsetInRgbaArray=(currentY*width+currentX)*4;
absoluteSourceX=mapImage[offsetInRgbaArray+0];
absoluteSourceY=mapImage[offsetInRgbaArray+1];
sourceAlpha=mapImage[offsetInRgbaArray+3];

if(sourceAlpha>254){
  mapImage[offsetInRgbaArray+0]=(absoluteSourceX-currentX+16384)%256;
  mapImage[offsetInRgbaArray+1]=(absoluteSourceY-currentY+16384)%256;
  mapImage[offsetInRgbaArray+2]=0; mapImage[offsetInRgbaArray+3]=255;
}

And that's it. Try every transformation you can think of, like a lens deformation to create a globe that you can travel.

Labels: , , ,

Making use of Video tag and Canvas

Thursday, March 19, 2009
There's a lot of great stuff in the (X)HTML5 spec, but the greates thing is how these additions work together. For example, the video element may not seem terribly exciting at first. YAVE - Yet Another Video Embeder, so to speak. But once you scroll a few pages down to the Canvas element and fully grasp what the following two sentences actually mean, you can't help but marvel at its magnificence: "To draw images onto the canvas, the drawImage method can be used. [...] The image argument must be an instance of an HTMLImageElement, HTMLCanvasElement, or HTMLVideoElement." What this means is that videos are for the first time in a browser fully scriptable. Just draw it to a canvas and you can read it, pixel by pixel. For example, you can have a song include volume and frequency information in the video track, then use Javascript to build great visualizations (this only works in recent Firefox 3.5 beta builds for now) from it. Or you could prepare a depth map so that it appears threedimensional when viewed through anaglyph glasses. Or feed it into a real 3D engine and view it from all sides. Sure, there's lots more to do until web applications will have the same power available as desktop ones, but with video and canvas working together we are making major progress towards web browsers not just showing media content, but actually being able to process it. Right now, the web is a great place to be :)

Labels: ,

Google Chrome? Good for some people, not good enough for me.

Tuesday, September 2, 2008
UPDATE: A few people have since pointed out that there are developer tools available in the "page" menu. Sorry, it wasn't obvious to me. So cross out the points below concerning the absence of such tools. Concerning Google Chrome,
Right now, Blogs all over the world are reporting about the great new browser Google has and I too decided to take a look. After all, it's Google we're talking about here, so it has to be good. And it is, kinda. Google is trying to create a browser for the "casual" crowd. People who spend less than an hour a day using the internet, people who don't have a lot of tabs open and who freak out when a program crashes. People who don't have friends who can help them set up their computer and are therefore stuck with Microsoft's slow and buggy Internet Explorer. And for that purpose, Chrome is actually quite good. Let's start with the installation. Run, say whether you want to import your Internet Explorer favorites (it didn't even give me an option to import my Firefox bookmarks). Done. It's really that simple and straightforward. Of course I'd like to have more options, but I'm not really the one Google is trying to win over, so that's OK. Then it starts. And my first thoughts are "Man, this is ugly". Where other browsers try to look like native applications, Google has chosen the opposite route. The buttons on the top look a bit like Vista's, but that's about it (besides, I'm not using Vista, so it would be the wrong OS anyway). Everything else is in a Google typical gray/blue theme that looks more like a webpage than an application. The fact that it integrates poorly with the OS alone is almost a dealbreaker for me, but once again, it might actually appeal to people who do little enough with their PC that they value glamour over consistency. However, it seems like usability was not really that interesting to the Google folks either: The grey/light blue color combination provides little contrast and my first few clicks where actually attempts to click on the nearly invisible scrollbar. Next step. The welcome page has opened and greats me with what to expect the next time I come here (a list of most used pages). I already know that, but decide to take a look at the help anyway, which turns out to be a little page with a few UI tips. Sadly, the navigation breaks and pressng "back" doesn't work as expected as it only changes the title of the page to "Untitled". I have to admit, I expected a bit more polish here and while it isn't really a dramatic bug, it's not a good thing to present the user with it on his first launch. The basic browsing functions work fine, after all WebKit has been used a few times before and by now is pretty good. The Javascript engine also is almost as fast as promised and generally does a good job. Nothing to complain about here. So I decide to take a look at the taskmanager to see how Google's idea to seperate the tabs into individual processes has worked out. Not to well for me as it turns out. Chrome is using 267MB of memory right now, while Firefox with the same pages open uses 186MB. Again, Chrome turned out to be very bad for my habbits... I can't even see any of my tab's titles anymore, because there's no tabbar scrolling. But would your typical "casual" surfer open 30+ tabs at once? Probably not. Again, a major issue for me turned out to be just fine for the target audience. And so it goes on and on. No addons, no error console, no developer tools, nothing that a casual user won't miss. And that's really all there is to it. If you want just a simple browser, then this is fine. The only question that remains for me: Why then not use Safari itelf, instead of Google's version? Oh and one last thing. Whoever wrote that comic didn't do Google a favour. Because to me, this "that's how we do it and that's the only right way to do it" talking sounds just terrible. Mockery doesn't really inspire sympathy and when a friend asks me "which browser should I install?" it might be this bit that keeps me from saying "Try Google Chrome".

Labels: ,

Accelerating per-pixel collisions in Canvas

Thursday, August 28, 2008
For the impatient ones: Main demo HTML: index.xhtml I think the code could be interesting for people working on highly interactive content for decent browsers (yes, that excludes InternetExplorer. There's no way to work around this short of offering Canvas as a plugin). The only way so far to use per-pixel collisions with Canvas is using getImageData, which has a terrible overhead and I thought I could accelerate the whole thing by using bitmap functions to pre-filter the data. Right now it is meant for colliding a map with a sprite, but with a bit of work it could also be used to colliding two sprites. Basically it works like this:
  1. Calculate size of the rotated and scaled sprite.
  2. Create a canvas of this size
  3. Load the map file and blit it to that canvas.
  4. Load the sprite and blit it to the same canvas, keeping only parts where the previous content and the sprite overlap.
  5. Scale the canvas down to 1/16 of it's original size) (technically 1/256 should also work, but it seems that the scaling starts skipping pixels then).
  6. Convert the downscaled image to a pixel array.
  7. Check the alpha channel of the pixel array. If any pixel has an alpha value >0, we have a colission.
Using this optimization my PC (1.8Ghz) is able to calculate around 3000 16x16 sprite collisions per second, which should be plenty for any normal game. I've written a little demo, where 100 Tentacles invade my hometown (Mannheim). With 100 collisions, there's even time for a fancy cloud shadow effect :) . Note that they don't collide with each other. While this is possible (actually, the code is already in there, you just have to remove the comments) it slows the whole thing down with little noticeable effect. So far I've tested it in today's Minefield build and Opera 9.50. While it does work in Opera, it's too slow for practical use. In Minefield it works with or without tracing, but with negligible difference as most work is done natively by the image functions anyway. Safari fails totally for me, but then again Safari never worked properly on my system anyway (I can't get to the error console. Yes I have the menu enabled, but when I select it, nothing happens). The source for the main classes is GPLed, but the main file intentionally isn't, because the map image is provided by GoogleMaps and so only licensed under "fair use". Likewise, the tentacle is a redrawn character from Day of the Tentacle. GPLed sources: $js.js CanvasCollision.js Entity.js Crowd.js main.js Main demo HTML: index.xhtml The individual images used in this demo: map_walkable.png map.png clouds.png sprite.png

Secure web applications - using JS to create a new web language

Friday, January 18, 2008
When you look around on security mailing lists you'll probably an increase in security warnings relating to web applications... many of them based on JS code injected into a webpage. This has lead to the uncomfortable situation where pages that are based on usercontent can not trust their users to provide JS as part of their submitted content. So now we can share video, audio and other passive media but anything interactive is out of the question. What to do about it? The JS security system is entirely based on domain names and some providers have resorted to running all user js code on a seperate domain... but this again limits the usefulness of JS because it can only operate within the assigned iFrame. Others are trying to run the JS code through code analysis tools to find out if it is doing anything "forbidden". But who are we kidding? Blacklist attempts have never worked so far and the thing about web security is that even a single attack can leave data from dozens of apps exposed. The alternative is quite simple, but to my best knowledge has never been tried: Implementing a second language in JS, running protected in a seperate sandbox, allowing only whitelisted calls and if necessary filtering the results. Is this possible? Certainly? Is it hard? Not as hard as one would imagine? Is it slow? Definately slower than true JS but still fast enough to be of use. Let's tackle these questions one by one: Is it possible? Every language that can implement basic text parsing can implement it's own parser... it's really as simple as that. And it JS it's even easier because we have a bunch of text processing tools like RegularExpressions that make parsing quite straight-forward and simple. Is it hard? Not really... many of the requirements for the interpreted language can be mapped to native behaviour. For example: the garbage collector can work for the interpreted language as well if we map stacks and variables in the interpreted language back to native objects. Is it slow? In order to answer this question we have to remember how code is usually stored in high level languages: The CodeDOM. The codedom is a simple, object-based tree structure where any number of atoms make up expressions. Once we have parsed the expressions into this DOM and inserted all implicit behaviour, executing code is really just a matter of walking this tree. So each interpreted operation means running the atom handler and following the tree. The atom handlers usually don't change and can therefore be compiled by the JS handler and the jump to the next atom is just following a single reference. Combine that with the fact that we can replace known atom combinations with optimized functions and you'll see that this is fast enough for the majority of simple web apps. Just think about it what people could do if their apps were not restricted to their iFrames... youTubeOS? mySpace dynamic layouts? The sky would be the limit (That and the rules inserted into the interpreter... mySpace could opt to give users full access over the page's elements, but not their ads and not the document and window elements).

Labels: , ,

If I had a Hammer OR Why RFID in passports is a really bad idea...

Sunday, January 13, 2008
First things first: I actually do have a hammer and I know how to use it when it's time to get my new RFID-enabled passport. It's a fairly easy method to disable this ugly tracking device. The more important question is why should I do it? Well there are a couple of reasons, so let's make a list: Let's start with the basic problems of any encrypted data: 1. I don't want the state to identify me... sure they say the data is encrypted, but there was no way for officials to read it, then we wouldn't have to carry it around... so the key is somewhere and let's face it: If any part of our state has this key then it won't take long until every single policestation or whatever has access to it. 2. I don't want others to identify me ... if the key is available somewhere, then it won't take long until it leaks out. But are there other scenarios where the chip could reveal your presence. Even if the encryption was not compromised? 3. Hell yes. With RFID anybody can track you, even without the encryption key. This is by far the most interesting point. Lets assume for a moment that the data is stored 100% perecent secure and that the key is not available to anybody (I know, it's difficult but let's try). Then the chip is still sending out the encrypted data which may not be readable by itself, but it's still a unique identifier. It says that person XY was last seen going to a bank, then going to a chemical supply firm and finally after a brief visit to Starbucks boarding a flight to Saudi Arabia (at least if there's a RFID scanner at all these locations.... this probably isn't the case now but it's still a possiblity we'll have to deal with). Maybe you can't find out who person XY is, but you sure can find out what he's been doing as XY has left the same digital fingerprint at all these locations. And if XY has used another identifier, let's say a credit card, at at least two locations with an RFID scanner, we even know that this person is me. Now this may all be very useful when trying to catch a criminal (eventhough it violates about every privacy law we've got), but this kind of information is available to anybody who can afford an RFID scanner. Let's assume a group of stores agrees to exchange RFID information... not with any other authority, just among themselves. Sounds pretty harmless doesn't it? But from this information alone, combined with the list of items bought while you were at the store and matched across multiple shopping sessions and some easy statistical analysis they'll get something like this: Usually around 1pm at store A, usually buys sweets, pizza, Coke and bathroom acessories. around 6pm either at store B or C. This is only a tiny bit of what they could derive but already they'd know where you live, where you work and what you buy, just like that. And this would only be the "normal", "marketing" way of analysing your data. Criminals are much more inventive... I'm not asking you to do anything but think about it how your privacy gets a beating with RFID passports.

Labels:

CSI moves to Origo

Sunday, August 26, 2007
CSI, the Javascript client side inclusion library, is moving to a new home over at Origo... if you're interested in joining the project, just create an account over at Origo and drop me a line.

You've gotta love some quotes

Every once in a while, you come across a quote that is so absolutely stunning, you simply cannot believe that the person who wrote it was crazy enough to even put it in writing. This is just such a case.

From: Bill Gates Sent: Saturday, December 5 1998 To: Bob Muglia, Jon DeVann, Steven Sinofsky Subject : Office rendering

One thing we have got to change in our strategy - allowing Office documents to be rendered very well by other peoples browsers is one of the most destructive things we could do to the company.

We have to stop putting any effort into this and make sure that Office documents very well depends on PROPRIETARY IE capabilities.

Anything else is suicide for our platform. This is a case where Office has to avoid doing something to destroy Windows.

I would be glad to explain at a greater length.

Likewise this love of DAV in Office/Exchange is a huge problem. I would also like to make sure people understand this as well.

CSI - Client Side Includes

Monday, August 20, 2007
This has plagued me for the past few months and I simply couldn't find any nice, simple, small solutions available. If your Javascript code consists of separate parts, you probably have them separated into any number of .js files... problem is: If these JS files, like any self-respecting library, want to include other JS files, then all you can do is write down it into a comment. Then, when you start a new project that would benefit from that library, you have to add the library itself via a script tag, look at the comments, find that library that your library needs, add it via a script tag, look at the comments of that library... you see what I'm getting at. The alternative would be to let a PHP, or other script do that task... but that would either require you to move all your projects to your web directory or run that script every time you want to test your code. Additionally, when an error occurs during runtime, you won't get the file and line number of your working files, but the one in the compiled file. Not very satisfactory. Enter CSI - Client Side Includes. CSI is something in between a library and a framework. It's tiny (the core is <2k uncompressed) and requires only minimal modifications to your code. For more details (as well as a demo) and the download, check here.

Smoothly fading slideshows and hover buttons

Sunday, August 19, 2007
This was done per request and while the code is not really beautiful, it works just fine. "Fade" is a small (8kb uncompressed, 2kb compressed), standalone Javascript library which provides smooth slideshows and hover buttons, while requiring only an absolute minimum on coding knowledge. Just set a few class attributes, copy the loader code and voilĂ . It even degrades gracefully if there's no Javascript available. See it in action, along with a short introduction here. I'd love to hear some feedback, too. :) (License is CC Attribution-ShareAlike 3.0)

Sam and Max

OK, so this post doesn't have any useful information whatsoever. Big Deal? Well yes, because it's got something so utterly useless that it stands out: A dog in a suit and a naked white rabbit. More precisely, a guy in a dog suit wearing a suit carrying a rabbit. In case you haven't noticed, over at Telltale games, they're developing a new video game series and well, these guys are simply nuts. Here's their official report from Comic-Con. Watch it, enjoy it, vote for Max!

Spore - It's not that scary!

Monday, August 6, 2007
I just finished reading an article over at Bona Fide Reviews and I simply can't keep but smiling. You should read the actual article for yourself and then consider my reply. Enjoy: OK, let's start one by one. First of all we should clarify if we're talking directly about programming or rather some greater logic that is the basic for the whole program. In this case this is almost certainly the logic behind the programming, not the actual language itself. In fact, it's not even the logic behind the whole program: It's the logic behind one subsystem, namely the model generation. The point is that Spore simply adds a whole new level of abstraction for generating and maintaining models. Notice that the system itself is nothing new... it has been around since the first days of game programming. But maybe it's easier to explain it using a well known example. Consider the model generation in Half Life You see a guy lifting his arm... what data is actually stored and which one is generated on-the-fly by Half Life, DirectX or your graphics card? What you see is a two dimensional raster image, so does Half Life come with a image of that guy from every imaginable angle? No, it doesn't. This would either require a huge amount of memory or limit the number of angles. However, this was done by older games like Doom to save processing power... as a result no matter from which angle you would look at a monster, it was always one of four images (Left,Right,Front,Back). So, we've established that the guy isn't stored as a 2D raster image, so what is he made of? What data is processed into the image we see? Well, it is a vector image... an image where points and the areas between them, together with a number of parameters like the color of a area make up a description that can be used to generate a bitmap. But this doesn't really solve our problem, there are still way too many angles. We really have to abstract some more. What data can be used that when combined with a particular angle results in a 2D vector image? You've got it: a 3D vector image! We just spread the points along an additional third axes and suddenly we can generate a 2D vector image from every imaginable point. Hurray! But wait, the guy is lifting his arm! Uh... do we have to store a 3D vector image for every single point in time while he's lifting his arm? Well... this was done by the game on which Half Life is based (Quake) and it wasn't a very good system... In order to keep the size of all these models down, they had to remove precission resulting in a very strange effect where parts of the model would appear to change shape. Luckily, there's an alternative! We can use yet another form of abstraction! We simply divide the data up again, in this case in the static 3D vector image and a skeleton that defines which parts of the 3D vector image belong to which bone. So now we just have to store the 3D model of the skeleton and in order to for example lift his arm, we simply move the arm bone, and all points in the 3D vector image that belong to the arm bone will move the same way. But this isn't enough! There may be hundreds of guy in the game and most of them lift their arm in a similar way. Since we seperated the skeletal animation data from the 3D vector image, we can use it for all guys, not just this one! But we still have to define all individual states, so let's abstract some more! We can simply define a number of points along which the bone should move, and voila, we only have to save two or three states and interpolate between them. ----------- This is where it ends for Half Life. But wait! There's more! Unreal was one of the first games to dynamically generate images to be used as textures for the areas in a 3D vector image: They would for example specify a image and then generate a whole series of images where water was flowing across it. Quake3 brought parametric skeletal animation to the masses. There would only be one animation for walking which was modified to make it appear as if different characters walked differently. Some would spread their legs more, others less and so on. Others, like the famous N64 game Waveracer, would generate models for a whole see using a set of rules that formed a simplistic physics model. And finally we see games like World of Warcraft creating a near infinite number of models by combining parts of different models. ----------- But there's one gap. We always end up with a static model that's being deformed in various ways. And this is where Sporn offers (or appears to offer) something new. We can create arbitary models from a simple model (in this case a ball). In fact it's not new at all. We're simply add better deforming algorithms and give them more freedom in that we not only allow them to not only move existing points, but also add new ones. We add routines that we've developed to simulate physics to make it appear a if we were actually sculpting. Then we apply all the techniques mentioned before. It's a great example of evolution, not revolution.

xmlTree - minimalistic XML processor for PHP

Friday, March 30, 2007
xmlTree is a tiny, little XML processor for PHP that doesn't even offer 10% of what the XML spec has to offer, but still manages to do almost everything a normal developer needs (and besides, it's easy to extend). It's meant for all those people that
  • Hate to use code that they cannot possibly understand
  • Prefer small libraries
  • Don't expect the XML Library to validate their data
  • Don't need the XML library to handle data that's not trustworthy
  • Don't need automatic character conversion, like " to \" or <>
So, it's really quite minimalistic. It was initially written to store configuration data for another program, but ended but managing quite a bit of the HTML code too. Essentially, it provides the following features:
  • An XMLElement class that provides parentNode, childNodes, tagName and attributes. It also provides a value for text nodes
  • A Javascript like DOM manipulation system, featuring such gems as appendChild, setAttribute, getAttribute, removeChild, getElementsByTagName, getElementsByName,getElementById, toXML and toFile, all of which (with the exception of the last two methods) behave almost exactly like their Javascript counterparts.
  • An XMLDocument class with html, head, title and body (nothing special, but it makes life easier)
  • An XMLParser class that turns an XML string into a XMLElement tree.
You can find the source, along with some more notes here. Oh, and it's GPL too.

Labels: , ,