diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,18 @@
+## 0.4
+
+### Breaking changes
+
+- Removed `splineSampler` from `Spline`. It has to be passed to `spline`
+  explicitely now on.
+
+### Non-breaking changes
+
+- Added ToJSON instances for Spline.
+- Added ToJSON instances for Key.
+- Added the keyInterpolation function to get a Text version of the
+  interpolation of a Key.
+- `Eq`, `Functor` and `Show` instances for `Spline`.
+
 ## 0.3.3.3
 
 - Support for vector-0.11.
diff --git a/smoothie.cabal b/smoothie.cabal
--- a/smoothie.cabal
+++ b/smoothie.cabal
@@ -1,7 +1,7 @@
 name:                smoothie
-version:             0.3.3.3
+version:             0.4
 synopsis:            Smooth curves via several interpolation modes
-description:         This package exports several splines you can use
+description:         This package exports several splines you can use
                      to interpolate points in between. It includes instances for
                      <https://hackage.haskell.org/package/aeson aeson> so that
                      you can quickly store the splines and restore them.
@@ -39,6 +39,7 @@
                      , linear >= 1.16 && < 1.20
                      , vector >= 0.10 && < 0.12
                      , aeson  >= 0.9  && < 0.10
+                     , text   >= 1.2  && < 1.3
 
   hs-source-dirs:      src
 
diff --git a/src/Data/Spline/Curve.hs b/src/Data/Spline/Curve.hs
--- a/src/Data/Spline/Curve.hs
+++ b/src/Data/Spline/Curve.hs
@@ -17,7 +17,6 @@
     -- * Splines
     Spline
   , splineKeys
-  , splineSampler
     -- * Building splines
   , spline
     -- * Sampling splines
@@ -42,19 +41,19 @@
 -- Thus, the interpolation mode of the latest key might be ignored. There’s an
 -- exception, though, when using the 'Bezier' interpolation mode. Feel free
 -- to dig in the "Key" documentation.
-data Spline a s = Spline {
+newtype Spline a s = Spline {
     -- |Extract the 'Key's.
     splineKeys :: Vector (Key (a s))
-    -- |Extract the sampler. The sampler is a function used to extract a
-    -- reference value used to perform several operations on the 'Key's.
-  , splineSampler :: a s -> s
-  }
+  } deriving (Eq,Functor,Show)
 
 instance (FromJSON (a s), Ord s) => FromJSON ((a s -> s) -> Spline a s) where
-  parseJSON = withObject "spline" $ \o -> do
-    keys <- o .: "keys"
+  parseJSON value = do
+    keys <- parseJSON value
     pure $ \sampler -> spline sampler keys
 
+instance (ToJSON (a s)) => ToJSON (Spline a s) where
+  toJSON = Array . fmap toJSON . splineKeys
+
 -- |Build a @'Spline' a s@.
 --
 -- @a s@ is the type held by 'Key's. For instance, @'V2' Float@.
@@ -67,13 +66,19 @@
        => (a s -> s)
        -> [Key (a s)]
        -> Spline a s
-spline sampler keys =
-  Spline (fromList $ sortBy (comparing $ sampler . keyValue) keys) sampler
+spline sampler = Spline . fromList . sortBy (comparing $ sampler . keyValue)
 
 -- |Sample a 'Spline' at a given 's' sampling value. If no sample exists,
 -- yields 'Nothing'.
-sample :: (Additive a,Floating s,Ord s) => Spline a s -> s -> Maybe (a s)
-sample (Spline keys sampler) at = do
+--
+-- The first parameter is a /sampler/ function used to extract a comparison
+-- value. For most curves, the reflected value should be the time or the frame.
+sample :: (Additive a,Floating s,Ord s)
+       => (a s -> s)
+       -> Spline a s
+       -> s
+       -> Maybe (a s)
+sample sampler (Spline keys) at = do
   i <- bsearchLower (\k -> compare at (sampler $ keyValue k)) keys
   k0 <- keys !? i
   k1 <- keys !? (i + 1)
diff --git a/src/Data/Spline/Key.hs b/src/Data/Spline/Key.hs
--- a/src/Data/Spline/Key.hs
+++ b/src/Data/Spline/Key.hs
@@ -20,6 +20,7 @@
   ) where
 
 import Data.Aeson
+import Data.Text ( Text )
 import Linear
 
 -- |A 'Key' is a point on the spline with extra information added. It can be,
@@ -45,15 +46,7 @@
   | Cosine a
   | CubicHermite a
   | Bezier a a a
-    deriving (Eq,Show)
-
-instance Functor Key where
-  fmap f k = case k of
-    Hold a         -> Hold (f a)
-    Linear a       -> Linear (f a)
-    Cosine a       -> Cosine (f a)
-    CubicHermite a -> CubicHermite (f a)
-    Bezier l a r   -> Bezier (f l) (f a) (f r)
+    deriving (Eq,Functor,Show)
 
 instance (FromJSON a) => FromJSON (Key a) where
   parseJSON = withObject "key" $ \o -> do
@@ -70,6 +63,16 @@
           pure $ Bezier left value right
       | otherwise                        -> fail "unknown interpolation mode"
 
+instance (ToJSON a) => ToJSON (Key a) where
+  toJSON k = object $
+      ["value" .= value,"interpolation" .= interpolation] ++ tangents
+    where
+      value = keyValue k
+      interpolation = keyInterpolation k
+      tangents = case k of
+        Bezier l _ r -> ["left" .= l,"right" .= r]
+        _            -> []
+
 -- |Extract the value out of a 'Key'.
 keyValue :: Key a -> a
 keyValue k = case k of
@@ -78,6 +81,15 @@
   Cosine a       -> a
   CubicHermite a -> a
   Bezier _ a _   -> a
+
+-- |Extract the interpolation mode from a 'Key'.
+keyInterpolation :: Key a -> Text
+keyInterpolation k = case k of
+  Hold{}         -> "hold"
+  Linear{}       -> "linear"
+  Cosine{}       -> "cosine"
+  CubicHermite{} -> "cubic-hermite"
+  Bezier{}       -> "bezier"
 
 -- |@'interpolateKeys' t start end@ interpolates between 'start' and 'end' using
 -- 's' as a normalized sampling value.
