diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -27,6 +27,10 @@
 
 0.7.0.0 - added proofs, reduced API size by removing trivial or weird (special)
           combinators, changed some names, Event is a synonym of Maybe, removed
-	  Time (moved functions to Event), renamed Event.mergeE to Event.bothE,
-          added Spline.untilProc and Spline.whileProc, documentation - working 
-	  towards 1.0
+      Time (moved functions to Event), renamed Event.mergeE to Event.bothE,
+          added Spline.untilProc and Spline.whileProc, documentation - working
+      towards 1.0
+
+0.7.1.2 - Fixed broken ArrowLoop instance, updated documentation.
+
+0.8.0.0 - TweenT is a newtype.
diff --git a/src/Control/Varying.hs b/src/Control/Varying.hs
--- a/src/Control/Varying.hs
+++ b/src/Control/Varying.hs
@@ -27,3 +27,6 @@
 import           Control.Varying.Event  as V
 import           Control.Varying.Spline as V
 import           Control.Varying.Tween  as V
+
+-- TODO: CICD and auto-push master to hackage.
+-- This would be very nice.
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
@@ -92,6 +92,7 @@
     where g (b, vb) = (f b, f <$> vb)
 
 -- | A var is a category.
+--
 -- @
 --   id = var id
 --   f . g = g >>> f
@@ -180,6 +181,7 @@
 -- | Inputs can depend on outputs as long as no time-travel is required.
 --
 -- This isn't the best example but it does make a good test case:
+--
 -- >>> :{
 -- let
 --   testVar :: VarT IO Double (Maybe Double)
diff --git a/src/Control/Varying/Spline.hs b/src/Control/Varying/Spline.hs
--- a/src/Control/Varying/Spline.hs
+++ b/src/Control/Varying/Spline.hs
@@ -15,7 +15,6 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs            #-}
 {-# LANGUAGE LambdaCase       #-}
-{-# LANGUAGE TupleSections    #-}
 module Control.Varying.Spline
   ( -- * Spline
     Spline
@@ -51,10 +50,7 @@
 import           Control.Varying.Core
 import           Control.Varying.Event
 import           Data.Functor.Identity
-import           Data.Monoid
 
--- $setup
--- >>> import Control.Varying.Time
 
 -- | 'SplineT' shares all the types of 'VarT' and adds a result value. Its
 -- monad, input and output types (@m@, @a@ and @b@, respectively) represent the
@@ -101,6 +97,7 @@
                        Left  c               -> runSplineT (f c) a
                        Right (b, SplineT s1) -> return $ Right (b, SplineT $ g s1)
 
+
 -- | A spline responds to 'pure' by returning a spline that never produces an
 -- output value and immediately returns the argument. It responds to '<*>' by
 -- applying the left arguments result value (the function) to the right
@@ -117,9 +114,9 @@
   pure = return
   sf <*> sx = do
     f <- sf
-    x <- sx
-    return $ f x
+    f <$> sx
 
+
 -- | A spline is a transformer by running the effect and immediately concluding,
 -- using the effect's result as the result value.
 --
@@ -315,21 +312,39 @@
 -- spline's result. This is helpful when you want to sample the last
 -- output value in order to determine the next spline to sequence.
 --
+-- The tupled value is returned in as a 'Maybe b' since it is not
+-- guaranteed that an output value is produced before a Spline concludes.
+--
 -- >>> :{
--- let s = do (Just x, "boom") <- capture $ do step 0
---                                             step 1
---                                             step 2
---                                             return "boom"
---            -- x is 2
---            step $ x + 1
--- in testVarOver (outputStream s 666) [(),(),(),()]
+-- let
+--   s :: MonadIO m => SplineT () Int m String
+--   s = do
+--     (mayX, boomStr) <-
+--       capture
+--         $ do
+--           step 0
+--           step 1
+--           step 2
+--           return "boom"
+--     -- x is 2, but 'capture' can't be sure of that
+--     maybe
+--       (return "Failure")
+--       ( (>> return boomStr)
+--         . step
+--         . (+1)
+--       )
+--       mayX
+-- in
+--   testVarOver (outputStream s 666) [(),(),(),()]
 -- >>> :}
 -- 0
 -- 1
 -- 2
 -- 3
-capture :: Monad m
-        => SplineT a b m c -> SplineT a b m (Event b, c)
+capture
+  :: Monad m
+  => SplineT a b m c
+  -> SplineT a b m (Maybe b, c)
 capture = SplineT . f Nothing
     where f mb s = runSplineT s >=> return . \case
             Left c        -> Left (mb, c)
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
@@ -13,17 +13,15 @@
 --   time you use. At some point it would be great to be able to tween
 --   arbitrary types, and possibly tween one type into another (pipe
 --   dreams).
-
-{-# LANGUAGE Rank2Types   #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE Rank2Types                 #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
 module Control.Varying.Tween
   ( -- * Tweening types
     Easing
   , TweenT
   , Tween
-    -- * Running tweens
-  , runTweenT
-  , scanTween
-  , tweenStream
     -- * Creating tweens
     -- $creation
   , tween
@@ -31,6 +29,8 @@
   , constant
   , withTween
   , withTween_
+    -- * Combining tweens
+    -- $combining
     -- * Interpolation functions
     -- $lerping
   , linear
@@ -47,26 +47,50 @@
   , easeOutCubic
   , easeInQuad
   , easeOutQuad
-    -- * Writing your own tweens
-    -- $writing
+    -- * Running tweens
+  , tweenStream
+  , runTweenT
+  , scanTween
   ) where
 
 import           Control.Monad             (void)
 import           Control.Monad.Trans.State (StateT, evalStateT, get, put,
                                             runStateT)
+import           Control.Monad.Trans.Class (MonadTrans (..))
 import           Control.Varying.Core      (VarT (..), done)
+import           Control.Varying.Event     (after)
 import           Control.Varying.Spline    (SplineT (..), mapOutput, scanSpline,
                                             untilEvent_)
-import           Control.Varying.Event     (after)
+import           Data.Bifunctor            (first, second)
 import           Data.Functor.Identity     (Identity)
+import           GHC.Generics              (Generic)
 
+
+-- $setup
+-- >>> import Control.Varying.Core
+
+
 --------------------------------------------------------------------------------
+-- | An easing function. The parameters are often named `c`, `t` and `b`,
+-- where `c` is the total change in value over the complete duration
+-- (endValue - startValue), `t` is the current percentage (0 to 1) of the
+-- duration that has elapsed and `b` is the start value.
+--
+-- To make things simple only numerical values can be tweened and the type
+-- of time deltas must match the tween's value type. This may change in the
+-- future :)
+type Easing t f = t -> f -> t -> t
+
+
+--------------------------------------------------------------------------------
 -- $lerping
 -- These pure functions take a `c` (total change in value, ie end - start),
 -- `t` (percent of duration completion) and `b` (start value) and result in
 -- an interpolation of a value. To see what these look like please check
 -- out http://www.gizma.com/easing/.
 --------------------------------------------------------------------------------
+
+
 -- | Ease in quadratic.
 easeInQuad :: (Fractional t, Real f) => Easing t f
 easeInQuad c t b =  c * realToFrac (t*t) + b
@@ -131,30 +155,121 @@
 linear :: (Floating t, Real f) => Easing t f
 linear c t b = c * realToFrac t + b
 
--- TODO: Don't use StateT for leftover time in Tweens.
--- This creates a funky state where running two tween splines together
--- causes leftover time interplay. Think about continuations or something.
+-- | A 'TweenT' is a 'SplineT' that holds a duration in local state. This allows
+-- 'TweenT's to be sequenced monadically.
+--
+-- * 'f' is the input time delta type (the input type)
+-- * 't' is the start and end value type (the output type)
+-- * 'a' is the result value type
+--
+-- You can sequence 'TweenT's with monadic notation to produce more complex ones.
+-- This is especially useful for animation:
+--
+-- >>> :{
+-- let
+--   tweenInOutExpo
+--     :: ( Monad m, Floating t, Real t, Real f, Fractional f )
+--     => t
+--     -> t
+--     -> f
+--     -> TweenT f t m t
+--   tweenInOutExpo start end dur = do
+--       x <- tween easeInExpo start (end/2) (dur/2)
+--       tween easeOutExpo x end $ dur/2
+-- >>> :}
+newtype TweenT f t m a
+  = TweenT { unTweenT :: SplineT f t (StateT f m) a }
+  deriving (Generic, Functor, Applicative, Monad)
 
-type TweenT f t m = SplineT f t (StateT f m)
-type Tween f t = TweenT f t Identity
 
-runTweenT :: TweenT f t m x -> f -> f -> m (Either x (t, TweenT f t m x), f)
-runTweenT s dt = runStateT (runSplineT s dt)
+instance MonadTrans (TweenT f t) where
+  lift = TweenT . lift . lift
 
-scanTween :: (Monad m, Num f)
-          => TweenT f t m a -> t -> [f] -> m [t]
-scanTween s t dts = evalStateT (scanSpline s t dts) 0
 
+type Tween f t a = TweenT f t Identity a
+
+
+runTweenT
+  :: Functor m
+  => TweenT f t m a
+  -> f
+  -- ^ The input time delta this frame
+  -> f
+  -- ^ The leftover time delta from last frame
+  -> m (Either a (t, TweenT f t m a), f)
+  -- ^ Returns
+  -- @
+  -- a tuple of
+  --   either
+  --     the result
+  --     or a tuple of
+  --       this step's output value
+  --       and the tween for the next step
+  --   and the leftover time delta for the next step
+  -- @
+runTweenT (TweenT s) dt leftover =
+  first (second $ second TweenT)
+  <$> runStateT
+        (runSplineT s dt)
+        leftover
+
+
+scanTween
+  :: (Monad m, Num f)
+  => TweenT f t m a
+  -> t
+  -> [f]
+  -> m [t]
+scanTween (TweenT s) t dts =
+  evalStateT
+    (scanSpline s t dts)
+    0
+
+
 -- | Converts a tween into a continuous value stream. This is the tween version
--- of `outputStream`.
-tweenStream :: (Monad m, Num f)
-            => TweenT f t m x -> t -> VarT m f t
-tweenStream s0 t0 = VarT $ f s0 t0 0
-  where f s t l i = do (e, l1) <- runTweenT s i l
-                       case e of
-                         Left _        -> return (t, done t)
-                         Right (b, s1) -> return (b, VarT $ f s1 b l1)
+-- of 'Control.Varying.Spline.outputStream'. This is the preferred way to run
+-- your tweens.
+--
+-- >>> :{
+-- let
+--   x :: TweenT Float Float IO Float
+--   x = tween linear 0 1 1
+--   y :: TweenT Float Float IO Float
+--   y = tween linear 0 1 2
+--   v :: VarT IO Float (Float, Float)
+--   v = (,)
+--       <$> tweenStream x 0
+--       <*> tweenStream y 0
+-- in
+--   testVarOver v [0.5, 0.5, 0.5, 0.5]
+-- >>> :}
+-- (0.5,0.25)
+-- (1.0,0.5)
+-- (1.0,0.75)
+-- (1.0,1.0)
+tweenStream
+  :: forall m f t x
+   . (Functor m, Monad m, Num f)
+  => TweenT f t m x
+  -- ^ The tween to convert into a stream
+  -> t
+  -- ^ An initial output value
+  -> VarT m f t
+tweenStream s0 t0 = VarT $ go s0 t0 0
+  where
+    go ::
+         TweenT f t m x -- The Tween
+      -> t -- the last output value
+      -> f -- the leftover time delta from last fram
+      -> f -- the input time delta
+      -> m (t, VarT m f t)
+    go s t l i = do
+      (e, l1) <- runTweenT s i l
+      case e of
+        Left _        -> return (t, done t)
+        Right (b, s1) -> return (b, VarT $ go s1 b l1)
 
+
 --------------------------------------------------------------------------------
 -- $creation
 -- The most direct route toward tweening values is to use 'tween'
@@ -174,21 +289,26 @@
 -- `tween` concludes returning the latest output value.
 tween :: (Monad m, Real t, Real f, Fractional f)
       => Easing t f -> t -> t -> f -> TweenT f t m t
-tween f start end dur = SplineT g
-  where c = end - start
-        b = start
-        g dt = do
-          leftover <- get
-          let t = dt + leftover
+tween f start end dur =
+  TweenT
+    $ SplineT g
+  where
+    c = end - start
+    b = start
+    g dt = do
+      leftover <- get
+      let
+        t = dt + leftover
+      if t == dur
+        then
+          put 0 >> return (Right (end, return end))
+        else
+          if t > dur
+          then
+            put (t - dur - dt) >> return (Left end)
+          else
+            put t >> return (Right (f c (t/dur) b, SplineT g))
 
-          if t == dur
-            then do put 0
-                    return $ Right (end, return end)
-            else if t > dur
-              then do put $ t - dur - dt
-                      return $ Left end
-              else do put t
-                      return $ Right (f c (t/dur) b, SplineT g)
 
 -- | A version of 'tween' that discards the result. It is simply
 --
@@ -202,14 +322,19 @@
 
 -- | A version of 'tween' that maps its output using the given constant
 -- function.
+--
 -- @
 -- withTween ease from to dur f = mapOutput (pure f) $ tween ease from to dur
 -- @
 withTween :: (Monad m, Real t, Real a, Fractional a)
           => Easing t a -> t -> t -> a -> (t -> x) -> TweenT a x m t
-withTween ease from to dur f = mapOutput (pure f) $ tween ease from to dur
+withTween ease from to dur f =
+  TweenT
+    $ mapOutput (pure f)
+    $ unTweenT
+    $ tween ease from to dur
 
--- | A version of 'withTween' that discards its output.
+-- | A version of 'withTween' that discards its result.
 withTween_ :: (Monad m, Real t, Real a, Fractional a)
            => Easing t a -> t -> t -> a -> (t -> x) -> TweenT a x m ()
 withTween_ ease from to dur f = Control.Monad.void (withTween ease from to dur f)
@@ -217,24 +342,6 @@
 -- | Creates a tween that performs no interpolation over the duration.
 constant :: (Monad m, Num t, Ord t)
          => a -> t -> TweenT t a m a
-constant value duration = pure value `untilEvent_` after duration
---------------------------------------------------------------------------------
--- $writing
--- To create your own tweens just write a function that takes a start
--- value, end value and a duration and return an event stream.
---
--- @
--- tweenInOutExpo start end dur = do
---     (dt, x) <- tween easeInExpo start end (dur/2)
---     tween easeOutExpo x end $ dt + dur/2
--- @
---------------------------------------------------------------------------------
--- | An easing function. The parameters are often named `c`, `t` and `b`,
--- where `c` is the total change in value over the complete duration
--- (endValue - startValue), `t` is the current percentage (0 to 1) of the
--- duration that has elapsed and `b` is the start value.
---
--- To make things simple only numerical values can be tweened and the type
--- of time deltas must match the tween's value type. This may change in the
--- future :)
-type Easing t f = t -> f -> t -> t
+constant value duration =
+  TweenT
+    $ pure value `untilEvent_` after duration
diff --git a/test/DocTests.hs b/test/DocTests.hs
new file mode 100644
--- /dev/null
+++ b/test/DocTests.hs
@@ -0,0 +1,7 @@
+module Main where
+
+import Test.DocTest
+
+main :: IO ()
+main =
+  doctest ["src", "app"]
diff --git a/varying.cabal b/varying.cabal
--- a/varying.cabal
+++ b/varying.cabal
@@ -1,150 +1,107 @@
--- Initial varying.cabal generated by cabal init.  For further
--- documentation, see http://haskell.org/cabal/users-guide/
-
--- The name of the package.
-name:                varying
-
--- The package version.  See the Haskell package versioning policy (PVP)
--- for standards guiding when and how versions should be incremented.
--- http://www.haskell.org/haskellwiki/Package_versioning_policy
--- PVP summary:      +-+------- breaking API changes
---                   | | +----- non-breaking API additions
---                   | | | +--- code changes with no API change
-version:             0.7.1.1
-
--- A short (one-line) description of the package.
-synopsis:            FRP through value streams and monadic splines.
-
--- A longer description of the package.
-description:         Varying is a FRP library aimed at providing a
-                     simple way to describe values that change over a domain.
-                     It allows monadic, applicative and arrow notation and has
-                     convenience functions for tweening.
-
--- URL for the project homepage or repository.
-homepage:            https://github.com/schell/varying
-
--- The license under which the package is released.
-license:             MIT
-
--- The file containing the license text.
-license-file:        LICENSE
-
--- The package author(s).
-author:              Schell Scivally
-
--- An email address to which users can send suggestions, bug reports, and
--- patches.
-maintainer:          schell@takt.com
-
--- A copyright notice.
--- copyright:
-
-category:            Control, FRP
-
-build-type:          Simple
-
--- Extra files to be distributed with the package, such as examples or a
--- README.
--- extra-source-files:
+cabal-version: 1.12
 
--- Constraint on the version of Cabal needed to build this package.
-cabal-version:       >=1.10
+-- This file has been generated from package.yaml by hpack version 0.31.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 23f79975d60664192d4aec0699c6a80542dc85db8ebfb018fd84bea51c196f7b
 
-extra-source-files:  README.md, changelog.md
+name:           varying
+version:        0.8.0.0
+synopsis:       FRP through value streams and monadic splines.
+description:    Varying is a FRP library aimed at providing a simple way to describe values that change over a domain. It allows monadic, applicative and arrow notation and has convenience functions for tweening. Great for animation.
+category:       Control, FRP
+homepage:       https://github.com/schell/varying
+bug-reports:    https://github.com/schell/varying/issues
+author:         Schell Scivally
+maintainer:     schell@takt.com
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    changelog.md
 
 source-repository head
-  type:     git
-  location: https://github.com/schell/varying.git
+  type: git
+  location: https://github.com/schell/varying
 
 library
-  ghc-options:         -Wall
-  if impl(ghc >= 8)
-    ghc-options:       -Wno-type-defaults
-
-  -- Modules exported by the library.
-  exposed-modules:     Control.Varying,
-                       Control.Varying.Core,
-                       Control.Varying.Event,
-                       Control.Varying.Tween,
-                       Control.Varying.Spline
-
-  -- Modules included in this library but not exported.
-  -- other-modules:
-
-  -- LANGUAGE extensions used by modules in this package.
-  -- other-extensions:
-
-  -- Other library packages from which modules are imported.
-  build-depends:       base >=4.8 && <5.0
-                     , transformers >=0.3
-                     , contravariant >= 1.4
-
-  -- Directories containing source files.
-  hs-source-dirs:      src
-
-  -- Base language which the package is written in.
-  default-language:    Haskell2010
+  exposed-modules:
+      Control.Varying
+      Control.Varying.Core
+      Control.Varying.Event
+      Control.Varying.Spline
+      Control.Varying.Tween
+  other-modules:
+      Paths_varying
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base >=4.8 && <5.0
+    , contravariant >=1.4
+    , transformers >=0.3
+  default-language: Haskell2010
 
 executable varying-example
-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
-  if impl(ghc >= 8)
-    ghc-options:       -Wno-type-defaults
-
-  -- Other library packages from which modules are imported.
-  build-depends:       base >=4.8 && <5.0
-                     , transformers >=0.3
-                     , time >=1.4
-                     , varying
-
-
-  -- Directories containing source files.
-  hs-source-dirs:      app
-
-  main-is:             Main.hs
-
-  -- Base language which the package is written in.
-  default-language:    Haskell2010
-
-test-suite varying-test
-  type:                exitcode-stdio-1.0
-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
-  if impl(ghc >= 8)
-    ghc-options:       -Wno-type-defaults
-
-  -- Other library packages from which modules are imported.
-  build-depends:       base >=4.8 && <5.0
-                     , time >=1.4
-                     , transformers
-                     , varying
-                     , hspec
-                     , QuickCheck
-
-  -- Directories containing source files.
-  hs-source-dirs:      test
+  main-is: Main.hs
+  other-modules:
+      Paths_varying
+  hs-source-dirs:
+      app
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.8 && <5.0
+    , contravariant >=1.4
+    , time >=1.4
+    , transformers >=0.3
+    , varying
+  default-language: Haskell2010
 
-  main-is:             Main.hs
+test-suite doctests
+  type: exitcode-stdio-1.0
+  main-is: DocTests.hs
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.8 && <5.0
+    , contravariant >=1.4
+    , doctest
+    , transformers >=0.3
+    , varying
+  default-language: Haskell2010
 
-  -- Base language which the package is written in.
-  default-language:    Haskell2010
+test-suite other
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      QuickCheck
+    , base >=4.8 && <5.0
+    , contravariant >=1.4
+    , hspec
+    , time >=1.4
+    , transformers >=0.3
+    , varying
+  default-language: Haskell2010
 
 benchmark varying-bench
-  type:                exitcode-stdio-1.0
-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
-  if impl(ghc >= 8)
-    ghc-options:       -Wno-type-defaults
-
-  -- Other library packages from which modules are imported.
-  build-depends:       base >=4.8
-                     , time >=1.4
-                     , transformers
-                     , varying
-                     , criterion
-
-  -- Directories containing source files.
-  hs-source-dirs:      bench
-
-  main-is:             Main.hs
-
-  -- Base language which the package is written in.
-  default-language:    Haskell2010
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  other-modules:
+      Paths_varying
+  hs-source-dirs:
+      bench
+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.8 && <5.0
+    , contravariant >=1.4
+    , criterion
+    , time >=1.4
+    , transformers
+    , varying
+  default-language: Haskell2010
