diff --git a/Graphics/GL/Low.hs b/Graphics/GL/Low.hs
--- a/Graphics/GL/Low.hs
+++ b/Graphics/GL/Low.hs
@@ -1,8 +1,6 @@
 module Graphics.GL.Low (
 
-  -- * In a Nutshell
-  --
-  -- ** Overview
+  -- * Overview
   -- | OpenGL is a graphics rendering interface. This library exposes a vastly
   -- simplified subset of OpenGL that is hopefully still complete enough for
   -- many purposes, such as following tutorials, making simple games, and
@@ -19,6 +17,105 @@
   -- 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 \"Demo\" 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
+  --   setVertexAttributeLayout [Attrib "position" 2 VFloat]
+  --   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
+  --
+  -- <<demo.png Demo>>
+
+  -- * 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:
   --
@@ -159,15 +256,15 @@
   -- - 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
+  -- - 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 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.
+  -- 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
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
@@ -1,3 +1,4 @@
+{-# LANGUAGE ScopedTypeVariables #-}
 -- | VBO and ElementArrays. Both are buffer objects but are used for two
 -- different things.
 module Graphics.GL.Low.BufferObject (
@@ -14,6 +15,7 @@
 ) where
 
 import Foreign.Ptr
+import Foreign.ForeignPtr
 import Foreign.Marshal
 import Foreign.Storable
 import qualified Data.Vector.Storable as V
@@ -57,17 +59,8 @@
 
 -- | Create a buffer object from a blob of bytes. The usage argument hints
 -- at how often you will modify the data.
-newVBO :: Vector Word8 -> UsageHint -> IO VBO
-newVBO src usage = do
-  n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
-  let len = V.length src
-  glBindBuffer GL_ARRAY_BUFFER n
-  V.unsafeWith src $ \ptr -> glBufferData
-    GL_ARRAY_BUFFER
-    (fromIntegral len)
-    (castPtr ptr)
-    (toGL usage)
-  return (VBO n)
+newVBO :: Storable a => Vector a -> UsageHint -> IO VBO
+newVBO = newBufferObject VBO GL_ARRAY_BUFFER
 
 -- | Delete a VBO or ElementArray.
 deleteBufferObject :: BufferObject a => a -> IO ()
@@ -75,14 +68,8 @@
 
 -- | Modify the data in the currently bound VBO starting from the specified
 -- index in bytes.
-updateVBO :: Vector Word8 -> Int -> IO ()
-updateVBO src offset = do
-  let len = V.length src
-  V.unsafeWith src $ \ptr -> glBufferSubData
-    GL_ARRAY_BUFFER 
-    (fromIntegral offset)
-    (fromIntegral len)
-    (castPtr ptr)
+updateVBO :: Storable a => Vector a -> Int -> IO ()
+updateVBO = updateBufferObject GL_ARRAY_BUFFER
 
 -- | Bind a VBO to the array buffer binding target. The buffer object bound
 -- there will be replaced, if any.
@@ -92,32 +79,42 @@
 
 -- | Create a new ElementArray buffer object from the blob of packed indices.
 -- The usage argument hints at how often you plan to modify the data.
-newElementArray :: Vector Word8 -> UsageHint -> IO ElementArray
-newElementArray bytes usage = do
-  n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
-  glBindBuffer GL_ELEMENT_ARRAY_BUFFER n
-  let len = V.length bytes
-  V.unsafeWith bytes $ \ptr -> do
-    glBufferData
-      GL_ELEMENT_ARRAY_BUFFER
-      (fromIntegral len)
-      (castPtr ptr)
-      (toGL usage)
-  return (ElementArray n)
+newElementArray :: Storable a => Vector a -> UsageHint -> IO ElementArray
+newElementArray = newBufferObject ElementArray GL_ELEMENT_ARRAY_BUFFER
 
 -- | Modify contents in the currently bound ElementArray starting at the
 -- specified index in bytes.
-updateElementArray :: Vector Word8 -> Int -> IO ()
-updateElementArray bytes offset = V.unsafeWith bytes $ \ptr -> do
-  glBufferSubData
-    GL_ELEMENT_ARRAY_BUFFER
-    (fromIntegral offset)
-    (fromIntegral (V.length bytes))
-    (castPtr ptr)
-
+updateElementArray :: Storable a => Vector a -> Int -> IO ()
+updateElementArray = updateBufferObject GL_ELEMENT_ARRAY_BUFFER
 
 -- | Assign an ElementArray to the element array binding target. It will
 -- replace the ElementArray already bound there, if any. Note that the state
 -- of the element array binding target is a function of the current VAO.
 bindElementArray :: ElementArray -> IO ()
 bindElementArray (ElementArray n) = glBindBuffer GL_ELEMENT_ARRAY_BUFFER n
+
+
+newBufferObject :: forall a b . Storable a => (GLuint -> b) -> GLenum -> Vector a -> UsageHint -> IO b
+newBufferObject ctor target src usage = do
+  n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
+  glBindBuffer target n
+  let (fptr, off, len) = V.unsafeToForeignPtr src
+  let size = sizeOf (undefined :: a)
+  withForeignPtr fptr $ \ptr -> glBufferData
+    target
+    (fromIntegral (len * size))
+    (castPtr (ptr `plusPtr` off))
+    (toGL usage)
+  return (ctor n)
+
+updateBufferObject :: forall a . Storable a => GLenum -> Vector a -> Int -> IO ()
+updateBufferObject target bytes offset = do
+  let (fptr, off, len) = V.unsafeToForeignPtr bytes
+  let size = sizeOf (undefined :: a)
+  withForeignPtr fptr $ \ptr -> glBufferSubData
+    target
+    (fromIntegral offset)
+    (fromIntegral (len * size))
+    (castPtr (ptr `plusPtr` off))
+
+
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
@@ -87,7 +87,7 @@
 drawTriangleFan = drawArrays GL_TRIANGLE_FAN
 
 drawArrays :: GLenum -> Int -> IO ()
-drawArrays mode n = glDrawArrays mode (fromIntegral n) 0
+drawArrays mode n = glDrawArrays mode 0 (fromIntegral n)
 
 drawIndexedPoints :: Int -> IndexFormat -> IO ()
 drawIndexedPoints = drawIndexed GL_POINTS
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
@@ -116,12 +116,17 @@
       let total = totalLayout layout
       forM_ layout' $ \(name, size, offset, fmt) -> do
         attrib <- withCString name $ \ptr -> glGetAttribLocation (fromIntegral p) (castPtr ptr)
+        let stride = total - size * sizeOfVertexComponent fmt
         let norm = isNormalized fmt
         glVertexAttribPointer
           (fromIntegral attrib)
           (fromIntegral size)
           (toGL fmt)
-          (fromIntegral . fromEnum $ norm)
-          (fromIntegral offset)
+          (toGL norm)
+          (fromIntegral stride)
           (castPtr (nullPtr `plusPtr` offset))
         glEnableVertexAttribArray (fromIntegral attrib)
+
+instance ToGL Bool where
+  toGL True = GL_TRUE
+  toGL False = GL_FALSE
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.2.0.1
+version:             0.2.1.0
 
 -- A short (one-line) description of the package.
 synopsis:            Basic gl wrapper and reference
@@ -89,4 +89,4 @@
 source-repository this
   type: git
   location: https://github.com/evanrinehart/lowgl
-  tag: 0.2.0.1
+  tag: 0.2.1.0
