diff --git a/layout-iscroll2.html b/layout-iscroll2.html
index ff6a93f..0c6ad2a 100755
--- a/layout-iscroll2.html
+++ b/layout-iscroll2.html
@@ -100,6 +100,9 @@ $(document).ready(function(){
 					'default': nextPage,								//	Space
 					'shift': prevPage									//	shift-Space
 				},
+				// combined navigation with actions..
+				38: function(){togglePageView()},						//	Up
+				40: function(){togglePageView()},						//	Down
 
 				70: function(){											//	F
 					togglePageFitMode()
@@ -137,112 +140,6 @@ $(document).ready(function(){
 	//limit_scroll()
 })
 
-function makeScrollHandler(root, callback){
-
-	// local data...
-	var scrolling = false
-	var touch = false
-	var touches = 0
-	var start
-	var prev_x
-	var prev_t
-	var shift
-	var scale
-	var x
-	var t
-	var dx
-	var dt
-
-	function startMoveHandler(evt, callback){
-		prev_t = event.timeStamp || Date.now();
-		if(event.touches != null){
-			touch = true
-		}
-		scrolling = true
-		scroller.state = 'scrolling'
-		//root.trigger('userScrollStart')
-		//togglePageDragging('on')
-		shift = getMagazineShift()
-		scale = getMagazineScale()
-		// get the user coords...
-		prev_x = touch ? event.touches[0].pageX : evt.clientX
-		start = prev_x
-
-		return false
-	}
-	// XXX add limits to this...
-	// XXX try and make this adaptive to stay ahead of the lags...
-	function moveHandler(evt){
-		evt.preventDefault()
-		t = event.timeStamp || Date.now();
-		// get the user coords...
-		x = touch ? event.touches[0].pageX : evt.clientX
-		touches = touch ? event.touches.length : 0
-		if(scrolling){
-			shift += x - prev_x
-			shiftMagazineTo(shift, scale)
-		}
-		dx = x - prev_x
-		dt = t - prev_t
-		prev_t = t
-		prev_x = x
-		//root.trigger('userScroll')
-	}
-	function endMoveHandler(evt){
-		x = touch ? event.changedTouches[0].pageX : evt.clientX
-		touch = false
-		scrolling = false
-		scroller.state = 'waiting'
-		touches = 0
-		//togglePageDragging('off')
-		// XXX add speed to this...
-		//root.trigger('userScrollEnd')
-		callback && callback(dx/dt, start - x)
-	}
-
-	var scroller = {
-		start: function(){
-			this.state = 'waiting'
-			// XXX STUB: this makes starting the scroll a bit sluggish, 
-			//		find a faster way...
-			togglePageDragging('on')
-
-			// NOTE: if we bind both touch and mouse events, on touch devices they 
-			//		might start interfering with each other...
-			if('ontouchmove' in window){
-				root
-					.on('touchstart', startMoveHandler)
-					.on('touchmove', moveHandler) 
-					.on('touchend', endMoveHandler)
-			} else {
-				root
-					.on('mousedown', startMoveHandler) 
-					.on('mousemove', moveHandler) 
-					.on('mouseup', endMoveHandler) 
-			}
-			return this
-		},
-		stop: function(){
-			this.state = 'stopped'
-			if('ontouchmove' in window){
-				root
-					.off('touchstart', startMoveHandler)
-					.off('touchmove', moveHandler) 
-					.off('touchend', endMoveHandler)
-			} else {
-				root
-					.off('mousedown', startMoveHandler) 
-					.off('mousemove', moveHandler) 
-					.off('mouseup', endMoveHandler) 
-			}
-			return this
-		},
-		// NOTE: this is updated live but not used by the system in any way...
-		state: 'stopped'
-	}
-	return scroller
-}
-
 
 var SCROLL_LIMIT = 800 * 1.5
 
diff --git a/layout.js b/layout.js
index dc6a448..909747a 100755
--- a/layout.js
+++ b/layout.js
@@ -76,8 +76,159 @@ var togglePageView = createCSSClassToggler(
 
 
 
+/************************************************** event handlers ***/
+
+function makeScrollHandler(root, callback){
+
+	// local data...
+	var scrolling = false
+	var touch = false
+	var touches = 0
+	var start
+	var prev_x
+	var prev_t
+	var shift
+	var scale
+	var x
+	var t
+	var dx
+	var dt
+
+	function startMoveHandler(evt, callback){
+		prev_t = event.timeStamp || Date.now();
+		setTransitionDuration($('.magazine'), 0)
+		if(event.touches != null){
+			touch = true
+		}
+		scrolling = true
+		scroller.state = 'scrolling'
+		//root.trigger('userScrollStart')
+		//togglePageDragging('on')
+		shift = getMagazineShift()
+		scale = getMagazineScale()
+		// get the user coords...
+		prev_x = touch ? event.touches[0].pageX : evt.clientX
+		start = prev_x
+
+		return false
+	}
+	// XXX add limits to this...
+	// XXX try and make this adaptive to stay ahead of the lags...
+	function moveHandler(evt){
+		evt.preventDefault()
+		t = event.timeStamp || Date.now();
+		// get the user coords...
+		x = touch ? event.touches[0].pageX : evt.clientX
+		touches = touch ? event.touches.length : 0
+		if(scrolling){
+			shift += x - prev_x
+			setElementTransform($('.magazine'), shift, scale)
+		}
+		dx = x - prev_x
+		dt = t - prev_t
+		prev_t = t
+		prev_x = x
+		//root.trigger('userScroll')
+
+		return false
+	}
+	function endMoveHandler(evt){
+		// XXX get real transition duration...
+		setTransitionDuration($('.magazine'), 200)
+		x = touch ? event.changedTouches[0].pageX : evt.clientX
+		touch = false
+		scrolling = false
+		scroller.state = 'waiting'
+		touches = 0
+		//togglePageDragging('off')
+		// XXX add speed to this...
+		//root.trigger('userScrollEnd')
+		callback && callback(dx/dt, start - x)
+
+		return false
+	}
+
+	var scroller = {
+		start: function(){
+			this.state = 'waiting'
+			// XXX STUB: this makes starting the scroll a bit sluggish, 
+			//		find a faster way...
+			//togglePageDragging('on')
+
+			// NOTE: if we bind both touch and mouse events, on touch devices they 
+			//		might start interfering with each other...
+			if('ontouchmove' in window){
+				root
+					.on('touchstart', startMoveHandler)
+					.on('touchmove', moveHandler) 
+					.on('touchend', endMoveHandler)
+			} else {
+				root
+					.on('mousedown', startMoveHandler) 
+					.on('mousemove', moveHandler) 
+					.on('mouseup', endMoveHandler) 
+			}
+			return this
+		},
+		stop: function(){
+			this.state = 'stopped'
+			if('ontouchmove' in window){
+				root
+					.off('touchstart', startMoveHandler)
+					.off('touchmove', moveHandler) 
+					.off('touchend', endMoveHandler)
+			} else {
+				root
+					.off('mousedown', startMoveHandler) 
+					.off('mousemove', moveHandler) 
+					.off('mouseup', endMoveHandler) 
+			}
+			return this
+		},
+		// NOTE: this is updated live but not used by the system in any way...
+		state: 'stopped'
+	}
+	return scroller
+}
+
+
+
 /********************************************************* helpers ***/
 
+// XXX there is something here that depends on scale that is either not 
+// 		compensated, or is over compensated...
+function getMagazineOffset(page, scale, align){
+	if(page == null){
+		page = $('.current.page')
+	}
+	if(scale == null){
+		scale = getMagazineScale()
+	}
+	if(align == null){
+		align = getPageAlign(page)
+	}
+	var mag = $('.magazine')
+
+	// calculate the align offset...
+	if(align == 'left'){
+		var offset = 0
+
+	} else if(align == 'right'){
+		var offset = $('.viewer').width() - page.width()*scale
+
+	// center (default)
+	} else {
+		var offset = $('.viewer').width()/2 - (page.width()/2)*scale
+	}
+
+	var w = mag.outerWidth(true)
+	// XXX this depends on scale...
+	var pos = page.position().left//*scale
+
+	return -((w - w*scale)/2 + pos) + offset
+}
+
+
 // XXX make this work for narrow and left/right alligned pages...
 function getPageNumber(page){
 	// a page is given...
@@ -100,12 +251,10 @@ function getPageNumber(page){
 		var res = $('.page').map(function(i, e){
 			e = $(e)
 			var l = e.position().left
-			//var l = e.offset().left
 			var w = e.width()*scale
-			//return Math.abs((l+(w/2)) - (s+(W/2)))
 			return Math.abs((l+(w/2)) - (o+(W/2)))
-		})
-		cur = res.index(Math.min.apply(Math, res))
+		}).toArray()
+		cur = res.indexOf(Math.min.apply(Math, res))
 		return cur
 	}
 }
@@ -116,16 +265,11 @@ function getMagazineScale(){
 }
 function setMagazineScale(scale){
 	var mag = $('.magazine')
-	// NOTE: we are updating margins to make the scroll area adapt to new scale...
-	var w = mag.width()
-	var m = -(w - (w*scale))/2 + $('.viewer').width()/2
-	mag.css({
-		'margin-left': m,
-		'margin-right': m
-		// XXX also add margins at top and bottom for vertical elements...
-	})
-	setElementScale(mag, scale)
-	//setCurrentPage()
+	var cur = $('.current.page')
+
+	var left = getMagazineOffset(cur, scale, 'center')
+
+	setElementTransform(mag, left, scale)
 }
 
 
@@ -141,26 +285,16 @@ function setCurrentPage(n){
 	n = n < 0 ? l - n : n
 	n = n < -l ? 0 : n
 	n = n >= l ? l - 1 : n
+
 	$('.current.page').removeClass('current')
 	$($('.page')[n]).addClass('current')
+
 	var cur = $('.current.page')
-	if(USE_PAGE_ALIGN
-			&& $('.page').width()*2*scale > $('.viewer').width()){
-		var align = getPageAlign()
-	} else {
-		var align = 'center'
-	}
-	if(align == 'left'){
-		var offset = 0
-	} else if(align == 'right'){
-		var offset = $('.viewer').width() - cur.width()*scale
-	} else {
-		var offset = $('.viewer').width()/2 - (cur.width()/2)*scale
-	}
-	cur.ScrollTo({
-		offsetTop: $('.viewer').height()/2 - (cur.height()/2)*scale,
-		offsetLeft: offset
-	})
+
+	var left = getMagazineOffset(cur)
+
+	setElementTransform($('.magazine'), left, scale)
+
 	return cur
 }
 
diff --git a/lib/jli.js b/lib/jli.js
index 33194bf..8d9f19e 100755
--- a/lib/jli.js
+++ b/lib/jli.js
@@ -194,6 +194,44 @@ function unanimated(obj, func, time){
 
 
 
+// NOTE: at this point this works only on the X axis...
+function setElementTransform(elem, offset, scale){
+	if(offset == null){
+		var offset = getElementShift(elem).left
+	}
+	if(scale == null){
+		var scale = getElementScale(elem)
+	}
+	if(USE_TRANSFORM){
+		var transform = 'translate('+ offset +'px, 0px) scale('+ scale +') translateZ(0px)'
+		elem.css({
+			'-ms-transform' : transform, 
+			'-webkit-transform' : transform, 
+			'-moz-transform' : transform, 
+			'-o-transform' : transform, 
+			'transform' : transform, 
+
+			// XXX can we avoid this here?? 
+			left: 0
+		})
+	} else {
+		var transform = 'translate(0px, 0px) scale('+ scale +') translateZ(0px)'
+		elem.css({
+			// NOTE: this will be wrong during a transition, that's why we 
+			// 		can pass the pre-calculated offset as an argument...
+			left: offset,
+
+			// XXX can we avoid this here?? 
+			'-ms-transform' : transform, 
+			'-webkit-transform' : transform, 
+			'-moz-transform' : transform, 
+			'-o-transform' : transform, 
+			'transform' : transform, 
+		})
+	}
+	return elem
+}
+
 // Return a scale value for the given element(s).
 // NOTE: this will only return a single scale value...
 function getElementScale(elem){
@@ -220,14 +258,43 @@ function getElementScale(elem){
 	return parseFloat((/(scale|matrix)\(([^,]*),.*\)/).exec(transform)[2])
 }
 
+// XXX account for other transitions...
 function setElementScale(elem, scale){
-	return elem.css({
-		'transform': 'scale('+scale+')',
-		'-moz-transform': 'scale('+scale+')',
-		'-o-transform': 'scale('+scale+')',
-		'-ms-transform': 'scale('+scale+')',
-		'-webkit-transform': 'scale('+scale+')',
-	})
+	return setElementTransform(elem, null, scale)
+}
+
+function getElementShift(elem){
+	elem = $(elem)
+	// using transform...
+	if(USE_TRANSFORM){
+		var vendors = ['o', 'moz', 'ms', 'webkit']
+		var transform = elem.css('transform')
+		var res
+
+		// go through vendor prefixes... (hate this!)
+		if(!transform || transform == 'none'){
+			for(var i in vendors){
+				transform = elem.css('-' + vendors[i] + '-transform')
+				if(transform && transform != 'none'){
+					break
+				}
+			}
+		}
+		// no transform is set...
+		if(!transform || transform == 'none'){
+			return {left: 0, top: 0}
+		}
+		return {
+			left: parseFloat(/(translate\(|matrix\([^,]*,[^,]*,[^,]*,[^,]*,)([^,]*),/.exec(transform)[2]),
+			top: null
+		}
+	// using left...
+	} else {
+		return {
+			left: elem.position().left,
+			top: null
+		}
+	}
 }
 
 
diff --git a/magazine.js b/magazine.js
index a4f12ec..707d001 100755
--- a/magazine.js
+++ b/magazine.js
@@ -192,7 +192,7 @@ function getPageScale(){
 	return getElementScale($('.scaler'))
 }
 function setPageScale(scale){
-	return setElementScale($('.scaler'), scale)
+	return setElementTransform($('.scaler'), null, scale)
 }
 
 
@@ -216,75 +216,11 @@ function getPageAt(n){
 	return $(page[n])
 }
 
-// NOTE: at this point this works only on the X axis...
-function shiftMagazineTo(offset, scale){
-	var mag = $('.magazine')
-	if(scale == null){
-		var scale = getElementScale(mag)
-	}
-	if(USE_TRANSFORM){
-		var transform = 'translate('+ offset +'px, 0px) scale('+ scale +') translateZ(0px)'
-		mag.css({
-			'-ms-transform' : transform, 
-			'-webkit-transform' : transform, 
-			'-moz-transform' : transform, 
-			'-o-transform' : transform, 
-			'transform' : transform, 
-
-			// XXX can we avoid this here?? 
-			left: 0,
-		})
-	} else {
-		var transform = 'translate(0px, 0px) scale('+ scale +') translateZ(0px)'
-		mag.css({
-			// NOTE: this will be wrong during a transition, that's why we 
-			// 		can pass the pre-calculated offset as an argument...
-			left: offset,
-
-			// XXX can we avoid this here?? 
-			'-ms-transform' : transform, 
-			'-webkit-transform' : transform, 
-			'-moz-transform' : transform, 
-			'-o-transform' : transform, 
-			'transform' : transform, 
-		})
-	}
+function shiftMagazineTo(offset){
+	setElementTransform($('.magazine'), offset)
 }
+
 // XXX this is almost the same as getElementScale...
-function getElementShift(elem){
-	elem = $(elem)
-	// using transform...
-	if(USE_TRANSFORM){
-		var vendors = ['o', 'moz', 'ms', 'webkit']
-		var transform = elem.css('transform')
-		var res
-
-		// go through vendor prefixes... (hate this!)
-		if(!transform || transform == 'none'){
-			for(var i in vendors){
-				transform = elem.css('-' + vendors[i] + '-transform')
-				if(transform && transform != 'none'){
-					break
-				}
-			}
-		}
-		// no transform is set...
-		if(!transform || transform == 'none'){
-			return {left: 0, top: 0}
-		}
-		return {
-			left: parseFloat(/(translate\(|matrix\([^,]*,[^,]*,[^,]*,[^,]*,)([^,]*),/.exec(transform)[2]),
-			top: null
-		}
-	// using left...
-	} else {
-		return {
-			left: elem.position().left,
-			top: null
-		}
-	}
-}
-
 function getMagazineShift(){
 	return getElementShift($('.magazine')).left
 }