Hacker News new | comments | show | ask | jobs | submit login
Simple Minecraft Clone in 580 lines of Python (github.com)
401 points by wting 1187 days ago | past | web | 108 comments

If someone were to make something like this a step-by-step tutorial/template appropriate for a classroom setting it would be huge. Imagine a class at High School where you start off learning the basics of Python for the first few weeks and the rest of the semester is spent writing the chunks of code into a template that has lots of notes for guidance.

I'd image something like :

def setDefaultBlockColor(color): # recall that this is a function that takes in a variable called 'color' as its argument, write the code that will set the current game files configuration file to either 'red', 'blue' or 'green' (p.s. DONT FORGET TO INDENT YOUR CODE!)

Just writing this function and seeing it work once you load up the game is enough to hook almost anyone that has the potential to enjoy programming but just doesn't know it yet.

> If someone were to make something like this a step-by-step tutorial/template appropriate for a classroom setting it would be HUGE.

(emphasis mine :-))

That's the first thing I thought. I teach kids to do creative/interesting things with computers. It's hard to get them writing code[0] (it's not a classroom--they come voluntarily and explore what technology topics they like), one of the older (14) kids started out doing that, however, because he wanted to write Minecraft mods. Those are written in Java, in an Eclipse environment working on a decompiled (and only partially annotated) version of the Minecraft .jar. That was not how I envisioned a gentle introduction to computer-programming :) But he was persistent, and got it to work. This only goes to show what's really important: not if the language is simple, complex, elegant, whether the subject matter is easy to grasp, no. It's just a matter of whether the thing they need to learn is on the path towards a goal they really really want to achieve[1].

But yes, Minecraft is a huge thing among these kids. Others are cobbling together multi-player servers from scrap computers.

While in a sense, brooksbp (sibling comment) is right, there's a LOT going on in these 580 lines of code (I haven't looked at it yet, but I can imagine), 580 lines is not that much either. And if it's something they can run, edit, run, mess around with, see why it broke, edit, run, etc, that's enough to get started. They don't need to understand the whole thing right away. In fact even something as simple (and hardly programming) as changing the colour or textures is awesome because it teaches them that whatever's going on behind those graphics is yours and yours to control (unlike, say, the TV or their aunt's iPhone).

That 14 year-old kid is currently experimenting with Unity, trying to make an actual game. Unfortunately, I haven't had time to get acquainted with that environment myself, so I can only give him general advice. I'm way more comfortable with Python (especially a mere 580 lines of it :P) so who knows.

[0] Which still mystifies me, I was writing my first lines of BASIC at the age of 9, without help from my parents or anyone except library books and magazines. That probably makes me an outlier, but enough children pass through here that I'd expect to see at least maybe one or two. I guess it's different because back then that machine (an Amstrad PCW) wouldn't do anything interesting except word-processing unless I coded it myself.

[1] That was actually a big lesson for me :) I kind of knew it to be the case, but witnessing the process really nailed it down for me.

I've been teaching my oldest kid (14) programming. By far the toughest problem is finding or developing motivation. Kids have too many interesting things pulling at them these days. Programming can be very dull and confusing until you have a good arsenal of tools and patterns in your head. That also works against developing motivation. It's simply not interesting.

Thankfully we do other things. I was able to use the example of when he learned to fly model airplanes to show why he had to push through the stuff that's just not fun to be able to reach for the good stuff. I reminded him of the work we had to do for him to be able to fly and land solo before he could start on fun aerobatics.

This is why I would suggest simply converting something like this to a tutorial might not guarantee engagement. You need to really think through the "fun and interesting" factor both during and after the course. Not easy.

There's an awful LOT happening behind those 580 lines. I'm not sure whether it is a good thing to start at such an unrealistically high level of abstraction for a 3d game.

As something for beginners, this would be great. When you start learning a new skill, it's important to have that feeling of tangible achievement to keep students motivated. Anyone interested enough to pursue a career in game dev will dig into pyglet to understand what's happening, as they start to push the limits of the knowledge gained from this kind of exercise.

And then here's the other nice lesson: students can learn that they don't need to know everything before they start making cool and useful stuff. The confidence that comes from knowing that is just as important (more so?) as being able to implement pyglet from scratch if necessary. The former is a skill used daily, whereas the latter -- well, consider how often in your engineering career you casually rely on the work of others to power your creation. Has anyone ever required you to write a WSGI implementation, or a framework?

That's been my experience, at least.

Totally agree.

I remember writing this:


20 GOTO 10

Seeing actual things happen was awesome. Now we have 3D games, seeing your name over and over wont enthrall, so being able to mod and extend a basic Minecraft world would be an incredible gateway.

The way to hook people is exactly like you say. Make a small change, see a huge difference. Suddenly ... YOU HAVE THE POWER!!!


20 GOTO 10

Wow, that just brought back a massive flash from the past. I actually remembered how I felt then I wrote those lines (or something very similar) for the first time. It's a powerful feeling. Thanks for that.

I remember typing something similar (but probably more seditious) on the computers at every store I came across and watching the staff not know how to turn it off.

Probably a jerk move in retrospect, but how can you work in a computer store and not play around with the computers?!


20 GOTO 10

There was an awful lot happening behind my very first program too. And that was the available level of abstraction. Why start kids coding something so simple when they can mess with something so powerful?

I definitely agree, I graduated with BS in Computer Science but never touched 3D (only 2D game design). Although if I had, I probably would be a lot further than I am now. High expectations, but the results could be amazing.

Don't worry, it is a good thing. The ones who want to take it further will naturally start digging into what's going on behind the scenes.

Where would games be if we didn't have abstraction?

As a country the USA needs much more top down (you can do this now! don't you wanna learn how?) rather than bottom up (learn all this math, all these concepts, all this stuff over here, then do it all again for in college, then gradschool and maybe you'll make more money in 20years) education.

I wrote down the basic steps to get this running on windows at https://github.com/fogleman/Minecraft/wiki

This probably needs floated towards the top a bit. I thought I couldn't get it to work, but then I saw step 6 ...

Actually you should just write it in the project's README.md :)

I used a variant of this code for a project for my students. Just had to clean it up a bit and organize the code into parts they should be reading (game logic) and parts they should ignore unless they're really curious (mostly the OpenGL stuff).

If possible could you post a link to your code? I was going to go through and pep8/document everything but if you've already done that it would be awesome to see.

Please, if you have a link or would agree to send us a copy on request, that would be amazing. I haven't seen the code yet, so I don't know how badly it is needed, but I am definitely going to use this project for teaching programming. And if you already have a cleaned-up version, that would be a great help.

If, for some reason you don't want to link the code here, I put my email in my profile info.

Please put this online, it'll be a very very valuable resource.

Pyglet is vastly more pythonic than pygame for writing games. I have found it much easier to teach pyglet for newcomers and the code is easier to read too. Since it uses ctypes, it is very easy to port pyglet to a platform that supports OpenGL.

Unfortunately there is very little momentum in the project. Last year an alpha version was released after a gap of two years. I truly hope that pyglet gets the popularity it deserves.

PyOpenGL is by far the most pythonic of them all, though this comes at the cost of being around 4x slower than pyglet. Pyglet is a good compromise between the two.

Since they are interoperable, you can write in pyopengl for Punic code, then convert your half dozen opengl calls in your innermost loops into pyglet for performance.

These seemingly "big" games written in a handful of lines of code always make me feel very, very stupid. I know if I made this, I could easily imagine writing 50,000 lines.

How do people do this? How do their minds work?

I'm exactly the opposite. Whenever I see a project consisting of 50,000 lines of code, I am amazed that somebody had the stamina to bite down and actually write all that code.

I could never imagine myself writing 50,000 lines, I'm way too lazy for that. Fifty-thousand lines? You could write a universe in that, with a high-level language like Python (or in assembly, a smallish planet).

Semi-kidding aside, it's part laziness and part DRY-principle. I hate writing code twice, even if it's two chunks with similar functionality. If they are so similar (in an abstract way), there's probably a reason for that, and I try to capture that reason into my code by unraveling the similar parts from the specific parts. That usually makes it smaller.

Can you imagine what happens if those 50K lines (comments/white-space aside) all implement nearly unique functionality? Those 64k demos linked upthread are what happens. I'm going to guess those are 100K-250K lines C++ [1], maybe? But then, a prize-winning 64k probably does a little bit more than a basic partial Minecraft engine :-P

Since you're asking "how do their minds work?", maybe I can get a little bit obsessive over this optimizing (wouldn't call it OCD--that would trivialize the disorder), but I do really get a slight "mind itch" if I notice code with duplicate functionality.

[0] Sometimes it doesn't. But often there's other advantages, too. If that's not the case either (or I'm on a deadline), I grit my teeth and write the duplicate code, but I try to make it really obvious that it is duplicate. That way at least it'll compress well :P

[1] Not even the 4K demos use pure assembly any more, compiler tricks and exe packers have become amazing in the past decade since I stopped making them. Not counting the external procedural/generative design tools/Werkzeuge, btw.

most 50 KLOC projects were not written by one person, but rather by lots and lots of them.

For example the scala compiler + standard library:

find src -name "*.scala" | xargs cat | wc -l = 244,601 git log --format="%an" | sort | uniq | wc -l = 149

Take a look at the code, it's not THAT hard when you have the right tools (language, libraries, knowledge...) though it's quite awesome nonetheless.

IMHO the game actually shows how powerful Python + Pyglet (OpenGL actually) are.

Wanna get your mind blown even harder? Check some 4kb demos[1]... and that's binary size! No JVM/Python runtime supporting it.

[1] http://www.youtube.com/results?search_query=4kb+demo&pag...

If you want to show off the demoscene, try the 64KB prod "Chaos Theory".


If you want to really show off the demoscene, try Farbrausch - fr-041.

It's comparatively very big (179KB), but impressive how they were able to squeeze so much stuff there: video http://www.youtube.com/watch?v=wqu_IpkOYBg, official repository: http://j.mp/11ETcY0.

If you want to dig deeper, Farbrausch published most of their material and tools last year including the source code for fr-041. Search for farbrausch on GitHub. But I must say, it's pretty hardcore.

That is so incredible.

I had to draw the line somewhere. If I could show the WHOLE demoscene...

I still remember how I was blown away when seeing .kkrieger[1][2] for the first time, introducing me to the potential of procedural assets in games.

[1] http://en.wikipedia.org/wiki/.kkrieger [2] http://www.youtube.com/watch?v=2NBG-sKFaB0

Yeah, it's really awesome. Check werkkzeug3, a demotool for procedural asset generation by the .kkrieger team (Farbrausch).

It's in Farbrausch's GitHub with many more demos/demotools https://github.com/farbrausch/fr_public

While demoscene stuff is seriously impressive most are using a shit load of DirectX to do what they do in such a small size. They are not bare metal demos.

Obviously. You can't program the GPU without driver interfaces (DX/OGL).

  (DirectX + 4kb) vs. (OpenGL + Python + Pyglet + 500LOC)
  4kb vs. (Python + Pyglet + 500LOC)
Long are gone the days when you could manage the framebuffer yourself :) Specially if you want to run the demo in modern OSes.

I think its most impressive to actually run the demos themselves. On this site are some good examples: http://awards.scene.org/archive.php?year=2011&cat=9

Edit: It would be intresting to see demos like this (4KB / 64KB) for WebGL. Does something like this exist already ?

Actually this demo lacks any of big or mid-sized features (as in implementation) of Minecraft, such as infinite world, terrain generation, mobs, mechanisms (pistons/redstone).

Most "Doom clones" just showed static maps and lighting too. They aren't really games at this point, the are just demonstrating the techniques to create some aspect of the game, usually a world view like in this project. Within this project you see voxels with textures, rudimentary world building, and interaction with the world controlled by the direction the camera is looking. I think that is sufficient to call it a "Minecraft clone." This still has a ways to go before it can be called a game, but that wouldn't make it less interesting as a teaching aid.

You must be great fun at parties.

That's because its not a game is a proof of concept

It's all about standing on the shoulders of giants.

Well, that's certainly true when we're talking about the underlying 3D graphics libraries, IO, etc. But it seems like there's still a lot more to the rest of it, and that it shouldn't fit in 500 lines of code.

This one really gets me as well:


> it shouldn't fit in 500 lines of code.

Talk to me about "shouldn't" when we start breaking the Shannon-limit or other hard information-theoretical limits :-P

Code size has no relationship to game world size. Interactions are the unit of size for games. If you pay attention to what is going on in this video, it is actually very "small".


Code a lot. Write games a lot.

The code I invent myself is almost always a big mess. When I'm working seriously, I research the answer to the problem.

This produces slower results, better code. The other trade off is I'm not working from direct memory or skill, so co-workers have less respect for me, even if "my" solution is better than theirs.

This makes me functional years ahead of my experience, but belies a true understanding of the concepts. As I methodically catch up with myself over time, this is less true.

When first learning Python, I was amazed at how my code would shrink.

That is, I would write something in the first, most-obvious way that occurred to me. Then, recognizing patterns, I would refactor it down to something smaller. Usually this repeated a few times, until the 100ish lines of code I wrote turned into 10 or 20.

Python gives a programmer a lot of help in reducing redundant code. It makes C#/Java/etc. feel really tedious with all of the boilerplate code you end up writing.

tl;dr: DRY

This is incredibly inspiring for young kids. I am going to study this so I can teach it to my younger brother who loves Minecraft and is trying to learn Python.

I think everyone forgets that Minecraft's big feature is not its graphics or its gameplay, it's the procedural content generation. Almost anyone could learn to do Minecraft-level graphics in a few weeks, and the level of interactions (combat, crafting, moving things) could be reasonably approximated, too. But its procedural content generation algorithm is quite complex. You're not going to make an algorithm quite as nice as Minecraft's without a lot of research, a lot of hard work, and a lot of tweaking time.

Well, to be honest, this point is also where one could beat Minecraft at its own game. The minecraft devs haven't put emphasis on world exploration in a long time, instead preferring more traditional game features (like "the end").

There are many features notch promised when the project first started that where never acted upon, and there's definitely still demand for those.

More than 100 lines of this are textures!

Got this error though. Any ideas?

OSError: dlopen(/System/Library/Frameworks/QuickTime.framework/QuickTime, 6): no suitable image found. Did find: /System/Library/Frameworks/QuickTime.framework/QuickTime: mach-o, but wrong architecture /System/Library/Frameworks/QuickTime.framework/QuickTime: mach-o, but wrong architecture

I got it to work on OSX 10.8!

slunk's suggestion:

`arch -i386 python main.py`

got me halfway there

You also have to run it with python 2.6 like so:

`arch -i386 /usr/bin/python2.6 main.py`

If you only have pyglet for 2.7, you will have to install it for 2.6. Installing packages in python for 2.6 will require pip-2.6 which you get like this:

`sudo easy_install-2.6 pip`


`pip-2.6 install pyglet`


Another option is to use a version of Pyglet from the main repository on googlecode. Thats been updated to avoid the Avbin problems and add OSX 64 bit support.

I needed to run the last command as sudo:

sudo pip-2.6 install pyglet

After that it worked perfectly. Thanks!

That worked great for me, thanks!

I had to use this command:

arch -i386 /System/Library/Frameworks/Python.framework/Resources/Python.app/Contents/MacOS/Python main.py

Someone should update Pyglet... Why does it need QuickTime?

I got a similar error.

"arch -i386 python main.py" solve the problem for me.

I'm running OS X 10.8 and ran into the same problem as the OP. This workaround unfortunately didn't resolve the problem.

try forcing python into 32-bit mode? defaults write com.apple.versioner.python Prefer-32-Bit -bool yes

Try running it using 32 bit Python vs 64 bit Python. It also depends on your OS. Which OS X are you on?

It was built with an old version of pyglet trying to run on 64bit python. Update.

Unless I'm just terribly mistaken, good luck getting pyglet to run on OS X right now. However, I really hope I am wrong, because that means I was just being a fool last week and will soon be using pyglet.

Pyglet is very slow for releases, it's almost always better to build it right out of hg (pip install hg+https://pyglet.googlecode.com/hg/). It's had Cocoa support for something like a year, at least.

Looks like pyglet now runs on OS X: http://www.pyglet.org/news.html

That's sad to hear - I ran in to that last week with pygame (can't run it in a 64 bit environment on OS X).

[rant mode on]

1. 80% of the bang takes 20% of the time

2. Writing games is 99% fine tuning and game play

3. It's just a rendering exercise, certainly not a "clone"

FYI: The above is "the internet" in three lines! :-)

[rant mode off]

To be fair, he did say 'simple'. I'm assuming he meant clone in terms of the overall physical characteristics, and not so much that it was a full clone.

Software has a habit of becoming exponentially complex as the featureset increases, so I am not that impressed by small code if you cut features aggressively.

To prove a point, I wrote a minecraft clone in about 60 lines of code (10x less than the Python version). It cuts a few more corners (no textures, no gravity), but has the basics of world generation, rendering, and most importantly, adding and removing blocks in front of the crosshairs to build (see the little arch I made in the middle):


It's written in Lobster in about 1.5hrs, which is quite similar in features to Python + pyglet. Yes it uses a few high level calls like simplex() and camera_FPS_view(), but these have been part of the Lobster standard library for a while, so I believe that's fair. All code I created for this demo are in that screenshot.

Please...someone put a Udacity course together which backs into the underlying math used to create this (for those of us who didn't have it or don't remember it)...

Nice. Next stop: Dwarf Fortress.

Simple Dwarf Fortress Clone in 58000 lines of Python

Lispers that preach of concision mere mortals cannot possibly dream of, this is your call to arms.

I mess around with roguelike development and have been migrating from python to scheme for brevity.

I started with python. I've had lots of problems with it, but I'm far stronger in python than anything else, so have been in a sense stuck on it despite separate attempts over the last twelve months to get to momentum in C, C++ and racket.

During the recent 7-day roguelike challenge I found myself still stuck on my old python codebase, now creating DSLs in order to define entities and relationship opportunities between them (e.g. water -> planted_seed = sapling). I found I was able to significantly reduce code size, it's cleaner, and it's far sturdier. That was the point where I realised I needed to drop everything and make the jump to scheme, which I've been doing since.

This derailed my 7-day roguelike effort a couple of weeks ago, but it's progress.

OT, but another benefit I've found is that it's trivial to write zero-dependency, multiplatform code in racket. "raco exe main.rkt".

Whereas getting that done with with python is fiddly. With the previous game I released, I spent more time trying to get exes for the major platforms than I did on everything else combined.

I think that would actually be great for an introduction to actor-based modeling. That is, if you think that it's a valid discipline.

SimPy looks interesting, it would definitely be a more "pure" approach than scripting RePast. http://simpy.sourceforge.net/

See I look at this and absolutely amazed. I wish I could make something like this but I have no idea of how to event start.

I tried making a Settlers game in Python/PyGame and so far all I have been able to do is generate the board: https://gist.github.com/sareon/5268205 - I've been told I am not properly discretizing the difference between the drawing of the game and the logic of the game which is going to hinder the development of the game.

I have a BSc and an MSc in CS - focusing on NLP and Machine Learning, so I have an idea how to program, just not how to program games like the Minecraft clone or my own Settlers game. I've tried looking for tutorials and resources online and I've followed the InventWithPython which showed me how to make a simple game similar to how I started making my own. Clearly it was inefficient for a larger game.

What are some good resources out there that can help me learn how to make games such as the Minecraft clone or even how to make my own settlers game actually be a useable game?

This is really freaking cool. I can't believe how short the code is.

Just curious, what is it that makes the performance not so great?

Could performance be significantly improved by doing a re-write in Lua, for example? (Probably not... it's probably something in Pyglet itself...)

(FWIW, it's choppy compared to Minecraft, which is obviously much more complex and has a greater rendering distance.)

It's rather simple: you are proccessing huge grids of 3D data, it's always going to be less then-optimal unless you write parts of it in languages that can do this fast. (This also includes interaction between blocks if you are going to processing a lot of those.)

You also will want to optimize the approach. For example, do you really need to draw each block as a cube? You could draw slabs of identical blocks as a single cuboid. That will complicate the code, but may allow you to run larger worlds faster. Also, you probably want to be smarter in computing which cubes to draw and what parts of them to draw (in a 'no reflections' world, you can see at most three faces of a cube. There is code for drawing fewer faces on lines 177-185, but that is disabled. If you figure out why, you may be able to improve the code). [My guess would be that the display does not look nice enough if you do. Maybe you will get flicker when looking at blocks near edge conditions (no pun intended)?]

Also, keeping angles in degrees means you have to convert to radians on every iteration. It is easy to get rid of that. That will be a tiny, tiny speed up, but if you want to get top speed, you will eventually have to make many of those.

Almost every such improvement in speed will come at the cost of code readability and maintainability.

So far, all the suggestions seem to be for main.py, not Pyglet.

So is this something that can be "fixed" without diving into Pyglet?

That's because I only looked at main.py.

If you want the utmost speed, you get it where you can get it the easiest. I bet the other code also can be sped up.

I would expect that the major improvements would be in main.py, though. That Pyglet library would have to be really bad to screw up what main.py does.

I know that, but I was asking specifically about whether it's mainly a Pyglet issue, or the program itself, or both.

Jump speed is too fast... if you slow it it works better and is more like minecraft IMHO

        elif symbol == key.SPACE:
            if self.dy == 0:
                self.dy = 0.500 # jump speed

This. This is why Python, Pyglet, and this particular project rock.

Not the jump thing. But the whole class of things there is something you don't like and can more or less instantly find it, tweak it and see changes. No hours of learning, searching through code, waiting on compilers. Just experiment -> fun -> back to experiment.

I mean

self.dy = 0.050 # jump speed

Jump higher for more fun...

Hook this code up to redstone (the nodejs server also on the front page) and you'll really have something :) Not to detract from the demo, it's really cool!

Could someone annotate this and re-release it. This seems like an awesome learning tool. A little more info about what everything does would go a long way.

I have been teaching my 10 year old Python as an exercise. Recently I've noticed he's getting a little bored and I'm being very careful not to 'sicken' him, as this needs to be fun. I've just shown him the video for this and downloaded the code to show him that its possible in Python. He loves Minecraft (we watched the documentary movie about Mojang) and seeing this has given him a bit more of an interest again

Maybe you should let your 10 year old be bored.


Ooh, a sample size of one! Sounds compelling!

Not only that, it's not even to do with "boredom" in any sense that I understand the word:

"participants limited TV, computer and video games, music, and telephone time to 30 min per day; in the time made free thereby, they were to read, sit quietly, write in their journals, meet with friends, and so on"

Calling that "boredom", says more about whoever wrote the title "Why Kids Need To Be Bored" than it says about kids' performance and boredom.

Then, the result of this study seems to be: out of 3 participants, 1 showed improvement, the other 2 dropped out. No data on 2 out of 3 test subjects, really, statistically proves nothing at all. It could go either way, or completely different. And it's bad science to not clearly point this out in the abstract. There's no shame in a failed experiment, but there is a lot of shame in pretending that it shows a trend that you didn't actually measure.

I'd be very surprised if research points out that more boring study material leads to improved results. Actually, with N=1 I won't be surprised no matter what.

A fork for those having trouble getting this to run on Mountain Lion.


Thank you!

Can we get a JS answer to this in the browser? I'm curious if Three.js can match this level of terseness.

there already is http://voxeljs.com/

poxel rendering like in the python scribble is trivial, there many much more interesting problems to solve, like managing the geometry. If anyone is truly interested they should begin here: http://0fps.wordpress.com/2012/07/07/meshing-minecraft-part-...

It would have a pretty-much identical amount of code, if someone first ported pyglet!

  building penises out of dirt right now.
I find this comment a bit distracting, and in poor taste. Everybody knows real minecraft users build castles.

  building castles in the sky.

I expect it's at least somewhat referencing this:


I was thinking of writing something like this to help my girls code. Modding minecraft with Java is fun, but the language gets in the way of beginners. This python version is great for that.

This works on PyPy (Pyglet, and therefore this) by the way.

Just grab Pyglet trunk and install it, and run main.py with pypy instead of with CPython.

This is amazing. I've been playing with it all night. From a high level, what would be a strategy for making this multiplayer?

I remember being as excited about Liero as kids are about Minecraft today. Minecraft is great, but so was Liero.

Sigh, right in the nostalgia. Liero was better though, it had fluid simulation. You could flood a level with water and drown people, or better - oil and then set it aflame. And it had guided missiles, which you could spam, making one long queue of keyboard-guided death. It was basically Worms Quake.

If anyone are having problems starting this:

* You need Python2 virtualenv,

* You need to install `pyglet` in it,

* Start it with `bin/python main.py`;

I remember the times when I had time and readed this things until I digested them...

How are the graphics being drawn? Is Pyglet being used to so this?

Pyglet provides native windowing and a full OpenGL wrapper.

Wow! This is so cool!

This proves Python's ability to be RAD.

This is really amazing, nice job.

This is, in a word, dope.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact