Giter VIP home page Giter VIP logo

cfoust / sour Goto Github PK

View Code? Open in Web Editor NEW
144.0 6.0 26.0 421.43 MB

Sauerbraten for the web in a single Docker image.

Home Page: https://sourga.me/

License: MIT License

Shell 0.14% JavaScript 1.01% HTML 0.03% Python 0.68% Makefile 0.80% C 39.15% C++ 47.28% CMake 0.31% TypeScript 2.03% Objective-C 0.14% Earthly 0.05% Dockerfile 0.02% Go 8.26% CUE 0.10%
game multiplayer cube emscripten first-person-shooter golang multiplatform typescript metaverse

sour's Introduction

๐Ÿ‹Sour

Sour Cover Image

Sour Gitpod Development Environment TypeScript Language Go Language Google Chrome iOS Sour License Badge MIT

Sour is a multiplatform modernization of Cube 2: Sauerbraten delivered as a single Docker image. Give it a try.

Features

  • A complete web version of Sauerbraten
    • All original game assets and features
    • Support for mobile devices
    • Connect to all existing Sauerbraten community servers and crossplay with desktop players
    • Open and play back Sauerbraten demos by dragging them to the page
    • Arbitrary game mods
    • Sophisticated load-on-demand system for assets that allows for loading arbitrary content that has been packaged for the game
    • Links to servers (/server/[ip]/[port]) and maps (/map/complex)
  • An advanced Sauerbraten game server
    • Supports connections both from the web and from desktop Sauerbraten clients
    • Server multiplexing: you can run arbitrary game servers with their own maps, modes, and configurations and allow users to move between them without disconnecting from the server
    • Players can create private game servers and invite other players on-demand
    • Discord authentication both for web and desktop clients
    • 1v1 matchmaking and persistent ELO scores for users
    • Persistent map editing: edits users make to maps are stored on the server side and visible to other clients who join (no more /getmap and /sendmap)
    • User-owned spaces that they can edit (player housing, basically)
    • User sessions can be saved as demos for debugging
    • Automatically sends game maps to desktop clients that don't have them
    • Mechanism for running client-side CubeScript on desktop clients
  • Utilities and libraries for working with Sauerbraten
    • sourdump, a tool for calculating all of the files a Sauerbraten map, model, or .cfg file uses so that you can only send the minimum set of assets a client needs
    • Go library for opening, manipulating, and saving Sauerbraten game maps
    • Go library providing interoperation between Go and CubeScript

Goals

  • Modernize Sauerbraten. The gaming landscape has changed. Provide a modern multiplayer experience with matchmaking, private games, rankings, and seamless collaboration on maps. Make as much of this functionality available to the unmodified desktop game as possible.
  • Preserve the experience of playing the original game. While it is possible that Sour may someday support arbitrary game modes, assets, clients, and server code, the vanilla game experience should still be available.
  • Be the best example of a cross-platform, open-source FPS. Deployment of Sour on your own infrastructure with whatever configuration you like should be easy. Every aspect of Sour should be configurable.

Running

docker run --rm -it -p 1234:1234 -p 28785:28785/udp ghcr.io/cfoust/sour

You can then access Sour at http://localhost:1234/ or by connecting in the desktop client with /connect localhost.

Deploying

If you wish to deploy Sour more seriously, I provide an example configuration for docker-compose here using letsencrypt-nginx-sidecar.

Architecture

Here is a high level description of the repository's contents:

  • services/game: All of the Cube 2 code and Emscripten compilation scripts. Originally this was a fork of BananaBread, kripken's original attempt at compiling Sauerbraten for the web. Since then I have upgraded the game to the newest mainline version several times and moved to WebGL2.
  • services/go/: All Go code used in Sour and its services.
    • A Go program that calculates the minimum list of files necessary for the game to load a given map.
    • The Sour game server, which provides a number of services to web clients:
      • Gives clients both on the web and desktop client access to game servers managed by Sour.
      • Periodically fetches Sauerbraten server information from the master server, pings all of the available servers, and broadcasts the results to web clients. This is so we can fill in the server browser.
  • services/assets: Scripts for building web-compatible game assets. This is an extremely complicated topic and easily the most difficult aspect of shipping Sauerbraten to the web. Check out this section's README for more information.
  • services/ingress/: nginx configurations for development, production, and Gitpod.
  • services/proxy/: A fork of wsproxy. This allows web clients to connect to all of the existing Sauerbraten servers and crossplay with desktop clients.
  • services/client/: A React web application that controls Sauerbraten, pulls assets, and proxies all game communication over WebSockets.

Contributing

Join us on Discord to chat with us and see how you can help out! Check out the issues tab to get an idea of what needs doing.

The easiest way to hack on Sour is in Gitpod using the button below. Gitpod is a web-based VSCode environment that runs everything necessary for development in a cloud-based container, meaning that everything is set up and working for you right away. You do not even have to use VSCode; Gitpod supports custom dotfiles which allows me to use my full vim-based setup from a browser tab.

Open in Gitpod

If you want to run things locally all you need is Docker, Earthly, and docker-compose. After that, just run ./serve. Then navigate to http://localhost:1234. All of the game's services will recompile and restart when you make changes.

Inspiration

Some years ago I came across BananaBread, which was a basic tech demo that used Emscripten to compile Sauerbraten for the web. The project was limited in scope and done at a time when bandwidth was a lot more precious.

License

Each project that was forked into this repository has its own original license intact, though the glue code and subsequent modifications I have made are licensed according to the MIT license specified in LICENSE.

sour's People

Contributors

cfoust avatar croydon avatar gamemann avatar kripken avatar noahcoetsee avatar sbc100 avatar secretrobotron avatar vvuk 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

sour's Issues

Heroku?

Would it be possible to host this on heroku? I wanna add it to my site because, well, Bananabread is awesome so this is too.
If so, can you add the Deploy to Heroku button or just put a tutorial here?

Max health boost is wrong

I noticed that HB seems to function both the way it did in collect (by adding a constant +10 to your max health) and 2020 edition (by giving you +50 to your maxhealth during the current life and healing 100 health)
image

Allow for backgrounding the tab by responding to pings

Right now, when the tab is backgrounded the game is completely suspended, which makes sense because it uses requestAnimationFrame. Unfortunately this means the game completely stops responding to pings from the server, meaning that other players see the user go into the LAG state on the scoreboard and after a few seconds, the server disconnects them (at least on community servers).

Theoretically this could be solved by running the game in a Web Worker and or man-in-the-middling communication with the server in the backend and responding to pings on behalf of the user. The former would be ideal, but is extremely complicated from what I can gather. The latter is not ideal because when the user returns to the tab, there will be a significant buildup of server messages that may cause bugs or a temporary slowdown.

Allow users to "favorite" maps

One of the coolest things about Sour is exploring all of its thousands of maps. Users should be able to "favorite" or "like" maps and return to them later.

Better demo playback controls

We already have code for fetching demos that are stored in the backend, but it doesn't work very well. Make it work better and add an interface for playing, pausing, and seeking the demo with traditional playback controls. For bonus points, allow the user to jump to all of the kills a player makes in a match.

Unable to use mouse after browser captures it in Firefox

Tested on Mozilla Firefox 98 on Linux - untested on other OSes.
When the browser captures the mouse when attempting to select something, the mouse moves on its own to the Top Left corner of the screen. It will continue to attempt to do this as long as the mouse is captured, making playing the game impossible.

Tested on sourga.me.

Enforce max texture size on mobile

Right now, assets are compressed based on their file size, not the size of the texture, which is a problem on mobile devices (like iOS) where the memory usage is a function of raw texture size, not size on disk.

Support teleporting users to locations inside of rooms

There is some vestigial code that establishes a system of "links" between spaces, wherein the server intercepts N_TELEPORT messages and can send the user to another space. Ideally we would be able to move them upon arrival to a particular position and orientation, ie so that users could make teleports to arbitrary locations in other spaces, not just at random playerstarts.

Gamepad support

the possibility to play sour with a gamepad seems like a good addition to the app

Link to here from BananaBread?

Really awesome stuff here!

What do you think about linking to here from the BananaBread repo? Now and then people ask there about whether there is any news in this space.

Game "Locks up" almost immediately after data is loaded and game is ready to play

While attempting to play on sourga.me. Ater the game loads and is ready to play, the game locks up. I can hit Escape to release the mouse. The browser itself is still responding, just no response in-game.

Fedora Linux 35
Browser: Version 100.0.4896.60 (Official Build, ungoogled-chromium) (64-bit)
(Also had same issue starting on 2022-04-03 on Chromum 98.x)

From The Console:

WebGL: INVALID_VALUE: texImage2D: invalid internalformat
sauerbraten.js:10410 WebGL: too many errors, no more errors will be reported to the console for this context.
_glTexImage2D @ sauerbraten.js:10410
$createtexture(int, int, int, void*, int, int, unsigned int, unsigned int, int, int, int, bool, unsigned int, bool) @ 008b38ce:0xe1b4
$newtexture(Texture*, char const*, ImageData&, int, bool, bool, bool, int) @ 008b38ce:0x53fef
$textureload(char const*, int, bool, bool) @ 008b38ce:0x81c5
$loadcaustics(bool) @ 008b38ce:0x7e38b
$setupmaterials(int, int) @ 008b38ce:0x72295
$allchanged5(void*) @ 008b38ce:0xf58db
func @ sauerbraten.js:5554
Browser_mainLoop_runner @ sauerbraten.js:4940
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
index.tsx:268 main loop blocker "allchanged5" took 612 ms
index.tsx:268 The Complex by Dacker & Nieb
index.tsx:268 main loop blocker "allchanged_next" took 3 ms
unsafe-startup.js:59 glMapBufferRange is only supported when access is MAP_WRITE|INVALIDATE_BUFFER
printErr @ unsafe-startup.js:59
_emscripten_glMapBufferRange @ sauerbraten.js:8610
$gle::begin(unsigned int, int) @ 008b38ce:0xcb928
$flushwater(int, bool) @ 008b38ce:0x44b46
$renderwater() @ 008b38ce:0x5091b
$glaretexture::dorender() @ 008b38ce:0x145e97
$rendertarget::render(int, int, int, float, int) @ 008b38ce:0x75a26
$main_loop_caller() @ 008b38ce:0x13cb1d
callUserCallback @ sauerbraten.js:4989
runIter @ sauerbraten.js:5051
Browser_mainLoop_runner @ sauerbraten.js:4966
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
setTimeout (async)
Browser_mainLoop_runner @ sauerbraten.js:4954
unsafe-startup.js:94 RuntimeError: null function or function signature mismatch
    at gle::end() (008b38ce:0x5507)
    at flushwater(int, bool) (008b38ce:0x44cc4)
    at renderwater() (008b38ce:0x5091b)
    at glaretexture::dorender() (008b38ce:0x145e97)
    at rendertarget::render(int, int, int, float, int) (008b38ce:0x75a26)
    at main_loop_caller() (008b38ce:0x13cb1d)
    at callUserCallback (sauerbraten.js:4989:3)
    at Object.runIter (sauerbraten.js:5051:4)
    at Browser_mainLoop_runner (sauerbraten.js:4966:20)

Healthboost, Armor & Quad appears too early

When joining the Sour server on Sourga.me; the Healthboost, Green & Yellow Armor, and Quad Damage items appear on the screen before they are actually spawned. You can not pick them up until they spawn in game. Then will then disappear like they are supposed to when picked up.

Tested on Sourga.me using Chromium on Linux.

Sour not loading on Gitpod

When I try to deploy the repo on Gitpod, the game is stuck on "Loading Index Data (0/2)"

I have no idea how to fix this. Maybe it has something to do with the "Deprecated. Please use the Project Settings to configure prebuilds." error?

User-provided server configurations for spaces

Users should be able to modify the Sauerbraten server configuration for spaces that they own, perhaps using an in-browser version of VSCode that we could use for other things as well. This would expose all of the functionality the underlying Sauerbraten server provides, e.g. being able to disable damage on a server.

Add a completed bb.html build folder

I have been trying to build this for the last 3 days and I just cannot get it to work, so I've given up and I was wondering if you could add a completed build?

Thank you!

I'ts not opnening

Before your latest update all i would see is the text that it show as soon as you click on the link but it would not load i even waited about an hour and no change and with your latest update it is now just a white screen is there anyway you can revert/fix the game?

Add ARM64-Support

Hello,

When I try to run this image on my Oracle Cloud Server (linux/arm64/v8), I get the following error:

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
exec /bin/entrypoint: exec format error

So, is there any chance you guys could create an ARM version of the docker image? I (and other Oracle Cloud Free Tier users) would greatly appreciate it.

Add <noscript> HTML to let users know they need to enable Javascript

If a user visits the site with Javascript disabled in their browser (or a browser that doesn't support Javascript), the page comes up blank. This can look like the site is down.

Please add a noscript tag line to let the user know the site is available and they need to enable Javascript for the site/game to work.

Example:

...</script>
   <noscript>Please enable Javascript to play Sour</noscript>
  </body>

Nginx error

============================ โŒ FAILURE [2. Build ๐Ÿ”ง] ============================

Repeating the output of the command that caused the failure
+image-slim failed | --> RUN apt-get update && apt-get install -y nginx
+image-slim failed | Ign:1 http://archive.ubuntu.com/ubuntu groovy InRelease
+image-slim failed | Ign:2 http://security.ubuntu.com/ubuntu groovy-security InRelease
+image-slim failed | Ign:3 http://archive.ubuntu.com/ubuntu groovy-updates InRelease
+image-slim failed | Err:4 http://security.ubuntu.com/ubuntu groovy-security Release
+image-slim failed | 404 Not Found [IP: 91.189.88.142 80]
+image-slim failed | Ign:5 http://archive.ubuntu.com/ubuntu groovy-backports InRelease
+image-slim failed | Err:6 http://archive.ubuntu.com/ubuntu groovy Release
+image-slim failed | 404 Not Found [IP: 91.189.88.142 80]
+image-slim failed | Err:7 http://archive.ubuntu.com/ubuntu groovy-updates Release
+image-slim failed | 404 Not Found [IP: 91.189.88.142 80]
+image-slim failed | Err:8 http://archive.ubuntu.com/ubuntu groovy-backports Release
+image-slim failed | 404 Not Found [IP: 91.189.88.142 80]
+image-slim failed | Reading package lists...
+image-slim failed | E: The repository 'http://security.ubuntu.com/ubuntu groovy-security Release' does not have a Release file.
+image-slim failed | E: The repository 'http://archive.ubuntu.com/ubuntu groovy Release' does not have a Release file.
+image-slim failed | E: The repository 'http://archive.ubuntu.com/ubuntu groovy-updates Release' does not have a Release file.
+image-slim failed | E: The repository 'http://archive.ubuntu.com/ubuntu groovy-backports Release' does not have a Release file.
+image-slim failed | Command /bin/sh -c 'apt-get update && apt-get install -y nginx' failed with exit code 100
+image-slim failed | +image-slim failed | ERROR: Command exited with non-zero code: RUN apt-get update && apt-get install -y nginx
Error: build target: build main: bkClient.Build: failed to solve: process "/bin/sh -c PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin /usr/bin/earth_debugger /bin/sh -c 'apt-get update && apt-get install -y nginx'" did not complete successfully: exit code: 100

Leaderboard for ELO rankings

Every user has an ELO ranking for the 1v1 duel game modes but we do not show them anywhere. It would be cool to have a leaderboard accessible through the web.

Repair or port shaders that were disabled

Several shaders were non-trivial to enable in the web port, so I left them disabled.

  • Fix the outline shader (pressing 7 in edit mode)
  • Water reflection and refraction (this is really hard)

Building is broken, and where can this be hosted?

First off, love the project. Definitely would be cool! However, we people are poor and need to host this for free. Also, building is [BARK]ed. Where can we host and play this, and when will building be fixed??

Use password field for queueing or room joining

Desktop clients are able to provide a password when connecting to the server, which we could use to allow them to provide a destination space they want to connect to e.g. /connect sourga.me 28785 ffa.

Can't build sour on Mac

I'm using a fresh install of Earthly, Docker, and Sour. All Earthly builds complete as expected, but when running docker-compose these messages cause an endless loop. This is despite the fact that config/config.json exists and the generated files all seem to be in build. Any ideas? This is a project that we have on our web game aggregator and I was excited to pull it down and hack on the UI!

services-game-1     | /usr/bin/watch: line 11: /game/build: No such file or directory
services-server-1   | Couldn't watch /usr/bin/config/config.json: No such file or directory
services-game-1     | Building /game failed.
services-server-1   | /usr/bin/watch: line 11: /server/build: No such file or directory
services-server-1   | Building /server failed.
services-server-1   | Couldn't watch /usr/bin/config/config.json: No such file or directory
services-server-1   | /usr/bin/watch: line 11: /server/build: No such file or directory
services-server-1   | Building /server failed.
services-server-1   | Couldn't watch /usr/bin/config/config.json: No such file or directory
services-assets-1   | Couldn't initialize inotify.  Are you running Linux 2.6.13 or later, and was the
services-assets-1   | CONFIG_INOTIFY option enabled when your kernel was compiled?  If so, 
services-assets-1   | something mysterious has gone wrong.  Please e-mail [email protected]
services-assets-1   |  and mention that you saw this message.
services-game-1     | Couldn't initialize inotify.  Are you running Linux 2.6.13 or later, and was the
services-game-1     | CONFIG_INOTIFY option enabled when your kernel was compiled?  If so, 
services-game-1     | something mysterious has gone wrong.  Please e-mail [email protected]
services-game-1     |  and mention that you saw this message.
services-server-1   | /usr/bin/watch: line 11: /server/build: No such file or directory
services-server-1   | Building /server failed.

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.