diff --git a/Graphics/GL/Low.hs b/Graphics/GL/Low.hs
--- a/Graphics/GL/Low.hs
+++ b/Graphics/GL/Low.hs
@@ -14,285 +14,45 @@
   -- process of understanding OpenGL. It seems that understanding the entire
   -- picture up-front is the only way to get started, so this should also serve
   -- as a quick reference guide to the core commands and concepts.
+  -- "Graphics.GL.Low.EntirePictureUpFront"
   --
   -- This library uses the `gl' package for raw bindings to OpenGL and the
   -- `linear' package for matrices.
-
-  -- * Example
   --
-  -- | The hello world program shows a white triangle on a black background.
-  -- It uses the packages `GLFW-b' and `monad-loops'. Note that it forces a
-  -- 3.2 core profile when setting up the context through GLFW.
   --
-  -- @
-  -- module Main where
-  --
-  -- import Control.Monad.Loops (whileM_)
-  -- import Data.Functor ((\<$\>))
-  -- import qualified Data.Vector.Storable as V
-  -- 
-  -- import qualified Graphics.UI.GLFW as GLFW
-  -- import Graphics.GL.Low
-  -- 
-  -- -- GLFW will be the shell of the demo
-  -- main = do
-  --   GLFW.init
-  --   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
-  --   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
-  --   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
-  --   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
-  --   mwin <- GLFW.createWindow 640 480 \"Hello World\" Nothing Nothing
-  --   case mwin of
-  --     Nothing  -> putStrLn "createWindow failed"
-  --     Just win -> do
-  --       GLFW.makeContextCurrent (Just win)
-  --       GLFW.swapInterval 1
-  --       (vao, prog) <- setup -- load and configure objects
-  --       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
-  --         GLFW.pollEvents
-  --         draw vao prog -- render
-  --         GLFW.swapBuffers win
-  -- 
-  -- setup = do
-  --   -- establish a VAO
-  --   vao <- newVAO
-  --   bindVAO vao
-  --   -- load shader program
-  --   vsource <- readFile "hello.vert"
-  --   fsource <- readFile "hello.frag"
-  --   prog <- newProgram vsource fsource
-  --   useProgram prog
-  --   -- load vertex data: three 2D vertex positions
-  --   let blob = V.fromList
-  --         [ -0.5, -0.5
-  --         ,    0,  0.5
-  --         ,  0.5, -0.5 ] :: V.Vector Float
-  --   vbo <- newVBO blob StaticDraw
-  --   bindVBO vbo
-  --   -- connect program to vertex data via the VAO
-  --   setVertexLayout [Attrib "position" 2 GLFloat]
-  --   return (vao, prog)
-  -- 
-  -- draw vao prog = do
-  --   clearColorBuffer (0,0,0)
-  --   bindVAO vao
-  --   useProgram prog
-  --   drawTriangles 3
-  -- @
-  --
-  -- The vertex shader file looks like
-  --
-  -- @
-  -- #version 150
-  --
-  -- in vec2 position;
-  --
-  -- void main()
-  -- {
-  --    gl_Position = vec4(position, 0.0, 1.0);
-  -- }
-  -- @
-  --
-  -- And the corresponding fragment shader file
-  --
-  -- @
-  -- #version 150
-  --
-  -- out vec4 outColor;
-  --
-  -- void main()
-  -- {
-  --   outColor = vec4(1.0, 1.0, 1.0, 1.0);
-  -- }
-  -- @
-  --
-  -- And the output should look like
-  --
-  -- <<hello_world.png Hello World>>
-
-  -- * OpenGL API Basically
-  --
-  -- | <https://www.opengl.org/registry/doc/glspec32.core.20090803.pdf The spec>
-  -- for OpenGL 3.2 is actually quite readable and is worth reviewing.
-  -- The following is my synopsis of things which roughly coincide with the
-  -- simplified OpenGL ES 2.0.
-
-  -- ** Objects
-  -- | Objects may be created and destroyed by client code. They include:
-  --
-  -- - Vertex Array Object ('VAO')
-  -- - Buffer Objects ('VBO', 'ElementArray')
-  -- - Textures ('Tex2D', 'CubeMap')
-  -- - Shader 'Program's
-  -- - Framebuffer Objects ('FBO')
-  -- - Renderbuffer Objects ('RBO')
-
-  -- ** Binding Targets
-  -- | Objects are referenced with integers (called names in GL), so binding
-  -- targets can be thought of as global variables to put those references.
-  -- Many operations implicitly read from these globals to determine what the
-  -- target object of the operation is. They include:
+  -- See specific modules for topic-specific docs and example code
   --
-  -- - Vertex array binding target (for VAO)
-  -- - Buffer binding targets (ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER)
-  -- - Texture binding targets (TEXTURE_2D and TEXTURE_CUBE_MAP)
-  -- - Framebuffer binding target (for FBO)
+  -- @"Graphics.GL.Low.VAO"@
   --
-  -- (not binding targets but similar)
+  -- @"Graphics.GL.Low.BufferObject"@
   --
-  -- - Shader program "in use"
-  -- - Texture units
-  -- - Current active texture unit
-  -- - Image attachment points of an FBO
-
-  -- ** Shader Programs
-  -- | See "Graphics.GL.Low.Shader"
-
-  -- ** VAO
-  -- | The VAO is essential. At least one VAO must be created and bound to the
-  -- vertex array binding target before rendering, before configuring a
-  -- program's vertex attributes. Here is why: the VAO stores the association
-  -- between vertex inputs in the program and a VBO from which to pipe input
-  -- from. It also stores the format of the VBO data, which is otherwise just
-  -- a big blob. Finally, the VAO stores the state of the element array binding
-  -- target used for indexed rendering.
+  -- @"Graphics.GL.Low.Shader"@
   --
-  -- After installing a program with 'useProgram' and binding a source VBO
-  -- to the array buffer binding target ('bindVBO') then the bound VAO can be
-  -- updated ('setVertexLayout') with new vertex attribute information.
-  -- After this, the VBO can be rebound to configure a different set of inputs
-  -- with a different source. Many VAOs can be created and swapped out to pipe
-  -- vertex data in different ways to different programs (or the same program).
+  -- @"Graphics.GL.Low.VertexAttrib"@
   --
-  -- When a VAO is bound ('bindVAO') it restores the state of the element array
-  -- binding target. For this reason you can think of that binding target as
-  -- simply being a function of the VAO itself rather than a separate global
-  -- state.
-
-  -- ** Uniforms and Samplers (Textures)
-  -- | Programs may also have uniform variables and "sampler uniforms" as
-  -- input. Uniforms are accessible from the vertex or fragment shader part of
-  -- the program but their values are fixed during the course of a rendering
-  -- command. They can be set and reset with the setUniform family (ex.
-  -- 'setUniform1f'), which updates the current program object with new uniform
-  -- values. Among other things, updating the uniforms each frame is the main
-  -- way to animate a scene.
+  -- @"Graphics.GL.Low.Texture"@
   --
-  -- Samplers are textures that the shader can interpolate to get "in between"
-  -- values. The texture a sampler uses is determined by the contents of the
-  -- texture unit that that sampler points to. The sampler is a uniform with
-  -- an integer type. This integer is the texture unit to use. The word texture
-  -- should not be construed to mean a color image. Shaders can make use of
-  -- many kinds of multi-dimensional data that happen to be available through
-  -- the samplers.
-
-  -- ** Texture Objects and Texture Units
-  -- | Before a shader can use a texture it must be assigned to a texture unit.
-  -- First set the active texture unit to the desired unit number
-  -- ('setActiveTextureUnit') then bind the texture object to one of the
-  -- two texture binding targets, depending on what kind of texture it is (2D
-  -- or cubemap). Binding a texture has the side effect of assigning it to the
-  -- active texture unit.
-
-  -- ** Custom Framebuffers
-  -- | It is possible (and important in many techniques) to utilize an
-  -- off-screen render target. To do this create an FBO ('newFBO'), bind it to
-  -- the framebuffer binding target ('bindFramebuffer') and attach a color
-  -- /image/ object (texture or renderbuffer object). If necessary a depth
-  -- image or combination depth-stencil image can be attached as well. If no
-  -- color image is attached then the FBO is incomplete and rendering will be
-  -- an error.  After rendering to an FBO any textures that were attached can
-  -- be used in a second pass by assigning them to a texture unit. Watch out
-  -- for feedback loops accidentally sampling a texture that is also being
-  -- rendered to at the same time!
+  -- @"Graphics.GL.Low.Render"@
   --
-  -- A renderbuffer object is a minor character to be used when you do not
-  -- expect to use the results of rendering but need an image anyway. For
-  -- example you may need a depth buffer to do depth testing, or you may want
-  -- to ignore the (required for rendering to work at all) color buffer.
-
-  -- ** Images and Image Formats
-  -- | FBOs have attachment points for /images/. A texture serves as an image
-  -- and a renderbuffer object serves as an image. Images have an "internal
-  -- format" which describes the size and interpretation of pixel components.
-  -- There are seven internal formats, five of which are color image formats
-  -- such as grayscale and RGB. The other two are the depth buffer format and
-  -- the combination depth-stencil format. RBOs ('newRBO') and empty textures
-  -- ('newEmptyTexture2D', 'newEmptyCubeMap') can be created with any of these
-  -- formats.
+  -- @"Graphics.GL.Low.Color"@
   --
-  -- (The above is a gross simplification of OpenGL's image formats. I should
-  -- probably revise, because it may greatly improve performance to use some
-  -- of the 16-bit color formats rather than 32. Also HDR color format.)
-
-  -- ** Depth Testing and Stencil Testing
-  -- | The depth test and stencil test use extra buffers in parallel with the
-  -- color buffer to cause regions of pixels to not show. It does this by
-  -- making a comparison between the depth each pixel and the value present
-  -- in those buffers, then updating the buffers as necessary. The stencil
-  -- test in particular has many configurable options. See the respective
-  -- modules for the "Graphics.GL.Low.Depth" and "Graphics.GL.Low.Stencil"
-  -- tests. 
-
-  -- ** Scissor Test
-  -- | The scissor test, if enabled ('enableScissorTest'), disallows all
-  -- rendering outside of a rectangle region of the window called the scissor
-  -- box.
-
-  -- ** Coordinate Systems (Mappings)
-  -- | There are three transformation mechanisms which work together to get raw
-  -- vertex data from VBOs to rasterized primitives somewhere on the window.
-  -- You can imagine four coordinate systems between these three transformations
-  -- if you want to.
+  -- @"Graphics.GL.Low.Depth"@
+  -- 
+  -- @"Graphics.GL.Low.Stencil"@
   --
-  -- - The __vertex shader__ takes vertex positions as specified in vertex
-  -- attributes to clip space. This is how the client code specifies a camera,
-  -- movement of objects, and perspective.
-  -- - The __perspective division__ or ""W-divide"" takes vertices from clip
-  -- space and maps them to normalized device coordinates (NDC) by dividing all
-  -- the components of the vertex by that vertex's W component. This allows a
-  -- perspective effect to be accomplished in the shader by modifying the W
-  -- components. You can't configure this W-division; it just happens.  Note
-  -- that if W = 1 for all vertices then this step has no effect. This is
-  -- useful for orthographic projections. The resulting geometry will be
-  -- clipped to a 2x2x2 cube centered around the origin. You can think of an XY
-  -- plane of this cube as the viewport of the final 2D image.
-  -- - The configurable __viewport transformation__ ('setViewport') will then
-  -- position the viewport somewhere in the window.  This step is necessary
-  -- because your window is probably not a 2x2 square.  The viewport
-  -- transformation is configured by specifying a rectangular region of your
-  -- window where you want the image to map to. The default setting for this is
-  -- to fill the entire window with the viewport.  If you didn't previously
-  -- account for your aspect ratio then this will have the effect of squishing
-  -- the scene, so you need to compensate in the vertex shader.
-
-  -- ** Rendering Points, Lines, and Triangles
-  -- | The draw family (ex. 'drawTriangles') of commands commissions the
-  -- rendering of a certain number of vertices worth of primitives. The
-  -- current program will get input from the current VAO, the current texture
-  -- units, and execute on all the potentially affected pixels in the current
-  -- framebuffer. Vertexes are consumed in the order they appear in their
-  -- respective source VBOs. If the VAO is missing, the program is missing, or
-  -- the current framebuffer has no color attachment, then rendering will not
-  -- work.
+  -- @"Graphics.GL.Low.Blending"@
   --
-  -- The drawIndexed family (ex. 'drawIndexedTriangles') of commands carries
-  -- out the same effects as the non-indexed rendering commands but traverses
-  -- vertices in an order determined by the sequence of indexes packed in the
-  -- ElementArray currently bound to the element array binding target. This
-  -- mainly allows a huge reuse of vertex data in the case that the object
-  -- being rendered forms a closed mesh.
-
+  -- @"Graphics.GL.Low.Framebuffer"@
 
   -- * VAO
-  -- | See also "Graphics.GL.Low.VAO"
+  -- | See also "Graphics.GL.Low.VAO".
   newVAO,
   bindVAO,
   deleteVAO,
   VAO,
 
   -- * Buffer Objects
-  -- | See also "Graphics.GL.Low.BufferObject"
+  -- | See also "Graphics.GL.Low.BufferObject".
   newVBO,
   newElementArray,
   bindVBO,
@@ -303,10 +63,9 @@
   VBO,
   ElementArray,
   UsageHint(..),
-  IndexFormat(..),
 
   -- * Shader Program
-  -- | See also "Graphics.GL.Low.Shader"
+  -- | See also "Graphics.GL.Low.Shader".
   newProgram,
   newProgramSafe,
   useProgram,
@@ -326,14 +85,14 @@
   ProgramError(..),
 
   -- ** Vertex Attributes
-  -- | See also "Graphics.GL.Low.VertexAttrib"
+  -- | See also "Graphics.GL.Low.VertexAttrib".
   setVertexLayout,
   VertexLayout(..),
   DataType(..),
 
 
   -- * Textures
-  -- | See also "Graphics.GL.Low.Texture"
+  -- | See also "Graphics.GL.Low.Texture".
   newTexture2D,
   newCubeMap,
   newEmptyTexture2D,
@@ -355,12 +114,9 @@
   Wrapping(..),
 
   -- * Rendering
-  -- | See also "Graphics.GL.Low.Render"
-
+  --
   -- ** Primitives
-  -- | Draw primitives to the framebuffer currently bound to the framebuffer
-  -- binding target. Each primitive drawing command takes the number of vertices
-  -- in the VBOs to render. The vertices are traversed in order.
+  -- | See also "Graphics.GL.Low.Render".
   drawPoints,
   drawLines,
   drawLineStrip,
@@ -368,11 +124,6 @@
   drawTriangles,
   drawTriangleStrip,
   drawTriangleFan,
-
-  -- ** Primitives by Index
-  -- | Draw primitives as above, but use the order of vertices defined in
-  -- the ElementArray currently bound to the element array buffer binding
-  -- target.
   drawIndexedPoints,
   drawIndexedLines,
   drawIndexedLineStrip,
@@ -380,15 +131,23 @@
   drawIndexedTriangles,
   drawIndexedTriangleStrip,
   drawIndexedTriangleFan,
+  setViewport,
+  enableScissorTest,
+  disableScissorTest,
+  enableCulling,
+  disableCulling,
+  Viewport(..),
+  Culling(..),
+  IndexFormat(..),
 
   -- ** Color Buffer
-  -- | See also "Graphics.GL.Low.Color"
+  -- | See also "Graphics.GL.Low.Color".
   enableColorWriting,
   disableColorWriting,
   clearColorBuffer,
 
   -- ** Depth Test
-  -- | See also "Graphics.GL.Low.Depth"
+  -- | See also "Graphics.GL.Low.Depth".
   enableDepthTest,
   disableDepthTest,
   clearDepthBuffer,
@@ -403,15 +162,6 @@
   StencilFunc(..),
   StencilOp(..),
 
-  -- ** Scissor Test
-  enableScissorTest,
-  disableScissorTest,
-
-  -- ** Facet Culling
-  Culling(..),
-  enableCulling,
-  disableCulling,
-
   -- ** Blending
   -- | See also "Graphics.GL.Low.Blending".
 
@@ -422,12 +172,8 @@
   BlendFactor(..),
   BlendEquation(..),
 
-  -- ** Viewport
-  Viewport(..),
-  setViewport,
-
   -- * Framebuffers
-  -- | See also "Graphics.GL.Low.Framebuffer"
+  -- | See also "Graphics.GL.Low.Framebuffer".
   DefaultFramebuffer(..),
   FBO,
   bindFramebuffer,
diff --git a/Graphics/GL/Low/Blending.hs b/Graphics/GL/Low/Blending.hs
--- a/Graphics/GL/Low/Blending.hs
+++ b/Graphics/GL/Low/Blending.hs
@@ -1,5 +1,6 @@
--- | = Blending
--- When blending is enabled, colors written to the color buffer will be
+module Graphics.GL.Low.Blending (
+
+-- | When blending is enabled, colors written to the color buffer will be
 -- blended using a formula with the color already there. The three options
 -- for the formula are:
 --
@@ -11,136 +12,16 @@
 -- factors s and d are computed blending factors which can depend on the alpha
 -- component of the source pixel, the destination pixel, or a specified
 -- constant color. See 'basicBlending' for a common choice.
---
--- = Example
---
--- @
--- module Main where
--- 
--- import Control.Monad.Loops (whileM_)
--- import Data.Functor ((\<$\>))
--- import qualified Data.Vector.Storable as V
--- import Control.Concurrent.STM
--- 
--- import qualified Graphics.UI.GLFW as GLFW
--- import Linear
--- import Graphics.GL.Low
--- 
--- main = do
---   GLFW.init
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
---   mwin <- GLFW.createWindow 640 480 \"Blending\" Nothing Nothing
---   case mwin of
---     Nothing  -> putStrLn "createWindow failed"
---     Just win -> do
---       GLFW.makeContextCurrent (Just win)
---       GLFW.swapInterval 1
---       shouldSwap <- newTVarIO False
---       (GLFW.setKeyCallback win . Just)
---         (\_ _ _ _ _ -> atomically (modifyTVar shouldSwap not))
---       (vao, prog) <- setup
---       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
---         GLFW.pollEvents
---         draw vao prog shouldSwap
---         GLFW.swapBuffers win
--- 
--- setup = do
---   vao <- newVAO
---   bindVAO vao
---   vsource <- readFile "blending.vert"
---   fsource <- readFile "blending.frag"
---   prog <- newProgram vsource fsource
---   useProgram prog
---   let blob = V.fromList
---         [ -0.5,  0.5
---         ,  0.5,    0
---         , -0.5, -0.5 ] :: V.Vector Float
---   vbo <- newVBO blob StaticDraw
---   bindVBO vbo
---   setVertexLayout [Attrib "position" 2 GLFloat]
---   enableBlending basicBlending
---   return (vao, prog)
--- 
--- draw vao prog shouldSwap = do
---   clearColorBuffer (0,0,0)
---   yes <- readTVarIO shouldSwap
---   if yes
---     then sequence [drawRed, drawGreen]
---     else sequence [drawGreen, drawRed]
--- 
--- drawGreen = do
---   setUniform3f "color" [V3 0 1 0]
---   setUniform1f "alpha" [0.5]
---   setUniform44 "move" [eye4]
---   drawTriangles 3
--- 
--- drawRed = do
---   let ninety = pi/2
---   let move = mkTransformation (axisAngle (V3 0 0 1) ninety) (V3 0.25 0.5 0)
---   setUniform3f "color" [V3 1 0 0]
---   setUniform1f "alpha" [0.5]
---   setUniform44 "move" [transpose move]
---   drawTriangles 3
--- @
--- 
--- blending.vert
---
--- @
--- #version 150
--- 
--- in vec3 Color;
--- in float Alpha;
--- out vec4 outColor;
--- 
--- void main()
--- {
---     outColor = vec4(Color, Alpha);
--- }
--- @
---
--- blending.frag
---
--- @
--- #version 150
--- 
--- uniform vec3 color;
--- uniform float alpha;
--- uniform mat4 move;
--- 
--- in vec2 position;
--- out vec3 Color;
--- out float Alpha;
--- 
--- void main()
--- {
---     gl_Position = move * vec4(position, 0.0, 1.0);
---     Color = color;
---     Alpha = alpha;
--- }
--- @
---
--- This program draws two half-transparent shapes. When you press a key they
--- are rendered in the opposite order. This makes one appear as if it were in
--- front of the other. Because the depth test (see "Graphics.GL.Low.Depth")
--- must be disabled while using this kind of blending, there may be significant
--- overdraw in areas with many blending layers. This can harm performance.
--- Also the order-dependency can make using alpha blending in a 3D scene
--- complex or impossible. It may make more sense to use an off-screen render
--- pass (see "Graphics.GL.Low.Framebuffer") and an appropriate shader to
--- simulate transparency effects.
---
--- <<blending1.png Blending Before>> <<blending2.png Blending After>>
 
-module Graphics.GL.Low.Blending (
   enableBlending,
   disableBlending,
   basicBlending,
   Blending(..),
   BlendFactor(..),
   BlendEquation(..)
+
+  -- * Example
+  -- $example
 ) where
 
 import Data.Default
@@ -243,3 +124,124 @@
   toGL BlendOneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA
 
 
+-- $example
+--
+-- <<blending1.png Blending Before>> <<blending2.png Blending After>>
+--
+-- This program draws two half-transparent shapes. When you press a key they
+-- are rendered in the opposite order. This makes one appear as if it were in
+-- front of the other. Because the depth test (see "Graphics.GL.Low.Depth")
+-- must be disabled while using this kind of blending, there may be significant
+-- overdraw in areas with many blending layers. This can harm performance.
+-- Also the order-dependency can make using alpha blending in a 3D scene
+-- complex or impossible. It may make more sense to use an off-screen render
+-- pass (see "Graphics.GL.Low.Framebuffer") and an appropriate shader to
+-- simulate transparency effects.
+--
+-- @
+-- module Main where
+-- 
+-- import Control.Monad.Loops (whileM_)
+-- import Data.Functor ((\<$\>))
+-- import qualified Data.Vector.Storable as V
+-- import Control.Concurrent.STM
+-- 
+-- import qualified Graphics.UI.GLFW as GLFW
+-- import Linear
+-- import Graphics.GL.Low
+-- 
+-- main = do
+--   GLFW.init
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
+--   mwin <- GLFW.createWindow 640 480 \"Blending\" Nothing Nothing
+--   case mwin of
+--     Nothing  -> putStrLn "createWindow failed"
+--     Just win -> do
+--       GLFW.makeContextCurrent (Just win)
+--       GLFW.swapInterval 1
+--       shouldSwap <- newTVarIO False
+--       (GLFW.setKeyCallback win . Just)
+--         (\_ _ _ _ _ -> atomically (modifyTVar shouldSwap not))
+--       (vao, prog) <- setup
+--       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
+--         GLFW.pollEvents
+--         draw vao prog shouldSwap
+--         GLFW.swapBuffers win
+-- 
+-- setup = do
+--   vao <- newVAO
+--   bindVAO vao
+--   vsource <- readFile "blending.vert"
+--   fsource <- readFile "blending.frag"
+--   prog <- newProgram vsource fsource
+--   useProgram prog
+--   let blob = V.fromList
+--         [ -0.5,  0.5
+--         ,  0.5,    0
+--         , -0.5, -0.5 ] :: V.Vector Float
+--   vbo <- newVBO blob StaticDraw
+--   bindVBO vbo
+--   setVertexLayout [Attrib "position" 2 GLFloat]
+--   enableBlending basicBlending
+--   return (vao, prog)
+-- 
+-- draw vao prog shouldSwap = do
+--   clearColorBuffer (0,0,0)
+--   yes <- readTVarIO shouldSwap
+--   if yes
+--     then sequence [drawRed, drawGreen]
+--     else sequence [drawGreen, drawRed]
+-- 
+-- drawGreen = do
+--   setUniform3f "color" [V3 0 1 0]
+--   setUniform1f "alpha" [0.5]
+--   setUniform44 "move" [eye4]
+--   drawTriangles 3
+-- 
+-- drawRed = do
+--   let ninety = pi/2
+--   let move = mkTransformation (axisAngle (V3 0 0 1) ninety) (V3 0.25 0.5 0)
+--   setUniform3f "color" [V3 1 0 0]
+--   setUniform1f "alpha" [0.5]
+--   setUniform44 "move" [transpose move]
+--   drawTriangles 3
+-- @
+-- 
+-- blending.vert
+--
+-- @
+-- #version 150
+-- 
+-- in vec3 Color;
+-- in float Alpha;
+-- out vec4 outColor;
+-- 
+-- void main()
+-- {
+--     outColor = vec4(Color, Alpha);
+-- }
+-- @
+--
+-- blending.frag
+--
+-- @
+-- #version 150
+-- 
+-- uniform vec3 color;
+-- uniform float alpha;
+-- uniform mat4 move;
+-- 
+-- in vec2 position;
+-- out vec3 Color;
+-- out float Alpha;
+-- 
+-- void main()
+-- {
+--     gl_Position = move * vec4(position, 0.0, 1.0);
+--     Color = color;
+--     Alpha = alpha;
+-- }
+-- @
diff --git a/Graphics/GL/Low/BufferObject.hs b/Graphics/GL/Low/BufferObject.hs
--- a/Graphics/GL/Low/BufferObject.hs
+++ b/Graphics/GL/Low/BufferObject.hs
@@ -2,13 +2,16 @@
 
 -- | Buffer Objects are objects for holding arbitrary blobs of bytes. This
 -- library exposes two types of buffer objects: VBOs and ElementArrays.
---
--- = VBO
---
--- Vertex Buffer Objects (VBO) contain data for a sequence of vertices. A
+
+module Graphics.GL.Low.BufferObject (
+
+-- * VBO
+
+-- | Vertex Buffer Objects (VBO) contain data for a sequence of vertices. A
 -- vertex shader interprets the data for each vertex by mapping the attributes
 -- of the vertex (position, normal vector, etc) to input variables using the
--- VAO. /VBOs have the data which is used as input to the vertex shader according to the configuration of the VAO/.
+-- VAO. VBOs have the data which is used as input to the vertex shader
+-- according to the configuration of the VAO/.
 --
 -- Example VBO contents:
 --
@@ -16,10 +19,10 @@
 --
 -- The shader will interpret those parts of the VBO as illustrated only after
 -- appropiately configuring a VAO. See "Graphics.GL.Low.VAO".
---
--- = ElementArray
---
--- Element arrays are buffer objects that contain a sequence of indices. When
+
+-- * ElementArray
+
+-- | Element arrays are buffer objects that contain a sequence of indices. When
 -- using indexed rendering, the bound element array determines the order that
 -- the vertices in the VBOs are visited to construct primitives. This allows
 -- sharing vertices in cases that many vertices overlap with each other. OpenGL
@@ -37,17 +40,18 @@
 -- the primitive render commands will simply traverse the vertices in order
 -- specified in the VBOs.
 
-module Graphics.GL.Low.BufferObject (
-  VBO,
-  ElementArray,
-  UsageHint(..),
+-- * Documentation
+
   newVBO,
   updateVBO,
   bindVBO,
   newElementArray,
   updateElementArray,
   bindElementArray,
-  deleteBufferObject
+  deleteBufferObject,
+  VBO,
+  ElementArray,
+  UsageHint(..)
 ) where
 
 import Foreign.Ptr
diff --git a/Graphics/GL/Low/EntirePictureUpFront.hs b/Graphics/GL/Low/EntirePictureUpFront.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/GL/Low/EntirePictureUpFront.hs
@@ -0,0 +1,277 @@
+module Graphics.GL.Low.EntirePictureUpFront (
+
+  -- * OpenGL API Basically
+  --
+  -- | <https://www.opengl.org/registry/doc/glspec32.core.20090803.pdf The spec>
+  -- for OpenGL 3.2 is actually quite readable and is worth reviewing.
+  -- The following is my synopsis of things which roughly coincide with the
+  -- simplified OpenGL ES 2.0.
+
+  -- ** Objects
+  -- | Objects may be created and destroyed by client code. They include:
+  --
+  -- - Vertex Array Object ('Graphics.GL.Low.VAO.VAO')
+  -- - Buffer Objects ('Graphics.GL.Low.BufferObject.VBO', 'Graphics.GL.Low.BufferObject.ElementArray')
+  -- - Textures ('Graphics.GL.Low.Texture.Tex2D', 'Graphics.GL.Low.Texture.CubeMap')
+  -- - Shader 'Graphics.GL.Low.Shader.Program's
+  -- - Framebuffer Objects ('Graphics.GL.Low.Framebuffer.FBO')
+  -- - Renderbuffer Objects ('Graphics.GL.Low.Framebuffer.RBO')
+
+  -- ** Binding Targets
+  -- | Objects are referenced with integers (called names in GL), so binding
+  -- targets can be thought of as global variables to put those references.
+  -- Many operations implicitly read from these globals to determine what the
+  -- target object of the operation is. They include:
+  --
+  -- - Vertex array binding target (for VAO)
+  -- - Buffer binding targets (ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER)
+  -- - Texture binding targets (TEXTURE_2D and TEXTURE_CUBE_MAP)
+  -- - Framebuffer binding target (for FBO)
+  --
+  -- (not binding targets but similar)
+  --
+  -- - Shader program "in use"
+  -- - Texture units
+  -- - Current active texture unit
+  -- - Image attachment points of an FBO
+
+  -- ** Shader Programs
+  -- | See "Graphics.GL.Low.Shader"
+
+  -- ** VAO
+  -- | The VAO is essential. At least one VAO must be created and bound to the
+  -- vertex array binding target before rendering, before configuring a
+  -- program's vertex attributes. Here is why: the VAO stores the association
+  -- between vertex inputs in the program and a VBO from which to pipe input
+  -- from. It also stores the format of the VBO data, which is otherwise just
+  -- a big blob. Finally, the VAO stores the state of the element array binding
+  -- target used for indexed rendering.
+  --
+  -- After installing a program with 'Graphics.GL.Low.Shader.useProgram' and
+  -- binding a source VBO to the array buffer binding target
+  -- ('Graphics.GL.Low.BufferObject.bindVBO') then the bound VAO can be updated
+  -- ('Graphics.GL.Low.VertexAttrib.setVertexLayout') with new vertex attribute
+  -- information. After this, the VBO can be rebound to configure a different
+  -- set of inputs with a different source. Many VAOs can be created and
+  -- swapped out to pipe vertex data in different ways to different programs
+  -- (or the same program).
+  --
+  -- When a VAO is bound ('Graphics.GL.Low.VAO.bindVAO') it restores the state
+  -- of the element array binding target. For this reason you can think of that
+  -- binding target as simply being a function of the VAO itself rather than a
+  -- separate global state.
+
+  -- ** Uniforms and Samplers (Textures)
+  -- | Programs may also have uniform variables and "sampler uniforms" as
+  -- input. Uniforms are accessible from the vertex or fragment shader part of
+  -- the program but their values are fixed during the course of a rendering
+  -- command. They can be set and reset with the setUniform family (ex.
+  -- 'Graphics.GL.Low.Shader.setUniform1f'), which updates the current program
+  -- object with new uniform values. Among other things, updating the uniforms
+  -- each frame is the main way to animate a scene.
+  --
+  -- Samplers are textures that the shader can interpolate to get "in between"
+  -- values. The texture a sampler uses is determined by the contents of the
+  -- texture unit that that sampler points to. The sampler is a uniform with
+  -- an integer type. This integer is the texture unit to use. The word texture
+  -- should not be construed to mean a color image. Shaders can make use of
+  -- many kinds of multi-dimensional data that happen to be available through
+  -- the samplers.
+
+  -- ** Texture Objects and Texture Units
+  -- | Before a shader can use a texture it must be assigned to a texture unit.
+  -- First set the active texture unit to the desired unit number
+  -- ('Graphics.GL.Texture.setActiveTextureUnit') then bind the texture object
+  -- to one of the two texture binding targets, depending on what kind of
+  -- texture it is (2D or cubemap). Binding a texture has the side effect of
+  -- assigning it to the active texture unit.
+
+  -- ** Custom Framebuffers
+  -- | It is possible (and important in many techniques) to utilize an
+  -- off-screen render target. To do this create an FBO
+  -- ('Graphics.GL.Low.Framebuffer.newFBO'), bind it to the framebuffer binding
+  -- target ('Graphics.GL.Low.Framebuffer.bindFramebuffer') and attach a color
+  -- /image/ object (texture or renderbuffer object). If necessary a depth
+  -- image or combination depth-stencil image can be attached as well. If no
+  -- color image is attached then the FBO is incomplete and rendering will be
+  -- an error.  After rendering to an FBO any textures that were attached can
+  -- be used in a second pass by assigning them to a texture unit. Watch out
+  -- for feedback loops accidentally sampling a texture that is also being
+  -- rendered to at the same time!
+  --
+  -- A renderbuffer object is a minor character to be used when you do not
+  -- expect to use the results of rendering but need an image anyway. For
+  -- example you may need a depth buffer to do depth testing, or you may want
+  -- to ignore the (required for rendering to work at all) color buffer.
+
+  -- ** Images and Image Formats
+  -- | FBOs have attachment points for /images/. A texture serves as an image
+  -- and a renderbuffer object serves as an image. Images have an "internal
+  -- format" which describes the size and interpretation of pixel components.
+  -- There are seven internal formats, five of which are color image formats
+  -- such as grayscale and RGB. The other two are the depth buffer format and
+  -- the combination depth-stencil format. RBOs
+  -- ('Graphics.GL.Low.Framebuffer.newRBO') and empty textures
+  -- ('Graphics.GL.Low.Texture.newEmptyTexture2D',
+  -- 'Graphics.GL.Low.Texture.newEmptyCubeMap') can be created with any of
+  -- these formats.
+  --
+  -- (The above is a gross simplification of OpenGL's image formats. I should
+  -- probably revise, because it may greatly improve performance to use some
+  -- of the 16-bit color formats rather than 32. Also HDR color format.)
+
+  -- ** Depth Testing and Stencil Testing
+  -- | The depth test and stencil test use extra buffers in parallel with the
+  -- color buffer to cause regions of pixels to not show. It does this by
+  -- making a comparison between the depth each pixel and the value present
+  -- in those buffers, then updating the buffers as necessary. The stencil
+  -- test in particular has many configurable options. See the respective
+  -- modules for the "Graphics.GL.Low.Depth" and "Graphics.GL.Low.Stencil"
+  -- tests. 
+
+  -- ** Scissor Test
+  -- | The scissor test, if enabled
+  -- ('Graphics.GL.Low.Render.enableScissorTest'), disallows all rendering
+  -- outside of a rectangle region of the window called the scissor box.
+
+  -- ** Coordinate Systems (Mappings)
+  -- | There are three transformation mechanisms which work together to get raw
+  -- vertex data from VBOs to rasterized primitives somewhere on the window.
+  -- You can imagine four coordinate systems between these three transformations
+  -- if you want to.
+  --
+  -- - The __vertex shader__ takes vertex positions as specified in vertex
+  -- attributes to clip space. This is how the client code specifies a camera,
+  -- movement of objects, and perspective.
+  -- - The __perspective division__ or ""W-divide"" takes vertices from clip
+  -- space and maps them to normalized device coordinates (NDC) by dividing all
+  -- the components of the vertex by that vertex's W component. This allows a
+  -- perspective effect to be accomplished in the shader by modifying the W
+  -- components. You can't configure this W-division; it just happens.  Note
+  -- that if W = 1 for all vertices then this step has no effect. This is
+  -- useful for orthographic projections. The resulting geometry will be
+  -- clipped to a 2x2x2 cube centered around the origin. You can think of an XY
+  -- plane of this cube as the viewport of the final 2D image.
+  -- - The configurable __viewport transformation__
+  -- ('Graphics.GL.Low.Render.setViewport') will then position the viewport
+  -- somewhere in the window.  This step is necessary because your window is
+  -- probably not a 2x2 square.  The viewport transformation is configured by
+  -- specifying a rectangular region of your window where you want the image to
+  -- map to. The default setting for this is to fill the entire window with the
+  -- viewport.  If you didn't previously account for your aspect ratio then
+  -- this will have the effect of squishing the scene, so you need to
+  -- compensate in the vertex shader.
+
+  -- ** Rendering Points, Lines, and Triangles
+  -- | The draw family (ex. 'Graphics.GL.Low.Render.drawTriangles') of commands
+  -- commissions the rendering of a certain number of vertices worth of
+  -- primitives. The current program will get input from the current VAO, the
+  -- current texture units, and execute on all the potentially affected pixels
+  -- in the current framebuffer. Vertexes are consumed in the order they appear
+  -- in their respective source VBOs. If the VAO is missing, the program is
+  -- missing, or the current framebuffer has no color attachment, then
+  -- rendering will not work.
+  --
+  -- The drawIndexed family (ex. 'Graphics.GL.Low.Render.drawIndexedTriangles')
+  -- of commands carries out the same effects as the non-indexed rendering
+  -- commands but traverses vertices in an order determined by the sequence of
+  -- indexes packed in the ElementArray currently bound to the element array
+  -- binding target. This mainly allows a huge reuse of vertex data in the case
+  -- that the object being rendered forms a closed mesh.
+
+  -- * Example
+  --
+  -- | The hello world program shows a white triangle on a black background.
+  -- It uses the packages `GLFW-b' and `monad-loops'. Note that it forces a
+  -- 3.2 core profile when setting up the context through GLFW.
+  --
+  -- @
+  -- module Main where
+  --
+  -- import Control.Monad.Loops (whileM_)
+  -- import Data.Functor ((\<$\>))
+  -- import qualified Data.Vector.Storable as V
+  -- 
+  -- import qualified Graphics.UI.GLFW as GLFW
+  -- import Graphics.GL.Low
+  -- 
+  -- -- GLFW will be the shell of the demo
+  -- main = do
+  --   GLFW.init
+  --   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
+  --   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
+  --   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
+  --   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
+  --   mwin <- GLFW.createWindow 640 480 \"Hello World\" Nothing Nothing
+  --   case mwin of
+  --     Nothing  -> putStrLn "createWindow failed"
+  --     Just win -> do
+  --       GLFW.makeContextCurrent (Just win)
+  --       GLFW.swapInterval 1
+  --       (vao, prog) <- setup -- load and configure objects
+  --       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
+  --         GLFW.pollEvents
+  --         draw vao prog -- render
+  --         GLFW.swapBuffers win
+  -- 
+  -- setup = do
+  --   -- establish a VAO
+  --   vao <- newVAO
+  --   bindVAO vao
+  --   -- load shader program
+  --   vsource <- readFile "hello.vert"
+  --   fsource <- readFile "hello.frag"
+  --   prog <- newProgram vsource fsource
+  --   useProgram prog
+  --   -- load vertex data: three 2D vertex positions
+  --   let blob = V.fromList
+  --         [ -0.5, -0.5
+  --         ,    0,  0.5
+  --         ,  0.5, -0.5 ] :: V.Vector Float
+  --   vbo <- newVBO blob StaticDraw
+  --   bindVBO vbo
+  --   -- connect program to vertex data via the VAO
+  --   setVertexLayout [Attrib "position" 2 GLFloat]
+  --   return (vao, prog)
+  -- 
+  -- draw vao prog = do
+  --   clearColorBuffer (0,0,0)
+  --   bindVAO vao
+  --   useProgram prog
+  --   drawTriangles 3
+  -- @
+  --
+  -- The vertex shader file looks like
+  --
+  -- @
+  -- #version 150
+  --
+  -- in vec2 position;
+  --
+  -- void main()
+  -- {
+  --    gl_Position = vec4(position, 0.0, 1.0);
+  -- }
+  -- @
+  --
+  -- And the corresponding fragment shader file
+  --
+  -- @
+  -- #version 150
+  --
+  -- out vec4 outColor;
+  --
+  -- void main()
+  -- {
+  --   outColor = vec4(1.0, 1.0, 1.0, 1.0);
+  -- }
+  -- @
+  --
+  -- And the output should look like
+  --
+  -- <<hello_world.png Hello World>>
+
+
+) where
+
+
diff --git a/Graphics/GL/Low/Framebuffer.hs b/Graphics/GL/Low/Framebuffer.hs
--- a/Graphics/GL/Low/Framebuffer.hs
+++ b/Graphics/GL/Low/Framebuffer.hs
@@ -1,37 +1,31 @@
--- | Framebuffers, FBO, RBO...
---
--- == Example
---
--- This example program renders an animating object to an off-screen
--- framebuffer. The resulting texture is then show on a full-screen quad
--- with an effect.
---
--- @
---
--- @
---
--- The vertex shader for this program is
---
--- @
---
--- @
---
--- The two fragment shaders, one for the object, one for the effect, are
---
--- @
+{-# LANGUAGE RankNTypes #-}
+module Graphics.GL.Low.Framebuffer (
+
+-- | By default, rendering commands output graphics to the default framebuffer.
+-- This includes the color buffer, the depth buffer, and the stencil buffer. It
+-- is possible to render to a texture instead. This is important for many
+-- techniques. Rendering to a texture (either color, depth, or depth/stencil)
+-- is accomplished by using a framebuffer object (FBO).
 --
--- @
+-- The following ritual sets up an FBO with a blank 256x256 color texture for
+-- off-screen rendering:
 --
 -- @
---
+-- do
+--   fbo <- newFBO
+--   tex <- newEmptyTexture2D 256 256 :: IO (Tex2D RGB)
+--   bindFramebuffer fbo
+--   attachTex2D tex
+--   bindFramebuffer DefaultFramebuffer
+--   return (fbo, tex)
 -- @
 --
--- And the output looks like
---
--- <<framebuffer.gif Animated screenshot showing post-processing effect>>
+-- After binding an FBO to the framebuffer binding target, rendering commands
+-- will output to its color attachment and possible depth/stencil attachment
+-- if present. An FBO must have a color attachment before rendering. If only
+-- the depth results are needed, then you can attach a color RBO instead of
+-- a texture to the color attachment point.
 
-{-# LANGUAGE RankNTypes #-}
-module Graphics.GL.Low.Framebuffer (
   newFBO,
   bindFramebuffer,
   deleteFBO,
@@ -42,7 +36,11 @@
   deleteRBO,
   FBO,
   DefaultFramebuffer(..),
-  RBO,
+  RBO
+
+  -- * Example
+  -- $example
+ 
 ) where
 
 import Foreign.Ptr
@@ -145,3 +143,157 @@
 -- | Delete an RBO.
 deleteRBO :: RBO a -> IO ()
 deleteRBO (RBO n) = withArray [n] (\ptr -> glDeleteRenderbuffers 1 ptr)
+
+
+-- $example
+--
+-- <<framebuffer.gif Animated screenshot showing post-processing effect>>
+--
+-- This example program renders an animating object to an off-screen
+-- framebuffer. The resulting texture is then shown on a full-screen quad
+-- with an effect.
+--
+-- @
+-- module Main where
+-- 
+-- import Control.Monad.Loops (whileM_)
+-- import Data.Functor ((\<$\>))
+-- import qualified Data.Vector.Storable as V
+-- import Data.Maybe (fromJust)
+-- import Data.Default
+-- import Data.Word
+-- 
+-- import qualified Graphics.UI.GLFW as GLFW
+-- import Linear
+-- import Graphics.GL.Low
+-- 
+-- main = do
+--   GLFW.init
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
+--   mwin <- GLFW.createWindow 640 480 \"Framebuffer\" Nothing Nothing
+--   case mwin of
+--     Nothing  -> putStrLn "createWindow failed"
+--     Just win -> do
+--       GLFW.makeContextCurrent (Just win)
+--       GLFW.swapInterval 1
+--       (vao1, vao2, prog1, prog2, fbo, texture) <- setup
+--       whileM_ (not <$> GLFW.windowShouldClose win) $ do
+--         GLFW.pollEvents
+--         t <- (realToFrac . fromJust) \<$\> GLFW.getTime
+--         draw vao1 vao2 prog1 prog2 fbo texture t
+--         GLFW.swapBuffers win
+-- 
+-- setup = do
+--   -- primary subject
+--   vao1 <- newVAO
+--   bindVAO vao1
+--   let blob = V.fromList
+--         [ -0.5, -0.5, 0, 0
+--         ,  0,    0.5, 0, 1
+--         ,  0.5, -0.5, 1, 1] :: V.Vector Float
+--   vbo <- newVBO blob StaticDraw
+--   bindVBO vbo
+--   vsource  <- readFile "framebuffer.vert"
+--   fsource1 <- readFile "framebuffer1.frag"
+--   prog1 <- newProgram vsource fsource1
+--   useProgram prog1
+--   setVertexLayout
+--     [ Attrib "position" 2 GLFloat
+--     , Attrib "texcoord" 2 GLFloat ]
+-- 
+--   -- full-screen quad to show the post-processed scene
+--   vao2 <- newVAO
+--   bindVAO vao2
+--   let blob = V.fromList
+--         [ -1, -1, 0, 0
+--         , -1,  1, 0, 1
+--         ,  1, -1, 1, 0
+--         ,  1,  1, 1, 1] :: V.Vector Float
+--   vbo <- newVBO blob StaticDraw
+--   bindVBO vbo
+--   indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw
+--   bindElementArray indices
+--   fsource2 <- readFile "framebuffer2.frag"
+--   prog2 <- newProgram vsource fsource2
+--   useProgram prog2
+--   setVertexLayout
+--     [ Attrib "position" 2 GLFloat
+--     , Attrib "texcoord" 2 GLFloat ]
+-- 
+--   -- create an FBO to render the primary scene on
+--   fbo <- newFBO
+--   bindFramebuffer fbo
+--   texture <- newEmptyTexture2D 640 480 :: IO (Tex2D RGB)
+--   bindTexture2D texture
+--   setTex2DFiltering Linear
+--   attachTex2D texture
+--   return (vao1, vao2, prog1, prog2, fbo, texture)
+-- 
+-- draw :: VAO -> VAO -> Program -> Program -> FBO -> Tex2D RGB -> Float -> IO ()
+-- draw vao1 vao2 prog1 prog2 fbo texture t = do
+--   -- render primary scene to fbo
+--   bindVAO vao1
+--   bindFramebuffer fbo
+--   useProgram prog1
+--   clearColorBuffer (0,0,0)
+--   setUniform1f "time" [t]
+--   drawTriangles 3
+-- 
+--   -- render results to quad on main screen
+--   bindVAO vao2
+--   bindFramebuffer DefaultFramebuffer
+--   useProgram prog2
+--   bindTexture2D texture
+--   clearColorBuffer (0,0,0)
+--   setUniform1f "time" [t]
+--   drawIndexedTriangles 6 UByteIndices
+-- @
+--
+-- The vertex shader for this program is
+--
+-- @
+-- #version 150
+-- in vec2 position;
+-- in vec2 texcoord;
+-- out vec2 Texcoord;
+-- void main()
+-- {
+--     gl_Position = vec4(position, 0.0, 1.0);
+--     Texcoord = texcoord;
+-- }
+-- @
+--
+-- The two fragment shaders, one for the object, one for the effect, are
+--
+-- @
+-- #version 150
+-- uniform float time;
+-- in vec2 Texcoord;
+-- out vec4 outColor;
+-- void main()
+-- {
+--   float t = time;
+--   outColor = vec4(
+--     fract(Texcoord.x*5) < 0.5 ? sin(t*0.145) : cos(t*0.567),
+--     fract(Texcoord.y*5) < 0.5 ? cos(t*0.534) : sin(t*0.321),
+--     0.0, 1.0
+--   );
+-- }
+-- @
+--
+-- @
+-- #version 150
+-- uniform float time;
+-- uniform sampler2D tex;
+-- in vec2 Texcoord;
+-- out vec4 outColor;
+-- 
+-- void main()
+-- {
+--   float d = pow(10,(abs(cos(time))+1.5));
+--   outColor c = texture(tex, floor(Texcoord*d)/d);
+-- }
+-- @
diff --git a/Graphics/GL/Low/Render.hs b/Graphics/GL/Low/Render.hs
--- a/Graphics/GL/Low/Render.hs
+++ b/Graphics/GL/Low/Render.hs
@@ -1,7 +1,11 @@
 module Graphics.GL.Low.Render (
-  Culling(..),
-  Viewport(..),
-  IndexFormat(..),
+
+  -- * Primitives
+  --
+  -- | Render various kinds of primitives to the current framebuffer using
+  -- the current shader program. The integer argument is the number of
+  -- vertices to read from the VBOs via the current VAO.
+  --
   drawPoints,
   drawLines,
   drawLineStrip,
@@ -9,6 +13,13 @@
   drawTriangles,
   drawTriangleStrip,
   drawTriangleFan,
+
+  -- * Primitives (by index)
+  --
+  -- | Render various kinds of primitives by traversing the vertices in the
+  -- order specified in the current ElementArray. The format argument indicates
+  -- the size of each index in the ElementArray.
+  --
   drawIndexedPoints,
   drawIndexedLines,
   drawIndexedLineStrip,
@@ -16,11 +27,21 @@
   drawIndexedTriangles,
   drawIndexedTriangleStrip,
   drawIndexedTriangleFan,
+
+  -- * Scissor Test
   enableScissorTest,
   disableScissorTest,
+
+  -- * Facet Culling
   enableCulling,
   disableCulling,
-  setViewport
+
+  -- * Viewport
+  setViewport,
+
+  Culling(..),
+  Viewport(..),
+  IndexFormat(..)
 ) where
 
 import Foreign.Ptr
diff --git a/Graphics/GL/Low/Shader.hs b/Graphics/GL/Low/Shader.hs
--- a/Graphics/GL/Low/Shader.hs
+++ b/Graphics/GL/Low/Shader.hs
@@ -1,3 +1,6 @@
+
+{-# LANGUAGE DeriveDataTypeable #-}
+module Graphics.GL.Low.Shader (
 -- | A shader program is composed of two cooperating parts: the vertex program
 -- and the fragment program. The vertex program is executed once for each
 -- vertex. The fragment program is executed once for each pixel covered by
@@ -28,159 +31,10 @@
 -- - a color (this is more complicated in reality but close enough)
 -- - the depth of the pixel, gl_FragDepth, which will default to the pixel's Z.
 --
--- = Example
---
--- @
--- module Main where
--- 
--- import Control.Monad.Loops (whileM_)
--- import Data.Functor ((\<$\>))
--- import qualified Data.Vector.Storable as V
--- import Data.Maybe (fromJust)
--- 
--- import qualified Graphics.UI.GLFW as GLFW
--- import Linear
--- import Graphics.GL.Low
--- 
--- main = do
---   GLFW.init
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
---   mwin <- GLFW.createWindow 640 480 \"Shaders\" Nothing Nothing
---   case mwin of
---     Nothing  -> putStrLn "createWindow failed"
---     Just win -> do
---       GLFW.makeContextCurrent (Just win)
---       GLFW.swapInterval 1
---       (vao, prog1, prog2, prog3) <- setup
---       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
---         GLFW.pollEvents
---         t <- (realToFrac . fromJust) \<$\> GLFW.getTime
---         draw vao prog1 prog2 prog3 t
---         GLFW.swapBuffers win
--- 
--- setup = do
---   vao <- newVAO
---   bindVAO vao
---   vsource <- readFile "shader.vert"
---   fsource1 <- readFile "shader1.frag"
---   fsource2 <- readFile "shader2.frag"
---   fsource3 <- readFile "shader3.frag"
---   prog1 <- newProgram vsource fsource1
---   prog2 <- newProgram vsource fsource2
---   prog3 <- newProgram vsource fsource3
---   useProgram prog1
---   let blob = V.fromList
---         [ -0.4, -0.4, 0, 0
---         ,  0,    0.4, 0, 1
---         ,  0.4, -0.4, 1, 1] :: V.Vector Float
---   vbo <- newVBO blob StaticDraw
---   bindVBO vbo
---   setVertexLayout
---     [ Attrib "position" 2 GLFloat
---     , Attrib "location" 2 GLFloat ]
---   return (vao, prog1, prog2, prog3)
--- 
--- draw vao prog1 prog2 prog3 t = do
---   clearColorBuffer (0,0,0)
---   bindVAO vao
---   drawThing prog1 t (V3 (-0.5)   0.5    0.0)
---   drawThing prog2 t (V3   0.5    0.5    0.0)
---   drawThing prog3 t (V3   0.0  (-0.5) (-0.0))
--- 
--- drawThing :: Program -> Float -> V3 Float -> IO ()
--- drawThing prog t shift = do
---   let angle = t / 5
---   let move = mkTransformation (axisAngle (V3 0 0 1) angle) shift
---   useProgram prog
---   setUniform1f "time" [t]
---   setUniform44 "move" [transpose move]
---   drawTriangles 3
--- @
---
--- Where the vertex shader is
---
--- @
--- #version 150
--- uniform mat4 move;
--- in vec2 position;
--- in vec2 location;
--- out vec2 Location;
--- void main()
--- {
---     gl_Position = move * vec4(position, 0.0, 1.0);
---     Location = location;
--- }
--- @
---
--- And the three fragment shaders are
---
--- @
--- #version 150
--- uniform float time;
--- in vec2 Location;
--- out vec4 outColor;
--- void main()
--- {
---   float x = gl_FragCoord.x / 640;
---   float y = gl_FragCoord.y / 480;
---   outColor = vec4(
---     fract(x*25) < 0.5 ? 1.0 : 0.0,
---     fract(y*25) < 0.5 ? 1.0 : 0.0,
---     0.0, 1.0
---   );
--- }
--- @
---
--- @
--- #version 150
--- uniform float time;
--- in vec2 Location;
--- out vec4 outColor;
--- void main()
--- {
---   outColor = vec4(
---     fract(Location.x*10) < 0.5 ? 1.0 : 0.0,
---     fract(Location.y*10) < 0.5 ? 1.0 : 0.0,
---     0.0, 1.0
---   );
--- }
--- @
---
--- @
--- #version 150
--- uniform float time;
--- in vec2 Location;
--- out vec4 outColor;
--- void main()
--- {
---   float t = time;
---   outColor = vec4(
---     fract(Location.x*5) < 0.5 ? sin(t*3.145) : cos(t*4.567),
---     fract(Location.y*5) < 0.5 ? cos(t*6.534) : sin(t*4.321),
---     0.0, 1.0
---   );
--- }
--- @
---
--- The output should look like
---
--- <<shaders.gif 3 Different Shaders Animated Demo>>
---
--- Where the window coordinates, the interpolated location on the triangle,
--- and the elapsed time are used to color the triangle respectively.
---
-
-{-# LANGUAGE DeriveDataTypeable #-}
-module Graphics.GL.Low.Shader (
-  Program,
-  ProgramError(..),
-  newProgramSafe,
-  deleteProgram,
   newProgram,
+  newProgramSafe,
   useProgram,
+  deleteProgram,
   setUniform1f,
   setUniform2f,
   setUniform3f,
@@ -191,7 +45,12 @@
   setUniform4i,
   setUniform44,
   setUniform33,
-  setUniform22
+  setUniform22,
+  Program,
+  ProgramError(..)
+
+  -- * Example
+  -- $example
 ) where
 
 import Foreign.Ptr
@@ -345,3 +204,145 @@
         else glAction loc (fromIntegral n) bytes
 
 
+-- $example
+--
+-- <<shaders.gif 3 Different Shaders Animated Demo>>
+--
+-- This example renders three differently-shaded triangles. The window
+-- coordinates, the interpolated location on the triangle, and the elapsed time
+-- are used to color the triangles respectively.
+--
+-- @
+-- module Main where
+-- 
+-- import Control.Monad.Loops (whileM_)
+-- import Data.Functor ((\<$\>))
+-- import qualified Data.Vector.Storable as V
+-- import Data.Maybe (fromJust)
+-- 
+-- import qualified Graphics.UI.GLFW as GLFW
+-- import Linear
+-- import Graphics.GL.Low
+-- 
+-- main = do
+--   GLFW.init
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
+--   mwin <- GLFW.createWindow 640 480 \"Shaders\" Nothing Nothing
+--   case mwin of
+--     Nothing  -> putStrLn "createWindow failed"
+--     Just win -> do
+--       GLFW.makeContextCurrent (Just win)
+--       GLFW.swapInterval 1
+--       (vao, prog1, prog2, prog3) <- setup
+--       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
+--         GLFW.pollEvents
+--         t <- (realToFrac . fromJust) \<$\> GLFW.getTime
+--         draw vao prog1 prog2 prog3 t
+--         GLFW.swapBuffers win
+-- 
+-- setup = do
+--   vao <- newVAO
+--   bindVAO vao
+--   vsource <- readFile "shader.vert"
+--   fsource1 <- readFile "shader1.frag"
+--   fsource2 <- readFile "shader2.frag"
+--   fsource3 <- readFile "shader3.frag"
+--   prog1 <- newProgram vsource fsource1
+--   prog2 <- newProgram vsource fsource2
+--   prog3 <- newProgram vsource fsource3
+--   useProgram prog1
+--   let blob = V.fromList
+--         [ -0.4, -0.4, 0, 0
+--         ,  0,    0.4, 0, 1
+--         ,  0.4, -0.4, 1, 1] :: V.Vector Float
+--   vbo <- newVBO blob StaticDraw
+--   bindVBO vbo
+--   setVertexLayout
+--     [ Attrib "position" 2 GLFloat
+--     , Attrib "location" 2 GLFloat ]
+--   return (vao, prog1, prog2, prog3)
+-- 
+-- draw vao prog1 prog2 prog3 t = do
+--   clearColorBuffer (0,0,0)
+--   bindVAO vao
+--   drawThing prog1 t (V3 (-0.5)   0.5    0.0)
+--   drawThing prog2 t (V3   0.5    0.5    0.0)
+--   drawThing prog3 t (V3   0.0  (-0.5) (-0.0))
+-- 
+-- drawThing :: Program -> Float -> V3 Float -> IO ()
+-- drawThing prog t shift = do
+--   let angle = t / 5
+--   let move = mkTransformation (axisAngle (V3 0 0 1) angle) shift
+--   useProgram prog
+--   setUniform1f "time" [t]
+--   setUniform44 "move" [transpose move]
+--   drawTriangles 3
+-- @
+--
+-- Where the vertex shader is
+--
+-- @
+-- #version 150
+-- uniform mat4 move;
+-- in vec2 position;
+-- in vec2 location;
+-- out vec2 Location;
+-- void main()
+-- {
+--     gl_Position = move * vec4(position, 0.0, 1.0);
+--     Location = location;
+-- }
+-- @
+--
+-- And the three fragment shaders are
+--
+-- @
+-- #version 150
+-- uniform float time;
+-- in vec2 Location;
+-- out vec4 outColor;
+-- void main()
+-- {
+--   float x = gl_FragCoord.x / 640;
+--   float y = gl_FragCoord.y / 480;
+--   outColor = vec4(
+--     fract(x*25) < 0.5 ? 1.0 : 0.0,
+--     fract(y*25) < 0.5 ? 1.0 : 0.0,
+--     0.0, 1.0
+--   );
+-- }
+-- @
+--
+-- @
+-- #version 150
+-- uniform float time;
+-- in vec2 Location;
+-- out vec4 outColor;
+-- void main()
+-- {
+--   outColor = vec4(
+--     fract(Location.x*10) < 0.5 ? 1.0 : 0.0,
+--     fract(Location.y*10) < 0.5 ? 1.0 : 0.0,
+--     0.0, 1.0
+--   );
+-- }
+-- @
+--
+-- @
+-- #version 150
+-- uniform float time;
+-- in vec2 Location;
+-- out vec4 outColor;
+-- void main()
+-- {
+--   float t = time;
+--   outColor = vec4(
+--     fract(Location.x*5) < 0.5 ? sin(t*3.145) : cos(t*4.567),
+--     fract(Location.y*5) < 0.5 ? cos(t*6.534) : sin(t*4.321),
+--     0.0, 1.0
+--   );
+-- }
+-- @
diff --git a/Graphics/GL/Low/Stencil.hs b/Graphics/GL/Low/Stencil.hs
--- a/Graphics/GL/Low/Stencil.hs
+++ b/Graphics/GL/Low/Stencil.hs
@@ -1,3 +1,5 @@
+module Graphics.GL.Low.Stencil (
+
 -- | The stencil test is like a configurable depth test with a dedicated
 -- additional buffer. Like the depth test, if the stencil test fails then the
 -- pixel being tested will not be rendered. The stencil test happens before the
@@ -17,7 +19,6 @@
 -- - When the stencil test passes then the depth test fails or
 -- - When both tests pass.
 
-module Graphics.GL.Low.Stencil (
   enableStencil,
   disableStencil,
   clearStencilBuffer,
diff --git a/Graphics/GL/Low/Texture.hs b/Graphics/GL/Low/Texture.hs
--- a/Graphics/GL/Low/Texture.hs
+++ b/Graphics/GL/Low/Texture.hs
@@ -1,3 +1,5 @@
+module Graphics.GL.Low.Texture (
+
 -- | Textures are objects that contain image data that can be sampled by
 -- a shader. While an obvious application of this is texture mapping, there
 -- are many other uses for textures (the image data doesn't have to be an
@@ -11,113 +13,7 @@
 -- points to by setting it using the 'Graphics.GL.Low.Shader.setUniform1i'
 -- command. You can avoid dealing with active texture units if theres only one
 -- sampler because the default unit is zero.
---
--- == Example
---
--- This example loads a 256x256 PNG file with JuicyPixels and displays the
--- image on a square. Of course without a correction for aspect ratio the
--- square will only be square if you adjust your window to be square.
---
--- @
--- module Main where
--- 
--- import Control.Monad.Loops (whileM_)
--- import Data.Functor ((\<$\>))
--- import qualified Data.Vector.Storable as V
--- import Codec.Picture
--- import Data.Word
--- 
--- import qualified Graphics.UI.GLFW as GLFW
--- import Linear
--- import Graphics.GL.Low
--- 
--- main = do
---   GLFW.init
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
---   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
---   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
---   mwin <- GLFW.createWindow 640 480 \"Texture\" Nothing Nothing
---   case mwin of
---     Nothing  -> putStrLn "createWindow failed"
---     Just win -> do
---       GLFW.makeContextCurrent (Just win)
---       GLFW.swapInterval 1
---       (vao, prog, texture) <- setup
---       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
---         GLFW.pollEvents
---         draw vao prog texture
---         GLFW.swapBuffers win
--- 
--- setup = do
---   -- establish a VAO
---   vao <- newVAO
---   bindVAO vao
---   -- load the shader
---   vsource <- readFile "texture.vert"
---   fsource <- readFile "texture.frag"
---   prog <- newProgram vsource fsource
---   useProgram prog
---   -- load the vertices
---   let blob = V.fromList -- a quad has four vertices
---         [ -0.5, -0.5, 0, 1
---         , -0.5,  0.5, 0, 0
---         ,  0.5, -0.5, 1, 1
---         ,  0.5,  0.5, 1, 0 ] :: V.Vector Float
---   vbo <- newVBO blob StaticDraw
---   bindVBO vbo
---   setVertexLayout [ Attrib "position" 2 GLFloat
---                   , Attrib "texcoord" 2 GLFloat ]
---   -- load the element array to draw a quad with two triangles
---   indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw
---   bindElementArray indices
---   -- load the texture with JuicyPixels
---   let fromRight (Right x) = x
---   ImageRGBA8 (Image w h image) <- fromRight \<$\> readImage "logo.png"
---   texture <- newTexture2D image (Dimensions w h) :: IO (Tex2D RGBA)
---   setTex2DFiltering Linear
---   return (vao, prog, texture)
--- 
--- draw vao prog texture = do
---   clearColorBuffer (0.5, 0.5, 0.5)
---   bindVAO vao
---   useProgram prog
---   bindTexture2D texture
---   drawIndexedTriangles 6 UByteIndices
--- @
---
--- The vertex shader for this example looks like
---
--- @
--- #version 150
--- in vec2 position;
--- in vec2 texcoord;
--- out vec2 Texcoord;
--- void main()
--- {
---     gl_Position = vec4(position, 0.0, 1.0);
---     Texcoord = texcoord;
--- }
--- @
---
--- And the fragment shader looks like
---
--- @
--- #version 150
--- in vec2 Texcoord;
--- out vec4 outColor;
--- uniform sampler2D tex;
--- void main()
--- {
---   outColor = texture(tex, Texcoord);
--- }
--- @
---
--- Should produce output like
---
--- <<texture.png Screenshot of Texture Example>>
 
-module Graphics.GL.Low.Texture (
   newTexture2D,
   newCubeMap,
   newEmptyTexture2D,
@@ -134,7 +30,11 @@
   CubeMap,
   Filtering(..),
   Wrapping(..),
-  Dimensions(..),
+  Dimensions(..)
+
+  -- * Example
+  -- $example
+
 ) where
 
 import Foreign.Ptr
@@ -330,3 +230,106 @@
 
 instance GLObject (CubeMap a) where
   glObjectName (CubeMap n) = fromIntegral n
+
+-- $example
+--
+-- <<texture.png Screenshot of Texture Example>>
+--
+-- This example loads a 256x256 PNG file with JuicyPixels and displays the
+-- image on a square. Of course without a correction for aspect ratio the
+-- square will only be square if you adjust your window to be square.
+--
+-- @
+-- module Main where
+-- 
+-- import Control.Monad.Loops (whileM_)
+-- import Data.Functor ((\<$\>))
+-- import qualified Data.Vector.Storable as V
+-- import Codec.Picture
+-- import Data.Word
+-- 
+-- import qualified Graphics.UI.GLFW as GLFW
+-- import Linear
+-- import Graphics.GL.Low
+-- 
+-- main = do
+--   GLFW.init
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)
+--   GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)
+--   GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)
+--   mwin <- GLFW.createWindow 640 480 \"Texture\" Nothing Nothing
+--   case mwin of
+--     Nothing  -> putStrLn "createWindow failed"
+--     Just win -> do
+--       GLFW.makeContextCurrent (Just win)
+--       GLFW.swapInterval 1
+--       (vao, prog, texture) <- setup
+--       whileM_ (not \<$\> GLFW.windowShouldClose win) $ do
+--         GLFW.pollEvents
+--         draw vao prog texture
+--         GLFW.swapBuffers win
+-- 
+-- setup = do
+--   -- establish a VAO
+--   vao <- newVAO
+--   bindVAO vao
+--   -- load the shader
+--   vsource <- readFile "texture.vert"
+--   fsource <- readFile "texture.frag"
+--   prog <- newProgram vsource fsource
+--   useProgram prog
+--   -- load the vertices
+--   let blob = V.fromList -- a quad has four vertices
+--         [ -0.5, -0.5, 0, 1
+--         , -0.5,  0.5, 0, 0
+--         ,  0.5, -0.5, 1, 1
+--         ,  0.5,  0.5, 1, 0 ] :: V.Vector Float
+--   vbo <- newVBO blob StaticDraw
+--   bindVBO vbo
+--   setVertexLayout [ Attrib "position" 2 GLFloat
+--                   , Attrib "texcoord" 2 GLFloat ]
+--   -- load the element array to draw a quad with two triangles
+--   indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw
+--   bindElementArray indices
+--   -- load the texture with JuicyPixels
+--   let fromRight (Right x) = x
+--   ImageRGBA8 (Image w h image) <- fromRight \<$\> readImage "logo.png"
+--   texture <- newTexture2D image (Dimensions w h) :: IO (Tex2D RGBA)
+--   setTex2DFiltering Linear
+--   return (vao, prog, texture)
+-- 
+-- draw vao prog texture = do
+--   clearColorBuffer (0.5, 0.5, 0.5)
+--   bindVAO vao
+--   useProgram prog
+--   bindTexture2D texture
+--   drawIndexedTriangles 6 UByteIndices
+-- @
+--
+-- The vertex shader for this example looks like
+--
+-- @
+-- #version 150
+-- in vec2 position;
+-- in vec2 texcoord;
+-- out vec2 Texcoord;
+-- void main()
+-- {
+--     gl_Position = vec4(position, 0.0, 1.0);
+--     Texcoord = texcoord;
+-- }
+-- @
+--
+-- And the fragment shader looks like
+--
+-- @
+-- #version 150
+-- in vec2 Texcoord;
+-- out vec4 outColor;
+-- uniform sampler2D tex;
+-- void main()
+-- {
+--   outColor = texture(tex, Texcoord);
+-- }
+-- @
diff --git a/Graphics/GL/Low/VAO.hs b/Graphics/GL/Low/VAO.hs
--- a/Graphics/GL/Low/VAO.hs
+++ b/Graphics/GL/Low/VAO.hs
@@ -1,3 +1,6 @@
+
+module Graphics.GL.Low.VAO (
+
 -- | Vertex Array Objects (VAO). Despite having almost no operations of its
 -- own, the VAO mechanism is one of the most complex pieces of OpenGL. A VAO
 -- has mutable state which associates vertex shader input variables (actually
@@ -52,12 +55,10 @@
 -- }
 -- @
 
-module Graphics.GL.Low.VAO 
-(
-  VAO,
   newVAO,
   deleteVAO,
-  bindVAO
+  bindVAO,
+  VAO
 ) where
 
 import Foreign.Storable
diff --git a/Graphics/GL/Low/VertexAttrib.hs b/Graphics/GL/Low/VertexAttrib.hs
--- a/Graphics/GL/Low/VertexAttrib.hs
+++ b/Graphics/GL/Low/VertexAttrib.hs
@@ -1,9 +1,8 @@
+module Graphics.GL.Low.VertexAttrib (
 -- | To feed vertices into the vertex shader, the layout of a vertex must be
 -- specified in the current VAO for the current shader program. Make a list of
 -- LayoutElements and use 'setVertexLayout' on it as seen below.
 --
--- == Example
---
 -- @
 -- setVertexLayout
 --   [ Attrib "position"  3 GLFloat   -- first 12 bytes maps to: in vec3 position;
@@ -17,8 +16,6 @@
 -- In this example four mappings from the current VBO to the variables
 -- in the current Program will be established in the current VAO.
 
-
-module Graphics.GL.Low.VertexAttrib (
   setVertexLayout,
   VertexLayout(..),
   DataType(..)
diff --git a/lowgl.cabal b/lowgl.cabal
--- a/lowgl.cabal
+++ b/lowgl.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.3.1.0
+version:             0.3.1.1
 
 -- A short (one-line) description of the package.
 synopsis:            Basic gl wrapper and reference
@@ -56,6 +56,7 @@
                        Graphics.GL.Low.Cube
                        Graphics.GL.Low.Depth
                        Graphics.GL.Low.Error
+                       Graphics.GL.Low.EntirePictureUpFront
                        Graphics.GL.Low.Framebuffer
                        Graphics.GL.Low.ImageFormat
                        Graphics.GL.Low.Render
@@ -89,4 +90,4 @@
 source-repository this
   type: git
   location: https://github.com/evanrinehart/lowgl
-  tag: 0.3.1.0
+  tag: 0.3.1.1
