diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.1
+
+- Fixed sampling implementation.
+- Updated documentation.
+- Added normalizeSampling.
+
 ## 0.3
 
 - Added Bézier interpolation mode.
diff --git a/smoothie.cabal b/smoothie.cabal
--- a/smoothie.cabal
+++ b/smoothie.cabal
@@ -1,5 +1,5 @@
 name:                smoothie
-version:             0.3
+version:             0.3.1
 synopsis:            Smooth curves via several splines and polynomials.
 description:         This package exports several splines and curves you can use
                      to interpolate points in between.
diff --git a/src/Data/Spline.hs b/src/Data/Spline.hs
--- a/src/Data/Spline.hs
+++ b/src/Data/Spline.hs
@@ -7,12 +7,8 @@
 -- Stability   : experimental
 -- Portability : portable
 --
--- A @Spline s a@ represents a curve in which 'a' is very likely to be
+-- A @Spline a s@ represents a curve in which 'a' is very likely to be
 -- 'Additive' (see "linear") and 's' is the sampling type.
---
--- The library exports two useful functions: 'spline' and 'smooth'. The former
--- enables you to create splines while the latter enables you to sample from
--- them using their control points.
 ----------------------------------------------------------------------------
 
 module Data.Spline (
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
@@ -60,7 +60,9 @@
 sample :: (Additive a,Floating s,Ord s) => Spline a s -> s -> Maybe (a s)
 sample (Spline keys sampler) at = do
   i <- bsearchLower (\k -> compare at (sampler $ keyValue k)) keys
-  interpolateKeys at <$> keys !? i <*> keys !? (i + 1)
+  k0 <- keys !? i
+  k1 <- keys !? (i + 1)
+  pure $ interpolateKeys (normalizeSampling sampler at k0 k1) k0 k1
 
 -- Helper binary search that searches the ceiling index for the
 -- value to be searched according to the predicate.
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
@@ -14,6 +14,7 @@
   , keyValue
     -- * interpolation
   , interpolateKeys
+  , normalizeSampling
   ) where
 
 import Linear
@@ -33,8 +34,8 @@
 -- key.
 --
 -- @Bezier l v r@ represents a cubic Bezier interpolation, where 'l' refers
--- to the input – left – normal of the key and 'r' is the
--- output – right – normal of the key.
+-- to the input – left – tangent of the key and 'r' is the
+-- output – right – tangent of the key.
 data Key a
   = Hold a
   | Linear a
@@ -81,7 +82,7 @@
     b = keyValue end
 
 -- @interpolateBezier s k0 r0 l1 k1@ performs a Bezier interpolation
--- between keys 'k0' and 'k1' using their respectives right and left handles.
+-- between keys 'k0' and 'k1' using their respectives right and left tangents.
 interpolateBezier :: (Additive a,Floating s)
                   => s
                   -> a s
@@ -93,3 +94,24 @@
   where
     u = k0 ^+^ (r0 ^-^ k0) ^* s
     v = l1 ^+^ (k1 ^-^ l1) ^* s
+
+-- |Normalize a sampling value by clamping and scaling it between two keys.
+--
+-- The following laws should be satisfied in order to get a coherent output:
+--
+-- @
+--   sampler :: a s -> s
+--
+--   sampler (keyValue k1) <= s >= sampler (keyValue k0)
+--   0 <= normalizeSampling sampler s k0 k1 <= 1
+-- @
+normalizeSampling :: (Fractional s)
+                  => (a s -> s)
+                  -> s
+                  -> Key (a s)
+                  -> Key (a s)
+                  -> s
+normalizeSampling sampler s k0 k1 = (s - s0) / (s1 - s0)
+  where
+    s0 = sampler (keyValue k0)
+    s1 = sampler (keyValue k1)
