diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,4 @@
+hcg-minus-cairo -- cairo rendering for hcg-minus
+
+(c) rohan drape, 2009-2011
+    gpl, http://gnu.org/copyleft/
diff --git a/Render/CG/Minus.hs b/Render/CG/Minus.hs
new file mode 100644
--- /dev/null
+++ b/Render/CG/Minus.hs
@@ -0,0 +1,121 @@
+-- | CG (minus) rendering in terms of 'C.Render'.
+module Render.CG.Minus where
+
+import qualified Codec.Binary.UTF8.String as U {- utf8-string -}
+import Data.CG.Minus
+import Data.CG.Minus.Colour
+import Data.Colour
+import qualified Graphics.Rendering.Cairo as C {- cairo -}
+import System.FilePath
+
+-- * Paths
+
+-- | Render nothing.
+nil :: C.Render ()
+nil = return ()
+
+-- | Render 'Ls' as 'C.moveTo' then sequence of 'C.lineTo'.
+line :: Ls R -> C.Render ()
+line l =
+  case l of
+    [] -> nil
+    (p0:pp) -> do let (x0,y0) = pt_xy p0
+                  C.moveTo x0 y0
+                  let f p = let (x,y) = pt_xy p in C.lineTo x y
+                  mapM_ f pp
+
+-- | Variant of 'line' that runs 'C.closePath'.
+polygon :: Ls R -> C.Render ()
+polygon l =
+    case l of
+      [] -> nil
+      _ -> line l >> C.closePath
+
+-- | Render 'Ls' as set of square points with 'R' dimension.
+-- Runs 'C.fill' on each square.
+points :: R -> Ls R -> C.Render ()
+points n l = do
+  let f p = do let (x,y) = pt_xy p
+               C.rectangle x y n n
+               C.fill
+  mapM_ f l
+
+-- | Circle centred at 'Pt' with radius 'R'.
+circle :: Pt R -> R -> C.Render ()
+circle o z =
+    let (x,y) = pt_xy o
+    in C.arc x y z 0 (2 * pi)
+
+-- * Context & drawing
+
+-- | Greyscale call to 'C.setSourceRGBA'.
+grey :: R -> C.Render ()
+grey x = C.setSourceRGBA x x x 1
+
+-- | 'Ca' call to 'C.setSourceRGBA'.
+colour :: Ca -> C.Render ()
+colour c =
+  let (r,g,b,a) = unCa c
+  in C.setSourceRGBA r g b a
+
+-- | Set line width 'R' and 'Ca'.
+pen :: R -> Ca -> C.Render ()
+pen lw c = C.setLineWidth lw >> colour c
+
+-- * Composite
+
+-- | Run 'polygon' on 'Ls' then 'fill' and 'stroke'.
+area :: R -> Ca -> Ca -> Ls R -> C.Render ()
+area lw sc fc a = do
+  polygon a
+  colour fc
+  C.fill
+  pen lw sc
+  C.stroke
+
+-- | Variant of 'area' with fixed grey border of width @0.005@ and
+-- grey @0.15@.
+area' :: Ca -> Ls R -> C.Render ()
+area' = area 0.005 (opaque (mk_grey 0.15))
+
+-- | Run 'polygon' on 'Ls' then 'pen' and 'C.stroke'.
+outline :: R -> Ca -> Ls R -> C.Render ()
+outline lw c l = polygon l >> pen lw c >> C.stroke
+
+-- | Render rectangle given colour 'Ca', upper-left 'Pt' and
+-- /(width,height)/.
+rect :: Ca -> Pt R -> (R,R) -> C.Render ()
+rect c p (w,h) = do
+  let (x,y) = pt_xy p
+  C.rectangle x y w h
+  pen 0.05 c
+  C.stroke
+
+-- * Text
+
+-- | Render text 'String' in colour 'Ca' at 'Pt' in font size /sz/.
+text :: Ca -> Pt R -> R -> String -> C.Render ()
+text c p sz txt = do
+  let (x,y) = pt_xy p
+      (r,g,b,_) = unCa c
+  C.save
+  C.selectFontFace "Times" C.FontSlantNormal C.FontWeightNormal
+  C.setFontSize sz
+  C.setSourceRGBA r g b 1
+  C.moveTo x y
+  C.showText (U.utf8Encode txt)
+  C.restore
+
+-- * Rendering
+
+-- | Enumeration of file types.
+data File_Type = F_PDF | F_SVG
+
+-- | Render to 'File_Type'.  \(w,h)\ give the page size.  The
+-- appropriate extension is appended to 'FilePath'.
+render_to_file :: File_Type -> (R,R) -> FilePath -> C.Render () -> IO ()
+render_to_file ty (w,h) nm f = do
+  let r_fn = case ty of
+               F_PDF -> C.withPDFSurface (nm <.> "pdf")
+               F_SVG -> C.withSVGSurface (nm <.> "svg")
+  r_fn w h (`C.renderWith` f)
diff --git a/Render/CG/Minus/Arrow.hs b/Render/CG/Minus/Arrow.hs
new file mode 100644
--- /dev/null
+++ b/Render/CG/Minus/Arrow.hs
@@ -0,0 +1,44 @@
+-- | Rendering of "Data.CG.Minus.Arrow".
+module Render.CG.Minus.Arrow where
+
+import Data.CG.Minus
+import Data.CG.Minus.Arrow
+import Data.CG.Minus.Colour
+import qualified Graphics.Rendering.Cairo as C
+import Render.CG.Minus
+
+arrow_strk :: Ca -> C.Render ()
+arrow_strk c = do
+  C.setLineCap C.LineCapRound
+  pen 0.01 c
+  C.stroke
+
+-- | Render 'Ln' with solid arrow tip at endpoint.  Arrow tip
+-- co-ordinates are given by 'arrow_coord'.
+arrow_ep :: R -> R -> Ca -> Ln R -> C.Render ()
+arrow_ep n a c l = do
+  let (p0,p1) = ln_pt l
+      (p2,p3) = arrow_coord l n a
+  line [p0,ln_midpoint (ln p2 p3)]
+  arrow_strk c
+  polygon [p2,p1,p3]
+  C.fill
+
+-- | Variant of 'arrow_ep' to render 'Ls' as sequence of arrows.
+arrows_ep :: R -> R -> Ca -> Ls R -> C.Render ()
+arrows_ep n a c xs = mapM_ (arrow_ep n a c) (zipWith ln xs (tail xs))
+
+-- | Variant of 'arrow_ep' with draws tip at mid-point of 'Ln'.
+arrow_mp :: R -> R -> Ca -> Ln R -> C.Render ()
+arrow_mp n a c l = do
+  let (p0,p1) = ln_pt l
+      p1' = ln_midpoint (ln p0 (pt_linear_extension n l))
+      (p2,p3) = arrow_coord (ln p0 p1') n a
+  line [p0,p1]
+  arrow_strk c
+  polygon [p2,p1',p3]
+  C.fill
+
+-- | Variant of 'arrow_mp' to render 'Ls' as sequence of arrows.
+arrows_mp :: R -> R -> Ca -> Ls R -> C.Render ()
+arrows_mp n a c xs = mapM_ (arrow_mp n a c) (zipWith ln xs (tail xs))
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMain
diff --git a/hcg-minus-cairo.cabal b/hcg-minus-cairo.cabal
new file mode 100644
--- /dev/null
+++ b/hcg-minus-cairo.cabal
@@ -0,0 +1,28 @@
+name:              hcg-minus-cairo
+version:           0.12
+synopsis:          haskell cg (minus) (cairo rendering)
+description:       cg (minus) library (cairo rendering)
+license:           BSD3
+category:          Math
+author:            Rohan Drape
+maintainer:        rd@slavepianos.org
+homepage:          http://slavepianos.org/rd/?t=hcg-minus-cairo
+tested-with:       GHC==7.2.2
+build-type:        Simple
+cabal-version:     >= 1.8
+
+data-files:        README
+
+library
+  build-depends:   base==4.*,cairo,colour,hcg-minus==0.12.*,filepath,SG,utf8-string
+  ghc-options:     -Wall -fwarn-tabs
+  exposed-modules: Render.CG.Minus
+                   Render.CG.Minus.Arrow
+
+Source-Repository  head
+  Type:            darcs
+  Location:        http://slavepianos.org/rd/sw/hcg-minus-cairo
+
+-- Local Variables:
+-- truncate-lines:t
+-- End:
