diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Cliff Harvey
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
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/ansigraph.cabal b/ansigraph.cabal
new file mode 100644
--- /dev/null
+++ b/ansigraph.cabal
@@ -0,0 +1,65 @@
+name:                ansigraph
+version:             0.1.0.0
+synopsis:            Terminal-based graphing via ANSI and Unicode
+
+description:         Ansigraph is an ultralightweight terminal-based graphing utility. It uses
+                     Unicode characters and ANSI escape codes to display and animate colored graphs
+                     of vectors/functions in real and complex variables.
+                     .
+
+                     This functionality is provided by a 'Graphable' type class, whose method
+                     'graphWith' draws a graph at the terminal. Another function 'animateWith' takes
+                     a list of Graphable elements and displays an animation by rendering them in
+                     sequence. Both of these functions take an options record as an argument. The
+                     'graph' and 'animate' functions are defined to use the default options, and the
+                     user can define similar functions based on their own settings.
+                     .
+
+                     There are two main ways to use the package.
+
+                     Importing "System.Console.Ansigraph" provides all the functionality we
+                     typically use. This includes the /FlexibleInstances/ extension, which makes it
+                     marginally more convenient to use graphing functions by allowing instances like
+                     'Graphable [Double]'.
+                     .
+
+                     If you want to use the package without activating /FlexibleInstances/ then you
+                     can import "System.Console.Ansigraph.Core", which provides everything except
+                     these instances. Then you must use one of a few newtype wrappers, namely:
+                     'Graph', 'PosGraph', 'CGraph', 'Mat', 'CMat'. These wrappers are also
+                     available from the standard 'Ansigraph' module.
+                     .
+
+                     The "System.Console.Ansigraph.Examples" module contains examples of all the
+                     graph types with animations of various plane waves, and also shows the
+                     available ANSI colors.
+
+
+homepage:            https://github.com/BlackBrane/ansigraph
+license:             MIT
+license-file:        LICENSE
+author:              Cliff Harvey
+maintainer:          cs.hbar+hs@gmail.com
+copyright:           2015
+category:            Graphics
+build-type:          Simple
+
+cabal-version:       >=1.10
+
+source-repository head
+  type:     git
+  location: git://github.com/BlackBrane/ansigraph.git
+
+library
+  exposed-modules:     System.Console.Ansigraph,
+                       System.Console.Ansigraph.Core,
+                       System.Console.Ansigraph.Examples
+
+  other-modules:       System.Console.Ansigraph.Internal.Core,
+                       System.Console.Ansigraph.Internal.FlexInstances,
+                       System.Console.Ansigraph.Internal.Horizontal,
+                       System.Console.Ansigraph.Internal.Matrix
+
+  build-depends:       base >=4.8 && <4.9, ansi-terminal >=0.6 && <0.7
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/System/Console/Ansigraph.hs b/src/System/Console/Ansigraph.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE FlexibleInstances #-}
+
+-- | This is the primary module to import for use of the ansigraph package, which provides
+--   terminal-based graphing for vectors and matrices of real and complex numbers.
+--
+--   This functionality is implemented via a 'Graphable' type class.
+--
+--   __Ansigraph is intended to be used in on of two ways:__
+--
+--   * __By importing "System.Console.Ansigraph"__.
+--   This provides all the functionality we typically use, including the FlexibleInstances
+--   extension which makes it easier to use graphing functions by allowing instances like
+--   'Graphable [Double]'. It also provides "System.Console.AnsiGraph.Core" which provides all the
+--   core functionality. See the Haddock page for that module for more details.
+--
+--   * __By directly importing "System.Console.Ansigraph.Core"__, which does not activate
+--   FlexibleInstances but includes everything else provided by the other module. This just means
+--   you must use one of a handful of newtype wrappers, namely: 'Graph', 'PosGraph', 'CGraph',
+--   'Mat', 'CMat'. These wrappers are also available from the standard module.
+module System.Console.Ansigraph (
+    module System.Console.Ansigraph.Internal.FlexInstances
+  , module System.Console.Ansigraph.Core
+) where
+
+
+import System.Console.Ansigraph.Core
+import System.Console.Ansigraph.Internal.FlexInstances
diff --git a/src/System/Console/Ansigraph/Core.hs b/src/System/Console/Ansigraph/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Core.hs
@@ -0,0 +1,173 @@
+-- | This module provides the core functionality of the ansigraph package:
+--   terminal-based graphing for vectors and matrices of real and complex numbers.
+--
+--   This is implemented via a 'Graphable' type class.
+--
+--   __Ansigraph is intended to be used in on of two ways:__
+--
+--   * __By importing "System.Console.Ansigraph"__.
+--   This provides all the functionality we typically use, including the FlexibleInstances
+--   extension which makes it easier to use graphing functions by allowing instances like
+--   'Graphable [Double]'.
+--
+--
+--   * __By directly importing "System.Console.Ansigraph.Core"__, which does not activate FlexibleInstances but
+--   includes everything else provided by the other module. This just means you must use one of a
+--   handful of newtype wrappers, namely: 'Graph', 'PosGraph', 'CGraph', 'Mat', 'CMat'.
+--   These wrappers are also available from the standard module.
+module System.Console.Ansigraph.Core (
+
+  -- * Core Functionality
+  -- *** The Graphable class
+    Graphable (graphWith)
+  , graph
+  , animateWith
+  , animate
+
+  -- *** Graphing options
+  , AGSettings (..)
+
+  -- *** Default options
+  , graphDefaults
+  , blue, pink, white
+
+  -- *** ANSI data
+  , AnsiColor (..)
+  , Coloring (..)
+
+-- *** ANSI helpers
+  , realColors
+  , imagColors
+  , colorSets
+  , invert
+  , setFG
+  , setBG
+  , lineClear
+  , clear
+  , applyColor
+  , colorStr
+  , colorStrLn
+
+  -- * Graphable wrapper types
+  , Graph (..)
+  , CGraph (..)
+  , PosGraph (..)
+  , Mat (..)
+  , CMat (..)
+
+  -- * Graphing
+  -- *** Horizontal vector graphing
+  , displayRV
+  , displayCV
+  , displayPV
+  , simpleRender
+  , simpleRenderR
+
+  -- *** Matrix graphing
+  , matShow
+  , displayMat
+  , displayCMat
+
+-- *** Simple (non-ANSI) graphing for strictly-positive data
+  , posgraph
+  , posanim
+
+) where
+
+import System.Console.Ansigraph.Internal.Core
+import System.Console.Ansigraph.Internal.Horizontal
+import System.Console.Ansigraph.Internal.Matrix
+
+import System.Console.ANSI
+import System.IO (hFlush,stdout)
+import Control.Concurrent (threadDelay)
+import Data.List (intersperse,transpose)
+import Data.Complex (Complex,realPart,imagPart,magnitude)
+
+
+-- | Things that ansigraph knows how to render at the terminal are
+--   instances of this class.
+class Graphable a where
+  graphWith :: AGSettings -> a -> IO ()
+
+-- | Invokes the 'Graphable' type class method 'graphWith' with the
+--   default 'AGSettings' record, 'graphDefaults'.
+graph :: Graphable a => a -> IO ()
+graph = graphWith graphDefaults
+
+
+---- IO / ANSI helpers ----
+
+-- | Pauses for the specified number of µs.
+pauseFor :: Int -> IO ()
+pauseFor n = hFlush stdout >> threadDelay n
+
+-- | 'pauseFor' some time interval, then clear screen and set the cursor at (0,0).
+next :: Int -> IO ()
+next n = do pauseFor n
+            clearScreen
+            setCursorPosition 0 0
+
+-- | For some number of frames per second, return the corresponding time delta in microseconds.
+deltaFromFPS :: Int -> Int
+deltaFromFPS fps = 1000000 `div` fps
+
+
+---- Animation ----
+
+-- | Any list of a 'Graphable' type can be made into an animation, by
+--   'graph'ing each element with a time delay and screen-clear after each.
+--   'AGSettings' are used to determine the time delta and any coloring/scaling options.
+animateWith :: Graphable a => AGSettings -> [a] -> IO ()
+animateWith s xs = let delta = deltaFromFPS $ framerate s in
+  sequence_ $ intersperse (next delta) (graphWith s <$> xs)
+
+-- | Perform 'animateWith' using default options. Equivalent to 'graph'ing each member
+--   of the supplied list with a short delay and screen-clear after each.
+animate :: Graphable a => [a] -> IO ()
+animate = animateWith graphDefaults
+
+
+---- Wrappers to avoid needing FlexibleInstances ----
+
+-- | Wrapper type for graph of a real vector/function
+newtype Graph = Graph { unGraph :: [Double] }
+
+-- | Wrapper type for graph of a complex vector/function
+newtype CGraph = CGraph { unCGraph :: [Complex Double] }
+
+-- | Wrapper type for graph of a non-negative real vector/function
+newtype PosGraph = PosGraph { unPosGraph :: [Double] }
+
+-- | Wrapper type for graph of a real two-index vector/two-argument function
+newtype Mat = Mat { unMat :: [[Double]] }
+
+-- | Wrapper type for graph of a complex two-index vector/two-argument function
+newtype CMat = CMat { unCMat :: [[Complex Double]] }
+
+
+instance Graphable Graph where
+  graphWith s = displayRV s . unGraph
+
+instance Graphable CGraph where
+  graphWith s = displayCV s . unCGraph
+
+instance Graphable PosGraph where
+  graphWith s = displayPV s . unPosGraph
+
+instance Graphable Mat where
+  graphWith s = displayMat s . unMat
+
+instance Graphable CMat where
+  graphWith s = displayCMat s . unCMat
+
+
+---- helpers for graphing/animating strictly-positive real functions ----
+
+-- | Display a graph of the supplied (non-negative) real vector.
+posgraph :: [Double] -> IO ()
+posgraph = graph . PosGraph
+
+-- | Display an animation of the supplied list of (non-negative) real vectors.
+posanim :: [[Double]] -> IO ()
+posanim = animate . map PosGraph
diff --git a/src/System/Console/Ansigraph/Examples.hs b/src/System/Console/Ansigraph/Examples.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Examples.hs
@@ -0,0 +1,68 @@
+-- | A module that exports some simple demonstrations of how to use the package.
+module System.Console.Ansigraph.Examples (
+    waveDemo
+  , waveDemoR
+  , waveDemoP
+  , showColors
+  , demo
+  , wave
+) where
+
+import System.Console.Ansigraph
+import System.Console.ANSI
+import Control.Monad (forM_)
+import Data.Complex
+
+
+---- Wave Demo ----
+
+wave :: [Complex Double]
+wave = cis . (*) (pi/20) <$> [0..79]
+
+deltas :: [Double]
+deltas = (*) (-pi/10) <$> [0..50]
+
+waves :: [[Complex Double]]
+waves = zipWith (\z -> map (* z)) (cis <$> deltas) $ replicate 50 wave
+
+pwave :: PosGraph
+pwave = PosGraph $ (+1) . realPart <$> wave
+
+rwaves :: [[Double]]
+rwaves = map (map realPart) waves
+
+pwaves :: [PosGraph]
+pwaves = PosGraph . map (+1) <$> rwaves
+
+-- | Display an animation of the positive real function /p(x,t) = cos(x-t) + 1/ in some units.
+waveDemoP :: IO ()
+waveDemoP = animate pwaves
+
+-- | Display an animation of the real function /r(x,t) = cos(x-t)/ in the standard style, i.e. with both
+--   positive and negative regions.
+waveDemoR :: IO ()
+waveDemoR = animate rwaves
+
+-- | Display an animation of the complex wave /z(x,t) = exp(ix - it)/ in some units.
+waveDemo :: IO ()
+waveDemo = animate waves
+
+
+---- Show ANSI Colors ----
+
+colors = [Black,Red,Green,Yellow,Blue,Magenta,Cyan,White]
+intensities = [Dull,Vivid]
+
+-- | Show all of the available 'AnsiColor's and corresponding 'ColorIntensity', 'Color' pairs.
+showColors = do
+  putStrLn "\n Available colors:"
+  forM_ colors $ \clr -> do
+     forM_ intensities $ \inten -> do
+       setSGR [SetColor Foreground inten clr]
+       putStr $ replicate 20 '█'
+       setSGR [Reset]
+       putStrLn $ "  " ++ show inten ++ " " ++ show clr
+  setSGR [Reset]
+
+-- | Run all of the demos in sequence.
+demo = sequence_ [waveDemoP,waveDemoR,waveDemo,showColors]
diff --git a/src/System/Console/Ansigraph/Internal/Core.hs b/src/System/Console/Ansigraph/Internal/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Internal/Core.hs
@@ -0,0 +1,107 @@
+module System.Console.Ansigraph.Internal.Core (
+    AnsiColor (..)
+  , AGSettings (..)
+  , blue, pink, white
+  , graphDefaults
+  , Coloring (..)
+  , realColors
+  , imagColors
+  , colorSets
+  , invert
+  , setFG
+  , setBG
+  , lineClear
+  , clear
+  , applyColor
+  , colorStr
+  , colorStrLn
+) where
+
+import System.Console.ANSI
+import System.IO (hFlush, stdout)
+
+---- Basics ----
+
+-- | ANSI colors are characterized by a 'Color' and a 'ColorIntensity'. This
+--   data type holds one of each.
+data AnsiColor = AnsiColor ColorIntensity Color deriving Show
+
+-- | Record that holds graphing options.
+data AGSettings =
+  AGSettings
+    {
+      -- | Foreground color for real number component
+      realColor :: AnsiColor
+      -- | Foreground color for imaginary number component.
+    , imagColor :: AnsiColor
+      -- | Background color for real number component.
+    , realBG    :: AnsiColor
+      -- | Background color for imaginary number component.
+    , imagBG    :: AnsiColor
+    -- | Framerate in fps.
+    , framerate :: Int
+    -- | How to rescale the size of a vector before displaying it
+    --   (which is not implemented yet).
+    , scaling   :: (Int -> Int)
+    }
+
+blue   = AnsiColor Vivid Blue
+pink   = AnsiColor Vivid Magenta
+white  = AnsiColor Vivid White
+
+graphDefaults = AGSettings blue pink white white 15 (max 150)
+
+-- | Holds two 'AnsiColor's representing foreground and background colors for display via ANSI.
+data Coloring = Coloring AnsiColor AnsiColor deriving Show
+
+-- | Projection retrieving foreground and background colors
+--   for real number graphs in the form of a 'Coloring'.
+realColors :: AGSettings -> Coloring
+realColors sets = Coloring (realColor sets) (realBG sets)
+
+-- | Projection retrieving foreground and background colors
+--   for imaginary component of complex number graphs in the form of a 'Coloring'.
+imagColors :: AGSettings -> Coloring
+imagColors sets = Coloring (imagColor sets) (imagBG sets)
+
+-- | Retrieves a pair of 'Coloring's for real and imaginary graph components respectively.
+colorSets :: AGSettings -> (Coloring,Coloring)
+colorSets s = (Coloring (realColor s) (realBG s), Coloring (imagColor s) (imagBG s))
+
+-- | Swaps foreground and background colors within a 'Coloring'.
+invert :: Coloring -> Coloring
+invert (Coloring fg bg) = Coloring bg fg
+
+-- | 'SGR' command to set the foreground to the specified 'AnsiColor'.
+setFG :: AnsiColor -> SGR
+setFG (AnsiColor ci c) = SetColor Foreground ci c
+
+-- | 'SGR' command to set the background to the specified 'AnsiColor'.
+setBG :: AnsiColor -> SGR
+setBG (AnsiColor ci c) = SetColor Background ci c
+
+-- | Clear any SGR settings, then print a new line and flush stdout.
+lineClear :: IO ()
+lineClear = setSGR [Reset] >> putStrLn "" >> hFlush stdout
+
+-- | Clear any SGR settings and then flush stdout.
+clear :: IO ()
+clear = setSGR [Reset] >> hFlush stdout
+
+-- | Apply both foreground and background color.
+applyColor :: Coloring -> IO ()
+applyColor (Coloring fg bg) = setSGR [setFG fg, setBG bg]
+
+-- | Use a particular ANSI 'Coloring' to print a string at the terminal (without a newline),
+--   then clear all ANSI SGR codes and flush stdout.
+colorStr :: Coloring -> String -> IO ()
+colorStr c s = do applyColor c
+                  putStr s
+                  clear
+
+-- | Use a particular ANSI 'Coloring' to print a string at the terminal,
+--   then clear all ANSI SGR codes, print a newline and flush stdout.
+colorStrLn :: Coloring -> String -> IO ()
+colorStrLn c s = do applyColor c
+                    putStr s
+                    lineClear
diff --git a/src/System/Console/Ansigraph/Internal/FlexInstances.hs b/src/System/Console/Ansigraph/Internal/FlexInstances.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Internal/FlexInstances.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE FlexibleInstances #-}
+
+module System.Console.Ansigraph.Internal.FlexInstances where
+
+import System.Console.Ansigraph.Core
+import Data.Complex
+
+
+instance Graphable [Double] where
+  graphWith = displayRV
+
+instance Graphable [Complex Double] where
+  graphWith = displayCV
+
+instance Graphable [[Double]] where
+  graphWith = displayMat
+
+instance Graphable [[Complex Double]] where
+  graphWith = displayCMat
diff --git a/src/System/Console/Ansigraph/Internal/Horizontal.hs b/src/System/Console/Ansigraph/Internal/Horizontal.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Internal/Horizontal.hs
@@ -0,0 +1,94 @@
+module System.Console.Ansigraph.Internal.Horizontal (
+    displayRV
+  , displayCV
+  , displayPV
+  , simpleRender
+  , simpleRenderR
+) where
+
+import System.Console.Ansigraph.Internal.Core
+import Data.Complex
+import System.IO (hFlush, stdout)
+
+---- Graphing Infrastructure  ----
+
+barChars = "█▇▆▅▄▃▂▁"
+
+-- These values delineate regions for rounding to the nearest 1/8.
+barVals :: [Double]
+barVals = (+ 0.0625) . (/8) <$> [7,6..0]
+     -- = [15/16, 13/16, 11/16, 9/16, 7/16, 5/16, 3/16, 1/16]
+
+{- forward and reverse versions of unicode bar selection
+   for positive and negative graph regions respectively -}
+
+bars, barsR :: [(Double,Char)]
+bars  = zipWith (,) barVals barChars
+
+barsR = zipWith (,) barVals (reverse barChars)
+
+
+selectBar, selectBarR :: Double -> Char
+selectBar x = let l = filter (\p -> fst p < x) bars in case l of
+  []     -> ' '
+  (p:ss) -> snd p
+
+selectBarR x = let l = filter (\p -> fst p < x) barsR in case l of
+  []     -> '█'
+  (p:ss) -> snd p
+
+-- | Simple vector rendering. Yields a string of unicode chars representing graph bars
+--   varying in units of 1/8. To be primarily invoked via 'graph', 'graphWith',
+--   'animate', 'animateWith'.
+simpleRender :: [Double] -> String
+simpleRender xs = let mx = maximum xs in
+                  (selectBar . (/mx)) <$> xs
+
+-- | Simple vector rendering – inverted version. Rarely used directly.
+--   It is needed to render negative graph regions.
+simpleRenderR :: [Double] -> String
+simpleRenderR xs = let mx = maximum xs in
+                   (selectBarR . (/mx)) <$> xs
+
+
+renderCV :: [Complex Double] -> (String,String,String,String)
+renderCV l = let rp = realPart <$> l
+                 rm = negate   <$> rp
+                 ip = imagPart <$> l
+                 im = negate   <$> ip
+                 mx = maximum $ rp ++ rm ++ ip ++ im
+  in (selectBar  . (/mx) <$> rp,
+      selectBarR . (/mx) <$> rm,
+      selectBar  . (/mx) <$> ip,
+      selectBarR . (/mx) <$> im)
+
+renderRV :: [Double] -> (String,String)
+renderRV l = let rp = l
+                 rm = negate <$> rp
+                 mx = maximum $ rp ++ rm
+  in (selectBar  . (/mx) <$> rp,
+      selectBarR . (/mx) <$> rm)
+
+-- | ANSI based display for complex vectors. To be primarily invoked via 'graph', 'graphWith',
+--   'animate', 'animateWith'.
+displayCV :: AGSettings -> [Complex Double] -> IO ()
+displayCV s l = let (rp,rm,ip,im) = renderCV l
+                    (rcol,icol) = colorSets s
+  in do colorStrLn rcol          rp
+        colorStrLn (invert rcol) rm
+        colorStrLn icol          ip
+        colorStrLn (invert icol) im
+
+-- | ANSI based display for real vectors. To be primarily invoked via 'graph', 'graphWith',
+--   'animate', 'animateWith'.
+displayRV :: AGSettings -> [Double] -> IO ()
+displayRV s l = let (rp,rm) = renderRV l
+                    rcol = realColors s
+  in do colorStrLn rcol          rp
+        colorStrLn (invert rcol) rm
+
+-- | ANSI based display for positive real vectors. To be primarily invoked via 'graph', 'graphWith',
+--   'animate', 'animateWith'.
+displayPV :: AGSettings -> [Double] -> IO ()
+displayPV s l = let (rp,_) = renderRV l
+                    rcol = realColors s in colorStrLn rcol rp
diff --git a/src/System/Console/Ansigraph/Internal/Matrix.hs b/src/System/Console/Ansigraph/Internal/Matrix.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Console/Ansigraph/Internal/Matrix.hs
@@ -0,0 +1,61 @@
+module System.Console.Ansigraph.Internal.Matrix (
+    matShow
+  , displayMat
+  , displayCMat
+) where
+
+import System.Console.Ansigraph.Internal.Core
+import Data.Complex
+
+---- Matrices ----
+
+mmap :: (a -> b) -> [[a]] -> [[b]]
+mmap = map . map
+
+mmax :: (Num a, Ord a) => [[a]] -> a
+mmax = maximum . map maximum . mmap abs
+
+densityChars = "█▓▒░"
+
+densityVals :: [Double]
+densityVals = (+ 0.125) . (/4) <$> [3,2,1,0]
+         -- = [7/8, 5/8, 3/8, 1/8]
+
+blocks, blocksR :: [(Double,Char)]
+blocks  = zipWith (,) densityVals densityChars
+
+blocksR = zipWith (,) densityVals (reverse densityChars)
+
+
+selectBlock :: Double -> Char
+selectBlock x = let l = filter (\p -> fst p < abs x) blocks in case l of
+  []     -> ' '
+  (p:ss) -> snd p
+
+-- | Given a matrix of Doubles, return the list of strings illustrating the absolute value
+--   of each entry relative to the largest, via unicode chars that denote a particular density.
+matShow :: [[Double]] -> [String]
+matShow m = let mx = mmax m
+            in  mmap (selectBlock . (/ mx)) m
+
+-- | Use ANSI coloring (specified by an 'AGSettings') to visually display a Real matrix.
+displayMat :: AGSettings -> [[Double]] -> IO ()
+displayMat s = mapM_ (colorStrLn (realColors s)) . matShow
+
+
+matShow_Imag :: [[Complex Double]] -> [String]
+matShow_Imag m = let mx = max (mmax $ mmap realPart m)
+                              (mmax $ mmap imagPart m)
+                 in  mmap (selectBlock . (/ mx) . imagPart) m
+
+matShow_Real :: [[Complex Double]] -> [String]
+matShow_Real m = let mx = max (mmax $ mmap realPart m)
+                              (mmax $ mmap imagPart m)
+                 in  mmap (selectBlock . (/ mx) . realPart) m
+
+-- | Use ANSI coloring (specified by an 'AGSettings') to visually display a Complex matrix.
+displayCMat :: AGSettings -> [[Complex Double]] -> IO ()
+displayCMat s m = sequence_ $
+  zipWith (\x y -> x >> putStr " " >> y)
+          (colorStr   (realColors s) <$> matShow_Real m)
+          (colorStrLn (imagColors s) <$> matShow_Imag m)
