Code Monkey home page Code Monkey logo

codecombat's Introduction

CodeCombat

Build Status Coverage Status

CodeCombat is a multiplayer programming game for learning how to code. See the Archmage (coder) developer wiki for a dev setup guide, extensive documentation, and much more to get started hacking!

It's both a startup and a community project, completely open source under the MIT and Creative Commons licenses. Since it's a game (with really cool tech), it's really fun to hack on. Join us in teaching the world to code! Your contribution will go on to show millions of players how cool programming can be.

Whether you're novice or pro, the CodeCombat team is ready to help you implement your ideas. Reach out on our forum, our issue tracker, or our developer chat room on Slack, or see the docs for more on how to contribute.

MIT for the code, and CC-BY for the art and music. Please also sign the CodeCombat contributor license agreement so we can accept your pull requests. It is easy.

Note: the levels on codecombat.com are not open source.

API

We offer a partner API for SSO, user management, progress data, etc., with API docs here and SDKs here. You'll need client credentials, so get in touch with us if you have a use case for that.

For the very simplest case that can power some data integrations with your CodeCombat account, you can fetch https://codecombat.com/db/user/your-user-name-or-id to get some user progress stats. For example, Beeminder uses this API to help you commit to learning to code.

Nick Winter George Saines Scott Erickson Matt Lott Catherine Weresow Maka Gradin Rob Blanckaert Josh Callebaut Michael Schmatz Josh Lee Dan TDM Alex Cotsarelis Alex Crooks Alexandru Caciulescu Andreas Linn Andrew Witcher Axandre Oge Bang Honam Benjamin Stern Brad Dickason Carlos Maia Chloe Fan Dan Ristic Danny Whittaker David Liu David Pendray Deepak1556 Derek Wong Dominik Kundel Glen De Cauwsemaecker Ian Li Jeremy Arns Joachim Brehmer Jose Antonini Katharine Chan Ken Stanley Kevin Holland Laura Watiker Michael Heasell Michael Polyak Mischa Lewis-Norelle Nathan Gosset Oleg Ulyanicky Paul Buser Pavel Konstantynov Popey Gilbert Prabhsimran Baweja Rachel Xiang Rebecca Saines Robert Moreton Ronnie Cheng Ruben Vereecken Russ Fan Shiying Zheng Sébastien Moratinos Thanish Muhammed Tom Steinbrecher Yang Shun Tay Zach Martin

codecombat's People

Contributors

adamkecskes avatar andrewjakubowicz avatar basicer avatar bryukh avatar catsync avatar coco-ci avatar codeluggage avatar darredevil avatar differentmatt avatar dkundel avatar gintau avatar glendc avatar gsaines avatar imperadeiro98 avatar jayantj avatar jmif avatar m-r-a avatar mayakmccoy avatar mohit-codecombat avatar mrfinch avatar nixel2007 avatar nwinter avatar phoenixeliot avatar ryang217 avatar schmatz avatar sderickson avatar shubhi1092 avatar smallst avatar wjllance avatar zerrien avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

codecombat's Issues

Figure out how to do read-only Programmable property access

In the programming.Programmable Component, the player's code runs within a context that is a copy of part of the World, limited to the properties specified in programmableProperties. So for example, if I'm coding chooseAction() for my Artillery, I might have;

programmableProperties = [
  'pos', 'setTarget', 'setAction', 'getNearestEnemy', 'say', 'attackRange'
];

All this code should work:

var enemy = this.getNearestEnemy();
if(this.pos.distance(enemy.pos) < this.attackRange) {
  this.setTarget(enemy);
  this.setAction('attack');
  this.say('Die, ' + enemy.id + '!');
}

So we need the getNearestEnemy, setTarget, setAction, and say methods to actually interact with the World to get the enemy and set the target and action and such. But this code should not work:

this.world.abort();
// Good--doesn't work, because world isn't in context

this.getNearestEnemy().world.abort();
// Oops, that was the real world, wasn't it?

this.getNearestEnemy().health = -9001;
// Yup, you just killed it!

this.pos.z = 100;
// Good--doesn't work because this is just a copy of this.pos

this.getNearestEnemy().getNearestEnemy().pos.z = 100;
// Aaaaa--<splat>

I was trying to get around this with Object.defineProperty and marking things readonly and such, but I ran into some bugs where it wouldn't work. More testing is needed. Also, more thinking, since I'm a bit confused myself as to how best to do this. I originally thought that making a copy-only context, running the code in that, and them pulling the necessary changes out with a whitelist approach would do it, but then I ran into these problems and made the functions refer to the real functions, and now we have neither full security nor full versatility.

Fix /contribute link offsets so we can see the headers

Often we do things like link eager players to specific character classes in the /contribute page, like this: http://codecombat.com/contribute#artisan

When the page loads, though, the scroll doesn't take account the top bar, so we get the character class title cut off:

screenshot 2014-01-01 11 12 38

It should instead scroll like this:

screenshot 2014-01-01 11 16 40

We're already doing something funky with hashes in app/views/kinds/RootView.coffee:

  afterInsert: ->
    # force the browser to scroll to the hash
    # also messes with the browser history, so perhaps come up with a better solution
    super()
    hash = location.hash
    location.hash = ''
    location.hash = hash

    # TODO: automate tabs to put in hashes and navigate to them here

I wonder if this should be fixed on the HTML/CSS side, or if we should just add more code in afterInsert to take the top bar height into account.

Improve visibility of "can cast", "casting", "have cast" states

It's not obvious enough yet when the code is ready to cast, is casting, or has been cast. Beginners don't realize what's going on. Here are what things look like now:

screenshot 2013-12-31 19 22 03

screenshot 2013-12-31 19 22 15

screenshot 2013-12-31 19 21 58

Any improved design might think about improving more than just the cast button, like changing the look of the spell editor itself. And anything involving the cast button might consider a different button design, because this one falls over for i18n:

screenshot 2013-12-31 19 21 12

What I'd imagine we'd do is to come up with a new design for the cast button that gives it more space, more visual prominence, and a much more obvious animation. It would be good if it looked cool, too! See the Tome docs for info on how this stuff works.

Note that the cast button does include this kind of world-casting-progress fill as it's casting. That should either be preserved in any upgraded design or moved to some other area of the interface.

Relevant files

Create and link to other versions views.

Right now we have two basically identical views, one for level versions and one for article versions. Turn them into a superclass that both views use instead. They could also share the same template.

Then use this superclass view to create new versions views for Components, Systems and Thangs.

It would also be good to link directly to these views from the level, article and thang editors.

Permissions modal

Need a way for users to modify permissions of any given document. Something like the share modal in Google Docs, where you can add and remove individuals and set permissions to read, write and owner. This would include:

  1. Creating the modal view logic and basic layout.
  2. Create an endpoint for taking a username string and returning the id of the user. The permissions list needs an id in order to target a specific user, but users will only know the username, so there needs to be a way to go from one to the other.
  3. Set up the modal to use this endpoint, be able to receive a list of permissions and return a modified list of permissions.

Highly recommend using Treema to handle building the interface for editing the list of permissions. It's used throughout the rest of the site, and will handle a lot of the grunt work like adding and removing entries. You would only need to implement a node for editing a single row and tying into the user lookup endpoint.

Improve DialogueAnimator performance

screenshot 2013-12-31 19 35 07

The HUDView uses a DialogueAnimator to animate script dialogue messages in one character at a time while preserving HTML elements. However, it's really inefficient, and when the framerate is low for some reason, it can take a really long time time for the DialogueAnimator to complete (which then makes players wait a long time to go onto the next script on slow computers).

We should make the dialogue animation speed independent of any lag or dropped frames from the rest of the interface being slow, and we should probably profile it to make sure that it isn't contributing to any slowness itself.

@sderickson Did you have any ideas on a better implementation?

Related files:

Improve visibility of guide

screenshot 2014-01-01 10 55 48

screenshot 2014-01-01 10 58 09

In UX testing, in support chats, everywhere--no one sees or thinks to click that Guide button. We've tried saying "Check the Guide" in the default code comments, which helps a little, but players still don't usually notice that, so more is needed. @sderickson 's ideas:

  • Have the guide glow after 5 or 10 minutes of gameplay and no win condition or script triggering
  • Put together a player's guide that we link to prominently from the home page which goes over tips for how to get through a level (like playing multiplayer, or reading the guide carefully, or checking on the forum).

I thought some sort of redesign of the button itself might be in order. Maybe the word "Guide" isn't right. Maybe we need to make the first three levels' scripts need to put the big red arrow on it and tell them to click it for more info, which might at least get players playing through in order into the habit.

Related files:

Add cursors to collection endpoints

Set up endpoints that return multiple documents to take limit values and return cursors so the client can fetch more documents as needed. These cursors could either be directly taken from MongoDB (suboptimal since that takes server resources, but built in and workable) or they could be set up as query modifications passed to the client to be passed back for more information. For example, if the collection is sorted by date, the endpoint might return a timestamp of the last item in the collection, which would be passed back and used for the same query, but only after the given timestamp. The ideal system would be something like Google App Engine's Query Cursors, but for MongoDB queries.

Endpoints that could use cursors include versions, files, and search (which would probably just require the native MongoDB cursor system). These can be found in /server/handlers/Handler.coffee.

Improve layout for mobile

It's probably too early to think about how to make it at all fun / playable / performant on mobile devices (since who wants to type code on mobile?), though any steps in that direction will be good. But we should at least be able to pluck some low-hanging fruit for making the rest of the site a bit responsive so that it doesn't look stupid or break when you pull it up on an phone to see what it is.

So if someone's on top of the latest responsive real-time media query peer-to-peer streaming CSS4 accessible standards-based user-focused design principles and wants to take a crack at improving our layout for mobile, be our guest--we haven't even started, so it's only up from here!

bad_mobile

Let players define new methods in the Tome

Defining inner functions within a method is pretty janky and doesn't work very well with Aether's transpilation assumptions, since we can't yield control or instrument execution well within them. It's also not a good way to organize anything, especially within our little spell editor UI.

It should be possible to just have a "+" button somewhere in the Tome interface that lets players define their own spells (methods), which will then be accessible just like any other spell in the Tome. Not sure where we'd put the button yet, but one obvious choice would be at the bottom of the SpellListView:

screenshot 2014-01-01 14 58 04

Perhaps it then opens up a ModalView asking for the name of the method and which Thang(s) should use it. After the player specifies that, we need to propagate the update across those Programmable Thangs, the Tome, and maybe the LevelSession.

Later we might let players think about saving these methods to their own method library somewhere so they'd be easily accessible in other challenges.

(Originally suggested by @MalcolmMcC)

Make item pick-up and transfer animations

The entire Inventory System is just a temporary hack right now and could use more thought in order to make useful levels that do more with inventory and items. I know Mischa's team will need more power here, so perhaps they can spearhead a new implementation of it.

One of the things we need to do is to make item pickup much cooler. Currently the item just disappears and possibly plays a sound. What it should do instead of just disappearing is to momentarily float above the collector's head, possibly with a cloud or bubble behind it, as it plays the sound, then disappear. This would look pretty good and would allow us to let any sprite collect any other sprite without having any sprite-specific collect or collected animations. Here's a hacky example:

screenshot 2014-01-02 14 19 48

It should feel really cool, like Link picking up a sweet item in Legend of Zelda. Having awesome pickup noises per item will also help with that; those are already ready.

Related to that, I know Mischa's team was thinking of being able to give and receive items between Thangs. It would be good to have this item-in-bubble-over-head animation code also support transferring the item, so maybe it first appears above the donor's head, then moves over to the receiver's head, then disappears.

Making items look better is also related to making them bobbing from #48.

The code for this will start in app/lib/surface/CocoSprite.coffee and could possibly extend to SpriteBoss and perhaps a new class designed for this purpose. Mark and Label might be useful examples.

Get arrows and spears to arc and perspectivize properly

Currently when an Archer or Arrow Tower shoots an Arrow, the Arrow does properly rotate in the x-y plane so that it's facing its target, but it doesn't handle the other ones (yaw? pitch? roll?). So it doesn't point up when its z-velocity is positive, nor down when it's negative. It also doesn't appear shorter when flying more parallel to the camera's line of sight than it does when flying orthogonally.

screenshot 2014-01-02 12 11 52
screenshot 2014-01-02 12 13 06

I think one would just need to do some math to update the Arrow Thang's CocoSprite imageObject transform properties or their shorthands (scaleX, skewY, rotation, etc.) according to the velocity of the Arrow and the Camera's view. I was trying to do it but got confused. If you like affine transforms or computer graphics, you might have some fun with this one!

It's easy to test: just play Zone of Danger and get the arrows looking good. You might want to make the arrows travel a lot slower by editing their maxSpeed in their movement.Moves Component, which would emphasize their arcs. One of the reasons arrows travel so fast now is that they don't look good when actually needing to arc.

The code to write may be in or related to app/lib/surface/CocoSprite.coffee in the updateScale and updateRotation methods.

Improve visibility of currently-executing-line indicator

Aether can (in some levels) highlight the currently executing line, as well as indicating which lines have been executed already:

screenshot 2013-12-31 19 43 39

See the black gutter arrow and light blue highlight on line five, and the lighter blue highlight on line three? Really? You're the only one.

In our UX testing, players almost never see this even when it would be really helpful, so it's clearly not obvious enough. Also, I just made up the design as a placeholder, but I didn't make it ugly enough to warrant immediate redesign, so no one has come along to do a better job. If you have an idea for a design that meets these objectives, then let's hear it:

  1. It should be totally obvious which line is currently executing.
  2. It should be clear that that's what the indicator is trying to indicate.
  3. We should be able to indicate which statements have already executed (not just lines, since we can be more specific than that).
  4. It looks cool. (Wizardly magic animation?!)

Currently, we're using dynamic marker ranges in ACE to add "executing" or "executed" classes to spans of text (stacking up to three of the "executed" markers to indicate multiple executions), as well as adding the "executing" class to the gutter cell for the current line:

screenshot 2013-12-31 19 51 29

screenshot 2013-12-31 19 49 46

We could get more complicated if this CSS doesn't cut it, but if you have an idea that can be done just by tweaking the effects of those classes, then it'll be easy to try out by tweaking app/styles/play/level/tome/spell.sass

Otherwise, check out how the ranges are done in app/views/play/level/tome/spell_view.coffee:highlightCurrentLine.

Improve i18n fallback for non-i18next usages

We use i18next for internationalization, which correctly handles language fallbacks like es-ES -> es -> en when we use it in a CocoView's render method by calling @$el.i18n().

However, when we use code to grab our localization strings in other ways, like for doing script dialogue in SpriteScriptModule, we don't have any of that fallback implemented and in fact use quite lame code:

    for response in responses ? []
      response.text = response.i18n?[me.lang()]?.text ? response.text
    text = sprite.say.i18n?[me.lang()]?.text or sprite.say.text
    blurb = sprite.say.i18n?[me.lang()]?.blurb or sprite.say.blurb
    sound = sprite.say.sound?[me.lang()]?.sound or sprite.say.sound

Not only do we not get the default Spanish ("es") translation if we looked for the Spain Spanish ("es-ES") translation, but we're repeating all that code each time. Also, this behaves differently than i18next in that it doesn't look for an "en" string, either, instead just using the string set in the base script message. This probably doesn't matter, but it's different from how the Views do, where they fallback to whatever is hardcoded in the template only if the "en" string doesn't exist, either.

This is how the strings are put into the scripts, inside the level editor:

screenshot 2014-01-01 11 43 08

This produces the following object:

{
    "text": "G'day, Wizard! Come to practice? Well, let's get started...",
    "i18n": {
        "es-419": {
            "text": "¡Buenas, Hechicero! ¿Vienes a practicar? Bueno, empecemos..."
        },
        "es-ES": {
            "text": "¡Buenas Mago! ¿Vienes a practicar? Bien, empecemos..."
        },
        "fr": {
            "text": "S'lut, Magicien! Venu pratiquer? Ok, bien débutons..."
        },
        "pt-BR": {
            "text": "Bom dia, feiticeiro! Veio praticar? Então vamos começar..."
        },
        "de": {
            "text": "'N Tach auch, Zauberer! Kommst Du zum Üben? Dann lass uns anfangen..."
        },
        "tr": {
            "text": "İyi günler, Büyücü! Antremana mı geldin? Güzel, hadi başlayalım..."
        },
        "sv": {
            "text": "Godagens, trollkarl! Kommit för att öva? Nå, låt oss börja..."
        }
    },
    "sound": {
        "mp3": "db/level/52740644904ac0411700067c/gday_wizard_come_to_practice.mp3",
        "ogg": "db/level/52740644904ac0411700067c/gday_wizard_come_to_practice.ogg"
    }
}

Perhaps we should add a utility function somewhere to grab the best string possible for a given property from any given i18n object and start using that throughout the code.

Install Backbone plugin to support subdocuments

Currently to save subdocuments, one needs to do something like:

state = @session.get('state')
state.scripts = {}
state.complete = false
@session.set('state', state)

We could use a plugin that would make it possible to trim lines like that to:

session.set('state.scripts', {})

LevelBus.coffee would be the prime class to benefit from this. Make sure that the patching still works.

Some candidates for plugins are in the Backbone Wiki.

Refactor schemas to be in /app instead of /server

Currently schemas are stored only on the server and fetched separately as needed by the client (see /app/models/CocoModel.coffee for how the schema is fetched, and the /server/db.coffee and /server/schemas/* files for how they are served). Instead, have the schemas in the client and then accessed by the server from the client code. So a general outline of steps are:

  1. Copy the '/server/schemas' folder to the /app folder, make sure the client and server can access them.
  2. Have all the client model classes import and reference the schemas directly rather than as a BackboneModel (so Level.schema refers to the schema object rather than a Backbone Model that contains the fetched schema).
  3. Fix any parts of the site that access the schemas (for example, /app/views/editor/article/edit.coffee accesses Article.schema.attributes, but should instead after this simply reference Article.schema). Test by making sure the Thang, Level and Article editors still work, and the User creation and login forms still work.
  4. Switch /server/db.coffee to serve these schemas from the new /app/schemas folder instead of /server/schemas. The site itself should no longer need these endpoints since they'll be embedded in app.js, but it's good to still be able to access them for development and have these schemas available directly via a URL.
  5. Delete /server/schemas, now that it's in /app/schemas and should no longer be used.

This is a good task for learning the ins and outs of how JSON-schemas are tied into the rest of the site.

Have search views use projections

Currently views for listing thangs, levels and articles download the complete models, and with enough of them the request can get quite big. Set up the search handler in /server/handlers/Handler.coffee to return only those properties used in the SearchView and its subclasses.

Make items bob

Items, like health potions and swords and such, are currently kind of boring: they just sit on the ground. Lame. What instead they should do is what the Coins and Gems do: bob up and down in the air. But it'd be best to not have to embed a bobbing animation in each ThangType we intend to use with the inventory.Collectable Component.

screenshot 2014-01-02 13 58 42

Instead we should do something like what the WizardSprite does and make the bobbing happen automatically in the updatePosition method of any CocoSprite with thang.isCollectable == true.

screenshot 2014-01-02 13 59 56

Once that started working, we could remove the built-in bobbing animation from Coin and Gem, too.

After that's working, we'd probably want to not tie bobbing to the inventory.Collectable Component, but instead to make a new Component: display.Bobs or something like that. That would be nice, because then we could attach it to any flying Thangs, and we could remove the special-case code from the WizardSprite, too. All that display.Bobs would need to do is attach a bobs or maybe bobsUpAndDown property to the Thang, and the CocoSprite would read that instead of isCollectable. If we really wanted, we could configure the bob distance in that Component.

Refactor FoundationView and FoundationClass into CocoView and CocoClass

Originally was thinking of having non-CodeCombat specific stuff in FoundationView/Class classes but it's probably too early to do that sort of division. Refactor FoundationClass to CocoClass and combine FoundationView with CocoView. The Foundation classes are in /app/fond, and CocoView is in /app/views/kinds.

Improve spell editor performance

I keep getting bug reports like this: "During casting, sometimes everything got extremely slow and it became almost impossible to type. It made me worry I was going to lose my work, since it's hard to even select the code when it's stuck like this."

I never see it, but maybe my computer is too fast? I don't know. I can probably fix it anyway, although if anyone who does see these kinds of problems wanted to dig into it with the Chrome profiler or something, that'd be awesome.

One thought: move Aether's linting and parsing and such into a web worker? We're going to all this trouble to avoid blocking the main thread by linting and parsing and transpiling too often, but we could do it more often and not have performance problems if we did it in the background instead.

Force \n and spaces, not tabs, in spell editor

When people send me their multiplayer links for code submissions, I often see one of two problems. Either JSHint is warning me about mixed spaces and tabs, or I only see the first line of code. Example:

// Fill the empty space with the minimum number of rectangles.

screenshot 2014-01-01 12 01 01

Whereas the other player sees it just fine. If I look at the session, it contains all the code with "\r\n" in there:

{
  "code": {
    "thoktar": {
      "plan": "// Fill the empty space with the minimum number of rectangles.\r\n// (Rectangles should not overlap each other or walls.)\r\n// The grid size is 1 meter, but the smallest wall/floor tile is 4 meters.\r\n// If you can do better than one rectangle for every tile, let us know!\r\n// We'll help you find a programming job (if you want one).\r\n// Check the guide for more info, and press Contact below to report success.\r\n// Just include your multiplayer link in the contact email.\r\n// Make sure to sign up on the home page to save your code.\r\n\r\nvar grid = this.getNavGrid().grid;\r\nvar tileSize = 4;\r\nvar width = 0;\r\n\r\nfor (var y = 0; y + tileSize < grid.length; y += tileSize) {\r\n    for (var x = 0; x + tileSize < grid[0].length; x += tileSize) {\r\n        var occupied = grid[y][x].length > 0;\r\n        if (!occupied) {\r\n            width += tileSize;\r\n        }   ......."
    }
  }
}

ACE probably has some way of sanitizing things so that you can only have \n for newlines and spaces, not tabs, so I would start looking at the ACE docs. Otherwise, we'll probably want to do some sanitization in the spell editor, which might be a bit tricky if Firepad is enabled.

Try playing sounds backwards when scrubbing backwards through time

I don't know if this is even possible in the browser, but wouldn't it be cool if we could transform the audio on-the-fly (or maybe once for each sound when loaded) so that in app/lib/Surface:playScrubbedSounds, we can play reversed versions of the sounds? Or even fast-forwarded versions depending on the playback speed?

If anyone knows of a cool way to do this kind of audio processing on the fly performantly, it should be a ton of fun.

Guide general articles stopped showing up

Specific articles are still there (even with tabs when multiple), but general articles aren't. Haven't dug in; wonder if this has something to do with any recent changes to supermodel fetching of Article models?

screenshot 2014-01-01 11 10 01

screenshot 2014-01-01 11 09 25

Add page(s) to highlight contributors

We didn't have a good place to acknowledge contributors, so I started putting them in the /contribute sidebar for now. It quickly started getting long, looking terrible, and scrolling into the footer:

screenshot 2014-01-01 11 19 28

In an ideal world, we either make a new /contributors page and start listing everyone there, or we make a new page per class (like /contribute/archmage) to hold them all. Eventually we'll have more than just a name and a few words of text per contributor, too.

To create the new page(s), we'd add a /contribute directory to each of app/templates, app/styles, and app/views, then start putting .jade, .sass, and .coffee files in there per page.

An interim improvement would be to fix the style on that sidebar to not scroll off into the footer, and possibly to look less horrible. @TomSteinbrecher expressed interest in that.

Related files:

Add spell casting sound effects

This could be done in a few different ways.

  1. We could either hook up cast_begin, cast, and cast_end WizardSprite action sounds, so that they're tied to the visual animations that we already trigger when players are typing.
  2. We could add Interface sounds that get triggered through the CastButtonView, hooked up to the transitions between "can cast", "casting", and "has cast".

I have no idea how many sounds we need or what they might sound like, but by gosh, it's magic! It should sound like something! It would probably also help the UX to subtly indicate what's going on. Hopefully the sounds wouldn't become annoying.

Thoughts on what sounds we might use are welcome, or even code to add in the sounds. If you find some good sounds, I can put them in the WizardSprite actions, or maybe @sderickson can explain how to add them as interface sounds to our MongoDB. (Non-admins might not have permission to add them directly.)

Improve pathfinding AI

There is at least one bug sometimes causing Thangs to think they can't get to places that they can get to, leading them to run straight at their target (since they gave up on actually pathfinding).

There's at least one other bug causing Thangs to not take wide enough corners around structural nav mesh vertices that ends up in them bouncing off of corners a few times, especially if their radius isn't an even multiple of one meter. Try looking at Taunt the Guards, where the archer is following Tharin, and setting her width/height down to 1.5m or less instead of 2m. She'll bounce off corners like crazy.

Part of this is because the grid/pathfinding resolution isn't high enough, i.e., 2.5m ogres are treated as 1.25m radius which gets rounded up to 2m which, with a 1m radius grid and 4m hallways, means the grid thinks they cannot pass.

Those are the only two bugs I know about, but probably there are others resulting from how the nav meshes are generated or how the A* vertices are picked.

In addition to fixing the bugs, it would be awesome to improve performance (should be really easy to do if you look at the code and perhaps cache rectangles' vertices) and to clean it up (the way rectangle vertex associations is currently done is just nasty).

If one were extraordinarily ambitious, one could extend the nav mesh and pathfinding to operate an convex polygons, not just rectangles.

To get an idea of where this code is coming from, just look at the ai.Pathfinds Component and the AI System (from within the level editor) and follow any imports to things like app/lib/world/Grid.coffee and app/lib/world/world_utils.coffee.

This touches upon the code that everyone trounced me with in Gridmancer, too, for generating the nav meshes.

Here are some links I found helpful when implementing this:

Fun fact: I was on an epic coding binge implementing all this stuff in the middle of the week: http://www.youtube.com/watch?v=E0qlr22cF14

Add folder system to files

Read more about our DB Filesystem for more info.

A folder system would involve:

  1. Being able to query what subfolders are in a given folder
  2. Folder permissions

One implementation would be to create another collection of permission'd documents that are the folders, one document for each folder. Some key elements would include:

  1. When a new document of one type or another is created, the system automatically creates a folder for that document that the user can control. So if they make a new level, the system creates an empty folder in /db/level for that level which that user has ownership of.
  2. When creating new folders that are many layers deep, the system has to add any parent folders that are missing, and the first folder it finds that does exist gives write permissions to that user.
  3. Adding an endpoint for getting all subfolders in a given folder.

See the existing models in /server for how to create collections and give them the permissions plugin. There are probably also perfectly serviceable folder systems that can hook into GridFS, so that could be researched.

Have versions pages load only required data

Right now, versions pages for versioned documents load the full documents. Particularly large version pages like the one for the Rescue Mission level fail to load because it's trying to load a huge number of large documents.

Have the system instead download just the parts of the documents required: the version object, the commit message, the name and the id. The function which serves versions for all documents is in /server/handlers/Handler.coffee:versions.

  1. Edit this handler to return just those properties needed.
  2. Make sure all versions pages work with this new system (search for versions.coffee files in /app)

Build client testing framework

We need client testing framework that is more thoroughly integrated with the /app code itself. Here's the gist of the plan:

  1. Create a /test/* view which takes the rest of the path and looks up the /app module in that path and runs those tests with the standard Jasmine test runner. /test simply runs all tests in /app (all modules that end with .spec).
  2. Set up brunch to include these spec files in app.js for development builds, but not for production builds.
  3. Add .spec files with Jasmine tests to /app itself, often paired with the class or module it tests (so there would be Camera.spec.coffee right next to Camera.coffee). Some existing tests can be grabbed from /test.
  4. Build common systems for replacing various resource grabbing systems with Jasmine spies, such as Backbone, PreloadJS and Firebase.
  5. Integrate with the Developer Tools Window, if available (so for any instance of a class, click a button to open a test window for its class).

These steps are in increasing importance. Just doing the first one so tests can be written for and viewed with the development server will go a long way toward covering the app with unit tests and better descriptions of how things work.

Improve usability of CoordinateDisplay

screenshot 2014-01-01 10 32 02

Sometimes you want to grab some (x, y) coordinates, so we built this stopgap app/lib/surface/CoordinateDisplay.coffee for displaying them on cursor hover after a slight delay. It's pretty bad, though:

  1. It's not visible enough--players often miss it even when looking for it, and it's hard to see even when you know it's there.
  2. It's so ugly, and usually not used, that you wouldn't want to just make it much bigger or something.
  3. You have to leave your cursor hovered over the map while you type the coordinates into the spell editor, and you're out of luck if you ever click anything (since units will deselect or the map will pan).

@chloester suggested having a waving flag where you click down and every time you click to a different place, it keeps the coordinate, with a background bubble/pin. @sderickson was thinking that it'd be a button you'd press to activate the tool, and then the next point you clicked would get inserted into the editor. I tried out adding a grid, so you could just read coordinates by following the major tick lines, and that's in, but the initial grid design sucked:

screenshot 2014-01-01 10 45 27

It needs the numbers to go onto the Screen Layer but the grid lines to either stay on the Surface Layer or to also be on the Screen Layer but change whenever the viewport changes. More on Layers here. Maybe if we improve the CoordinateDisplay enough, we can just get rid of the grid?

Tag more i18n strings in our templates

This one doesn't take much programming knowledge, just time. I went through most of the highest-use templates and added data-i18n attributes so that we could get a first round of localizations done, but I skipped some areas, and a few things have been changed and need new tags. We need to go through the rest of the templates and add the rest of the tags.

Here's an example tag:

h1#site-slogan(data-i18n="home.slogan") Learn to Code JavaScript by Playing a Game

This then can be translated into various languages in our locale data for, say, Latin American Spanish (es-419):

translation =
  home:
    slogan: "Aprende a programar en JavaScript jugando"
    no_ie: "¡Lo sentimos! CodeCombat no funciona en Internet Explorer 9 o versiones anteriores."
  # ...

After which someone can change their language to Spanish and see:

screenshot 2014-01-01 15 49 08

instead of:

screenshot 2014-01-01 15 48 46

(We also detect the user's Accept-Language headers to guess their preferred language on first visit instead of always defaulting to English.)

The data-i18n attrbiute

Let's take our example:

h1#site-slogan(data-i18n="home.slogan") Learn to Code JavaScript by Playing a Game

This is a Jade template, so it's just a more concise way to write this HTML:

<h1 id="site-slogan" data-i18n="home.slogan">Learn to Code JavaScript by Playing a Game</h1>

All we need to do is to find elements with text that don't have these data-i18n tags and add them. I know there are a lot in the /contribute, /legal, /about, /teachers, and /editor pages. If you want to find more, you can just set your language to Brazilian Portuguese or any other language where we have full coverage and look for things that still show up in English.

Sometimes you need to tag a link separately from surrounding text, like in this example:

span(data-i18n="contact.forum_prefix") For anything public, please try 
a(href="http://discourse.codecombat.com/", data-i18n="contact.forum_page") our forum
span(data-i18n="contact.forum_suffix")  instead.

I've been adding prefix and suffix tags like that so that the links can be internationalized separately. Note the trailing space in the prefix and the leading space in the suffix: if those weren't there, Jade wouldn't put spaces in between the non-linked text and the link. This is an unsatisfactory approach, because no one who is translating these strings sees those extra bits of whitespace. A better way to do this, where Diplomats don't have to care about whitespace, would be useful.

The translations themselves are currently going in app/locale, but hopefully we can just move those to the database soon by doing #22.

Improve paths appearance and performance

The past/future paths are useful sometimes, but overwhelming or unintuitive at other times, and often are terribly slow. See more info on paths in the wiki.

screenshot 2013-12-31 17 46 56

The code is all in app/lib/surface/path.coffee It'd be nice to:

  1. Come up with an appearance for the paths that makes more sense, like perhaps footprints fading in and out to show the travel.
  2. Figure out how we can show the selected Thang's actions less confusingly than having slightly larger, slow-motion, faded copies of them at the places where the actions change. (Players think they're bugs / ghosts.)
  3. Be fast. Paths are currently the slowest part of the Surface, because they're recalculated and redrawn every frame and there are tons of little shapes. Perhaps we could use sprite animations here, too?

One could propose a better design, or just start playing with the code. Any improvements are welcome.

Improve versioning stability

Read up on Versioning for more info.

Right now if something goes wrong in the middle of switching versions, the system can be left in an unresolved state. If the existing versions are successfully updated but the new version is not successfully saved:

  1. Search will not work for that document family. Only the latest versions of a given document are indexed in the text search, and if nothing is in the system marked as the latest version, it's not indexed.
  2. Slugs will not work for the document family. Only the latest versions of a given document have their slug property set, so urls to that document will no longer work.

MongoDB does not support transactions natively, so that's not an option.

Possible solutions include:

  1. Implement two-phase commits. This would be very complicated, and would require some sort of independent system to keep on the look out for unfinished transactions to finish them.
  2. Instead of first updating the old document and creating a new document, change the existing document and then create a copy of the old document. This way the change happens first, and if anything is lost it's one previous commit (it is not vital that the database versioning system be airtight, it's much more important that slugs and searches always work).

Bear in mind that any solution must deal with the fact that there are MongoDB unique indexes in place that prevent there being more than one document with the same slug and more than one document with the same minor and major versions.

All of this is contained in the /server/models/plugins.coffee file, where it shows how versions are fetched and created and how indexes work and how named and searchable models work. There are fairly extensive tests on the plugins.spec.coffee file as well.

Add i18n to modal titles

See #23 for more info on i18n tags. Basically, there's no code for internationalizing ModalView titles, which are sometimes dynamic, but are usually specified as the modalTitle property of ModalView instead of being in the Jade template where we can statically add data-i18n attributes. We'll need to add that.

screenshot 2014-01-01 17 06 54

Try adding WebRTC-based voice/video chat

Firefox, Chrome, and Opera can use the new WebRTC protocol to do peer-to-peer voice and video chat, which might be really cool for multiplayer (or might prove not as versatile as text chat, which we have right now). Given how many frameworks there are that make it easy to try out, it's probably worth an experiment! Here's a semi-recent list I found. @sderickson also saw interesting presentations by XIRSYS and OpenClove a few months ago.

This is, of course, an enhancement for CodeCombat's multiplayer. I'm thinking that even if it doesn't make sense to use the video chat, it could be fun to add voice chat so that players can play together more like a game. We'll just have to try it out and see if it's fun.

Stop ThangListView selection after level-lock-select events

Some Scripts trigger a Backbone Mediator "level-lock-select" event, which is currently only subscribed by the SpriteBoss and prevents you from clicking on CocoSprites to select them, or from deselecting anything if you have already selected something. This is done so that we can make sure players don't start/stop looking at the spell editor when we're trying to explain something with a script.

I don't have a good test case for right now, but basically there should be code in all other places where we publish "level-select-sprite" through the Mediator to first subscribe to the "level-lock-select" event and to not issue the selection event if select is locked. ThangListEntryView is one such place:

screenshot 2013-12-31 20 28 45

One shouldn't be able to click that Arrow Tower or a spell in its spell list to select it if select is locked. Likewise, if one has the spell editor open, one shouldn't be able to change which Spell or Thang is selected through the SpellListView.

Time-travel debugging interface

The biggest problem when trying to do harder levels in CodeCombat is that players have only one way of debugging their code:

this.say("Rect is at " + rect.x + ", " + rect.y + " with size " + rect.width + " x " rect.height");

It took me 30 seconds just to type that out, and I made a syntax error. This is not okay. As a Hacker News commenter put it:

"Only the very darkest realm would deprive its wizards of the mighty printf spell! To what Silicon demon legion did you pledge fealty to summon this coding abomination upon an unsuspecting land? Winter is truly coming at last."

So why is debugging so bad? Well, for one, serializing things across the web worker boundary is imperfect--you can't pass most World objects because they'll point to Thangs and Vectors and such which contain functions--and very slow if you're sending strings for each step of your algorithm for each frame of the simulation. So not only do you get really boring and unhelpful log statements like "Rect is at [Object object]", but it's very easy to blow up the simulation performance, and you have to either add a better UI than this.say() for seeing the messages or force the player to go to the browser console. We used to do this, but we shut it off.

We could solve most of these problems, but there is a better way. An amazing way. Just lurking, waiting for us to have time to implement it. CodeCombat's programming environment should allow us to build a time-travel debugging interface that combines the best of both breakpoint-based stepping debuggers and using log statements, but far better than either. It'll be quite Victorian. You'll just scrub back and forward through your code's execution history and hover over any variable to see its value at any point in time.

jsdares actually does something like this already:

screenshot 2014-01-02 10 06 03

In its solution, each statement generates a step message, and when you over over that statement's frame number, it shows the step message below the statement. It also uses blue dots to show which statements were recently executed or will execute. Finally, on the left you can see it shows the values of all currently defined variables. @janpaul123's thesis discusses the interface and motivations in Chapter 3, although the implementation has advanced beyond the thesis since its writing. There is some discussion of how it's done in Chapter 4.

I was thinking of implementing something different. Instead of trying to show all variables and their values, I'd prefer to focus on one variable when the player hovers over it. CodeCombat variables are often complex objects like Thangs, so a simple string isn't going to be enough to get a good picture of their state. You might want to see a Thang's pos property, or perhaps even its target.target.id to see who its enemy is attacking. Clearly we're not going to serialize all that state for every variable for every frame for every Programmable method.

Instead, what I plan to do is to keep the simulated World around in the web worker thread, possibly more than one at various intervals to make things even faster, and resimulate up until the current call whenever this kind of debugging info is requested. Then we can use Aether to thoroughly inspect the state of all accessible properties, serialize everything we can, and send it over for custom presentation that's aware of our common types (like Thangs and Vectors).

2014-01-02 11 30 16

I think the delay should be just a split second on most levels--suitable for idly hovering over various variables in the code to check them out. Then when the player wants to see a variable change over time, she can just scrub the playback and watch the variable change. It should be especially fast scrubbing forward, since we'll already have the World simulated up until the current frame and can just get the next frame--but it shouldn't be too bad going backwards, either.

With some cleverness plus the insanity of Aether's control flow yielding, we should also be able to scrub/step forward and backward within the current function execution on a statement-by-statement basis. We probably can't use the main playback scrubber for this, but perhaps some keyboard shortcut or traditional step forward/back/over/out buttons for when one wants to get really fine-grained could do the trick. jsdares experimented with a second timeline sort of interface, since beginners are confused by stepping debugger buttons, but as I recall having two was also confusing.

To implement this, we'll also need to do a bunch of improvements over in the Aether project, where I've added a companion issue. This issue can track the progress on the front-end interface as well as the coordination of Aether state harvesting and World resimulation in the background thread.

If we can pull this off well (and polish up some other editor rough edges), it has the potential to turn CodeCombat into the best environment for solving programming challenges that the world has ever seen, since not only will be there a sweet visual interface to see what's going on and gameplay mechanics to make it fun, but the overly powerful debugging, live-coding, and co-op multiplayer should make it possible to solve harder algorithms than you'd be able to do in a traditional environment--programming without a blindfold on, as it were.

Fix goals in IE9

If you try to play Rescue Mission (or presumably any level) in Internet Explorer 9, there's only one thing that prevents it from working: there's some bug where goals don't update properly. So when you look at the GoalsView, there appear two copies of each goal, and goals never get fulfilled. When the first goal of getting Tharin out of the dead end can't succeed, then the rest of the scripts don't fire.

screenshot 2014-01-01 22 21 16

I as of yet have no idea why they don't work. Are they not being sent properly to the World? Are they not triggering in the World? Are they not serializing or deserializing properly? Is the GoalScriptModule not recognizing them? Is there a separate problem with the GoalsView?

It's probably something tiny and totally stupid.

Autocomplete interface

One of the reasons that method names are so long (attackNearbyEnemy) is that we've always been planning to add really good autocomplete, so that players don't actually have to type that stuff out. I'm not even just talking about tab-completing identifiers, either--that's something that beginners may not know they can do. We could go all out like jsdares does and obey the Victorian commandment to get something on the screen as soon as possible:

screenshot 2014-01-01 12 43 43

screenshot 2014-01-01 12 47 31

(@janpaul123, you followed the vision--how did that end up working for beginner jsdares players?)

So how will we do it? There are two parts:

  1. Knowing which completions we could use.
  2. Showing the autocomplete UI.

For finding completions, our secret weapon will be Aether, since it should know not only which properties are available on this, but also through runtime introspection can actually know any property available on anything, what its type is, and what its current value is. I've opened a related issue over on that project to get that part of it ready.

For autocomplete UI, I hadn't thought too much about it beyond starting with something simple and trying to evolve it toward the screenshots above while iterating through some UX tests. Developing the interface is what this issue (in the main CodeCombat project) is about.

I found a couple potentially useful links for doing autocomplete within ACE:

I'm guessing we'll probably want something weird enough that we won't really go through ACE for it, though.

Improve 404 Page

Right now it just says 'Page Not Found'. Ideas for improvement:

  • Add some good artwork
  • Build a chaotic, surreal level and have it play on a surface embedded in the 404.

The 404 view is in /app/views/not_found.coffee.

Add JSON Schemas to Backbone.Mediator

Create a system for defining, listing and enforcing all events going through Backbone.Mediator in CodeCombat. Read up on Subscriptions and JSON-Schema for this issue.

All notifications going through Backbone.Mediator only allow one argument: an object. In practice, though, these objects should follow certain structures, and could use some explaining.

Design a way to list events going through Backbone.Mediator and a JSON Schema defining the objects that they pass around. This could be a single file which is an object of subscription names to JSON schemas, or a folder of these files, all of which one way or another are fed to a modified version of Backbone.Mediator which runs tv4 validation on event objects to make sure they conform with their definitions.

This listing would be used to:

  1. Build some sort of docs that could be referenced for Archmages trying to use these subscriptions.
  2. Run sanity checks, at least during development (possibly not in production?) to make sure event arguments are being structured correctly and help debug issues.
  3. In the Level Editor for scripts, for choosing a trigger for a script and for emitting notifications as a result of scripts (for example when pressing buttons).

Have permissions use the latest version of a given document

Read up on Versioning and Permissions for this issue.

Currently it's possible to create a new version based on the permissions of any previous version of a given document, effectively making it impossible to actually revoke permissions on a versioned document. Fix the postNewVersion endpoint in /server/handlers/Handler.coffee to base permissions checking on the latest version rather than on the one passed in.

Refactor Server

Big issue here, but this could be taken any number of ways (which are not necessarily mutually exclusive). Here are some possible routes I had in mind:

  1. Rework what we have to be cleaner and better organized. Mainly this would involve splitting Handler into several parts and responsibilities and unifying the error handling.
  2. Replace Express with Koa. Getting to use generators would be fantastic.
  3. Replace Express with Restify. Since CodeCombat is basically just an API, a framework more aligned toward building APIs would make more sense.

This is a major project, although not as large as it sounds. The server is much, much smaller than the client, so reworking the entire thing is not a hideously large project. If you're interested in this issue you should get in touch with us to talk about how to approach this.

Create Developer Tools Window

One cool project for learning the higher level structure of the site and incredibly useful for Archmages everywhere would be a window which displays many helpful stats about the site at any given time. Anywhere on the site, the developer could click a button or press a shortcut and open a Developer Tools like interface in a separate window which includes:

  1. Current view and subviews. They could be clicked to highlight what element that view represents. Show the module path for each one.
  2. Current instances of other classes and models and collections in existence.
  3. Events, subscriptions and keyboard shortcuts currently active, and what they call.
  4. Active log of events, subscriptions and keyboard shortcuts as they happen.
  5. Regular updating of all these as they change.

This could be used to:

  1. Edify an Archmage on what is going on with a given view. See what files are involved and how they're involved and how they communicate with one another.
  2. Debug issues involving tearing down objects and views and investigating memory leaks.

Make arrows and spears bury into the ground

When arrows/spears get stuck in the ground, they should appear buried in the ground. We have a die animation that cuts off the points, but we aren't 1) using it or 2) adjusting the rotation to make them point down into the ground.

Our arrow die state:

screenshot 2014-01-02 13 43 22

When an arrow misses and lodges into the ground, it should look kind of like this:

screenshot 2014-01-02 13 47 48

Adding the "die" action

In the combat.Arrow Component (edit the code in the level editor), which serves for both Arrow and Spear ThangTypes, do something like what the combat.Shell Component does to set the action to "die" when the missile gets stuck in the ground. That should trigger the die action animation in the CocoSprite. We'll also need to add the action.Acts Component to the Thang. (I can add that to the Arrow and Spear ThangType default Components when it's ready.)

Pointing into the ground

See #46 for some info on adjusting the apparent rotation / skew / transform properties in general. We'd want to adjust those also so that the arrows and spears appear to be buried in the ground, even though their velocity and rotation may no longer be meaningful (as they're not moving). So you'd add code in app/lib/surface/CocoSprite.coffee in perhaps the updateRotation or updateAction methods.

Add delete endpoint to /file/*

Make it possible for people to delete files. It would only be useable to admins until a permissions system is in place for files.

This would only require extending /server/file.coffee.

Move i18n strings to the database

Shortly after we launched our beta, we had so many amazing Diplomats volunteer from across the world to translate CodeCombat into ~20 languages before we could blink. We set up i18next to help translate our static text and also added an InternationalizationNode to Treema to help translate strings inside our levels. Cool.

But where did we put the i18next-based strings? Why, we just hardcoded them into a bunch of CoffeeScript files in app/locale and compiled them into the app, of course!

It's past time for that to change, since I can't keep manually transferring updates for all the languages from the exploding Google Spreadsheet we used to collect the initial translations into those locale files. Instead, we need:

  1. A way to store each locale in its own MongoDB document, so that a player can load only those translations she needs for her given language.
  2. An interface for Diplomats to use to edit and add translations. Perhaps we can use i18next-webtranslate instead of rolling our own? Otherwise, something involving Treema would probably make sense.

Fix spell palette popover hovering strobe effect

@gsaines notices this all the time and I can never reproduce--wonder if it's something to do with my Chrome theme or his scroll bars or something. His report:

"When I hover over the available spells in the spell palette and move my mouse left and right, the popup flickers like crazy, it's mostly aesthetic, but does make it hard to focus on the contents of the popup."

This is what the popover looks like:

screenshot 2013-12-31 20 14 53

The problem is somewhere in our use of Bootstrap 2.3's popover in the Tome's, here being triggered by the SpellPaletteEntry. The same bug might apply to other popovers like in SpellListTabEntryView; not sure. The styles for both of those are set in the Tome's style file, since their parent elements are a few layers up from the views triggering them.

Excellently easy dev setup

Scott and I were thinking about how it would be awesome if we had a single command people could run (like with curl) that would clone the repo and install all the dev dependencies and everything. This would make it much easier for novices to get involved.

The second part would be to consolidate the coco-brunch, coco-dev-server, coco-mongodb, and maybe coco-test-server and coco-server-test-runner scripts into one script that could be run from a single terminal, so that people don't have to set up five different terminals to get going. We'd strip down any extra logging from coco-dev-server, coco-test-server, and coco-server-test-runner so that the stdout from five things didn't get overwhelming.

Create production -> testing Mongo dump cron

The development server should be able to just download a copy of the relevant parts of the latest production database whenever it wants, so the production database should probably have a regular (hourly?) cron set up to make a dump of that available for download.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.