Giter Club home page Giter Club logo

box2d.ts's Introduction

@box2d Monorepository

All Contributors

Work in Progress of a full Box2D ecosystem for the web. This includes TypeScript ports of:

Quick Start

This monorepo is in it's early stage, so to get started, you'll have to taka a look at the testbed project for now.

Monorepo Commands:

Most important commands to execute from the root folder (you need yarn installed):

  • yarn -> install dependencies
  • yarn build -> build all projects
  • yarn build:libs -> build only the libraries
  • yarn build:testbed -> build the testbed
  • yarn credit "<username>" <type> -> Add user to all contributors list. Use quotes, as otherwise wrong people get added.
  • yarn start -> Run testbed locally
  • yarn start:fresh -> Run testbed locally after building all libraries freshly
  • yarn bench -> Run the benchmark using node.js
  • yarn bench:web -> Start a webserver for running the benchmarks using a browser,
  • yarn lint -> Run linters, formatters, etc.
  • yarn lint:fix -> Run linters, formatters, etc. and autofix if possible

The @box2d Ecosystem

@box2d is a full-blown ecosystem for box2d for the JavaScript/TypeScript world. It can be used both in the browser and in node.js

Check out demos and compare performance here: https://lusito.github.io/box2d.ts/

Fair Warning: The whole @box2d ecosystem is in an early stage, so it will probably change a lot before we release the first stable version (1.0.0).

Other packages included in the ecosystem:

  • Benchmark: Based on bench2d by joelgwebber
  • Controllers: From the LiquidFun project
  • Particles: Also from the LiquidFun project
  • Lights: ported from LibGDX
  • DebugDraw: Debug drawing using a canvas
  • Testbed: A set of demos, partially ports of the original projects, partially new ones.

Contributing

We're looking for contributors to make this the best place to start with box2d on the web. Check out the project page for more information: https://github.com/Lusito/box2d.ts

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Erin Catto

💻

Isaac Burns

💻 📦

Maxime Veber

💻

finscn

💻

lusito

💻 🚧

Daniel Zhang

🤔

This project follows the all-contributors specification. Contributions of any kind welcome!

box2d.ts's People

Contributors

allcontributors[bot] avatar finscn avatar flyover avatar lusito avatar nek- 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

Watchers

 avatar  avatar  avatar

box2d.ts's Issues

Roadmap to Version 1.0.0

So there are a couple of things I'd like to address before a 1.0.0 release:

  • Find differences to official box2d code (c++ version) and try to merge them if possible. Done via #13
  • Further performance improvements if possible
  • Improve garbage collection
  • Making the code more idiomatic to TypeScript
  • Decide on a naming convention for files, classes, attributes, methods, functions, etc. and apply them to the code
    • Partially discussed in this ticket: #3
  • Code cleanup
    • For example, instead of defining const b2Cos = Math.cos;, use Math.cos instead of b2Cos.
  • Readme files and package.json keywords for all packages for better npm pages.
  • Write documentation and possibly tutorials
  • Clean up comments
  • Take a good look at the current linting rules and which are being disabled in the code. Find ways to make things consistently good.
  • Establish build/publish/release workflow
  • Decide what to do with b2_version, which is currently showing 2.4.0 (just as upstream does). We can't use the same version as box2d upstream, but maybe we want to somehow show which version this is based on? Probably not in code though, rather in readme (0.8.0 => upstream 2.4.1, etc.)

We should create separate issues for each of these in order to keep discussions clean. If an issue doesn't exist yet, create it and I will insert a link in this description.

Evaluate possibilities for further *Def simplifications

In flyovers port, all *Def ports had one interface and one class defined.
In some cases, I was able to make this just an interface, making creation of objects even simpler by just passing an object rather than creating it and adjust its settings. b2FixtureDef is one of those.

There are however other places, where this has not been done yet. Partially, because in some of these cases, inheritance is part of the equation.

Evaluate what can be done to further improve this.

An added benefit might be that we could allow third-party joints if we only required an interface for the JointDef.

Links in documentation don't work on local server

I installed a local server globally:

npm i -g http-server

I downloaded the repository, went to the documentation folder and started the local server:

http-server

Opened the browser and entered the address:

localhost:8080/index.html

There is a page with links: "Benchmarks", "Demos", "Documentation" and "GitHub". But when I try to click "Benchmarks", "Demos", "Documentation" I see these links:

and the message:

image

Evaluate and implement a consistent and safe style for temporary variables.

JavaScript has a garbage collector.. we gotta live with it.

In the original code, temporary vectors and similar where created on the stack without problems.
If we use new objects everytime, we'll just push work for the garbage collector.

Flyover has 2 solutions for this:

  • Making functions take an extra out-parameter
  • Adding static variables to the classes and reusing these variables when doing internal computations.

The former is fine.

The latter, however, is a but ugly to work with and compare code. This also allows to access these static variables from other classes, which flyover does a lot with the b2Vec2 static attributes. This requires you to have a good eye on these to avoid accidental double use.

In order to make the code easier to compare to upstream, I used top-level constants instead in some places, but that approach isn't perfect either:

const temp = {
    J1: new b2Vec2(),
    J2: new b2Vec2(),
    J3: new b2Vec2(),
    r: new b2Vec2(),
    e1: new b2Vec2(),
    e2: new b2Vec2(),
    Jd1: new b2Vec2(),
    Jd2: new b2Vec2(),
    d: new b2Vec2(),
    u: new b2Vec2(),
    dp1: new b2Vec2(),
    dp2: new b2Vec2(),
    dp3: new b2Vec2(),
    d1: new b2Vec2(),
    d2: new b2Vec2(),
    dHat: new b2Vec2(),
};

When I'm talking about double use, I mean something like:

function doStuff(m: b2Vec2, n: b2Vec2, out: b2Vec2) {
    const t = b2Vec2.s_t0.Set(0, 1);
    // ...
    out.x = m.x + n.x + t.x;
    out.y = m.y + n.y + t.y;
    return out;
}

function accidentalDoubleUse() {
    const a = new b2Vec2(1, 2);
    const b = new b2Vec2(2, 3);
    const c = doStuff(a, b2Vec2.Add(a, b, b2Vec2.s_t0), b2Vec2.s_t1);
    return c.y;
}

Both functions use b2Vec2.s_t0, causing loss of data.

The goal of this task would be to evaluate the best approach to encapsulate the temp variables, so they can't easily get used in two places at once.

Then when implementing these changes, ensure, that no public temporary variables get shared over multiple modules.

Convert comments to jsdoc

Blocked by #13 in order to not make it harder than it already is to port upstream code and comments.

Currently, all comments are in a c++ style, which can't be harnessed by vscode and probably other editors.

All comments should be converted to be in jsdoc style. It's not part of this task to add missing jsdoc. Just convert the existing comments.

It might be necessary to adjust the updiff project a bit after this has been done. Not sure if the updiff project is going to be used much after #13 is done. So maybe it's not worth the effort. We'll have to see.

bit flags vs boolean attributes

Flyover converted some of the bit-flags to boolean attributes. Not sure about this. Would be good to investigate:

  • Does this take up more memory?
  • Is it faster/slower than bit manipulation?

Since it does make comparison between upstream source-code and this port a bit harder, I tend to revert that change unless it has some benefit.

Drawing colliders for box2d-core using Pixi.js

This issue is similar to this one: Rotation problem with box2d-core and WebGL

box2d-core has a method to draw vertices without translation and rotation: DrawSolidPolygon(vertices, vertexCount, color) and separate method to set translations and rotations:

    PushTransform(xf) {
        this.translationX = xf.p.x;
        this.translationY = xf.p.y;
        this.angle = xf.q.s * 180 / Math.PI;
    }

I created the lines object in the DebugDrawer class:

    constructor(stage, pixelsPerMeter) {
        this.lines = new PIXI.Graphics();
        stage.addChild(this.lines);

I draw lines but transforms applied on whole lines object:

    DrawSolidPolygon(vertices, vertexCount, color) {
        const c = new PIXI.Color([color.r, color.g, color.b]).toHex();
        this.lines.lineStyle(1, c, 1, 0.5, true);

        this.lines.moveTo((vertices[0].x + this.translationX) * this.pixelsPerMeter,
            (vertices[0].y + this.translationY) * this.pixelsPerMeter);
        this.lines.lineTo((vertices[1].x + this.translationX) * this.pixelsPerMeter,
            (vertices[1].y + this.translationY) * this.pixelsPerMeter);
        this.lines.lineTo((vertices[2].x + this.translationX) * this.pixelsPerMeter,
            (vertices[2].y + this.translationY) * this.pixelsPerMeter);
        this.lines.lineTo((vertices[3].x + this.translationX) * this.pixelsPerMeter,
            (vertices[3].y + this.translationY) * this.pixelsPerMeter);
        this.lines.lineTo((vertices[0].x + this.translationX) * this.pixelsPerMeter,
            (vertices[0].y + this.translationY) * this.pixelsPerMeter);

        this.lines.angle = this.angle;
    }

falling-box-debug-drawer-box2dcore-pixijs-js

Active development

I was wondering, is this still actively being worked on? I might flip my game over that is using fly-over's version of Box2d. Any gotcha's with doing that?

Port upstream code

I've written a simple tool named updiff, which is located in the packages/updiff folder to help with comparing the current state of this project against upstream code of Erin Catto.

I've already ported a lot of the changes in recent upstream version, but during this effort, I improved the tool a lot and it seems I have missed some places.

This is quite stupid work, but it needs to be done: Compare code and port everything that has not been ported yet.

Here's the list of all modules to check:

  • b2_body
  • b2_broad_phase
  • b2_chain_circle_contact
  • b2_chain_polygon_contact
  • b2_chain_shape
  • b2_circle_contact
  • b2_circle_shape
  • b2_collide_circle
  • b2_collide_edge
  • b2_collide_polygon
  • b2_collision
  • b2_common
  • b2_contact
  • b2_contact_manager
  • b2_contact_solver
  • b2_distance
  • b2_distance_joint
  • b2_draw
  • b2_dynamic_tree
  • b2_edge_circle_contact
  • b2_edge_polygon_contact
  • b2_edge_shape
  • b2_fixture
  • b2_friction_joint
  • b2_gear_joint
  • b2_island
  • b2_joint
  • b2_math
  • b2_motor_joint
  • b2_mouse_joint
  • b2_polygon_circle_contact
  • b2_polygon_contact
  • b2_polygon_shape
  • b2_prismatic_joint
  • b2_pulley_joint
  • b2_revolute_joint
  • b2_rope
  • b2_settings
  • b2_shape
  • b2_timer
  • b2_time_of_impact
  • b2_time_step
  • b2_types
  • b2_weld_joint
  • b2_wheel_joint
  • b2_world
  • b2_world_callbacks

I will update the checkboxes when they've been "upstreamed".

Evaluate Build & Publishing Tools

Goal:
It would be nice to have tooling that supports build/release/publish workflows including good changelogs without requiring a steep learning curve, as that prevents people from contributing.

So there are multiple ways to go about this:

  • Manual workflow:
    • Yarn (current setup)
      • supports installs for workspaces
      • Good documentation
      • Comfort shortcuts to execute scripts on one or multiple packages.
      • No publishing helpers
    • NPM v7
      • Very new, not battle-tested
      • supports installs for workspaces
      • documentation scarce
      • No comfort shortcuts like yarn workspace(s) command
      • No publishing helpers
    • todo: research PNPM
    • todo: research additional tooling:
      • semantic-release
      • commitlint
      • auto-changelog
      • release-it
      • ...
  • Advanced workflow:
    • Lerna
      • todo: research pros/cons
    • Rush
      • todo: research pros/cons
  • todo: research more tools

An error occurs when using the SetTransformXY method

@Lusito hi! How are you? I hope you are alive. There was no activity from you for six months.

I am making a simple Pong game. Sandbox: https://plnkr.co/edit/ievETHfAsuARZtzf?preview

I want to set a ball position to zero when it collides with holes:

image

I try to make it in the contact-listener.js file:

         let ballBody = null;

        if (nameA === "leftPointTrigger" || nameB === "rightPointTrigger" ||
            nameA === "rightPointTrigger" || nameB === "leftPointTrigger") {
            if (nameA === "ball") {
                ballBody = fixtureA.GetBody();
            } else {
                ballBody = fixtureB.GetBody();
            }
            ballBody.SetTransformXY(0, 0, 0);
        }

But the error happens when the ball collides with holes at this line: ballBody.SetTransformXY(0, 0, 0); in the contact-listener.js file:

image

Make attributes and methods protected or private again

In flyovers port, almost all members have been made public. Probably due to TypeScript not having a "friend" concept as C++ does.

This should be avoided. Possible alternatives:

  • Using the respective getter/setter methods
  • Introducing actual getter/setter (language feature)
  • Accessing private attributes using the bracket syntax, which bypasses the protection:
class A {
    private x = 0;
}

const a = new A();
a["x"] = 10; // no error

This style should only be used as a last resort internally to imitate the "friend" concept of C++.
I usually only use this in tests, where I want to access/modify data, which is otherwise not allowed to be touched.

Update: After trying this a bit, it causes other issues. Like false detection of unused properties (property is only being written, not being read)

Update 2:
As said in the comments, I've written idtsc to get this working. The core project has been extended with this technique. The other projects might need adjustments as well.

Projects to adjust:

  • controllers
  • core
  • lights
  • particles

As a project developer, I want to be able to render the world to a canvas using a function

The testbed is neat at all, but its only useful for proof of concepts. It also doesnt seem to be exposed anywhere. Which means anyone working on their own project will be unable to visualize their world unless they copypaste all their files into the testbed website.

What I'd prefer is a function to call that renders a world to canvas. (The original box2d.js has this, but that project is old and throws errors in modern environments. The dev also doesnt publish to npm despite having git updates)

I'd like something where I can run everything in a functional way in places that I control:

const initWorld = ()=>{ ... };
const tick = ()=>{
    handleInputs();
    world.step(time);
    renderWorld({ world, canvas });
};

I'm looking through the code, but it seems impossible to figure out how to get this working. I know the functionality is there given that the testbed works. But I dont understand why its not easily available.

I dont particularly care how the api looks. bounds, strokeColor, and strokeSize are good enough for me.
box2d.js has a class structure that probably works decently: https://github.com/kripken/box2d.js/#using-debug-draw

[Proposal] Publishing to NPM

I think it would be a good idea to publish the packages to NPM before a v1.0.0 release. This would give some initial exposure to the beginnings of the Box2d ecosystem, and allow early adopters to test/report issues/give feedback on the API before things have solidified. Versioning everything under 0.x.x and having a disclaimer in the readme should be enough forewarning.

From my fork, I published a few of the packages under the @plane2d organization (due to not having access to @box2d), purely to test the publish workflow. This involved manually running yarn publish for each package, as the global find-replace of all @box2d to @plane2d broke yarn workspaces run build for me.

Ideally, the entire publish workflow can be automated via GitHub actions and triggered on release.

@Lusito Do you own the @box2d organization on NPM? What are your thoughts on releasing to NPM during the initial development phase?

[Solved] The requested module '@box2d/core' does not provide an export named 'b2Draw'

What is wrong with this JavaScript code: https://plnkr.co/edit/uCCFl4gDC4oOygxm

import { b2Draw } from "@box2d/core";
import { gl } from "./webgl-context.js";

// This class implements debug drawing callbacks that
// are invoked inside b2World::Step
export default class DebugDrawer extends b2Draw {

    DrawSolidPolygon(vertices, vertexCount, color) {
        // console.log(vertices);
        // console.log(color);
    }

    PushTransform(xf) {}
    PopTransform(xf) {}
    DrawPolygon(vertices, vertexCount, color) {}
    DrawCircle(center, radius, color) {}
    DrawSolidCircle(center, radius, axis, color) {}
    DrawSegment(p1, p2, color) {}
    DrawTransform(xf) {}
    DrawPoint(p, size, color) {}
}

[Proposal] Remove `b2` prefix from all user-facing APIs

I don't see a benefit of prefixing classes/methods/properties with b2, other than making the API more idiomatic to the original C++ implementation. If a user wants to prefix, they can choose to use a default/namespace import instead of named imports.

This would result in a less verbose, cleaner looking API:

With prefixing:

const gravity = new b2Vec2(0, 0);
const world = b2World.Create(gravity);
// or default import
const gravity = new Box2D.b2Vec2(0, 0);
const world = Box2D.b2World.Create(gravity);

Without prefixing:

const gravity = new Vec2(0, 0);
const world = World.Create(gravity);
// or default import
const gravity = new Box2D.Vec2(0, 0);
const world = Box2D.World.Create(gravity);

Using camelCase for class methods and property names would make the code even more idiomatic to Typescript, but that can be its own discussion.

Clean up comments

Currently, a lot of comments exist, which need to be cleaned up.

  • If it's a description for a class, method, attribute, etc., convert it to jsdoc syntax and make sure it is up to date for this TypeScript version.
  • If it's code that was not commented in original box2d code, implement it (or remove if not needed).
  • If it's a comment in original box2d code, keep it?
  • If the comment explains something about TypeScript or the specifics to this project, keep it.
    • Except if it's bloody obvious
  • Otherwise, remove it.

[Solved] `DrawSolidPolygon` gets wrong collider position

box2d-core 0.10.0
JavaScript

DrawSolidPolygon gets wrong collider position: https://plnkr.co/edit/GU2srU06SAzySUg6

image

I try to set collider position in main.js here:

    const groundBody = world.CreateBody({ type: b2BodyType.b2_staticBody,
        position: { x: groundPosition[0] / pixelsPerMeter,
        y: groundPosition[1] / pixelsPerMeter}});

But I have wrong line positions in debug-drawer.js:

    DrawSolidPolygon(vertices, vertexCount, color) {
        // console.log(vertices);
        // console.log(color);
        mat4.mul(this.projViewMatrix, this.projMatrix, this.viewMatrix);
        gl.uniform3f(this.uColorLocation, color.r, color.g, color.b);
        this.drawLine(vertices[0], vertices[1]);
        this.drawLine(vertices[1], vertices[2]);
        this.drawLine(vertices[2], vertices[3]);
        this.drawLine(vertices[3], vertices[0]);
    }

I ported this example to box2d-wasm v7.0.0 and it works fine: https://plnkr.co/edit/exqhktfXnvxwtBRq

debug-drawer-box2dwasm-js

ReferenceError: performance is not defined

This seems to be originating from the b2Timer class and its usage of performance.now() when @box2d/core is executed from nodejs. A simple fix would be to synchronously require the performance module when running in node>=8.5.

export const performance =
    typeof globalThis.window !== "undefined"
        ? window.performance
        : (require("perf_hooks") as typeof import("perf_hooks").performance;

However, this leads to Module "perf_hooks" not found error when bundling with webpack, unless {externals: {perf_hooks: 'empty'}} is set in the config.

Potential Project Dependant - How to install and Good Fit?

Hey, I didn't see a contact link, so I am adding a not-issue.

I am actively working on an IO game that I am building and I have two question I need answered.

  1. How would I add Box2d as a dependency for an Angular project?
  2. Would Box2D be a good fit for my project?

Projects general premise is:
2D Spaceship combat simulation-lite with planets, gravity, ships etc etc.
Main physics needed: raycasts, impulse, newtonian physics, box collision.

Plz make little note in guide

Plz make little note in guide or jsdoc that Vec2 methods returns self (which usable for chaining) and not clone. I didn't notice it at first, which led to a bug in my code

Feature Request: Implementation of b2Draw, SetDebugDraw and DebugDraw

Please, implement b2Draw, SetDebugDraw, and DebugDraw like it was implemented in pybox2d

edit-gravity-debug-drawer-opengl3-pyqt6

from Box2D import b2Draw
from OpenGL.GL import *


class DebugDrawer(b2Draw):

    def __init__(self, program, worldScale):
        super().__init__()
        self.program = program
        self.WORLD_SCALE = worldScale

    def DrawSolidPolygon(self, vertexes, color):
        print("Polygon. Begin")
        print(vertexes[0][0] * 30, vertexes[0][1] * 30)
        print(vertexes[1][0] * 30, vertexes[1][1] * 30)
        print(vertexes[2][0] * 30, vertexes[2][1] * 30)
        print(vertexes[3][0] * 30, vertexes[3][1] * 30)
        print("Polygon. End")
        self.debugDrawer = DebugDrawer(self.program, self.WORLD_SCALE)
        self.world.renderer = self.debugDrawer
        self.debugDrawer.flags = { 'drawShapes': True,
            'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)
        glBindVertexArray(self.vao)
        self.projViewMatrix = self.projMatrix * self.viewMatrix

        if self.showColliders:
            self.world.DrawDebugData()

Create API Docs

It would be nicer to have API Docs, since I'm confused on how this API works.

Hello World example

Hello!
I don't know if this is a bug or I don't understand something

"dependencies" : "@box2d/core": "^0.10.0"

I try this code

Снимок экрана 2022-09-30 в 00 44 45

console log output
Снимок экрана 2022-09-30 в 00 44 09

Hacktoberfest

It would be nice to list this project in hacktoberfest WDYT ? (it requires adding the tag hacktoberfest to the project)

box2d-core on the server side

I tried running box2d-core on the server side using Node.js:

app.js

import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });

console.log("ok");

Error:

`
E:_Projects\Physics\box2d-core\server-side-box2dcore-webgl-js>nodemon src/server/app.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter rs
[nodemon] watching path(s): .
[nodemon] watching extensions: js,mjs,json
[nodemon] starting node src/server/app.js
E:_Projects\node_modules@box2d\core\dist\common\b2_timer.js:27
this.m_start = performance.now();
^

ReferenceError: performance is not defined
at new b2Timer (E:_Projects\node_modules@box2d\core\dist\common\b2_timer.js:27:24)
at Object. (E:_Projects\node_modules@box2d\core\dist\collision\b2_time_of_impact.js:230:32)
at Module._compile (internal/modules/cjs/loader.js:1072:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
at Module.load (internal/modules/cjs/loader.js:937:32)
at Function.Module._load (internal/modules/cjs/loader.js:778:12)
at Module.require (internal/modules/cjs/loader.js:961:19)
at require (internal/modules/cjs/helpers.js:92:18)
at Object. (E:_Projects\node_modules@box2d\core\dist\index.js:46:14)
at Module._compile (internal/modules/cjs/loader.js:1072:14)
[nodemon] app crashed - waiting for file changes before starting...
`

Feature Request: Add an information to jsDelivr that @box2d/core is JavaScript port too

Box2D beginners with JavaScript skills think @box2d/core is a port of TypeScript when they read the description in jsDelivr. You must add the "JavaScript and TypeScript port of Box2D". Then you will have many more users of your Box2D port, because there are significantly more JavaScript programmers than TypeScript programmers.

image

Like it was made for Planck.js:

image

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.