diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,3 +3,17 @@
 [![Build Status](https://travis-ci.org/ocramz/plot-light.png)](https://travis-ci.org/ocramz/plot-light)
 
 A lightweight plotting library, exporting to SVG
+
+
+## Usage
+
+Import the user-facing module: `Graphics.Rendering.Plot.Light.Internal`
+
+`plot-light` provides functionality for rendering vector graphics as SVG.
+It is geared in particular towards scientific plotting, and it is termed "light" because it only requires native Haskell dependencies.
+
+It builds upon `blaze-svg` by adding type-safe combinators, geometry primitives and functionality
+
+To use this project you just need to import this module qualified (to avoid name clashes with any other modules you might have loaded on the side), for example as follows :
+
+@import Graphics.Rendering.Plot.Light as P@
diff --git a/plot-light.cabal b/plot-light.cabal
--- a/plot-light.cabal
+++ b/plot-light.cabal
@@ -1,5 +1,5 @@
 name:                plot-light
-version:             0.1.0.3
+version:             0.1.0.4
 synopsis:            A lightweight plotting library, exporting to SVG
 description:         A lightweight plotting library, exporting to SVG
 homepage:            https://github.com/ocramz/plot-light
@@ -27,7 +27,8 @@
                        Graphics.Rendering.Plot.Light.IO.Text
                        Graphics.Rendering.Plot.Light.PlotTypes.Heatmap
                        Graphics.Rendering.Plot.Light.PlotTypes.TimeSeries
-                       Graphics.Rendering.Plot.Light.PlotTypes.TimeSeries.Candlestick                          Data.TimeSeries.Forex
+                       Graphics.Rendering.Plot.Light.PlotTypes.TimeSeries.Candlestick
+                       Data.TimeSeries.Forex
                        Graphics.Rendering.Plot.Light.Internal.Types
                        Graphics.Rendering.Plot.Light.Internal.Geometry
   build-depends:       base >= 4.7 && < 5
@@ -40,6 +41,8 @@
                      , colour
                      , palette
                      , blaze-svg
+                     , hspec
+                     , QuickCheck                     
 
 executable plot-light
   default-language:    Haskell2010
diff --git a/src/Graphics/Rendering/Plot/Light.hs b/src/Graphics/Rendering/Plot/Light.hs
--- a/src/Graphics/Rendering/Plot/Light.hs
+++ b/src/Graphics/Rendering/Plot/Light.hs
@@ -1,6 +1,51 @@
 {-# LANGUAGE OverloadedStrings #-}
-module Graphics.Rendering.Plot.Light (module Plot) where
 
+-- |
+-- Module      :  Graphics.Rendering.Plot.Light
+-- Copyright   :  Marco Zocca 2017
+-- License     :  BSD3
+-- Maintainer  :  Marco Zocca <zocca marco gmail>
+--
+-- `plot-light` provides functionality for rendering vector
+-- graphics in SVG format. It is geared in particular towards scientific plotting,
+-- and it is termed "light" because it only requires few native Haskell dependencies.
+--
+-- It builds upon `blaze-svg` by adding type-safe combinators,
+-- geometry primitives and related functions.
+--
+-- == Usage
+--
+-- To use this project you just need to import this module qualified (to avoid name clashes with any other modules you might have loaded on the side), for example as follows :
+--
+-- @import Graphics.Rendering.Plot.Light as P@
+--
+-- If you wish to try out the examples in this page, you will need to have `renderSvg` in scope as well:
+--
+-- @import Text.Blaze.Svg.Renderer.String (renderSvg)@
+
+module Graphics.Rendering.Plot.Light (
+  -- * Graphical elements
+  rectCentered, line, axis, text, polyline,
+  -- * Types
+  FigureData(..), Point(..), LabeledPoint(..), Axis(..),
+  mkFigureData, svgHeader,
+  -- * Geometry
+  -- ** Vectors
+  V2(..),
+  -- ** Matrices
+  Mat2(..), DiagMat2(..), diagMat2,
+  -- ** Primitive elements
+  origin, e1, e2,
+  -- ** Vector operations 
+  norm2, normalize2,
+  -- ** Vector construction
+  mkV2fromEndpoints, v2fromPoint, 
+  -- ** Operations on points
+  movePoint, moveLabeledPointV2, fromUnitSquare, toUnitSquare,
+  -- ** Typeclasses
+  AdditiveGroup(..), VectorSpace(..), Hermitian(..), LinearMap(..), MultiplicativeSemigroup(..), MatrixGroup(..)
+  ) where
+
 -- import Data.Foldable
 import qualified Data.Text as T
 
@@ -15,7 +60,7 @@
 import qualified Data.Colour.SRGB as C
 
 
-import Graphics.Rendering.Plot.Light.Internal as Plot
+import Graphics.Rendering.Plot.Light.Internal
 
 
 
diff --git a/src/Graphics/Rendering/Plot/Light/Internal.hs b/src/Graphics/Rendering/Plot/Light/Internal.hs
--- a/src/Graphics/Rendering/Plot/Light/Internal.hs
+++ b/src/Graphics/Rendering/Plot/Light/Internal.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
-module Graphics.Rendering.Plot.Light.Internal (FigureData(..), Point(..), LabeledPoint(..), Axis(..), mkFigureData, figure, rectCentered, line, tick, ticks, axis, text, polyline, V2(..), Mat2, DiagMat2, diagMat2, AdditiveGroup(..), VectorSpace(..), Hermitian(..), LinearMap(..), MultiplicativeSemigroup(..), MatrixGroup(..), norm2, normalize2, mkV2fromEndpoints, v2fromPoint, origin, movePoint, moveLabeledPointV2, fromUnitSquare, toUnitSquare, e1, e2) where
+module Graphics.Rendering.Plot.Light.Internal (FigureData(..), Point(..), LabeledPoint(..), Axis(..), mkFigureData, svgHeader, rectCentered, line, tick, ticks, axis, text, polyline, V2(..), Mat2(..), DiagMat2(..), diagMat2, AdditiveGroup(..), VectorSpace(..), Hermitian(..), LinearMap(..), MultiplicativeSemigroup(..), MatrixGroup(..), norm2, normalize2, mkV2fromEndpoints, v2fromPoint, origin, movePoint, moveLabeledPointV2, fromUnitSquare, toUnitSquare, e1, e2) where
 
 import Data.Monoid ((<>))
 import Control.Arrow ((&&&), (***))
@@ -28,15 +28,20 @@
 
 
 
-mkFigureData :: Num a => a -> a -> a -> a -> FigureData a
-mkFigureData xmin ymin xlen ylen =
-  FigData xlen ylen xmin (xmin + xlen) ymin (ymin + ylen)
+-- | Create a `FigureData` structure from the top-left corner point and its side lengths
+mkFigureData :: Num a =>
+          Point a      
+       -> a
+       -> a
+       -> FigureData a
+mkFigureData (Point xmi ymi) xlen ylen =
+  FigData xlen ylen xmi (xmi + xlen) ymi (ymi + ylen)
 
 
 
--- | Header for a Figure
-figure :: FigureData Int -> Svg -> Svg
-figure fd =
+-- | Create the SVG header from `FigureData`
+svgHeader :: FigureData Int -> Svg -> Svg
+svgHeader fd =
   S.docTypeSvg
   ! SA.version "1.1"
   ! SA.width (vi $ _width fd)
@@ -46,62 +51,63 @@
 
 -- | A filled rectangle, centered at (x0, y0)
 rectCentered
-  :: Double -> Double -> Double -> Double -> C.Colour Double -> Svg
-rectCentered x0 y0 wid hei col = S.g ! SA.transform (S.translate x0c y0c) $ 
+  :: Point Double    -- ^ Center coordinates           
+  -> Double          -- ^ Width
+  -> Double          -- ^ Height
+  -> C.Colour Double -- ^ Colour
+  -> Svg
+rectCentered (Point x0 y0) wid hei col = S.g ! SA.transform (S.translate x0c y0c) $ 
   S.rect ! SA.width (vd wid) ! SA.height (vd hei) ! SA.fill (colourAttr col) where
    x0c = x0 - (wid / 2)
    y0c = y0 - (hei / 2)   
 
--- centeredAt x0 y0 = S.g ! A.transform (translate x0 y0) 
 
--- | Line segment
---
--- e.g. 
--- > putStrLn $ renderSvg (line 0 0 1 1 0.1 C.blueviolet)
+-- | Line segment between two `Point`s
 -- 
--- <line x1="0.0" y1="0.0" x2="1.0" y2="1.0" stroke="#8a2be2" stroke-width="0.1" />
-line :: Double -> Double -> Double -> Double -> Double -> C.Colour Double -> Svg
-line x1 y1 x2 y2 sw col = S.line ! SA.x1 (vd x1) ! SA.y1 (vd y1) ! SA.x2 (vd x2)  ! SA.y2 (vd y2) ! SA.stroke (colourAttr col )! SA.strokeWidth (vd sw)
+-- > > putStrLn $ renderSvg (line 0 0 1 1 0.1 C.blueviolet)
+-- > <line x1="0.0" y1="0.0" x2="1.0" y2="1.0" stroke="#8a2be2" stroke-width="0.1" />
+line :: Point Double -> Point Double -> Double -> C.Colour Double -> Svg
+line (Point x1 y1) (Point x2 y2) sw col = S.line ! SA.x1 (vd x1) ! SA.y1 (vd y1) ! SA.x2 (vd x2)  ! SA.y2 (vd y2) ! SA.stroke (colourAttr col )! SA.strokeWidth (vd sw)
 
 tick :: Axis -> Double -> Double -> C.Colour Double -> Point Double -> Svg
-tick ax len sw col (Point x y) = line x1 y1 x2 y2 sw col where
+tick ax len sw col (Point x y) = line (Point x1 y1) (Point x2 y2) sw col where
   lh = len / 2
   (x1, y1, x2, y2)
     | ax == Y = (x, y-lh, x, y+lh)
     | otherwise = (x-lh, y, x+lh, y)
 
 tickX, tickY ::
-     Double          -- | Length
-  -> Double          -- | Stroke width
-  -> C.Colour Double -- | Stroke colour
-  -> Point Double    -- | Center coordinates
+     Double          -- ^ Length
+  -> Double          -- ^ Stroke width
+  -> C.Colour Double -- ^ Stroke colour
+  -> Point Double    -- ^ Center coordinates
   -> Svg
 tickX = tick X
 tickY = tick Y
 
 -- | An array of axis-aligned identical segments (to be used as axis tickmarks), with centers given by the array of `Point`s
 ticks :: Foldable t =>
-               Axis                -- | Axis 
-               -> Double           -- | Length         
-               -> Double           -- | Stroke width
-               -> C.Colour Double  -- | Stroke colour
-               -> t (Point Double) -- | Center coordinates
+               Axis                -- ^ Axis 
+               -> Double           -- ^ Length         
+               -> Double           -- ^ Stroke width
+               -> C.Colour Double  -- ^ Stroke colour
+               -> t (Point Double) -- ^ Center coordinates
                -> Svg
 ticks ax len sw col ps = forM_ ps (tick ax len sw col)
 
 
 -- | An axis with tickmarks
 --
--- λ> putStrLn $ renderSvg $ axis X 200 2 C.red 0.05 (Point 150 10) [Point 50 1, Point 60 1, Point 70 1]
--- <line x1="50.0" y1="10.0" x2="250.0" y2="10.0" stroke="#ff0000" stroke-width="2.0" /><line x1="50.0" y1="5.0" x2="50.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" /><line x1="60.0" y1="5.0" x2="60.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" /><line x1="70.0" y1="5.0" x2="70.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" />
+-- > > putStrLn $ renderSvg $ axis X 200 2 C.red 0.05 (Point 150 10) [Point 50 1, Point 60 1, Point 70 1]
+-- > <line x1="50.0" y1="10.0" x2="250.0" y2="10.0" stroke="#ff0000" stroke-width="2.0" /><line x1="50.0" y1="5.0" x2="50.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" /><line x1="60.0" y1="5.0" x2="60.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" /><line x1="70.0" y1="5.0" x2="70.0" y2="15.0" stroke="#ff0000" stroke-width="2.0" />
 axis :: (Functor t, Foldable t) =>
-              Axis
-              -> Double
-              -> Double
-              -> C.Colour Double
-              -> Double
-              -> Point Double
-              -> t (Point Double)
+              Axis                  -- ^ Axis (i.e. either `X` or `Y`)
+              -> Double             -- ^ Length
+              -> Double             -- ^ Stroke width
+              -> C.Colour Double    -- ^ Stroke colour
+              -> Double             -- ^ Tick length fraction (w.r.t axis length)
+              -> Point Double       -- ^ Axis center coordinate
+              -> t (Point Double)   -- ^ Tick center coordinates
               -> Svg
 axis ax len sw col tickLenFrac p@(Point x y) ps = do
   tick ax len sw col p
@@ -114,18 +120,20 @@
 
 -- * text
 
--- | `text` renders text onto the SVG canvas. It is also possible to rotate and move the text, however the order of these modifier matters.
+-- | `text` renders text onto the SVG canvas. It is also possible to rotate and move the text, however the order of these modifiers matters.
+-- 
 -- NB1: `x` and `y` determine the position of the bottom-left corner of the text box. If a nonzero rotation is applied, the whole text box will move in a circle of radius || x^2 + y^2 ||
--- NB2: the `rotate` and `translate` apply to the _center_ of the text box instead
 --
--- > putStrLn $ renderSvg $ text (-45) C.red "hullo!" (V2 (-30) 0) (Point 0 20)
--- <text x="-30" y="0" transform="translate(0 20)rotate(-45)" fill="#ff0000">hullo!</text>
+-- NB2: the `rotate` and `translate` attributes apply to the _center_ of the text box instead
+--
+-- > > putStrLn $ renderSvg $ text (-45) C.red "hullo!" (V2 (-30) 0) (Point 0 20)
+-- > <text x="-30" y="0" transform="translate(0 20)rotate(-45)" fill="#ff0000">hullo!</text>
 text :: (Show a, Show a1, S.ToValue a2) =>
-              a1        -- | Rotation angle 
-     -> C.Colour Double -- | Font colour
-     -> T.Text          -- | Text 
-     -> V2 a2           -- | Displacement
-     -> Point a         -- | Initial center position of the text box
+              a1        -- ^ Rotation angle 
+     -> C.Colour Double -- ^ Font colour
+     -> T.Text          -- ^ Text 
+     -> V2 a2           -- ^ Displacement
+     -> Point a         -- ^ Initial center position of the text box
      -> Svg
 text rot col te (V2 x y) (Point dx dy) = 
   S.text_ (S.toMarkup te) ! SA.x (S.toValue x) ! SA.y (S.toValue y) ! SA.transform (S.translate dx dy <> S.rotate rot) ! SA.fill (colourAttr col)
@@ -137,11 +145,14 @@
 -- <polyline points="20,20 40,25 60,40 80,120 120,140 200,180" style="fill:none;stroke:black;stroke-width:3" />
 
 -- | Polyline (piecewise straight line)
--- e.g.
--- > putStrLn $ renderSvg (polyline [(1,1), (2,1), (2,2), (3,4)] 0.1 C.red)
---
--- <polyline points="1,1 2,1 2,2 3,4" fill="none" stroke="#ff0000" stroke-width="0.1" />
-polyline :: (Show a1, Show a) => [(a1, a)] -> Double -> C.Colour Double -> Svg
+-- 
+-- > > putStrLn $ renderSvg (polyline [(1,1), (2,1), (2,2), (3,4)] 0.1 C.red)
+-- > <polyline points="1,1 2,1 2,2 3,4" fill="none" stroke="#ff0000" stroke-width="0.1" />
+polyline :: (Show a1, Show a) =>
+            [(a1, a)]       -- ^ Data
+         -> Double          -- ^ Stroke width
+         -> C.Colour Double -- ^ Stroke colour
+         -> Svg
 polyline lis sw col = S.polyline ! SA.points (S.toValue $ unwords $ map showP2 lis) ! SA.fill none ! SA.stroke (colourAttr col )! SA.strokeWidth (vd sw) ! SA.strokeLinejoin (S.toValue ("round" :: String))
 
 showP2 :: (Show a, Show a1) => (a1, a) -> String
diff --git a/src/Graphics/Rendering/Plot/Light/Internal/Geometry.hs b/src/Graphics/Rendering/Plot/Light/Internal/Geometry.hs
--- a/src/Graphics/Rendering/Plot/Light/Internal/Geometry.hs
+++ b/src/Graphics/Rendering/Plot/Light/Internal/Geometry.hs
@@ -19,14 +19,20 @@
   mempty = V2 0 0
   (V2 a b) `mappend` (V2 c d) = V2 (a + b) (c + d)
 
--- | Additive group : 
--- v ^+^ zero = zero ^+^ v = v
--- v ^-^ v == zero
+-- | Additive group :
+-- 
+-- > v ^+^ zero == zero ^+^ v == v
+--
+-- > v ^-^ v == zero
 class AdditiveGroup v where
+  -- | Identity element
   zero :: v
+  -- | Group action ("sum")
   (^+^) :: v -> v -> v
+  -- | Inverse group action ("subtraction")
   (^-^) :: v -> v -> v
 
+-- | Vectors form an additive group
 instance Num a => AdditiveGroup (V2 a) where
   zero = mempty
   (^+^) = mappend
@@ -35,6 +41,7 @@
 -- | Vector space : multiplication by a scalar quantity
 class AdditiveGroup v => VectorSpace v where
   type Scalar v :: *
+  -- | Scalar multiplication
   (.*) :: Scalar v -> v -> v
   
 instance Num a => VectorSpace (V2 a) where
@@ -44,6 +51,7 @@
 -- | Hermitian space : inner product
 class VectorSpace v => Hermitian v where
   type InnerProduct v :: *
+  -- | Inner product
   (<.>) :: v -> v -> InnerProduct v
 
 instance Num a => Hermitian (V2 a) where
@@ -71,17 +79,22 @@
 origin = Point 0 0
 
 
--- | A Mat2 can be seen as a linear operator V2 -> V2
+-- | A Mat2 can be seen as a linear operator that acts on points in the plane
 data Mat2 a = Mat2 a a a a deriving (Eq, Show)
 
 -- | Linear maps, i.e. linear transformations of vectors
 class Hermitian v => LinearMap m v where
+  -- | Matrix action, i.e. linear transformation of a vector
   (#>) :: m -> v -> v
 
 -- | Multiplicative matrix semigroup ("multiplying" two matrices together)
 class MultiplicativeSemigroup m where
+  -- | Matrix product
   (##) :: m -> m -> m
 
+instance Num a => MultiplicativeSemigroup (Mat2 a) where
+  Mat2 a00 a01 a10 a11 ## Mat2 b00 b01 b10 b11 = Mat2 (a00*b00+a01*b10) (a00*b01+a01*b11) (a10*b00+a11*b10) (a10*b01+a11*b11)
+
 instance Num a => LinearMap (Mat2 a) (V2 a) where
   (Mat2 a00 a01 a10 a11) #> (V2 vx vy) = V2 (a00 * vx + a01 * vy) (a10 * vx + a11 * vy)
 
@@ -95,14 +108,16 @@
 
 -- | The class of invertible linear transformations
 class LinearMap m v => MatrixGroup m v where
+  -- | Inverse matrix action on a vector
   (<\>) :: m -> v -> v
   
 instance Num a => MultiplicativeSemigroup (DiagMat2 a) where
   DMat2 a b ## DMat2 c d = DMat2 (a*c) (b*d)
 
--- | Diagonal matrices can always be inverted
 instance Num a => LinearMap (DiagMat2 a) (V2 a) where
   DMat2 d1 d2 #> V2 vx vy = V2 (d1 * vx) (d2 * vy)
+
+-- | Diagonal matrices can always be inverted
 instance Fractional a => MatrixGroup (DiagMat2 a) (V2 a) where
   DMat2 d1 d2 <\> V2 vx vy = V2 (vx / d1) (vy / d2)
 
@@ -130,7 +145,7 @@
     o1 = _fpmin from
     vmove = mm <\> (p -. o1)
 
--- | The vector translation from a `Point` contained in the unit square onto a `Frame`
+-- | The vector translation from a `Point` `p` contained in the unit square onto a `Frame`
 --
 -- NB: we do not check that `p` is actually contained in [0,1] x [0,1], This has to be supplied correctly by the user
 fromUnitSquare :: Num a => Frame a -> Point a -> Point a
@@ -141,9 +156,11 @@
     vmove = (mm #> v2fromPoint p) ^+^ vo
 
 
--- | Coordinate unit vectors
-e1, e2 :: Num a => V2 a
+-- | X-aligned unit vector
+e1 :: Num a => V2 a
 e1 = V2 1 0
+-- | Y-aligned unit vector
+e2 :: Num a => V2 a
 e2 = V2 0 1
 
 
diff --git a/src/Graphics/Rendering/Plot/Light/Internal/Types.hs b/src/Graphics/Rendering/Plot/Light/Internal/Types.hs
--- a/src/Graphics/Rendering/Plot/Light/Internal/Types.hs
+++ b/src/Graphics/Rendering/Plot/Light/Internal/Types.hs
@@ -27,11 +27,12 @@
 setPointX = setPointCoord X
 setPointY = setPointCoord Y
 
--- | A `LabeledPoint` carries the information of where a point should be plotted, what label should it carry (e.g. for labelling the axes) and its function value 
+-- | A `LabeledPoint` carries a "label" (i.e. any additional information such as a text tag, or any other data structure), in addition to position information. Data points on a plot are `LabeledPoint`s.
 data LabeledPoint l a =
   LabeledPoint {
    _lp :: Point a,
-   _lplabel :: l } deriving (Eq, Show)
+   _lplabel :: l
+   } deriving (Eq, Show)
 
 moveLabeledPoint :: (Point a -> Point b) -> LabeledPoint l a -> LabeledPoint l b
 moveLabeledPoint f (LabeledPoint p l) = LabeledPoint (f p) l
@@ -39,7 +40,8 @@
 -- | A frame, i.e. a bounding box for objects
 data Frame a = Frame {
    _fpmin :: Point a,
-   _fpmax :: Point a} deriving (Eq, Show)
+   _fpmax :: Point a
+   } deriving (Eq, Show)
 
 -- | Frame corner coordinates
 xmin, xmax, ymin, ymax :: Frame a -> a
