Giter Club home page Giter Club logo

overwatch-team-comps's Introduction

Overwatch Team Comps

Build Status

A web app that allows Overwatch players to plan out their team composition for every point of every map on both offense and defense. Players should be able to save their team comps as well as be able to easily share their team comps.

Feature planning is done on our Trello board.

If interested, see also our requirements document that contains a high-level description of all the end-user features of this product.

App Structure

  • Ruby on Rails web app using React for a speedy, single-page front end
    • This means most views will be implemented in JSX in app/assets/javascripts/components/ instead of ERB in app/views/.
  • Rails endpoints will provide a JSON REST API for the front end
  • PostgreSQL database for convenient deployment to Heroku
  • Potential integration with OAuth providers such as Discord for authentication built on top of Devise

How to Develop

You will need Ruby, Rubygems, PostgreSQL, and npm installed.

bundle install
npm install
bin/rake db:setup
bundle exec rails s

Visit localhost:3000.

You can view the style guide at localhost:3000/pages/styleguide.

To add a new JavaScript package: npm install WHATEVER_PACKAGE --save

OAuth in Local Development

To test OAuth signin locally, you will need to create a Battle.net API app, cp dotenv.sample .env, and copy your app key and secret into the .env file. You will also need to use a service like ngrok to have a public URL that will hit your local server. Start ngrok via ngrok http 3000; look at the https URL it spits out. In your Battle.net app, set https://your-ngrok-id-here.ngrok.io/users/auth/bnet/callback as the "Register Callback URL" value. Update .env so that BNET_APP_HOST is set to the same your-ngrok-id-here.ngrok.io as ngrok spit out and you used in the Battle.net app; omit the https:// in .env. Start the Rails server via bundle exec rails s. Now you should be able to go to https://your-ngrok-id-here.ngrok.io/ and click the Battle.net link.

Installing PostgreSQL on macOS

There are multiple ways to install PostgreSQL, but the recommended way is through homebrew:

brew install postgresql

To manage your installation of PostgreSQL, one way is to use brew/services:

brew install homebrew/services
brew services start postgresql

At anytime you can stop the PostgreSQL service:

brew services stop postgresql

How to Test

After running through the development setup above, then:

npm test # to run the JavaScript style checker and JavaScript tests
bundle exec rspec # to run Rails tests

You can run just the style checker via npm run style. You can run just the JavaScript tests via npm run unit-test.

Snapshots are used in JavaScript tests -- see spec/javascript/components/__snapshots__/ -- to test that a React component is rendered the same way consistently based on the props it's given. If you update a component, a test may fail because the snapshot is now different from what is rendered. Manually compare the two and if the change is expected, update the now out-of-date snapshot with npm run unit-test -- -u.

See also these links about the JavaScript tests:

How to Deploy to Heroku

Create an app on Heroku.

Create a Battle.net app and set its "Register Callback URL" to https://your-heroku-app.herokuapp.com/users/auth/bnet/callback.

heroku git:remote -a your-heroku-app
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-nodejs.git
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-ruby.git
heroku config:set BNET_APP_ID=your_app_id_here
heroku config:set BNET_APP_SECRET=your_app_secret_here
heroku config:set BNET_APP_HOST=your-heroku-app.herokuapp.com
git push heroku master
heroku run rake db:migrate
heroku run rake db:seed
heroku open

Mockups

These show the design we are building toward:

Sample Mockup of Team Comp Form 01

Sample Mockup of Team Comp Form 02

Sample Mockup of Hero Pool Page

Sample Mockup of Hero Select Drop Down Menu

overwatch-team-comps's People

Contributors

cheshire137 avatar pseudobeard avatar rewinfrey avatar robthepm avatar smbriones avatar tung-vu-tiki avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

overwatch-team-comps's Issues

Let team organizer specify role for each player selection

We have a player_selections.role field that's intended to let the organizer specify a role that player is fulfilling in the composition by playing that hero. It's an optional field. We should let the user set it and then, on the composition show page #80, we should make it visible in a subtle way, perhaps on hover as a tooltip.

We need an interface with a text field that the user can set to the role for each player+hero on each point. We need a way for the user to access this text field because there's not room on the page for it to be visible all the time, for every selection.

Like maybe I want Rob to play Mercy not as a primary healer, but as DPS because he's gonna Battle Mercy. Or maybe we need Soldier: 76 as our Healer: 76.

Blank white screen, no JS errors

@RobThePM went back to the app in his same Windows Chrome browser and got a blank screen instead. He opened the JavaScript console but didn't see any errors.

I thought maybe it could be because of using http instead of https, but the page still loads for me like that. That probably only affects OAuth sign in.

Add JavaScript test framework

#19 and #10 add some JavaScript models and components that ideally would be tested. I had good luck in this other React app with using Jest and Enzyme for testing. We could use the same setup here and run jest to run JavaScript tests while continuing to run rake test for Rails tests. Both could be run on Travis for #17.

Load previously saved composition on page load

When I load the app again after having saved a composition before, the player names, hero selections, map, composition notes, and composition name should be populated with the values from that previous composition of mine.

It would be nice if the front end just had to make one request to get composition details regardless of whether it's a new composition or a previously saved one. Maybe an /api/compositions/load endpoint would be better than the /api/compositions/new request that the front end makes now? This would parallel the existing /api/compositions/save endpoint.

  • Add a new /api/compositions/load endpoint that determines, based on the current_user or the session.id if current_user is nil, what the last modified Composition is, if any, for that user/session. It should respond with the same JSON structure as in new.json.
  • Remove the /api/compositions/new endpoint. Reuse its tests for the /api/compositions/load endpoint.
  • Change the front end to hit /api/compositions/load instead of /api/compositions/new. This will mean a different method in OverwatchTeamCompsApi and a different call in CompositionForm.

Flesh out models

Barebones models were added in #5. We should add reasonable validations and relations in a follow-up branch. Some fields are marked as NOT NULL in the database, so we should have presence validations on them. There should be length validations on string fields. Relations such as belongs_to :user on the Player model should be added to connect models together based on foreign keys.

Different models could be tackled in separate branches to keep pull requests easily reviewable.

Save player selections when user selects a hero

This will involve a new endpoint for persisting changes in the composition form as well as the client-side code to hit that endpoint when a change occurs. For now, the endpoint + JS need only work with the hero select menus. Hooking up other parts of the form can come in a later branch. The server-side code will probably have to fill out some other fields in the new records to make them valid.

Add a couple new database fields

Based on our call yesterday, we need the following adjustments to our data model, made via Rails migrations:

  • Add nullable string battlenet field to users table, to mirror the same field already in the players table -- this will be handled as part of #33
  • Add nullable text video_url field to compositions table
  • Add non-nullable string session_id field to compositions table. We can probably put a limit of 32 on it, based on http://guides.rubyonrails.org/security.html.
  • Modify compositions.user_id to be non-nullable.

@rewinfrey does this seem right to you?

Add Rubocop

To keep our coding style consistent, we can use Rubocop. When we set up CI, we can tie our Rubocop style checker in so that tests will fail if there are style complaints.

Create a Slack team

I'd like to propose Slack as a fun way to communicate and share in the camaraderie of working on this project. The use of Slack is not to take the place of Trello cards or GitHub, but it often can serve as useful place to bounce ideas off the group and get feedback. It's also a fun way to build communities!

Is there any interest in creating a Slack team for this project?

/cc @RobThePM @cheshire137

Save player names as they're entered

When a user changes a player name in the composition form, we should persist that as a players record. We need to identify that when user A types "Jim" they mean someone else than when user B types "Jim." So we need to scope players by the user who created them.

I think a new creator_id field on the players table -- first mentioned in #50 -- would allow us to do this. We also want a creator_session_id field on the players table to capture when an anonymous user creates a player.

  • Add non-null int creator_id and non-null string creator_session_id fields to players table. Validations on the Player model and tests would also be good. Having a non-null creator_id depends on #47.
  • Add new Rails endpoint that saves the specified player name. It should determine whether to create a new Player record or update the name on an existing Player record, based on the user or session ID the request is coming from. The endpoint should probably require the old name and the new name, so that it can look if a player by the old name exists for the user/session doing the requesting.
  • Hook up JavaScript such that when the user changes one of the player name fields, a request with the name from before they started typing as well as the name after they finished typing is sent to the back end for saving. I think we'll want to handle setting the old value ourselves, since it looks like defaultValue won't update with React state changes. Some kind of data-previous-name attribute on each player name input would work, then we update that value after a successful save request. We could do the request after a delay when the user has finished typing -- see this debounce answer -- or when the input loses focus.

Support Markdown formatting in the 'notes' text field

There are a few parts to supporting Markdown in the 'notes' field:

  • When we render the notes on a static page where the user can't edit them, we should convert the Markdown to HTML so that links, boldface, and other formatting appears.
  • In the composition edit form, it would be cool to offer a toolbar so the user doesn't have to manually type Markdown if they don't want to. This isn't critical, but maybe there's a simple drop-in solution?
    new_issue_ _cheshire137_overwatch-team-comps
  • We should strip certain kinds of formatting from the 'notes' field, either on render or before we save the value in the database. style attributes, img tags, embed tags, etc. we don't want to render.

Allow user to edit and delete players they've created

Maybe I made a typo and saved a player I didn't intend to save. Maybe I no longer play with someone I used to put in my team comps. Maybe I want to set Battle.net IDs on my friends. Maybe I want to rename "@pseudobeard" to "ATastySnack."

We should allow the user to:

  • Edit existing player names for players they've created
  • Delete players they've created
  • Add battletags for players they've created

Any thoughts on how these features might be exposed, @smbriones?

Set up continuous integration

I figured we'd use Travis CI for this. I may have to toggle some switch on Travis since the repo is tied to my GitHub user. We need a Travis config file in the repo, though, before I toggle said switch. Ideally, Travis would run Rails tests via RAILS_ENV=test rake test for us. So Travis will also have to run database migrations via RAILS_ENV=test bin/rake db:migrate before it runs tests. Once we add some style checkers like ESLint and Rubocop -- see #8 -- Travis should also incorporate those.

#13 adds our first tests, so this issue would make sense to complete after that lands.

We'll probably want the following cache options for Travis:

cache:
  directories:
  - vendor/bundle
  - node_modules

/cc @pseudobeard โค๏ธ

Allow the team organizer to set the battletag per player

Currently you just see a field for the 'name' of each player, and that will be saved in the players.name field. To let the team organizer see hero confidence levels for their players, the players.battletag field has to be populated so we can link players to the users they represent.

I'm not sure how we'd work this into the UI. Maybe a menu for each player, possibly triggered in the players column of the composition form, with an option 'Set battletag'? Then if a battletag is set for a player, we could show it written below the player name in smaller text. Thoughts on this design @smbriones?

This issue needs:

  • A Rails endpoint to uniquely identify a specified player (maybe by its id or by its name + a new creator_id field on the players table that could contain the current_user who created that Player?) and set their battletag.
  • UI to hit this endpoint.
  • UI to display player battletags when they're set.

Tech Stack

I would like to discuss the text the tech stack.

I know rails really well and am happy to use it. But if we are using react and going heavy from end (which I think makes sense for this), we should probably consider using Node.js and at least talk through the pros and cons thereof.

Create content for 'Instructions / How to Use' page

I can work on the content for instructions. This will probably be texts and screenshots on a page, but I'm also probably going to do a video or something if we can embed that into the page as well.

Also, we don't necessarily need a separate page for this; it can be added to the home page, about us page, or some other page if you guys prefer. Although I think it makes sense to have it be it's own page. Maybe the text and screenshots can be it's own page and the video can be on the home page. Open to opinions.

Persist session ID to identify owners of anonymously created compositions

When I check the Application > Cookies view in Chrome's web inspector for the app, I see a session cookie from Rails whose expiry time is "Session." "Session" cookies are handled differently by browser, and Chrome will keep your session cookies around, as I understand it, if the user has selected the "Continue where you left off" Chrome browser setting. I don't think we want to depend on this, as per RQ06, to hook up a bunch of ownerless compositions records if a user who has been using the site anonymously decides to sign up.

http://stackoverflow.com/a/1232231 looks relevant for modifying how long a Rails session cookie lasts. I'm not sure if that will be a rolling expiration date, like if we set it for a year in the future and the user uses the app again after 364 days, will the new expiration date be another year beyond that?

Let a user specify their heroes

We need a form to let a user specify the heroes they play and their confidence with each hero. This page should only be accessible if you're signed in. The form will let you create player_heroes records tied to a Player tied to the current_user. This issue depends on #6 so that we have relations tying Player, User, Hero, and PlayerHero models together.

Perhaps the page could list all available heroes with a slider for each one. Each slider could start at 0%. When the user changes a slider, like setting Mercy to 90%, an AJAX request could be made to create/update a PlayerHero for the user's player and that hero.

This issue could be tackled in multiple steps if desired: create a UI, create an endpoint for saving the PlayerHero, and hook up the UI via JavaScript so that it hits the endpoint.

Add endpoint to get all composition details

Currently, we have /api/maps that returns the list of maps to display in the composition form. We also need:

  • list of players
  • composition name and user
  • map segments
  • player selections -- a new has_many :player_selections will be necessary on Composition

It'd be cool if we could fetch all this data with one request. Maybe an /api/compositions/new endpoint? This would be hit when the user goes to a new composition form. We'd probably have an /api/compositions/some-unique-id endpoint for loading the details of a persisted composition.

Populate hero select menus in composition form

The menus currently have no options, just 'select hero.' We should fill them up with heroes. If there is a player specified for that row, and there are PlayerHero records for that player that have confidence values, we should list the most confident heroes first.

Get map images for the header

In @smbriones' mockup, she used a pretty photo of the map in the header area:

Map

We need such an image for each map in the game. My thinking is we can get these images ourselves from inside Overwatch by taking a screenshot. Ideally we'd use the highest resolution possible so we have more options for cropping the image while keeping the quality high.

I have a 2560x1440 resolution; does anyone have higher? Maybe we don't even need that high. Go sightseeing in the game, find a pretty view of the map, grab a screenshot. ๐Ÿ“ธ Perhaps you can use the spectator camera controls to get to a good viewpoint?

Change composition form header color based on map

The gradient used in the header of the composition form should change based on the map that's selected.

Route 66 just isn't a pink-and-blue kind of map:

overwatchteamcomps

@smbriones and @justbarreto, can you guys pick out some pretty colors and one of the devs can plug them in so that they change when the map selection changes?

This is related to #74.

Choose a CSS framework

Do we want to use a CSS framework, and if so, which one? I like them even if we're doing a lovely custom UI because they specify basic styles that are Good Enough โ„ข๏ธ, like line-height and font size hierarchies.

I've had good luck with Bulma for previous projects. It provides a convenient grid system while also mostly staying out of your way; I don't find myself fighting it a lot to customize styles. I'm open to other options, too -- please share your thoughts!

Other frameworks: Primer, Bootstrap

/cc @justbarreto @summasmiff @smbriones

Hook up user authentication

We have a users table and the Devise gem for authentication. It would be cool if users could register and sign in. This would give us a current_user in controllers such that we could tie new Composition records to that User so the user can log in later and edit them.

We can start with basic user name and password authentication, and add OAuth authentication via Discord, etc. later.

We could present login + registration forms in two ways:

  • Via React components in app/assets/javascripts/components/, using a single HTML page.
  • Via separate pages as is the Devise default, leaving single-page stuff for the team composition form, specifying the heroes you main, etc.

Test the product before version 1 go live

This is really just a reminder for me to perform ongoing testing of the product before go live. I'll create separate issues for each individual bug, etc.

I'm also happy to delete this issue if it doesn't really belong here as an issue.

Add hero confidence view

We need a view for letting the user specify their hero confidence levels for each hero.

Check this mockup:

Hero pool selection

The idea is to rank your skill at a given hero in terms of the competitive ranks. So if you suck at Hanzo, maybe you rank yourself bronze on him; if you're very confident of your Zarya skills, slide it up to grandmaster, and so forth.

  • Get high-quality images of the competitive rank chevrons.

  • Add a new React component, perhaps name HeroPoolForm to parallel the existing CompositionForm.

  • Hook up navigation to this new view. MainNav could take an onNavigate handler that App would give it. App can setState inside that handler to change some activeView. Then App can decide whether to render CompositionForm or HeroPoolForm based on activeView. activeView should default to showing the composition form.

    If our routing gets more complicated, we can go with react-router. I just think it's premature at this point when we only have two top-level components to choose between. The URL doesn't have to change when you're viewing the hero pool versus the composition form.

    The option to switch to HeroPoolForm should only be shown to authenticated users.

  • Add a new backend route for creating/updating PlayerHero records, which is where confidence is stored. Each Player record should be tied to current_user via the user_id field. This backend route should only be available when the user is signed in; it's not for anonymous users.

  • Flesh out the HeroPoolForm component to list all the heroes. I think a set of radio buttons where the labels are the competitive rank chevrons would work best.

  • Hook up HeroPoolForm so that whenever one of the radio buttons changes, a request is sent to the new backend endpoint to save that confidence value for that hero and player. A new Player record may need to be created, depending on if a Player exists where creator_id and user_id are the current_user. We need a mapping from the discrete competitive ranks to the continuous confidence field, like bronze = 0, grandmaster = 100, and so forth.

  • Tests for the new endpoint.

This is a large issue, so multiple people could work on different parts of it at once.

Switch to PostgreSQL from SQLite

When I generated the Rails app, it defaulted to SQLite for our database. That won't fly when we deploy to Heroku later. We can drop the sqlite3 gem from the Gemfile and replace it with pg. database.yml needs to be updated to specify PostgreSQL, too; see http://edgeguides.rubyonrails.org/configuring.html#configuring-a-postgresql-database. Instructions should be added to README.md about how to create a PostgreSQL database locally for development and tests. If you have to take any particular steps to install PostgreSQL on macOS, such as Homebrew commands, those could be listed in the readme as well.

Add composition 'show' page

We need a unique URL for each composition such that a user can copy that URL and share it with their friends. The fields should only be editable if the URL is viewed by the creator of the composition (so either the authenticated user, or the anonymous user with the right session ID). The URL should be presented somewhere on the composition form so that while I edit my composition, I can copy the URL at any time to view the static version myself or to share it.

It'd be cool if the URL to view a composition didn't just rely on the integer composition ID in it. Use the friendly_id gem to make a unique, friendly slug for each composition and use that in the URL. The URL might look like /composition/hanamura-my-fave-dive-comp-1.

I figure the page can be laid out much the same as the composition form, just with static text in place of inputs and select menus.

Introductions

๐Ÿ‘‹ Since so many folks want to help out on this project, I thought we could have some introductions to share how we'd each like to contribute. This should help with requesting code reviews on pull requests and knowing which work to tackle.

Feel free to share your name from Overwatch, too. I think a lot of us will recognize each other. ๐Ÿ˜€

/cc @RobThePM @justbarreto @rewinfrey @siege911 @summasmiff and anyone else I've left off

Hook up map menu

When the user chooses a different map, they should get a new composition, or if they've created a composition on that map before, that composition should be loaded.

We can add a separate interface later for swapping between compositions for a single map. For now, go with the simplest case of letting the user access one composition per map.

Use select menu for player selection, adding new players

Instead of a text field where the user can type a new player name, let's use a select menu. The menu can start with just 'Add a new player' as an option. As the user adds players to their compositions, we can prefill that select menu with every player they've ever created.

As @rewinfrey points out in #57, this will let us simplify the logic in the CompositionSaver model because we can extract player-creation logic from composition-saving logic.

Add concept of an "anonymous" user

  • Add to seeds.rb a User that we can recognize as being our fake user to represent anonymous users. Perhaps the distinguishing feature could be the email address, say [email protected]?
  • Add a class method like User#anonymous that always returns this particular User record.
  • Test your new class method. โœจ

Fit team composition form inside bounds of page

The composition form should be no wider than the Signed in as cheshire137#1695 in the top right. I'd love to avoid a horizontal scrollbar. We could probably shrink the first column with the player names a bit, and maybe also shorten map segment names. We could also widen the .container class if necessary.

overwatchteamcomps

Force https in production

If I go to the http URL on Heroku, the app will happily stay there. I'd rather use https when it's available. We should add JavaScript to the page such that if the app is not in development mode, or if it's on a host other than localhost, we redirect to the same URL but with https.

Display errors to user, don't just console.error them

In

console.error('failed to load maps', error)
and other error handlers, we're just logging the error message in the JavaScript console. As mentioned in #46 (comment), we should also render a friendly message to the user that something went wrong. I think a new ErrorMessage component is the way to go. Here's how I imagine the flow working:

  • Some JSON response fails and one of our error handlers in ComponentForm is called. Besides console.error'ing, they should also this.setState({ error: 'description of the problem' }).
  • In the render for ComponentForm, we render <ErrorMessage error={this.state.error} />.
  • The ErrorMessage component is smart enough to render null when the error it is given is undefined/blank/null. Otherwise, it renders a <p className="text-attack">{this.props.error}</p>.
  • We could also include an 'X' button in the <p> tag of ErrorMessage that, onClick, will call some function given to it, like onDismiss. ComponentForm should pass this onDismiss prop to ErrorMessage. When it's called, ComponentForm should this.setState({ error: null }) which will result in ErrorMessage re-rendering to be empty.

Allow connecting to Battle.net via OAuth

Use Blizzard's OAuth API to allow a registered user to connect their account with Battle.net, or to allow an unregistered user to register their account via signing in with Battle.net.

I'm assuming we can get the user's Battle.net ID from this API somehow. We should verify that. If it's possible, we should auto-fill the users.battlenet field #30 with it. We should also then update any players records that have that battlenet so that their user_id is that user's.

https://github.com/Blizzard/omniauth-bnet looks like a good gem to use with Devise; see https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview.

Add "Clear Sans" Typeface

This is the typeface I've been using in the design so far. Can we add the webfont to our project to start adding font styles? I'm mostly using Regular, Medium, and Bold, but it would be nice to have all of the weights.

I think this makes it simple, but also happy to add them via font-face:
https://github.com/resir014/Clear-Sans-Webfont

Disable inputs when a request is out

We should update the state to indicate when a request is starting and update it again when the request comes back successful or with an error. When a request is in progress, all inputs on the page should be disabled. This will serve two purposes:

  • Visually indicate to the user something is happening
  • Possibly prevent one request from clobbering another

Data model

Based on https://trello.com/c/wXa0dJqb/23-robert-to-build-wireframe-using-balsamiq these are the tables I think we'll need:

  • users - I figure https://github.com/plataformatec/devise would be a good gem for authentication. I've used it before, it'll generate a users table for us with username, password, etc. We could also put fields like discord_user_id and the like on this table if we want.
  • maps
    • id
    • name - e.g., Watchpoint Gibraltar
    • type - payload, escort, hybrid, control
    • slug - for use in the URL, e.g., watchpoint-gibraltar
  • compositions - this will have 1+ player_selections records
    • id
    • name - e.g., Rob's Fave Picks
    • notes
    • slug - for use in the URL, e.g., robs-fave-picks
    • map_id - which map is this team composition for?
  • players
    • id
    • name - e.g., Sarah
    • battlenet - e.g., jimbob#1234
    • user_id - is the player another user of the app?
  • heroes
    • id
    • name - e.g., Hanzo
  • player_selections
    • id
    • player_id
    • hero_id
    • role - e.g., support, offense payload 1, defense capture point
    • composition_id - a field to tie this player + hero combination back to a particular composition
  • hero_pools - I'm open to a better name for this join table that hooks up players with the heroes they're comfortable playing
    • player_id
    • hero_id
    • confidence - thinking a floating point value between 0-1 that indicates how comfortable the player is with this hero, like 0.75 for fairly confident, 0.1 for not confident at all actually I'll probably make this an integer between 0-100 because floating point is scary

/cc @justbarreto @RobThePM

Highlight when there are duplicate heroes selected in a given column

Notice the two red Mercys in this mockup:

mockup

They're highlighted in red because you can't have more than one of the same hero on a given map segment, at least with normal quick player and competitive rules.

Detect if there are duplicate picks in a given column and highlight all the duplicates in red like in the mockup. The detection can happen on the server side, with a list of duplicate hero IDs per map segment coming back in the JSON response. It could also happen just on the client side, in the JSX React components. It's your pick! โœจ

Update existing players, compositions on user signup

When an anonymous user signs in via Battle.net and a User record is created for them, we should update the existing Player and Composition records for their session ID so that they're now tied to the new user.

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.