Giter VIP home page Giter VIP logo

unity-renderer's Introduction

Decentraland Unity Renderer

This repository contains the reference implementation of the decentraland explorer. It includes two main big components, located in the folders:

  • unity-renderer which contains the main 3D experience and UI
  • browser-interface to connect to the different aspects requiring of a web browser, such as connection with a wallet and WebRTC communications

Running the Explorer

Main Dependencies

  • Install images and binary files using git lfs (git-lfs.github.com). These can be installed from bash or PowerShell by typing:

    git lfs install git lfs pull

  • The Unity engine and IDE, currently using version 2021.3.14f1

  • node.js, version 16 or later

Steps

Check: Multiplatform in Editor

  1. Download and install Unity 2022.3.6f1
  2. Open the scene named InitialScene
  3. Within the scene, select the DebugConfig GameObject.
  4. On DebugConfig inspector, make sure that Base url mode is set to Custom and Base url custom is set to https://play.decentraland.zone/?
  5. Run the Initial Scene in the Unity editor
  6. A browser tab with explorer should open automatically and steal your focus, don't close it! Login with your wallet, go back to Unity and explorer should start running on the Game View.
  7. As you can see, DebugConfig has other special options like the starting position, etc. You are welcome to use them as you see fit, but you'll have to close the tab and restart the scene for them to make effect.

Troubleshooting

Missing git lfs extension

If while trying to compile the Unity project you get an error regarding some libraries that can not be added (for instance Newtonsoft Json.NET or Google Protobuf), please execute the following command in the root folder:

git lfs install
git lfs pull

Then, on the Unity editor, click on Assets > Reimport All


Testing your branch using automated builds

To test against a build made on this repository, you can use a link with this format:

https://play.decentraland.zone/?explorer-branch=<branch-name>

Links for Contributors

  1. Contribution Guidelines
  2. Coding Guidelines
  3. Code Review Standards
  4. Architecture

Advanced debugging scenarios

Running the browser-interface

In order to run browser interface in any platform follow the next instructions

How to run make watch

  1. Open browser-interface with Visual Studio Code
  2. Make sure you have the devcontainers extension installed
  3. Make sure Docker Desktop is running
  4. At Visual Studio Code press F1 execute Reopen in Container and wait for it to finish.
  5. Go to Terminal > New Terminal menu and run make watch command.

How to run browser-interface unit tests

  1. Follow the previous process to run make watch
  2. Open localhost:8080/test in your browser
  3. Watch the results

Debug with Unity Editor + local Browser Interface

Use this approach when working on any features that need both Browser Interface and Unity modifications, and you need to watch Unity code changes fast without the need of injecting a wasm targeted build in the browser.

When the steps are followed, you will be able to test your changes by just pressing the "Play" button within Unity. This will open a tab running the local Browser Interface build and Unity will connect to it using websocket.

This is the most useful debugging scenario for advanced feature implementation.

Steps

  1. Make sure you have the proper Unity version up and running
  2. Make sure you are running browser-interface through make watch command on browser-interface path.
  3. Back in unity editor, open the DebugConfig component inspector of InitialScene
  4. Make sure that the component is setup correctly
  5. Hit 'Play' button

Debug with browsers + local Unity build

This approach works when your Unity modifications run well in the wasm targeted unity build, but you don't want to wait for the CI to kick in. This is also useful for remote profiling.

When the steps are followed, you will be able to run the local Unity build by going to localhost:3000 without the need of CI.

Steps

  1. Make sure you have the proper Unity version up and running
  2. Make sure you are running browser-interface correctly by running npm install, make build-unity-local and make watch commands in that directory and leave that server running.
  3. Produce a Unity wasm targeted build using the Build menu (the build should be named just "unity" to avoid renamings later).
  4. When the build finishes, copy all the files inside the resulting /build folder (unity.loader.js may not be necessary) and paste them inside browser-interface/node_modules/@dcl/explorer.
  5. Run the browser explorer through http://localhost:8080/?ENABLE_WEB3. Now, it should use your local Unity build. Don't mind the white screen at the beginning, that's because the website repo is not being used and it's only loading Browser Interface with the build.
  6. If you need a Unity re-build, you can just replace the files and reload the browser without restarting the make watch process.

Alternatively you can go through these steps after step 3 and load the build locally using localhost:3000

  1. Make sure you have the explorer website repository cloned.
  2. Make sure you have the local website up and running by executing npm run start:linked in the cloned repo directory (npm i first just in case).
  3. When the WebGL build finishes, copy all the files inside the resulting /build folder (unity.loader.js is not necessary as we use a modified loader) and paste them inside explorer-website/node_modules/@dcl/explorer.
  4. Access using localhost:3000

Troubleshooting

MacOS: Missing xcrun

If you get the "missing xcrun" error when trying to run the make watch command, you should download the latest command line tools for macOS, either by downloading them from https://developer.apple.com/download/more/?=command%20line%20tools or by re-installing XCode

MacOS: Build fails throwing System.ComponentModel.Win32Exception (2): No such file or directory...

If the local WebGL build always fails with the error System.ComponentModel.Win32Exception (2): No such file or directory... it's because you are missing Python needed version (MacOS 12.3 onwards removes the previously-integrated python installation). So to solve this issue just install this Python version.

Frameworks and Tools

Technical how-to guides and explainers

Setup CircleCI

Setup CircleCI

Copyright info

This repository is protected with a standard Apache 2 license. See the terms and conditions in the LICENSE file.

unity-renderer's People

Contributors

0xd-fabio avatar 2fd avatar aixacode avatar ajimenezdcl avatar alejandroalvarezmeluccidcl avatar anicalbano avatar d4rwinss avatar dalkia avatar davidejensen avatar eordano avatar fmiras avatar gonpombo8 avatar javiermaria avatar kinerius avatar kuruk-mm avatar leanmendoza avatar lorux0 avatar m3taphysics avatar menduz avatar mikhail-dcl avatar moliva avatar nchamo avatar oozakmckrackenoo avatar pablitar avatar palauidcl avatar pbosio avatar popuz avatar pravusjif avatar rominamarchetti avatar sandrade-dcl 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

unity-renderer's Issues

Add visual tests for Material components and different GLTF materials setups

  • We should add a visual test with the mesh we use in the parcel deployed in ZONE 58,-71, it has different materials with different propeties representing standars configurations

https://play.decentraland.zone/?position=58%2C-71

Also we should add:

  • Visual test for PBRMaterial: A transparent plane with alpha == 1 with opaque objects behind and SSAO enabled. SSAO should not be visible.
  • Visual test for PBRMaterial. At least emission and alpha properties with different values (AlphaTexture set).
  • Visual test for PBRMaterial. AlphaTexture and AlbedoTexture both set with the same texture. The texture has to have different RGB values (i.e. be colored with red green and blue) (to prevent regressions from #283)
  • Visual test for GLTF with transparencies that come from albedo (0.5) and NO alpha texture (to prevent regressions from decentraland/explorer#2328)
  • Visual test for GLTF with transparencies and no emission.

Refactor material components to share more code

We have 2 classes for Material to do practically the same things. We need to extract the common code into a common library.

  • Create Material component visual tests before implementing this refactor

When hot reloading entities sometimes get red tint

Sometimes when you do hot reload, one or several entities get red tint, as if they were outside the scene bounds. The entities are tinted red but they don't have their bounding box marked in red.

This issue is not easy to reproduce, happens inconsistently, likely a race condition. It always gets fixed by manually reloading.

It would seem that in some cases an entity gets first loaded in 0,0,0 and then is still considered out of bounds when positioned in its right place.

We have the theory that this same problem happens occasionally in production, where some entity is randomly not visible in a scene. There were various random irreproducible instances reported in Halloween, where different entities just didn't appear, but reloading fixed it. If this is happening in production, instead of getting the red tint, the entity won't render at all.

How to reproduce?
Take any large scene, and make minor changes so that it hot reloads. After a few (maybe as much as 10 attempts), you'll surely have some entity appear red, as if out of bounds.
For example:
https://github.com/decentraland-scenes/Genesis-Plaza

Other avatars execute walk/jump animation while on moving-platforms

When another player's avatar position changes, the walk or fly animation is executed. This happens even when the avatar is being moved by a moving platform. This also causes any other animation (such as dancing) to stop. Ideally, we would want other avatars to behave as the own avatar, when being moved by a platform.

Use SetUpFixture to encapsulate shared resources in AvatarEditor tests

Due to some optimizations we are using the same AvatarEditorHUDController in different tests. The benefits are obvious, a single initialization of a time consuming UI creation, but due to the current SetUp/TearDown approach, the instance of the controller is not getting collected by the garbage collector and not being disposed.

This "ghost" instance is subscribed to Catalog and reacting to changes on it. Although right now it's not happening, it could lead to some issues in the future whether somebody want to add mock wearables to the Catalog and making the controller instance crash by reacting to them.

To solve it we can use SetUpFixture https://nunit.org/docs/2.6/setupFixture.html. We can instantiate the controller in the Fixture SetUp, run all the tests in the same namespace using the shared controller, and dispose it in the Fixture TearDown.

AvatarEditorHUDControllerShould and AvatarEditorHUDViewShould tests are subject to this improvement, but a project-wide research is needed to check that no instance is ghosting in the background.

After using movePlayerTo the performance drops

I found a small issue with movePlayerTo , after using it the performance drops (using it more than one time don't make it worse, the effect does not accumulate)

Tested on Chrome, GNU/Linux, using the latests ECS version 6.6.0

Before:
Selección_999(1030)

After:
Selección_999(1031)

Code:

const respawner = new Entity()
respawner.addComponent(new BoxShape())
respawner.addComponent(new Transform({ position: new Vector3(8, 0, 8) }))
respawner.addComponent(
  new OnPointerDown(
    (e) => {
      movePlayerTo({ x: 1, y: 0, z: 1 }, { x: 8, y: 1, z: 8 })
    },
    { hoverText: "Move player" }
  )
)

engine.addEntity(respawner)

Test scene, in case that portion of the code is not enough to reproduce the issue:
slow_after_teleport.zip

BoxShape component has no uv values

The BoxShape component can't have its uvs set, to determine how a texture gets wrapped around it.

It would be great to be able to set it just like we do for the PlaneShape, where you can use that to stretch, rotate or tile a texture how you like.

Would be great to also be able to map the inside of the cube, to use as a skymap

Would be great to also have them in other shapes like SphereShape

Related comment from someone in discord:
Please could we gain the option to reverse the texture normals on a primitive SphereShape as the usual -1 scaling tricks do not workaround.
Spheres mapped inside out and viewed from the inside outwards would allow scenes to lever skybox like qualities along with certain essential perks like external/dynamic video mapping. Something which afaik gltf's alone cannot currently match.
The platform already has everything else in place in this regard... only requires reverse mapping to complete.

Confusing name for global configuration: "renderProfile"

Due to the lack of context of explorer.json; the field "renderProfile" doesn't communicate well what it does.

  • It's a 0. Could this mean a boolean value? Is this a disabled feature?
  • Does the "profile" there mean that this disables rendering of other user's Profiles?
  • After taking a look at what it does, it sets night mode as a default when it's set to 1.

I think this is going to be super tricky to understand in the future. After taking a look at what it does, it's an "aha! it's the default rendering profile to be used!". Let's fix this for more understandable configuration:

  • Change the name from "renderProfile" to "defaultDayNightMode", or "defaultEnvironmentalRenderingSetup" (avoiding Profile to prevent confusion with avatars or other people, avoiding Settings because of all the settings the user can select) for the name of the configuration, if we're looking to have more rendering profiles in the future.
  • Change the value from 0 or 1 to "day" and "night" (make it an enumeration in the config, not in the code)

TL;DR: Pay tech debt, turn this

{
  "renderProfile": 1
}

Into this:

{
  "defaultDayNightMode": "night"
}

So it's more understandable for someone modifying the client

Fix UUIDComponent "event-triggered" tests

right now the "event-triggered" tests are explicit (disabled) as they fail even though the events work.

The comment on the tests mention that the PointerEventsController has trouble getting the camera in its RetrieveCamera() but i just debugged a little and I think that's no longer the case but further investigation is needed.

  • Fix "event-triggered" tests and remove the explicit tag and category

Voice chat indicator next to name

With voice chat enabled, the mic icon does not show next to the speaking user and it's very hard to detect where the audio comes from

image

Use local assets or dummy assets for Avatar Tests

Currently the AvatarShape/Renderer/Wearables tests are loading a catalog.json from TestResources.

This catalog is pointing to the assets in production. If something changes in production (like a hash) all the tests will break. To prevent this, a basic set of wearables/bodyshapes must be downloaded and included in the repository and the catalog must point to them.

A texture image is replaced by a red questionmark on white background for certain filenames or path wording.

Some images used as textures show up as red question marks on white, rather than the correct image.
It appears to depend on the wording of the folder name/path containing the image, or on the file name.

I can reproduce it if the path contains a segment of "advertise" or if the filename starts with "YourAdHere".
This does not require my ad blocker to be on for the site, or even enabled, and happens both in preview and in-world.

https://gitlab.com/dcl-tech/texture-issue exemplifies the issue, and the game.ts has commented out lines that show what does and doesn't exhibit this for various filenames of the same file.
I have also seen it where the filename would work, but a segment in the path is "advertise"

Seems to be not too hard to work around once you understand how

AvatarRenderer should be better covered by tests

  • Reactivate Explicit test for AvatarRenderer

Right now, we lack a proper AvatarRenderer testing suite. We should re-organize the class and mock anything necessary to get to a deeper coverage. The aim of this task is to make the avatar loading logic more resilient and prevent invisible wearables bugs and such in the future.

Green blockers get removed before smart items are fully loaded.

Brian:

This can happen in:
ORG -55, 142
ORG 12, 77

As far as I debugged, the builder scenes with smart items have some await statements that makes the scene send incomplete initialization messages. Waiting a bit before sending the remaining messages with all the addEntity and addComponent necessary to complete the scene.

If I force a setTimeout(1000) after the first eval statement in worker code, the remaining messages to load scenes are magically sent. In this interval, no messages come from systems or events, so it should be an await.

Before the rest of messages come, suspicious chest connect logs can be seen.

All the non-smart item objects should be added to the scene in the first frame or the loading lifecycle will fail.

@cazala @moliva

Temporarily scaled entities culled out

Recently, Meteor Chaser suffered from a change that made 1/3 of the meteors stop appearing. After debugging with Rob, I think we found the root.

It's a common trick to scale an entity down to 0.01 scale to keep it hidden before you want to show it. The meteors have a model and animations that take a second to load, so what Rob was doing was he first kept the meteor loaded but super small while it loaded, then enlarged it and animated it.

As a suboptimal workaround, he started to render the meteor up in the air at full scale, but it's quite visible at night.

My suggestion is to reevaluate culling of entities every time there's a scale change.

Some excepts from my conversation with Rob:

Screen Shot 2020-12-29 at 09.56.37.png

Screen Shot 2020-12-29 at 09.57.28.png

Review scene memory limits and how we handle limitations explorer side

Task list:

  • Review existing scene metrics criteria

    • Write RFC and share with the team
  • Gather existing scene metrics

    • Meet with data to obtain quantitative metrics usage
    • Remove material replacement from bounds checker red feedback
    • Add support for texture counting to scene metrics counter
    • Write tool to perform qualitative analysis
    • Implement new memory metrics for textures, meshes, audio clips and animations (WIP)
    • Add support for Billboard counting to metrics
    • Add support for TextShape counting to metrics
    • Fix NFT shape tests, add tests for gif NFTs texture counting.

Fix Bloom postprocessing effect is too bright

The glowing materials are too saturated in the world.
After talking about this issue to @ShibuyaMartin it seems like the world renderer is multiplying the glowing factor much more than expected.

In order to be consistent with what our designers create, we should have a kind of glow adjust model showing many different combinations of colors, textures, and emissivity. Then we should compare how this adjustment model is rendered in different model editors and inside the world, and we should adjust our default values to match as close as possible the editors. We must consider at least https://sketchfab.com/, and possible https://www.blender.org/ and https://www.babylonjs.com/.

UI Hover Feedback disappears on hot reload

This only seems to happen in preview and with relatively large scenes for some reason, or scenes that have something particular in them, haven't found the pattern

If I run this scene once, it sometimes loads fine. If I point at things I see feedback.

Screen Shot 2020-12-22 at 09.48.59.png

Change something in the source code for hot reload to kick in, and the feedback is gone. Same item, same distance, same everything.
If I click the entity, it will execute its click behavior correctly, I just don't have the hover feedback. If I reload the browser manually, it often gets fixed.

Screen Shot 2020-12-22 at 09.49.39.png

With this scene, I see it happen 100% of the time with all clickable entities.

https://github.com/decentraland-scenes/Xmas_Plaza

Check the standalone branch of this repo for the most updated version.

(ask me (Nico E) for access if you can't open)

I'm using a Mac & Chrome when I see this happen.

Thumbnail gender override for unisex wearables

Be able to create an NFT for both male and female, e.g. with very similar design and slight gender differences, and that display two different gender versions for the thumbnail.

   thumbnail : "dcl:://asdasdasd/generalThumbnail"
   representations : [
     {
        id : "BaseMale"
        thumbnailOverride : "dcl:://asdasdasd/maleThumbnail"
     }.
     {
        id : "BaseFemale"
        thumbnailOverride : "dcl:://asdasdasd/FemaleThumbnail"
     },
     {
        id : "Robot"
        thumbnailOverride : ""
     }
  ]
}```

![image.png](https://images.zenhubusercontent.com/5d91dca0703cca0001efbe30/99c5f190-de1b-4285-bc73-09910249ce8b)

Any running animations need to be stopped before playing a new one

If I play an animation and then I want to play another animation, or the same animation again, I need to first explicitly stop the last played animation. It's a very common newbie pitfall, they aren't able to play an animation a second time, and the reason is that they need to stop the animation explicitly before they call it again.

This doesn't work

sit.play()

Input.instance.subscribe('BUTTON_DOWN', ActionButton.POINTER, true, (e) => {
  sit.play()
}

When dealing with a model that has several animations that may have ben called before, the workarounds needed for this can get really nasty.
See this example:
https://github.com/decentraland-scenes/Block-dog

Here you need to explicitly stop all these animations every time before you want to play another one
sit.playing = false
stand.playing = false
walk.playing = false
drink.playing = false
idle.playing = false
stand.playing = false

This issue has been around ever since we migrated away from Babylon. Back when HardlyDifficult did the escape room tutorial (April 2019), he avoided mentioning the workaround for this bc it was a bug we were supposedly going to fix by the time the videos were released. ....sure.

Allow scene music to be heard from nearby scenes

Right now, some scene music/broadcasting is not being heard from the contiguous scene. It would be desirable that we change that behavior (using 3D positioning of the sound). We could make it so that the scene.json can disable the music from neighbouring scenes (in case I have a noisy neighbor).

External links don't open from global E or F buttons

Opening external links is a restricted action that intentionally can only be triggered from a user's action to avoid spamming.

We allowed it to be called from OnPointerDown events and it seems also from click events
BUT, it's reported that it can't be called from a global E or F event.

This seems arbitrarily inconsistent. It's for example a good use case to be able to call an external link from an NPC interaction, and there it would work with E and F global events too.

As reported, this works:

Input.instance.subscribe('BUTTON_DOWN', ActionButton.POINTER, true, (e) => {
  openExternalURL("www.google.com")
}

This doesn't:

Input.instance.subscribe('BUTTON_DOWN', ActionButton.PRIMARY, true, (e) => {
  openExternalURL("www.google.com")
}

The avatar snapshot is not being loaded for new users

Whenever a new user enters the world for the first time, his avatar face snapshot is never loading and the avatar HUD stay in "loading" state indefinitely:

image

The only way to avoid this issue is opening the AvatarEditorHUD and click on DONE button. From that moment on the avatar face snapshot loads always correctly.

STEPS TO REPRODUCE IT:

  1. Create a new Metamask account.
  2. Enter the world with this new user.
  3. Notice the issue.

NOTE: Debugging the code I noticed that the problem is that the profile that is being sent to Unity during the LoadProfile() event contains invalid snapshot urls. For example, something like this: https://peer-eu1.decentraland.org/content/contents/QmVrwSKEt4W4RovVhQbNTZxu4XNHfjVrs5QF3vjML59SaF. Then Unity try to resolve this url and fail.

Missing fonts

This bug is being reproduced again. No clear steps or repro rate.

Specs: Windows + Chrome + GeForce gtx 1080 ti

image.png

Marc O Matic wearables are not shown

One of our Users is reporting errors while trying to use a Marc o Matic wearable.

This is the log he's receiving in the js console:

An abnormal situation has occurred: the PlayerLoop internal function has been called recursively. Please contact Customer Support with a sample project so that we can reproduce the problem and troubleshoot it. 
(Filename:  Line: 377)
rollbar.min.js:2 OpenGL Error: Invalid texture unit! 
(Filename:  Line: 72)
this right?
inside the abnormal playerloop it says
r.<computed>    @    rollbar.min.js:2
_JS_Log_Dump    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8
(anonymous)    @    06dc05fe:0x20218b
(anonymous)    @    06dc05fe:0x2020ba
(anonymous)    @    06dc05fe:0x201da4
(anonymous)    @    06dc05fe:0x20123f
(anonymous)    @    06dc05fe:0x468271
(anonymous)    @    06dc05fe:0x46643c
(anonymous)    @    06dc05fe:0x478bf1
dynCall_vi    @    06dc05fe:0x1796fb3
(anonymous)    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8
dynCall    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8
dynCall_wrapper    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8
wrapper    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8
(anonymous)    @    e62eb3f0-7954-483b-8567-d1ec963b89ef:8

Sell item wrong URL

When clicking sell CTA on any collectible item, it took the players to their assets URL on the marketplace when it should be taking them directly to the wearable URL instead.Screen Shot 2020-08-31 at 10.16.01.png

Nav map update

  • Coordinates should still visible near the map cursor when the scene card is opened.

  • For scenes without name or image, show the default image and "Untitle Scence" if those fields are empty.

  • Remove coords and scene description from the card (let's discuss coords. May be we should keep this info if the card overlaps the cursor plus coords reference on the map).

  • Add ongoing event tag (ray icon+"now" copy with blue background).

  • If a creator of a scene doesn't exist, don't show it.

Screen Shot 2020-09-15 at 16.41.22.png

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.