27 ms·
Notch trying jsFiddle
- shocks 14y agosetInterval(clock, 1000 / 100); Is there any reason for writing 1000/100 instead of 10? edit: Thanks guys!
- Riesling 14y agoProbably just to emphasize that clock will be called 100 times per second (which will result in 100 fps).
- Rygu 14y ago100 frames per second. He probably changed that during development.
- estel 14y agoIt's a good way to remind you the figure is in ms, and easily manipulate the interval as a fraction of a second.
- anatoli 14y agoIt 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.
- dag11 14y agoIt was probably for readability, i.e. "100 times per second". Similarly, people will write (10 * 60 * 60) if the value is seconds and the programmer intends to indicate 10 hours.
- sisk 14y agoI personal do this for legibility and ease of comprehension. Kinda loses its value when dealing with such nicely rounded numbers but, as an example, 1000ms / 24 is easier or me to comprehend as 24 ticks per second than 41.6666ms.
- JungleGymSam 14y agoWhy 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?
- petercooper 14y agoYes. It's the calculations and direct pixel setting that's slow, not the actual "rendering" of the canvas (which is accelerated like crazy in most browsers now).
- deleted 14y ago[deleted]
- jQueryIsAwesome 14y agoYep, the hard part is the calculations required for every pixel being displayed. It does get better framerate changing the variables: http://jsfiddle.net/wATAp/ http://jsfiddle.net/wATAp/
- kevingadd 14y agoPart 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/ http://jsfiddle.net/uzMPU/1573/
- voltagex_ 14y agoYes, at least 2x here. I'll pull up Chrome's FPS display later.
- deleted 14y ago[deleted]
- jeffehobbs 14y agoSo cool.
- tgandrews 14y agoCan anyone explain how this works? I never have got to grips with 3D.
- ewolfe 14y agoIt looks like he's using a matrix to create cartesian coordinates in a model-view space and then performing some basic linear algebra on the points to animate it. For a primer on 3D worlds check out http://learningwebgl.com/blog/?page_id=1217 http://learningwebgl.com/blog/?page_id=1217 where they go over it using WebGL.
- deleted 14y ago[deleted]
- tylerdiaz 14y agoLooks like he's ray casting it, no 3D code implemented, just the illusion itself.
- antirez 14y agoWell... 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? :-)
- Jare 14y agoThere is no explicit geometry, polygons, or GPU acceleration, but raycasting in 3D is certainly 3D.
- DanielRibeiro 14y agoUpdate: Thanks for the repliers. You are absolutely right: this is a 3D rendering. What I meant to say is that it is using Canvas 2D, instead of Canvas 3D, also known as WebGl. Antirez gave a wonderful explanation above[1]: 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 [1] http://news.ycombinator.com/item?id=4862910 http://news.ycombinator.com/item?id=4862910
- Empro 14y agoInteresting, and pretty damn cool!
- antirez 14y agoAwesome 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.
- ukjadoon 14y agoIf the creator of Redis approves this, it's definitely awesome! =)
- WA 14y agoI totally agree. You probably meant "code operates at such a _high_ level" :) low level = close to hardware, high level = high abstraction, like JS
- antirez 14y agoNo I really mean low level :-) Javascript is high level, but here notch is using it as a low level framebuffer.
- WA 14y agoAh ok, thanks for clarification
- experiment0 14y ago> And indeed it is pretty impressive how fast the rendering happens given that the code operates at such lower level. Sorry if this is a stupid question, but wouldn't you normally expect low level code, whilst more time consuming to write, be faster or just as fast as higher level code. For example, how C is used as a standard for fast code since it's so low level.
- shawnz 14y agoYes, but when you write in a high-level language like javascript without taking advantage of all of the high-level features like webgl (which are provided by the implementation and assumed to be fast), performance suffers. In this case, Notch is writing code that doesn't necessitate the overhead of using JS. It could easily be rewritten as C and probably run faster that way. Not that it isn't interesting, of course.
- experiment0 14y agoCorrect 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!
- deleted 14y ago[deleted]
- antirez 14y agoYes, 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 14y agoOk, that's pretty cool :P
- petercooper 14y agoI've recorded a video explaining how it works: https://www.youtube.com/watch?v=WaZvDCmlERc https://www.youtube.com/watch?v=WaZvDCmlERc
- barredo 14y agoWondeful
- gameshot911 14y agoThis was incredibly helpful - thank you.
- JungleGymSam 14y agoGreat. Good humor too.
- scottyallen 14y agoThis 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 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/ 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 http://livecoding.io/4191583. Not sure why it's running so much slower though...
- undergroundhero 14y agoThanks 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 14y agoGood 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 14y agoOr if it works at all like Scrubby (http://nornagon.github.com/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.
- dxq 14y agoHow do you suppose event-based models are notified of changes? Ultimately you are still polling, you're just abstracting it out of your higher-level design.
- 14y ago
- gbenitez 14y agoI showed it to my mom, and she was like ":Ooohh mother fucker"
- deleted 14y ago[deleted]
- JoeCortopassi 14y agoSuch 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 14y agoThis 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 14y agoHaving 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_ 14y agoFor those interested, here are the first three hours of the "Prelude of the Chambered" stream. http://www.youtube.com/watch?v=rhN35bGvM8c&t=10m05s&hd=1 http://www.youtube.com/watch?v=rhN35bGvM8c&t=10m05s&...
- kleiba 14y agoThanks so much for this! I watched this back when ludum dare was happening, but after he moved his streaming channel to twitch.tv this part of the stream was lost.
- ricardobeat 14y ago"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 14y agoTo be fair, that's the description notch used in his tweet: https://twitter.com/notch/status/275331530040160256 https://twitter.com/notch/status/275331530040160256 :)
- citricsquid 14y ago"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]"
- Pezmc 14y agoCan someone dissect this code and explain what it does?
- snprbob86 14y agoThe 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 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 14y agoIt 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) ...
- petercooper 14y agoI've recorded a screencast that digs into how the programmatic texture generation works: https://www.youtube.com/watch?v=WaZvDCmlERc https://www.youtube.com/watch?v=WaZvDCmlERc (but I'm not touching the 3D.. yet ;-))
- arriu 14y agoI 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 14y agoCan you explain why?
- codeka 14y agoI assume because there's four different "xd" variables differing only in the number of underscores prefixed ("xd", "_xd", "__xd" and "___xd"). (Same for "yd" and "zd").
- arriu 14y agoI 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 14y agoI think the underscores standout better.
- petercooper 14y agoHere's a rendering of the texture map so you can see what it generates directly: http://jsfiddle.net/cXvKa/ http://jsfiddle.net/cXvKa/
- gavanwoolery 14y agoVery 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 14y agoRuns about 6-7 fps on my iPhone 5.
- gavanwoolery 14y agoNice :) Shows you how fast ARM is progressing...
- hornbaker 14y agoBut only 4-5 fps on my iPad 3. Hmmmph, thought that'd be faster.
- manmal 14y agoMy 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.
- svachalek 14y agoNote also that he's got his canvas set to half the CSS size, i.e. each canvas pixel is 4 screen pixels on a normal display. On a retina display each canvas pixel will be 16 screen pixels. So if you tried to manipulate real pixels this way on those devices it wouldn't be pretty. (Retina version: http://jsfiddle.net/RFLaW/ http://jsfiddle.net/RFLaW/)
- AshleysBrain 14y agoWhile 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 14y agoIt's just a demo. It's for fun.
- zzzzzzzzz 14y agoObligatory flash port: http://wonderfl.net/c/sqL5 http://wonderfl.net/c/sqL5
- marcamillion 14y agoThis 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 14y agoThe 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).
- petercooper 14y agoI've recorded a screencast that digs into how the programmatic texture generation works in this code: https://www.youtube.com/watch?v=WaZvDCmlERc https://www.youtube.com/watch?v=WaZvDCmlERc
- unoti 14y agoEnjoyed that immensely, thank you!
- terhechte 14y agoGreat analysis of whats going on. Thanks.
- chii 14y agogreat work. it'd be also great to do an analysis of the geometry data as well, if you can!
- ozataman 14y agoThanks a lot for taking the time! Any chance you can do one for the game loop and the rest of the code?
- seetherage 14y agowho the heck is Notch?
- josephagoss 14y agoNotch 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 14y agothank you very much!
- citricsquid 14y agohttp://en.wikipedia.org/wiki/Markus_Persson http://en.wikipedia.org/wiki/Markus_Persson http://en.wikipedia.org/wiki/Minecraft http://en.wikipedia.org/wiki/Minecraft http://en.wikipedia.org/wiki/Mojang http://en.wikipedia.org/wiki/Mojang
- pbhjpbhj 14y agoHow is that a bad question. Yes he could have looked it up but it wouldn't have hurt to have "Minecraft creator Notch trying jsFiddle" as the title, would it?
- bitteralmond 14y agoFunny how he writes it so much like Java. I see so many different styles with JavaScript.
- prawn 14y agoInteresting 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 14y agoits 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.
- moconnor 14y agoI'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.
- Flow 14y agoThis 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 14y agoI 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?
- gps408 14y agoWhy is init called twice? Once at the end of the js and then again in the html.
- ghenne 14y agoThe one in the html should not be there.
- phete 14y agohttp://jsfiddle.net/uzMPU/3165/ http://jsfiddle.net/uzMPU/3165/ using window.requestAnimationFrame just because we can!
- Aissen 14y agoWow! This is incredibly smoother here on Firefox 18! (slow machine)
- recurser 14y agoNotch has made a couple of comments on reddit : http://www.reddit.com/r/programming/comments/146v69/how_notch_procedurally_generates_minecraft/c7aelxz http://www.reddit.com/r/programming/comments/146v69/how_notc... 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_notch_procedurally_generates_minecraft/c7aflnm?context=3 http://www.reddit.com/r/programming/comments/146v69/how_notc... 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_notch_procedurally_generates_minecraft/c7afwjp?context=3 http://www.reddit.com/r/programming/comments/146v69/how_notc... 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.
- ghenne 14y agoHere is the code in an App Studio project: http://blog.nsbasic.com/?p=1060 http://blog.nsbasic.com/?p=1060 Runs fine on an iPhone 5!
- HyprMusic 14y agoThere'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.
- malkia 14y agoAlmost straight port here to luajit - http://github.com/malkia/ufo/blob/master/samples/notch.lua http://github.com/malkia/ufo/blob/master/samples/notch.lua
- p01 14y agoTooting 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=0JB66fttJXY#t=143s http://www.youtube.com/watch?feature=player_detailpage&v... ). 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.