Coder Social home page Coder Social logo

hecrj / coffee Goto Github PK

View Code? Open in Web Editor NEW
1.1K 1.1K 55.0 1.41 MB

An opinionated 2D game engine for Rust

Home Page: https://docs.rs/coffee

License: MIT License

Rust 98.96% GLSL 0.76% Shell 0.29%
2d-game-engine engine game game-development game-engine gamedev rust

coffee's People

Contributors

5t0n3 avatar darkdrek avatar debris avatar dlight avatar gordon-f avatar hecrj avatar jalbert-dev avatar jms55 avatar johndoneth avatar memoryruins avatar ocboogie avatar oguzkocer avatar pvdberg1998 avatar ralith avatar shika-blyat avatar trimental 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

coffee's Issues

Coffee + specs

Hello! I'm having some trouble with borrowing when integrating Coffee and specs. The Coffee interact function borrows &mut State which is where I'm storing my specs World. When I try to run a specs System on the World it blows up with a alloc::boxed::Box already borrowed mutably error. Is there a way I can make this work? Is there any prior art for coffee + specs?

I'm re-posting here so I don't lose it in the Discord again!

Your response:

You shouldn't need to do anything special to get specs to work with Coffee. Simply store it in your type implementing Game, and you should be able to access it normally from interact and update.
โ€“ @hecrj

I'm storing the World on my type implementing Game as suggested which is where I believe the borrow error is coming from.

a few days later

After you said it should just work I took another crack and worked it out. Here's the code with the fix in case it helps other folks. The problematic code and fix is in the interact function.

use coffee::{
    graphics::{Color, Frame, Window, WindowSettings},
    load::Task,
    Game, Result, Timer,
};
use specs::{prelude::*, Builder, Component, VecStorage, World, Write, WriteStorage};

#[macro_use]
extern crate specs_derive;

#[derive(Component, Debug)]
#[storage(VecStorage)]
pub struct Foo;

#[derive(Component, Debug, Default)]
#[storage(VecStorage)]
pub struct Bar {
    baz: f32,
}

pub struct System;

impl<'a> specs::System<'a> for System {
    type SystemData = (WriteStorage<'a, Foo>, Write<'a, Bar>);

    fn run(&mut self, (_, _): Self::SystemData) {
        //
    }
}

struct State {
    world: World,
}

impl Game for State {
    type Input = ();
    type LoadingScreen = ();

    fn load(_window: &Window) -> Task<Self> {
        Task::new(move || {
            let mut world = World::new();
            world.register::<Foo>();
            world.insert(Bar { baz: 42.0 });
            world.create_entity().with(Foo {}).build();

            State { world }
        })
    }

    fn interact(&mut self, _input: &mut (), _window: &mut Window) {
        // Breaks:
        let mut bar = self.world.write_resource::<Bar>();
        *bar = Bar { baz: 43.0 };

        // Fixed:
        // {
        //     let mut bar = self.world.write_resource::<Bar>();
        //     *bar = Bar { baz: 43.0 };
        // }

        let mut system = System;
        system.run_now(&self.world);
    }

    fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
        frame.clear(Color::BLACK);
    }
}

fn main() -> Result<()> {
    State::run(WindowSettings {
        title: String::from("Foo"),
        size: (1280, 1024),
        resizable: true,
        fullscreen: false,
    })
}

Thanks!

Max Number of Shapes Renderable with Mesh

When rendering over 1k PolyLines on a single mesh, as the number of lines increased, I saw other lines disappear and a gradient streak appear, stretching from the top-left corner towards the middle where some line was rendered. See the below image:

Screen Shot 2019-08-31 at 11 16 15 PM

Given that my code works for a lower number of lines perfectly, I tried to allocate more than 1 mesh for drawing all the lines. Distributing the total number of lines among several meshes seems to have fixed the bug. I assume that this bug relates to some max bound for how many shapes a mesh can hold, but have not been able to find evidence of that in the documentation. If this bound does exist, it should be documented.

Implement a `TextInput` widget

We need a widget to ask users for text input. This seems to be a highly interactive widget that may pose a real challenge. We could start simple and forget about text selection, copy, cut, paste, etc.

Here are a couple of challenges that I see:

  • Choosing where to place the input cursor based on a mouse click. I am not sure if we will have to contribute additional functionality to glyph-brush to get this working properly.
  • Clipping text when it does not fit inside the input. Maybe we could use a Canvas to emulate it, but it may be tricky with the current Widget API. We may need to change it in order to make rendering more composable.

This is the kind of API I would personally like:

pub enum Message {
    TextChanged(String),
}

let state = &mut text_input::State::new();
let value = String::from("Some text!");

TextInput::new(state, &value).on_change(Message::TextChanged);

Controller support

We could use gilrs. I have never dealt with gamepad integration in a game, so any insights here will be greatly appreciated.

I imagine we could simply extend input::Event to add gamepad events.

`stretch` seems to ignore `Text` measurements

If we stop the Text widget from filling the width of its parent by default and its parent aligns items using Align::Start (the default), Text just keeps growing horizontally with no limit:

image

I don't think this issue can be produced with the current API, so this is an improvement instead of a bug for now.

It seems that stretch chooses the wrong bounding box for the Node. Text should shrink and have its own width, while filling horizontal space of its parent when possible. Maybe I am wrong, but I think that is the whole point of measure functions.

Additionally, when I implemented the Text widget, I noticed that stretch was calling the measure function provided in Node::with_measure way too many times. I was able to optimize this by using a RefCell to cache the first measurement, which seems to be the only one that matters. This last assumption could be wrong, but toggling this optimization seems to have no effect on the issue described above.

In any case, I think both things could be related. We should try to create a simple test in the stretch codebase reproducing the problem and open an issue/PR.

Game crashes when minimizing

OS: Win10
Version: crates.io

Just minimized the example project (opengl + debug feat.) and it crashed with the following error:

thread 'main' panicked at 'The left corner must not be equal to the right corner.', C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\nalgebra-0.18.0\src\geometry\orthographic.rs:622:9
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
             at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.29\src\backtrace\mod.rs:66
   1: std::sys_common::backtrace::_print
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\sys_common\backtrace.rs:47
   2: std::sys_common::backtrace::print
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\sys_common\backtrace.rs:36
   3: std::panicking::default_hook::{{closure}}
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panicking.rs:200
   4: std::panicking::default_hook
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panicking.rs:214
   5: std::panicking::rust_panic_with_hook
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panicking.rs:477
   6: std::panicking::begin_panic<str*>
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\src\libstd\panicking.rs:411
   7: nalgebra::geometry::orthographic::Orthographic3<f32>::new
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\nalgebra-0.18.0\src\geometry\orthographic.rs:0
   8: nalgebra::base::matrix::Matrix<f32, nalgebra::base::dimension::U4, nalgebra::base::dimension::U4, nalgebra::base::array_storage::ArrayStorage<f32, nalgebra::base::dimension::U4, nalgebra::base::dimension::U4>>::new_orthographic
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\nalgebra-0.18.0\src\base\cg.rs:118
   9: coffee::graphics::transformation::Transformation::orthographic
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\coffee-0.3.1\src\graphics\transformation.rs:30
  10: coffee::graphics::target::Target::new
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\coffee-0.3.1\src\graphics\target.rs:32
  11: coffee::graphics::window::frame::Frame::as_target
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\coffee-0.3.1\src\graphics\window\frame.rs:55
  12: coffee::graphics::window::frame::Frame::clear
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\coffee-0.3.1\src\graphics\window\frame.rs:62
  13: example::gui::{{impl}}::draw
             at .\client\src\gui.rs:29
  14: coffee::game::Game::run<example::gui::MyGame>
             at C:\Users\USER\.cargo\registry\src\github.com-1ecc6299db9ec823\coffee-0.3.1\src\game.rs:217
  15: example::gui::start
             at .\client\src\gui.rs:6
  16: example::main
             at .\client\src\main.rs:4
  17: std::rt::lang_start::{{closure}}<()>
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\src\libstd\rt.rs:64
  18: std::rt::lang_start_internal::{{closure}}
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\rt.rs:49
  19: std::panicking::try::do_call<closure,i32>
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panicking.rs:296
  20: panic_unwind::__rust_maybe_catch_panic
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libpanic_unwind\lib.rs:82
  21: std::panicking::try
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panicking.rs:275
  22: std::panic::catch_unwind
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\panic.rs:394
  23: std::rt::lang_start_internal
             at /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b\/src\libstd\rt.rs:48
  24: main
  25: invoke_main
             at d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
  26: __scrt_common_main_seh
             at d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
  27: BaseThreadInitThunk
  28: RtlUserThreadStart
error: process didn't exit successfully: `target\debug\example.exe` (exit code: 101)

I guess this can be solved in here.

Exporting as Image

This is probably outside of the scope of the game engine, but is it possible to use the current target or frame as an image type from the Image crate? My goal is essentially to save the frame as an image file. Thanks

Audio support

I guess we could use rodio.

The tricky part will be exposing an interesting API for it, and how to extend the current Game trait to make it work. Maybe Track or Sound types as resources, and something like a Speaker with a play method?

I don't think we should allow playing audio from update (the same way we do not allow rendering), so we will probably need a new provided method in the Game trait to play audio. And also a new associated type Audio to store the audio data.

Rewrite the `gfx`-based OpenGL graphics backend

The current OpenGL graphics backend is implemented using the deprecated gfx crate. While it works, it seems to be performing a lot of unnecessary state changes that may be affecting performance.

I think we could try to rewrite the backend using a well-maintained crate. Maybe glow?

Validate SPIR-V compiled shaders on CI

In order to avoid directly depending on the SPIR-V compiler when building the crate, we are currently providing the compiled shaders for the wgpu graphics backend here.

It would be great to have CI validate that these binaries are up-to-date with the shader code. I guess we could just simply recompile the code in CI (using glslangValidator -V) and check for differences with Git.

Benchmark graphics backends

As #1 mentions, in order to avoid performance regressions, it would be great to have a way to run benchmarks and compare results when making changes.

Is criterion well-suited for graphics benchmarks?

Mesh support

There is no way to draw a triangle right now!

It would be cool to have something like ggez's MeshBuilder. I think it uses lyon under the hood.

I will need this for my game so I will work on this pretty soon, unless someone else wants to tackle it!

Integration tests for `graphics`

This is just an idea. I do not know how practical it is, but I think it is worth a shot.

I am quite a fan of integration tests.

We could implement a suite of image-based integration tests for the graphics module. We would render to an image and compare it with an expected image pixel by pixel. If a test fails, we could keep the wrong image and mark the differences somehow (maybe another transparent image pointing the pixels that differ). We could have simple tests and very complicated ones, with off-screen rendering, text, batched draws and texture arrays, etc.

This will give us a lot of confidence when making changes/optimizations to the different graphics backends, or when implementing a new one. Also, I think it would be really cool.

I would like to do this myself, but any help or insights will be greatly appreciated. Share your thoughts here first!

Color improvements

Some ideas possibly worth implementing:

  • Hex constructor: Color::hex(0xFFFFFF)
  • Debug assertions for invalid arguments
  • Additional constants

Implement an `Image` widget

We should have a widget to simply render a graphics::Image:

let image = graphics::Image::new(gpu, "my_image.png");

widget::Image::new(&image).clip(Sprite { /* ... */ });

It should try to fill its parent and keep the correct aspect ratio at all times.

This should be similar in difficulty to #45.

Should Task::new expect a result?

Task::new doesn't expect a Result, but Task::from_gpu does. I'm loading a non-image data file using serde_json; which I figured made sense to put inside a Task.

I'd initially started with Task::new because i don't need a Gpu but it doesn't expect a Result, and neither does Game.load, so I found myself needing to unwrap the Result<(), MyError> during the .map portion of task loading.

I eventually ended up using Task::using_gpu like so

Task::using_gpu(|_gpu| load_data().map_err(|e| coffee::Error::from(e)))

with a custom Error enum providing the Froms for i.e. io::Error, serde_json::Error, and coffee::Error (converting everything into a coffee::Error::IO variant because that seemed like the only potentially relevant category of error.


On a somewhat related note, I have a config file that I'm currently loading twice because it specifies the WindowSettings size, which it's not clear to me how to only load this file during the load Task process. Maybe this doesn't make sense, given that you need an initial display size to display e.g. the progress bar. but at the same time I didn't see a way to programmatically resize the display after load either.

Scrollable widget support

Scrolling is quite a basic feature for a UI toolkit. We need it!

I see two different approaches to tackle this:

  1. Draw the scrollable contents into a Canvas. The issue is that we would need to recreate it once the scrollable changes dimensions. We could circumvent this initially by forcing users to set a fixed width and height for scrollables. However, this destroys the purpose of a responsive UI. Another approach could be simply avoid resizing the Canvas every frame while resizes happen, and only do it at a specific rate. Although this would cause the UI to not resize smoothly, it could be good enough for now.
  2. Implement scissor test support for Target. This sounds way more elegant, but it entails more work as we will have to add scissor support for all the current pipelines (quads and font rendering). It should be doable, but it needs to be done carefully.

In both scenarios, Widget::draw definition will probably need to change to improve composability and recursive draws (scrollables inside scrollables). Although I think a tree-like data structure stored in Renderer could work too.

Any other ideas?

Composing Input types

When #65 and #69 are implemented there are three basic Input's and one combination of two Input's.
Do users want all possible combinations as predefined types?
Is there a elegant way to implement all Input combinations?

A macro like this gist may help.

Rethink `Font` and `Text` API

A Font currently represents a bunch of text with a single font that can be drawn. However, glyph_brush supports rendering text with multiple fonts with a single draw call.

We should rethink the API so we can take advantage of this. Maybe the Text type should hold a collection of Sections, which have a Font attached to them. Then, we store the GlyphBrush type on the Gpu type instead of Font and we make Font contain just a FontId.

Allow to gracefully quit the game on demand

As of now, the only way to gracefully quit a Game after Game::run is to implement Game::on_close_request and wait for a close request.

However, it is very common in games to have a UI option to "Quit the game". While we can use std::process::exit, it's not ideal as it doesn't gracefully stop the execution.

Therefore, I think we need to rethink the Game API a bit to allow graceful quits on demand.

Shape rendering support

Something I have enjoyed in other game frameworks is the ability to debug ideas by first using shape primitives such as circles, rectangles, lines, etc, using some sort of shape renderer. Off the top of my head LibGDX, as well as Love2D support this feature.

I propose a similar API for prototyping with Coffee.

A ShapeBatch type and possibly rename Batch to SpriteBatch to avoid confusion.

Some possible methods:

impl ShapeBatch {
    color(&mut self, color: Color) -> &mut self;
    circle(&mut self, x: f32, y: f32, radius: f32) -> &mut self;
    line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) -> &mut self;
    rectangle(&mut self, x: f32, y: f32, width: f32, height: f32) -> &mut self;
}

Where each method returns self, or ShapeBatch for method chaining if desired.

The implementation would likely require a separate render pass, shader set, and a different per-vertex definition with just position and color. Fill vs Line drawing per shape would need to change the primitive type from lines to triangles and generate slightly different geometry.

Of course, this is just a rough idea and can use much improvement and could be improved by debate. Let me know what you think of the idea.

Review and optimize `wgpu` backend

The current wgpu graphics backend implementation in Coffee is quite naive and inefficient when performing multiple draw calls (benchmarks needed, though!). It scales quite well when using Batch, though. I get better performance in the particles example using wgpu.

In any case, I am a total beginner in computer graphics. I basically learned about Vulkan 3 weeks ago, and I am pretty sure the current implementation can be improved a lot.

I was able to get quite a speedup by only submitting the work once every frame here.

Currently, here is basically where most of the work happens. I suspect that creating mapped buffers every time is not a good idea. Should we implement something like a buffer pool?

Also, because a SwapChainOutput is bound to the SwapChain by a lifetime, we are currently rendering on a texture and then copying it here. We could maybe tie the SwapChainOutput to a Frame, keep the frame alive in the game loop and pass that into Game::draw instead of a Window, consuming it at the end of the iteration.

I would greatly appreciate any insights from more experienced people on how to proceed here.

Split `Keyboard` and `Mouse` into `Keyboard` and `Mouse` structs

We could split KeyboardAndMouse into two structs: Keyboard and Mouse, and use composition. Then it could be used like this (particles example):

fn interact(&mut self, input: &mut KeyboardAndMouse, window: &mut Window) {
    let mouse = input.mouse();

    self.gravity_centers[0] = mouse.cursor_position();
    self.gravity_centers.extend(mouse.button_clicks(mouse::Button::Left));

    let keyboard = input.keyboard();

    if keyboard.was_key_released(keyboard::KeyCode::I) {
        self.interpolate = !self.interpolate;
    }

    if keyboard.was_key_released(keyboard::KeyCode::F) {
        window.toggle_fullscreen();
    }
}

Both Keyboard and Mouse could implement Input too.

Improve `Debug` type to allow customization of the debug view

I think we could extend the Debug type with some methods to allow games to easily customize the debug view.

Here is how it currently looks:

Debug view

Here are a couple of features that would be nice to have:

  • Add additional key/value text. Basically extend the current view. This can be useful for counters (think entity count, loaded chunks count, etc.), player position, additional performance information, etc. Some way to define the position of the text on screen would be nice.
  • Add rectangles, once we implement mesh support (#4), possibly with customizable color. This will be useful to allow games to debug colliders, hitboxes, quadtrees, etc.

The API should be declarative (i.e. no side-effects until Debug::draw). Feel free to share any more ideas here!

Off-screen text rendering

Right now, text can only be rendered on a Frame. However, it should be theoretically possible to render text on any Target.

In order to implement this properly, some changes in glyph_brush will be necessary:

After this, it should be a matter of simply fitting everything together:

Implement a `ProgressBar` widget

A ProgressBar widget should be easy to implement. It must fill the parent width by default. The implementation of the current widgets could be used as a guide.

ProgressBar::new(percentage);

For consistency, we should probably choose sprites from Kenney UI packs.

Apply screen DPI scaling and expose logical coordinates instead of physical (?)

As of now, Coffee converts logical coordinates into physical coordinates (examples here and here) for everything.

However, the winit::dpi documentation seems to hint that we should instead expose logical coordinates everywhere and apply a scaling transformation when rendering on screen. This can be easily implemented by making Frame apply a scaling transformation using Target::with_transform in the as_target method here.

This would have the benefit that games will look similar in size in different devices. However, targeting specific pixels when rendering becomes harder. Can this cause graphical glitches? Maybe Window could expose the dpi value so developers can undo the dpi scaling if they deem necessary? What about a different type, like Frame but that does not apply a DPI transformation when seen as a Target?

Introduce more loading screens

We only have a quite simple ProgressBar loading screen built into Coffee currently. It would be great to have more diversity!

This can be a great way to get familiar with the graphics module of the engine and contribute at the same time. If you want to give it a shot, start by taking a look at the LoadingScreen trait!

Create game examples

It would be great to create some actual game examples to showcase the engine as a whole. It should also help us understand the shortcomings of the engine and serve us to choose what to improve next!

The examples should be simple, so we shouldn't go too crazy with the game complexity. I think simple games like tetris, breakout, pong, etc., are the way to go. We can use OpenGameArt.org for any assets we need and give proper credits in the examples README!

This is the perfect chance if you want to get familiar with the engine while contributing at the same time!

Configurable texture filtering

Currently, Coffee does only nearest neighbor interpolation.

We should probably allow to change this somehow. Is texture filtering normally a parameter that stays constant for a particular game? Could it be a simple configuration field on initialization?

Add rotation and color support for `Quad` and `Sprite` types

As of now, there is no way to set a rotation/color per quad/sprite. This is a really basic feature.

We could add support for it easily here and here. However, some games do not really need to use this feature and sending additional data to the GPU has a cost.

Before implementing this, I think we should write some basic benchmarks so we can discuss how to proceed (see #13). Maybe the overhead is negligible (I doubt it)? Maybe we can implement a different pipeline with a different shader and smartly select it at runtime? Maybe instanced drawing is not a good idea once we add more data? Maybe we can add it as a feature?

Errors running examples, when using coffee as a dependency.

First of all thanks for all the hard work and coffee is rad, but i would like to report something i found.

When i am trying to run the examples from https://github.com/hecrj/coffee/tree/master/examples

But instead of cloning the repository and then running them, i am using coffee as a dependency.

I am adding coffee to Cargo.toml like this.

[dependencies]
coffee = { version = "0.2", features = ["vulkan"] }

When i now copy the examples and try to run them, i get trait mismatch errors in all examples,
for example such.

 --> src/main.rs:36:5
   |
36 |     fn draw(&self, view: &mut Self::View, frame: &mut Frame, _timer: &Timer) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `coffee::graphics::window::Window`, found struct `coffee::graphics::window::frame::Frame`
   |
   = note: expected type `fn(&Colors, &mut View, &mut coffee::graphics::window::Window, &coffee::timer::Timer)`
              found type `fn(&Colors, &mut View, &mut coffee::graphics::window::frame::Frame<'_>, &coffee::timer::Timer)`

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.