Hacker News new | past | comments | ask | show | jobs | submit login
VVVVVV’s source code is now public, 10 year anniversary jam happening now (distractionware.com)
870 points by ciroduran on Jan 10, 2020 | hide | past | favorite | 223 comments



It’s always great to be able to study the source code for successful, released, real games.

I will note that this is actually the source code of the C++ rewrite! The original game was written in Flash, and this version was apparently written by Simon Roth.

My impressions: The source code is a bit of a tangle here. There are magic numbers (https://wiki.c2.com/?MagicNumber) all over the place, plenty of god classes (https://wiki.c2.com/?GodClass), and in general you will have to do a bit too much archaeology to figure out what a particular class or member function is supposed to do (the function and class names don’t give you enough, and there are no comments to help out). There are a few WTFs in here, like the "int i, j, j;" in Script.h.

THAT SAID, This is not really out of the ordinary for successful, released, real games. It’s not really different in style from the Celeste Player code.

https://github.com/NoelFB/Celeste/blob/master/Source/Player/...

But if you’re writing a game of this size or complexity, I recommend doing some refactoring work along the way. In my experience, this will reduce the amount of insanity in the project towards the second half of the development cycle.

But I am always more impressed by ugly code behind a good game than I am by clean code behind an unreleased, unfinished, or unfun game.


> The source code is a bit of a tangle here. There are magic numbers (https://wiki.c2.com/?MagicNumber) all over the place, plenty of god classes (https://wiki.c2.com/?GodClass), and in general you will have to do a bit too much archaeology to figure out what a particular class or member function is supposed to do (the function and class names don’t give you enough, and there are no comments to help out). There are a few WTFs in here, like the "int i, j, j;" in Script.h.\

> This is not really out of the ordinary for successful, released, real games.

Maybe these supposed anti-patterns don't really matter as much as we think they do for successful software? Given that plenty of successful software has them.


The key insight is that most games are released largely once, and then only minor work is done after that. If it's really successful it may get additional ports or content expansions. It does not make sense to pour so much time into making code reusable and clean if it is not going to be built on continuously for long periods of time. Additionally, games do not have to deal with security issues as much; most code is running on trusted data sans networking features. Bad code is 100% counter to security - it's those edge cases where assumptions fail and you lose big time.

As a counterpoint for example, code running on servers should totally be built for the long haul: it's gotta evolve continuously with requirements, it has to cope with edge conditions and especially it has to be secure. You can't get away with the same type of spaghetti in your ACL checking that you can in the code that handles player physics in a platformer.

That does not mean video game devs are bad coders. They are just optimizing for different scenarios.


Where this style applies the most is with hardcoded assets: initializations and runtime behaviors that require an unknown degree of flexibility.

When someone is trained in OOP, the requirement "flexible behavior" triggers a search for answers through polymorphism, but polymorphism is much more structured than a copy-paste-modify code path. It creates limits to scope and requires more explicit names for things. That is the point, of course. You have write more code and do more complex things to get the same level of flexibility, and it'll be harder to debug since the call stack will have to jump around throughout the layers of abstraction. In a "time from idea to production code" latency analysis, OOP structures lose to copy-paste.

And that's why, across the bulk of game codebases I've seen, there tends to be a big jump from hardcoded assets straight into data-driven ECS-style approaches. Small games start with the former, and if they get big enough switch to the latter. The ECS approach still exacts a debugging penalty because more bugs will exist in data, where they're harder to analyze with IDE tooling, but more behaviors are encoded as explicit patterns with limited scope, which is good in a team environment, and it's possible to go data-driven in an incremental rewrite: simply find all the truly redundant stuff, replace it with a parameterized pattern, expose the pattern as data. For the stuff that isn't easily parameterized, consider encoding a small state machine interpreter so that an imperative program definition may occur in data. In the entity system, add some notion of dynamic compositions of state and behavior at initialization. Between those three you can cover just about everything, and you never have to do it 100% to ship: it's there to assist the things that benefit from additional structure, which probably isn't all of the game. (rather, in the AAA environment the data-driven approach can tend to get out of hand - it's a move that allows the designers to avoid needing explicit code support for longer and longer periods of time, with the predictable result of enterprise anti-patterns that abuse scripting in a fashion that is much harder to debug than the hardcoded equivalent.)

This distinction is also basically why you don't see Jon Blow, for example, really get excited about discussing the runtime architecture of his game projects: If the bulk of the game is assets all the way down, there's nothing to talk about, and the only part that concievably could be exciting is some of the core algorithms that drive the interactivity.

It's also why so many gamedevs are apologetic about their code: half of them try to escape this reality by finding a magic mix of abstractions(which eventually blows up and causes rewrites once sufficient complex behavior hits the codebase), the other half run with it and stay in the local optimum of inlined, hardcoded, primitive-heavy functions.


My experience 100% mirrors the code vs data trade off. The games I work on are all data driven from the start, but are also never could have been made hardcoded in the firs tplace.


Game development mostly relies on getting creative stuff implemented fast, not good. And if it works then it works, why spend any more time on it if you can implement even more cool ideas (or release it).

And Minecraft is one of the best examples for a game that is still paying for such a development style.


Ex-gamedev here, slight tweak on "fast", its important that the iteration loop is fast, sometimes that's code and sometimes it's other things.

At the end of the day no one really knows what fun is so the more chances you have the better the opportunity to strike on something "fun".


> And Minecraft is one of the best examples for a game that is still paying for such a development style.

But most games aren't in continuous development to the extent Minecraft is


Game code is usually specifically built to be useful for a very short amount of time, and is frequently the definition of "one and done". Examples against are long lived games like world of warcraft, engines like infinity, unreal, naughty dog etc, which must support extension over time.

A game like VVVVVV is, once a class is created, unlikely to be changed a thousand times. It wouldn't scale if you had 200 people working on it with new people coming in and leaving all the time. But at the end it doesn't really matter much in this case, and isn't the right thing to focus on while coding up a game.

> Maybe these supposed anti-patterns don't really matter as much as we think they do for successful software

They matter a lot for some software more than others. All software is a set of tradeoffs in some ways or another - in this case its attention to things like perfect class naming.


They may not matter as much for this particular scenario. Most of the conclusions I would draw wouldn't extend past independent projects with a small close knit team, or an individual project.

Right now, I'm working on a piece of personal productivity software and trying ideas and patterns that I couldn't get away with in building software with others and to the requirements of other people. I can get away with things that are traditionally anti-patterns because I'm the only one it has to pattern to.

I have to imagine indie game dev is a similar sort of getaway.


This is a classic, but I think it applies here: https://web.archive.org/web/20200108125657/https://www.jwz.o...

Edit, I've been informed that the direct link has a NSFW redirect, so using archive.org instead


I've read that before but on this re-reading it really hit me that he was describing 'go fast and break things' more or less with the so called New Jersey approach.

"It is better to get half of the right thing available so that it spreads like a virus. Once people are hooked on it, take the time to improve it to 90% of the right thing."

This is like Facebook.


Watch out, this gives a NSFW redirect


Is owner of the server playing some tricks, when I tried that URL on Firefox Focus on my phone, it is just the text and I believe what parent wanted to submit, but indeed it looks fishy, I got 403 when tried to see what the redirect was using curl.

What did showed for you?


jwz isn't a fan of this site. Last I checked, if the referer was news.ycombinator.com, it redirected to a testicle in an egg cup.


Some people, when confronted with a problem, think "I know, I'll use a testicle in an egg cup." Now they have two problems.


For anyone who is as curious as me and wants to test it: https://www.jwz.org/doc/worse-is-better.html


This is one reason I love having changed network.http.referer.XOriginPolicy[1] in Firefox. I never send the referer to third party domains, and I've only ever seen one or two sites broken because of this. It's a vast improvement for privacy as well.

[1] https://wiki.mozilla.org/Security/Referrer


Once you go to the link directly, it appears to work fine coming from HN? It seems to work consistently if you visit (from this thread) in a new tab


jwz's entire site checks your Referer header and does this if it comes from HN.


Copy paste it, don't click a jwz link from HN.


> Maybe these supposed anti-patterns don't really matter as much as we think they do for successful software? Given that plenty of successful software has them.

There's more than one variable involved. You can write successful software full of anti-patterns, but you'll probably pay for it in some other way (like increased QA effort or a low bus-factor [1]).

[1] https://en.wikipedia.org/wiki/Bus_factor


The motivations around those kinds of factors are different for games, though.

e.g., bus factor has to be weighted a lot more highly on software that needs to be maintained indefinitely than it does on software that is going to be shipped on a fast-approaching deadline and then (probably) never touched again.

Also, bus factor's importance depends on the size of the team. In the limit case - a 1-developer project like VVVVVV - it's meaningless.


It’s not meaningless when you’re spending exponentially more time debugging random bugs due to lack of architecture (which usually implies you can’t properly test anything, too).


> There's more than one variable involved.

Doesn't 'success' encompass all these variables at the same time?

If you can be successful with a very high QA effort then fine. If QA costs were too high then you wouldn't be making money and you wouldn't be successful.

If you can stay successful with a very low bus-factor then good for you.

And so on with other variables.


This is a game that has gone through a few revisions by different authors. And whilst I doubt any of them were happy with the hand they were dealt it still shipped after their work. So maybe it had increased QA effort over the baseline version that doesn’t exist but it certainly had no bus factor.


Seems more likely they get blindly ported over because nobody can decipher what the hell the code was supposed to do.


its the game that is successful not the software. This game could be written many different ways. Players dont care. Now if there is a particular pain point or glitch in the game and it can be shown that its the style of code that allowed for this to happen. That better organized code would have mitigated this bug then that is important to investigate.

But trying to figure out what a successful game is by its source code is like trying to find what makes a painting good analyzing the chemicals used to make the pigments.


> This is not really out of the ordinary for successful, released, real games

Well said. A lot of people will nitpick and talk big about how they would use proper abstraction and write very clean code, but probably none of those people have ever had a successful indie game out.


To be fair, one of the most vocal advocates of higher code quality is Carmack, who has put out a few games.

What I’ve seen is that it’s hard for someone who’s not released a game before and supported it post-release to know where and how you can sacrifice code quality for a faster development time.


Right, but at the same time what Carmack considers quality code may well be considered low quality by non-game devs because it's too complex, too magical, not documented enough or whatever. Context matters; some code is one game developers beauty; while it's some other developers nightmare.

I'm not a game developer, but I've worked with enough game developers to realize they have a completely different mindset and point of view from mine. It doesn't make them wrong, and it doesn't make me wrong either, it's just that – different points of view, different contexts, different constraints. I have immense respect for game developers.

I'll play Battlefield 1 or Horizon Zero Dawn and marvel that they can get a stable 60 or 30 FPS despite seemingly infinite complexity, all the while I'm struggling to filter a grid with 250 rows in a web browser...

You're absolutely right – no one knows better where to sacrifice quality (whatever that means) for dev time or performance, than game devs.


Carmack is also generally writing foundations and engines that are reused in multiple games. If it's not readable, it's useless.

Most indie devs are trying to crank out a game fast because they have a vision and/or they just want to sell it while the market's hot. Most have no plans on touching the game beyond maybe a couple tiny absolutely essential bugfixes shortly after release. Writing cleaner code is ideal, but that takes planning, foresight, and refactoring. That's loads of time for solo devs or tiny teams to devote which could be otherwise spent making new content entirely.


Yeah but carmack style quality isn't as SOLID as people want to. Game devs have always also factor in performance, that's what other dev communities have lost. Apart from embedded devs.


I would caution people against taking SOLID as a measure of code quality. That’s a trap. SOLID is just a set of object-oriented design principles, not laws. If you take the guidelines too seriously, you will end up with a damaged code base which is difficult to read or understand.

Having spent quite some time in id Software code bases, I will defend them as being high quality, but whether or not they are SOLID is not something I really care about. The SOLID guidelines also regularly conflict with YAGNI.


I fully agree with this.

Guiding principles are a good thing, but the one principle that should top them all is "no dogma".


> To be fair, one of the most vocal advocates of higher code quality is Carmack, who has put out a few games.

I'm working on a port of Doom right now, and have worked with the Quake 2 source code before. I also took a quick look at the Wolfenstein source code yesterday.

It's very clear that Carmack and his colleagues have developed their craft over time. Wolfenstein doesn't seem to have much structure to it at all. Doom is still a mess of global variables and ugly code. But you're starting to see some nice abstractions, like the WAD loading (which made it modder friendly) and the sound module system.

It's been a while since I worked with the Quake 2 code, but I remember it being quite elegant. From what I've heard the Doom 3 source code is excellent.

I think the point is, for your first projects, for small indie-style games, you really shouldn't worry too much. In my experience, it's really hard to learn to use good abstractions effectively unless you've tried to do things the hacky way first, and actually have a solid feeling for what the abstractions try to solve. I still notice this, that I really have trouble getting some projects off the ground if I try to do it the elegant way from the start. Sometimes you spend too much time with an abstraction that turns out to be a bad fit. If I just hack it together, and then refactor it later, it's much easier to get things started.

It's also important to remember that the more people you're collaborating with, the more important it is to have a clean structure.


I think the code bases prove it in their own right...

When I look at how many games Raven was able to churn out with the Quake 3 engine (and most of them were pretty good! Elite Force and Soldier of Fortune are both games that I remember quite fondly).

Carmack saw the value of clean code in providing a quality experience. I'd also wager that was a big part in their ability to iterate on the engine so quickly.

> Wolfenstein doesn't seem to have much structure to it at all. Doom is still a mess of global variables and ugly code.

Part of me asks how much of that was by necessity, and by that I mean whether some of those things were intended as ways to get every last bit of performance out of the code (especially things like globals, and for something as old as wolf3d one starts to also ask about things like segments shudder)


> To be fair, one of the most vocal advocates of higher code quality is Carmack

His code is full of these antipatterns!

One concrete example - magic numbers in Quake.

https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac...

Doesn't seem to cause him any problems in achieving success.


That's a weighed average with, presumably, hand-chosen coefficients to make a nice visual effect. I fail to see how these numbers are "magic." How would you produce this effect without numbers?


> How would you produce this effect without numbers?

That's not what 'magic numbers' means.

The idea is that you factor out the number into named variables so they don't appear unnamed in the body of expressions.


Ok, sure. Even so, this is about the least compelling example of "magic number" that I've seen. They're used once, the intent is clear, and you don't have to go hunting for the definition.


From a pragmatic point of view I would actually expect it to be pretty common for games to sacrifice code quality. You build a game with a set end date, and do a small amount of maintenance on it moving forward. As opposed to an engine where it's a product you're building on and you want to grow over a much larger timeframe, and those unfamiliar with a piece of code are likely to maintain it down the road.


Exactly this! I was a mobile game developer for several years. The technical dept at the end never needs to get paid .


> The original game was written in Flash, and this version was apparently written by Simon Roth

Thanks, I did not know that at all - I know VVVVVV (Linux version) and Roth rang a bell - it's the same guy that wrote (writes? the game has a very long development story) Maia - a space colony simulation/game.


> I will note that this is actually the source code of the C++ rewrite!

"The repo contains two versions – the desktop version, ported to C++ by Simon Roth in 2011, and later updated and maintained by Ethan Lee – and the mobile version, written in Actionscript for Adobe AIR, based on the original v1.0 flash version of the game."


Your impressions pretty much mirrors his own notes about the code, if you read through his actual post.


> There are a few WTFs in here, like the "int i, j, j;" in Script.h.

The blog post does explain this though.


I figured OP was referring specifically to defining j twice, which would definitely have been a WTF, but it seems in the actual source it's i,j,k. So, still weird, but better.

https://github.com/TerryCavanagh/VVVVVV/blob/master/desktop_...


Oh gods.

VVVVVV's core mechanic is that you don't so much "jump" as you just flip gravity, and you only get to do so when your feet are firmly on the floor. This leads to some very interesting designs.

The stage "Veni Vidi Vici (Doing Things The Hard Way)" is possibly the evilest level I've ever completed in a video game. Just a tiny little block, trivial to jump over, but the lack of a jump button means you have to... do things the hard way.

https://www.youtube.com/watch?v=4CtiY5D6HCs


> is possibly the evilest level I've ever completed in a video game

That was the case for me too, until I recently picked up the game Celeste. Some of the C-sides were so evil I just gave up and never beat them (I have a wife and kids, time is limited). This is coming from someone who generally likes hard games (big fan of Dark Souls series, for example, and yes, I know "hard" is relative).

The Celeste Chapter 9 golden strawberry though... that has got to be the most evil collectible I've ever seen included in a mainstream game. I would bet <.01% of Celeste players will ever earn the Chapter 9 golden strawberry.

To put it in perspective - to earn a golden strawberry you must beat the level without dying once. If you die, you are sent all the way back to the beginning. This isn't too hard if the level only takes 10 minutes to beat like Chapter 1. However, Chapter 9 took me over 4 hours to beat and I died over 1,000 times. And not only that, if you manage to beat Chapter 9 without dying, you are transported to a secret extra level (that you've never had a chance to practice). You have one chance to beat the secret extra level without dying - only then does the game award the golden strawberry.

I can't even fathom the amount of time and practice required to accomplish this feat. It must be up there with some of those insane Mario Maker levels.


I got sucked back into Celeste recently; as of last night, the only golden berries left for me are 5B-8B, Farewell, and the dashless winged berry for 1A. (I also haven't gotten the moon berry yet, I kind of forgot about it when I was polishing off the red berries earlier). At the same time, it's easy to believe that this is as far as I'll ever make it; part of what makes going for golden berries so addictive to me is that each new level has seemed pretty much impossible before I start practicing it, so I guess we'll see.

The subreddit r/celestegame tries to keep track of everyone who's gotten the Farewell golden berry; the official list only has about 20 people on them. Of course, you have to record and post your gameplay to be eligible for this list, but there can't be many more people than that who've done it.

But from the other side of things, there's actually a speedrunning category for collecting all 202 berries, including the Farewell berry. TGH just set the world record on Christmas Day, I believe, completing that chapter's golden berry on his first attempt, along with the other hard golden berries. I think this really puts into perspective how skill curves work in games; not only are there very few people who ever approach the top level of skill, but the individuals at the very top are separated by wider skill gaps than you can imagine. This is why matchmaking at the top of a ranked ladder is so hard!


Dashless 1A isn't as hard as you think - just go into options and remap the dash button and then take it one room at a time - you can die as much as you want, you just aren't allowed to dash. Watch a video if you get stuck. I was able to do it in one sitting.


I got it the other day after finishing 5B! I got curious about skipping the keys in 5B, which involved a lot of spike jump tricks (ended up not doing them), and then polished off 1A dashless the same day. I definitely followed along with a video, and I had to restart after a few of the hard rooms after I instinctively dashed to save myself.

I don't think I thought it would be hard, I just wasn't interested in learning precise spike tricks when I started going for golden berries. It was more interesting to see how the easy levels play out when you have to memorize and execute the whole thing at once.


You may be interested in the TAS (Tool assisted speedrun) of Celeste from AGDQ 2018. https://www.youtube.com/watch?v=BEcv7BD1q9o

ADGQ 2020 is currently going on.


AGDQ is very much on my calendar, don’t worry.


I stopped playing celeste when it was no longer fun for me. I made it about half way through the b-sides before throwing in the towel.


That makes two of us. I never did hit that point with VVVVVV: I've played it enough that I can 100% it in under half an hour.


only 4 hours? Im impressed. I took 8h to 12h with 5k deaths!


Oh, it took me over 4 hours (maybe even 5 or 6) but my memory is fuzzy enough that 4 was the lower bound I could confidently say. Same with my death count. 1000 is the lower bound, it could have been 2000-3000 range


What I love about VVVVVV is that there's almost no way to describe it and make it sound fun; if you just watched that video and know nothing about the game it would not seem fun at all; and yet it's one of the most fun video games I have ever played.



Thanks for the link. This is actually pretty neat! Elegant in its own way, gets the job done pretty quickly, and you can change and fine tune the level designs. I like it!


That code is generated by the level editor, IIRC.


It's cool how you can kind of see the level if you squint.


Oh wow that brings back memories! That section took what felt like ages to eventually successfully perform.


400ish attempts for me IIRC. But then I could do it on demand for a while (I’ve since lost the muscle memory of course)


I need to play through this again. So many great memories. It was one of the great early indie games that paved the way for thousands more, alongside World of Goo, Braid and Super Meat Boy.


The first time not dying going up and down in ‘Veni Vidi Vici’, I was so exited, that I landed on the wrong side of the box ...


Veni Vidi Vici is definitively my favorite level in my gaming history. I would play VVVVVV again and again just for it.


Hahaha, despite playing VVVVVV around the time of its release (it's really been 10 years, wow), I realized I could still feel my muscle memory firing up when I saw this level.


I just completed that on switch the other day, took me about 100 deaths. In fairness it's not the first time I played the game, but it's been nearly a decade since the last time.


that was the task where I put VVVVVV down. lol


Terry Cavanagh is one of the greatest game designers of our time. His simple mechanics and designs often remind me of something like Chess or Go, where a simple ruleset covers a massively deep game, or is used to communicate a story in a very minimalist fashion. Don't Look Back is one of my favorites: https://terrycavanaghgames.com/dontlookback/

A few years back, he did a beta of a game called Four Letter Word... Though that's not the real title: http://distractionware.com/blog/2011/11/the-four-letter-word... The real title is a set of cryptic non-alphabet characters.

It was like an Atari 2600 cartridge from a space alien. It featured 2600-style graphics, a hidden hard-as-nails FPS game, and a buncha hidden 2d content that seems simple at first, but was super intriguing. So crazy non-traditional, and with some obscure mechanics, it was one of my favorite things I've ever played, and he never finished it, sadly. I love cryptic games, and I love simple mechanics taken to extreme conclusions. That's why I adore Terry.


Super Hexagon is one of my favorite games ever, as it's extremely simple, extremely hard and extremenly engaging at the same time. Brilliant.


Super Hexagon is a game that when I first played it I could not believe it was possible to complete it, yet a year later I could get >60s in all the levels. An insane grind but somehow immensely satisfying.


An interesting quote from the build instructions: " In particular, the Windows version absolutely positively must be compiled in Debug mode, with /RTC enabled. If you build in Release mode, or have /RTC disabled, the game behaves dramatically different in ways that were never fully documented (bizarre softlocks, out-of-bounds issues that don't show up in tools like Valgrind, stuff like that)."

I wonder if people will spend the time to actually debug this properly now that the source is available.


Considering other quotes, like this one: "For example, maybe my worst programming habit is declaring temporary variables like i, j and k as members of each class, so that I didn’t have to declare them inside functions (which is annoying to do in flash for boring reasons). This led to some nasty and difficult to track down bugs, to say the least." I wish those people the best of luck :)


Cunning way to never have uninitialized variables!


Maybe somebody who wants to extend this game? That would be funny.


I appreciate big successes revealing the jank-ness going on behind the scenes. It helps me fight imposter syndrome knowing that everyone is always learning.


Ethan Lee worked on this! Ethan Lee is an awesome person. Ethan is probably the single biggest contributor to gaming on Linux, and he's always worked in the background. Thanks Ethan, you rock, and deserve more credit.


Maybe I've just been out of the scene too long, but can't let mention of Linux gaming luminaries go without Ryan C. Gordon of Loki Games/icculus.org. For many years, if there was a big project coming to Linux, Ryan Gordon was likely to be the wizard behind it.

His homepage: http://icculus.org/

Wikipedia: https://en.wikipedia.org/wiki/Ryan_C._Gordon

Patreon: https://www.patreon.com/icculus


Ryan is currently working on on a new cross-platform game engine where you write entirely Ruby: https://dragonruby.itch.io/dragonruby-gtk


It's fantastic that he provided a place to host code for game modders / developers as well, I definitely spent years of my life playing http://svn.icculus.org/tremulous/


indeed, Ethan Lee's portfolio is impressive ! http://www.flibitijibibo.com/index.php?page=Portfolio/Ports

I wouldn't have thought linux games were such a small thing, for a single person to have worked on so many of them


That's an impressive collection of Indie games. This looks like the classic example of a consultant gig. You have some specialized knowledge of how to solve a problem that's easy when you know what you're doing. Indie devs can hire you for a day and check off that "Linux support" box so they can show up in a Humble Bundle and make a little more than you spent on the consultant with those 5% or so Linux gamers.

> Dream Daddy: A Dad Dating Simulator

WTF???


Dating Dads is probably the least risqué thing in that genre.


It was a very popular game!


It's a comedy/meme game.


If anyone is looking for a really great game, you should check out Terry's latest, Dicey Dungeons. Incredible variation. Each episode and character has you discovering new strategies and play styles.

30% off on Steam right now: https://store.steampowered.com/app/861540/Dicey_Dungeons/


Hmm, not anymore it seems (the 30% off).


Quite cool, although the license is quite strict:

https://github.com/TerryCavanagh/VVVVVV/blob/master/LICENSE....


Not much more strict than CC-BY-NC, unless I’m missing something? The “you may not represent your fork as my product” is a good abuse prevention that I’m not sure the equivalent CC contains, good call including that.


You may not alter or redistribute this software in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation.

This kind of stuff is generally regarded as non-Open Source.


Terry is no longer calling this open source after someone pointed this out. The title of the original article now reads "VVVVVV’s Source Code Is Now Public".


"Don't make VVVVV 2 with my code" seems to be what they're going for. I don't know if I agree with the sentiment, but it's nice to have this source available, so if this is the price we have to pay...


Why? The source is open to the public?


The term “Open Source” has a precise definition, determined by the Open Source Initiative, who invented the term and started promoting it. Nobody used this term in software contexts before they did. They get to define it.


Not sure why this is downvoted. One of the criteria when the term "open source" was decided on by the people who went to form the OSI was that it must not have (much) documented earlier use in order to become eligible for trademark protection.

It was always meant to be a trademark, even if they ended up losing that particular battle. It was deemed to descriptive and generic to be trademarkable, IIRC. The OSI published their criteria anyway, enforced it as much as they could, and really publicized the term over the years. Of course they get to define it.


it's a "look but don't touch" situation. open-source means giving freedom to the users.

there's nothing wrong with source-available, but source-available and open-source are not equivalent.


The source is being shown to the public.

It's not open for them to use.

To argue otherwise is to confuse a window with a door.


The analogy doesn’t really hold. Is a bathroom door at a grocery store called a “window” rather than a “door” if they prohibit you from bringing unpaid groceries through it?


I have no idea what you're going for here. I feel like Programmer Analogies always rely on the reader agreeing with the author... :|


Not all windows are doors. Don’t worry about it, I’m terrible at analogies that make sense to anyone (including programmers, sadly). And if I clarified I’d just be attacked further for not endorsing the OSI party line when it comes to these things. It’s not you, it’s me, etc.



No kidding. I sincerely doubt this actually qualifies as Open Source. It certainly can’t be distributed by, e.g., Debian.


This probably could go in the Debian nonfree repo


…which is defined as being not distributed by Debian; it is, IIRC, the reason it exists.


It looks similar to e.g. Quake 3's license, source is open but assets aren't.


Not at all, Quake 3's source code is GPL[1]. You can totally sell a game made with Quake 3's source, you just have to redistribute the source as mandated by the GPL. v{6}'s license is more restrictive.

The assets are a different problem. You can use the code without the assets and vice-versa.

[1] https://github.com/id-Software/Quake-III-Arena/blob/master/C...


Oops, I missed that extra clause, thanks.


Prohibiting commercial use would make it non-open. But it's not that surprising given that VVVVVV is still sold today. I'd rather have the source with limits over not having the source at all.


It's such a good game, I highly recommend it. The level design, the music, and the creative names of all the rooms you visit.


You know, people like to crap on Flash (and there are valid reasons to do so), but I really miss how quick you could get a game built with it, while it still felt like "real" programming.

With Flash, I felt like a nice "one-stop-shop" in a lot of ways; you could draw your graphics, animate them, and code them, and you could get a simple game made in an hour or two.

I haven't tried Unity or really any other dedicated game engine, so maybe you get that feeling with those, but I will always be nostalgic for Flash; it really helped make programming "fun" for me.


Flash was great and I haven't found a direct replacement yet (GameMaker Studio 2 is the closest I have found). I pumped out 8 Flash games about a decade ago that generated enough ad revenue to cover all my bills for a few years! I miss how easy it was. Another huge win is how effortless it was to distribute Flash games (they spread like wildfire after I uploaded it to one or two sites).


It's not the loss of Flash per se (as there are plenty of rapid game making tools targetting HTML5 about) it's the complete collapse of the supporting infrastructure.

Mochi Media closing was huge. I went from getting a steady trickle of money for games I wrote to nothing.

As far as I can see there is no Mochi for HTML5 games. Every portal is its own closed environment.


A friend just messaged me telling me that i need to check out Scirra Construct; apparently that gives a very Flash-style interface to build games. I'll have to play with that.


Have you tried Roblox?


I thought Roblox was a game... is it also a game making platform?


Most of the Roblox games are user created. It ships with Roblox studio.

Just remember that the average age of a Roblox player is like 8, so in-depth RPGs or complex sim games probably won't get a lot of traction.


Unfortunately most of Roblox games are just attempts to siphon your money by buying Robux. Their target market, kids around 8, beg their parents for Robux so they can buy some stuff in one person's game.

It's incredible how much money they make through tactics that make many of their games not really enjoyable unless you spend a lot of money in them.


There was an interesting podcast about Roblox in Hanselminutes a few weeks ago: https://hanselminutes.com/709/robloxs-kelly-mayes-on-communi...


There's also one on Software Engineering Daily, quite interesting and it made me consider trying it out just to see what the building tools are like.

https://softwareengineeringdaily.com/2019/12/18/roblox-engin...


You can still do with haxe: https://haxe.org/use-cases/games/

Haxe is somewhat a flash clone. https://github.com/HaxeFoundation/haxe/


Notably, Terry built his most recent game, Dicey Dungeons, using haxe.


Does Haxe have drawing tools too? I thought it was just a programming environment (very possible I'm wrong though).


Haxe is just a language. However, there are several graphical frameworks that allow for that. Dicey Dungeons (his newest game) is specifically built off the OpenFL framework which tries to replicate the Flash API.


I always used the Flash WYSISWYG editor for the canvas and graphics, so OpenFL isn't a replacement at all in that respect.


You can actually create graphics in the Flash WYSIWYG editor and import them into OpenFL. You won't get the exact same workflow, but it's not completely lacking the visual tooling either.


Same here. I remember implememting the game loop using one or two timeline frames.


OpenFL, a library for Haxe that implements the Flash API, includes a mechanism to import graphics drawn with Flash's original tooling.


If you happen to know, how does haxe compare to Godot? Would you say it's simpler to draw and get a very basic game/prototype up and running?


Haxe is more like a traditional programming language, not an "engine" or whatever is the right term for Godot.


I would call Godot/Unity/GameMaker an engine-IDE.

You can have an engine like Love or pygame where the engine is literally just a shared object or dll and you need to basically supply your own tools for level design, programming, etc.

Engine-IDEs are one-stop-shops with nearly everything you could need built in (level editor, code editor, particle effect sandbox, etc.).


Super easy. Haxe's Flixel is probably one of the most full featured and easy to use 2d engines around.


Flash was awesome and it's can't be overstated how much it empowered the indie game community in the aughts.

Seems like people crap on it not because of the tool itself but because Adobe dropped the ball and let it become a crashy, resource-hogging mess, aligning powerful people (like Steve Jobs) against it.


I feel like Google simply didn't like users having such control over extending their browsers' functionality in ways that are harder to track, so they started the anti-flash bandwagon by abusing their browser's market share to kill it along with all other add-ons (a continuation of their death grip on what extensions are allowed and making unapproved extensions not available to the average user either), leaving a vast graveyard of significant, great content unavailable to the average web user. The golden age of web functionality was the period of HTML5 and Flash both being supported at the same time and Firefox having full support for NPAPI and the old extension system including allowing unsigned extensions. Now we're stuck suffocating in sterilized walled gardens almost everywhere we go. Android still lets you install third party apps for now at least but I bet the days of that are numbered too. Sad state of affairs for users all around.


I think Steve Jobs was more responsible for Flash's death than Google. YouTube only stopped serving Flash as the default less than 5 years ago while hubs like Newgrounds were seeing significant declines well before then.

Maybe I'm misremembering, but the golden age of Flash content was certainly over before HTML5 hit in a big way.


People crap on Flash because of the sites made on it. It wasn't for games nor videos.

Adobe had a site building tool that was more productive than ASP, but only barely so, and created sites that would break on about every computer. The few times they were working, they would have completely non-standard UI elements, including buttons and links, and break nearly all interaction modes.


I worked in Flash animation around 2000-2005 and it was always a crashy resource hog.


Would it be ridiculous to write a Flash game then package it with Electron bundled with a Flash Player?

I feel like the issues most people have with Flash are one of two things. It isn't a great choice for rich interfaces (especially things that aren't games) when considering accessibility and different screen sizes. It also presents security vulnerabilities when it was intended to be sandboxed.

By moving it from web browsers to standalone applications, you lose any expectation of sandboxing. When only using it for games, it ceases to have the same accessibility constraints.


Unless I'm missing something that Electron adds to the equation, that's already possible (and common!) via standalone Flash player packages or Adobe AIR. There's a fair number of smaller indie games on Steam distributed that way, for example.


There are many interesting potential outcomes that could emerge from such an idea.

Here is one that would be a tad awkward:

- The concept goes appreciably (if not crazily) viral, people start distributing "SWF-lectron" containers, and much fun is had by all.

- Flash is officially deprecated (incidentally 20 days from now, the 11th of January 2020). It dies; the bitrot process is exponentially accelerated because of the huge installed base yet abrupt and utter lack of updates. Many, many, MANY vulnerabilities are found in the platform. How much impact do they have? Theoretically little to none. But you never know.

- The Electron containers used in this idea probably never get updated. It proves surprisingly easy to just wait for Chrome 0days to float to the top of the pond, scoop them up, and rework them.

Practically speaking I know the above will never really eventuate. But it's what I envisage; more generally, that anything that leverages Flash will fall victim to a very mature ecosystem of hackers (the cracker kind) who've been studying the platform for years, and have a once-in-a-lifetime moment to attack while the platform remains installed.

Flash will have a half-life of years, but it's going to become a VERY big target, I think.

I think.

Maybe I'm wrong/being overdramatic/freaking out/am wearing too many security hats at once/none of the above?


I am not really seeing how any of the hacking discussion relates to a self distributed game, using a packaged version of Flash.

It’s not the browser, so it’d be easier for hacker to just distribute their malware directly than go to the trouble of making malware that hacks an unrelated game, then does something else.


Dude just export to Flash Player. Electron is such a ridiculous resource hog


Pico8 for you, if you're OK with a retro look. Very quick and satisfying. :)


I absolutely love Pico-8, and actually teach that to teenagers at the library on Saturday, and I will agree that it does somewhat satisfy some similar niche as Flash.

That said, Pico-8 is (purposefully) very limited, and if you want to do something a bit more advanced than C64-era gaming, the limitations show. Flash is limited too, but not as much.

It's obscenely fun to play with, definitely agree with you there.


Flash left a huge void in the indie community that has yet to be filled by something. Remember Newgrounds.


Also remember Kongregate (in its early days at least, before every game was a MMORPG clone or tried to sell you something).

Flash was a huge boon for indie games.


Newgrounds is still around, and there are probably some great HTML5 games out there; I don't really play games anymore so I don't go on there much now.

A friend of mine recommended just Scirra Construct if I want something similar to Flash that exports to HTML5.


I think you can do that pretty much with 'defold'[0]

[0] https://defold.com/


This looks really neat; I will have to play with this tonight...thanks!


Flash was my first programming language from way back when I Was 12-13 in a game programming club when I got to high school. It was a fun, creative way to get introduced to programming. Which I have done non-stop ever since, and now do professionally.

It will always be a cherished toolset to me.


There are also great Javascript platforms for all kinds of purposes these days. As a former flash developer (hobbyist level) I do not miss Flash at all.


> There are also great Javascript platforms for all kinds of purposes these days.

Except nothing replace it in a one-stop do it all like Flash was able to do. You open it, you had a timeline that could contains both graphics and code, you could easily reference them on the IDE directly, and then when exported, it was a single binary file that could be shared everywhere and could easily be made quite secure. That meant that there was platforms like Mochimedia that allowed you to import a SWF, that added the ads and it was shared on multiple thousands website for people to play on.

Nowadays you have to use a bunch of different tools, which sure is more flexible in a way but it's a barrier big enough to remove any desire to do a quick prototype for fun. There's software like Unity which is amazing (and a proof that a one-stop software is highly preferred by people), but it's made for bitmap or 3D graphics, which both are made over an other platform and are more complex to handle than vectors that just works great in any context.

That's while considering that everything can be done, which isn't really true because even in term of performance, it took a decade for JS to reach a performance similar to what Flash was able to do at the time. The vector editor was so good that I knew many people that preferred it over Illustrator. I was able to do some nice graphics easily on it, I tried to do the same with Illustrator nowadays and I just can't.

> As a former flash developer (hobbyist level) I do not miss Flash at all.

Lucky you.


I don't really have anything to add... But as a former professional Flash developed, and now nearly 10 years doing game dev (with Unity), I agree 100% with what you said.

It's not really about the language or about the Flash player itself. There was something special about the direct integration of the code and the visual design/animation tool with Flash. Nothing else really comes close these days. Nothing else allows such rapid development.


That's probably fair; I think part of my rose-colored viewing of this is in no small part because I largely don't do any kind of games programming anymore, and as a result am largely ignorant to the newer alternatives to Flash.


I was under the impression that Adobe Animate was a direct successor to Flash the authoring software (but with output options including HTML5 instead of SWF).


And Adobe let it rot.


This is the saddest part. Even with the Flash Player being killed Adobe could have done so much more with the authoring tool. Instead they did little incremental updated and basically let it (and the vibrant community around it) die off.


Did they use a transpiler or something for the mobile version? Lot of magic numbers and odd code like this

    if (t == 0) t = 0;
    if (t == 1) t = 20;
    if (t == 2) t = 14;
    if (t == 3) t = 15;
    if (t == 4) t = 13;
    if (t == 5) t = 16;
or

    case 17:
        blocks[k].prompt = "Press ENTER to activate terminal";
        if(mobilemenus) blocks[k].prompt = "Activate terminal";
        blocks[k].script = "terminal_warp_1";
        setblockcolour(k, "orange");
        trig=0;
        break;
    case 18:
        blocks[k].prompt = "Press ENTER to activate terminal";
        if(mobilemenus) blocks[k].prompt = "Activate terminal";
        blocks[k].script = "terminal_warp_2";
        setblockcolour(k, "orange");
        trig=0;
        break;
    case 19:
        blocks[k].prompt = "Press ENTER to activate terminal";
        if(mobilemenus) blocks[k].prompt = "Activate terminal";
        blocks[k].script = "terminal_lab_1";
        setblockcolour(k, "orange");
        trig=0;
        break;
from https://github.com/TerryCavanagh/VVVVVV/blob/master/mobile_v...


This just looks like typical game dev code to me. You treat the code like a scratchpad, exploring the space and looking for things that work well. Lots of things written once and never touched again, lots of things written with magic numbers because that makes it easier to delete.


Whenever I look at game source code, I start to realize how all of the crazy speedrun glitches exist


Especially on limited platforms of old, where crazy hacks were necessary to get the game to fit in the cartridge/RAM/CPU speed.


It was hand-ported from Flash. I can imagine it being harder to do better than that in ActionScript especially if it was an older version.


The Awesome Games Done Quick speedrunning marathon [0] ran this game this morning. I didn't get a chance to see it, but I wonder if they mentioned anything about its tenth anniversary? Watch for the video here [1] after today's stream is archived.

[0] gamesdonequick.com [1] https://www.reddit.com/r/speedrun/comments/ek9zmz/agdq_vod_t...


This source code release was actually announced at AGDQ on a custom end-game screen once the runner completed it, which is why you're hearing about it now.


Whoops, I missed that. Have to watch it when I get home then!


Terry, the creator of the game, sends a $1k donation before the beginning of the run as well


Here is the direct link to watch (the run is 21 minutes total):

https://www.twitch.tv/videos/533706108?t=05h29m30s


And the exact occasion when the source code release was announced:

https://www.twitch.tv/videos/533706108?t=05h52m06s


Awesome, thank you for posting this! 100% glitchless is what I do myself when I want to have a little fun, but I can't compete with speedrunners, my best time is 28 minutes and change.


I remember getting this game from the first humble bundle and enjoying it, it had very simple gameplay, little to no time to get into and very enjoyable. Going to play it again!


This is a great game, by the way. If you haven't played it, you should.


It's really good. Had a real 80s vibe and nice gameplay.


Yes it is very enjoyable.


I always love when something closed source goes open.

While I never played this game in particular (looks like I've missed something!), I love to study code. It's always interesting to see how other devs tackled a problem or just structured their code.

Thanks a lot!


Indeed. Someone open sourcing their previously closed project will always get my upvote. :)

In this case the code is likely pretty messy. The repo explains that it was ported from a Flash game and a lot of the bad hacks used to make it work in Flash were ported to C++ more or less verbatim.


From the article:

> For example, maybe my worst programming habit is declaring temporary variables like i, j and k as members of each class, so that I didn’t have to declare them inside functions (which is annoying to do in flash for boring reasons). This led to some nasty and difficult to track down bugs, to say the least. In entity collision in particular, several functions will share the same i variable. Infinite loops are possible.


> which is annoying to do in flash for boring reasons

Does anyone know what are these boring reasons? I've used AS2 and AS3 extensively and don't remember this ever being an issue


Same here. The only thing I can think of is variable hoisting, but I don't think that's annoying enough to prefer this other approach.


This isn't open.

Studying this code then making anything too much like it might be a problem.


It's helpful/inspiring to see you don't have to be the greatest programmer to create successful video games.

Just skimming the code a bit reminded me I probably spend way too much time on elegant interfaces, clean implementations, and good naming, in my own games.


Well, I think most games err to the "quick and dirty" side of things. Tracking down intermittent issues in code like this must be horrible, if not impossible. Leading to delayed projects, buggy releases and developer burn out.


Ah yes, fond memories of spending hours trying to navigate my little dude through several screens of Godzilla’s Spiky Asshole.


Oh this is really cool! I've been thinking how interesting this could be to backport to NES or C64. I'm guessing there isn't too much in the game happening that couldn't probably happen on those systems with minor modifications.


I've spent days speedrunning this game. Highly recommend it!

I also suggest "Don't Look Back" from the same developer. It is a short but touching platformer that fills more like a book than a game without even telling a single word.


The PVS-Studio Team couldn't get past the source code of this game: https://www.viva64.com/en/b/0707/


VVVVVV is probably my favorite game of all time. I've gotten so many great hours out of it, it's very relaxing. Thanks Terry for everything and now for releasing the code as well!


Gosh, this brings back sooo many good memories. If you haven't played it yet, you must! It is an excellent game, with superbly simple gameplay and excellent music!


I just replayed this over the holidays! Time for more :)


It says a lot about vvvvv that, I don't like this TYPE of game, lots of jump puzzles. But I like this game! It is just really well done.


I got this confused with VVVV

https://vvvv.org/


This is one of my favorite games and one of my favorite game soundtracks!


i was so hoping this was about vvvv.


This is really great! I wish they wouldn't call it "open source", though. It looks like a source-available license:

https://github.com/TerryCavanagh/VVVVVV/blob/master/LICENSE....

If Terry is reading this, please correct your article. The correct terminology is important! Open source is defined by the OSD, which this license doesn't qualify for:

https://opensource.org/osd

Kudos for releasing your game's source, though!

Edit: I sent Terry an email and he agreed to change it <3 Thank you!

Edit 2: Ethan Lee worked on this! Ethan Lee is an awesome person. Ethan is probably the single biggest contributor to gaming on Linux, and he's always worked in the background. Thanks Ethan, you rock, and deserve more credit.


Thank you for doing this.

Could a mod please change the HN title to match the new article title?


Sure!

p.s. I asked Drew to post another version of his comment praising Ethan, so we could move the replies to that bit to another subthread which isn't so offtopic. He did: https://news.ycombinator.com/item?id=22014064.


> Open source is defined by the OSD, which this license doesn't qualify for

The OSD isn't an arbiter of what is and isn't. Open-source is a flexible term, and insisting that projects must meet definitions A, B, and C is just going to fragment the community and exclude people.


The point of insisting what "open source" means is that we want to ensure the freedoms that open source guarantees. If we don't insist on this definition people will start pushing licenses that forbid commercial use and other things, as this license forbids, and we'll embrace it because we think "ah, open source!"

And yes, when you coin a term, you also get to say what that term means. That's the whole point of coining it:

https://news.ycombinator.com/item?id=22012429


The freedoms are guaranteed by the language of the license itself. That's what licenses are for.


You're arguing about linguistic prescriptivism vs. descriptivism. Is the definition of the term what the coiner says, or is it how it is commonly understood?

A lot of people are going to disagree with you if you claim that prescriptivism is somehow more correct.


It is different for technical terms. It's perfectly fine if I told a novice mathematician, "no, wait, that's wrong, a Riemannian manifold is..."

We have a precise, technical definition of open source precisely so we can judge when a license satisfies the legal freedoms that open source demands.


Perhaps, but "open source" isn't a technical term, and anyway there are lots of vaguely technical terms that have a subtly different layman's definition anyway.

Categorizing certain phrases as "technical terms" to which different rules apply is just another form of linguistic prescriptivism, after all.


"Open source" is very much a technical term with a very precise definition.

Microsoft knew this when they wanted to jump on the bandwagon and named their own license "Shared Source Initiative" (https://en.wikipedia.org/wiki/Shared_Source_Initiative). It wasn't open source, it was "Shared Source", because it didn't comply with the definition of open source.


"Open Source" specifically was coined precisely because there was little or no documented previous use of the term. They wanted something that would mean roughly the same as "Free Software" but possible to protect with a trademark and owned by an industry association. (Not the FSF.)


I'm very curious how many of those insisting on the strict definition also pronounce .gif as GIFF, despite the creator clearly insisting it's JIFF.

Words change. The coiner has no more real authority over them than anyone else.


To be fair I see a fundamental difference between changing a words pronunciation and meaning.


That's true enough.

Related, the definition of gif has actually changed for some. Instead of a specific file format they use the term to mean "soundless looping video". Admittedly even I have a hard time swallowing that definition.


Seems more like calling a JPEG a GIF.


> Open source is defined by the OSD

To be a bit pedantic, your statement is a slightly ambiguous.

They have a good/accurate definition of open source. They don't "define it" in that they can change the definition to mean "and the packaging must be blue" and that becomes part of what open source means.


Yes, OSI is responsible for the OSD, but the term has gotten somewhat "genericised". It's like saying that the Kimberly-Clark company doesn't define what "kleenex" is anymore.

Whenever this debates comes up everyone always says, "wait, the term existed before OSI", but no, it really did not. Essentially nobody was saying "open source" before 1998 when OSI and Tim O'Reilly started pushing "open source".

https://thebaffler.com/salvos/the-meme-hustler

"Open source" wasn't our idea, and the greatest marketing trick that OSI ever did was convince so many of us that it was.


Well, there are references of "Open source" being in use earlier; for example:

https://groups.google.com/forum/#!msg/comp.os.ms-windows.pro...

http://www.xent.com/FoRK-archive/fall96/0269.html

Especially that Caldera one seems pretty high profile.

"Open source" has always been used as a generic term, because it's a very descriptive adjective+noun one. Trying to reserve such terms for one particular narrow usage seems like an fools' errand to me, which is why these discussion are being held all the time.


The Caldera one is always "open source-code", not "open-source code". The words happen to appear together but aren't being used with the same intent.

I didn't know about the NT example. It's a new one to me. But it's also very isolated. I said "essentially nobody" not absolutely "no one". There are a few scattered and rare examples before 1998, but it was not common parlance and most people had never heard about "open source" before Tim O'Reilly bankrolled OSI.


Not kleenex, no, but open source as a term exists in the same way that escalator does. If the OSI was to change their definition, they would be wrong. The definition has transcended them. I honestly have a hard time understanding how people don't agree with that.


OSI got bad legal advice and quickly abandoned the trademark of the term "open source" itself.

https://trademark.trademarkia.com/open-source-75439502.html

Bruce Perens regrets this[1]. But they could have. The term was not generic when they coined it. It really is like "kleenex".

----

[1] private communication


But due to how trademarks work, they would have had to then aggressively protect that trademark with lawyers and stuff and I have a hard time imagining that working out all that well with a lot of us open source software enthusiasts and companies.

Simply put, I think if the name “open source” was a trademark, the open source community would still exist, and businesses would produce open source software as they do today too, but a lot of us would be using some other name for this instead of referring to it as “open source”, so that we’d avoid any potential problems with the trademark of open source.


It wouldn't be such a big deal. As the current situation with VVVVV shows, we already kind of have our own little informal community-driven "trademark enforcement", and it works.


I used escalator specifically because a lot of people don't realize it originated as a trademarked term for the Otis Elevator Company's moving staircase. Kleenex is still well known as a brand name for tissues, even if it is used generically.


I bought this game for 1 dollar (in the first Humble bundle) and I still consider it as of the most fun games ever. Simple controls, catchy music, interesting mechanics (for its time), nice difficulty, without being "unfair". It has everything. If you like platformers and simple games you should check it out.


I'm giving a side-eye to that 'without being "unfair"' comment. I remember a few levels with some real bullshit.


Any difficulty spikes were usually for the optional trinkets, and not required to beat the game.


It's easier to distract people than to give them traction. I think budgeting software would be the best way for a developer to write software which gives traction.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: