diff --git a/gdscript.html.markdown b/gdscript.html.markdown
new file mode 100644
index 00000000..ed779c8a
--- /dev/null
+++ b/gdscript.html.markdown
@@ -0,0 +1,321 @@
+---
+language: GDScript
+contributors:
+ - ["Wichamir", "https://github.com/Wichamir/"]
+filename: learngdscript.gd
+---
+
+GDScript is a dynamically typed scripting language made specifically for
+free and open source game engine Godot. GDScript's syntax is similar to
+Python's. Its main advantages are ease of use and tight integration with
+the engine. It's a perfect fit for game development.
+
+## Basics
+
+```nim
+# Single-line comments are written using hash symbol.
+"""
+ Multi-line
+ comments
+ are
+ written
+ using
+ docstrings.
+"""
+
+# Script file is a class in itself and you can optionally define a name for it.
+class_name MyClass
+
+# Inheritance
+extends Node2D
+
+# Member variables
+var x = 8 # int
+var y = 1.2 # float
+var b = true # bool
+var s = "Hello World!" # String
+var a = [1, false, "brown fox"] # Array - similar to list in Python,
+ # it can hold different types
+ # of variables at once.
+var d = {
+ "key" : "value",
+ 42 : true
+} # Dictionary holds key-value pairs.
+var p_arr = PoolStringArray(["Hi", "there", "!"]) # Pool arrays can
+ # only hold a certain type.
+
+# Built-in vector types:
+var v2 = Vector2(1, 2)
+var v3 = Vector3(1, 2, 3)
+
+# Constants
+const ANSWER_TO_EVERYTHING = 42
+const BREAKFAST = "Spam and eggs!"
+
+# Enums
+enum { ZERO, ONE , TWO, THREE }
+enum NamedEnum { ONE = 1, TWO, THREE }
+
+# Exported variables are visible in the inspector.
+export(int) var age
+export(float) var height
+export var person_name = "Bob" # Export type hints are unnecessary
+ # if you set a default value.
+
+# Functions
+func foo():
+ pass # pass keyword is a placeholder for future code
+
+func add(first, second):
+ return first + second
+
+# Printing values
+func printing():
+ print("GDScript ", "is ", " awesome.")
+ prints("These", "words", "are", "divided", "by", "spaces.")
+ printt("These", "words", "are", "divided", "by", "tabs.")
+ printraw("This gets printed to system console.")
+
+# Math
+func doing_math():
+ var first = 8
+ var second = 4
+ print(first + second) # 12
+ print(first - second) # 4
+ print(first * second) # 32
+ print(first / second) # 2
+ print(first % second) # 0
+ # There are also +=, -=, *=, /=, %= etc.,
+ # however no ++ or -- operators.
+ print(pow(first, 2)) # 64
+ print(sqrt(second)) # 2
+ printt(PI, TAU, INF, NAN) # built-in constants
+
+# Control flow
+func control_flow():
+ x = 8
+ y = 2 # y was originally a float,
+ # but we can change it's type to int
+ # using the power of dynamic typing!
+
+ if x < y:
+ print("x is smaller than y")
+ elif x > y:
+ print("x is bigger than y")
+ else:
+ print("x and y are equal")
+
+ var a = true
+ var b = false
+ var c = false
+ if a and b or not c: # alternatively you can use &&, || and !
+ print("This is true!")
+
+ for i in range(20): # GDScript's range is similar to Python's
+ print(i) # so this will print numbers from 0 to 19
+
+ for i in ["two", 3, 1.0]: # iterating over an array
+ print(i)
+
+ while x > y:
+ printt(x, y)
+ y += 1
+
+ x = 2
+ y = 10
+ while x < y:
+ x += 1
+ if x == 6:
+ continue # 6 won't get printed because of continue statement
+ prints("x is equal to:", x)
+ if x == 7:
+ break # loop will break on 7, so 8, 9 and 10 won't get printed
+
+ match x:
+ 1:
+ print("Match is similar to switch.")
+ 2:
+ print("However you don't need to put cases before each value.")
+ 3:
+ print("Furthermore each case breaks on default.")
+ break # ERROR! Break statement is unnecessary!
+ 4:
+ print("If you need fallthrough use continue.")
+ continue
+ _:
+ print("Underscore is a default case.")
+
+ # ternary operator (one line if-else statement)
+ prints("x is", "positive" if x >= 0 else "negative")
+
+# Casting
+func casting_examples():
+ var i = 42
+ var f = float(42) # cast using variables constructor
+ var b = i as bool # or using "as" keyword
+
+# Override functions
+# By a convention built-in overridable functions start with an underscore,
+# but in practice you can override virtually any function.
+
+# _init is called when object gets initialized
+# This is the object's constructor.
+func _init():
+ # Initialize object's internal stuff here.
+ pass
+
+# _ready gets called when script's node and
+# its children have entered the scene tree.
+func _ready():
+ pass
+
+# _process gets called on every frame.
+func _process(delta):
+ # The delta argument passed to this function is a number of seconds,
+ # which passed between the last frame and the current one.
+ print("Delta time equals: ", delta)
+
+# _physics_process gets called on every physics frame.
+# That means delta should be constant.
+func _physics_process(delta):
+ # Simple movement using vector addition and multiplication.
+ var direction = Vector2(1, 0) # or Vector2.RIGHT
+ var speed = 100.0
+ self.global_position += direction * speed * delta
+ # self refers to current class instance
+
+# When overriding you can call parent's function using the dot operator
+# like here:
+func get_children():
+ # Do some additional things here.
+ var r = .get_children() # call parent's implementation
+ return r
+
+# Inner class
+class InnerClass:
+ extends Object
+
+ func hello():
+ print("Hello from inner class!")
+
+func use_inner_class():
+ var ic = InnerClass.new()
+ ic.hello()
+ ic.free() # use free for memory cleanup
+```
+
+## Accessing other nodes in the scene tree
+
+```nim
+extends Node2D
+
+var sprite # This variable will hold the reference.
+
+# You can get references to other nodes in _ready.
+func _ready() -> void:
+ # NodePath is useful for accessing nodes.
+ # Create NodePath by passing String to its constructor:
+ var path1 = NodePath("path/to/something")
+ # Or by using NodePath literal:
+ var path2 = @"path/to/something"
+ # NodePath examples:
+ var path3 = @"Sprite" # relative path, immediate child of the current node
+ var path4 = @"Timers/Firerate" # relative path, child of the child
+ var path5 = @".." # current node's parent
+ var path6 = @"../Enemy" # current node's sibling
+ var path7 = @"/root" # absolute path, equivalent to get_tree().get_root()
+ var path8 = @"/root/Main/Player/Sprite" # absolute path to Player's Sprite
+ var path9 = @"Timers/Firerate:wait_time" # accessing properties
+ var path10 = @"Player:position:x" # accessing subproperties
+
+ # Finally, to get a reference use one of these:
+ sprite = get_node(@"Sprite") as Sprite # always cast to the type you expect
+ sprite = get_node("Sprite") as Sprite # here String gets
+ # implicitly casted to NodePath
+ sprite = get_node(path3) as Sprite
+ sprite = get_node_or_null("Sprite") as Sprite
+ sprite = $Sprite as Sprite
+
+func _process(delta):
+ # Now we can reuse the reference in other places.
+ prints("Sprite has global_position of", sprite.global_position)
+
+# Use onready keyword to assign a value to
+# a variable just before _ready executes.
+# This is a commonly used syntax sugar.
+onready var tween = $Tween as Tween
+
+# You can export NodePath, so you can assign it within the inspector.
+export var nodepath = @""
+onready var reference = get_node(nodepath) as Node
+```
+
+## Signals
+
+Signal system is Godot's implementation of the observer programming
+pattern. Here's an example:
+
+```nim
+class_name Player extends Node2D
+
+var hp = 10
+
+signal died() # define signal
+signal hurt(hp_old, hp_new) # signals can take arguments
+
+func apply_damage(dmg):
+ var hp_old = hp
+ hp -= dmg
+ emit_signal("hurt", hp_old, hp) # emit signal and pass arguments
+ if hp <= 0:
+ emit_signal("died")
+
+func _ready():
+ # connect signal "died" to function "_on_death" defined in self
+ self.connect("died", self, "_on_death")
+
+func _on_death():
+ self.queue_free() # destroy Player on death
+```
+
+## Type hints
+
+GDScript can optionally use static typing.
+```nim
+extends Node
+
+var x: int # define typed variable
+var y: float = 4.2
+var z := 1.0 # infer type based on default value using := operator
+
+onready var node_ref_typed := $Child as Node
+
+export var speed := 50.0
+
+const CONSTANT := "Typed constant."
+
+func _ready() -> void:
+ # function returns nothing
+ x = "string" # ERROR! Type can't be changed!
+ return
+
+func join(arg1: String, arg2: String) -> String:
+ # function takes two Strings and returns a String
+ return arg1 + arg2
+
+func get_child_at(index: int) -> Node:
+ # function takes an int and returns a Node
+ return get_children()[index]
+
+signal example(arg: int) # ERROR! Signals can't take typed arguments!
+```
+
+## Further Reading
+
+* [Godot's Website](https://godotengine.org/)
+* [Godot Docs](https://docs.godotengine.org/en/stable/)
+* [Getting started with GDScript](https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/index.html)
+* [NodePath](https://docs.godotengine.org/en/stable/classes/class_nodepath.html)
+* [Signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html)
+* [GDQuest](https://www.gdquest.com/)
+* [GDScript.com](https://gdscript.com/)
\ No newline at end of file