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/layout.cabal b/layout.cabal
new file mode 100644
--- /dev/null
+++ b/layout.cabal
@@ -0,0 +1,31 @@
+Name:           layout
+Version:        0.0.0.0
+License:        BSD3
+Author:         Robert Hensing
+Maintainer:     hackage@roberthensing.nl
+Synopsis:       Turn values into pretty text or markup
+Description:    A library for turning values into text or markup. Flexibility
+                is achieved by separating the semantics from the formatting
+                implementation. This way, a function can output, for example,
+		a table, which can then be rendered to any format.
+                
+                This library provides 'standard' objects that can be formatted,
+                in module @Text.Layout.Objects@. It also provides data types for
+                a few formats. These data types are glued together with
+                instances of @Convertible@
+Build-Type:     Simple
+Cabal-Version:  >= 1.2
+Stability:      work in progress
+Category:       Pretty Printer, Text, Typography
+
+Library
+    Build-Depends:      base >= 4 && < 5
+                        , convertible
+                        , hinduce-missingh >= 0.0.0.0
+    Exposed-Modules:    Text.Layout
+                        Text.Layout.Class
+                        Text.Layout.Objects
+                        Text.Layout.DisplayText
+                        Text.Layout.DisplayLatex
+    Hs-Source-Dirs:     src
+    Extensions:	        MultiParamTypeClasses, FlexibleContexts
diff --git a/src/Text/Layout.hs b/src/Text/Layout.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout.hs
@@ -0,0 +1,20 @@
+module Text.Layout ( module Text.Layout.Class
+                   , module Text.Layout.Objects
+                   , module Text.Layout.DisplayText
+                   , module Text.Layout.DisplayLatex
+                   ) where
+import Text.Layout.Class
+import Text.Layout.Objects
+import Text.Layout.DisplayText
+import Text.Layout.DisplayLatex
+
+{---- begin TODO move to modules ----}
+
+import Data.Convertible
+
+newtype DisplayHtml = DisplayHtml String
+
+instance Convertible DDisplayHtml DisplayHtml where
+  safeConvert = Right
+
+{---- end TODO move to modules ----}
diff --git a/src/Text/Layout/Class.hs b/src/Text/Layout/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Class.hs
@@ -0,0 +1,15 @@
+module Text.Layout.Class where
+import Data.List
+import Data.Monoid
+
+class (Monoid format) => IsFormat format where
+  formatVerbatim :: String -> format
+  fromShow :: (Show a) => a -> format
+  fromShow = formatVerbatim . show
+
+class (IsFormat format) => Layout a format where
+  format :: a -> format
+  formatList :: [a] -> format -- required to implement exception for String
+  formatList as = formatVerbatim "[" `mappend`
+                  (mconcat $ intersperse (formatVerbatim ", ") $ map format as) `mappend` 
+                  formatVerbatim "]"
diff --git a/src/Text/Layout/DisplayLatex.hs b/src/Text/Layout/DisplayLatex.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/DisplayLatex.hs
@@ -0,0 +1,15 @@
+module Text.Layout.DisplayLatex where
+import Data.Convertible
+
+newtype DisplayLatex = DisplayLatex { fromDisplayLatex :: String }
+
+-- | Shortcut for convert
+dltx :: (Convertible a DisplayLatex) => a -> DisplayLatex
+dltx = convert
+
+-- This Show instance is for use with ghci -- there is no Read
+instance Show DisplayLatex where
+  show = fromDisplayLatex
+
+instance Convertible DisplayLatex DisplayLatex where
+  safeConvert = Right
diff --git a/src/Text/Layout/DisplayText.hs b/src/Text/Layout/DisplayText.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/DisplayText.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
+module Text.Layout.DisplayText ( DisplayText(..)
+                               , dt
+                               ) where
+import Control.Arrow
+import Data.Convertible
+import Data.List
+import Data.List.HIUtils
+import Data.Maybe
+import Data.Monoid
+import Data.Ord
+import Data.Ratio
+import Data.String.HIUtils
+import Text.Layout.Objects
+import Text.Layout.Class
+
+newtype DisplayText = DisplayText { fromDisplayText :: String }
+
+-- This Show instance is for use with ghci -- there is no Read
+instance Show DisplayText where
+  show = fromDisplayText
+  
+instance Monoid DisplayText where
+  mempty = DisplayText ""
+  a `mappend` b = DisplayText $ 
+                  (fromDisplayText a) `mappend` (fromDisplayText b)
+  mconcat = DisplayText . mconcat . map fromDisplayText
+
+instance IsFormat DisplayText where
+  formatVerbatim = DisplayText
+
+instance Layout DisplayText DisplayText where
+  format = id
+
+instance Layout Char DisplayText where
+  format = fromShow
+  formatList = fromShow
+  
+instance (Layout a DisplayText) => Layout [a] DisplayText where
+  format = formatList
+
+instance (Layout a DisplayText) => Convertible a DisplayText where
+  safeConvert = Right . format
+
+--instance Convertible DisplayText DisplayText where
+--  safeConvert = Right
+
+instance Layout () DisplayText where format = fromShow
+instance Layout Integer DisplayText where format = fromShow
+instance Layout Int DisplayText where format = fromShow
+instance Layout Float DisplayText where format = fromShow
+instance Layout Double DisplayText where format = fromShow
+instance (Show (Ratio a)) => Layout (Ratio a) DisplayText where format = fromShow
+instance (Show a) => Layout (Maybe a) DisplayText where format = fromShow
+instance (Show a, Show b) => Layout (Either a b) DisplayText where format = fromShow
+instance (Show a, Show b) => Layout (a, b) DisplayText where format = fromShow
+instance (Show a, Show b, Show c) => Layout (a, b, c) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d) => Layout (a, b, c, d) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d, Show e) => Layout (a, b, c, d, e) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d, Show e, Show f) => Layout (a, b, c, d, e, f) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g) => Layout (a, b, c, d, e, f, g) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h) => Layout (a, b, c, d, e, f, g, h) DisplayText where format = fromShow
+instance (Show a, Show b, Show c, Show d, Show e, Show f, Show g, Show h, Show i) => Layout (a, b, c, d, e, f, g, h, i) DisplayText where format = fromShow
+
+-- | Shortcut for @(Layout :: a -> DisplayText)@
+dt :: (Layout a DisplayText) => a -> DisplayText
+dt = format
+ 
+instance (Layout a DisplayText,
+          Layout b DisplayText,
+          Layout c DisplayText) =>
+  Layout (Table a b c) DisplayText where
+    format (Table caption (x, y) sparseRepr) = formatVerbatim s
+      where s = asciiTable caption (x, y) sparseRepr
+
+-- for x, x' of types a, b, or c, we assume show x == show x' <==> x == x'
+asciiTable :: --(Show a, Eq a, Show b, Eq b, Show c, Eq c)
+  ( Convertible a DisplayText
+  , Convertible b DisplayText
+  , Convertible c DisplayText ) => 
+  String -> (String, String) -> [((a,b), c)] -> String
+asciiTable title (astr, bstr) table' = "Table: " ++ title ++ "\n"
+                                  ++ thead ++ "\n" ++ tbody
+  where
+        table = map ((renderdt *** renderdt) *** renderdt) table'
+        renderdt :: (Convertible t DisplayText) => t -> String
+        renderdt = fromDisplayText . convert
+        
+        colAL = sortBy (comparing fst) $ aggregateAL $ map (first fst) table
+        rowsAL = sortBy (comparing fst) $ aggregateAL $ map (\((a,b), c) -> (b, (a, c))) table
+        
+        rows = map fst rowsAL
+        cols = map fst colAL
+
+        rowhdr = bstr ++ "\\/" -- "\x2193"
+        rhlen = maximum $ map length (rowhdr : rows)
+        
+        renderrow (rn, rv) = padl rhlen rn ++ " " ++
+                              (concat . intersperse " " . map
+                                (renderval rv)) collengths
+        renderval rv (c,l) = padl l $ fromMaybe "" $ lookup c rv
+        padval (col,v) = maybe "" (flip padl v) $ lookup col collengths
+        collengths = [ (colname, maximum $ map length xs) |
+                       (colname, colvals) <- colAL, let xs = (colname:colvals) ]
+        thead = thead1 ++ "\n" ++ thead2
+        thead1 = padl rhlen "||" ++ " " ++ astr ++ " ==>" {-" \x2192"-}
+        thead2 = padl rhlen rowhdr ++ " " ++ concat (intersperse " " (map (uncurry (flip padl)) collengths))
+        tbody = concat . intersperse "\n" . map renderrow $ rowsAL
diff --git a/src/Text/Layout/Objects.hs b/src/Text/Layout/Objects.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Objects.hs
@@ -0,0 +1,10 @@
+module Text.Layout.Objects where
+import Control.Arrow
+
+data Table a b c = Table { tableCaption :: String
+                         , tableAxes    :: (String, String) 
+                         , tableValues  :: [((a,b), c)]
+                         }
+
+instance Functor (Table a b) where
+  fmap f x = x { tableValues = map (second f) $ tableValues x }
