diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+change log
+==========
+
+0.1.5.0 - added Control.Varying.Spline
diff --git a/src/Control/Varying/Core.hs b/src/Control/Varying/Core.hs
--- a/src/Control/Varying/Core.hs
+++ b/src/Control/Varying/Core.hs
@@ -45,6 +45,7 @@
 import Prelude hiding (id, (.))
 import Control.Arrow
 import Control.Category
+import Control.Monad (when)
 import Control.Applicative
 import Data.Monoid
 import Debug.Trace
@@ -82,7 +83,7 @@
 --------------------------------------------------------------------------------
 -- | Lift a pure computation into a 'Var'.
 var :: Applicative a => (b -> c) -> Var a b c
-var f = Var $ \a -> pure $ (f a, var f)
+var f = Var $ \a -> pure (f a, var f)
 
 -- | Lift a monadic computation into a 'Var'.
 varM :: Monad m => (a -> m b) -> Var m a b
@@ -113,11 +114,11 @@
 
 -- | Iterate a 'Var' once and return the sample value.
 evalVar :: Functor m => Var m a b -> a -> m b
-evalVar v a = fst <$> (runVar v a)
+evalVar v a = fst <$> runVar v a
 
 -- | Iterate a 'Var' once and return the next 'Var'.
 execVar :: Functor m => Var m a b -> a -> m (Var m a b)
-execVar v a = snd <$> (runVar v a)
+execVar v a = snd <$> runVar v a
 
 -- | Loop over a 'Var' that takes no input value.
 loopVar_ :: (Functor m, Monad m) => Var m () a -> m ()
@@ -166,7 +167,7 @@
 testWhile_ :: Show a => (a -> Bool) -> Var IO () a -> IO ()
 testWhile_ f v = do
     (a, v') <- runVar v ()
-    if f a then print a >> testWhile_ f v' else return ()
+    when (f a) $ print a >> testWhile_ f v'
 
 -- | A utility function for testing 'Var's that require input. The input
 -- must have a 'Read' instance. Use this in GHCI to step through your 'Var's
@@ -176,12 +177,12 @@
                     ~> varM (const getLine)
                     ~> var read
                     ~> v
-                    ~> varM (putStrLn . show)
+                    ~> varM print
 
 -- | A utility function for testing 'Var's that don't require input. Use
 -- this in GHCI to step through your 'Var's using the `return` key.
 testVar_ :: Show b => Var IO () b -> IO ()
-testVar_ v = loopVar_ $ pure () ~> v ~> varM print ~> varM (const $ getLine)
+testVar_ v = loopVar_ $ pure () ~> v ~> varM print ~> varM (const getLine)
 --------------------------------------------------------------------------------
 -- Adjusting and accumulating
 --------------------------------------------------------------------------------
@@ -221,7 +222,7 @@
 (~>) v1 v2 = Var $ \a -> do
     (b, v1') <- runVar v1 a
     (c, v2') <- runVar v2 b
-    return $ (c, v1' ~> v2')
+    return (c, v1' ~> v2')
 infixr 1 ~>
 --------------------------------------------------------------------------------
 -- Typeclass instances
@@ -256,7 +257,7 @@
     pure = var . const
     vf <*> va = Var $ \a -> do (f, vf') <- runVar vf a
                                (b, va') <- runVar va a
-                               return $ (f b, vf' <*> va')
+                               return (f b, vf' <*> va')
 
 -- | 'Var's are arrows, which means you can use proc notation.
 --
@@ -272,7 +273,7 @@
 instance (Applicative m, Monad m) => Arrow (Var m) where
     arr = var
     first v = Var $ \(b,d) -> do (c, v') <- runVar v b
-                                 return $ ((c,d), first v')
+                                 return ((c,d), first v')
 
 -- | 'Var's can be monoids
 --
diff --git a/src/Control/Varying/Event.hs b/src/Control/Varying/Event.hs
--- a/src/Control/Varying/Event.hs
+++ b/src/Control/Varying/Event.hs
@@ -39,13 +39,13 @@
     startWith,
     -- * Temporal operations (time - related)
     between,
-    until,
     after,
     beforeWith,
     beforeOne,
     before,
     filterE,
     takeE,
+    dropE,
     once,
     always,
     never,
@@ -89,14 +89,14 @@
 latchWith :: (Applicative m, Monad m)
           => (b -> c -> d) -> Var m a (Event b) -> Var m a (Event c)
           -> Var m a (Event d)
-latchWith f vb vc = latchWith' (NoEvent, vb) vc
-    where latchWith' (eb, vb') vc' =
+latchWith f vb = latchWith' (NoEvent, vb)
+    where latchWith' (eb, vb') vc =
               Var $ \a -> do (eb', vb'') <- runVar vb' a
-                             (ec', vc'') <- runVar vc' a
+                             (ec', vc') <- runVar vc a
                              let eb'' = eb' <|> eb
-                             return $ ( f <$> eb'' <*> ec'
-                                      , latchWith' (eb'', vb'') vc''
-                                      )
+                             return ( f <$> eb'' <*> ec'
+                                    , latchWith' (eb'', vb'') vc'
+                                    )
 
 -- | Produces values from the first unless the second produces event
 -- values and if so, produces the values of those events.
@@ -190,7 +190,7 @@
 
 -- | Like a left fold over all the stream's produced values.
 foldStream :: Monad m => (a -> t -> a) -> a -> Var m (Event t) a
-foldStream f acc = Var $ \e -> do
+foldStream f acc = Var $ \e ->
     case e of
         Event a -> let acc' = f acc a
                    in return (acc', foldStream f acc')
@@ -271,35 +271,44 @@
         Event b' -> return (Event b', never)
         NoEvent  -> return (Event b, vb' `beforeOne` ve')
 
--- | Produce events with the initial varying value only before the second stream
--- has produced one event.
-before :: (Applicative m, Monad m) => Var m a b -> Var m a (Event c) -> Var m a (Event b)
-before = until
-
--- | Produce events with the initial varying value until the input event stream
--- `ve` produces its first event, then never produce any events.
-until :: (Applicative m, Monad m) => Var m a b -> Var m a (Event c) -> Var m a (Event b)
-until vb ve = Var $ \a -> do
+-- | Produce events of the initial varying value until the given event stream
+-- produces its first event, then inhibit forever.
+before :: (Applicative m, Monad m)
+       => Var m a b -> Var m a (Event c) -> Var m a (Event b)
+before vb ve = Var $ \a -> do
     (b, vb') <- runVar vb a
     (e, ve') <- runVar ve a
     case e of
         Event _ -> return (NoEvent, never)
-        NoEvent -> return (Event b, vb' `until` ve')
+        NoEvent -> return (Event b, vb' `before` ve')
 
 -- | Produce the given value once and then inhibit forever.
 once :: (Applicative m, Monad m) => b -> Var m a (Event b)
 once b = Var $ \_ -> return (Event b, never)
 
 -- | Stream through some number of successful events and then inhibit forever.
-takeE :: (Applicative m, Monad m) => Int -> Var m a (Event b) -> Var m a (Event b)
+takeE :: (Applicative m, Monad m)
+      => Int -> Var m a (Event b) -> Var m a (Event b)
+takeE 0 _ = never
 takeE n ve = Var $ \a -> do
     (eb, ve') <- runVar ve a
     case eb of
         NoEvent -> return (NoEvent, takeE n ve')
         Event b -> return (Event b, takeE (n-1) ve')
 
+-- | Inhibit the first n occurences of an event.
+dropE :: (Applicative m, Monad m)
+      => Int -> Var m a (Event b) -> Var m a (Event b)
+dropE 0 ve = ve
+dropE n ve = Var $ \a -> do
+    (eb, ve') <- runVar ve a
+    case eb of
+        NoEvent -> return (NoEvent, dropE n ve')
+        Event _ -> return (NoEvent, dropE (n-1) ve')
+
 -- | Inhibit all events that don't pass the predicate.
-filterE :: (Applicative m, Monad m) => (b -> Bool) -> Var m a (Event b) -> Var m a (Event b)
+filterE :: (Applicative m, Monad m)
+        => (b -> Bool) -> Var m a (Event b) -> Var m a (Event b)
 filterE p v = v ~> var check
     where check (Event b) = if p b then Event b else NoEvent
           check _ = NoEvent
@@ -327,7 +336,7 @@
     (e, y1') <- runVar y1 a
     case e of
         NoEvent -> runVar y2 a
-        Event b -> return $ (Event b, y1' `andThenE` y2)
+        Event b -> return (Event b, y1' `andThenE` y2)
 
 -- | Switches from one event stream when that stream stops producing. A new
 -- stream is created using the last produced value (or `Nothing`) and used
@@ -339,7 +348,7 @@
               (e, w1') <- runVar w1 a
               case e of
                   NoEvent -> runVar (f mb) a
-                  Event b -> return $ (b, go (Just b) w1' f)
+                  Event b -> return (b, go (Just b) w1' f)
 
 -- | Switches using a mode signal. Signals maintain state for the duration
 -- of the mode.
@@ -352,7 +361,7 @@
         where switchOnUnique v sv = Var $ \a -> do
                   (eb, sv') <- runVar sv a
                   (c', v')  <- runVar (vOf eb) a
-                  return $ (c', switchOnUnique v' sv')
+                  return (c', switchOnUnique v' sv')
                       where vOf eb = case eb of
                                          NoEvent -> v
                                          Event b -> f b
@@ -388,7 +397,7 @@
 combineWith :: (Applicative m, Monad m)
             => (b -> c -> d) -> Var m a (Event b) -> Var m a (Event c)
             -> Var m a (Event d)
-combineWith f vb vc = (uncurry f <$>) <$> (combine vb vc)
+combineWith f vb vc = (uncurry f <$>) <$> combine vb vc
 
 -- | Combine two event streams into an event stream of tuples. A tuple is
 -- only produced when both event streams produce a value.
@@ -438,6 +447,14 @@
     pure = Event
     (<*>) (Event f) (Event a) = Event $ f a
     (<*>) _ _ = NoEvent
+
+-- | Any event is a monoid that responds to mempty with NoEvent. It
+-- responds to mappend by always choosing the rightmost event. This means
+-- left events are replaced unless the right event is NoEvent.
+instance Monoid (Event a) where
+    mempty = NoEvent
+    mappend a NoEvent = a
+    mappend _ b = b
 
 instance Functor Event where
     fmap f (Event a) = Event $ f a
diff --git a/src/Control/Varying/Spline.hs b/src/Control/Varying/Spline.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Varying/Spline.hs
@@ -0,0 +1,199 @@
+-- |
+--   Module:     Control.Varying.SplineT
+--   Copyright:  (c) 2015 Schell Scivally
+--   License:    MIT
+--   Maintainer: Schell Scivally <schell.scivally@synapsegroup.com>
+--
+--  Using splines we can easily create continuously varying values from
+--  multiple piecewise event streams. A spline is a monadic layer on top of
+--  event streams which are only continuous over a certain domain. The idea
+--  is that we use do notation to "run an event stream" from which we will
+--  consume produced values. Once the event stream inhibits the do-notation
+--  computation completes and returns a result value. That result value is then
+--  used to determine the next spline in the sequence. This allows us to build
+--  up long, complex behaviors sequentially using a very familiar notation
+--  that can be easily turned into a continuously varying value.
+
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TupleSections #-}
+module Control.Varying.Spline (
+    -- * Spline
+    Spline,
+    runSpline,
+    execSpline,
+    spline,
+    -- * Spline Transformer
+    SplineT(..),
+    runSplineT,
+    evalSplineT,
+    execSplineT,
+    varyUntilEvent,
+    capture,
+    -- * Step
+    Step(..),
+) where
+
+import Control.Varying.Core
+import Control.Varying.Event
+import Control.Monad.IO.Class
+import Control.Applicative
+import Data.Monoid
+
+-- | A discrete step in a continuous function. This is simply a type that
+-- discretely describes an eventual value on the right and a monoidal output
+-- value on the left.
+data Step f b where
+    Step :: Monoid f => f -> Event b -> Step f b
+
+-- | Returns the left value of a step.
+stepIter :: Step f b -> f
+stepIter (Step a _) = a
+
+-- | Returns the right value of a step.
+stepResult :: Step f b -> Event b
+stepResult (Step _ b) = b
+
+-- | A discrete step is a functor by applying a function to the contained
+-- event's value.
+instance Functor (Step f) where
+    fmap f (Step a b) = Step a $ fmap f b
+
+-- | A discrete spline is a monoid if its left and right types are monoids.
+instance (Monoid f, Monoid b) => Monoid (Step f b) where
+    mempty = Step mempty (Event mempty)
+    mappend (Step a ea) (Step b eb) = Step (mappend a b) (mappend <$> ea <*> eb)
+
+-- | A discrete spline is an applicative if its left datatype is a monoid. It
+-- replies to 'pure' with an empty left value while the right value is the
+-- argument wrapped in an event. It means "the argument happens instantly".
+instance Monoid f => Applicative (Step f) where
+    pure a = Step mempty $ Event a
+    (Step uia f) <*> (Step uib b) = Step (mappend uia uib) (f <*> b)
+
+-- | 'SplineT' shares a number of types with 'Var', specifically its monad,
+-- input and output types (m, a and b, respectively). A spline adds
+-- a container type that determines how empty output values should be
+-- created, appended and applied (the type must be monoidal and applicative).
+-- It also adds a result type which represents the monadic computation's result
+-- value.
+-- Much like the State monad it has an "internal state" and an eventual
+-- return value, where the internal state is the output value. The result
+-- value is used only in determining the next spline to sequence.
+data SplineT m f a b c = SplineT { unSplineT :: Var m a (Step (f b) c) }
+                       | SplineTConst c
+
+-- | Unwrap a spline into a varying value.
+runSplineT :: (Applicative m, Monad m, Monoid (f b))
+           => SplineT m f a b c -> Var m a (Step (f b) c)
+runSplineT (SplineT v) = v
+runSplineT (SplineTConst x) = pure $ pure x
+
+-- | 'Spline' is a specialized 'SplineT' that uses Event as its output
+-- container. This means that new values overwrite/replace old values due to
+-- Event's 'Last'-like monoid instance.
+type Spline m a b c = SplineT m Event a b c
+
+-- | A spline is a functor by applying the function to the result.
+instance (Applicative m, Monad m) => Functor (SplineT m f a b) where
+    fmap f (SplineT v) = SplineT $ fmap (fmap f) v
+    fmap f (SplineTConst c)  = SplineTConst $ f c
+
+-- | A spline is an applicative if its output type is a monoid. It
+-- responds to 'pure' by returning a spline that immediately returns the
+-- argument. It responds to '<*>' by applying the left arguments eventual
+-- value (the function) to the right arguments eventual value. The
+-- output values will me combined with 'mappend'.
+instance (Monoid (f b), Applicative m, Monad m)
+    => Applicative (SplineT m f a b) where
+    pure = SplineTConst
+    (SplineTConst f) <*> (SplineTConst x) = SplineTConst $ f x
+    (SplineT vf) <*> (SplineTConst x) = SplineT $ fmap (fmap ($ x)) vf
+    (SplineTConst f) <*> (SplineT vx) = SplineT $ fmap (fmap f) vx
+    (SplineT vf) <*> (SplineT vx) = SplineT $ ((<*>) <$> vf) <*> vx
+
+-- | A spline is monad if its output type is a monoid. A spline responds
+-- to bind by running until it produces an eventual value, then uses that
+-- value to run the next spline.
+instance (Monoid (f b), Applicative m, Monad m) => Monad (SplineT m f a b) where
+    (SplineTConst x) >>= f = f x
+    (SplineT v) >>= f = SplineT $ Var $ \i -> do
+        (Step b e, v') <- runVar v i
+        case e of
+            NoEvent -> return (Step b NoEvent, runSplineT $ SplineT v' >>= f)
+            Event x -> runVar (runSplineT $ f x) i
+
+-- | A spline can do IO if its underlying monad has a MonadIO instance. It
+-- takes the result of the IO action as its immediate return value and
+-- uses 'mempty' to generate an empty output value.
+instance (Monoid (f b), Functor m, Applicative m, MonadIO m)
+    => MonadIO (SplineT m f a b) where
+    liftIO f = SplineT $ Var $ \_ -> do
+        n <- (Step mempty . Event) <$> liftIO f
+        return (n, pure n)
+
+-- | Evaluates a spline to a varying value of its output type.
+execSplineT :: (Applicative m, Monad m, Monoid (f b))
+            => SplineT m f a b c -> Var m a (f b)
+execSplineT = (stepIter <$>) . runSplineT
+
+-- | Evaluates a spline to an event stream of its result. The resulting
+-- varying value inhibits until the spline's domain is complete and then it
+-- produces events of the result type.
+evalSplineT :: (Applicative m, Monad m, Monoid (f b))
+            => SplineT m f a b c -> Var m a (Event c)
+evalSplineT = (stepResult <$>) . runSplineT
+
+-- | Create a spline using an event stream. The spline will run until the
+-- stream inhibits, using the stream's last produced value as the current
+-- output value. In the case the stream inhibits before producing
+-- a value the default value is used. The spline's result value is the last
+-- output value.
+spline :: (Applicative m, Monad m) => b -> Var m a (Event b) -> Spline m a b b
+spline x ve = SplineT $ Var $ \a -> do
+    (ex, ve') <- runVar ve a
+    case ex of
+        NoEvent  -> let n = Step (Event x) (Event x) in return (n, pure n)
+        Event x' -> return (Step (Event x') NoEvent, runSplineT $ spline x' ve')
+
+-- | Unwrap a spline into a varying value. This is an alias of
+-- 'runSplineT'.
+runSpline :: (Applicative m, Monad m) => Spline m a b c -> Var m a (Step (Event b) c)
+runSpline = runSplineT
+
+-- | Using a default start value, evaluate the spline to a varying value.
+-- A spline is only defined over a finite domain so we must supply a default
+-- value to use before the spline produces its first output value.
+execSpline :: (Applicative m, Monad m) => b -> Spline m a b c -> Var m a b
+execSpline x (SplineTConst _) = pure x
+execSpline x s = execSplineT s ~> foldStream (\_ y -> y) x
+
+-- | Create a spline from a varying value and an event stream. The spline
+-- uses the varying value as its output value. The spline will run until
+-- the event stream produces a value, at that point the last output
+-- value and the event value are used in a merge function to produce the
+-- spline's result value.
+varyUntilEvent :: (Applicative m, Monad m)
+               => Var m a b -> Var m a (Event c) -> (b -> c -> d)
+               -> Spline m a b d
+varyUntilEvent v ve f = SplineT $ Var $ \a -> do
+    (b, v') <- runVar v a
+    (ec, ve') <- runVar ve a
+    case ec of
+        NoEvent -> return (Step (Event b) NoEvent,
+                           runSplineT $ varyUntilEvent v' ve' f)
+        Event c -> let n = Step (Event b) (Event $ f b c)
+                   in return (n, pure n)
+
+-- | Capture the spline's latest output value and tuple it with the
+-- spline's result value. This is helpful when you want to sample the last
+-- output value in order to determine the next spline to sequence.
+capture :: (Applicative m, Monad m, Monoid (f b), Eq (f b))
+        => SplineT m f a b c -> SplineT m f a b (f b, c)
+capture (SplineTConst x) = SplineTConst (mempty, x)
+capture (SplineT v) = capture' mempty v
+    where capture' mb v' = SplineT $ Var $ \a -> do
+              (Step fb ec, v'') <- runVar v' a
+              let mb' = if fb == mempty then mb else fb
+                  ec' = (mb',) <$> ec
+              return (Step fb ec', runSplineT $ capture' mb' v'')
diff --git a/src/Control/Varying/Tween.hs b/src/Control/Varying/Tween.hs
--- a/src/Control/Varying/Tween.hs
+++ b/src/Control/Varying/Tween.hs
@@ -22,6 +22,9 @@
     -- $creation
     tween,
     constant,
+    -- * Tweening with splines
+    -- $splines
+    tweenTo,
     -- * Interpolation functions
     -- $lerping
     linear,
@@ -52,6 +55,7 @@
 
 import Control.Varying.Core
 import Control.Varying.Event hiding (after, before)
+import Control.Varying.Spline
 import Control.Varying.Time
 import Control.Arrow
 import Control.Applicative
@@ -155,8 +159,8 @@
 --------------------------------------------------------------------------------
 -- $creation
 --
--- The standard way to start tweening values is to use 'tween' along with
--- an interpolation function such as 'easeInOutExpo'. For example,
+-- The most direct route toward tweening values is to use 'tween'
+-- along with an interpolation function such as 'easeInOutExpo'. For example,
 -- @tween easeInOutExpo 0 100 10@, this will create an event stream that
 -- produces @Event t@s where `t` is tweened from 0 to 100 over 10 seconds.
 -- Once the 10 seconds are up, the stream will inhibit (produce `NoEvent`)
@@ -201,6 +205,27 @@
 constant :: (Applicative m, Monad m, Num t, Ord t)
          => a -> t -> Var m t (Event a)
 constant value duration = use value $ before duration
+
+--------------------------------------------------------------------------------
+-- $splines
+-- If you plan on doing a lot of tweening it's probably easiest to build up
+-- your tweens as splines using do-notation.
+-- A spline in this context is a numeric computation that is "smooth" over some
+-- domain. It is defined in a piecewise manner by sequencing other splines
+-- together using do-notation.
+-- You can then run the spline, transforming it back into a continuous
+-- varying value.
+--
+-- @
+-- thereAndBack = execSpline 0 $ do
+--   x <- tweenTo easeOutExpo 0 100 1
+--   tweenTo easeOutExpo x 0 1
+-- @
+--------------------------------------------------------------------------------
+-- |
+tweenTo :: (Applicative m, Monad m, Fractional t, Ord t)
+        => Easing t -> t -> t -> t -> Spline m t t t
+tweenTo f start end dur = spline start $ tween f start end dur
 
 -- | Varies 0.0 to 1.0 linearly for duration `t` and 1.0 after `t`.
 timeAsPercentageOf :: (Applicative m, Monad m, Ord t, Num t, Fractional t)
diff --git a/varying.cabal b/varying.cabal
--- a/varying.cabal
+++ b/varying.cabal
@@ -10,16 +10,16 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.1.4.0
+version:             0.1.5.0
 
 -- A short (one-line) description of the package.
-synopsis:            Automaton based varying values, event streams and tweening.
+synopsis:            FRP through varying values and monadic splines.
 
 -- A longer description of the package.
-description:         Varying is another FRP or LSP library aimed at providing a
-                     simple way to describe discrete or continuously varying
-                     values. It is capable of tweening out of the box and
-                     provides a small, well documented API.
+description:         Varying is a FRP implentation aimed at providing a
+                     simple way to describe values that change over some domain.
+                     It allows monadic, applicative or arrow notation and has
+                     convenience functions for tweening.
 
 -- URL for the project homepage or repository.
 homepage:            https://github.com/schell/varying
@@ -51,7 +51,7 @@
 -- Constraint on the version of Cabal needed to build this package.
 cabal-version:       >=1.10
 
-extra-source-files:  README.md
+extra-source-files:  README.md, changelog.md
 
 
 source-repository head
@@ -65,7 +65,8 @@
                        Control.Varying.Core,
                        Control.Varying.Time,
                        Control.Varying.Event,
-                       Control.Varying.Tween
+                       Control.Varying.Tween,
+                       Control.Varying.Spline
 
   -- Modules included in this library but not exported.
   -- other-modules:
@@ -75,7 +76,8 @@
 
   -- Other library packages from which modules are imported.
   build-depends:       base >=4.7 && <4.9,
-                       time >=1.5 && <1.6
+                       time >=1.5 && <1.6,
+                       transformers >= 0.4 && <0.5
 
   -- Directories containing source files.
   hs-source-dirs:      src
@@ -88,7 +90,8 @@
 
   -- Other library packages from which modules are imported.
   build-depends:       base >=4.7 && <4.9,
-                       time >=1.5 && <1.6
+                       time >=1.5 && <1.6,
+                       transformers >= 0.4 && <0.5
 
 
   -- Directories containing source files.
