         // animations to behave properly
         // TODO: some better way to abstract this. If a value below changes it
         //       needs to change here as well
-        let viewIndex = itemViews.indexOf(view)!
-        let nextViewXPoint = viewPositions[view]!.x + offset
-        rootOffset = (2.5 * log2(nextViewXPoint)) * 10 + (CGFloat(viewIndex) * 50)
+        if let view = view {
+            // TODO: clean this up
+            let viewIndex = itemViews.indexOf(view)!
+            let nextViewXPoint = max(0, viewPositions[view]!.x + offset)
+            let v: CGFloat = nextViewXPoint == 0 ? 0 : log2(nextViewXPoint)
+            absoluteOffset = (25 * v) + (CGFloat(viewIndex) * 50)
+            
+            print("nextViewXPoint: \(nextViewXPoint), view index: \(viewIndex), absOffset: \(absoluteOffset)")
+        }
+        else {
+            absoluteOffset += offset
+        }
+
+        let nextViewXPoint = bounds.midX
+        let v: CGFloat = nextViewXPoint == 0 ? 0 : log2(nextViewXPoint)
+        let lastAbsoluteOffset = (25 * v) + (CGFloat(itemViews.count - 1) * 50)
+        
+        absoluteOffset = min(lastAbsoluteOffset, absoluteOffset)
         
         for (index, itemView) in itemViews.enumerate() {
             var transform = CATransform3DIdentity

    private var itemViews: [UIView] = []
    // TODO: clean up property names here
    private var transformView = TransformView()
    private var rootOffset = CGFloat(0)
    private var viewPositions: [UIView: Point3D] = [:]
    
    var decelerateDisplayLinkProgressor: DisplayLinkProgressor?

        layoutItemViews()
    }
    
    // TODO: change name now that view can be nil
    private func viewDidPanHorizontally(view: UIView?, byOffset offset: CGFloat) {
        // TODO: clean this up
        
        // Calculate the new x origin point for the view that was panned.
