
Notch trying jsFiddle - vasco
http://jsfiddle.net/uzMPU/
======
antirez
Awesome implementation, actually no advanced feature is used, this code could
easily ported even to assembler in any device where you can set pixels in RGB
format.

And indeed it is pretty impressive how fast the rendering happens given that
the code operates at such lower level... Even selecting the color of every
pixel requires non trivial work in the inner loop.

AWESOME code.

~~~
jrogers65
I would argue that this is terrible code. It's not using the appropriate tools
(webGL), it's badly structured, uncommented and unmaintainable (seriously, why
on earth would anyone name their variables zd, _zd and __zd?). The Minecraft
source code is also of notoriously poor quality. I honestly don't understand
how you came to your conclusion.

~~~
mmcnickle
The code is a direct port of Minecraft4k[1], it's optimised for space
considerations.

[1] <https://twitter.com/notch/status/275329867984302081>

~~~
jrogers65
But that directly backs up my argument. From the horses mouth:

"Code is awful due to the nature of the project"

------
JoeCortopassi
Such a great example of what can be done in javascript/canvas. As it is, I was
completely blown away by how _little_ code it actually took to do that. My
only gripe would be, why couldn't he have used descriptive variable names, so
I can better go through and understand it? :-)

~~~
antirez
This code uses zero canvas / javascript specific functions. It is using basic
trigonometric functions and is using canvas only to write RGB pixels. Canvas
are much more powerful and high level than that, but this is not a good
example as Notch just needed to set pixels.

~~~
petercooper
Having watched Notch write Prelude of the Chambered (which I then ported to
JRuby) it seems he really loves this direct pixel manipulation style - as do
I!

The sad part, though, is it doesn't particularly scale well with canvas (yet)
and using sprites, shape primitives, or even WebGL is way to get full speed at
a regular resolution. (Imagine a 640x480 pixel field of randomized colors, you
can get hundreds of FPS for that in Java without a sweat. Not so in the
browser and most certainly not in JRuby.. my PotC port struggled to hit 12fps
with equivalent code.)

The title of "ChamberedTest" here makes me wonder if notch is planning to use
JS and canvas in the forthcoming Ludum Dare 25 (the gamedev contest where he
created Prelude of the Chambered). I hope so!

~~~
pygy_
For those interested, here are the first three hours of the "Prelude of the
Chambered" stream.

[http://www.youtube.com/watch?v=rhN35bGvM8c&t=10m05s&...](http://www.youtube.com/watch?v=rhN35bGvM8c&t=10m05s&hd=1)

~~~
pygy_
An hopefully ad free version will soon be available here (I trimmed the first
ten minutes where nothing was happenning but infringing audio):

[http://www.youtube.com/watch?v=xYRBBXq3s6c&hd=1](http://www.youtube.com/watch?v=xYRBBXq3s6c&hd=1)

~~~
pygy_
Please disregard. Other copyrighted stuff was instantly detected.

------
petercooper
I've recorded a screencast that digs into how the programmatic texture
generation works in this code: <https://www.youtube.com/watch?v=WaZvDCmlERc>

~~~
ozataman
Thanks a lot for taking the time! Any chance you can do one for the game loop
and the rest of the code?

------
petercooper
Here's a rendering of the texture map so you can see what it generates
directly: <http://jsfiddle.net/cXvKa/>

------
recurser
Notch has made a couple of comments on reddit :

[http://www.reddit.com/r/programming/comments/146v69/how_notc...](http://www.reddit.com/r/programming/comments/146v69/how_notch_procedurally_generates_minecraft/c7aelxz)

    
    
        Please do NOT write code like this. It was originally written for the Java4k 
        competition, which focuses on executable code size, and is as a result almost 
        intentionally poorly written. It got even worse when I ported it to JS.
        It was mainly meant as a test for me to see what HTML5/JS can do, and an 
        exercise in porting code over.
    

[http://www.reddit.com/r/programming/comments/146v69/how_notc...](http://www.reddit.com/r/programming/comments/146v69/how_notch_procedurally_generates_minecraft/c7aflnm?context=3)

    
    
        It would run a bit smoother if it was written in C++ (mainly due to not having 
        to rely on the GC, and having it precompiled gets rid of the warmup time), and 
        modern OpenGL would help quite a lot as well. A lot of the stuff done in CPU 
        now could be moved to a shader, which both makes code simpler, and gets rid of 
        the slow JNI calls required now.
        The main reason why Minecraft is slow is mainly 1) There's a LOT of polygons, 
        combined with 2) The difficulty of making an efficient culling algorithm in a 
        dynamic world.
        If someone solves #2, very interesting things could be made with a game similar 
        to Minecraft.
    

[http://www.reddit.com/r/programming/comments/146v69/how_notc...](http://www.reddit.com/r/programming/comments/146v69/how_notch_procedurally_generates_minecraft/c7afwjp?context=3)

    
    
        No, they don't get merged because the textures are all pulled from the same atlas 
        to avoid texture swapping. With GLSL, they could be merged, saving quite a lot of 
        polygons. For a while, I did attempt switching the atlas from a 16 x 16 grid to a 
        1 x 256 grid and merging horizontal runs of the same texture, but the resulting 
        texture size was to tall some graphics cards (on low end computers) would 
        automatically downsample it.
        The problem with the occlusion culling is not about knowing what parts are static, 
        but rather figuring out what occluders there are. It would be very beneficial not 
        to have to render caves under ground below the player, for example, or not to 
        render the entire outside when a player is inside a small closed house. Figuring 
        this out in runtime on the fly as the player moves around is.. expensive.

------
scottyallen
This would be a great demo to see running in a responsive programming
environment, ala Bret Victor's amazing Inventing on Principle talk
(<http://vimeo.com/36579366>). I want to be able to click on hex values and
get a color picker that updates the demo in realtime, and be able to click on
various magic numbers and drag a slider to change them.

Incidentally, Bret Victor's talk was the starting point for Khan Academy's CS
curriculum that John Resign led (<http://ejohn.org/blog/introducing-khan-
cs/>).

Edit: I managed to get this running in livecoding.io, which does some of what
Bret Victor was talking about (basic sliders and color pickers):
<http://livecoding.io/4191583>. Not sure why it's running so much slower
though...

~~~
undergroundhero
Thanks for the livecoding link. I assume there's some overhead in constantly
checking for and applying code changes - that's probably the reason for the
lower frame rate.

~~~
scottyallen
Good point, I hadn't thought about the fact they might be polling for changes.
Might be better if livecoding used an event based model to check for
updates...

~~~
akx
Or if it works at all like Scrubby (<http://nornagon.github.com/scrubby/>)
which was on HN a couple days ago, it might rewrite all constants into global
lookup table indexes, which surely wreaks havoc on performance.

------
experiment0
Correct me if I'm wrong but does this procedurally generate the textures for
each block. I can't see any code for loading assets and the init function, has
some quite complicated color code. If so that is awesome!

~~~
antirez
Yes, the procedure generates the texture of every "type" of block, the first
loops after the init() function. 16 different types of blocks are generated.

Then a random map is created, with the "center" that is set to empty blocks
with high probability. Finally a function traces the map on the screen at
every tick of the clock.

~~~
andrewmunsell
Ok, that's pretty cool :P

~~~
petercooper
I've recorded a video explaining how it works:
<https://www.youtube.com/watch?v=WaZvDCmlERc>

~~~
gameshot911
This was incredibly helpful - thank you.

------
arriu
I enjoy that everything is procedural generated. The software rasterizing is
pretty cool too. I don't mind that he uses short variable names, sometimes
it's nice to have multiple lines line up perfectly. But this is just silly...

    
    
        for ( var x = 0; x < w; x++) {
            var ___xd = (x - w / 2) / h;
            for ( var y = 0; y < h; y++) {
                var __yd = (y - h / 2) / h;
                var __zd = 1;
    
                var ___zd = __zd * yCos + __yd * ySin;
                var _yd = __yd * yCos - __zd * ySin;
    
                var _xd = ___xd * xCos + ___zd * xSin;
                var _zd = ___zd * xCos - ___xd * xSin;

~~~
albertzeyer
Can you explain why?

~~~
arriu
I don't enjoy comparing the length of relatively similar lines. Why not use
xa, xb, xc, etc... instead of xd, _xd, __xd, ___xd, yd, _yd, __yd, ___yd, zd,
_zd, __zd, ___zd?

~~~
Raticide
I think the underscores standout better.

------
moconnor
I'm shocked and pleasantly surprised that js/canvas can putpixel fast enough
for this. It must be around as fast as assembly on a 486!

Part of me can't decide if that's awesome or tragic.

------
gavanwoolery
Very cool, but a few notes to anyone getting their hopes up on the powers of
Canvas:

As you may have anticipated, this demo runs at less than 1 frame per second on
my Nexus 7. :/

In terms of per-pixel manipulation of a Canvas, it is very slow, even with
javascript's (not very well supported) typed arrays. Simply put,
multidimensional loops (unrolled or not) will always kill performance in JS
with any significant dimensions. I learned this the hard way by trying to
write a pixel-based GUI, and even that (with some crazy optimizations) could
not render fast enough for all devices. If you are just doing blits, Canvas
works very well (especially since this operation often uses the GPU).

For now, I think the best option is still WebGL, even though it is not widely
supported yet, mobile devices are beginning to pick it up (Blackberry, for
example).

~~~
hornbaker
Runs about 6-7 fps on my iPhone 5.

~~~
gavanwoolery
Nice :) Shows you how fast ARM is progressing...

~~~
hornbaker
But only 4-5 fps on my iPad 3. Hmmmph, thought that'd be faster.

~~~
manmal
My iPhone 5 is considerably smoother and faster than my iPad 3. That's surely
also related to the iPad's insane pixel count, but the iPhone also loads and
switches apps faster, before CPU-based rendering is a factor.

------
zzzzzzzzz
Obligatory flash port: <http://wonderfl.net/c/sqL5>

~~~
spyder
That's faster than the JS demo (even the improved one) in any browser. It's
sad that browsers still don't have at least the same performance as flash :(

~~~
kevingadd
It's faster because he made the Flash version use strongly-typed arrays.

------
tgandrews
Can anyone explain how this works? I never have got to grips with 3D.

~~~
tylerdiaz
Looks like he's ray casting it, no 3D code implemented, just the illusion
itself.

~~~
antirez
Well... actually the code contains a minimal 3D engine, it is not an illusion,
you have the observer variable and could use it to navigate inside the map
created in the initialization function. What is more 3D than that? :-)

------
AshleysBrain
While this is cool, isn't this exactly what WebGL is for? I know
drivers/support is an issue, but Chrome also ships with a multicore software
renderer (SwiftShader) which can probably get a lot further than a JS
putImageData engine.

~~~
Raticide
It's just a demo. It's for fun.

------
Pezmc
Can someone dissect this code and explain what it does?

~~~
snprbob86
The first set of three nested loops is procedurally generating texmap, which
is a multidimensional Array(16 * 16 * 3 * 16). 16x16 pixel textures, one for
each the top, sides, and bottom, and then 16 of those. The inner loop tests
against i, which is the current block "type" and performs customizations to
the procedurally generated textures.

The next set of three nested loops is generating a random "world" with a
tunnel cut out of it.

The renderMinecraft function is performing a minimal perspective projection
<http://en.wikipedia.org/wiki/3D_projection> for a single ray cast into the
world. Each pixel is cast and then, for each object hit by the ray cast, the
closest is found, and a texture mapped pixel is calculated and written into
the frame buffer.

~~~
antirez
It is worth to note that lightning model is trivial and only maps given
directions of faces to given amount of bright. But other than that the bright
is adjusted by distance.

It is pretty cool to see how a trivial lightning model like that can produce a
pretty looking result.

If you want to see just the brightness of faces without texture to see more
easily how light is used, just change the line:

    
    
        var cc = texmap[u + v * 16 + tex * 256 * 3];
    

Into:

    
    
        var cc = 255+(255<<8)+(255<<16);
    

To also remove the "distant is less bright" effect just add:

    
    
        ddist = 255;
    

Before:

    
    
        var r = ((col >> 16) ...

------
phete
<http://jsfiddle.net/uzMPU/3165/>

using window.requestAnimationFrame just because we can!

~~~
Aissen
Wow! This is incredibly smoother here on Firefox 18! (slow machine)

------
shocks

        setInterval(clock, 1000 / 100);
    

Is there any reason for writing 1000/100 instead of 10?

edit: Thanks guys!

~~~
anatoli
It just makes it clearer that he wants it to run at 100FPS: (1000ms / desired
FPS)

The usefulness is more obvious when you want 60FPS, which is not easily
represented without rounding.

------
p01
Tooting my own horn here, but here's my own little "Minecraft" renderer in
Neja, circa 2005 (
[http://www.youtube.com/watch?feature=player_detailpage&v...](http://www.youtube.com/watch?feature=player_detailpage&v=0JB66fttJXY#t=143s)
). Over 4 years before Minecraft, and even then that was nothing new. It was
kinda cool for JavaScript, in 2005, but all things considered, it was pretty
lame compared to Ken Silverman's voxlap for instance.

The "cool" thing about this demo, was that Canvas was not widespread back then
so I generated all the chunky effects on the fly as 24bits BMP image, then
made a data: URI and update an IMG tag.

------
ricardobeat
"Notch coding in JS" is a bit more descriptive than "trying jsfiddle",
specially since it looks like code posted after the fact. A minecraft-like env
rendered on canvas with it's own mini-3d-engine is amazing nonetheless :D

~~~
felixthehat
To be fair, that's the description notch used in his tweet:
<https://twitter.com/notch/status/275331530040160256> :)

~~~
citricsquid
"Trying jsfiddle.net" was in reference to his previous tweet, the previous
host he used crashed under the load from his twitter link. He wasn't "trying
jsfiddle.net", he was "trying jsfiddle [as an alternative to the previous host
that crashed]"

------
Flow
This is actually quite fluid on iPhone 5. I asked a co-worker to try this on
his Galaxy S3(quad-core, no lte) and it was really slow there. And in Chrome
it was even slower than that on the S3.

Doesn't any web browser on Android use a JIT?

~~~
pja
I believe Firefox for Android does, and as far as I know so does the stock
Android browser! Perhaps the pixel writing that Notch is doing is not well
optimised on Android?

------
JungleGymSam
Why is the framerate poor even when I shrink the viewing area down 10x10? It
seems to have the same stutter as the original large view. Is it because it's
doing the same calculations but just showing fewer pixels?

~~~
kevingadd
Part of the reason it's slow is that it doesn't use typed arrays. This may be
much faster for you: <http://jsfiddle.net/uzMPU/1573/>

~~~
voltagex_
Yes, at least 2x here. I'll pull up Chrome's FPS display later.

------
bitteralmond
Funny how he writes it so much like Java. I see so many different styles with
JavaScript.

------
HyprMusic
There's been quite a bit of analysis as to what's happening here, if anyone
could do a breakdown (or provide good examples) it would be awesome for people
like me who are amazed by the power of the maths involved here.

------
prawn
Interesting for an untrained programmer to tweak and see what happens each
time - changing colours, speeds, sizes, reversing the flow, changing textures,
etc. Accomplishes so much with such concise code.

~~~
chii
its a good exercise to work out how to stop it from moving "forward" and get
the mouse to control the camera. Its a little tricky, but you can do it with
about 10-20 more lines of code.

------
malkia
Almost straight port here to luajit -
<http://github.com/malkia/ufo/blob/master/samples/notch.lua>

------
ghenne
Here is the code in an App Studio project:

<http://blog.nsbasic.com/?p=1060>

Runs fine on an iPhone 5!

------
gps408
Why is init called twice? Once at the end of the js and then again in the
html.

~~~
ghenne
The one in the html should not be there.

------
seetherage
who the heck is Notch?

~~~
josephagoss
Notch created a popular pc game called minecraft where you mine blocks and
build things. It became very popular and made him a multi-millionaire.

This demo has a little bit of minecraft in it. :)

~~~
gyazbek
thank you very much!

------
jeffehobbs
So cool.

------
Empro
Interesting, and pretty damn cool!

------
marcamillion
This shows how far the browser has to go....was it just me, or did your
browser start to choke while rendering this?

It rendered it fine, but I could tell that the DOM was being abused heavily. I
don't mean that in a bad way, but it just felt very 'heavy'.

On the flip side, this is awesome that the browser can do this - and it's
awesome that browsers can do this.

~~~
epidemian
The DOM is not being heavily abused; it's just a canvas element and nothing
else. The demo is so CPU intensive because the code is drawing the rasterized
image pixel by pixel on the canvas, instead of relying on the GPU and using
WebGL which would, AFAIK, result in much better performance.

One positive effect of doing this is that the code is _very_ portable and
doesn't require any crazy feature in the browser or the PC (for example, i'm
able to see the demo on my work computer even though WebGL doesn't work on it
because of lack of drivers).

------
gbenitez
I showed it to my mom, and she was like ":Ooohh mother fucker"

