diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,70 @@
+SFML-control
+============
+
+This library expose a SFML monad which deliver a higher level of abstraction
+over the low level bindings.
+
+# What do you mean by higher level?
+It exposes a `SFML` monad you must use and eventually run to go back into `IO`.
+In doing that, the `SFML` monad runs all the destructors for you. This means you
+don't have to worry about explicit deallocation of the underlying C resources.
+
+# How the bindings are achieved?
+To scrap as much boilerplate as possible, TH has been used. In fact, thanks to
+the TH machinery, the whole [SFML](https://github.com/SFML-haskell/SFML) functions has been lifted appropriately here:
+
+[Conversions](https://github.com/SFML-haskell/SFML-control/blob/master/src/Control/Monad/SFML/Conversions.hs)
+
+# Example
+This is a 1:1 translation of [this](https://github.com/SFML-haskell/SFML/blob/master/demos/hello/main.hs) example:
+
+``` haskell
+module Main where
+
+import Control.Monad.SFML
+import qualified SFML.Graphics as G
+import qualified SFML.Window as W
+import SFML.Graphics.Color
+
+import Paths_SFMLExamples
+
+main :: IO ()
+main = runSFML $ do
+    let ctxSettings = Just $ W.ContextSettings 24 8 0 1 2
+    wnd <- createRenderWindow (W.VideoMode 640 480 32)
+           "SFML-Control Demo" [W.SFDefaultStyle] ctxSettings
+    logoPath  <- liftIO $ getDataFileName "Haskell-Logo.png"
+    fontPath  <- liftIO $ getDataFileName "Vera.ttf"
+    musicPath <- liftIO $ getDataFileName "DST-BreakOut.ogg"
+    tex <- textureFromFile logoPath Nothing
+    spr <- createSprite
+    fnt <- fontFromFile fontPath
+    txt <- createText
+    setTextString txt "Haskell-Control\nhandles memory\nfor you"
+    setTextFont txt fnt
+    setTextCharacterSize txt 20
+    setTextColor txt blue
+    msc <- musicFromFile musicPath
+    play msc
+    setTexture spr tex True
+    loop wnd spr txt
+
+
+loop :: G.RenderWindow -> G.Sprite -> G.Text -> SFML ()
+loop wnd spr txt = do
+    drawSprite wnd spr Nothing
+    drawText   wnd txt $ Just (G.renderStates { G.transform = G.translation 460 40 })
+    display wnd
+    evt <- waitEvent wnd
+    case evt of
+        Nothing -> return ()
+        Just W.SFEvtClosed -> return ()
+        _ -> loop wnd spr txt
+```
+
+As you can see it's almost a 1:1 translation, you just need to run the monad
+and get rid of explicit `destroy` !
+
+# Why two libraries?
+We decided that the user shouldn't pay the extra burder of a `SFML` monad if all he
+wants is a low level SFML binding.
diff --git a/SFML-control.cabal b/SFML-control.cabal
new file mode 100644
--- /dev/null
+++ b/SFML-control.cabal
@@ -0,0 +1,30 @@
+name:                SFML-control
+version:             0.2.0.0
+synopsis:            Higher level library on top of SFML
+license:             MIT
+license-file:        LICENSE
+author:              Alfredo Di Napoli
+maintainer:          alfredo.dinapoli@gmail.com
+category:            Graphics
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  exposed-modules:
+      Control.Monad.SFML
+      Control.Monad.SFML.Types
+      Control.Monad.SFML.Types.TH
+  other-modules:
+      Control.Monad.SFML.Types.Internal
+      Control.Monad.SFML.Conversions
+  -- other-extensions:
+  build-depends:
+      base >= 4.6 && < 5,
+      mtl >= 2.0.0.0,
+      SFML >= 0.2.0.0,
+      template-haskell -any
+  hs-source-dirs:
+      src
+  default-language:
+      Haskell2010
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Control/Monad/SFML.hs b/src/Control/Monad/SFML.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/SFML.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+
+module Control.Monad.SFML
+  ( module Control.Monad.SFML.Types
+  , module Control.Monad.SFML.Conversions
+  , liftIO
+  ) where
+
+
+import SFML.System.Vector2
+import qualified SFML.Graphics as G
+
+import Control.Monad.State.Strict hiding (lift)
+
+
+import Control.Monad.SFML.Types.Internal
+import Control.Monad.SFML.Types
+import Control.Monad.SFML.Conversions
+
+
+--------------------------------------------------------------------------------
+drawRectangleOfSize :: Vec2f -> SFML G.RectangleShape
+drawRectangleOfSize size = SFML $ do
+  shp <- liftIO . G.err $ G.createRectangleShape
+  liftIO $ G.setSize shp size
+  modify $ \s -> G.destroy shp : s
+  return shp
diff --git a/src/Control/Monad/SFML/Conversions.hs b/src/Control/Monad/SFML/Conversions.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/SFML/Conversions.hs
@@ -0,0 +1,326 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+
+module Control.Monad.SFML.Conversions where
+
+
+import Control.Monad.SFML.Types.TH
+import qualified SFML.Graphics as G
+import qualified SFML.Audio as A
+import qualified SFML.System as S
+import qualified SFML.Window as W
+import Data.Maybe
+
+-- | Run the given IO action and throw an error if it fails.
+mb :: IO (Maybe a) -> IO a
+mb = (maybe (error "Nothing found.") return =<<)
+
+
+-- Audio / Listener.hs
+$(lift 'A.setGlobalVolume)
+$(lift 'A.getGlobalVolume)
+$(lift 'A.setListenerPosition)
+$(lift 'A.getListenerPosition)
+$(lift 'A.setListenerDirection)
+$(lift 'A.getListenerDirection)
+
+-- Audio / Music.hs
+$(liftWithDestroy 'G.err 'A.musicFromFile)
+$(liftWithDestroy 'G.err 'A.musicFromMemory)
+$(liftWithDestroy 'G.err 'A.musicFromStream)
+$(lift 'A.setLoop)
+$(lift 'A.getLoop)
+$(lift 'A.getDuration)
+$(lift 'A.play)
+$(lift 'A.pause)
+$(lift 'A.stop)
+$(lift 'A.getChannelCount)
+$(lift 'A.getSampleRate)
+$(lift 'A.getStatus)
+$(lift 'A.getPlayingOffset)
+$(lift 'A.setPitch)
+$(lift 'A.setVolume)
+$(lift 'A.setPosition)
+$(lift 'A.setRelativeToListener)
+$(lift 'A.setMinDistance)
+$(lift 'A.setAttenuation)
+$(lift 'A.setPlayingOffset)
+$(lift 'A.getPitch)
+$(lift 'A.getVolume)
+$(lift 'A.getPosition)
+$(lift 'A.isRelativeToListener)
+$(lift 'A.getMinDistance)
+$(lift 'A.getAttenuation)
+
+-- Audio / Sound.hs
+$(liftWithDestroy 'id 'A.createSound)
+$(lift 'A.copySound)
+$(lift 'A.setSoundBuffer)
+$(lift 'A.getSoundBuffer)
+
+-- Audio / SoundBuffer.hs
+$(liftWithDestroy 'G.err 'A.soundBufferFromFile)
+$(liftWithDestroy 'G.err 'A.soundBufferFromMemory)
+$(liftWithDestroy 'G.err 'A.soundBufferFromStream)
+$(liftWithDestroy 'mb 'A.soundBufferFromSamples)
+$(lift 'A.copySoundBuffer)
+$(lift 'A.saveSoundBufferToFile)
+$(lift 'A.getSamples)
+$(lift 'A.getSampleCount)
+
+-- Audio / SoundBufferRecorder.hs
+$(liftWithDestroy 'G.err 'A.createSoundBufferRecorder)
+$(lift 'A.startRecording)
+$(lift 'A.stopRecording)
+
+-- Audio / SoundRecorder.hs
+$(liftWithDestroy 'G.err 'A.createSoundRecorder)
+$(lift 'A.isSoundRecorderAvailable)
+
+-- Audio / SoundStream.hs
+$(liftWithDestroy 'id 'A.createSoundStream)
+
+-- Graphics / CircleShape.hs
+$(liftWithDestroy 'G.err 'G.createCircleShape)
+$(lift 'G.copy)
+$(lift 'G.setRotation)
+$(lift 'G.setScale)
+$(lift 'G.setOrigin)
+$(lift 'G.getRotation)
+$(lift 'G.getScale)
+$(lift 'G.getOrigin)
+$(lift 'G.move)
+$(lift 'G.rotate)
+$(lift 'G.scale)
+$(lift 'G.getTransform)
+$(lift 'G.getInverseTransform)
+$(lift 'G.setTexture)
+$(lift 'G.setTextureRect)
+$(lift 'G.getTexture)
+$(lift 'G.getTextureRect)
+$(lift 'G.setFillColor)
+$(lift 'G.setOutlineColor)
+$(lift 'G.setOutlineThickness)
+$(lift 'G.getFillColor)
+$(lift 'G.getOutlineColor)
+$(lift 'G.getOutlineThickness)
+$(lift 'G.getPointCount)
+$(lift 'G.getPoint)
+$(lift 'G.setRadius)
+$(lift 'G.getRadius)
+$(lift 'G.setPointCount)
+$(lift 'G.getLocalBounds)
+$(lift 'G.getGlobalBounds)
+
+-- Graphics / ConvexShape.hs
+$(liftWithDestroy 'G.err 'G.createConvexShape)
+$(lift 'G.setPoint)
+
+-- Graphics / Font.hs
+$(liftWithDestroy 'G.err 'G.fontFromFile)
+$(liftWithDestroy 'G.err 'G.fontFromMemory)
+$(liftWithDestroy 'G.err 'G.fontFromStream)
+$(lift 'G.getGlyph)
+$(lift 'G.getKerning)
+$(lift 'G.getLineSpacing)
+$(lift 'G.getFontTexture)
+
+-- Graphics / Image.hs
+$(liftWithDestroy 'G.err 'G.createImage)
+$(liftWithDestroy 'id 'G.imageFromColor)
+$(liftWithDestroy 'id 'G.imageFromPixels)
+$(liftWithDestroy 'mb 'G.imageFromFile)
+$(liftWithDestroy 'mb 'G.imageFromMemory)
+$(liftWithDestroy 'mb 'G.imageFromStream)
+$(lift 'G.destroy)
+$(lift 'G.saveImage)
+$(lift 'G.imageSize)
+$(lift 'G.createMaskFromColor)
+$(lift 'G.copyImage')
+$(lift 'G.setPixel)
+$(lift 'G.getPixel)
+$(lift 'G.getPixels)
+$(lift 'G.flipHorizontally)
+$(lift 'G.flipVertically)
+
+-- Graphics / RectangleShape.hs
+$(liftWithDestroy 'G.err 'G.createRectangleShape)
+$(lift 'G.setSize)
+$(lift 'G.getSize)
+
+-- Graphics / RenderTexture.hs
+$(liftWithDestroy 'G.err 'G.createRenderTexture)
+$(lift 'G.getTextureSize)
+$(lift 'G.setActive)
+$(lift 'G.clear)
+$(lift 'G.setView)
+$(lift 'G.getView)
+$(lift 'G.getDefaultView)
+$(lift 'G.getViewport)
+$(lift 'G.mapPixelToCoords)
+$(lift 'G.drawSprite)
+$(lift 'G.drawText)
+$(lift 'G.drawShape)
+$(lift 'G.drawCircle)
+$(lift 'G.drawConvexShape)
+$(lift 'G.drawRectangle)
+$(lift 'G.drawVertexArray)
+$(lift 'G.drawPrimitives)
+$(lift 'G.drawPrimitives')
+$(lift 'G.pushGLStates)
+$(lift 'G.popGLStates)
+$(lift 'G.resetGLStates)
+$(lift 'G.getRenderTexture)
+$(lift 'G.setSmooth)
+$(lift 'G.isSmooth)
+
+-- Graphics / RenderWindow.hs
+$(liftWithDestroy 'id 'G.createRenderWindow)
+$(liftWithDestroy 'id 'G.renderWindowFromHandle)
+$(lift 'G.close)
+$(lift 'G.isWindowOpen)
+$(lift 'G.getWindowSettings)
+$(lift 'G.pollEvent)
+$(lift 'G.waitEvent)
+$(lift 'G.getWindowPosition)
+$(lift 'G.setWindowPosition)
+$(lift 'G.getWindowSize)
+$(lift 'G.setWindowSize)
+$(lift 'G.setWindowTitle)
+$(lift' 'G.setWindowIcon 4)
+$(lift 'G.setWindowVisible)
+$(lift 'G.setMouseVisible)
+$(lift 'G.setVSync)
+$(lift 'G.setKeyRepeat)
+$(lift 'G.setWindowActive)
+$(lift 'G.display)
+$(lift 'G.setFramerateLimit)
+$(lift 'G.setJoystickThreshold)
+$(lift 'G.getSystemHandle)
+$(lift 'G.clearRenderWindow)
+$(lift 'G.captureRenderWindow)
+$(lift 'G.getMousePosition)
+$(lift 'G.setMousePosition)
+
+-- Graphics / Shader.hs
+$(liftWithDestroy 'G.err 'G.shaderFromFile)
+$(liftWithDestroy 'G.err 'G.shaderFromMemory)
+$(liftWithDestroy 'G.err 'G.shaderFromStream)
+$(lift 'G.setFloatParameter)
+$(lift 'G.setFloat2Parameter)
+$(lift 'G.setFloat3Parameter)
+$(lift 'G.setFloat4Parameter)
+$(lift 'G.setVector2Parameter)
+$(lift 'G.setVector3Parameter)
+$(lift 'G.setColorParameter)
+$(lift 'G.setTransformParameter)
+$(lift 'G.setTextureParameter)
+$(lift 'G.setCurrentTextureParameter)
+$(lift 'G.bind)
+$(lift 'G.isShaderAvailable)
+
+-- Graphics / Shape.hs
+$(liftWithDestroy 'id 'G.createShape)
+$(lift 'G.updateShape)
+
+-- Graphics / Sprite.hs
+$(liftWithDestroy 'G.err 'G.createSprite)
+$(lift 'G.setColor)
+$(lift 'G.getColor)
+
+-- Graphics / Text.hs
+$(liftWithDestroy 'G.err 'G.createText)
+$(lift 'G.setTextString)
+$(lift 'G.setTextStringU)
+$(lift 'G.setTextFont)
+$(lift 'G.setTextCharacterSize)
+$(lift 'G.setTextStyle)
+$(lift 'G.setTextColor)
+$(lift 'G.getTextString)
+$(lift 'G.getTextUnicodeString)
+$(lift 'G.getTextFont)
+$(lift 'G.getTextCharacterSize)
+$(lift 'G.getTextStyle)
+$(lift 'G.getTextColor)
+$(lift 'G.findTextCharacterPos)
+$(lift 'G.getTextLocalBounds)
+$(lift 'G.getTextGlobalBounds)
+
+-- Graphics / Texture.hs
+$(liftWithDestroy 'G.err 'G.createTexture)
+$(liftWithDestroy 'G.err 'G.textureFromFile)
+$(liftWithDestroy 'G.err 'G.textureFromMemory)
+$(liftWithDestroy 'G.err 'G.textureFromStream)
+$(liftWithDestroy 'G.err 'G.textureFromImage)
+$(lift 'G.textureSize)
+$(lift 'G.copyTextureToImage)
+$(lift 'G.updateTextureFromPixels)
+$(lift 'G.updateTextureFromImage)
+$(lift 'G.updateTextureFromWindow)
+$(lift 'G.updateTextureFromRenderWindow)
+$(lift 'G.setRepeated)
+$(lift 'G.isRepeated)
+
+-- Graphics / VertexArray.hs
+$(liftWithDestroy 'id 'G.createVA)
+$(lift 'G.getVertexCount)
+$(lift 'G.getVertex)
+$(lift 'G.clearVA)
+$(lift 'G.resizeVA)
+$(lift 'G.appendVA)
+$(lift 'G.setPrimitiveType)
+$(lift 'G.getPrimitiveType)
+$(lift 'G.getVABounds)
+
+-- Graphics / View.hs
+$(liftWithDestroy 'id 'G.createView)
+$(lift 'G.viewFromRect)
+$(lift 'G.copyView)
+$(lift 'G.setViewCenter)
+$(lift 'G.setViewSize)
+$(lift 'G.setViewRotation)
+$(lift 'G.setViewport)
+$(lift 'G.resetView)
+$(lift 'G.getViewCenter)
+$(lift 'G.getViewSize)
+$(lift 'G.getViewRotation)
+$(lift 'G.getViewViewport)
+$(lift 'G.moveView)
+$(lift 'G.rotateView)
+$(lift 'G.zoomView)
+
+-- System / Clock.hs
+$(liftWithDestroy 'id 'S.createClock)
+$(lift 'S.getElapsedTime)
+$(lift 'S.restartClock)
+
+-- System / Sleep.hsc
+$(lift 'S.sfSleep)
+
+
+-- Window / Context.hsc
+$(liftWithDestroy 'id 'W.createContext)
+$(lift 'W.setActiveContext)
+
+-- Window / Joystick.hs
+$(lift 'W.isJoystickConnected)
+$(lift 'W.getButtonCount)
+$(lift 'W.hasAxis)
+$(lift 'W.isJoystickButtonPressed)
+$(lift 'W.getAxisPosition)
+$(lift 'W.updateJoystick)
+
+-- Window / Keyboard.hs
+$(lift 'W.isKeyPressed)
+
+-- Window / Mouse.hs
+$(lift 'W.isMouseButtonPressed)
+
+-- Window / VideoMode.hs
+$(lift 'W.getDesktopMode)
+$(lift 'W.getFullscreenModes)
+$(lift 'W.isValid)
+
+-- Window / Window.hsc
+$(liftWithDestroy 'id 'W.createWindow)
+$(liftWithDestroy 'id 'W.windowFromHandle)
diff --git a/src/Control/Monad/SFML/Types.hs b/src/Control/Monad/SFML/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/SFML/Types.hs
@@ -0,0 +1,12 @@
+module Control.Monad.SFML.Types
+  ( SFML
+  , runSFML ) where
+
+import Control.Monad.State.Strict
+import Control.Monad.SFML.Types.Internal
+
+
+--------------------------------------------------------------------------------
+-- | Run the SFML monad, calling all the destructors appropriately.
+runSFML :: SFML a -> IO ()
+runSFML (SFML m) = join . fmap sequence_ . flip execStateT [] $ m
diff --git a/src/Control/Monad/SFML/Types/Internal.hs b/src/Control/Monad/SFML/Types/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/SFML/Types/Internal.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Control.Monad.SFML.Types.Internal
+  ( SFML(..)
+  , SFMLState) where
+
+import Control.Monad.State.Strict
+import Control.Applicative
+
+
+--------------------------------------------------------------------------------
+type DestroyAction = IO ()
+
+
+--------------------------------------------------------------------------------
+type SFMLState = [DestroyAction]
+
+
+--------------------------------------------------------------------------------
+newtype SFML a = SFML { unSFML :: StateT SFMLState IO a }
+  deriving (Functor, Applicative, Monad, MonadIO)
diff --git a/src/Control/Monad/SFML/Types/TH.hs b/src/Control/Monad/SFML/Types/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/SFML/Types/TH.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+module Control.Monad.SFML.Types.TH
+       ( lift
+       , lift'
+       , liftWithDestroy
+       ) where
+
+import Language.Haskell.TH
+import Data.Char
+import Control.Monad.State.Strict hiding (lift)
+import Control.Monad.SFML.Types.Internal
+import qualified SFML.Graphics as G
+
+
+{-- This module offer abstractions to easily convert
+    original low-level Haskell functions into the SFML monad
+--}
+
+--------------------------------------------------------------------------------
+-- | Generates a new function, lifted inside the SFML monad.
+lift :: Name -> Q [Dec]
+lift adapteeName = do
+  argsNum <- extractArgNum adapteeName
+  lift' adapteeName argsNum
+
+
+lift' :: Name -> Int -> Q [Dec]
+lift' adapteeName argNum = do
+  let args = mkArgs argNum
+  adapteeFn <- varE adapteeName
+  let wrapper = mkApply adapteeFn (map VarE args)
+  fnBody <- [| SFML $ liftIO $ $(return wrapper) |]
+  generateWrapper adapteeName args fnBody
+
+
+--------------------------------------------------------------------------------
+generateWrapper :: Name -> [Name] -> Exp -> Q [Dec]
+generateWrapper adapteeName args fnBody = do
+  adapterName <- newName $ nameBase adapteeName
+  adapteeFn <- varE adapteeName
+  let wrapper = mkApply adapteeFn (map VarE args)
+  return [FunD adapterName [Clause (map VarP args) (NormalB fnBody) []]]
+
+
+--------------------------------------------------------------------------------
+liftWithDestroy :: Name -> Name -> Q [Dec]
+liftWithDestroy modifier adapteeName = do
+  argsNum <- extractArgNum adapteeName
+  let args = mkArgs argsNum
+  adapteeFn <- varE adapteeName
+  let wrapper = mkApply adapteeFn (map VarE args)
+  fnBody <- [| SFML $ do
+    res <- liftIO $ $(varE modifier) $ $(return wrapper)
+    modify $ \s -> G.destroy res : s
+    return res |]
+  generateWrapper adapteeName args fnBody
+
+
+--------------------------------------------------------------------------------
+mkArgs :: Int -> [Name]
+mkArgs n = map (mkName . (:[])) . take n $ ['a' .. 'z']
+
+
+--------------------------------------------------------------------------------
+extractArgNum :: Name -> Q Int
+extractArgNum fname = do
+  info <- reify fname
+  case info of
+   (VarI _ (ForallT _ _ t) _ _) -> return . countArgs $ t
+   (VarI _ t _ _) -> return . countArgs $ t
+   (ClassOpI _ (ForallT _ _ t) _ _) -> return . countArgs $ t
+   e -> error $ show e ++ " is not a function."
+
+   where
+     countArgs (AppT (AppT ArrowT _) ts) = 1 + countArgs ts
+     countArgs _ = 0
+
+
+--------------------------------------------------------------------------------
+-- Given f and its args (e.g. x y z) builds ((f x) y) z)
+mkApply :: Exp -> [Exp] -> Exp
+mkApply fn [] = fn
+mkApply fn (x:xs) = foldl AppE (AppE fn x) xs
+
+
+--------------------------------------------------------------------------------
+capitalize [] = []
+capitalize (x:xs) = toUpper x : xs
