diff --git a/src/lens.rs b/src/lens.rs
index 2f7104bdefb33dc58e1bda99259d7e006f8cb5f2..93fb9ef675b5cd171b97f7e0821c523952a1dd4e 100644
--- a/src/lens.rs
+++ b/src/lens.rs
@@ -1,12 +1,46 @@
 //! Collection of predefined lenses for common Bevy components and assets.
+//!
+//! # Predefined lenses
+//!
+//! This module contains predefined lenses for common use cases. Those lenses are
+//! entirely optional. They can be used if they fit your use case, to save some time,
+//! but are not treated any differently from a custom user-provided lens.
+//!
+//! # Rotations
+//!
+//! Several rotation lenses are provided, with different properties.
+//!
+//! ## Shortest-path rotation
+//!
+//! The [`TransformRotationLens`] animates the [`rotation`] field of a [`Transform`]
+//! component using [`Quat::slerp()`]. It inherits the properties of that method, and
+//! in particular the fact it always finds the "shortest path" from start to end. This
+//! is well suited for animating a rotation between two given directions, but will
+//! provide unexpected results if you try to make an entity rotate around a given axis
+//! for more than half a turn, as [`Quat::slerp()`] will then try to move "the other
+//! way around".
+//!
+//! ## Angle-focused rotations
+//!
+//! Conversely, for cases where the rotation direction is important, like when trying
+//! to do a full 360-degree turn, a series of angle-based interpolation lenses is
+//! provided:
+//! - [`TransformRotateXLens`]
+//! - [`TransformRotateYLens`]
+//! - [`TransformRotateZLens`]
+//! - [`TransformRotateAxisLens`]
+//!
+//! [`rotation`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html#structfield.rotation
+//! [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+//! [`Quat::slerp()`]: https://docs.rs/bevy/0.6.0/bevy/math/struct.Quat.html#method.slerp
 
 use bevy::prelude::*;
 
 /// A lens over a subset of a component.
 ///
 /// The lens takes a `target` component or asset from a query, as a mutable reference,
-/// and animates (tweens) a subet of the fields of the component/asset based on the
-/// linear ratio `ratio`, already sampled from the easing curve.
+/// and animates (tweens) a subset of the fields of the component/asset based on the
+/// linear ratio `ratio` in \[0:1\], already sampled from the easing curve.
 ///
 /// # Example
 ///
@@ -83,8 +117,19 @@ impl Lens<Transform> for TransformPositionLens {
 
 /// A lens to manipulate the [`rotation`] field of a [`Transform`] component.
 ///
+/// This lens interpolates the [`rotation`] field of a [`Transform`] component
+/// from a `start` value to an `end` value using the spherical linear interpolation
+/// provided by [`Quat::slerp()`]. This means the rotation always uses the shortest
+/// path from `start` to `end`. In particular, this means it cannot make entities
+/// do a full 360 degrees turn. Instead use [`TransformRotateXLens`] and similar
+/// to interpolate the rotation angle around a given axis.
+///
+/// See the [top-level `lens` module documentation] for a comparison of rotation lenses.
+///
 /// [`rotation`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html#structfield.rotation
 /// [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+/// [`Quat::slerp()`]: https://docs.rs/bevy/0.6.0/bevy/math/struct.Quat.html#method.slerp
+/// [top-level `lens` module documentation]: crate::lens
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct TransformRotationLens {
     /// Start value of the rotation.
@@ -95,7 +140,117 @@ pub struct TransformRotationLens {
 
 impl Lens<Transform> for TransformRotationLens {
     fn lerp(&mut self, target: &mut Transform, ratio: f32) {
-        target.rotation = self.start.slerp(self.end, ratio); // FIXME - This slerps the shortest path only! https://docs.rs/bevy/latest/bevy/math/struct.Quat.html#method.slerp
+        target.rotation = self.start.slerp(self.end, ratio);
+    }
+}
+
+/// A lens to rotate a [`Transform`] component around its local X axis.
+///
+/// This lens interpolates the rotation angle of a [`Transform`] component from
+/// a `start` value to an `end` value, for a rotation around the X axis. Unlike
+/// [`TransformRotationLens`], it can produce an animation that rotates the entity
+/// any number of turns around its local X axis.
+///
+/// See the [top-level `lens` module documentation] for a comparison of rotation lenses.
+///
+/// [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+/// [top-level `lens` module documentation]: crate::lens
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct TransformRotateXLens {
+    /// Start value of the rotation angle, in radians.
+    pub start: f32,
+    /// End value of the rotation angle, in radians.
+    pub end: f32,
+}
+
+impl Lens<Transform> for TransformRotateXLens {
+    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
+        let angle = self.start + (self.end - self.start) * ratio;
+        target.rotation = Quat::from_rotation_x(angle);
+    }
+}
+
+/// A lens to rotate a [`Transform`] component around its local Y axis.
+///
+/// This lens interpolates the rotation angle of a [`Transform`] component from
+/// a `start` value to an `end` value, for a rotation around the Y axis. Unlike
+/// [`TransformRotationLens`], it can produce an animation that rotates the entity
+/// any number of turns around its local Y axis.
+///
+/// See the [top-level `lens` module documentation] for a comparison of rotation lenses.
+///
+/// [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+/// [top-level `lens` module documentation]: crate::lens
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct TransformRotateYLens {
+    /// Start value of the rotation angle, in radians.
+    pub start: f32,
+    /// End value of the rotation angle, in radians.
+    pub end: f32,
+}
+
+impl Lens<Transform> for TransformRotateYLens {
+    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
+        let angle = self.start + (self.end - self.start) * ratio;
+        target.rotation = Quat::from_rotation_y(angle);
+    }
+}
+
+/// A lens to rotate a [`Transform`] component around its local Z axis.
+///
+/// This lens interpolates the rotation angle of a [`Transform`] component from
+/// a `start` value to an `end` value, for a rotation around the Z axis. Unlike
+/// [`TransformRotationLens`], it can produce an animation that rotates the entity
+/// any number of turns around its local Z axis.
+///
+/// See the [top-level `lens` module documentation] for a comparison of rotation lenses.
+///
+/// [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+/// [top-level `lens` module documentation]: crate::lens
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct TransformRotateZLens {
+    /// Start value of the rotation angle, in radians.
+    pub start: f32,
+    /// End value of the rotation angle, in radians.
+    pub end: f32,
+}
+
+impl Lens<Transform> for TransformRotateZLens {
+    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
+        let angle = self.start + (self.end - self.start) * ratio;
+        target.rotation = Quat::from_rotation_z(angle);
+    }
+}
+
+/// A lens to rotate a [`Transform`] component around a given fixed axis.
+///
+/// This lens interpolates the rotation angle of a [`Transform`] component from
+/// a `start` value to an `end` value, for a rotation around a given axis. Unlike
+/// [`TransformRotationLens`], it can produce an animation that rotates the entity
+/// any number of turns around that axis.
+///
+/// See the [top-level `lens` module documentation] for a comparison of rotation lenses.
+///
+/// # Panics
+///
+/// This method panics if the `axis` vector is not normalized.
+///
+/// [`Transform`]: https://docs.rs/bevy/0.6.0/bevy/transform/components/struct.Transform.html
+/// [top-level `lens` module documentation]: crate::lens
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct TransformRotateAxisLens {
+    /// The normalized rotation axis.
+    pub axis: Vec3,
+    /// Start value of the rotation angle, in radians.
+    pub start: f32,
+    /// End value of the rotation angle, in radians.
+    pub end: f32,
+}
+
+impl Lens<Transform> for TransformRotateAxisLens {
+    fn lerp(&mut self, target: &mut Transform, ratio: f32) {
+        let angle = self.start + (self.end - self.start) * ratio;
+        target.rotation = Quat::from_axis_angle(self.axis, angle);
     }
 }
 
@@ -196,6 +351,7 @@ impl Lens<Sprite> for SpriteColorLens {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use std::f32::consts::TAU;
 
     #[test]
     fn text_color() {
@@ -272,6 +428,136 @@ mod tests {
         assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
     }
 
+    #[test]
+    fn transform_rotate_x() {
+        let mut lens = TransformRotateXLens {
+            start: 0.,
+            end: 1440_f32.to_radians(), // 4 turns
+        };
+        let mut transform = Transform::default();
+
+        for (index, ratio) in [0., 0.25, 0.5, 0.75, 1.].iter().enumerate() {
+            lens.lerp(&mut transform, *ratio);
+            assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+            if index == 1 || index == 3 {
+                // For odd-numbered turns, the opposite Quat is produced. This is equivalent in
+                // terms of rotation to the IDENTITY one, but numerically the w component is not
+                // the same so would fail an equality test.
+                assert!(transform
+                    .rotation
+                    .abs_diff_eq(Quat::from_xyzw(0., 0., 0., -1.), 1e-5));
+            } else {
+                assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5));
+            }
+            assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+        }
+
+        lens.lerp(&mut transform, 0.1);
+        assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+        assert!(transform
+            .rotation
+            .abs_diff_eq(Quat::from_rotation_x(0.1 * (4. * TAU)), 1e-5));
+        assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+    }
+
+    #[test]
+    fn transform_rotate_y() {
+        let mut lens = TransformRotateYLens {
+            start: 0.,
+            end: 1440_f32.to_radians(), // 4 turns
+        };
+        let mut transform = Transform::default();
+
+        for (index, ratio) in [0., 0.25, 0.5, 0.75, 1.].iter().enumerate() {
+            lens.lerp(&mut transform, *ratio);
+            assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+            if index == 1 || index == 3 {
+                // For odd-numbered turns, the opposite Quat is produced. This is equivalent in
+                // terms of rotation to the IDENTITY one, but numerically the w component is not
+                // the same so would fail an equality test.
+                assert!(transform
+                    .rotation
+                    .abs_diff_eq(Quat::from_xyzw(0., 0., 0., -1.), 1e-5));
+            } else {
+                assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5));
+            }
+            assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+        }
+
+        lens.lerp(&mut transform, 0.1);
+        assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+        assert!(transform
+            .rotation
+            .abs_diff_eq(Quat::from_rotation_y(0.1 * (4. * TAU)), 1e-5));
+        assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+    }
+
+    #[test]
+    fn transform_rotate_z() {
+        let mut lens = TransformRotateZLens {
+            start: 0.,
+            end: 1440_f32.to_radians(), // 4 turns
+        };
+        let mut transform = Transform::default();
+
+        for (index, ratio) in [0., 0.25, 0.5, 0.75, 1.].iter().enumerate() {
+            lens.lerp(&mut transform, *ratio);
+            assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+            if index == 1 || index == 3 {
+                // For odd-numbered turns, the opposite Quat is produced. This is equivalent in
+                // terms of rotation to the IDENTITY one, but numerically the w component is not
+                // the same so would fail an equality test.
+                assert!(transform
+                    .rotation
+                    .abs_diff_eq(Quat::from_xyzw(0., 0., 0., -1.), 1e-5));
+            } else {
+                assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5));
+            }
+            assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+        }
+
+        lens.lerp(&mut transform, 0.1);
+        assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+        assert!(transform
+            .rotation
+            .abs_diff_eq(Quat::from_rotation_z(0.1 * (4. * TAU)), 1e-5));
+        assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+    }
+
+    #[test]
+    fn transform_rotate_axis() {
+        let axis = Vec3::ONE.normalize();
+        let mut lens = TransformRotateAxisLens {
+            axis,
+            start: 0.,
+            end: 1440_f32.to_radians(), // 4 turns
+        };
+        let mut transform = Transform::default();
+
+        for (index, ratio) in [0., 0.25, 0.5, 0.75, 1.].iter().enumerate() {
+            lens.lerp(&mut transform, *ratio);
+            assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+            if index == 1 || index == 3 {
+                // For odd-numbered turns, the opposite Quat is produced. This is equivalent in
+                // terms of rotation to the IDENTITY one, but numerically the w component is not
+                // the same so would fail an equality test.
+                assert!(transform
+                    .rotation
+                    .abs_diff_eq(Quat::from_xyzw(0., 0., 0., -1.), 1e-5));
+            } else {
+                assert!(transform.rotation.abs_diff_eq(Quat::IDENTITY, 1e-5));
+            }
+            assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+        }
+
+        lens.lerp(&mut transform, 0.1);
+        assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5));
+        assert!(transform
+            .rotation
+            .abs_diff_eq(Quat::from_axis_angle(axis, 0.1 * (4. * TAU)), 1e-5));
+        assert!(transform.scale.abs_diff_eq(Vec3::ONE, 1e-5));
+    }
+
     #[test]
     fn transform_scale() {
         let mut lens = TransformScaleLens {