diff --git a/app/App.hs b/app/App.hs
--- a/app/App.hs
+++ b/app/App.hs
@@ -1,7 +1,26 @@
 {-# LANGUAGE DataKinds, TypeOperators #-}
 
+import Pipes
+import qualified Pipes.Prelude as P
+import Control.Concurrent (threadDelay)
+
 import Graphics.Liveplot
-import Graphics.Liveplot.Demo
 
 main :: IO ()
-main = runDemo
+main = runLiveplot std
+
+std :: Managed (View (Either (SensorReading GLfloat) GLApp),
+                Controller (Either (SensorReading GLfloat) Event))
+std = do
+  let inits = [ lineGraphN 2000 "adc" (1, 1) (0, 0) ]
+
+  (v, c) <- ogl inits
+
+  dat <- producer (bounded 1) (stdinData >-> normalize (20, 230) >-> named "adc")
+  return (v, fmap Left (dat) <> fmap Right c)
+
+stdinData :: Producer GLfloat IO ()
+stdinData = for P.stdinLn cvt
+  where cvt :: Monad m => String -> Producer Float m ()
+        cvt x = do
+          yield (read x)
diff --git a/app/Demo.hs b/app/Demo.hs
new file mode 100644
--- /dev/null
+++ b/app/Demo.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE DataKinds, TypeOperators #-}
+
+import Graphics.Liveplot
+import Graphics.Liveplot.Demo
+
+main :: IO ()
+main = runLiveplot demo
diff --git a/liveplot.cabal b/liveplot.cabal
--- a/liveplot.cabal
+++ b/liveplot.cabal
@@ -1,5 +1,5 @@
 name:                liveplot
-version:             0.0.1
+version:             0.1.0.0
 synopsis:            Liveplotting
 
 description:         Live plotting with OpenGL. This Haskell library allows feeding live data via Pipes to OpenGL plots.
@@ -50,6 +50,15 @@
 
 executable liveplot
   main-is:             App.hs
+  hs-source-dirs:      app
+  build-depends:       base >= 4.6 && < 5,
+                       mvc,
+                       pipes,
+                       liveplot
+  default-language:    Haskell2010
+
+executable liveplot-demo
+  main-is:             Demo.hs
   hs-source-dirs:      app
   build-depends:       base >= 4.6 && < 5,
                        liveplot
diff --git a/src/Graphics/Liveplot.hs b/src/Graphics/Liveplot.hs
--- a/src/Graphics/Liveplot.hs
+++ b/src/Graphics/Liveplot.hs
@@ -1,16 +1,19 @@
 module Graphics.Liveplot (
     runLiveplot
   , named
-  , initGraph
-  , lineGraph
   , SensorReading(..)
   , GLApp
   , Event
   , GLfloat
-  , rpad
-  , ogl) where
+  , ogl
+  , module Graphics.Liveplot.Utils
+  , module Graphics.Liveplot.Window
+  , module MVC
+  , module MVC.Prelude
+  ) where
 
 import MVC
+import MVC.Prelude
 import Graphics.Liveplot.Window
 import Graphics.Liveplot.Types
 import Graphics.Liveplot.Utils
diff --git a/src/Graphics/Liveplot/Utils.hs b/src/Graphics/Liveplot/Utils.hs
--- a/src/Graphics/Liveplot/Utils.hs
+++ b/src/Graphics/Liveplot/Utils.hs
@@ -5,6 +5,7 @@
   , cnf
   , cnfEndo
   , rpad
+  , normalize
   ) where
 
 import Prelude
@@ -13,8 +14,9 @@
 import Data.Foldable (Foldable, foldMap,foldl',fold)
 import Data.Set (Set)
 import qualified Data.Set as S
+import qualified Pipes.Prelude as P
 
-import Linear
+import Linear hiding (normalize)
 import MVC
 import Graphics.GLUtil.Camera2D
 import Graphics.GLUtil.Camera3D hiding (roll)
@@ -69,3 +71,16 @@
 
 rpad :: Int -> a -> [a] -> [a]
 rpad n x xs = xs ++ (take (n-(length xs)) $ repeat x)
+
+scaleRange :: Fractional a => (a, a) -> (a, a) -> a -> a
+scaleRange (fromLow, fromHigh) (toLow, toHigh) x = (x - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow
+
+normRange :: Fractional a => (a, a) -> a -> a
+normRange from = scaleRange from (-1, 1)
+
+graphRange :: Fractional a => (a, a) -> a -> a
+graphRange from = scaleRange from (0, 1)
+
+-- normalize input from range to graph range (0..1)
+normalize :: (Fractional b, Monad m) => (b, b) -> Pipe b b m r
+normalize from = P.map (graphRange from)
diff --git a/src/Graphics/Liveplot/Window.hs b/src/Graphics/Liveplot/Window.hs
--- a/src/Graphics/Liveplot/Window.hs
+++ b/src/Graphics/Liveplot/Window.hs
@@ -44,6 +44,16 @@
   , graph_scale = scale'
   }, 0)
 
+-- line graph with number of points argument
+lineGraphN :: Int -> String -> (Float, Float) -> (Int, Int) -> (GraphInfo, GLfloat)
+lineGraphN points name scale' offset = (defGI
+  { graph_name = name
+  , graph_points = points
+  , graph_samples = points
+  , graph_resolution = points
+  , graph_offset = offset
+  , graph_scale = scale'
+  }, 0)
 -- add scroll input callback
 -- http://www.glfw.org/docs/latest/input_guide.html#scrolling
 ogl :: (Plottable a) => [(GraphInfo, a)]
