Check out my
new book!
HTML5 Games book
WolfenFlickr 3D - An unlikely mashup Long after B.J. Blazkowicz left Castle Wolfenstein guns blazing, the castle still holds a few secrets. On a super secret floor stolen art in the form of Flickr images has been found and for the first time, this strange gallery is now open to the public.

If you're interested in building an engine such as this yourself, take a look at the Dev.Opera article I've written on this topic.

This is a (silly) mashup of Wolfenstein 3D and Flickr. More specifically, it's a Javascript raycaster using Wolfenstein graphics that allows you to import Flickr images by username/search query and then walk around this odd gallery.

If you don't care about the details and just want WolfenFlickr gallery action, go straight to the WolfenFlickr 3D demo page.

This little experiment killed two birds with one stone. First, I wanted to get to know Flickr's API (and Flickr itself, actually, me not being a big photo nerd). Second, I wanted to do a Javascript raycasting engine. In a moment of unusual clarity, it came to me that these goals were not mutually exclusive and while the end result borders the useless (hey, most things here do), the project served its purpose well.

WolfenFlickr 3D - Flickr / Wolfenstein 3D JavaScript MashupThe Flickr API part turned out to be pretty simple. The Flickr guys are good people and provide very easy to use methods, JSON data and the option to specify callback JS functions making it a breeze to implement Flickr integration, at least on the level that I'm using here. So, we simply retrieve all photos from a specified user (or matching a search query) to create a list of images for our gallery. For performance reasons, only the first 20 Flickr images are used.

The Wolfenstein part wasn't all too hard either, although lots of tinkering was needed to make it run semi-smoothly. Unlike the previous JavaScript Wolfenstein 3D experiments here, this one uses a raycasting engine and not the JavaScript 3D engine. If you want to read more about raycasting, check this link or Wikipedia.

Basically, The screen is divided into X amount of vertical strips (div elements). Each of these strips contains an image element with all the wall textures making the strips serve as containers and masks for the actual lines. "Rays" are then cast out on the map for each strip and when the ray hits a wall, we simply move and scale the wall texture image in the strip according to which wall type, where on the wall the ray hit and how far away it is. Each strip also holds a copy of all the Flickr images positioned on top of the wall textures. Each wall block (with picture frame) is assigned a Flickr image and then it's just a matter of showing the appropriate part of the image on top of the texture. The pictures are stretched (and slightly cropped) to fit the frames, so it looks best with pictures that are not too tall/wide. There are a few things I need to fix and then maybe I'll do a more detailed post on the raycasting part if there's any interest?

I also tried using canvas just to see what kind of performance that would give. It appeared to be roughly equal to the straight DOM approach but would get complicated (and probably slower) when sprites were added since the current approach utilizes the browser's own fast depth sorting via the z-index on the strips and sprites.

Tested with FF2, FF3, Opera 9.51, IE7 (IE8b1 doesn't work), Safari 3.3.2. For some reason the recent WebKit nightlies are not working for me at all (crashes on any page, anyone else get that?), but Safari 4 dev preview works fine.
Safari is awesome and runs very smoothly for me. Opera 9.51 runs ok, IE7 and FF2 a little slower and for some reason FF3 is just horrible slow. Where FF2 takes a hit at the raycasting (ie. pure Javascript) and is quite fast at changing/rendering the DOM elements, it seems FF3 is just the opposite. Maybe I'll give the canvas approach another go and see how FF3 likes that.
Edit: For better performance in Opera, turn off [Multimedia]->"Interpolate images" in "opera:config" and it should run a lot faster.
The player position is for some reason not drawn on the minimap in IE (and the map might not render at all). Other than that, there shouldn't be any major problems (aside from speed).

Take the WolfenFlickr 3D tour!

Edit: I also found a Youtube video of WolfenFlickr in action. Check it out if you're having trouble with the real thing!

And do leave a comment if you feel like it.
⇓ 38 comments Anonymous

Its incredible that you achieved this without the use of canvas! This raycasting technique is very interesting.. i would definitely like to understand better your implementation, however, maybe i wont understand this easily! As always, awesome work!

July 14, 2008 at 4:25 AM
Anonymous

Fun mashup. It's quite a change to wander in the Castle Wolfenstein with kitten ( live ones even ) on the walls :D

The engine feels quite slow here ( Op 9.5 on a 3.4Ghz P4 ), I'd say ~10fps and less when facing a Flickr image. Raycasting ~100 slices should run at 33 to 67 fps.

Too bad security restrictions would forbid to composite the textures using Canvas so as to only have one set of slices. A proxy script might be in order.

Anonymous: FYI, Canvas is not best the weapon in the DHTML arsenal to do raycasting as it makes the Zbuffering more tricky. Unless you want to do raycasting with a special twist, good old xHTML+CSS is the fastest and more convenient option.

July 14, 2008 at 4:31 AM
maikelkrause

"maybe I'll do a more detailed post on the raycasting part if there's any interest?"

Definitely. :)
As a web developer who's graphically inclined, I find these projects of yours really really interesting. Nice touch with the "Burned out web developers" by the way.

July 14, 2008 at 4:35 AM
Jacob Seidelin

@p01: One thing that drags performance down is having each slice carry all the Flickr images as well. Even when they're not displayed (display="none"), it seems they affect performance just by being there.

My first idea was actually to do the compositing you mention, but yea, security prevents getting it back out and scaling the canvas elements probably would be slow. Plus, no IE support.

July 14, 2008 at 4:42 AM
Anonymous

jacob: All the Flickr images need not to be in each slice. Of course you need an IMG node in each slice to show them but the images themselves only need to be in the memory/DOM once. Then a good'ole image swap with preload does the trick, and it's bloody fast.

The texture compositing is still doable with a server side script. Plus it'll give you textures that are all the same size, thus reducing the complexity of the render() method.

July 14, 2008 at 5:33 AM
Anonymous

Great mash-up!

Even more amazing you got away with using a load of div's. Congratulations. Would be nice hearing about how you got it all to work.

Seems to work on the iPod touch as well. Though sadly there are no controls, so one cannot move about. :(

July 14, 2008 at 5:57 AM
Anonymous

Really nice!

There were some performance issues after the change to Cairo on Firefox. Though, it works pretty fine with the nightlies, it's smooth except when you turn.
Using Athlon 64 3800+ 2.4Ghz 512 KB

Relevant bugs, if you're interested
Unix: https://bugzilla.mozilla.org/show_bug.cgi?id=334720
Windows: https://bugzilla.mozilla.org/show_bug.cgi?id=334719
Mac: https://bugzilla.mozilla.org/show_bug.cgi?id=334721

July 14, 2008 at 6:27 AM
Jacob Seidelin

@p01: Hmm, that does seem quite obivous, doesn't it? ... Ok, tried that now and it feels a little bit faster now (in FF2 at least). Thanks. There's still lots of room for improvement though, but that's for some other day.

And yea, the compositing could easily be done server side, but I'd rather stick with pure JS and then suffer the extra performance hit :)

One thing I noticed in Opera is that it looks like it's using different scaling methods for the walls and the sprite images, and I don't know why. Looks like the walls are interpolated, but the sprites aren't.
Turning off [Multimedia]->"Interpolate images" in opera:config makes everything run a lot faster.

@james: Thanks. Nice with the iPod. I don't have one (yet), otherwise I'd try to make it (and other things) work on it as well.

@anon: Ah thanks. Good to know.

July 14, 2008 at 6:28 AM
Jacob Seidelin

Ok, I'm puzzled. Opera seems to only interpolate images if they have 20 or more colors. Anything less than that gets the old nearest neighbour treatment.
The interpolating is making Opera slow, so for now I've made Opera use a different (uglier) wall texture image with only 19 colors. That speeds it up a bit, but the Flickr images are still interpolated.
For most profit, you still need to turn off "Interpolate images" in opera:config.

July 14, 2008 at 7:56 AM
Anonymous

jacob: This 20 colors madness is apparently due to a GDI method of Windows. :(

July 14, 2008 at 8:46 AM
Anonymous

jacob: The GDI method does not interpolate images with transparency. You can keep the original walls.png image by adding a transparent line at the bottom.

\:D/ for work arounds ... not!

July 14, 2008 at 9:20 AM
Jacob Seidelin

Haha, nice. Thanks for clearing that up. I think transparency in the wall texture reduced performance even more when I tried that earlier (for other purposes) but maybe I'll try it again.

July 14, 2008 at 9:37 AM
Jacob Seidelin

Yea, FF doesn't like the transparency. Oh what a mess.

I suppose the interpolation in Opera is nice and all but it'd be neat if there was a way to just tell it "leave this image alone, please"

July 14, 2008 at 9:41 AM
Anonymous

Well, finally managed to get movement working on my iPod touch. Unfortunately it is slooooow. As in, in the realm of ~1FPS.

I can also see banding where i presume the slices are. So all-in-all, it's not looking very nice.

Base64 encoded Code for the touch controls:

ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsIGZ1bmN0aW9uKGUpewogICAg
dmFyIGVsID0gZS50b3VjaGVzWzBdLnRhcmdldDsKICAgIGlmIChlbC5pZCA9PSAidG91Y2hfdXAi
KQogICAgICAgIG9QbGF5ZXIuc3BlZWRpbmMgPSA1MTI7CiAgICBlbHNlIGlmIChlbC5pZCA9PSAi
dG91Y2hfZG93biIpCiAgICAgICAgb1BsYXllci5zcGVlZGluYyA9IC01MTI7CiAgICBlbHNlIGlm
IChlbC5pZCA9PSAidG91Y2hfbGVmdCIpCiAgICAgICAgb1BsYXllci5yb3RpbmNkaXIgPSAtMTsK
ICAgIGVsc2UgaWYgKGVsLmlkID09ICJ0b3VjaF9yaWdodCIpCiAgICAgICAgb1BsYXllci5yb3Rp
bmNkaXIgPSAxOwp9LCBmYWxzZSk7CmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInRvdWNoZW5k
IiwgZnVuY3Rpb24oZSl7CiAgICAgICAgb1BsYXllci5zcGVlZGluYyA9IDA7CiAgICAgICAgb1Bs
YXllci5yb3RpbmNkaXIgPSAwOwp9LCBmYWxzZSk7Ly8gVG91Y2ggY29udHJvbA==

And the HTML element (to be placed before the map div. Also expand the container to 734px.

Jmx0O2RpdiBpZD0idG91Y2giIHN0eWxlPSJwb3NpdGlvbjphYnNvbHV0ZTsgbGVmdDozMjRweDsg
d2lkdGg6MjAwcHg7IGRpc3BsYXk6YmxvY2s7aGVpZ2h0OjIwMHB4OyBib3JkZXI6IDJweCBzb2xp
ZCAjY2NjIiAmZ3Q7CiAgICAgICAgJmx0O2RpdiBpZD0idG91Y2hfdXAiIHN0eWxlPSJtYXJnaW4t
bGVmdDphdXRvO21hcmdpbi1yaWdodDphdXRvO3dpZHRoOjYycHg7IGhlaWdodDo2MnB4OyBib3Jk
ZXI6IDJweCBzb2xpZCAjY2NjIiZndDtVJmx0Oy9kaXYmZ3Q7CiAgICAgICAgJmx0O2RpdiBpZD0i
dG91Y2hfbHIiJmd0OwogICAgICAgICZsdDtkaXYgaWQ9InRvdWNoX2xlZnQiIHN0eWxlPSJmbG9h
dDpsZWZ0O3dpZHRoOjYycHg7IGhlaWdodDo2MnB4OyBib3JkZXI6IDJweCBzb2xpZCAjY2NjIiZn
dDtMJmx0Oy9kaXYmZ3Q7CiAgICAgICAgJmx0O2RpdiBpZD0idG91Y2hfcmlnaHQiIHN0eWxlPSJm
bG9hdDpyaWdodDt3aWR0aDo2MnB4OyBoZWlnaHQ6NjJweDsgYm9yZGVyOiAycHggc29saWQgI2Nj
YyImZ3Q7UiZsdDsvZGl2Jmd0OwogICAgICAgICZsdDsvZGl2Jmd0OwogICAgICAgICZsdDtkaXYg
aWQ9InRvdWNoX2Rvd24iIHN0eWxlPSJjbGVhcjpib3RoO21hcmdpbi1sZWZ0OmF1dG87bWFyZ2lu
LXJpZ2h0OmF1dG87d2lkdGg6NjJweDsgaGVpZ2h0OjYycHg7IGJvcmRlcjogMnB4IHNvbGlkICNj
Y2MiJmd0O0QmbHQ7L2RpdiZndDsKJmx0Oy9kaXYmZ3Q7

In any case, keep up the good work!

July 14, 2008 at 10:54 AM
Anonymous

Hey Jacob,

Wow you did it again! I was going to release a raycaster sans canvas like this, but you beat me to the punch AND you've got a sweet mashup.

I'll try to get Ajaxian and Flickr to post about it too. Awesome stuff!

July 14, 2008 at 1:28 PM
Jacob Seidelin

@james: Yea, I figured the iPod would be a tad underpowered for something like this. But thanks for the touch code!

@matt: Thanks! (and sorry! ;) although I can see that you beat me to making the "other cool game experiments" post that I was planning.)

July 14, 2008 at 1:52 PM
Unknown

Very creative mashup!

BTW, the latest WebKit nightly (July 13) works great for me.

July 14, 2008 at 3:53 PM
Anonymous

Fresh raycasting engine application with a retro touch.
I <3

Blogged here: http://www.vedetta.com/unitone-said-143

July 14, 2008 at 7:55 PM
zproxy

Very cool project! :)

I will now need to learn raycasting!

July 16, 2008 at 3:56 AM
Anonymous

Awesome work!
I am quite noob at Javascript so I wasn't aware such things could be done with it!

July 18, 2008 at 10:02 AM
Anonymous

Amazing, brilliant, fantastic!! This is a really good mashup.

July 19, 2008 at 1:59 AM
Philip

I only see the flickr logo showing up where actual pictures should. Maybe you hit a rate limit or something?

August 28, 2008 at 12:39 AM
Anonymous

Interpolated images looks faster here.
And... how about a key to open the flickr image page on a new page/tab?
(if you are seeing imageidnumber by user, and press SHIFT the http://flickr.com/photos/user/imageidnumber/ will open on new tab)
I think is better than trying to find the image on google.

August 28, 2008 at 5:02 AM
Anonymous

You should only be pulling creative commons images licensed for commercial use. You *REALLY* need to read the legal Terms of Use for the Flickr API - what you're doing is against them.

This hit boingboing - prepare for an onslaught of "feedback" from peeps on Flickr when they find their photos can be used in this app.

August 28, 2008 at 3:28 PM
Jacob Seidelin

Still anxiously awaiting the onslaught...

August 31, 2008 at 3:08 AM
Anonymous

I played with this in Chrome... V8 really makes this fly. :-D

September 4, 2008 at 1:56 PM
mago28

great job!!!

September 18, 2008 at 12:26 AM
Anonymous

IE8B2 appears to render though not fast.

September 25, 2008 at 8:52 AM
Anonymous

i am running on my laptop PM1.1 and have to change to low res for sure.

however, firefox3 still lag. chrome is quite smooth

September 27, 2008 at 11:50 AM
Anonymous

This is just wirking with FireFx, is'nt it?

October 21, 2008 at 2:48 AM
Jacob Seidelin

It's supposed to work in all major browsers. Let me know if there are any problems.

October 21, 2008 at 9:01 AM
Anonymous

Excellent!

I want to be able to email a friend with a link to this with a URL parameter user=MyMatesFlickrName

All we need then is some kind of flickr badies to shoot at!

November 6, 2008 at 4:38 PM
Anonymous

neat stuff!impressive!!!

November 13, 2008 at 6:34 PM
Anonymous

Really cool idea, you should improve this!

November 25, 2008 at 11:43 AM
Andrew

How open are you to other folks using/modifying this code? I just saw your article on dev.opera.com -- are the examples there open for reuse/hacking? What would the license be? (I have a little RPG that would benefit greatly from this)

November 28, 2008 at 8:53 AM
Jacob Seidelin

@Andrew: Yes, the examples are free to use. The license would be the MIT license I usually use, I'll see about getting a note about that added to the dev.opera.com article.

November 28, 2008 at 9:20 AM
Ritchie Flick

This is a strange project, but it fascinates me!
Great job!

November 29, 2009 at 4:41 AM
Zsombor

Great idea and fantastic job! Keep going!

July 30, 2012 at 6:55 AM
Post a Comment