diff --git a/Graphics/PS/Cairo.hs b/Graphics/PS/Cairo.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/PS/Cairo.hs
@@ -0,0 +1,77 @@
+module Graphics.PS.Cairo (renderImage, cg) where
+
+import Data.IORef
+import Graphics.PS as P
+import Graphics.PS.Matrix as P
+import qualified Graphics.Rendering.Cairo as C
+import qualified Graphics.Rendering.Cairo.Matrix as C
+import qualified Graphics.UI.Gtk as G
+
+applyMatrix :: Matrix -> C.Render ()
+applyMatrix (Matrix a b c d e f) = C.transform (C.Matrix a b c d e f)
+
+applyFont :: Font -> C.Render ()
+applyFont (Font nm sz) = do
+  C.selectFontFace nm C.FontSlantNormal C.FontWeightNormal
+  C.setFontSize sz
+
+renderPath :: P.Path -> C.Render ()
+renderPath path =
+    case path of
+      P.MoveTo (Pt x y) -> C.moveTo x y
+      P.LineTo (Pt x y) -> C.lineTo x y
+      P.CurveTo (Pt x1 y1) (Pt x2 y2) (Pt x3 y3) -> C.curveTo x1 y1 x2 y2 x3 y3
+      P.Text f t -> applyFont f >> C.textPath t
+      P.PTransform m p -> C.save >> applyMatrix m >> renderPath p >> C.restore
+      P.Join p1 p2 -> renderPath p1 >> renderPath p2
+
+setGS :: GS -> C.Render ()
+setGS (GS (RGB r b g) w k j _ _) = do 
+  C.setSourceRGBA r g b 0.75
+  C.setLineWidth w
+  C.setLineCap (lineCap k)
+  C.setLineJoin (lineJoin j)
+
+renderImage :: P.Image -> C.Render ()
+renderImage image =
+    case image of
+      P.Empty -> return ()
+      P.Stroke g p -> renderPath p >> setGS g >> C.stroke
+      P.Fill g p -> renderPath p >> setGS g >> C.fillPreserve >> C.stroke
+      P.ITransform m i -> C.save >> applyMatrix m >> renderImage i >> C.restore
+      P.Over i1 i2 -> renderImage i1 >> renderImage i2
+
+lineCap :: LineCap -> C.LineCap
+lineCap RoundCap = C.LineCapRound
+lineCap ButtCap = C.LineCapButt
+lineCap ProjectingSquareCap = C.LineCapSquare
+
+lineJoin :: LineJoin -> C.LineJoin
+lineJoin MiterJoin = C.LineJoinMiter
+lineJoin RoundJoin = C.LineJoinRound
+lineJoin BevelJoin = C.LineJoinBevel
+
+--
+cg :: String -> Paper -> [P.Image] -> IO ()
+cg _ (Paper w h) pp = do
+  G.initGUI
+  window <- G.windowNew
+  canvas <- G.drawingAreaNew
+  n <- newIORef 0
+  G.windowSetResizable window False
+  G.widgetSetSizeRequest window w h
+  G.onKeyPress window (\_ -> modifyIORef n (+ 1) >> 
+                             G.widgetQueueDraw window >> 
+                             return True)
+  G.onDestroy window G.mainQuit
+  G.onExpose canvas (const (updateCanvas n canvas pp))
+  G.set window [G.containerChild G.:= canvas]
+  G.widgetShowAll window
+  G.mainGUI
+
+updateCanvas :: (G.WidgetClass w) => IORef Int -> w -> [P.Image] -> IO Bool
+updateCanvas n canvas pp = do
+  window <- G.widgetGetDrawWindow canvas
+  k <- readIORef n
+  G.renderWithDrawable window (renderImage (cycle pp !! k))
+  return True
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,6 @@
+hps-cairo - cairo backend for hps
+
+trivial cairo rendering, via hps
+
+(c) rohan drape 2006-2009
+    gpl.2, http://gnu.org/copyleft/
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/hps-cairo.cabal b/hps-cairo.cabal
new file mode 100644
--- /dev/null
+++ b/hps-cairo.cabal
@@ -0,0 +1,24 @@
+Name:              hps-cairo
+Version:           0.1
+Synopsis:          Cairo rendering for haskell postscript library
+Description:       Cairot rendering for the haskell postscript library
+License:           GPL
+Category:          Graphics
+Copyright:         Rohan Drape, 2006-2009
+Author:            Rohan Drape
+Maintainer:        rd@slavepianos.org
+Stability:         Experimental
+Homepage:          http://www.slavepianos.org/rd/f/399249/
+Tested-With:       GHC == 6.8.2
+Build-Type:	   Simple
+Cabal-Version:     >= 1.6
+
+Data-files:        README
+
+Library
+  Build-Depends:   base == 3.*,
+                   cairo,
+                   gtk,
+                   hps == 0.1
+  GHC-Options:     -Wall -fwarn-tabs
+  Exposed-modules: Graphics.PS.Cairo
