diff --git a/Graphics/Diagrams/Colors.hs b/Graphics/Diagrams/Colors.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Diagrams/Colors.hs
@@ -0,0 +1,171 @@
+module Graphics.Diagrams.Colors where
+
+import Data.Map
+import Prelude hiding (lookup)
+
+toRGB :: String -> Maybe (Double, Double, Double)
+toRGB s = lookup s colorMap
+
+colors :: [String]
+colors = keys colorMap
+
+-- | SVG color codes
+colorMap :: Map String (Double, Double, Double)
+colorMap = fromList
+    [ "aliceblue"  ==>  (240, 248, 255)
+    , "antiquewhite"  ==>  (250, 235, 215)
+    , "aqua"  ==>  ( 0, 255, 255)
+    , "aquamarine"  ==>  (127, 255, 212)
+    , "azure"  ==>  (240, 255, 255)
+    , "beige"  ==>  (245, 245, 220)
+    , "bisque"  ==>  (255, 228, 196)
+    , "black"  ==>  ( 0, 0, 0)
+    , "blanchedalmond"  ==>  (255, 235, 205)
+    , "blue"  ==>  ( 0, 0, 255)
+    , "blueviolet"  ==>  (138, 43, 226)
+    , "brown"  ==>  (165, 42, 42)
+    , "burlywood"  ==>  (222, 184, 135)
+    , "cadetblue"  ==>  ( 95, 158, 160)
+    , "chartreuse"  ==>  (127, 255, 0)
+    , "chocolate"  ==>  (210, 105, 30)
+    , "coral"  ==>  (255, 127, 80)
+    , "cornflowerblue"  ==>  (100, 149, 237)
+    , "cornsilk"  ==>  (255, 248, 220)
+    , "crimson"  ==>  (220, 20, 60)
+    , "cyan"  ==>  ( 0, 255, 255)
+    , "darkblue"  ==>  ( 0, 0, 139)
+    , "darkcyan"  ==>  ( 0, 139, 139)
+    , "darkgoldenrod"  ==>  (184, 134, 11)
+    , "darkgray"  ==>  (169, 169, 169)
+    , "darkgreen"  ==>  ( 0, 100, 0)
+    , "darkgrey"  ==>  (169, 169, 169)
+    , "darkkhaki"  ==>  (189, 183, 107)
+    , "darkmagenta"  ==>  (139, 0, 139)
+    , "darkolivegreen"  ==>  ( 85, 107, 47)
+    , "darkorange"  ==>  (255, 140, 0)
+    , "darkorchid"  ==>  (153, 50, 204)
+    , "darkred"  ==>  (139, 0, 0)
+    , "darksalmon"  ==>  (233, 150, 122)
+    , "darkseagreen"  ==>  (143, 188, 143)
+    , "darkslateblue"  ==>  ( 72, 61, 139)
+    , "darkslategray"  ==>  ( 47, 79, 79)
+    , "darkslategrey"  ==>  ( 47, 79, 79)
+    , "darkturquoise"  ==>  ( 0, 206, 209)
+    , "darkviolet"  ==>  (148, 0, 211)
+    , "deeppink"  ==>  (255, 20, 147)
+    , "deepskyblue"  ==>  ( 0, 191, 255)
+    , "dimgray"  ==>  (105, 105, 105)
+    , "dimgrey"  ==>  (105, 105, 105)
+    , "dodgerblue"  ==>  ( 30, 144, 255)
+    , "firebrick"  ==>  (178, 34, 34)
+    , "floralwhite"  ==>  (255, 250, 240)
+    , "forestgreen"  ==>  ( 34, 139, 34)
+    , "fuchsia"  ==>  (255, 0, 255)
+    , "gainsboro"  ==>  (220, 220, 220)
+    , "ghostwhite"  ==>  (248, 248, 255)
+    , "gold"  ==>  (255, 215, 0)
+    , "goldenrod"  ==>  (218, 165, 32)
+    , "gray"  ==>  (128, 128, 128)
+    , "grey"  ==>  (128, 128, 128)
+    , "green"  ==>  ( 0, 128, 0)
+    , "greenyellow"  ==>  (173, 255, 47)
+    , "honeydew"  ==>  (240, 255, 240)
+    , "hotpink"  ==>  (255, 105, 180)
+    , "indianred"  ==>  (205, 92, 92)
+    , "indigo"  ==>  ( 75, 0, 130)
+    , "ivory"  ==>  (255, 255, 240)
+    , "khaki"  ==>  (240, 230, 140)
+    , "lavender"  ==>  (230, 230, 250)
+    , "lavenderblush"  ==>  (255, 240, 245)
+    , "lawngreen"  ==>  (124, 252, 0)
+    , "lemonchiffon"  ==>  (255, 250, 205)
+    , "lightblue"  ==>  (173, 216, 230)
+    , "lightcoral"  ==>  (240, 128, 128)
+    , "lightcyan"  ==>  (224, 255, 255)
+    , "lightgoldenrodyellow"  ==>  (250, 250, 210)
+    , "lightgray"  ==>  (211, 211, 211)
+    , "lightgreen"  ==>  (144, 238, 144)
+    , "lightgrey"  ==>  (211, 211, 211)
+    , "lightpink"  ==>  (255, 182, 193)
+    , "lightsalmon"  ==>  (255, 160, 122)
+    , "lightseagreen"  ==>  ( 32, 178, 170)
+    , "lightskyblue"  ==>  (135, 206, 250)
+    , "lightslategray"  ==>  (119, 136, 153)
+    , "lightslategrey"  ==>  (119, 136, 153)
+    , "lightsteelblue"  ==>  (176, 196, 222)
+    , "lightyellow"  ==>  (255, 255, 224)
+    , "lime"  ==>  ( 0, 255, 0)
+    , "limegreen"  ==>  ( 50, 205, 50)
+    , "linen"  ==>  (250, 240, 230)
+    , "magenta"  ==>  (255, 0, 255)
+    , "maroon"  ==>  (128, 0, 0)
+    , "mediumaquamarine"  ==>  (102, 205, 170)
+    , "mediumblue"  ==>  ( 0, 0, 205)
+    , "mediumorchid"  ==>  (186, 85, 211)
+    , "mediumpurple"  ==>  (147, 112, 219)
+    , "mediumseagreen"  ==>  ( 60, 179, 113)
+    , "mediumslateblue"  ==>  (123, 104, 238)
+    , "mediumspringgreen"  ==>  ( 0, 250, 154)
+    , "mediumturquoise"  ==>  ( 72, 209, 204)
+    , "mediumvioletred"  ==>  (199, 21, 133)
+    , "midnightblue"  ==>  ( 25, 25, 112)
+    , "mintcream"  ==>  (245, 255, 250)
+    , "mistyrose"  ==>  (255, 228, 225)
+    , "moccasin"  ==>  (255, 228, 181)
+    , "navajowhite"  ==>  (255, 222, 173)
+    , "navy"  ==>  ( 0, 0, 128)
+    , "oldlace"  ==>  (253, 245, 230)
+    , "olive"  ==>  (128, 128, 0)
+    , "olivedrab"  ==>  (107, 142, 35)
+    , "orange"  ==>  (255, 165, 0)
+    , "orangered"  ==>  (255, 69, 0)
+    , "orchid"  ==>  (218, 112, 214)
+    , "palegoldenrod"  ==>  (238, 232, 170)
+    , "palegreen"  ==>  (152, 251, 152)
+    , "paleturquoise"  ==>  (175, 238, 238)
+    , "palevioletred"  ==>  (219, 112, 147)
+    , "papayawhip"  ==>  (255, 239, 213)
+    , "peachpuff"  ==>  (255, 218, 185)
+    , "peru"  ==>  (205, 133, 63)
+    , "pink"  ==>  (255, 192, 203)
+    , "plum"  ==>  (221, 160, 221)
+    , "powderblue"  ==>  (176, 224, 230)
+    , "purple"  ==>  (128, 0, 128)
+    , "red"  ==>  (255, 0, 0)
+    , "rosybrown"  ==>  (188, 143, 143)
+    , "royalblue"  ==>  ( 65, 105, 225)
+    , "saddlebrown"  ==>  (139, 69, 19)
+    , "salmon"  ==>  (250, 128, 114)
+    , "sandybrown"  ==>  (244, 164, 96)
+    , "seagreen"  ==>  ( 46, 139, 87)
+    , "seashell"  ==>  (255, 245, 238)
+    , "sienna"  ==>  (160, 82, 45)
+    , "silver"  ==>  (192, 192, 192)
+    , "skyblue"  ==>  (135, 206, 235)
+    , "slateblue"  ==>  (106, 90, 205)
+    , "slategray"  ==>  (112, 128, 144)
+    , "slategrey"  ==>  (112, 128, 144)
+    , "snow"  ==>  (255, 250, 250)
+    , "springgreen"  ==>  ( 0, 255, 127)
+    , "steelblue"  ==>  ( 70, 130, 180)
+    , "tan"  ==>  (210, 180, 140)
+    , "teal"  ==>  ( 0, 128, 128)
+    , "thistle"  ==>  (216, 191, 216)
+    , "tomato"  ==>  (255, 99, 71)
+    , "turquoise"  ==>  ( 64, 224, 208)
+    , "violet"  ==>  (238, 130, 238)
+    , "wheat"  ==>  (245, 222, 179)
+    , "white"  ==>  (255, 255, 255)
+    , "whitesmoke"  ==>  (245, 245, 245)
+    , "yellow"  ==>  (255, 255, 0)
+    , "yellowgreen"  ==>  (154, 205, 50)
+    ]
+ where
+    s ==> (r,g,b) = (s, (f r, f g, f b))
+
+    f :: Int -> Double
+    f 0 = 0
+    f 255 = 1
+    f n = fromIntegral n / 255
+
+
diff --git a/Graphics/Diagrams/Escape.hs b/Graphics/Diagrams/Escape.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Diagrams/Escape.hs
@@ -0,0 +1,135 @@
+-- | Strict evaluation of diagrams with time and size limit
+{-# LANGUAGE ScopedTypeVariables #-}
+module Graphics.Diagrams.Escape 
+    ( escapeDiagram
+    , numberErrors
+    ) where
+
+import Graphics.Diagrams
+import Graphics.Diagrams.Types
+import Graphics.Diagrams.Colors (toRGB)
+
+import Data.Data.GenRep.Functions (getErrorIndex)
+import Control.Exception.Pure (catchPureErrorsSafe)
+import System.SimpleTimeout.Limits
+import System.IO.Parallel (twoParallel)
+
+import Control.Monad (liftM2)
+import Control.DeepSeq (NFData, deepseq)
+import Control.Concurrent.MVar (MVar, newMVar, modifyMVar)
+import Control.Monad.State (State, runState)
+
+-------------------------
+
+-- | Strict evaluation of diagrams with time and size limit
+escapeDiagram :: TimeLimit -> SizeLimit -> Diagram -> IO Diagram
+escapeDiagram t s x = do
+    ch <- newBudget t s
+    idv <- newMVar 1        -- to generate identifiers for groups
+    escapeDiagram' ch idv x
+
+escapeDiagram' :: Budget -> MVar Int -> Diagram -> IO Diagram
+escapeDiagram' ch idv = fff where
+
+    fff :: Diagram -> IO Diagram
+    fff x = do
+        m <- checkBudget ch 1 
+                (return . return . err . timeError) 
+                (return . return $ err "size limit exceeded")
+                $ fmap (either err id) (catchPureErrorsSafe x) >>= check
+        m
+      where
+        timeError d
+            = "timeout at " ++ show (round $ 100 * d :: Int) ++ "%" 
+
+    err s = Error s EmptyDiagram
+
+    m1 :: NFData a => (a -> Diagram) -> a -> IO (IO Diagram)
+    m1 f a = fmap (return . either err f) $ catchPureErrorsSafe $ a `deepseq` a
+
+    m2 :: NFData a => (a -> Diagram -> Diagram) -> a -> Diagram -> IO (IO Diagram)
+    m2 f a b 
+        = fmap (either (\s -> fmap (Error s) $ fff b) 
+                       (\a -> fmap (f a) $ fff b)) 
+            $ catchPureErrorsSafe $ a `deepseq` a
+
+    checkColor :: Color -> Color
+    checkColor (Color s) = case toRGB s of
+        Just _  -> Color s
+        _   -> error $ "Not an SVG color: " ++ s
+    checkColor (RGB r g b) = RGB (f r) (f g) (f b)  where
+        f x = 0 `max` (1 `min` x)
+
+    check :: Diagram -> IO (IO Diagram)
+
+    check EmptyDiagram      = return $ return EmptyDiagram
+    check (Circle r)        = m1 Circle (if r >= 0 then r else error "negative radius") 
+    check (Text p s)        = m1 (uncurry Text) (p, s)
+    check (Rect a b)        = m1 (uncurry Rect) (a, b)
+    check (Polyline loop l) = fmap g $ m1 (uncurry Polyline) (loop, l) where
+        g m = m >>= \x -> case x of
+            Polyline loop l -> do
+                (b, l) <- decSizeBudget ch $ \x -> case splitAt (x+2) l of
+                        (a,[]) -> (min x (x+2-length a), (True, a))
+                        (a,_)  -> (0, (False, a))
+                return $ if b 
+                    then Polyline loop l
+                    else Error "size limit exceeded" $ Polyline False l
+            _ -> return x
+
+    check (Link s x)        = m2 Link s x
+    check (FontFamily s x)  = m2 FontFamily s x
+    check (Move p x)        = m2 Move p x
+    check (Scale t x)       = m2 Scale t x
+    check (ScaleXY x y d)   = m2 (uncurry ScaleXY) (x,y) d
+    check (Rotate t x)      = m2 Rotate t x
+    check (Fill t x)        = m2 Fill (checkColor t) x
+    check (Stroke t x)      = m2 Stroke (checkColor t) x
+    check (StrokeWidth t x) = m2 StrokeWidth (if t >= 0 then t else error "negative stroke width") x
+    check (Clip a b x)      = m2 (uncurry Clip) (a, b) x
+    check (Error s x)       = m2 Error s x
+    check (TransformMatrix a b c d e f x)
+        = m2 (\(a,b,c,d,e,f) -> TransformMatrix a b c d e f) (a,b,c,d,e,f) x
+
+    check (Pack x f) = return $ do
+        i <- modifyMVar idv (\i -> return (i+1,i))
+        fmap (\(x,y)-> Group x i y) $ twoParallel (fff x) (fff (f (Ref i)))
+
+    check (Overlay a b) = return $ fmap (uncurry Overlay) $ twoParallel (fff a) (fff b)
+
+    check (Ref i)       = return $ return $ Ref i
+    check (Group _ _ _) = error "check: Group not possible"
+
+-- | Error message extraction and numbering
+numberErrors 
+    :: Diagram
+    -> (Diagram, [(String, String)])
+numberErrors d = (res, reverse $ map swap errs)
+ where
+    swap (a,b) = (b,a)
+
+    (res, (_, errs)) = runState (replace d) (0, [])
+
+    m2 f x = fmap f $ replace x
+
+    replace :: Diagram -> State (Int, [(String, String)]) Diagram
+    replace (Link s x)        = m2 (Link s) x
+    replace (FontFamily s x)  = m2 (FontFamily s) x
+    replace (Move p x)        = m2 (Move p) x
+    replace (Scale t x)       = m2 (Scale t) x
+    replace (Rotate t x)      = m2 (Rotate t) x
+    replace (Fill t x)        = m2 (Fill t) x
+    replace (Stroke t x)      = m2 (Stroke t) x
+    replace (StrokeWidth t x) = m2 (StrokeWidth t) x
+    replace (Clip a b x)      = m2 (Clip a b) x
+    replace (TransformMatrix a b c d e f x)
+        = m2 (TransformMatrix a b c d e f) x
+    replace (Group a i b)   = liftM2 (\a b -> Group a i b) (replace a) (replace b)
+    replace (Overlay a b) = liftM2 Overlay (replace a) (replace b)
+    replace (Error e x) = do
+        i <- getErrorIndex e
+        x <- replace x
+        return $ Overlay x (i `textAt` (0,0) `fill` red)
+    replace x = return x
+
+
diff --git a/Graphics/Diagrams/FunctionGraphs.hs b/Graphics/Diagrams/FunctionGraphs.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Diagrams/FunctionGraphs.hs
@@ -0,0 +1,81 @@
+-- | Display function graphs
+{-# LANGUAGE ScopedTypeVariables #-}
+module Graphics.Diagrams.FunctionGraphs where
+
+import Graphics.Diagrams
+
+import Data.List (zip5)
+
+-------------------------
+
+-- | Make a function discrete
+dotty :: (Num a, Real b) => (a -> b) -> (Double -> Double)
+dotty f x
+    | abs (fromInteger rx - x) < 0.02 = realToFrac $ f $ fromInteger rx
+    | otherwise = sqrt (-1)
+  where
+    rx = round x
+
+-- | Draw coordinate system
+coords :: Point -> Point -> Diagram
+coords (a1,a2) (b1,b2) = union 
+    [ (a1,0) ~~ (b1,0)
+    , (b1-1,0.5) ~~ (b1,0)
+    , (b1-1,-0.5) ~~ (b1,0)
+    , (0.5,b2-1) ~~ (0,b2)
+    , (-0.5,b2-1) ~~ (0,b2)
+    , (0,a2) ~~ (0,b2)
+    , (1,-0.5) ~~ (1,0.5)
+    ]
+
+-- | Display a function
+showFun :: (Fractional a, Real b) => Bool -> Point -> Point -> (a -> b) -> Diagram
+showFun dotty a@(a1,a2) b@(b1,b2) f 
+    = clip a b $ rectangle a b `fill` black <|> coords a b `stroke` yellow 
+        <|> union rr `stroke` white `fill` white
+ where
+    l = map (\x->(x, realToFrac $ f $ realToFrac x)) [a1 - 0.1, a1 .. b1 + 0.1]
+    ds = zipWith (-) (map snd l) (map snd $ drop 1 l)
+
+    rr = if dotty then 
+            [circle 0.1 `move` (x, y) | x <- map fromIntegral [round a1 .. round b1 :: Integer]
+                , let y = realToFrac $ f $ realToFrac x, y <= b2 && y >= a2]
+        else lines ++ dots
+
+    lines = [e >-< f | (e,True,f) <- zip3 (drop 1 l) extralines (drop 2 l)]
+    dots = [circle 0.1 `move` b | (x,b,y)
+            <- zip3 extralines (drop 2 l) (drop 1 extralines)
+            , not (x && y), snd b <= b2 && snd b >= a2]
+    extralines = [abs y< (50* abs x) `max` 0.1 && abs y< (50* abs z) `max` 0.1 &&
+                 (x * y >= 0 || y * z >= 0)
+                 | (x,e,y,f,z)<-zip5 ds (drop 1 l) (drop 1 ds) (drop 2 l) (drop 2 ds)]
+
+
+-- showFun a b f = showArc (fst a, fst b) a b (\t -> (t, f t))
+
+-- | Display an arc
+showArc :: (Fractional a, Real b, Real c) => 
+    (Double,Double) -> Point -> Point -> (a -> (b, c)) -> Diagram
+showArc (k1,k2) a@(a1,a2) b@(b1,b2) f
+    = clip a b $ rectangle a b `fill` black <|> coords a b `stroke` yellow 
+        <|> union (lines ++ dots) `stroke` white `fill` white
+ where
+    l = map (\(x,y)-> (realToFrac x, realToFrac y)) 
+                $ map (f . realToFrac) [k1-0.1, k1.. k2+0.1]
+    ds = zipWith minu l (drop 1 l)
+
+    (a,b) `minu` (c,d) = (c-a, d-b)
+    abs (a,b) = sqrt (a*a+b*b)
+    (a,b) <<< (c,d) = a <= c && b <= d
+    (a,b) .* (c,d) = a*c + b*d
+
+    lines = [e >-< f | (e,True,f) <- zip3 (drop 1 l) extralines (drop 2 l)]
+    dots = [circle 0.1 `move` z | (x,z,y)
+            <- zip3 extralines (drop 2 l) (drop 1 extralines)
+            , not (x && y), a <<< z && z <<< b]
+    extralines = [abs y< (10* abs x) `max` 0.1 && abs y< (10* abs z) `max` 0.1 &&
+                 (x .* y >= 0 || y .* z >= 0)
+                 | (x,e,y,f,z)<-zip5 ds (drop 1 l) (drop 1 ds) (drop 2 l) (drop 2 ds)]
+
+
+
diff --git a/Graphics/Diagrams/SVG.hs b/Graphics/Diagrams/SVG.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Diagrams/SVG.hs
@@ -0,0 +1,166 @@
+-- | Diagrams SVG backend
+{-# LANGUAGE ScopedTypeVariables #-}
+module Graphics.Diagrams.SVG 
+    ( render
+    ) where
+
+import Graphics.Diagrams
+import Graphics.Diagrams.Types
+import Graphics.Diagrams.Escape (escapeDiagram, numberErrors)
+
+import System.SimpleTimeout.Limits
+
+import Text.XHtml.Strict (Html, tag, strAttr, (+++), (<<), (!), intAttr, toHtml, noHtml)
+
+import Data.Char (intToDigit, showLitChar, ord)
+import Data.List (intercalate, groupBy, sortBy)
+import Data.Function (on)
+
+-------------------------
+
+data SVG 
+    = G String [(String, String)] [SVG] (Maybe SVG)
+    | GText String
+
+mkSVG :: String -> [String] -> [String] -> SVG
+mkSVG n t l = G n (zip t l) [] Nothing
+
+addAtt :: (String, String) -> SVG -> SVG
+addAtt a@(x,_) (G n as l Nothing) 
+    | [j | (i,j)<-as, i == x] /= [""] 
+    = G n (a:as) l Nothing
+addAtt a g = G "g" [a] [g] Nothing
+
+mkFun :: String -> [String] -> String
+mkFun f l = f ++ "(" ++ intercalate "," l ++ ")"
+
+mkStyle :: String -> String -> SVG -> SVG
+mkStyle f c = addAtt ("style", f ++ ": " ++ c)
+
+mkTransform :: SVG -> String -> SVG
+g `mkTransform` s = addAtt ("transform", s) g
+
+
+showF :: Double -> String
+showF x = show (realToFrac x :: Float)
+
+showColor :: Color -> String
+showColor (Color s) = s
+showColor (RGB r g b) = "#" ++ f r ++ f g ++ f b where
+    f x = [intToDigit (i `div` 16 `mod` 16), intToDigit (i `mod` 16)] where
+        i = round (x * 255)
+
+---------------
+
+-- | An idetifier is needed
+-- because browsers maintain global xlink-s
+toSVGWithId :: String -> Diagram -> SVG
+toSVGWithId idi = toSVG where
+
+    toSVG :: Diagram -> SVG
+    toSVG EmptyDiagram  = G "g" [] [] Nothing
+    toSVG (Circle r)    = mkSVG "circle" ["r"] [showF r]
+    toSVG (Text pos s)  = G "text" [("style","text-anchor: " ++ showPos pos)] [GText $ concatMap escape s] Nothing
+      where
+        escape '\\' = "\\"
+        escape c | ord c >= 161 = [c]
+        escape c = showLitChar c ""
+
+        showPos Start = "start"
+        showPos Middle = "middle"
+        showPos End = "end"
+
+    toSVG (Link s x)    = G "a" [("xlink:href", s)] [toSVG x] Nothing
+    toSVG (Rect a b)    = mkSVG "rect" ["x","y","width","height"] $ map showF [-a/2, -b/2, a, b]
+    toSVG (Polyline _ [(x1, y1), (x2, y2)]) 
+                        = mkSVG "line" ["x1","y1","x2","y2"] $ map showF [x1, y1, x2, y2]
+    toSVG (Polyline loop l) 
+            = mkSVG (if loop then "polygon" else "polyline") ["points"] 
+                [unwords [showF x ++ "," ++ showF y | (x,y)<-l]]
+
+    toSVG a@(Overlay _ _) = G "g" [] (concatMap (unG . toSVG) $ collectU [] a) Nothing where
+
+        unG (G "g" [] l Nothing) = l
+        unG x = [x]
+
+        collectU acc EmptyDiagram = acc
+        collectU acc (Overlay a b) = collectU (collectU acc b) a
+        collectU acc x = x: acc
+
+    toSVG (Group d i s) = addDef [addAtt ("id", idi ++ show i) $ toSVG d] $ toSVG s  where
+        addDef [] x = x
+        addDef l (G "defs" [] l' (Just x)) = addDef (l++l') x
+        addDef l x = G "defs" [] l $ Just x
+
+    toSVG (Ref i) = mkSVG "use" ["xlink:href"] ["#" ++ idi ++ show i]
+    toSVG (Move (a,b) x)    = toSVG x `mkTransform` mkFun "translate" [showF a, showF b]
+    toSVG (Scale t x)       = toSVG x `mkTransform` mkFun "scale" [showF t, showF t]
+    toSVG (ScaleXY tx ty x) = toSVG x `mkTransform` mkFun "scale" [showF tx, showF ty]
+    toSVG (Rotate d x)      = toSVG x `mkTransform` mkFun "rotate" [showF d]
+    toSVG (FontFamily s x)  = mkStyle "font-family" s           $ toSVG x
+    toSVG (Fill c x)        = mkStyle "fill"   (showColor c)    $ toSVG x
+    toSVG (Stroke c x)      = mkStyle "stroke" (showColor c)    $ toSVG x
+    toSVG (StrokeWidth w x) = mkStyle "stroke-width" (showF w)  $ toSVG x
+    toSVG (TransformMatrix a b c d e f x) 
+        = toSVG x `mkTransform` ("matrix(" ++ intercalate " " (map showF [a,b,c,d,e,f]) ++ ")")
+    toSVG (Clip (a1,a2) (b1,b2) x)  = toSVG x -- inner clip is not implemented yet
+    toSVG (Error s x)               = toSVG x  -- not possible
+    toSVG (Pack x f)    = error "toSVG: use escape first"
+
+
+
+---------------------------------------------------
+
+showSVG :: SVG -> Html
+showSVG x = case x of
+    GText s    -> toHtml s
+    G n as l e -> (tag n !
+            [ strAttr a $ intercalate (sep a) is
+            | (a:_,is)<- map unzip $ groupBy ((==) `on` fst) $ sortBy (compare `on` fst) as]
+                    << map showSVG l)
+        +++ case e of
+                Nothing -> noHtml
+                Just x -> showSVG x
+  where
+    sep "transform" = " "
+    sep _ = "; "
+
+addSVGHeader :: Int -> Int -> Html -> Html
+addSVGHeader w h =
+    tag "svg" ! [ strAttr "xmlns" "http://www.w3.org/2000/svg"
+                , strAttr "xmlns:xlink" "http://www.w3.org/1999/xlink" 
+                , strAttr "version" "1.1"
+                , strAttr "baseProfile" "full" 
+                , intAttr "width" w
+                , intAttr "height" h
+                ] 
+
+
+render 
+    :: Double       -- ^ magnification
+    -> Point        -- ^ bottom-left corner
+    -> Point        -- ^ top-right corner
+    -> TimeLimit    -- ^ time limit
+    -> SizeLimit    -- ^ size limit
+    -> String       -- ^ identifier (needed only if there are several SVG picture on a page)
+    -> Diagram      -- ^ diagram to show
+    -> IO (Html, [(String,String)]) -- ^ xml code and error messages
+render mag bottomLeft topRight t s idi x = do
+    xx <- escapeDiagram t s x
+    let (x', err) = numberErrors xx
+    return (f x', err)
+ where
+    f (Clip a b x) = g a b x
+    f x = g bottomLeft topRight x
+
+    g (a1,a2) (b1,b2) s =
+        addSVGHeader (round $ mag * (b1 - a1)) (round $ mag * (b2 - a2)) 
+            << showSVG (
+            toSVGWithId idi
+                $ TransformMatrix mag 0 0 (-mag) (-mag*a1) (mag*b2) s `fill` white `stroke` black `strokeWidth` 0.1)
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright Péter Diviánszky 2010-2011
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Péter Diviánszky nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/dia-functions.cabal b/dia-functions.cabal
new file mode 100644
--- /dev/null
+++ b/dia-functions.cabal
@@ -0,0 +1,36 @@
+name:                dia-functions
+version:             0.1
+category:            Graphics, Education
+synopsis:            An EDSL for teaching Haskell with diagrams - functions
+description:
+    This package contains diagram manipulating functions
+    and an SVG backend.
+    .
+    For exaples see <http://pnyf.inf.elte.hu/fp/Diagrams_en.xml>
+stability:           alpha
+license:             BSD3
+license-file:        LICENSE
+author:              Péter Diviánszky
+maintainer:          divip@aszt.inf.elte.hu
+cabal-version:       >=1.2
+build-type:          Simple
+
+library
+  GHC-Options: -Wall -fwarn-tabs -fno-warn-unused-matches -fno-warn-name-shadowing 
+
+  Exposed-Modules:
+    Graphics.Diagrams.Colors,
+    Graphics.Diagrams.Escape,
+    Graphics.Diagrams.FunctionGraphs,
+    Graphics.Diagrams.SVG
+
+  Build-Depends:
+    data-pprint >= 0.2 && < 0.3,
+    dia-base >= 0.1 && < 0.2,
+    base >= 4.0 && < 4.4,
+    containers >= 0.4 && < 0.5,
+    xhtml >= 3000.2 && < 3000.3,
+    mtl >= 2.0 && < 2.1,
+    deepseq >= 1.1 && < 1.2
+
+
