fishfolk / jumpy Goto Github PK
View Code? Open in Web Editor NEWTactical 2D shooter in fishy pixels style. Made with Rust-lang 🦀 and Bevy 🪶
Home Page: https://fishfolk.org/games/jumpy/
License: Other
Tactical 2D shooter in fishy pixels style. Made with Rust-lang 🦀 and Bevy 🪶
Home Page: https://fishfolk.org/games/jumpy/
License: Other
There are still issues with the controllers:
On my machine (Linux), controller now gives input both to player 1 and to player 2.
Currently, the controls for the game are hardcoded. It would be nice to allow players to remap both the menu and in-battle controls. Some possible methods are:
We eventually want to let players create new levels from within the game itself, rather than having to open .json maps in Tiled. Our own level editor should support all of the basics we can currently do with Tiled, plus a few more conveniences added on top.
https://steamcommunity.com/sharedfiles/filedetails/?id=1305733533
https://duckgame.fandom.com/wiki/Level_editor
Level editor should let a modder:
Convenience features will include:
Later:
Prior art:
https://github.com/brooks-builds/platformer_with_level_editor
https://www.twitch.tv/collections/QZm7Miz_fxbNCw
We should eventually have our own version of this booklet to onboard new contributors:
https://not-fl3.github.io/platformer-book/intro.html
Anyone is welcome to have a go at writing one of the missing pages of the tutorial, or rewriting the existing pages using our game as the reference codebase. Start an issue or chat with us about it and we’ll walk you through it.
Because FF uses Macroquad, we gotta start off explaining how to use mq. The tutorial will basically make a lightweight reimplementation of Fish Fight as a demonstration of how to make a game with Mq.
So this tutorial will explain how to make a game exactly like Fish Fight. But because the Fish Fight codebase itself is a fast moving target, we’re not gonna couple the tutorial to the exact production game.
A good start would be the first three that are missing in the booklet:
The way to approach the writing is very simple:
There are some features that the standardized explosives #113 do not yet have.
Particularly, mines #99 should have these features. Possibly also grenades #98.
The fire could be replaced by a swarm of piranhas.
One gun could mass-shoot piranhas similarly to a flamethrower and if a fish comes in contact with them the piranhas "group up" and start biting the player. The fish then panics and runs around and either it sprays some sort of repellent that saves its life or the piranhas leave nothing but bones.
There could also be areas or pools of piranhas similar to lava pools.
Currently we have two kinds of explosions:
I propose that we go over to using the ones from cannonballs, created by @saveriomiroddi, for everything, as they look better and scale better.
We should also make a method for spawning these at a specified point, with a specific size and maybe a specific set of colors...
Please share your favorite animal weapons!
Some recent changes have impacted all the weapon hitboxes, so they all need to be checked (and fixed if required). If anybody's working on this, put your name, so that multiple devs won't work on the same task
For an example, see the following (in the first part, the weapon can't be picked up, then, the weapon doesn't kill the opponent): https://user-images.githubusercontent.com/1595356/127765921-b02d8342-33bb-46bc-92aa-00835f881bc2.mp4
Todo:
When picked up by the player provides a set number, of armor against damage from the player's back. I.e the player can take a set out amount of hits from the back without dying.
This would involve giving the player an armor attribute and incrementing it to the amount of armor the turtle shell armor provides. As mentioned by @olefasting, when the player takes damage, the direction parameter of the kill method can be checked to see whether it was taken from behind. If it was taken from behind, decrement the armor value. Otherwise, the player should die as usual.
Mines were added in #8. They were later removed, but I am going to put them back, as fatal and insidious as ever.
I use Athenaeum for playing many open-source games (it's an open-source game launcher and manager for Flatpak-based games), it would be great to have FishFight available via it too. It's especially good for users since it manages game updates automatically.
cargo fmt
is rust default formatter. This formatter has some study over it to define which is the best way to format and organize our code for future readability.cargo clippy
is rust default linter, by using using clippy::pedantic
/clippy::correctness
configuration we can detect some common logic redundancies as well as some improvements over the language usage. By using clippy::perf
configuration we can find performance improvements for our code.https://youtu.be/216_5nu4aVQ
https://youtu.be/Fy0aCDmgnxg
https://youtu.be/qaCBpgVIw0Q
https://youtu.be/UsGuN69g2NI
(Tools we hope to eventually have in the Rust gamedev ecosystem)
https://assetstore.unity.com/packages/tools/particles-effects/feel-183370
https://codemanu.itch.io/juicefx
There seems to be a problem with the level menu where mouse clicking Test Level lands you in the first level, in stead of the test one...
With the new functionality of the platform descension, the old mappings are not practical anymore (ie. pressing up and down arrow at the same time, or W+S); the key K
is also temporarily mapped to the second player (formerly, it was mapped to the first player).
Given the two above, it's time for a refresh, to find new, sensible, defaults.
There’s a great number of special tiles to be made:
Pressing any of the media keys (volume up/down, play/pause, etc.) on my keyboard crashes the game. The media keys seem to be mapped to their own evdev device, and Fish Fight detects that device as a gamepad.
Environment: Arch Linux 5.14.7, Xfce with Xorg
If you run over it you will “fall”. In DG this results in a hilarious rag-doll state. We’d love to have rag-doll eventually and it’d be fine to play around with it, but it’s certainly not a requirement for the MVP version of Seaweed. I think we just flip the character over just like we do for death.
The new sliding state coming in #35 might also useful here.
You can jump on top of it and you’re fine as long as you have minimal left/right momentum.
Drop any notes you might have, after play-testing, on how to tweak the weapons in the prototype.
In Linux, if a joystick is not connected, /dev/input/js* may not exist. The gamepad-rs
library assumes it always does. The solution is to check the path before starting the joystick thread; if a thread is not started, the respective joystick channel will simply not transport any data.
Since I can't fork/push, here there are the two (git format-patch
) patches; I had to renamed them because of GitHub attachment limitations.
0002-gamepad-rs-Start-joystick-threads-on-Linux-only-when.patch.txt
0001-gamepad-rs-Refactoring-Convert-joystick-block-device.patch.txt
An alternative approach is to return from inside the joystick_thread()
if the path doesn't exist:
0001-gamepad-rs-Exit-immediately-from-joystick-threads-on.patch.txt
Described by @erlend-sh (see here)
It’d also be interesting to see a generalized system for letting it rain projectiles of any weapon.
I.e. a rain of 20:
- grenades
- mines
- jellyfish
Etc.
DG has a rough equivalent to this: explosive item boxes blow out copies of some random weapon.
Simplest version is just vertical, yeah. But there are other ways to spawn the projectiles as well, like through randomly placed portals, that spawn in intervals, with a brief graphical warning ahead of time.
My thinking is just that it should be possible for someone who has just made a weapon to go: “Now I wanna drop this into the Env. system and see what happens.”
DG (and many other games before it) does some fun stuff with death effects that we should definitely do our own spin on. E.g. when a Duck dies by fire it turns into a cooked dish (which can even kill you if it lands on your head)
Please share your ideas for special death effect fitting for a certain cause of death.
Example from @ArcOfDream:
Cause: Heat
Effect: Fish & Chips
In our transition to a p2p multiplayer ready architecture, many of our existing weapons were left out of the big refactor. We need to add them back!
For reference material (and the right person to ask for pointers) check out any of these weapons:
https://github.com/fishfight/FishFight/pulls?q=is%3Apr+is%3Aclosed+label%3Aitem
You can get the most up-to-date version of the items before the refactor on this month old version:
https://github.com/fishfight/FishFight/tree/3ba21b6185114a5c69c791c12fc1e0884bfcb102
Now that we have a way to declare what assets individual items can use, it would be nice to implement a function that serializes the data into a format that could be easily viewable by, say, an artist.
I've been thinking of CSV, as it could be easily opened through Excel or Libreoffice Calc, but maybe something like a little HTML page could work better?
@olefasting is working on a genre-specific Macroquad-framework we could learn a lot from, and possibly even maintain stuff in common at the lightest abstraction layeres: https://github.com/olefasting/rust_rpg_toolkit
Features I’m interested in:
- Easy definition and modification of game data and resources, without having to tuch source code
- Mod support out-of-the-box with modules that can extend or replace a game's data and resources
- RPG mechanics, like character stats, items and an inventory system
Conversion from Tiled maps and instantiation of actors and items from map properties (a light RPG system for level-up access to new cosmetics etc. would be a lot of fun)
- Mission and reward system
For starters I’m most interested in easy game modification. We’re touching on that in #116, and @64kramsystem also made the point a long time ago in chat:
is it worth making the weapons tweakable by non-technical users (I don't know if you're familiar with Rust). for example, if the parameters were in a text file, playtesters could trivially edit the file and see which parameters are the most fun. This is absolutely trivial to implement (on a per-weapon basis).
Currently, there is no CD workflow for automating the release of tarballs/binaries on GitHub releases page. It would be nice to have this since it makes the whole release cycle easier by making it possible to release a new version by just pushing/creating a tag.
Currently all of the assets are hardcoded in the code. e.g:
/// resolves the asset at compile time
const HIT_FX: &str = include_str!("../assets/fxses/hit.json");
/// loads the asset at runtime
let decorations = load_texture("assets/decorations1.png").await?;
Thus, it is not possible to run fishfight
somewhere else other than the cwd
where assets/
is present.
The AUR package copies the assets/
directory to /opt/fishfight/assets
and does the following dirty trick for running fishfight
:
#!/bin/bash
cd /opt/fishfight
./fishfight
Which is not ideal, I think.
This was something I realized while examining the AUR package of fishfight
and my reasoning for creating this issue is basically the same: packaging.
As stated earlier, currently there is no way to specify a path for fishfight
to look for assets. However, I believe this can be changed by checking an environment variable at runtime and overriding the path values in load_{texture,sound,string}
calls. For example,
# build fishfight
CARGO_TARGET_DIR=target cargo build
# create a directory for demonstration
mkdir test_dir/
# move assets into the new directory
mv assets/ test_dir/
# normally this does not work because it cannot find the `assets` directory
./target/debug/fishfight
# this will work because default location for assets directory is being overrided by an environment variable
FISHFIGHT_ASSETS=test_dir/ ./target/debug/fishfight
(In this example we're moving the assets/
directory to another place after building the binary because otherwise it wouldn't be possible to build without having the assets at compile-time. (e.g. due to include_str!
))
So I'm basically proposing to have an environment variable (FISHFIGHT_ASSETS
) for specifying the assets directory at runtime. This change will make the previous launch script look like this:
#!/bin/bash
FISHFIGHT_ASSETS=/opt/fishfight ./fishfight
Overall, I believe this will make packaging and also integration with the other environments much easier.
There will be an environment variable that is going to be checked at runtime and it will be set to .
(current directory) as default:
let assets_dir = std::env::var("FISHFIGHT_ASSETS").unwrap_or_else(|_| String::from("."));
And also the arguments of loader functions will be changed like this:
- let decorations = load_texture("assets/decorations1.png").await?;
+ let decorations = load_texture(&format!("{}/assets/decorations1.png", assets_dir)).await?;
Tell me what you think :) I already have this changes present in my local repository and I'm happy to submit a PR for review soon.
The game does not work well when using the gamepads listed below. Inputs are frequently missed, stuck, or delayed.
Use case:
After playing with a friend over the course of a month, you’d like to know what your total score is for the entire month.
Who actually won the most matches?
Who took the most bo3 series?
Which maps do we have the highest/lowest win percentage on?
Requirements:
Longterm this would also be integrated with Nakama or a similar multiplayer cloud. You should be able to log into your cloud profile by simply entering a short pin code, which gives you read-access to your profile and its item stash.
Shoots bullets; see below.
Described by @erlend-sh (see here)
It’d also be interesting to see a generalized system for letting it rain projectiles of any weapon.
I.e. a rain of 20:
- grenades
- mines
- jellyfish
Etc.
DG has a rough equivalent to this: explosive item boxes blow out copies of some random weapon.
Simplest version is just vertical, yeah. But there are other ways to spawn the projectiles as well, like through randomly placed portals, that spawn in intervals, with a brief graphical warning ahead of time.
My thinking is just that it should be possible for someone who has just made a weapon to go: “Now I wanna drop this into the Env. system and see what happens.”
Some things should not appear upside down when thrown. Notably mines #117. They look silly upside down.
I think we might add a field to ThrowableItem
that communicates this detail. For instance, it could be a rotation vector. Mines would be rotated 90°. Maybe there should also be translation for fine-grained positioning, so that things do not float in the air.
There is a bug in the death coroutine that will make you not respawn if you die on a sproinger (corpse just bouncing up an down, ad infinitum)
I assume this is because the death coroutine waits till player is completely still before it respawns, or something like that.
Grenades were added in #7. They were later removed, but I am going to put them back, fresh and juicy.
It’s currently possible to kill an opponent by throwing a gun at them. This is unintended behavior; only melee weapons like a sword should be lethal when thrown.
The default result from a being hit by a thrown non-lethal object should be a 0.25s stun (play blöb sound) and a Disarm, I.e. if the hit character is holding something, they’ll drop it.
It would be nice to add more platforms/architectures to CI workflow for testing builds and revealing potential cross-platform issues.
Right now we’re shifting our priorities towards all the new areas of work in
However, additional items are always and forever welcome 🤗
They’re also the most documented part of our contributor-friendly surface areas, so it’s probably the easiest place to start, regardless of what other tracks you might be interested in.
If you wanna design your own item, check out any of the [SPEC] examples among our old or new item topics (GH issues) and make your own so we may review it.
The pixel art needed for the weapon will be provided by one of our artists. For the initial version you can just reuse the art of an existing weapon, or use some free placeholder art.
To implement an existing design, look for any open [SPEC] issues, as mentioned above. We prefer it if you tell us by issue-reply or Discord that you’re interested in taking on an open issue, but you don’t have to ask for anyone’s permission. If we’re unlucky and there ends up being a duplication of work due to under-communication, we can always just pivot one implementation into a new direction.
General features
Weapon behaviors
I have two laptops with different hardware but nearly identical software — Arch Linux. On the laptop №1 the game runs fine, but on the laptop №2 it has some sound problems.
% export RUST_BACKTRACE=full
% cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/fishfight`
thread '<unnamed>' panicked at 'Can't set rate.', /home/kindaro/.cargo/registry/src/github.com-1ecc6299db9ec823/quad-snd-0.2.2/src/alsa_snd.rs:54:9
stack backtrace:
0: 0x555b00baedc0 - std::backtrace_rs::backtrace::libunwind::trace::h930cf0be2ce43851
at /build/rust/src/rustc-1.54.0-src/library/std/src/../../backtrace/src/backtrace/libunwind.rs:90:5
1: 0x555b00baedc0 - std::backtrace_rs::backtrace::trace_unsynchronized::he8c90b95546147bf
at /build/rust/src/rustc-1.54.0-src/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x555b00baedc0 - std::sys_common::backtrace::_print_fmt::h2d518076e7529961
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:67:5
3: 0x555b00baedc0 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hc03afe5108b924f5
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:46:22
4: 0x555b00bd057c - core::fmt::write::h03501fd186e1f342
at /build/rust/src/rustc-1.54.0-src/library/core/src/fmt/mod.rs:1110:17
5: 0x555b00ba9225 - std::io::Write::write_fmt::he6bd3203a99cf841
at /build/rust/src/rustc-1.54.0-src/library/std/src/io/mod.rs:1588:15
6: 0x555b00bb0d8b - std::sys_common::backtrace::_print::h6d8d274cdb4b9345
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:49:5
7: 0x555b00bb0d8b - std::sys_common::backtrace::print::hdbba7107ed5db727
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:36:9
8: 0x555b00bb0d8b - std::panicking::default_hook::{{closure}}::h69616457d96cfc5a
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:208:50
9: 0x555b00bb0861 - std::panicking::default_hook::h10bbc125f6ee1853
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:225:9
10: 0x555b00bb1464 - std::panicking::rust_panic_with_hook::h6eb033573a515ade
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:622:17
11: 0x555b00b62974 - std::panicking::begin_panic::{{closure}}::h65c57f58059ea8de
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:542:9
12: 0x555b00b627bc - std::sys_common::backtrace::__rust_end_short_backtrace::h746ac89937dea4ce
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:141:18
13: 0x555b009b07ac - std::panicking::begin_panic::h270725cfc9587c4d
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:541:12
14: 0x555b00b5f60c - quad_snd::snd::setup_pcm_device::h08b37f8cb4bab291
at /home/kindaro/.cargo/registry/src/github.com-1ecc6299db9ec823/quad-snd-0.2.2/src/alsa_snd.rs:54:9
15: 0x555b00b5f60c - quad_snd::snd::audio_thread::hcd9d245f20df7ed5
at /home/kindaro/.cargo/registry/src/github.com-1ecc6299db9ec823/quad-snd-0.2.2/src/alsa_snd.rs:101:22
16: 0x555b00b62804 - quad_snd::snd::AudioContext::new::{{closure}}::h49ee68f5b0d82888
at /home/kindaro/.cargo/registry/src/github.com-1ecc6299db9ec823/quad-snd-0.2.2/src/alsa_snd.rs:152:13
17: 0x555b00b62804 - std::sys_common::backtrace::__rust_begin_short_backtrace::ha4910be306093841
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys_common/backtrace.rs:125:18
18: 0x555b00b607eb - std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}::h7bf2f5a18552903a
at /build/rust/src/rustc-1.54.0-src/library/std/src/thread/mod.rs:481:17
19: 0x555b00b607eb - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::h1c5520255c16006f
at /build/rust/src/rustc-1.54.0-src/library/std/src/panic.rs:347:9
20: 0x555b00b607eb - std::panicking::try::do_call::h9f9747d23dc8fce2
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:401:40
21: 0x555b00b607eb - std::panicking::try::h4e1c3bcecbeb55eb
at /build/rust/src/rustc-1.54.0-src/library/std/src/panicking.rs:365:19
22: 0x555b00b607eb - std::panic::catch_unwind::h6eb715a1a1e27846
at /build/rust/src/rustc-1.54.0-src/library/std/src/panic.rs:434:14
23: 0x555b00b607eb - std::thread::Builder::spawn_unchecked::{{closure}}::h1f3c632a0c1e06b9
at /build/rust/src/rustc-1.54.0-src/library/std/src/thread/mod.rs:480:30
24: 0x555b00b607eb - core::ops::function::FnOnce::call_once{{vtable.shim}}::h1c92d14966cdbae2
at /build/rust/src/rustc-1.54.0-src/library/core/src/ops/function.rs:227:5
25: 0x555b00bb4d07 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::h3cbd4244f09edcd9
at /build/rust/src/rustc-1.54.0-src/library/alloc/src/boxed.rs:1575:9
26: 0x555b00bb4d07 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::h041107f6fd35708c
at /build/rust/src/rustc-1.54.0-src/library/alloc/src/boxed.rs:1575:9
27: 0x555b00bb4d07 - std::sys::unix::thread::Thread::new::thread_start::h4934a766967bcd21
at /build/rust/src/rustc-1.54.0-src/library/std/src/sys/unix/thread.rs:71:17
28: 0x7f6d6716c259 - start_thread
29: 0x7f6d66f485e3 - __GI___clone
30: 0x0 - <unknown>
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Audio thread died
Let me know if there is some other information I should provide.
Now that we have all our essential items queued up, we need to map out the other “main tracks” of development we wanna kick off next. Item dev will always be an available track because there’s an infinite number of items (-variations) to be made.
🎨 👉 We also need main tracks for pixel-art, sounds, level design etc., but we’ll return to those in a few weeks, once the coding tracks are in progress.
🚧 Under Construction: ( edit by @zicklag ) With bevy rewrite, a lot of things have been moved around and we are still getting things stabilized. We're in the middle of documenting and re-organizing so these development tracks may not be 100% accurate at the moment. Feel free to comment, open a discussion, or hop on the Discord if you have questions on how you can contribute!
Upon death, a character should turn into a limp rag doll. So instead of playing a full death animation, player death results in death-face combined with a ragdoll-drop in whichever direction the player character got pushed by a killing force.
This also has implications on our art assets. We’ll want our character assets divided up into a few different body parts that can flail around with the rag doll system.
Some deaths however have special outcomes (new issue coming). E.g. getting killed by curse has its own special animation & effects.
On manually activated rag doll: While this is a fun thing to play around with for advanced players, it doesn’t bring a whole lot to the core game experience. It’s also much harder to avoid all sorts of bugs/exploits if the rag doll state can be manually activated.
It seems that the weapons pickup range extends too high (not sure if this is intended); see video
Jellyfish was initially implemented in PR #36
I'm going to reimplement it back.
The act of crouching or ducking is essential for dodging certain types of high-flying shots, or making sure you’re 99% safe behind a hard platform.
This will obviously necessitate an additional character art pass as well.
Crouching at speed results in a slide. Funnily enough, this will position our fish characters in their much more natural horizontally aligned posture 🐠
cargo run
churns for a bit and then fails to compile with this:
note: /usr/bin/ld: cannot find -lasound
/usr/bin/ld: cannot find -lGL
/usr/bin/ld: cannot find -lX11
/usr/bin/ld: cannot find -lXi
collect2: error: ld returned 1 exit status
Affects #129
While I was working on writing the section for adding an item to the game (I'm using a sniper rifle as an example), I noticed that a lot of the code I was writing for the sniper rifle was directly copying the musket code. I think that we could reduce code and lower the barrier of entry to contributing to the game by generalizing items into categories. For example, instead of having src/items/muscet.rs
we should have src/items/basic_gun.rs
. Then we can create a general gun struct:
pub struct Gun {
pub gun_sprite: GunlikeAnimation,
pub gun_fx_sprite: GunlikeAnimation,
pub gun_fx: bool,
pub bullets: i32,
pub body: PhysicsBody,
pub throwable: ThrowableItem,
pub guntype: GunType,
}
Then we can implement contractors for all the different types of guns.
impl Gun {
...
pub fn spawn_musket(pos: Vec2) -> HandleUntyped {
...
}
pub fn spawn_sniper(pos: Vec2) -> HandleUntyped {
...
}
pub fn shoot(&self, node: Handle<Muscet>, player: Handle<Player>) -> Coroutine {
match self.gun_type {
Sniper => {
...
},
Musket => {
...
},
}
}
...
}
We should also generalize bullets in a similar way.
Overall this will lower the barrier of entry to contributing to the game, because new coders/contributors could start off just modifying the gun struct for their new gun with adjusted values.
I believe shoes was initially implemented in PR #15
I'm going to reimplement them back.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.