diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+### 0.1.1
+
+- Added a tutoral in Graphics.Luminance.
+
 ### 0.1
 
 - Initial revision. Do not consider this revision as a stable release. It’s experimental. The
diff --git a/luminance.cabal b/luminance.cabal
--- a/luminance.cabal
+++ b/luminance.cabal
@@ -1,19 +1,27 @@
 name:                luminance
-version:             0.1
+version:             0.1.1
 synopsis:            Type-safe, dependently-typed and stateless graphics framework
-description:         This package exposes several modules to work with /GPU/ in a stateless and
-                     type-safe way. Currently, it uses **OpenGL** as backend hardware technology but
-                     others will be added later on, such as **Vulkan**.
+description:         This package exposes several modules to work with /GPUs/ in a stateless and
+                     type-safe way. Currently, it uses __OpenGL__ as backend hardware technology but
+                     others will be added later on, such as __Vulkan__.
                      .
                      The initial unstable version is /0.1/. Consider everything in that version as
                      part of an experiment, even though the library should be free of bugs. If you
                      find any, please report an issue. If you think something could be enhanced,
                      feel free to fill in an issue as well.
                      .
-                     One very important point is the fact that **luminance** has nothing to do with
+                     One very important point is the fact that __luminance__ has nothing to do with
                      /3D engines/ or /scene development kits/. Don’t expect to find /materials/,
                      /lights/ or /mesh/ loaders. It’s just a graphics framework initiated to fix the
-                     design choices of **OpenGL**. It won’t change in any other way.
+                     design choices of __OpenGL__. It won’t change in any other way.
+                     .
+                     __luminance__ is a small yet powerful graphics API. It was designed so that
+                     people can quickly get their feet wet and start having fun with graphics in
+                     /Haskell/. The main idea is to unleash the graphical and visual properties of
+                     /GPUs/ in a stateless and type-safe way.
+                     .
+                     This library doesn’t expose any architectural patterns or designs. It’s up to
+                     you to design your program as you want and following your own plans.
 license:             BSD3
 license-file:        LICENSE
 author:              Dimitri Sabadie <dimitri.sabadie@gmail.com>
diff --git a/src/Graphics/Luminance.hs b/src/Graphics/Luminance.hs
--- a/src/Graphics/Luminance.hs
+++ b/src/Graphics/Luminance.hs
@@ -6,22 +6,324 @@
 -- Maintainer  : Dimitri Sabadie <dimitri.sabadie@gmail.com>
 -- Stability   : experimental
 -- Portability : portable
-----------------------------------------------------------------------------
+--
+-- = What is luminance?
+--
+-- __luminance__ is a small yet powerful graphics API. It was designed so that people can quickly
+-- get their feet wet and start having fun with graphics in /Haskell/. The main idea is to unleash
+-- the graphical and visual properties of /GPUs/ in a stateless and type-safe way.
+--
+-- This library doesn’t expose any architectural patterns or designs. It’s up to you to design your
+-- program as you want and following your own plans. Because it’s a graphics and rendering API, you
+-- won’t find several common things you find in animations, games or simulations. If you need those
+-- you’ll have to look for dedicated libraries instead.
+--
+-- One of the most important thing you have to keep in mind is the fact that luminance won’t
+-- provide you with anything else than working with the /GPU/. That is, it won’t even provide
+-- functions to open windows. That’s actually a good thing, because then you’ll be able to use it
+-- with /any kind of windowing and system library you want to/!
+--
+-- The drawback is about safety. If you screw up setting up the OpenGL context, there’s no way
+-- luminance will work. If users feel the need, a few dedicated packages will be uploaded, like
+-- __luminance-glfw__ to add "GLFW-b" support for instance.
+--
+-- = Getting started
+--
+-- == Setting up the window and OpenGL context
+--
+-- The first thing to do is to create a window. Here’s a typical "GLFW-b" snippet to create such
+-- a window.
+--
+-- @
+--   initialized <- init
+--   when initialized $ do
+-- @
+--
+-- In the first place, we initialize the "GLFW-b" library and make sure everything ran smoothly.
+--
+-- @
+--     windowHint (WindowHint'Resizable False)
+--     windowHint (WindowHint'ContextVersionMajor 4)
+--     windowHint (WindowHint'ContextVersionMinor 5)
+--     windowHint (WindowHint'OpenGLForwardCompat False)
+--     windowHint (WindowHint'OpenGLProfile OpenGLProfile'Core)
+--     window <- createWindow 800 600 "luminance application" Nothing Nothing
+-- @
+--
+-- That part just setup the window’s OpenGL hints so that we create a compatible context for
+-- luminance. luminance will work with __OpenGL 4.5__ only, don’t even try to make it work with a
+-- lower implementation. We also disable the /forward compatibility/ because we don’t need it and
+-- ask to stick to a /core/ profile.
+--
+-- @
+--     case window of
+--       Just window' -> do
+--         makeContextCurrent window
+--         swapInterval 1
+--         -- we’re good to go!
+--         destroyWindow window'
+--       Nothing -> hPutStrLn stderr "unable to create window; please check your hardware support OpenGL4.5"
+-- @
+--
+-- We then test 'window'. If we have successfully opened the window, we go on by making the OpenGL
+-- context of the window the current one for the current thread, set the swap interval (that’s not
+-- important for the purpose of that tutorial) and we’re good to go. Otherwise, we just display an
+-- error message and quit.
+--
+-- @
+--   terminate
+-- @
+--
+-- We finally close the "GLFW-b" context to cleanup everything.
+--
+-- == Preparing the environment for luminance
+--
+-- A lot of the functions you’ll use work in special types. For instance, a lot of @create*@
+-- functions will require @('MonadIO' m,'MonadResource' m,'MonadError' e m) => m@ or so. For that
+-- reason, we’ll be using a type of our own and will unwrap it so that we end up in 'IO' in the end.
+--
+-- Here’s the type:
+--
+-- @
+--   type App = ExceptT AppError (ResourceT IO)
+--
+--   newtype AppError = AppError String deriving (Eq,Show)
+-- @
+--
+-- And we’ll unwrap from our type to 'IO' with:
+--
+-- @
+--   runResourceT . runExcepT
+-- @
+--
+-- = Getting something to the screen
+--
+-- == About the screen
+--
+-- luminance generalizes OpenGL concepts so that they’re made safer. In order to render something
+-- onto the screen, you have to understand what the screen truly is. It’s actually… a back buffer –
+-- assuming we have double buffering enabled, which the case with "GLFW-b" by default. So rendering
+-- to the screen is the same thing than rendering to the back buffer and ask "GLFW-b" to swap the
+-- back buffer with the front buffer.
+--
+-- And guess what. luminance wraps the back buffer into a 'Framebuffer' object. You can access it
+-- through 'defaultFrambuffer'. That value will always represent the back buffer.
+--
+-- == About batched rendering
+--
+-- In most graphics frameworks, rendering is the act of taking an object and getting it rendered.
+-- luminance follows a different path. Because of real world needs and, well, real applications, you
+-- cannot do that in luminance. Because, what serious application will render only __one__ object?
+-- None. If so, then it’s an exception. We shouldn’t design our libraries and interface for the
+-- exceptions. We should build them for the most used case, which is, having a lot of objects in a
+-- scene.
+--
+-- That’s why luminance exposes the concept of /batched rendering/. The idea is that you have to
+-- gather you objects in /batches/ and render them all at once. That enables a correct sharing of
+-- resources – for instance, framebuffers or textures – and is very straight-forward to reason
+-- about.
+--
+-- luminance has several types of batches, each for the type of shared information. You can – up to
+-- now – shared two information between the rendered objects:
+--
+-- * /framebuffer/: that means you can create a 'FBBatch' that will gather several values under the
+--   same 'Framebuffer';
+-- * or /shaders/: that means you can create a 'SPBatch' that will gather several values under the
+--   same shader 'Program'.
+--
+-- The idea is that the 'SPBatch'es are stored in 'FBBatch'es. That creates a structure similar to
+-- an AST luminance knows how to dispatch to the GPU.
+--
+-- == About shader stages
+--
+-- luminance supports five kinds of shader stage:
+--
+-- * /tessellation evaluation shader/
+-- * /tessellation control shader/
+-- * /vertex shader/
+-- * /geometry shader/
+-- * /fragment shader/
+--
+-- Additionnaly, you can create /compute shaders/ but they’re not usable up to now.
+--
+-- When creating a new shader, you have to pass a 'String' representing the source code. This will
+-- change in the end. An EDSL is planned to make things easier and safer, but in the waiting, you
+-- are stuck with 'String', I’m sorry.
+--
+-- You have to write /GLSL450/-conformant code.
+--
+-- == About uniforms
+--
+-- Shaders are customized through uniforms. Those are very handy and very simple to use in
+-- luminance. You have the possibility to get them when creating shader 'Program's. The
+-- 'createProgram' function expects two parameters: a list of shader 'Stage's and a uniform
+-- interface builder function. That function takes another function as parameter you can use to
+-- retrieve a uniform 'U' by passing 'Either' a 'String' for the name of the uniform or a 'Natural'
+-- for its explicit semantic. Be careful when using explicit semantics though; they’re not tested.
+--
+-- Here’s an exemple of such a use:
+--
+-- @
+--   (program,uniformInterface) <- createProgram shaderStages $ \uni -> do
+--     resolutionU <- uni $ Left "resolution"
+--     timeU <- uni $ Left "time"
+--     pure $ divided resolutionU timeU
+-- @
+--
+-- In that example, @uniformInterface@ has type @U ((Float,Float),Float)@, @(Float,Float@ being the
+-- type of the @resolutionU@ part and @Float@ being the part for @timeU@. 'divided' is a method of
+-- 'Divisible' – the typeclass of divisible contravariant functors – which is defined in the
+-- "contravariant" package.
+--
+-- If you don’t need uniform interface, you can build a dummy object, like @()@, or simply use the
+-- appropriate 'createProgram_' function.
+--
+-- == About 'RenderCmd' and 'Geometry'
+--
+-- 'RenderCmd' is a very simple type yet powerful one. It’s a way to add stateless support to
+-- OpenGL render commands – draw commands, actually. It gathers several information you can set
+-- when performing a draw command. A 'RenderCmd' can hold any type of object, but the most useful
+-- version of it holds 'Geometry'.
+--
+-- A 'Geometry' is a /GPU/ version of a mesh. It’s composed of /vertices/, /indices/ and a primitive
+-- mode used to know how to link vertices between each others. Sometimes, 'Geometry' doesn’t have
+-- /indices/. That’s called __direct geometry__, because the /vertices/ are supposed to be directly
+-- used when creating primitives. If you use /indices/, then you have a __indiced geometry__ and the
+-- /vertices/ can linked by looking at the /indices/ you’ve fed in.
+--
+-- A 'Geometry' is created with the 'createGeometry' function and a 'RenderCmd' is created with
+-- 'renderCmd'. You’re supposed to create a 'Geometry' once – while loading your resources for
+-- example – and the 'RenderCmd' can be created on the fly – it doesn’t require 'IO'.
+--
+-- == Putting all together
+--
+-- Let’s draw a triangle on the screen! First, we need the vertices!
+--
+-- @
+--   vertices :: ['V' 2 'Float']
+--   vertices =
+--     [
+--       'V2' (-0.5) (-0.5)
+--     , 'V2' 0 0.5
+--     , 'V2' 0.5 (-0.5)
+--     ]
+-- @
+--
+-- @'V' 2@ is a cool type used to represent /vertex attributes/. You’ll need `DataKinds` to be able
+-- to use it.
+--
+-- Then, we don’t need /indices/ because we can directly issue a draw. Let’s then have the /GPU/
+-- version of those vertices:
+--
+-- @
+--   triangle <- 'createGeometry' vertices 'Nothing' 'Triangle'
+-- @
+--
+-- Then, we need a shader! Let’s write the vertex shader first:
+--
+-- @
+--   in vec2 co;
+--   out vec4 vertexColor;
+--    
+--   vec4 color[3] = vec4[](
+--       vec4(1., 0., 0., 1.)
+--     , vec4(0., 1., 0., 1.)
+--     , vec4(0., 0., 1., 1.)
+--     );
+--    
+--   void main() {
+--     gl_Position = vec4(co, 0., 1.);
+--     vertexColor = color[gl_VertexID];
+--   }
+-- @
+--
+-- Nothing fancy, except that we pass @vertexColor@ to the next stage so that we can blend between
+-- vertices.
+--
+-- Now, a fragment shader:
+--
+-- @
+--   in vec4 vertexColor;
+--   out vec4 frag;
+--    
+--   void main() {
+--     frag = vertexColor;
+--   }
+-- @
+--
+-- Now, let’s create the shader 'Stage's and the shader 'Program':
+--
+-- @
+--   program <- 'sequenceA' ['createVertexShader' vsSrc,'createFragmentShader' fsSrc] >>= createProgram_
+-- @
+--
+-- Once again, that’s pretty straight-forward.
+--
+-- Finally, we need the batches. We’ll need one 'FBBatch' and one 'SPBatch'.
+--
+-- @
+--   let spb = 'shaderProgramBatch_' program ['stdRenderCmd_' triangle]
+--       fbb = 'framebufferBatch' 'defaultFramebuffer' ['anySPBatch' spb]
+-- @
+--
+-- Ok, so let’s explain all of this. 'shaderProgramBatch_' is a shorter version of
+-- 'shaderProgramBatch' you can use to build 'SPBatch'. The extra underscore means you don’t want no
+-- uniform interface. We pass our @program@ and a singleton list containing a 'RenderCmd' we create
+-- with the 'stdRenderCmd_'. Once again, the extra underscore stands for no uniform interface. We
+-- then just pass our @triangle@. Notice that both 'stdRenderCmd' and 'stdRenderCmd_' disable color
+-- blending and enable depth test so that you don’t have to pass those information around.
+--
+-- Then, we create the 'FBBatch'. That is done via the 'framebufferBatch' function. It takes the
+-- 'Framebuffer' to render into – in our case, the 'defaultFramebuffer', which is the /back buffer/.
+-- We also pass a singleton list of the universally quantified 'SPBatch' with the 'anySPBatch'
+-- function.
+--
+-- We just need to issue a command to the /GPU/ to render our triangle. That is done with a
+-- constrained type, 'Cmd'.
+--
+-- @
+--   void . runCmd $ draw fbb
+-- @
+--
+-- We don’t need the result of 'runCmd' in our case so we discard it with 'void'. 'runCmd' runs in
+-- 'MonadIO'.
+--
+-- We just need to swap the buffers with @swapBuffers window@ – see "GLFW-b" for further details –
+-- and we’re good!
+--
+-- = Dealing with 'Texture2D'
+--
+-- Up to now, luminance only supports 2D-textures. More texture types will be added as luminance
+-- gets mature. The interface might change a lot, because it might be very inefficient, especially
+-- when converting from containers to others.
+-----------------------------------------------------------------------
 
 module Graphics.Luminance (
-    module X
+    module Graphics.Luminance.Batch
+  , module Graphics.Luminance.Blending
+  , module Graphics.Luminance.Buffer
+  , module Graphics.Luminance.Cmd
+  , module Graphics.Luminance.Framebuffer
+  , module Graphics.Luminance.Geometry
+  , module Graphics.Luminance.Pixel
+  , module Graphics.Luminance.Query
+  , module Graphics.Luminance.RenderCmd
+  , module Graphics.Luminance.RW
+  , module Graphics.Luminance.Shader
+  , module Graphics.Luminance.Texture
+  , module Graphics.Luminance.Vertex
   ) where
 
-import Graphics.Luminance.Batch as X
-import Graphics.Luminance.Blending as X
-import Graphics.Luminance.Buffer as X
-import Graphics.Luminance.Cmd as X
-import Graphics.Luminance.Framebuffer as X
-import Graphics.Luminance.Geometry as X
-import Graphics.Luminance.Pixel as X
-import Graphics.Luminance.Query as X
-import Graphics.Luminance.RenderCmd as X
-import Graphics.Luminance.RW as X
-import Graphics.Luminance.Shader as X
-import Graphics.Luminance.Texture as X
-import Graphics.Luminance.Vertex as X
+import Graphics.Luminance.Batch
+import Graphics.Luminance.Blending
+import Graphics.Luminance.Buffer
+import Graphics.Luminance.Cmd
+import Graphics.Luminance.Framebuffer
+import Graphics.Luminance.Geometry
+import Graphics.Luminance.Pixel
+import Graphics.Luminance.Query
+import Graphics.Luminance.RenderCmd
+import Graphics.Luminance.RW
+import Graphics.Luminance.Shader
+import Graphics.Luminance.Texture
+import Graphics.Luminance.Vertex
diff --git a/src/Graphics/Luminance/Core/Blending.hs b/src/Graphics/Luminance/Core/Blending.hs
--- a/src/Graphics/Luminance/Core/Blending.hs
+++ b/src/Graphics/Luminance/Core/Blending.hs
@@ -29,11 +29,11 @@
 --
 -- 'Additive' represents the following blending equation:
 --
--- @blended = src * srcK + dst * dstK
+-- @blended = src * srcK + dst * dstK@
 --
 -- 'Subtract' represents the following blending equation:
 --
--- @blended = src * srcK - dst * dstK
+-- @blended = src * srcK - dst * dstK@
 --
 -- Because subtracting is not commutating, 'ReverseSubtract' represents the following additional
 -- blending equation:
@@ -42,11 +42,11 @@
 --
 -- 'Min' represents the following blending equation:
 --
--- @blended = min src dst@
+-- @blended = 'min' src dst@
 --
 -- 'Max' represents the following blending equation:
 --
--- @blended = max src dst@
+-- @blended = 'max' src dst@
 data BlendingMode
   = Additive
   | Subtract
@@ -65,20 +65,22 @@
 
 -- |Blending factors.
 data BlendingFactor
-  = One
-  | Zero
-  | SrcColor
-  | NegativeSrcColor
-  | DestColor
-  | NegativeDestColor
-  | SrcAlpha
-  | NegativeSrcAlpha
-  | DstAlpha
-  | NegativeDstAlpha
-  -- | ConstantColor
-  -- | NegativeConstantColor
-  -- | ConstantAlpha
-  -- | NegativeConstantAlpha
+  = One               -- ^ 1 * color = factor
+  | Zero              -- ^ 0 * color = 0
+  | SrcColor          -- ^ src * color
+  | NegativeSrcColor  -- ^ (1 - src) * color
+  | DestColor         -- ^ dst * color
+  | NegativeDestColor -- ^ (1 - dst) * color
+  | SrcAlpha          -- ^ srcA * color
+  | NegativeSrcAlpha  -- ^ (1 - src) * color
+  | DstAlpha          -- ^ dstA * color
+  | NegativeDstAlpha  -- ^ (1 - dstA) * color
+  {-
+  | ConstantColor
+  | NegativeConstantColor
+  | ConstantAlpha
+  | NegativeConstantAlpha
+  -}
   | SrcAlphaSaturate
     deriving (Eq,Show)
 
diff --git a/src/Graphics/Luminance/Shader.hs b/src/Graphics/Luminance/Shader.hs
--- a/src/Graphics/Luminance/Shader.hs
+++ b/src/Graphics/Luminance/Shader.hs
@@ -9,9 +9,11 @@
 ----------------------------------------------------------------------------
 
 module Graphics.Luminance.Shader (
-    module X
+    module Graphics.Luminance.Shader.Program
+  , module Graphics.Luminance.Shader.Stage
+  , module Graphics.Luminance.Shader.Uniform
   ) where
 
-import Graphics.Luminance.Shader.Program as X
-import Graphics.Luminance.Shader.Stage as X
-import Graphics.Luminance.Shader.Uniform as X
+import Graphics.Luminance.Shader.Program
+import Graphics.Luminance.Shader.Stage
+import Graphics.Luminance.Shader.Uniform
