diff --git a/08.selection-box/devlog.md b/08.selection-box/devlog.md
new file mode 100644
index 0000000..4b42893
--- /dev/null
+++ b/08.selection-box/devlog.md
@@ -0,0 +1,228 @@
+In the [Selectable Object experiment](https://pigdev.itch.io/experiments/devlog/166154/selectable-objects) we've saw how to use Area2D to create an SelectableArea to trigger selection on a single object at a time.
+
+But...in strategy games, especially in the RTS genre, it's more likely that we would want players to select multiple units at once. A common solution for this kind of system is a _SelectionBox_.
+
+![](https://img.itch.zone/aW1nLzQwMDI2NzIuZ2lm/original/9%2Bx2I2.gif)
+
+_Download the SelectionBox experiment!_
+
+
+
+This is the most common approach in many user interfaces, you've probably used such thing with your OS graphic interface.
+
+The SelectionBox is a rectangle that grows towards the mouse selecting everything inside it once we release the left mouse button.
+
+![](https://img.itch.zone/aW1nLzQwMDI2NzMuZ2lm/original/QKXJpf.gif)
+
+In this experiment's approach I'm going to take advantage of the previous experiment's SelectableArea, but once you get the idea you can implement it with any CanvasItem.
+
+## Rect resizing
+
+For this system I'm going to use a [`ColorRect`](https://docs.godotengine.org/en/stable/classes/class_colorrect.html) just to have a decent looking SelectionBox, but you can use any Control node, preferably one that serves pure graphical purposes like a TextureRect.
+
+Then I'll rename it _SelectionBox_ and change the _Color_ property to a transparent blue.
+
+![](https://img.itch.zone/aW1nLzQwMDI2ODUuZ2lm/original/R6RpzM.gif)
+
+Almost everything from here is done code wise, so let's attach a script to it!
+
+The first that we need to do is to detect when the player presses the left mouse button, here I've created an InputAction on the _Project > Project Settings > Input Map_ and called it "selection", it refers to left mouse button input events.
+
+When the player presses the `selection` InputAction we want to reset the Rect's size. We'll need to know where the player clicked, so let's keep the `click_position` stored in a member variable.
+
+```
+extends ColorRect
+
+var click_position = Vector2.ZERO
+
+func _unhandled_input(event):
+ if event.is_action("select"):
+ if event.is_pressed():
+ reset_rect()
+ click_position = get_global_mouse_position()
+
+
+func reset_rect():
+ rect_size = Vector2.ZERO
+```
+
+With the box in place we want to be allowed to scale it while holding the left mouse button and dragging the mouse. For that, we are going to expand the SelectionBox by setting its end point to the mouse position with the `set_end` method.
+
+Since we want to do this smootly whenever the mouse changes its position we are going to `expand_to_mouse`in the `_process` callback.
+
+To prevent this from happening if we are not holding the left mouse button, we can toggle the `_process` callback based on if the `select` action is pressed and start without processing by calling `set_process(false)` at the `_ready` callback.
+
+```
+func _ready():
+ set_process(false)
+
+
+func _unhandled_input(event):
+ if event.is_action("select"):
+ if event.is_pressed():
+ reset_rect()
+ set_process(event.is_pressed())
+
+
+func _process(delta):
+ expand_to_mouse()
+
+
+func expand_to_mouse():
+ var mouse_position = get_global_mouse_position()
+ set_begin(click_position)
+ set_end(mouse_position)
+```
+
+![](https://img.itch.zone/aW1nLzQwMDI2ODcuZ2lm/original/XY3SfT.gif)
+
+## Fixing begin and end points
+
+Now we have a bit of a problem, our SelectionBox only resizes to the right and bottom, i.e. in the third quadrant.
+
+![](https://img.itch.zone/aW1nLzQwMDI2ODguZ2lm/original/yP%2FbEw.gif)
+
+To fix that we need to fix the begin and end points. The idea is that:
+
+- The begin vertical and horizontal axes should be the minimum value between the current mouse position and the click position
+- The end vertical and horizontal axes should be the maximum value between the current mouse position and the click position
+
+Well...for that we can use the `min` and `max` builtin functions to build two new points based on that logic. Our `expand_to_mouse` method should become something like this:
+
+```
+func expand_to_mouse():
+ var mouse_position = get_global_mouse_position()
+
+ var min_point = Vector2.ZERO
+ min_point.x = min(mouse_position.x, click_position.x)
+ min_point.y = min(mouse_position.y, click_position.y)
+ set_begin(min_point)
+
+ var max_point = Vector2.ZERO
+ max_point.x = max(mouse_position.x, click_position.x)
+ max_point.y = max(mouse_position.y, click_position.y)
+ set_end(max_point)
+```
+
+And that should fix that problem!
+
+![](https://img.itch.zone/aW1nLzQwMDI2ODkuZ2lm/original/vvB8xH.gif)
+
+## Selecting selectable stuff
+
+Now, here is where things start to get a bit complicated because is when game systems start to interact with each other and the approaches can become quite _ad hoc-y_.
+
+When we release the left mouse button we want to deselect everything that was selected before and select everything that is selectable.
+
+Why did I say that things get a bit complicated? Simply because I don't know how your selection system works, so you have to guess it yourself. But if you are using my SelectableArea approach you can assume a few things:
+
+- We can toggle a `selected` bool on them
+- We can iterate through a `selected` node group to know what is currently selected
+
+But how do we know what is _selectable_ or not? Well...we can use more groups. By adding SelectableAreas to a `selectable` group we can scope down the objects we need to process to know what can be selected when we release the left mouse button.
+
+![](https://img.itch.zone/aW1nLzQwMDI2NTkucG5n/original/RxoPT9.png)
+
+Knowing the selectable objects available we just need to know if their `global_position` is inside the SelectionBox by using the `has_point` method on the SelectionBox global rectangle.
+
+```
+func select():
+ for selection_area in get_tree().get_nodes_in_group("selectable"):
+ if get_global_rect().has_point(selection_area.global_position):
+ selection_area.exclusive = false
+ selection_area.selected = true
+```
+
+Remember that if a `SelectableArea.exclusive = true` it will deselect other SelectableAreas when its `selected` becomes `true`. So to prevent that we set `exclusive` to `false` before selecting it.
+
+Now, to deselect is about the same process, but we have a scope even narrower. Since SelectableAreas add themselves to a `selected` group we just need to iterate on it and set their `selected` variable to `false`
+
+```
+func deselect():
+ for selection_area in get_tree().get_nodes_in_group("selected"):
+ selection_area.exclusive = true
+ selection_area.selected = false
+```
+
+Finally, we just need to call the `deselect()` method before calling the `select()` when we release the left mouse button and reset it again after we've selected what we want.
+
+```
+func _unhandled_input(event):
+ if event.is_action("select"):
+ if event.is_pressed():
+ reset_rect()
+ click_position = get_global_mouse_position()
+ else:
+ deselect()
+ select()
+ reset_rect()
+ set_process(event.is_pressed())
+```
+
+Since we are resetting the rect when we release the `select` InputAction, we don't need to reset it again when we click, so we can remove it from the `if event.is_pressed()` branch. The final code looks like this:
+
+```
+extends ColorRect
+
+var click_position = Vector2.ZERO
+
+func _ready():
+ rect_size = Vector2.ZERO
+ set_process(false)
+
+
+func _process(delta):
+ expand_to_mouse()
+
+
+func _unhandled_input(event):
+ if event.is_action("select"):
+ if event.is_pressed():
+ click_position = get_global_mouse_position()
+ else:
+ deselect()
+ select()
+ reset_rect()
+ set_process(event.is_pressed())
+
+
+func expand_to_mouse():
+ var mouse_position = get_global_mouse_position()
+
+ var min_point = Vector2.ZERO
+ min_point.x = min(mouse_position.x, click_position.x)
+ min_point.y = min(mouse_position.y, click_position.y)
+ set_begin(min_point)
+
+ var max_point = Vector2.ZERO
+ max_point.x = max(mouse_position.x, click_position.x)
+ max_point.y = max(mouse_position.y, click_position.y)
+ set_end(max_point)
+
+
+func select():
+ for selection_area in get_tree().get_nodes_in_group("selectable"):
+ if get_global_rect().has_point(selection_area.global_position):
+ selection_area.exclusive = false
+ selection_area.selected = true
+
+
+func deselect():
+ for selection_area in get_tree().get_nodes_in_group("selected"):
+ selection_area.exclusive = true
+ selection_area.selected = false
+
+
+func reset_rect():
+ rect_size = Vector2.ZERO
+
+```
+
+
+---
+
+If you have any questions or if something wasn't clear, please leave a comment below. Don't forget to [join the community](https://pigdev.itch.io/experiments/community) to discuss this experiment and more topics as well.
+
+You can also make [requests](https://itch.io/board/791663/requests) for more experiments you'd like to see.
+
+That's it for this experiment, thank you a lot for reading. _**Keep developing and until the next time!**_
diff --git a/08.selection-box/source/Actors/Player.gd b/08.selection-box/source/Actors/Player.gd
new file mode 100644
index 0000000..975f64e
--- /dev/null
+++ b/08.selection-box/source/Actors/Player.gd
@@ -0,0 +1,82 @@
+extends KinematicBody2D
+
+const FLOOR_NORMAL = Vector2.UP
+const SNAP_DIRECTION = Vector2.DOWN
+const SNAP_LENGTH = 32
+const SLOPE_LIMIT = deg2rad(45)
+
+export(float) var speed = 500.0
+export(float) var gravity = 2000.0
+export(float) var jump_strength = 800.0
+
+var direction = Vector2.ZERO
+var velocity = Vector2.ZERO
+var snap_vector = SNAP_DIRECTION * SNAP_LENGTH
+
+onready var sprite = $Sprite
+onready var label = $Label
+
+
+func _ready() -> void:
+ set_process_unhandled_input(false)
+
+
+func _physics_process(delta):
+ move(delta)
+
+
+func _unhandled_input(event):
+ handle_input(event)
+
+
+func handle_input(event):
+ if event.is_action("left") or event.is_action("right"):
+ update_direction()
+ if event.is_action_pressed("jump"):
+ if Input.is_action_pressed("down"):
+ fall_through()
+ else:
+ jump()
+ elif event.is_action_released("jump"):
+ cancel_jump()
+ cancel_fall_through()
+
+
+func move(delta):
+ velocity.y += gravity * delta
+ velocity.y = move_and_slide_with_snap(velocity, snap_vector, FLOOR_NORMAL).y
+ if is_on_floor():
+ snap_vector = SNAP_DIRECTION * SNAP_LENGTH
+
+
+func jump():
+ if is_on_floor():
+ snap_vector = Vector2.ZERO
+ velocity.y = -jump_strength
+
+
+func cancel_jump():
+ if not is_on_floor() and velocity.y < 0.0:
+ velocity.y = 0.0
+
+
+func fall_through():
+ if is_on_floor():
+ set_collision_mask_bit(1, false)
+
+
+func cancel_fall_through():
+ if get_collision_mask_bit(1) == false:
+ set_collision_mask_bit(1, true)
+
+
+func update_direction():
+ direction.x = Input.get_action_strength("right") - Input.get_action_strength("left")
+ velocity.x = direction.x * speed
+ if not velocity.x == 0:
+ sprite.flip_h = velocity.x < 0
+
+
+func _on_SelectableArea2D_selection_toggled(selected):
+ set_process_unhandled_input(selected)
+ label.visible = selected
diff --git a/08.selection-box/source/Actors/Player.tscn b/08.selection-box/source/Actors/Player.tscn
new file mode 100644
index 0000000..95c28f6
--- /dev/null
+++ b/08.selection-box/source/Actors/Player.tscn
@@ -0,0 +1,44 @@
+[gd_scene load_steps=7 format=2]
+
+[ext_resource path="res://Actors/side-scroll-player.svg" type="Texture" id=1]
+[ext_resource path="res://Actors/Player.gd" type="Script" id=2]
+[ext_resource path="res://Actors/SelectableArea.tscn" type="PackedScene" id=3]
+[ext_resource path="res://Interface/label_font.tres" type="DynamicFont" id=4]
+
+[sub_resource type="RectangleShape2D" id=1]
+extents = Vector2( 32, 32 )
+
+[sub_resource type="RectangleShape2D" id=2]
+extents = Vector2( 32, 32 )
+
+[node name="Player" type="KinematicBody2D"]
+collision_mask = 3
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2( 0, -32 )
+shape = SubResource( 1 )
+
+[node name="SelectableArea2D" parent="." instance=ExtResource( 3 )]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="SelectableArea2D"]
+position = Vector2( 0, -32 )
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="."]
+position = Vector2( 0, -32 )
+texture = ExtResource( 1 )
+
+[node name="Label" type="Label" parent="."]
+visible = false
+margin_left = -48.0
+margin_top = -96.0
+margin_right = 48.0
+margin_bottom = -70.0
+custom_fonts/font = ExtResource( 4 )
+text = "selected"
+align = 1
+__meta__ = {
+"_edit_use_anchors_": false
+}
+[connection signal="selection_toggled" from="SelectableArea2D" to="." method="_on_SelectableArea2D_selection_toggled"]
diff --git a/08.selection-box/source/Actors/SelectableArea.gd b/08.selection-box/source/Actors/SelectableArea.gd
new file mode 100644
index 0000000..25837f8
--- /dev/null
+++ b/08.selection-box/source/Actors/SelectableArea.gd
@@ -0,0 +1,30 @@
+extends Area2D
+
+signal selection_toggled(selected)
+
+export var exclusive = true
+
+var selected = false setget set_selected
+
+
+func _input_event(viewport, event, shape_idx):
+ if event.is_action_released("select"):
+ set_selected(not selected)
+
+
+func set_selected(select):
+ if select:
+ _make_exclusive()
+ add_to_group("selected")
+ else:
+ if is_in_group("selected"):
+ remove_from_group("selected")
+ selected = select
+ emit_signal("selection_toggled", selected)
+
+
+func _make_exclusive():
+ if not exclusive:
+ return
+ for selection_area in get_tree().get_nodes_in_group("selected"):
+ selection_area.selected = false
diff --git a/08.selection-box/source/Actors/SelectableArea.tscn b/08.selection-box/source/Actors/SelectableArea.tscn
new file mode 100644
index 0000000..4774278
--- /dev/null
+++ b/08.selection-box/source/Actors/SelectableArea.tscn
@@ -0,0 +1,8 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://Actors/SelectableArea.gd" type="Script" id=1]
+
+[node name="SelectableArea2D" type="Area2D" groups=[
+"selectable",
+]]
+script = ExtResource( 1 )
diff --git a/08.selection-box/source/Actors/side-scroll-player.svg b/08.selection-box/source/Actors/side-scroll-player.svg
new file mode 100644
index 0000000..a695daf
--- /dev/null
+++ b/08.selection-box/source/Actors/side-scroll-player.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/08.selection-box/source/Actors/side-scroll-player.svg.import b/08.selection-box/source/Actors/side-scroll-player.svg.import
new file mode 100644
index 0000000..3b1202d
--- /dev/null
+++ b/08.selection-box/source/Actors/side-scroll-player.svg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/side-scroll-player.svg-f1999ece214d406b010f4a21a872b51b.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Actors/side-scroll-player.svg"
+dest_files=[ "res://.import/side-scroll-player.svg-f1999ece214d406b010f4a21a872b51b.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/08.selection-box/source/Demo.tscn b/08.selection-box/source/Demo.tscn
new file mode 100644
index 0000000..b80f0a7
--- /dev/null
+++ b/08.selection-box/source/Demo.tscn
@@ -0,0 +1,14 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://Levels/Level.tscn" type="PackedScene" id=1]
+[ext_resource path="res://Interface/SelectionBox.tscn" type="PackedScene" id=2]
+
+[node name="Demo" type="Node"]
+
+[node name="LevelLayer" type="CanvasLayer" parent="."]
+
+[node name="Level" parent="LevelLayer" instance=ExtResource( 1 )]
+
+[node name="InterfaceLayer" type="CanvasLayer" parent="."]
+
+[node name="SelectionBox" parent="InterfaceLayer" instance=ExtResource( 2 )]
diff --git a/08.selection-box/source/Interface/Montserrat-ExtraBold.ttf b/08.selection-box/source/Interface/Montserrat-ExtraBold.ttf
new file mode 100644
index 0000000..80ea806
Binary files /dev/null and b/08.selection-box/source/Interface/Montserrat-ExtraBold.ttf differ
diff --git a/08.selection-box/source/Interface/SelectionBox.gd b/08.selection-box/source/Interface/SelectionBox.gd
new file mode 100644
index 0000000..a366453
--- /dev/null
+++ b/08.selection-box/source/Interface/SelectionBox.gd
@@ -0,0 +1,53 @@
+extends ColorRect
+
+var click_position = Vector2.ZERO
+
+func _ready():
+ rect_size = Vector2.ZERO
+ set_process(false)
+
+
+func _process(delta):
+ expand_to_mouse()
+
+
+func _unhandled_input(event):
+ if event.is_action("select"):
+ if event.is_pressed():
+ click_position = get_global_mouse_position()
+ else:
+ deselect()
+ select()
+ reset_rect()
+ set_process(event.is_pressed())
+
+
+func expand_to_mouse():
+ var mouse_position = get_global_mouse_position()
+
+ var min_point = Vector2.ZERO
+ min_point.x = min(mouse_position.x, click_position.x)
+ min_point.y = min(mouse_position.y, click_position.y)
+ set_begin(min_point)
+
+ var max_point = Vector2.ZERO
+ max_point.x = max(mouse_position.x, click_position.x)
+ max_point.y = max(mouse_position.y, click_position.y)
+ set_end(max_point)
+
+
+func select():
+ for selection_area in get_tree().get_nodes_in_group("selectable"):
+ if get_global_rect().has_point(selection_area.global_position):
+ selection_area.exclusive = false
+ selection_area.selected = true
+
+
+func deselect():
+ for selection_area in get_tree().get_nodes_in_group("selected"):
+ selection_area.exclusive = true
+ selection_area.selected = false
+
+
+func reset_rect():
+ rect_size = Vector2.ZERO
diff --git a/08.selection-box/source/Interface/SelectionBox.tscn b/08.selection-box/source/Interface/SelectionBox.tscn
new file mode 100644
index 0000000..6080381
--- /dev/null
+++ b/08.selection-box/source/Interface/SelectionBox.tscn
@@ -0,0 +1,12 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://Interface/SelectionBox.gd" type="Script" id=1]
+
+[node name="SelectionBox" type="ColorRect"]
+margin_right = 100.0
+margin_bottom = 100.0
+color = Color( 0.294118, 0.356863, 0.670588, 0.498039 )
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
diff --git a/08.selection-box/source/Interface/label_font.tres b/08.selection-box/source/Interface/label_font.tres
new file mode 100644
index 0000000..c3ac70b
--- /dev/null
+++ b/08.selection-box/source/Interface/label_font.tres
@@ -0,0 +1,9 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://Interface/Montserrat-ExtraBold.ttf" type="DynamicFontData" id=1]
+
+[resource]
+size = 20
+use_mipmaps = true
+use_filter = true
+font_data = ExtResource( 1 )
diff --git a/08.selection-box/source/Levels/Level.tscn b/08.selection-box/source/Levels/Level.tscn
new file mode 100644
index 0000000..5124759
--- /dev/null
+++ b/08.selection-box/source/Levels/Level.tscn
@@ -0,0 +1,62 @@
+[gd_scene load_steps=5 format=2]
+
+[ext_resource path="res://Actors/Player.tscn" type="PackedScene" id=1]
+[ext_resource path="res://Objects/Platform.tscn" type="PackedScene" id=2]
+
+[sub_resource type="LineShape2D" id=1]
+normal = Vector2( 1, 0 )
+
+[sub_resource type="LineShape2D" id=2]
+normal = Vector2( -1, 0 )
+
+[node name="Level" type="Node2D"]
+__meta__ = {
+"_edit_horizontal_guides_": [ 704.0 ]
+}
+
+[node name="Floor" type="StaticBody2D" parent="."]
+collision_mask = 0
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Floor"]
+polygon = PoolVector2Array( 0, 448, 0, 720, 1280, 728, 1280, 448 )
+
+[node name="Polygon2D" type="Polygon2D" parent="Floor"]
+color = Color( 0.278431, 0.231373, 0.470588, 1 )
+polygon = PoolVector2Array( 0, 448, 0, 720, 1280, 728, 1280, 448 )
+
+[node name="WallLeft" type="StaticBody2D" parent="."]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="WallLeft"]
+shape = SubResource( 1 )
+
+[node name="WallRight" type="StaticBody2D" parent="."]
+position = Vector2( 1280, 0 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="WallRight"]
+shape = SubResource( 2 )
+
+[node name="Platforms" type="Node2D" parent="."]
+
+[node name="Platform" parent="Platforms" instance=ExtResource( 2 )]
+position = Vector2( 384, 224 )
+
+[node name="Platform5" parent="Platforms" instance=ExtResource( 2 )]
+position = Vector2( 288, 304 )
+
+[node name="Platform2" parent="Platforms" instance=ExtResource( 2 )]
+position = Vector2( 704, 96 )
+
+[node name="Platform3" parent="Platforms" instance=ExtResource( 2 )]
+position = Vector2( 960, 288 )
+
+[node name="Platform4" parent="Platforms" instance=ExtResource( 2 )]
+position = Vector2( 640, 352 )
+
+[node name="Player" parent="." instance=ExtResource( 1 )]
+position = Vector2( 160, 448 )
+
+[node name="Player2" parent="." instance=ExtResource( 1 )]
+position = Vector2( 928, 448 )
+
+[node name="Player3" parent="." instance=ExtResource( 1 )]
+position = Vector2( 480, 448 )
diff --git a/08.selection-box/source/Objects/Platform.tscn b/08.selection-box/source/Objects/Platform.tscn
new file mode 100644
index 0000000..50e11ea
--- /dev/null
+++ b/08.selection-box/source/Objects/Platform.tscn
@@ -0,0 +1,16 @@
+[gd_scene load_steps=2 format=2]
+
+[sub_resource type="RectangleShape2D" id=1]
+extents = Vector2( 64, 32 )
+
+[node name="Platform" type="StaticBody2D"]
+collision_layer = 2
+collision_mask = 0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+one_way_collision = true
+
+[node name="Polygon2D" type="Polygon2D" parent="."]
+color = Color( 0.278431, 0.231373, 0.470588, 1 )
+polygon = PoolVector2Array( -64, -32, -64, 32, 64, 32, 64, -32 )
diff --git a/08.selection-box/source/default_env.tres b/08.selection-box/source/default_env.tres
new file mode 100644
index 0000000..20207a4
--- /dev/null
+++ b/08.selection-box/source/default_env.tres
@@ -0,0 +1,7 @@
+[gd_resource type="Environment" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )
diff --git a/08.selection-box/source/icon.ico b/08.selection-box/source/icon.ico
new file mode 100644
index 0000000..8867eed
Binary files /dev/null and b/08.selection-box/source/icon.ico differ
diff --git a/08.selection-box/source/icon.png b/08.selection-box/source/icon.png
new file mode 100644
index 0000000..1bd0665
Binary files /dev/null and b/08.selection-box/source/icon.png differ
diff --git a/08.selection-box/source/icon.png.import b/08.selection-box/source/icon.png.import
new file mode 100644
index 0000000..96cbf46
--- /dev/null
+++ b/08.selection-box/source/icon.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.png"
+dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/08.selection-box/source/icon.svg b/08.selection-box/source/icon.svg
new file mode 100644
index 0000000..bb565ab
--- /dev/null
+++ b/08.selection-box/source/icon.svg
@@ -0,0 +1,126 @@
+
+
diff --git a/08.selection-box/source/icon.svg.import b/08.selection-box/source/icon.svg.import
new file mode 100644
index 0000000..b806afb
--- /dev/null
+++ b/08.selection-box/source/icon.svg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.svg-218a8f2b3041327d8a5756f3a245f83b.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=[ "res://.import/icon.svg-218a8f2b3041327d8a5756f3a245f83b.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/08.selection-box/source/project.godot b/08.selection-box/source/project.godot
new file mode 100644
index 0000000..f597590
--- /dev/null
+++ b/08.selection-box/source/project.godot
@@ -0,0 +1,65 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=4
+
+_global_script_classes=[ ]
+_global_script_class_icons={
+
+}
+
+[application]
+
+config/name="Selection Box"
+config/description="A demo project showing how you can create a Selection Box to select multiple objects at once."
+run/main_scene="res://Demo.tscn"
+config/icon="res://icon.png"
+config/windows_native_icon="res://icon.ico"
+
+[display]
+
+window/size/width=1280
+window/size/height=720
+window/stretch/mode="2d"
+window/stretch/aspect="keep_width"
+
+[input]
+
+select={
+"deadzone": 0.5,
+"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
+ ]
+}
+left={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null)
+ ]
+}
+right={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null)
+ ]
+}
+jump={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
+ ]
+}
+down={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null)
+ ]
+}
+
+[rendering]
+
+environment/default_clear_color=Color( 0.196078, 0.160784, 0.278431, 1 )
+environment/default_environment="res://default_env.tres"