Git Product home page Git Product logo

scene-manager's Introduction

Godot Scene Manager

Logo

Plugin for managing transitions and Node references between scenes. Expect more features to be added in the future!

Demonstration of Shader Fades


All the README info has been moved to the new wiki!

scene-manager's People

Contributors

jabsatz avatar jecovier avatar jeuler avatar mouring avatar myin142 avatar savovuksan avatar zen14774 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

scene-manager's Issues

Allow for custom animations (besides shader fade images)

Is your feature request related to a problem? Please describe.
Adding custom animations via black-and-white shader images requires a good amount of proficiency in image editing and has several limitations. Godot's built-in animations seem like a relatively easy alternative, and it's also more likely for people to know if they find this addon.

Describe the solution you'd like
Allow pattern/pattern_enter/pattern_leave to take a Godot Animation resource and play it during the specified transition.

Update groups correctly when setting singleton entities

Describe the bug
When clicking the Singleton entity checkbox, the assigned groups do not update correctly in the UI

To Reproduce

  1. Go to any node
  2. Click the Singleton entity checkbox

Expected behavior
The node should be added or removed from the "scene_manager_entity_nodes" group.

This actually happens, and the plugin works correctly, but the UI does not reflect it.

Screenshots
image
Notice in the scene tree at the right, it still marks the node as belonging to a group, even though it does not anymore.

Desktop (please complete the following information):

  • OS: Windows 10

Additional context
Waiting for responses here godotengine/godot-proposals#2925

MAY I HAVE SOME HELP

Everytime i try to run the scene handler i get this error: Attempt to call function 'free' in base 'null instance' on a null instance.

Godot 4: Callbacks when changing scenes

Is your feature request related to a problem? Please describe.
Would like to solve the confusion/issues proposed in #8, without internally setting variables on the new scene in an obscure way.
Also would like to give as much control to the users of this library as possible without bloating it.

Describe the solution you'd like
A "hook" or "callback" sent to SceneManager when the new scene enters the tree and/or becomes ready. It should recieve the new scene and allow for direct modifications there. I'm imagining something like this:

SceneManager.change_scene("res://scene_2.tscn", {
  "on_tree_enter": func(scene): scene.some_variable = "some_value"
})

This would be a great feature to implement when Godot 4 releases, since it makes very good use of the new lambda functions feature.

Additional context
Unfortunately, I don't think there's a very good way to do this in Godot 3.x.
I don't think a FuncRef would work since the original scene that calls this function would most likely already be unloaded, and the logic in a separate static method seems like it would be more of a hassle than just using a regular Autoload or custom solution.
I also considered using "expressions" and evaluating them internally, but that also feels limiting and extremely hacky.

Support scenes ancestry -- go_back()

Is your feature request related to a problem? Please describe.
I've found it convenient to store (on-demand, so it adds new parameters to the scene switch API) the scene ancestry (instead of immediately queue_free), so we can go_back() to the previous scene (and free the current), optionally passing a value.

Describe the solution you'd like
A scene ancestry (a stack), filled if switching to a scene is provided an extra parameter add_current_to_ancestry. And methods in SceneManager to go back in the stack.

Describe alternatives you've considered
I made my own scene manager, and it's terrible.

Godot 3.5 : Error when switching between inherited scenes

Describe the bug
Please note that I am still on Godot 3.5 until my project is over. I do not expect a bug correction on this version, but rather a quick workaround if you know any.

When calling change_scene() between two inherited scenes, the scene replacement works as intended, but an error is shown in the debugger :
image

The error is on the instruction _root.add_child() :
image

Every time I call change_scene, the same error is repeated, but again the scene replacement works as intended.

To Reproduce
On Godot 3.5

  1. Have two Node2D scenes.
  2. Create an inherited scene from each scene (scene -> new inherited scene)
  3. Attach a script to a child scene, then call change_scene from the scene to the other child scene
  4. The scene replacement works as intended, but an error appears in the stacktrace.
  5. Call change_scene multiple times to get multiple errors.
  6. The error does not appear when calling change_scene between non-inherited scenes.

Expected behavior
The scene switch should happen with no error.
I would either like to solve the error, or to know if I can safely keep it.

Screenshots
The code to change scene (event fired from a Node2D collision)
image

The target inherited scene
image

The base scene
image

Desktop

  • Windows 10

Additional context
Godot 3.5

The color of fade doesn't change

Describe the bug
The color of fade doesn't change, I pass the green color and it remains black

To Reproduce

		var options ={	"color": Color("#00ff00"),""pattern": "scribbles", "pattern_leave": "squares"}
		SceneManager.change_scene(path,options)

Expected behavior
fade green screen

Additional context
-Godot v3.4.2

Passing parameters to next scene

I think there is no way currently to pass params to next scene.

Scenario:

  • Scene 1 has a button to open Scene 2.
  • Scene 2 has a few exports like:
    export(String) var some_variable = "some_value"

Here is a proposition how passing parameter(s) to Scene 2 could be done from Scene 1:

	SceneManager.change_scene("res://scene_2.tscn", {
		"scene_params": {
			"some_variable": "another_value"
		}
	})

RFC: Better API for custom animations

Goal

This is an RFC (Request for comments) on improving the custom animations API. We're looking for your thoughts on how you use this feature, and how you think it could be improved. If you have encountered any issues not mentioned here, feel free to comment them as well.

Current overview

Currently, the workflow involves:

  1. Creating a new Scene with an AnimationPlayer as root
  2. Set RESET and custom animations on that player
  3. Manually run SceneManager.set_animation_player(YourAnimationPlayerScene) once, early in your game.

I think the first two steps are good, since they allow users flexibility to move their files around as they please and create the scene as they like it, however the third step seems inconvenient.

It definitely gets the job done, but it creates two things I don't like:

  1. It makes users have to call set_animation_player on a script that is potentially completely unrelated to scene transitions (and potentially makes users have to create a script solely for this purpose)
  2. It adds a somewhat unnecesary API method (since it's only called once by a fraction of users)

Proposed Solutions

I can think of two alternatives that would solve these issues:

Plugin popup solution

There are plugins around which will add custom screens to the godot editor itself to configure plugin settings, such as Dialogic does with their dialogue preview options. We could implement something similar in a much smaller scale (perhaps a simple popup with a text input?) to set the path of the animation_player. We would save this data into a .tres file that is loaded when the game starts, so we instantly pick up the path and load it into SceneManager.

The main disadvantage of this approach is basically the difficulty of implementing it. In my experience doing similar plugins for Godot 3, these sorts of "Editor plugins" are a bit annoying to implement since the developer has to reload the plugin every time they make a change and the changes don't always apply on first try. I'm also not sure if a popup triggered from, for example, one of Godot's menu dropdowns at the top of the editor, can be achieved. The closest I've seen is a new "main screen" (such as the 2D, 3D, Script and AssetLib tabs), which seems a little intrusive and way too big for the use-case I'm describing.

Hardcoded path solution

We could set a "hardcoded" path to the AnimationPlayer scene. This could be something like res://SceneManagerAnimationPlayer.tscn or res://addons/scene_manager/SceneManagerAnimationPlayer.tscn, and we could even have both with the second one as a fallback for the first one. If this was implemented, this would work in addition to the current set_animation_player method, so the user could either use these paths OR set a custom one. This would also allow the (in my opinion) not recommended option of manually modifying the scene_manager code to just add paths directly there.

The disadvantages for this approach are several, it's more of a patch than a solution, since we're only adding a couple of places were users CAN just drop the AnimationPlayer and have it work instantly. However it's much easier to implement and it does solve the issue for some people.

Change scene with PackedScene instead of string

Is your feature request related to a problem? Please describe.
I usually don't like to call the get_tree().change_scene() method because it takes a string. If I ever move or rename the scene I have to find all usages of it and do the same. That's why I always use get_tree().change_scene_to() with a PackedScene. That way it will always be automatically updated whenever I change the path of the scene.

Describe the solution you'd like
Currently only the change_scene() is possible with this plugin. I would be nice if we also have the other option available

Godot 4.0 support

This isn't so much a request, but a future note for when 4.0 comes you can pull back some work and not have to fight through the changes. I've done a quick port in my tree to Godot 4.0. In general the code should be mostly the same. The following changes did occur:

  • shaders now end with .gdshader and refuses to load the old 3.x named .shader
  • assert() takes a static string so you can't do ("foo %s" % var) anymore. I've just stripped the variable replacement for the time being
  • yield -> await
  • Fixed import/onready/tool statements
  • is_abs_path is now is_absolute_path
  • Moved button to non-programmable in example (mainly because I don't fully get callable and connect() feature)

change_scene doesn't work with PackedScene

Describe the bug
change_scene fails when passed a PackedScene as it's looking for a resource path

To Reproduce
Steps to reproduce the behavior:

  1. var scene_path = "res://world.tscn"
  2. var packed_scene = load(scene_path)
  3. SceneManager.change_scene(packed_scene)
  4. Assertion failes: Path must be string in change_scene

Expected behavior
Function as per passing in path

Screenshots
N/A

Desktop (please complete the following information):
N/A

Smartphone (please complete the following information):
N/A

Additional context
Add any other context about the problem here.

Ability to manage fade out and in as independant operations along with more advanced fade_in_place() concept

Is your feature request related to a problem? Please describe.
I need to be able to independently control when to "fade out" and "fade in" occurs. My use case would be calling fade_in_place() to fade out, change the existing scene, and fade in. I don't trust that wait_time will be long enough to trust to do this via signal.

Describe the solution you'd like
I would like a new default_options:

  • "fade_direction": enum { BOTH, IN, OUT } with the default of "BOTH". Where if you select IN or OUT it will only call _fade_in() or _fade_out(). (Can be implemented in 3.x and 4.0)

Describe alternatives you've considered
The fade_direction option could be done with direct API call (how I implemented it originally). e.g. func scene_fade_in(options), func scene_fade_out(options). Which could call _get_final_options() and then the correct _fade_in(..)/_fade_out(..).

This is the code I'm currently using in my project. I suspect the enum {} should be in SceneManagerConstants.gd, but for the simplity I threw it all into SceneManager.gd.

--- ../Scene-Manager/addons/scene_manager/SceneManager.gd	2022-04-06 22:18:59.000000000 -0500
+++ addons/scene_manager/SceneManager.gd	2022-04-07 16:49:41.000000000 -0500
@@ -12,6 +12,13 @@
 @onready var _animation_player := $AnimationPlayer
 @onready var _shader_blend_rect := $CanvasLayer/ColorRect
 
+enum fade_dir {
+	BOTH,
+	NONE,
+	OUT,
+	IN
+}
+
 var default_options := {
 	"speed": 2,
 	"color": Color("#000000"),
@@ -22,6 +29,7 @@
 	"no_scene_change": false,
 	"on_tree_enter": func(scene): null,
 	"on_ready": func(scene): null,
+	"fade_direction" : fade_dir.BOTH,
 }
 # extra_options = {
 #   "pattern_enter": DEFAULT_IMAGE,
@@ -96,11 +104,13 @@
 func change_scene(path: Variant, setted_options: Dictionary = {}) -> void:
 	assert(path == null or path is String, 'Path must be a string')
 	var options = _get_final_options(setted_options)
-	await _fade_out(options)
+	if options["fade_direction"] == fade_dir.OUT or options["fade_direction"] == fade_dir.BOTH: 
+		await _fade_out(options)
 	if not options["no_scene_change"]:
 		_replace_scene(path, options)
 	await _tree.create_timer(options["wait_time"]).timeout
-	await _fade_in(options)
+	if options["fade_direction"] == fade_dir.IN or options["fade_direction"] == fade_dir.BOTH: 
+		await _fade_in(options)
 
 func reload_scene(setted_options: Dictionary = {}) -> void:
 	await change_scene(null, setted_options)

Background loading

Is your feature request related to a problem? Please describe.
I've recently considered handing over scene changing in my game to this addon.
However, I realized that it lacks the ability to load scene in background.
without it it's impossible to show the loading screen when loading a large scene.

Describe the solution you'd like
For now I'm using this approach in my own game. I've left out some parts, like the loading screen actually only appears after a certain amount of time has elapsed since loading:

var _target_scene_path :String
var progress := []

func switch_to_scene_path(scene_path: String):
	#...

	await fade_out()
	_target_scene_path = scene_path
	ResourceLoader.load_threaded_request(scene_path, "PackedScene")
	# Show Loading Screen
	LoadingScreen.show()


func _process(_delta: float) -> void:
	if _target_scene_path == "": return
	
	match ResourceLoader.load_threaded_get_status(_target_scene_path, progress):
		ResourceLoader.THREAD_LOAD_LOADED:
			var new_scene = ResourceLoader.load_threaded_get(_target_scene_path)
			
			# Do stuff here to Hide Loading Screen
			LoadingScreen.hide()

			get_tree().change_scene_to_packed(new_scene)
			_target_scene_path = ""
			await fade_in()			
		ResourceLoader.THREAD_LOAD_IN_PROGRESS:
			# Do stuff here to update Loading Screen
			LoadingScreen.update_progress(progress[0])

Describe alternatives you've considered

N/A

Additional context

N/A

Godot 4: set_shader_param was renamed

In the latest Godot 4 version the addon on branch godot-4.x is not working, searching for the problem, I noticed these lines should be changed from set_shader_param to set_shader_parameter

_shader_blend_rect.material.set_shader_param("dissolve_texture", options["pattern_enter"])
_shader_blend_rect.material.set_shader_param("fade", not options["pattern_enter"])
_shader_blend_rect.material.set_shader_param("fade_color", options["color"])
_shader_blend_rect.material.set_shader_param("inverted", options["invert"])

_shader_blend_rect.material.set_shader_param("dissolve_texture", options["pattern_leave"])
_shader_blend_rect.material.set_shader_param("fade", not options["pattern_leave"])
_shader_blend_rect.material.set_shader_param(

The VideoMemory fill up (loading) is not included in the loading screen.

Is your feature request related to a problem? Please describe.
This is kinda a problem, but more of a nice-to-have.
The VideoMemory fill up (loading) is not included in the loading screen.

So when my Project is getting loaded, it stays at 0%, but in the debugger I can see that the VideoMemory is getting filled (up to nearly 4GB, yeah I got a lot of Textures) and after all is loaded into the VideoMemory, then the percentage are counted up.

Describe the solution you'd like
The percentage should be including that the Video Memory is getting filled.

Describe alternatives you've considered
Maybe a VideoMemoryFillSize variable could be set to like 4GB (the dev need to know how much their going to need) and then maybe we could check how much is already filled.

Additional context
0%
I took a screenshot before the VideoMemory was filled, so you can see it stays for like 30 seconds at 0%.

Im not sure if this is a bug or not.

Describe the bug
Hi, to make it short when i change the scene and go to the next and die it never reloads the current scene. I have a state machine and when im in Die-State after the animation is played it should reload the current scene and when the scene starts from the beginning i go to Spawn-State but it never happens.

To Reproduce
State Machine GD-Quest

Expected behavior
True - get_tree().reload_current_scene()

Screenshots
Video Bellow

Desktop (please complete the following information):

  • OS: Windows 10

Additional context
I tried in the Die-State ( SceneManager.reload_scene() ) but same results. If i go (get_tree().change_scene_to_file()) so no SceneManager to change the scene it works as intended.

2023-06-22.12-29-00.mov

[Docs] Entity Singletons Features example missing options in Godot 4.1.1

Describe the bug
The documentation for https://github.com/glass-brick/Scene-Manager/wiki/Features#entity-singletons is seemingly inaccurate in the gif, I'm thinking it may be relevant to 3.x and not 4.x versions.

I believe this has changed to be relying on a group scene_manager_entity_nodes being applied (rather than the checkbox) and entity_name metadata applied on the node for

Also noting the API docs seem to be referencing the non existent fields https://github.com/glass-brick/Scene-Manager/wiki/API-(Godot-4)#get_entity

I was thinking about editing the wiki myself, but wanted to be sure that my assumptions/investigations were correct before doing so

References to "singleton-like" nodes

Is your feature request related to a problem? Please describe.
One problem we notice frequently is how to get access to certain single objects that should always be available in certain scenes.
This refers to nodes such as the player character (in case we want an enemy to track it's position) or the tilemap that are used in a platformer like game, but could potentially be expanded to other nodes such as checkpoints or other things.

Accessing these via something like get_node('/root/Level1/Player') is pretty easy to break since it depends on the names of both the current scene and the object we want in particular.

Describe the solution you'd like
I'd like to somehow mark certain nodes as "singleton-like" or "important", and have them be accessible from the SceneManager as soon as a new scene is loaded. Something like SceneManager.get_entity('Player') or SceneManager.entities["Player"].

Describe alternatives you've considered
We could potentially implement this manually in a separate singleton, but having the player be re-assigned on scene loading is specially important, since I would always expect this entity to point to the current scene's entity if it exists.

Exported windows binary returns Parse Error

Describe the bug
After export the Project, there are error messages in the debug console and the SceneManager isn't working.
See error in screenshots.

To Reproduce
Steps to reproduce the behavior:

  1. Export:

image
image

Features are empty and Script Export Mode is to Compiled.

SceneManager.change_scene("res://Combat/Combat.tscn")

Expected behavior
Working scene switch

Screenshots

PS C:\Users\Patrick\Desktop> .\test.exe
Godot Engine v3.3.2.stable.official - https://godotengine.org
OpenGL ES 3.0 Renderer: GeForce RTX 2060 SUPER/PCIe/SSE2
OpenGL ES Batching: ON


godot-stuff Logger
https://gitlab.com/godot-stuff/gs-logger
Copyright 2018-2019, SpockerDotNet LLC
Version 3.2-R4

SCRIPT ERROR: GDScript::load_byte_code: Parse Error: Unknown class: "EditorPlugin"
          At: res://addons/scene_manager/SceneManagerPlugin.gdc:1
ERROR: load_byte_code: Method failed. Returning: ERR_PARSE_ERROR
   At: modules/gdscript/gdscript.cpp:785
ERROR: Cannot load byte code from file 'res://addons/scene_manager/SceneManagerPlugin.gdc'.
   At: modules/gdscript/gdscript.cpp:2235
ERROR: Failed loading resource: res://addons/scene_manager/SceneManagerPlugin.gdc. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
SCRIPT ERROR: GDScript::load_byte_code: Parse Error: Unknown class: "EditorPlugin"
          At: res://addons/scene_manager/SceneManagerPlugin.gdc:1
ERROR: load_byte_code: Method failed. Returning: ERR_PARSE_ERROR
   At: modules/gdscript/gdscript.cpp:785
ERROR: Cannot load byte code from file 'res://addons/scene_manager/SceneManagerPlugin.gdc'.
   At: modules/gdscript/gdscript.cpp:2235
ERROR: Failed loading resource: res://addons/scene_manager/SceneManagerPlugin.gdc. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
SCRIPT ERROR: GDScript::load_byte_code: Parse Error: Unknown class: "EditorPlugin"
          At: res://addons/scene_manager/SceneManagerPlugin.gdc:1
ERROR: load_byte_code: Method failed. Returning: ERR_PARSE_ERROR
   At: modules/gdscript/gdscript.cpp:785
ERROR: Cannot load byte code from file 'res://addons/scene_manager/SceneManagerPlugin.gdc'.
   At: modules/gdscript/gdscript.cpp:2235
ERROR: Failed loading resource: res://addons/scene_manager/SceneManagerPlugin.gdc. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
SCRIPT ERROR: GDScript::load_byte_code: Parse Error: Unknown class: "EditorPlugin"
          At: res://addons/scene_manager/SceneManagerPlugin.gdc:1
ERROR: load_byte_code: Method failed. Returning: ERR_PARSE_ERROR
   At: modules/gdscript/gdscript.cpp:785
ERROR: Cannot load byte code from file 'res://addons/scene_manager/SceneManagerPlugin.gdc'.
   At: modules/gdscript/gdscript.cpp:2235
ERROR: Failed loading resource: res://addons/scene_manager/SceneManagerPlugin.gdc. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
SCRIPT ERROR: GDScript::load_byte_code: Parse Error: The class "SceneManagerPlugin" was found in global scope, but its script couldn't be loaded.
          At: res://addons/scene_manager/SceneManager.gdc:215
ERROR: load_byte_code: Method failed. Returning: ERR_PARSE_ERROR
   At: modules/gdscript/gdscript.cpp:785
ERROR: Cannot load byte code from file 'res://addons/scene_manager/SceneManager.gdc'.
   At: modules/gdscript/gdscript.cpp:2235
ERROR: Failed loading resource: res://addons/scene_manager/SceneManager.gdc. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
ERROR: poll: res://addons/scene_manager/SceneManager.tscn:4 - Parse Error: [ext_resource] referenced nonexistent resource at: res://addons/scene_manager/SceneManager.gd
   At: scene/resources/resource_format_text.cpp:440
ERROR: Failed to load resource 'res://addons/scene_manager/SceneManager.tscn'.
   At: core/io/resource_loader.cpp:212
ERROR: Failed loading resource: res://addons/scene_manager/SceneManager.tscn. Make sure resources have been imported by opening the project in the editor at least once.
   At: core/io/resource_loader.cpp:282
ERROR: Can't autoload: res://addons/scene_manager/SceneManager.tscn
   At: main/main.cpp:1774

Desktop (please complete the following information):

  • OS: Windows
  • Godot: v3.3.2.stable.official
  • SceneManager: 0.3.1 (From AssetLib)

Additional context
I removed the chrome and android/ios question. I think this is not a chrome or handy problem :D

I am kind of new in godot and maybe I am missing something, but other addons are working. If I am wrong then sorry :/

Godot 4 - shader parameters warning

Describe the bug
when I use this addon in Godot 4 I got a lot of warnings due to the shader parameters using an old name convention. It's not critical but it can be avoided updating the way this addon sets shader parameters

To Reproduce
Steps to reproduce the behavior:

  1. add this addon to a new project in Godot 4.0.1+
  2. add a transition in a scene
  3. look the debugger console in Godot

Expected behavior
I expect the console doesn't show any addon warning

Screenshots
Captura desde 2023-04-16 06-00-33

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.