Giter Club home page Giter Club logo

behaviourtoolkit's People

Contributors

dfego avatar sirpigeonz avatar thepat02 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

behaviourtoolkit's Issues

Example Scene to use static typing

I know there will be a new example scene in the future, but I was curious of the setup of current version. It's kinda hard to read for a first-time user (since all nodes have a script attached, even though the script has no logic), but what I want to mention in this issue is that there are function calls which do not point anywhere and are dynamically cast.

On the FSMState "TransformIntoGhost" there is the code

func _on_enter(actor: Node, _blackboard: Blackboard):
	# Make Transparent
	actor.set_modulate(Color(1, 1, 1, 0.5))
	actor.ghost_state_machine.fire_event("fully_transformed")

I cannot ctrl+click set_modulate either.

func _on_enter(actor: Node, _blackboard: Blackboard):
	# Make Transparent
	(actor as Actor).set_modulate(Color(1, 1, 1, 0.5))
	(actor as Actor).ghost_state_machine.fire_event("fully_transformed")

The above is more intuitive imo, and its a codestyle I suggest for the future example scene. After all, the example scene is what convinces a developer whether to use or not

I want to add Selectable 'process_frame' for BTree and FSM + API changes question

Yo :)
I've noticed that BT work on _process() by default. For my use case I will need it to work on physics frame not idle, so I wanted to create PR with functionality to select between IDLE and PHYSICS frames processing as an @export in BTree and FSM.

I poked at Beehave and their master also has it now (althoug AssetLib version doesnt). I would probably implement it in similar way, although they don't provide delta in tick() so users while coding the leafs will have to guess which process the Tree is using.

Thata said, while checking the BT code I've noticed that you store current delta in the Blackboard resource which is fine by me, but is there a reason to not provide it as a property in the tick() ?

Something like:

func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
    return Status.SUCCESS

I think this would be more performant, easier to optimise for GDScript, less error prone from user perspective and easier for user to understand how to use the API.

I also think that default should be PHYSICS_FRAME_PROCESS becasue BTree will most likely by used mostly to modify Actor that is a CollisionObject2D or CollisionObject3D.
And if user would need to run his BTree or FSM for some visual stuff where he want the code to run on every IDLE frame he will simply switch from default PHYSICS process to IDLE in the inspector. :)

What do you think?

BTSequence does not return SUCCESS when the last action is successful until the after first action has run again in some cases.

BTSequence does not return a SUCCESSful status when the last action is successful. Currently it waits for the next tick to reset itself and report success.

While this doesn't appear to be a problem for trivial cases, when a child node of an FSMStateIntegratedBT that is configured to fire an event on success, the event does not get fired until the first task of the sequence has already run. This is particularly problematic if the first task is intended to check conditions based on the current state of the game world.

The 'minimal' scene setup:

  • Node2D
    • FiniteStateMachine
      • FSMStateIntegratedBT # Fires an finished event on success.
        • BTRoot
          • BTSequence
            • ActionA # set a value on the black board and return SUCCESS
            • ActionB # do something for a tick (returning RUNNING) then return SUCCESS on the next tick.
        • FSMTransition # transitions to FSMState below on finished
      • FSMState # Starts a timer _on_enter()
        • FSMTransition # Transitions back to FSMStateIntegratedBT on timeout

Ultimately what will happen is this:

  • ActionA runs
  • ActionB runs
  • ActionA runs
  • FSMState is entered

I would have expected this sequence:

  • ActionA
  • ActionB
  • FSMState is entered
  • ActionA

The offending lines of code appear to be in bt_sequence.gd:

func tick(delta: float, actor: Node, blackboard: Blackboard):
	if current_leaf > leaves.size() -1:
		current_leaf = 0
		return BTStatus.SUCCESS

	var response = leaves[current_leaf].tick(delta, actor, blackboard)

	if response == BTStatus.RUNNING:
		return response
	
	if response == BTStatus.FAILURE:
		current_leaf = 0
		return response

	current_leaf += 1
	return BTStatus.RUNNING

I can put in a PR for a fix, but I really don't have any good way to know if doing so would introduce issues elsewhere. When I see a slightly awkward construction like this, I have to think there is a reason for it.

Add the _on_enter() function to the BTBehaviour class for leaf,composite and etc

I suggest adding the _on_enter(_actor: Node) function to leaf , composite and etc. Since this will make it possible to conveniently change behaviors or parameters in them.
Example:every time the behavior tree reaches BTRepeat, I need to write a number from _actor.rep in repetition and the same situation with LeafWait

C#?

It would be nice if this was easy to use with C#

Convert BehaviourToolKit to use resources and graphic edit

Consider converting behavior toolkit to use graph edit and resources..

Here are the pros of doing so...

  • Behaviours could still be saved and files
  • Behaviours would be resource based so they would be faster
  • Behaviours would be resource based so no more accidentally overriding _physics process. everything is done through your own bt interface.
  • Behaviours would be safer to export as moddable content since users would only have access to what is provided instead of a whole scripting language
  • Fsm events could be predefined and chosen with a dropdown box (no more invalid events)
  • Parent a child relationships could be staticly typed. (no more adding a Transition node as a child to another transition node only State nodes)
  • Actor signals and properties could be type checked.
  • AnimationTree could possibility be used as the node. aka behaviour toolkit root could extended AnimationTreeRoot

Here are the cons...

  • Rewriting everything as a resource and graph edit takes time
  • Might require implementation of some stuff for getting things like input or using physics since there would be no _input or _physics_process methods
  • Behaviors and states that are saved might need to be populated into a registry of some sort so we can create them later in the graph edit.

Debugging/Profiler tools

Your add-on looks very impressive!

Do you plan to make some debugging and profiling tools similar to Beehave ones?

`FiniteStateMachine` only processes one event per frame.

FiniteStateMachine only processes one event per frame.

I'm not sure if this is a bug or if it is intentional, but it was certainly a surprise to me. I was expecting the event stream to complete its processing within a given _process_*() callback. Ultimately this assumption led to some really wonky behaviour and/or delayed transitions as the queue backed up.

I can hack in a solution locally, but if this is intentional I'd rather not build on a hacked solution that breaks fundamental assumptions of the library.

I'm not sure what the intent is here. Could I get some clarity?

Open discussions tab for repo

It would be nice if there was a place to ask questions and discuss behavior toolkit that didn't flood the issues tab.

Loop decorator leaf

Title speaks for itself. It's kinda hard to make loops rn. I know that classic BT doesn't have this but such feature seems reasonable

Tween Leaves

Some general purpose utility leaves for behavior trees would be nice to have. I'm not sure how abstract they can be made given the limitations of Godot's editor(e.g. no support for Variant @export properties).

I think 1 leaf for each node property type that can be tweened would be useful? So, TweenVector3, TweenVector2, TweenInt etc.

Or you could maybe accomplish the same thing with a few Tween leafs for each primitive type in Godot:?

class_name TweenFloatProperty extends BTLeaf

@export var transition_type: Tween.TransitionType = Tween.TransitionType.TRANS_SINE
@export var ease_type: Tween.EaseType = Tween.EaseType.EASE_IN
@export var tween_property: String = "rotation:y"
@export var tween_value: float = 0.0
@export var duration: float = 2.0

var tween : Tween
func tick(actor: Node, _blackboard: Blackboard) -> Status:
	_init_tween(actor)
	if tween.is_running():
		return Status.RUNNING
	return Status.SUCCESS

func _init_tween(actor: Node):
	if tween == null:
		tween = get_tree().create_tween().bind_node(actor)
		tween.set_trans(transition_type)
		tween.set_ease(ease_type)
		tween.tween_property(actor, tween_property, tween_value, duration)

API Change: Provide frame `delta` as a method perameter in `tick()` and `_on_update()`

For now BTree adds it's frame delta to a Blackboard to be accessed in a extended BTLeaf script.
FSM for now doesn't provide frame delta but it's probably a bug :)

Not sure if it have any advantage over providing delta as parameter, it's quite cheap to add to a Blackboard but still slower than direct parameter and less cluncy to retrieve and delta between frames is very common thing to use.
Only reson to store it in Blackboard would be to share it with other system, but BTree and FSM would update it every frame either way so this is not needed and I don't think anybody would want to change it in the middle of evaluating BTree or FSM. That would be a silly thing to do :D

Providing it directly in the method call property would be also much more intuitive for the user, and less stuff to learn from documentation for them.

I was thinking about changing API for tick() and _on_update() to:

func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
    return Status.SUCCESS
func _on_update(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
    return Status.SUCCESS

Other thing maybe unrelated to this proposal (I can make new one if you wish).
Shouldn't tick() be _tick()?

Redesign feature request: Simplify transitions

Problem description

So I have a pretty simple FSM with 4 states: Idle, Walk, FollowUntil (follow enemy until it's not in attack range), Attack.

I want to have an opportunity to make transitions almost from every state to every other state. And sometimes I want to configure some transition using scripts. But it turns out I have to make 4 (states amount) * 3 (other states amount) = 12 transitions. Looks pretty bad... And I have to make even more when I make new states. And it turns out we have geometry progression of transitions...

изображение

Yes, I know we can call switch_state() on FSM to switch states. But it makes transitions uncustomizable. And mixing switch_state() and events are kinda bad decision

Possible solutions

Remove transitions

First thing that comes to mind is to remove transitions at all and make function like _handle_transition(to_state: String) in FSMState template. So you can process needed transitions using code

Smart solution - notify transitions during switch_state()

Ok. So the problem is "I want to change states from one to another and also have opportunity to customize some transitions". To solve this we can make switch_state() the desired way to change states instead of fire_event(). And in switch_state() function we will seek for child transition that satisfies our logic and call _on_transition() of this node if found

Errors after v2.0.1 update

On Windows 11, Godot 4.2.1, I started a new project, imported the plugin via the AssetLib, and see the following errors. It doesn't look like I can use the plugin either, when attempting to create a new node, I'm not seeing any of the types.

Godot Engine v4.2.1.stable.official (c) 2007-present Juan Linietsky, Ariel Manzur & Godot Contributors.
  modules/gltf/register_types.cpp:63 - Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported.
--- Debug adapter server started ---
--- GDScript language server started on port 6005 ---
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Add.svg-b8640946cfefb2cca92e911950570ce6.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Blackboard.svg-99aad113ca567e93eaff49dbc3f77175.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTBehaviour.svg-afa2230ba3707fb234ee9ca9709aead7.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTComposite.svg-412f185ff8fece951b022e38ba5a7c23.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeIntegration.svg-9584b35e5fb929ba98b0a02fb58c84cb.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandom.svg-c18a16f3d816da0799f1e1aa9211e913.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandomSelector.svg-0512a3de5f88f3ca2a3841f24ac587eb.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandomSequence.svg-190695524eac4f2c5cfb58aafe93cfbb.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeSelector.svg-c3f04299814d16ef776f826287ac3a80.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeSequence.svg-1ad4ef7ed8c22330cea4e8cfd8a06ca5.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecorator.svg-a54f8ee76d81f0aada9ae7822177699f.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorFail.svg-972bf6cae2c89e592f736f7d1eb80693.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorLimiter.svg-83cc68457edd2d4d6c5a47d3d203e0d1.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorNot.svg-db308d1bbf533b47c32d25af8f80de5d.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorRepeat.svg-a5c5ef593dd674d9da616e81f0a70c8c.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorSucceed.svg-5ae36e790992843eb08f1aaf9f19c05c.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeaf.svg-394bab6a37a064c62d9109929dce527d.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafCall.svg-0259ff3dd7a45558b84cab026665c30a.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafCondition.svg-555fd5d45040620aff94ac7db2b23380.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafIntegration.svg-974541a1d51285a695521e9140e5e19a.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafPrint.svg-f6f2d7d14c8ddb0bc684a53d76e39548.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafSignal.svg-f98548f09cd6423647caa2b3e0b830a4.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafTween.svg-72f39562bcea332854ab58b3a62fb7e4.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafWait.svg-f454910626932d116ba56d8724164bd1.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTRoot.svg-eacfbd4d2762cc392094c55ff923e78c.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTSimpleParallel.svg-8546d47eb70a7b37aaad191b53aafa06.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/EditorBTRoot.svg-6b6916705e3fa73f7ffe40a77ed65841.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/EditorFiniteStateMachine.svg-e8608d1bbb81a21982b3327f762e9126.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FiniteStateMachine.svg-e73522dd5cc41a5534bd00f4347b88cf.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMState.svg-5a4ec18f1220b396d81ac0c29c407dbb.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMStateIntegration.svg-a2b58c754cdf4634ea934415452099ad.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMStateIntegrationReturn.svg-3b3b086bb57c5145bc7be34e441fba59.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMTransition.svg-03add443dbedecc72086260f8244e911.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Gear.svg-4bd0640c31f268fb47db19b3b4730128.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Help.svg-b760ac21373bc62f0a4da09a57e2f015.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Logo.svg-8cfecbbf805a6ab0b538dbc1ba0eccfd.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/placeholder.svg-d1f5342e31d8125f82f8e7322e2c8be9.editor.meta'
  Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Search.svg-46c789b409eba86b5d04be6ddccfe69c.editor.meta'

Proposal: More Atomic Leaves design - for performance and tree readability

#37 mede me think - if customizable BTLeafs are good thing or is it better to granulate them more into more Atomic nodes?

My first design of LeafSignal only had one task to emit signal to drive code in other game systems built with composition in mind.
It was proposed to add ability to send signals from and Actor which is very usefull as well!
Te bo more coherent with LeafCall it also should support Custom nodes as well...

Issues with current approach

So my first issue is that adding extra functionality would add extra runtime calls for Leaves. With BT being used for complex behaviours of nodes. Usually used (but not only) for AI Actors, that in some games (like in mine) can have large numbers those calls might be in many use cases un-needed and called on every frame D:

Second problem I worry about is that it makes BTree less readable, user either will need to remember, check in inspector or add to nodes name information who the Leaf is calling.

Proposal

My proposal is to split nodes like LeafCall, LeafCondition, LeafSignal etc. into more atomic nodes:

  • LeafActorCall
  • LeafNodeCall
  • LeafBlackboardCall
  • LeafActorCondition
  • LeafNodeCondition
  • LeafBlackboardCondition - (new functionality)
  • LeafSignal
  • LeafActorSignal - (new functionality)
  • LeafNodeSignal - (new functionality)
  • LeafActorTween
  • LeafNodeTween - (new functionality)

Benefits

Aside from performance it has extra benefit of us able to add new icons for them that will describe compactly it's purpose in line with current Behaviour Tookit design. :) So no need for extra info in name, checking inspector, remembering stuff.

Icons design

If we go this route we should talk how to desing icons. I would suggest combining nodes with some sort of generic mini-icon for Actor, Node, Blackboard.

For example LeafActorCall would be current icon with Small A or small triangle in the corner? Maybe also color code the mini-icon or the whole icon?

What next

If approved I would gladly work on this refactor! 😃

If not, I would gladly make my own atomic Leaves for my project, because I will have a lot of actors in my game and I hope it to run on Switch CPU xD (a lot of mobs on the screen at the same time...)

UX Enhancement: Use CTRL and SHIFT and ALT to alter node adding behaviour in the GUI Toolkit

I rly like GUI Toolkit for editing BT behaviours trees and I have idea how to improve it a bit.

Currently pressing Node buttons in Toolkit just adds the respective Node as a child of the selected Node in the Scene Tree.

My problem is this might be not exactly what I want and I have to re-organize Nodes by hand after, which is error prone and takes time.
Example, for Decorators I often woudl want to add them as a parent of the selected node. When adding BTLeaf to Composite nodes I would usually want to add them as next node in line.

I was thinking of extending the behaviour of the Toolkit UI when using keyboard modifiers like SHIFT, ALT and CTRL

Example:
CTRL + ALT + Click = Replace selected node with clicked node. (Double modifier for this one to be more safe from error.)
CTRL + Click = Swap selected node with clicked node in place and add selected node as clicked node child. (Nice for decorators and composites)
SHIFT + Click = Add clicked node as a next sibiling of the selected node. (Usefull for BTLeaf and FSMState so user desn't have to changle selection after editing current one)

To make this more disovarable and easy to remember we could add a strip with hints on the bottom of the Toolkit UI dock.

Rename Status to BTStatus

The Status enum in the BTBehaviour class should be renamed into BTStatus or StatusBT, which will cause extensive renaming in the codebase.

Change Spaces indentation to Tabs

When I open BT scripts they often are corrected by Godot and indentations are auto corrected from spaces to tabs. ^^'

I think we should stick to official conventions and use tabs for GDScript so there will be less issues and hassle with that.

Or maybe you use external editor and it had configured indents as spaces by default?

Remove actor parameter in behavour's in favor of something else

Passing a actor is bad because the actor is of unknown type and in cases of built in scripts or scenes can't be typed.
Also if we rely on actors behaviors could rely on a variable or function that is not on that type of node.
This means that a behavior would either crash or fail in the case a node type is used that is incompatable

Consider one of the following...

  • A monolithic ActorControl, Actor2D and Actor3D type as well as respective BT counter parts
  • A ec base which has components for networking, gui, particles, pathfinding, graphics, colliison, input, and physics
  • A ecs base which has components for networking, gui, particles, pathfinding, graphics, colliison, input, and physics
  • Remove actor parameter and use a event driven appoach (this would mean handling logic through signals)

Godot's design philosophy doesn't help.

Godot 4.2 what is the policy

Ok so we have new Godot, what now?

Are we migrating on it with 2.0, if yes when (after waht PRs will be merged).

And do we make special version of 1.x branch for 4.2?

Input?

How would I handle input via behavior trees?

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.