diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,9 +1,11 @@
 # Changelog for S.P.A.D.E
 
-## Unreleased
+## 0.2.0.0
 
 * Fix space leak when updating arrays and maps.
 * Fix redraw overlap when `log` function is used.
+* Add more grahics functions.
+* Added more documentation content.
 
 ## 0.1.0.9
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -115,6 +115,17 @@
 
 Will execute the program without opening the IDE.
 
+### Packaging
+
+From repo root,
+```
+cd docker
+docker build . -t spade-packaging
+cd ..
+source docker/run-build.sh
+```
+
+
 ### Reporting bugs/issues
 
 Please use the issue tracker [here](https://bitbucket.org/sras/spade/issues).
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -5,7 +5,7 @@
 import Control.Concurrent.STM
 import Control.Monad
 import Control.Monad.IO.Class
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Text.IO as T
 import Main.Utf8 (withUtf8)
 import Paths_spade (version)
diff --git a/docs/functions/graphics.md b/docs/functions/graphics.md
--- a/docs/functions/graphics.md
+++ b/docs/functions/graphics.md
@@ -53,6 +53,17 @@
 line(100, 100, 200, 200)
 ```
 
+#### arrow
+
+Draws an arrow from the specified co-ordinates. First and second arguments represents x and y co-ordinates of the starting point, and the third and fourth arguments represents co-ordinates of the end point.
+The next two arguments decide the length and breadth of the arrow tip. Last optional boolean argument decides if the arrow tip is filled or not.
+
+Example:
+
+```
+arrow(100, 100, 200, 200, 20, 20)
+```
+
 #### lines
 
 Draws a sequence of lines from a list of points. Each point is represented by a list of two numbers, first one representing the x coordinate and the second one representing the y-coordinate.
@@ -128,14 +139,22 @@
 
 Sets the current background color using red, green and blue component values. The function #link: clearscreen# will use this color to clear the screen.
 
-#### setcolor
+#### mkcolor
 
-Sets the current drawing color using red, green and blue component values.
+Gets a color value using red, green and blue component values.
 
-#### setcolora
+#### mkcoloralpha
 
-Sets the current drawing color using red, green, blue and transparency component values.
+Gets a color value using red, green, blue and alpha/transparency component values.
 
+#### splitcolor
+
+Splits a color value into ints red,green,blue and alpha components. Returns an object with "red", "gree", "blue" and "alpha" keys.
+
+#### setcolor
+
+Sets the current drawing color using a color value obtained using mkcolor
+
 #### clearscreen
 
 Fills the graphics screen with current background color.
@@ -164,9 +183,9 @@
 
 Sets the logical size of the display, so that things being drawn on screen are scaled to fit the entire dimensions of actual display. Check #link: Graphics and Animation# to read more about using this function.
 
-#### gwaitforkey
+#### waitforkey
 
-Suspends the program till a key is pressed when the graphics window has focus. Use #link: waitforkey#
+Suspends the program till a key is pressed when the graphics window has focus. Use #link: waitforterminalkey#
 to wait for key press when running in a terminal window.
 
 
diff --git a/docs/functions/list.md b/docs/functions/list.md
--- a/docs/functions/list.md
+++ b/docs/functions/list.md
@@ -100,6 +100,15 @@
 getkey()
 ```
 
+#### sort
+
+Sorts the input list
+
+#### sorton
+
+Sorts the input list by using a callback. Callback should return a comparable (number or string)
+value and the list will be sorted based on that.
+
 #### size
 
 Returns the number of items in a list or a dictionary.
diff --git a/docs/functions/math.md b/docs/functions/math.md
--- a/docs/functions/math.md
+++ b/docs/functions/math.md
@@ -41,6 +41,14 @@
 
 Power of function.
 
+#### sqrt
+
+Optimized function to compute squre roots.
+
+#### abs
+
+Returns the absolute value of a number.
+
 #### hash
 
 Computes the hash using algorith specified and of input bytes. Right now only support following algorithms.
diff --git a/docs/functions/misc.md b/docs/functions/misc.md
--- a/docs/functions/misc.md
+++ b/docs/functions/misc.md
@@ -146,14 +146,14 @@
 Gets the screen/terminal size. Returns an object with
 "width" and "height" keys.
 
-#### waitforkey
+#### waitforterminalkey
 
-Waits for the user to press a key when the graphics window is in focus.
+Waits for the user to press a key.
 
 Example:
 
 ```
-waitforkey()
+waitforterminalkey()
 ```
 
 
diff --git a/docs/language-reference.md b/docs/language-reference.md
--- a/docs/language-reference.md
+++ b/docs/language-reference.md
@@ -187,7 +187,7 @@
 
 #### for statement
 
-This loop can be used to execute some group of statements repeatedly, while incrementing a variable at each iteration.
+The for loop can be used to execute some group of statements repeatedly, while incrementing a variable at each iteration.
 
 Example:
 
@@ -208,6 +208,43 @@
 
 The start/end/step value can be either interger or fractional. The break statement can be used to break out of the loop.
 
+#### foreach statement
+
+The foreach loop can be used to get each value in an array or dictionary one by one. When used with
+array, foreach loop will assign each value in the array to the loop variable,
+for every loop execution. When used with dictionary the foreach loop will assign a dictionary to the loop
+variable. This will contain the key as well as the value for each item in the dictionary. The
+key will be available under the "key" key, and value under "value" key.
+
+Example for array:
+
+```
+foreach [1,2,3] as i
+  println(i)
+endforeach
+waitforkey()
+```
+
+This will print the following:
+
+1
+2
+3
+
+Example for dictionary:
+
+```
+foreach {age: 15, name: "John"} as o
+  println(o.key, ":", o.value)
+endforeach
+waitforkey()
+```
+
+This will print the following:
+
+age: 15
+name: John
+
 #### while statement
 
 This loop execute a group of statements repeatedly as long as the specified condition hold.
@@ -339,7 +376,7 @@
 `*` : multiplication operator
 `/` : division operator
 
-##### Boolean operators
+##### Binary operators
 
 `<`   : less than
 `>`   : greater then
diff --git a/docs/toc.md b/docs/toc.md
--- a/docs/toc.md
+++ b/docs/toc.md
@@ -21,7 +21,7 @@
     #link: Conditional expression#
     #link: Binary expression#
       #link: Numeric operators#
-      #link: Boolean operators#
+      #link: Binary operators#
     #link: Function calls#
     #link: Index access#
     #link: Key access#
@@ -31,6 +31,7 @@
     #link: if-then-elseif-else#
   #link: Loops#
     #link: for statement#
+    #link: foreach statement#
     #link: while statement#
     #link: loop statement#
   #link: Scoping#
diff --git a/samples/concurrency.spd b/samples/concurrency.spd
--- a/samples/concurrency.spd
+++ b/samples/concurrency.spd
@@ -1,10 +1,22 @@
 proc thread1(r)
-  for i = 1 to 500
+  for i = 1 to 10000
     let rv = readref(r)
     writeref(r, (rv + 1))
   endfor
 endproc
+loop
 let ref = newref(0)
-let t = startthread(thread1)
+let t = startthread(thread1, ref)
+let t2 = startthread(thread1, ref)
+let t3 = startthread(thread1, ref)
+let t4 = startthread(thread1, ref)
+
+
 await(t)
-print(readref(ref))
+await(t2)
+await(t3)
+await(t4)
+
+println(readref(ref))
+endloop
+waitforkey()
diff --git a/samples/gravity.spd b/samples/gravity.spd
new file mode 100644
--- /dev/null
+++ b/samples/gravity.spd
@@ -0,0 +1,105 @@
+graphics(true)
+let ws = getwindowsize()
+let sunx = (ws.width / 2 + 0)
+let zoom = 1
+let suny = (ws.height / 2)
+let sun_radius = 50
+let sun_velocity = [0, 0]
+let planet_locations = [[100, 400, 0, 0], [130, 400, 0, 0], [150, 400, 0, 0]]
+let planet_velocities = [[3.5, -2.9], [3.8, -2.9], [3.9, -2.9]]
+-- let planet_velocities = [[0,0 ], [0, 0], [0, 0]]
+
+let forces_on_sun = [[0, 0], [0, 0], [0, 0]]
+let net_force_on_sun = [0.0, 0.0]
+let paused = false
+let lastpause = 0
+let planet_mass = 6000
+let sun_mass = 50689500
+let vec_magnification = 0.1
+let gs = getkeystate()
+let time_inc = 0.01
+loop
+  clearscreen()
+  draw_sun_at(sunx, suny)
+  draw_planets(planet_locations)
+  if not(paused) then
+    let net_force_on_sun = [0.0, 0.0]
+    for i = 1 to size(planet_locations)
+      let planet_locations[i][1] = (planet_locations[i][1] + planet_velocities[i][1]*time_inc)
+      let planet_locations[i][2] = (planet_locations[i][2] + planet_velocities[i][2]*time_inc)
+      let sunx = (sunx + sun_velocity[1]*time_inc)
+      let suny = (suny + sun_velocity[2]*time_inc)
+      let accelerating_force_vector = compute_gravity_vector([sunx, suny], planet_locations[i])
+      let forces_on_sun[i] = [-accelerating_force_vector[1], -accelerating_force_vector[2]]
+      let net_force_on_sun = [(net_force_on_sun[1] + forces_on_sun[i][1]), (net_force_on_sun[2] + forces_on_sun[i][2])]
+      let acceleration_x = (accelerating_force_vector[1] / planet_mass)
+      let acceleration_y = (accelerating_force_vector[2] / planet_mass)
+      let planet_locations[i][3] = accelerating_force_vector[1]
+      let planet_locations[i][4] = accelerating_force_vector[2]
+      let planet_velocities[i][1] = (planet_velocities[i][1] + acceleration_x*time_inc)
+      let planet_velocities[i][2] = (planet_velocities[i][2] + acceleration_y*time_inc)
+    endfor
+    let sun_velocity = [(sun_velocity[1] + (net_force_on_sun[1] / sun_mass)), (sun_velocity[2] + (net_force_on_sun[2] / sun_mass))]
+  endif
+  -- handle keyboard input
+  if inkeystate(gs, scancodes.q) then
+    break
+  elseif inkeystate(gs, scancodes.left) then
+    let sun_velocity[1] = (sun_velocity[1] - 0.0001)
+  elseif inkeystate(gs, scancodes.right) then
+    let sun_velocity[1] = (sun_velocity[1] + 0.0001)
+  elseif inkeystate(gs, scancodes.up) then
+    let sun_velocity[2] = (sun_velocity[2] - 0.0001)
+  elseif inkeystate(gs, scancodes.down) then
+    let sun_velocity[2] = (sun_velocity[2] + 0.0001)
+  elseif inkeystate(gs, scancodes.z) then
+    let zoom = zoom + 0.001
+    println(zoom)
+    setlogicalsize((ws.width * zoom), (ws.height * zoom))
+  elseif inkeystate(gs, scancodes.o) then
+    setlogicalsize(ws.width, ws.height)
+  elseif inkeystate(gs, scancodes.p) then
+    let paused = not(paused)
+    let lastpause = timestamp()
+  endif
+  let gs = getkeystate()
+  render()
+endloop
+waitforkey()
+
+proc compute_gravity_vector(sun_loc, planet_loc)
+  let x_delta = (sun_loc[1] - planet_loc[1])
+  let y_delta = (sun_loc[2] - planet_loc[2])
+  let distance_sqr = (pow(x_delta, 2) + pow(y_delta, 2))
+  if (distance_sqr < 300) then
+    return [0, 0]
+  endif
+
+  let force = ((0.001 * (sun_mass * planet_mass)) / distance_sqr)
+  let distance = pow(distance_sqr, 0.5)
+
+  return [(force * (x_delta / distance)), (force * (y_delta / distance))]
+endproc
+
+proc draw_sun_at(x, y)
+  circle(x, y, sun_radius)
+  setcolor(50, 250, 250)
+  foreach forces_on_sun as planet_force 
+    arrow(x, y, (x + (vec_magnification * planet_force[1])), (y + (vec_magnification * planet_force[2])), 5, 5)
+  endforeach
+  setcolor(255, 0, 250)
+  arrow(x, y, (x + (vec_magnification * net_force_on_sun[1])), (y + (vec_magnification * net_force_on_sun[2])), 5, 5)
+endproc
+
+proc draw_planets(planets)
+  setcolor(255, 255, 255)
+  foreach planets as p 
+    circle(p[1], p[2], 10)
+    setcolor(255, 0, 0)
+    arrow(p[1], p[2], (p[1] + (vec_magnification * p[3])), (p[2] + (vec_magnification * p[4])), 5, 5)
+    setcolor(0, 250, 0)
+    arrow(p[1], p[2], (p[1] + (vec_magnification * p[3])), p[2], 5, 5)
+    arrow(p[1], p[2], p[1], (p[2] + (vec_magnification * p[4])), 5, 5)
+    setcolor(255, 255, 255)
+  endforeach
+endproc
diff --git a/samples/text-rendering.spd b/samples/text-rendering.spd
--- a/samples/text-rendering.spd
+++ b/samples/text-rendering.spd
@@ -1,9 +1,11 @@
-graphics()
-let texture = texturefromtext("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 40, 255, 0, 0, 55, "Hello World!")
+graphics(true)
+setfont(loadfont(40))
+let texture = texttotexture("Hello World!")
 for i = 1 to 1000
   setcolor(0, 0, 0)
   clearscreen()
   copytexture(texture, (i + 200), 200, textureinfo(texture).width, textureinfo(texture).height)
   render()
+  wait(0.01)
 endfor
-gwaitforkey()
+waitforkey()
diff --git a/spade.cabal b/spade.cabal
--- a/spade.cabal
+++ b/spade.cabal
@@ -1,17 +1,17 @@
 cabal-version: 2.2
 
--- This file has been generated from package.yaml by hpack version 0.36.0.
+-- This file has been generated from package.yaml by hpack version 0.37.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:           spade
-version:        0.1.0.10
+version:        0.2.0.0
 synopsis:       A simple programming and debugging environment.
 description:    A simple weakly typed, dynamic, interpreted programming langauge and terminal IDE.
 category:       language, interpreter, ide
 author:         Sandeep.C.R
 maintainer:     sandeep@sras.me
-copyright:      2022 Sandeep.C.R
+copyright:      2026 Sandeep.C.R
 license:        GPL-3.0-only
 build-type:     Simple
 extra-source-files:
@@ -47,6 +47,7 @@
     samples/fib-cache.spd
     samples/fib-generator.spd
     samples/filechecker.spd
+    samples/gravity.spd
     samples/mandelbrot.spd
     samples/paratrooper.spd
     samples/snake.spd
@@ -175,49 +176,49 @@
   build-depends:
       Decimal >=0.5.2 && <0.6
     , WAVE >=0.1.6 && <0.2
-    , aeson >=2.1.2 && <2.2
-    , ansi-terminal >=0.11.5 && <0.12
-    , base >=4.16.3 && <4.17
+    , aeson >=2.2.4 && <2.3
+    , ansi-terminal >=1.1.5 && <1.2
+    , base >=4.21.0 && <4.22
     , bounded-queue >=1.0.0 && <1.1
-    , bytestring >=0.11.3 && <0.12
-    , constraints >=0.13.4 && <0.14
-    , containers >=0.6.5 && <0.7
+    , bytestring >=0.12.2 && <0.13
+    , constraints >=0.14.4 && <0.15
+    , containers ==0.7.*
     , cryptonite ==0.30.*
-    , deepseq >=1.4.6 && <1.5
-    , directory >=1.3.6 && <1.4
-    , exceptions >=0.10.4 && <0.11
-    , file-embed >=0.0.15 && <0.1
-    , filepath >=1.4.2 && <1.5
-    , hedgehog ==1.2.*
+    , deepseq >=1.5.1 && <1.6
+    , directory >=1.3.9 && <1.4
+    , exceptions >=0.10.9 && <0.11
+    , file-embed >=0.0.16 && <0.1
+    , filepath >=1.5.4 && <1.6
+    , hedgehog ==1.7.*
     , hex-text >=0.1.0 && <0.2
-    , hspec >=2.11.0 && <2.12
-    , hspec-discover >=2.11.1 && <2.12
-    , hspec-hedgehog >=0.0.1 && <0.1
+    , hspec >=2.11.17 && <2.12
+    , hspec-discover >=2.11.17 && <2.12
+    , hspec-hedgehog >=0.3.0 && <0.4
     , memory >=0.18.0 && <0.19
     , monad-loops >=0.4.3 && <0.5
-    , mtl >=2.2.2 && <2.3
+    , mtl >=2.3.1 && <2.4
     , neat-interpolation >=0.5.1 && <0.6
-    , ordered-containers >=0.2.3 && <0.3
-    , process >=1.6.13 && <1.7
-    , random >=1.2.1 && <1.3
+    , ordered-containers >=0.2.4 && <0.3
+    , process >=1.6.25 && <1.7
+    , random >=1.3.1 && <1.4
     , regex-tdfa >=1.3.2 && <1.4
-    , scientific >=0.3.7 && <0.4
+    , scientific >=0.3.8 && <0.4
     , sdl2 >=2.5.5 && <2.6
     , sdl2-gfx >=0.3.0 && <0.4
     , sdl2-mixer >=1.2.0 && <1.3
     , sdl2-ttf >=2.1.3 && <2.2
-    , stm >=2.5.0 && <2.6
+    , stm >=2.5.3 && <2.6
     , strip-ansi-escape >=0.1.0 && <0.2
-    , template-haskell >=2.18.0 && <2.19
+    , template-haskell >=2.23.0 && <2.24
     , terminal >=0.2.0 && <0.3
-    , text >=1.2.5 && <1.3
-    , time >=1.11.1 && <1.12
-    , unix >=2.7.2 && <2.8
-    , unliftio >=0.2.24 && <0.3
+    , text >=2.1.2 && <2.2
+    , time ==1.14.*
+    , unix >=2.8.6 && <2.9
+    , unliftio >=0.2.25 && <0.3
     , unliftio-core >=0.2.1 && <0.3
-    , unordered-containers >=0.2.19 && <0.3
-    , vector >=0.13.0 && <0.14
-    , with-utf8 >=1.0.2 && <1.1
+    , unordered-containers >=0.2.21 && <0.3
+    , vector >=0.13.2 && <0.14
+    , with-utf8 >=1.1.0 && <1.2
   default-language: Haskell2010
   autogen-modules: Paths_spade
 
@@ -277,50 +278,50 @@
   build-depends:
       Decimal >=0.5.2 && <0.6
     , WAVE >=0.1.6 && <0.2
-    , aeson >=2.1.2 && <2.2
-    , ansi-terminal >=0.11.5 && <0.12
-    , base >=4.16.3 && <4.17
+    , aeson >=2.2.4 && <2.3
+    , ansi-terminal >=1.1.5 && <1.2
+    , base >=4.21.0 && <4.22
     , bounded-queue >=1.0.0 && <1.1
-    , bytestring >=0.11.3 && <0.12
-    , constraints >=0.13.4 && <0.14
-    , containers >=0.6.5 && <0.7
+    , bytestring >=0.12.2 && <0.13
+    , constraints >=0.14.4 && <0.15
+    , containers ==0.7.*
     , cryptonite ==0.30.*
-    , deepseq >=1.4.6 && <1.5
-    , directory >=1.3.6 && <1.4
-    , exceptions >=0.10.4 && <0.11
-    , file-embed >=0.0.15 && <0.1
-    , filepath >=1.4.2 && <1.5
-    , hedgehog ==1.2.*
+    , deepseq >=1.5.1 && <1.6
+    , directory >=1.3.9 && <1.4
+    , exceptions >=0.10.9 && <0.11
+    , file-embed >=0.0.16 && <0.1
+    , filepath >=1.5.4 && <1.6
+    , hedgehog ==1.7.*
     , hex-text >=0.1.0 && <0.2
-    , hspec >=2.11.0 && <2.12
-    , hspec-discover >=2.11.1 && <2.12
-    , hspec-hedgehog >=0.0.1 && <0.1
+    , hspec >=2.11.17 && <2.12
+    , hspec-discover >=2.11.17 && <2.12
+    , hspec-hedgehog >=0.3.0 && <0.4
     , memory >=0.18.0 && <0.19
     , monad-loops >=0.4.3 && <0.5
-    , mtl >=2.2.2 && <2.3
+    , mtl >=2.3.1 && <2.4
     , neat-interpolation >=0.5.1 && <0.6
-    , ordered-containers >=0.2.3 && <0.3
-    , process >=1.6.13 && <1.7
-    , random >=1.2.1 && <1.3
+    , ordered-containers >=0.2.4 && <0.3
+    , process >=1.6.25 && <1.7
+    , random >=1.3.1 && <1.4
     , regex-tdfa >=1.3.2 && <1.4
-    , scientific >=0.3.7 && <0.4
+    , scientific >=0.3.8 && <0.4
     , sdl2 >=2.5.5 && <2.6
     , sdl2-gfx >=0.3.0 && <0.4
     , sdl2-mixer >=1.2.0 && <1.3
     , sdl2-ttf >=2.1.3 && <2.2
     , spade
-    , stm >=2.5.0 && <2.6
+    , stm >=2.5.3 && <2.6
     , strip-ansi-escape >=0.1.0 && <0.2
-    , template-haskell >=2.18.0 && <2.19
+    , template-haskell >=2.23.0 && <2.24
     , terminal >=0.2.0 && <0.3
-    , text >=1.2.5 && <1.3
-    , time >=1.11.1 && <1.12
-    , unix >=2.7.2 && <2.8
-    , unliftio >=0.2.24 && <0.3
+    , text >=2.1.2 && <2.2
+    , time ==1.14.*
+    , unix >=2.8.6 && <2.9
+    , unliftio >=0.2.25 && <0.3
     , unliftio-core >=0.2.1 && <0.3
-    , unordered-containers >=0.2.19 && <0.3
-    , vector >=0.13.0 && <0.14
-    , with-utf8 >=1.0.2 && <1.1
+    , unordered-containers >=0.2.21 && <0.3
+    , vector >=0.13.2 && <0.14
+    , with-utf8 >=1.1.0 && <1.2
   default-language: Haskell2010
   autogen-modules: Paths_spade
 
@@ -395,19 +396,19 @@
   build-depends:
       Decimal >=0.5.2 && <0.6
     , WAVE >=0.1.6 && <0.2
-    , aeson >=2.1.2 && <2.2
-    , ansi-terminal >=0.11.5 && <0.12
-    , base >=4.16.3 && <4.17
+    , aeson >=2.2.4 && <2.3
+    , ansi-terminal >=1.1.5 && <1.2
+    , base >=4.21.0 && <4.22
     , bounded-queue >=1.0.0 && <1.1
-    , bytestring >=0.11.3 && <0.12
-    , constraints >=0.13.4 && <0.14
-    , containers >=0.6.5 && <0.7
+    , bytestring >=0.12.2 && <0.13
+    , constraints >=0.14.4 && <0.15
+    , containers ==0.7.*
     , cryptonite ==0.30.*
-    , deepseq >=1.4.6 && <1.5
-    , directory >=1.3.6 && <1.4
-    , exceptions >=0.10.4 && <0.11
-    , file-embed >=0.0.15 && <0.1
-    , filepath >=1.4.2 && <1.5
+    , deepseq >=1.5.1 && <1.6
+    , directory >=1.3.9 && <1.4
+    , exceptions >=0.10.9 && <0.11
+    , file-embed >=0.0.16 && <0.1
+    , filepath >=1.5.4 && <1.6
     , hedgehog
     , hex-text >=0.1.0 && <0.2
     , hspec
@@ -415,28 +416,28 @@
     , hspec-hedgehog
     , memory >=0.18.0 && <0.19
     , monad-loops >=0.4.3 && <0.5
-    , mtl >=2.2.2 && <2.3
+    , mtl >=2.3.1 && <2.4
     , neat-interpolation
-    , ordered-containers >=0.2.3 && <0.3
-    , process >=1.6.13 && <1.7
-    , random >=1.2.1 && <1.3
+    , ordered-containers >=0.2.4 && <0.3
+    , process >=1.6.25 && <1.7
+    , random >=1.3.1 && <1.4
     , regex-tdfa >=1.3.2 && <1.4
-    , scientific >=0.3.7 && <0.4
+    , scientific >=0.3.8 && <0.4
     , sdl2 >=2.5.5 && <2.6
     , sdl2-gfx >=0.3.0 && <0.4
     , sdl2-mixer >=1.2.0 && <1.3
     , sdl2-ttf >=2.1.3 && <2.2
     , spade
-    , stm >=2.5.0 && <2.6
+    , stm >=2.5.3 && <2.6
     , strip-ansi-escape
-    , template-haskell >=2.18.0 && <2.19
+    , template-haskell >=2.23.0 && <2.24
     , terminal >=0.2.0 && <0.3
-    , text >=1.2.5 && <1.3
-    , time >=1.11.1 && <1.12
-    , unix >=2.7.2 && <2.8
-    , unliftio >=0.2.24 && <0.3
+    , text >=2.1.2 && <2.2
+    , time ==1.14.*
+    , unix >=2.8.6 && <2.9
+    , unliftio >=0.2.25 && <0.3
     , unliftio-core >=0.2.1 && <0.3
-    , unordered-containers >=0.2.19 && <0.3
-    , vector >=0.13.0 && <0.14
-    , with-utf8 >=1.0.2 && <1.1
+    , unordered-containers >=0.2.21 && <0.3
+    , vector >=0.13.2 && <0.14
+    , with-utf8 >=1.1.0 && <1.2
   default-language: Haskell2010
diff --git a/src/Common.hs b/src/Common.hs
--- a/src/Common.hs
+++ b/src/Common.hs
@@ -10,7 +10,7 @@
 import Control.Monad.IO.Class
 import Control.Monad
 import Data.List as DL
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Text.IO as T
 import Data.Time.Clock.POSIX (getPOSIXTime)
 import Data.Time.Format
diff --git a/src/Compiler/Lexer/Identifiers.hs b/src/Compiler/Lexer/Identifiers.hs
--- a/src/Compiler/Lexer/Identifiers.hs
+++ b/src/Compiler/Lexer/Identifiers.hs
@@ -6,7 +6,7 @@
 import Control.Applicative
 import Data.Char
 import Data.String
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Parser
 import Test.Common
 
diff --git a/src/Compiler/Lexer/Literals.hs b/src/Compiler/Lexer/Literals.hs
--- a/src/Compiler/Lexer/Literals.hs
+++ b/src/Compiler/Lexer/Literals.hs
@@ -6,7 +6,7 @@
 import Control.Monad
 import qualified Data.ByteString as BS
 import Data.Char
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Decimal
 import Text.Read hiding (choice)
 import Text.Hex (decodeHex, encodeHex)
diff --git a/src/Compiler/Parser.hs b/src/Compiler/Parser.hs
--- a/src/Compiler/Parser.hs
+++ b/src/Compiler/Parser.hs
@@ -5,7 +5,7 @@
 import Compiler.AST.Parser.Common
 import Compiler.AST.Program
 import Compiler.Lexer
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Parser
 
 tokenize :: Text -> IO [Token]
diff --git a/src/IDE/Help.hs b/src/IDE/Help.hs
--- a/src/IDE/Help.hs
+++ b/src/IDE/Help.hs
@@ -288,7 +288,11 @@
 
 helpWidget :: WidgetC m => Map.Map Text Text -> TChan IDEEvent -> m (WRef HelpWidget)
 helpWidget builtinsFull ideEventRef = do
-    let builtins = (Prelude.head . T.split (== '.')) <$> (Map.keys builtinsFull)
+    let safeHead l =
+          case l of
+            [] -> error "List empty"
+            (s:_) -> s
+    let builtins = (safeHead . T.split (== '.')) <$> (Map.keys builtinsFull)
     -- The help window
     let helpWidgetDimDistrbution = [
           undefined
diff --git a/src/IDE/Help/Parser.hs b/src/IDE/Help/Parser.hs
--- a/src/IDE/Help/Parser.hs
+++ b/src/IDE/Help/Parser.hs
@@ -4,7 +4,7 @@
 import Control.Monad
 import qualified Data.Map as Map
 import qualified Data.List as DL
-import Data.Text as T
+import Data.Text as T hiding (show)
 import qualified Data.Vector as V
 import System.Console.ANSI (Color(..))
 
diff --git a/src/IDE/IDE.hs b/src/IDE/IDE.hs
--- a/src/IDE/IDE.hs
+++ b/src/IDE/IDE.hs
@@ -15,7 +15,7 @@
 import Data.Map as Map
 import Data.Maybe
 import qualified Data.Set as S
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Text.IO as T
 import System.Process (createPipe)
 import qualified System.IO as SIO
diff --git a/src/Interpreter/Common.hs b/src/Interpreter/Common.hs
--- a/src/Interpreter/Common.hs
+++ b/src/Interpreter/Common.hs
@@ -1,4 +1,8 @@
-module Interpreter.Common where
+module Interpreter.Common
+  ( module Interpreter.Common
+  , module Control.Monad
+  )
+where
 
 import Control.DeepSeq
 import Control.Concurrent
@@ -21,7 +25,7 @@
 import Data.Map as M
 import Data.Maybe (fromMaybe, isJust)
 import Data.Proxy
-import Data.Text as T
+import Data.Text as T hiding (show, (:>))
 import Data.Text.IO as T
 import qualified Data.Vector as V
 import qualified Data.Vector.Storable as VS
@@ -38,6 +42,7 @@
 import qualified System.IO as SIO
 import System.Posix.Directory
 import Text.Hex (encodeHex)
+import Control.Monad (void)
 
 import Common
 import Compiler.AST.Program
@@ -63,9 +68,11 @@
 
 newtype SDLKeyboardStateCallback = SDLKeyboardStateCallback (SDL.Scancode -> Bool)
 
+newtype ColorValue = ColorValue (V4 Word8)
+
 data SDLValue
   = Renderer SDL.Renderer
-  | Color (V4 Int)
+  | Color (V4 Word8)
   | Keycode SDL.Keycode
   | Scancode SDL.Scancode
   | KeyboardState SDLKeyboardStateCallback
@@ -261,6 +268,7 @@
 
 instance Ord Value where
   compare (NumberValue x) (NumberValue y) = compare x y
+  compare (StringValue x) (StringValue y) = compare x y
   compare _ _                             = error "Cannot be compared"
 
 data ProcResult
@@ -361,13 +369,13 @@
   , isWidgetState        :: Maybe WidgetState
   , isTerminalParams     :: Maybe (ScreenPos, Dimensions)
   , isStdoutLock         :: Maybe TSem
-  , isLogChannel         :: LogMode
-  , isDefaultPrintParams :: Maybe (Text, Int, [Int])
-  , isDefaultFont        :: Maybe SDLF.Font
-  , isBgColor            :: Maybe (Word8, Word8, Word8, Word8)
   -- ^ This lock is required to sync stdout writing when the program
   -- is run from within the IDE and both IDE code and the interepreted
   -- program wants to write to stdout concurrently.
+  , isLogChannel         :: LogMode
+  , isDefaultPrintParams :: Maybe (Text, Int, [Int])
+  , isDefaultFont        :: Maybe SDLF.Font
+  , isBgColor            :: Maybe (SDL.V4 Word8)
   }
 
 instance HasDiffRender (ReaderT (TVar InterpreterState) IO) where
@@ -431,7 +439,7 @@
   , isLogChannel = NoLog
   , isWidgetState = Just emptyWidgetState
   , isDefaultPrintParams = Just (".", 2, [3, 2, 2, 2, 2, 2, 2])
-  , isBgColor = Just (0, 0, 0, 255)
+  , isBgColor = Just (V4 0 0 0 255)
   , isDefaultFont = Nothing
   }
 
@@ -579,6 +587,11 @@
   fromValue a = throwErr $ UnexpectedType ("texture", a)
   typeName = "texture"
 
+instance FromValue ColorValue where
+  fromValue (SDLValue (Color c)) = ColorValue c
+  fromValue a = throwErr $ UnexpectedType ("color", a)
+  typeName = "color"
+
 instance FromValue Sample where
   fromValue (SDLValue (SoundSample s)) = s
   fromValue a = throwErr $ UnexpectedType ("soundsample", a)
@@ -688,6 +701,9 @@
 mkPoint :: a -> a -> SDL.Point SDL.V2 a
 mkPoint x y = SDL.P (SDL.V2 x y)
 
+mkColor :: a -> a -> a -> a-> SDL.V4 a
+mkColor r g b a = SDL.V4 r g b a
+
 instance forall a. (FromValue a, VS.Storable a) => FromValue (VS.Vector (SDL.Point V2 a)) where
   fromValue (ArrayValue v) = VS.fromList $ V.toList $ fn <$> v
     where
@@ -745,7 +761,7 @@
 instance KnownArgs '[] where
   toArgDoc = []
   toArgs [] = EmptyArgs
-  toArgs _  = error "Unexpected arguments"
+  toArgs _  = error "Unexpected arguments for function"
 
 instance (KnownSymbol n, FromValue t, KnownArgs s) => KnownArgs (('(n, t) ': s)) where
   toArgDoc = (pack $ symbolVal (Proxy @n), typeName @t) : toArgDoc @s
diff --git a/src/Interpreter/Initialize.hs b/src/Interpreter/Initialize.hs
--- a/src/Interpreter/Initialize.hs
+++ b/src/Interpreter/Initialize.hs
@@ -35,6 +35,8 @@
   insertBuiltInWithDoc (SkIdentifier $ Identifier "getkey") (SomeBuiltin getkey)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "addkey") (SomeBuiltin addkey)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "filter") (SomeBuiltin filter_)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "sort") (SomeBuiltin sort_)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "sorton") (SomeBuiltin sortOn_)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "drop") (SomeBuiltin builtInDrop)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "take") (SomeBuiltin builtInTake)
 
@@ -55,7 +57,7 @@
   insertBuiltInWithDoc (SkIdentifier $ Identifier "toupper") (SomeBuiltin builtInToUpper)
 
   -- Keyboard
-  insertBuiltInWithDoc (SkIdentifier $ Identifier "waitforkey") (SomeBuiltin waitForKey)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "waitforterminalkey") (SomeBuiltin waitForKey)
 
   -- Files
   insertBuiltInWithDoc (SkIdentifier $ Identifier "mkdir") (SomeBuiltin builtInReadFile)
@@ -80,6 +82,7 @@
 
   -- Math
   insertBuiltInWithDoc (SkIdentifier $ Identifier "pow") (SomeBuiltin builtInPow)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "sqrt") (SomeBuiltin builtInSqrt)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "mod") (SomeBuiltin builtInMod)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "random") (SomeBuiltin builtInRandom)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "sin") (SomeBuiltin builtInSin)
@@ -89,6 +92,7 @@
   insertBuiltInWithDoc (SkIdentifier $ Identifier "acos") (SomeBuiltin builtInACos)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "atan") (SomeBuiltin builtInATan)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "sum") (SomeBuiltin builtInSum)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "abs") (SomeBuiltin builtInAbs)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "round") (SomeBuiltin builtInRound)
 
   -- List/Map
@@ -165,6 +169,7 @@
   insertBuiltInWithDoc (SkIdentifier $ Identifier "points") (SomeBuiltin drawPoints)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "line") (SomeBuiltin drawLine)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "lines") (SomeBuiltin drawLines)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "arrow") (SomeBuiltin drawArrow)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "arc") (SomeBuiltin drawArc)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "circle") (SomeBuiltin drawCircle)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "smoothcircle") (SomeBuiltin drawSmoothCircle)
@@ -175,9 +180,11 @@
   insertBuiltInWithDoc (SkIdentifier $ Identifier "smoothpolygon") (SomeBuiltin drawPolySmooth)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "box") (SomeBuiltin drawBox)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "render") (SomeBuiltin draw)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "mkcolor") (SomeBuiltin mkColor')
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "splitcolor") (SomeBuiltin getColorComponents)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "mkcoloralpha") (SomeBuiltin mkColorAlpha)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "setcolor") (SomeBuiltin setDrawColor)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "setbgcolor") (SomeBuiltin setBgColor)
-  insertBuiltInWithDoc (SkIdentifier $ Identifier "setcolora") (SomeBuiltin setDrawColorAlpha)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "clearscreen") (SomeBuiltin clear)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "getwindowsize") (SomeBuiltin getWindowSize)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "setlogicalsize") (SomeBuiltin setLogicalSize)
@@ -195,7 +202,7 @@
 
   -- SDL Keyboard
   insertBuiltInWithDoc (SkIdentifier $ Identifier "getkeypresses") (SomeBuiltin getKeys)
-  insertBuiltInWithDoc (SkIdentifier $ Identifier "gwaitforkey") (SomeBuiltin waitForSDLKey)
+  insertBuiltInWithDoc (SkIdentifier $ Identifier "waitforkey") (SomeBuiltin waitForSDLKey)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "getkeystate") (SomeBuiltin getKeyboardState)
   insertBuiltInWithDoc (SkIdentifier $ Identifier "inkeystate") (SomeBuiltin wasKeyDownIn)
 
diff --git a/src/Interpreter/Interpreter.hs b/src/Interpreter/Interpreter.hs
--- a/src/Interpreter/Interpreter.hs
+++ b/src/Interpreter/Interpreter.hs
@@ -6,14 +6,15 @@
 import Control.Monad.Catch (try)
 import Control.Concurrent
 import Control.Concurrent.STM as STM
-import Control.Exception (throw, IOException)
+import Control.Exception (throw, SomeException, IOException)
 import Control.Monad
 import Control.Monad.Catch (catch)
 import Control.Monad.Loops (iterateWhile)
+import Data.List (sortOn, sort)
 import Data.Coerce
 import qualified Data.List.NonEmpty as NE
 import Data.Map as M hiding (map)
-import Data.Text as T hiding (index, map)
+import Data.Text as T hiding ((:>), show, index, map)
 import qualified Data.Text as T (index)
 import qualified Data.Vector as V
 import qualified Data.ByteString as BS
@@ -186,7 +187,10 @@
   lookupScope sk >>= (\x -> evaluateProcedure_ x args)
 
 evaluateFn :: FnId -> [ExpressionWithLoc] -> Bool -> InterpretM (Maybe Value)
-evaluateFn fnId argsExps isTail = do
+evaluateFn fnId argsExps isTail = catch (evaluateFn_ fnId argsExps isTail) (\(e::SomeException) -> throwErr $ CustomRTE $ T.pack $ show e)
+
+evaluateFn_ :: FnId -> [ExpressionWithLoc] -> Bool -> InterpretM (Maybe Value)
+evaluateFn_ fnId argsExps isTail = do
   args <- mapM (\x -> evaluateExpression x) argsExps
   fnVal <- case fnId of
     FnOp op -> lookupScope (SkOperator op)
@@ -594,6 +598,23 @@
       Just (BoolValue x) -> pure x
       _           -> throwErr $ CustomRTE "Callback returned a non-bool value"
 
+sortOn_ :: BuiltInFnWithDoc '[ '("list", V.Vector Value), '("callback", Callback)]
+sortOn_ ((coerce -> v1) :> (coerce -> callback) :> _) = do
+  let list :: [Value] = V.toList v1
+  ordering :: [Value] <- mapM fn list
+  pure $ Just $ ArrayValue $ (V.fromList $ fst <$> (sortOn snd $ Prelude.zip list ordering))
+  where
+    fn :: Value -> InterpretM Value
+    fn v = evaluateCallback callback [v] >>= \case
+      Just (NumberValue x) -> pure (NumberValue x)
+      Just (StringValue x) -> pure (StringValue x)
+      Just _           -> throwErr $ CustomRTE "Callback returned a non-comparable value"
+      _           -> throwErr $ CustomRTE "Callback did not return a value"
+
+sort_ :: BuiltInFnWithDoc '[ '("list", V.Vector Value)]
+sort_ ((coerce -> v1) :> _) = do
+  let list :: [Value] = V.toList v1
+  pure $ Just $ ArrayValue $ (V.fromList (sort list))
 
 interpretPassOne :: Program -> InterpretM ()
 interpretPassOne x = mapM_ (\a -> fn a) x
diff --git a/src/Interpreter/Lib/Concurrency.hs b/src/Interpreter/Lib/Concurrency.hs
--- a/src/Interpreter/Lib/Concurrency.hs
+++ b/src/Interpreter/Lib/Concurrency.hs
@@ -5,10 +5,9 @@
 import Control.Concurrent.STM.TChan
 import Control.Concurrent.STM.TSem
 import Control.Concurrent.STM.TMVar
-import Control.Exception (SomeException, catch, toException)
+import Control.Exception (SomeException, catch, fromException, toException)
 import Control.Monad.IO.Class
 import Control.Monad.IO.Unlift
-import Control.Monad.State.Strict
 import Data.Coerce
 
 import Interpreter.Common
@@ -35,8 +34,12 @@
 
 builtInAwait :: BuiltInFnWithDoc '[ '("thread_result", ThreadInfo) ]
 builtInAwait ((coerce -> (ThreadInfo _ pmvar)) :> EmptyArgs) = do
-  void $ liftIO $ atomically $ readTMVar pmvar
-  pure Nothing
+  result <- liftIO $ atomically $ readTMVar pmvar
+  case result of
+    Right _ -> pure Nothing
+    Left e -> case fromException @ProgramError e of
+      (Just MissingProcedureReturn) -> pure Nothing
+      _ -> throwErr e
 
 builtInAwaitResult :: BuiltInFnWithDoc '[ '("thread_result", ThreadInfo) ]
 builtInAwaitResult ((coerce -> (ThreadInfo _ pmvar)) :> EmptyArgs) =
diff --git a/src/Interpreter/Lib/Crypto.hs b/src/Interpreter/Lib/Crypto.hs
--- a/src/Interpreter/Lib/Crypto.hs
+++ b/src/Interpreter/Lib/Crypto.hs
@@ -4,7 +4,7 @@
 import Data.ByteString as BS
 import Data.ByteArray
 import Data.Coerce
-import Data.Text
+import Data.Text hiding ((:>))
 
 import Interpreter.Common
 
diff --git a/src/Interpreter/Lib/FileSystem.hs b/src/Interpreter/Lib/FileSystem.hs
--- a/src/Interpreter/Lib/FileSystem.hs
+++ b/src/Interpreter/Lib/FileSystem.hs
@@ -6,7 +6,7 @@
 import qualified Data.ByteString.Internal as BSI
 import Data.Coerce
 import Data.Maybe (fromMaybe)
-import Data.Text as T
+import Data.Text as T hiding ((:>))
 import Data.Text.Encoding
 import Data.Text.IO as T
 import System.Directory
diff --git a/src/Interpreter/Lib/Math.hs b/src/Interpreter/Lib/Math.hs
--- a/src/Interpreter/Lib/Math.hs
+++ b/src/Interpreter/Lib/Math.hs
@@ -47,12 +47,19 @@
 builtInACos ((coerce -> v) :> _) = do
   pure $ Just $ NumberValue $ NumberFractional (radianToDegree $ acos v)
 
+builtInAbs :: BuiltInFnWithDoc '[ '("arg", FloatType)]
+builtInAbs ((coerce -> v) :> _) = do
+  pure $ Just $ NumberValue $ NumberFractional (abs v)
+
 builtInATan :: BuiltInFnWithDoc '[ '("arg", FloatType)]
 builtInATan ((coerce -> v) :> _) = do
   pure $ Just $ NumberValue $ NumberFractional (radianToDegree $ atan v)
 
-builtInPow :: BuiltInFnWithDoc '[ '("number", Double), '("pow", IntType)]
-builtInPow ((coerce -> (v :: FloatType)) :> (coerce -> (pw :: IntType)) :> EmptyArgs) = pure $ Just $ NumberValue $ NumberFractional $ v ^ pw
+builtInPow :: BuiltInFnWithDoc '[ '("number", FloatType), '("pow", FloatType)]
+builtInPow ((coerce -> (v :: FloatType)) :> (coerce -> (pw :: FloatType)) :> EmptyArgs) = pure $ Just $ NumberValue $ NumberFractional $ v ** pw
+
+builtInSqrt :: BuiltInFnWithDoc '[ '("number", FloatType)]
+builtInSqrt ((coerce -> (v :: FloatType)) :> EmptyArgs) = pure $ Just $ NumberValue $ NumberFractional $ sqrt(v)
 
 radianToDegree :: FloatType -> FloatType
 radianToDegree x = (x/pi*180)
diff --git a/src/Interpreter/Lib/Misc.hs b/src/Interpreter/Lib/Misc.hs
--- a/src/Interpreter/Lib/Misc.hs
+++ b/src/Interpreter/Lib/Misc.hs
@@ -18,7 +18,7 @@
 import Data.Map as M
 import Data.Proxy
 import qualified Data.Scientific as S
-import Data.Text as T
+import Data.Text as T hiding ((:>), show)
 import Data.Text.Encoding
 import Data.Text.IO as T
 import Data.Vector as V
diff --git a/src/Interpreter/Lib/SDL.hs b/src/Interpreter/Lib/SDL.hs
--- a/src/Interpreter/Lib/SDL.hs
+++ b/src/Interpreter/Lib/SDL.hs
@@ -3,7 +3,6 @@
 import qualified Data.Text as T
 import Control.Monad.IO.Class
 import Control.Monad.Loops
-import Control.Monad.State.Strict
 import qualified Data.ByteString as BS
 import System.Process (createPipe)
 import Data.Coerce
@@ -26,6 +25,7 @@
 import Interpreter.Common
 import Interpreter.Interpreter
 import qualified Interpreter.Lib.Fonts as Fonts
+import qualified Interpreter.Lib.Misc as InterpreterMisc
 
 makeSinWaveChunk :: Double -> BS.ByteString
 makeSinWaveChunk freq = BS.pack $
@@ -321,12 +321,16 @@
 getDefaultWindow :: InterpretM SDL.Window
 getDefaultWindow = isDefaultWindow <$> getInterpretM >>= \case
   Just x  -> pure x
-  Nothing -> throwErr $ SDLError "Graphics not Initialized"
+  Nothing -> do
+    _ <- initGraphics Nothing True False
+    getDefaultWindow
 
 getDefaultRenderer :: InterpretM SDL.Renderer
 getDefaultRenderer = isDefaultRenderer <$> getInterpretM >>= \case
   Just x  -> pure x
-  Nothing -> throwErr $ SDLError "Graphics not Initialized"
+  Nothing -> do
+    _ <- initGraphics Nothing True False
+    getDefaultRenderer
 
 draw :: BuiltInFnWithDoc '[]
 draw _ = do
@@ -341,9 +345,20 @@
   (Just False) -> draw'
   _            -> pure ()
 
-setDrawColor :: BuiltInFnWithDoc '[ '("red_component", Word8), '("green_component", Word8), '("blue_component", Word8)]
-setDrawColor ((coerce -> r) :> (coerce -> g) :> (coerce -> b) :> _) = do
-  setDrawColor' r g b 255
+mkColor' :: BuiltInFnWithDoc '[ '("red_component", Word8), '("green_component", Word8), '("blue_component", Word8)]
+mkColor' ((coerce -> r) :> (coerce -> g) :> (coerce -> b) :> _) = pure $ Just $ SDLValue (Color $ V4 r g b 255)
+
+mkColorAlpha :: BuiltInFnWithDoc '[ '("red_component", Word8), '("green_component", Word8), '("blue_component", Word8), '("alpha_component", Word8)]
+mkColorAlpha ((coerce -> r) :> (coerce -> g) :> (coerce -> b) :> (coerce -> a) :> _) = pure $ Just $ SDLValue (Color $ V4 r g b a)
+
+getColorComponents :: BuiltInFnWithDoc '[ '("color", ColorValue)]
+getColorComponents ((coerce -> (ColorValue (V4 r g b a))) :> EmptyArgs) = do
+  pure $ Just $ ObjectValue $ M.fromList [("alpha", NumberValue $ NumberInt $ fromIntegral a), ("blue", NumberValue $ NumberInt $ fromIntegral b), ("green", NumberValue $ NumberInt $ fromIntegral g), ("red", NumberValue $ NumberInt $ fromIntegral r)]
+
+setDrawColor :: BuiltInFnWithDoc '[ '("color", ColorValue)]
+setDrawColor ((coerce -> (ColorValue color)) :> EmptyArgs) = do
+  getDefaultRenderer >>= \renderer -> do
+    SDL.rendererDrawColor renderer $= color
   pure Nothing
 
 setBgColor :: BuiltInFnWithDoc '[ '("red_component", Word8), '("green_component", Word8), '("blue_component", Word8)]
@@ -351,26 +366,16 @@
   setBgColor' r g b 255
   pure Nothing
 
-setDrawColorAlpha :: BuiltInFnWithDoc '[ '("red_component", Word8), '("green_component", Word8), '("blue_component", Word8), '("transparency", Word8)]
-setDrawColorAlpha ((coerce -> r) :> (coerce -> g) :> (coerce -> b) :> (coerce -> t) :> _) = do
-  setDrawColor' r g b t
-  pure Nothing
-
-setDrawColor' :: Word8 -> Word8 -> Word8 -> Word8 -> InterpretM ()
-setDrawColor' r g b a = do
-  getDefaultRenderer >>= \renderer -> do
-    SDL.rendererDrawColor renderer $= V4 r g b a
-
 setBgColor' :: Word8 -> Word8 -> Word8 -> Word8 -> InterpretM ()
-setBgColor' r g b a = modifyInterpretM (\im -> im { isBgColor = Just (r, g, b, a) })
+setBgColor' r g b a = modifyInterpretM (\im -> im { isBgColor = Just $ V4 r g b a })
 
 clear :: BuiltInFnWithDoc '[]
 clear _ =
   getDefaultRenderer >>= \renderer -> do
     isBgColor <$> getInterpretM >>= \case
-      Just (r, g, b, a) -> do
+      Just v4 -> do
         (V4 r' g' b' a') <- SDL.get (SDL.rendererDrawColor renderer)
-        SDL.rendererDrawColor renderer $= V4 r g b a
+        SDL.rendererDrawColor renderer $= v4
         SDL.clear renderer
         SDL.rendererDrawColor renderer $= V4 r' g' b' a'
         drawIfNotAccelerated
@@ -441,7 +446,11 @@
     toSingle fn vec = VS.map fn vec
 
 drawLine :: BuiltInFnWithDoc ['("start_x", CInt), '("start_y", CInt), '("end_x", CInt), '("end_y", CInt)]
-drawLine ((coerce -> x) :> (coerce -> y) :> (coerce -> xEnd) :> (coerce -> yEnd) :>_) = do
+drawLine ((coerce -> x) :> (coerce -> y) :> (coerce -> xEnd) :> (coerce -> yEnd) :>_) =
+  drawLine' x y xEnd yEnd
+
+drawLine' :: CInt -> CInt -> CInt -> CInt -> InterpretM (Maybe Value)
+drawLine' x y xEnd yEnd = do
   renderer <- getDefaultRenderer
   let endpoint = mkPoint xEnd yEnd
   SDL.drawLine renderer (mkPoint x y) endpoint
@@ -453,6 +462,29 @@
   drawIfNotAccelerated
   pure Nothing
 
+drawArrow :: BuiltInFnWithDoc ['("start_x", CInt), '("start_y", CInt), '("end_x", CInt), '("end_y", CInt), '("tip_length", CInt), '("tip_width", CInt), '("fill_tip", Maybe Bool)]
+drawArrow ((coerce -> x) :> (coerce -> y) :> (coerce -> xEnd) :> (coerce -> yEnd) :> (coerce -> tipL) :> (coerce -> tipB) :> (coerce -> mfillTip)  :>_) = do
+  let
+    tipWidth = realToFrac @CInt @Double tipB
+    tipLength = realToFrac @CInt @Double tipL
+    length' = sqrt ((realToFrac @_ @Double (xEnd - x)) ^ 2 + (realToFrac @_ @Double (yEnd - y)) ^2)
+  if length' == 0 then do
+    void $ drawLine' x y xEnd yEnd
+    pure Nothing
+  else do
+    let
+      dx = (realToFrac @_ @Double $ (xEnd -x))/length'
+      dy = (realToFrac @_ @Double $ (yEnd -y))/length'
+      xb = (realToFrac @_ @Double xEnd) - dx*tipLength
+      yb = (realToFrac @_ @Double yEnd) - dy*tipLength
+      e1x = xb + (-dy * tipWidth/2)
+      e1y = yb + (dx * tipWidth/2)
+      e2x = xb + (dy * tipWidth/2)
+      e2y = yb + (-dx * tipWidth/2)
+    void $ drawLine' x y (round xb) (round yb)
+    void $ drawPoly' (VS.fromList  [mkPoint (round e1x) (round e1y), mkPoint (round e2x) (round e2y), mkPoint (fromIntegral xEnd) (fromIntegral yEnd)]) False mfillTip
+    pure Nothing
+
 drawBox :: BuiltInFnWithDoc ['("start_x", CInt), '("start_y", CInt), '("width", CInt), '("height", CInt), '("fill", Maybe Bool)]
 drawBox ((coerce -> x) :> (coerce -> y) :> (coerce -> width) :> (coerce -> height) :> (coerce -> fill) :> _) = do
   renderer <- getDefaultRenderer
@@ -521,13 +553,16 @@
   pure Nothing
 
 waitForSDLKey :: BuiltInFnWithDoc '[]
-waitForSDLKey _ = do
-  mv <- iterateWhile isNothing $ do
-    events <- (filter filterEvent) <$> pollEvents
-    case events of
-      [] -> pure Nothing
-      (h:_) -> pure $ convertEvent h
-  pure mv
+waitForSDLKey a = do
+  isDefaultRenderer <$> getInterpretM >>= \case
+    Nothing -> InterpreterMisc.waitForKey a
+    Just _ -> do
+      mv <- iterateWhile isNothing $ do
+        events <- (filter filterEvent) <$> pollEvents
+        case events of
+          [] -> pure Nothing
+          (h:_) -> pure $ convertEvent h
+      pure mv
   where
     convertEvent :: Event -> Maybe Value
     convertEvent event =
diff --git a/src/Interpreter/Lib/String.hs b/src/Interpreter/Lib/String.hs
--- a/src/Interpreter/Lib/String.hs
+++ b/src/Interpreter/Lib/String.hs
@@ -2,7 +2,7 @@
 
 import qualified Data.ByteString as BS
 import Data.Coerce
-import Data.Text as T
+import Data.Text as T hiding ((:>), show)
 import Data.Text.Encoding
 import Data.Vector as V
 
diff --git a/src/Parser/Parser.hs b/src/Parser/Parser.hs
--- a/src/Parser/Parser.hs
+++ b/src/Parser/Parser.hs
@@ -6,7 +6,7 @@
 import Control.Applicative
 import Control.Monad.IO.Class
 import Data.String (IsString(..))
-import Data.Text as T
+import Data.Text as T hiding (Empty)
 
 data ParseErrorWithParsed a = ParseErrorWithParsed
   { parialResult :: Maybe a
diff --git a/src/Test.hs b/src/Test.hs
--- a/src/Test.hs
+++ b/src/Test.hs
@@ -2,7 +2,7 @@
 
 import Compiler.Parser
 import Control.Applicative
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Text.IO as T
 import Parser
 
diff --git a/src/UI/Widgets/AutoComplete.hs b/src/UI/Widgets/AutoComplete.hs
--- a/src/UI/Widgets/AutoComplete.hs
+++ b/src/UI/Widgets/AutoComplete.hs
@@ -1,6 +1,6 @@
 module UI.Widgets.AutoComplete where
 
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Data.Typeable (Proxy, eqT, (:~:)(..))
 import System.Console.ANSI (Color(..))
 import Text.Printf
diff --git a/src/UI/Widgets/Common.hs b/src/UI/Widgets/Common.hs
--- a/src/UI/Widgets/Common.hs
+++ b/src/UI/Widgets/Common.hs
@@ -2,7 +2,7 @@
   ( module UI.Widgets.Common
   , module UI.Terminal.IO
   , module Control.Monad
-  , module Data.Text
+  , module Text
   , module Control.Monad.IO.Class
   , module Data.Constraint
   , module GHC.Stack
@@ -23,8 +23,8 @@
 import Data.Kind (Type)
 import Data.Map.Strict as M hiding (keys)
 import Data.Maybe
-import Data.Text as T
-import Data.Text hiding (lines)
+import Data.Text as Text hiding (show, (:>))
+import Data.Text as T hiding (show)
 import qualified Data.Text as C
 import Data.Text.IO as T
 import Data.Typeable (Proxy(..), Typeable, cast, typeRep)
diff --git a/src/UI/Widgets/Editor.hs b/src/UI/Widgets/Editor.hs
--- a/src/UI/Widgets/Editor.hs
+++ b/src/UI/Widgets/Editor.hs
@@ -4,7 +4,7 @@
 import Data.List as DL hiding (lines)
 import Data.Maybe
 import Data.Proxy (Proxy(..))
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Prelude hiding (lines)
 import System.Console.ANSI (Color(..))
 import Text.Printf
diff --git a/src/UI/Widgets/Spade/Selector.hs b/src/UI/Widgets/Spade/Selector.hs
--- a/src/UI/Widgets/Spade/Selector.hs
+++ b/src/UI/Widgets/Spade/Selector.hs
@@ -3,7 +3,6 @@
 import qualified Data.Text as T
 import Data.Typeable
 import qualified System.Console.ANSI as A
-import Control.Monad.State.Strict
 import Control.Monad.Reader
 import Control.Concurrent.STM.TVar
 
diff --git a/test/Common.hs b/test/Common.hs
--- a/test/Common.hs
+++ b/test/Common.hs
@@ -2,7 +2,7 @@
 
 import "spade" Common
 import Control.Monad.IO.Class
-import Data.Text as T
+import Data.Text as T hiding (show)
 import Parser
 import Test.Common
 import Test.Hspec.Hedgehog
