diff --git a/ui (gen4)/experiments/scale-origin.html b/ui (gen4)/experiments/scale-origin.html
new file mode 100755
index 00000000..9ada033b
--- /dev/null
+++ b/ui (gen4)/experiments/scale-origin.html	
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui (gen4)/index.html b/ui (gen4)/index.html
index 3b1ed277..37949ede 100755
--- a/ui (gen4)/index.html	
+++ b/ui (gen4)/index.html	
@@ -43,9 +43,9 @@
 
 /* basic animation... */
 .viewer:not(.no-transitions) .ribbon-set {
-	-webkit-transition: all 0.2s ease, transform 0.2s linear;
-	-moz-transition: all 0.2s ease, transform 0.2s linear;
-	transition: all 0.2s ease, transform 0.2s linear;
+	-webkit-transition: all 0.2s ease, transform 0.2s linear/*, transform-origin 0s none*/;
+	-moz-transition: all 0.2s ease, transform 0.2s linear/*, transform-origin 0s none*/;
+	transition: all 0.2s ease, transform 0.2s linear/*, transform-origin 0s none*/;
 }
 
 .viewer:not(.no-transitions) .ribbon {
diff --git a/ui (gen4)/lib/jli.js b/ui (gen4)/lib/jli.js
index b3104555..b8aaf590 100755
--- a/ui (gen4)/lib/jli.js	
+++ b/ui (gen4)/lib/jli.js	
@@ -509,6 +509,19 @@ function makeCSSVendorAttrGetter(attr, dfl, callback){
 }
 
 
+
+var getElementOrigin = makeCSSVendorAttrGetter(
+		'transformOrigin',
+		{top: 0, left: 0},
+		function(data){
+			res = /([0-9.]*(px|%)) ([0-9.]*(px|%))/.exec(data)
+			return {
+				left: res[1].slice(-2) == 'px' ? parseFloat(res[1]) : res[1],
+				top: res[3].slice(-2) == 'px' ? parseFloat(res[3]) : res[3],
+			}
+		})
+
+
 // Return a scale value for the given element(s).
 // NOTE: this will only return a single scale value...
 var getElementScale = makeCSSVendorAttrGetter(
@@ -519,7 +532,7 @@ var getElementScale = makeCSSVendorAttrGetter(
 		})
 
 
-var getElementShift = makeCSSVendorAttrGetter(
+var getElementOffset = makeCSSVendorAttrGetter(
 		'transform',
 		{left: 0, top: 0},
 		function(data){
@@ -544,7 +557,7 @@ function setElementTransform(elem, offset, scale, duration){
 	var t3d = USE_3D_TRANSFORM ? 'translate3d(0,0,0)' : ''
 
 	if(offset == null){
-		offset = getElementShift(elem)
+		offset = getElementOffset(elem)
 	// number -- only the x coord...
 	} else if(typeof(offset) == typeof(1)){
 		offset = {
@@ -686,7 +699,7 @@ function animateElementTo(elem, to, duration, easing, speed, callback, use_trans
 
 		var start = Date.now()
 		var then = start + duration
-		var from = getElementShift(elem)
+		var from = getElementOffset(elem)
 		var cur = {
 			top: from.top,
 			left: from.left
@@ -789,6 +802,11 @@ function stopAnimation(elem){
 
 
 // XXX account for other transitions...
+function setElementOffset(elem, l, t){
+	return setElementTransform(elem, [l, t])
+}
+
+
 function setElementScale(elem, scale){
 	return setElementTransform(elem, null, scale)
 }
@@ -802,11 +820,30 @@ function setElementOrigin(elem, x, y, z){
 
 	return $(elem).css({
 		'transform-origin': value, 
+		'-o-transform-origin':  value,
 		'-ms-transform-origin':  value,
+		'-moz-transform-origin':  value,
 		'-webkit-transform-origin':  value,
 	})
 }
 
+// this is like setElementOrigin(..) but will compensate for element 
+// shift when scaled...
+// NOTE: this will work only of translate is used for positioning...
+function shiftOriginTo(elem, l, t){
+	var o = getElementOrigin(elem)
+	var scale = getElementScale(elem)
+	var offset = getElementOffset(elem)
+
+	// calculate the offset change and compensate...
+	var cl = offset.left + ((o.left - o.left*scale) - (l - l*scale))
+	var ct = offset.top + ((o.top - o.top*scale) - (t - t*scale))
+
+	setElementOffset(elem, cl, ct)
+
+	return setElementOrigin(elem, l+'px', t+'px')
+}
+
 
 function setTransitionEasing(elem, ease){
 	if(typeof(ms) == typeof(0)){
diff --git a/ui (gen4)/ribbons.js b/ui (gen4)/ribbons.js
index a23b897c..2f270e8d 100755
--- a/ui (gen4)/ribbons.js	
+++ b/ui (gen4)/ribbons.js	
@@ -256,25 +256,123 @@ module.RibbonsPrototype = {
 	// 			- use translate for placement of the .ribbon-set (prefered)
 	// 			- use an extra eleemnt for positioning and keep the 
 	// 			  .ribbon-set at (0,0)
+	//
+	// XXX do we account vor viewer offset???
 	setScale: function(scale, t, l){
 		var ribbon_set = this.viewer.find('.ribbon-set')
 
-		var s = this.getScale()
+		var img = t == null ? this.getImage() : t
 
-		if(t == null){
-			var img = this.getImage()
-			t = img.offset()
-			l = t.left + (img.width()/s)/2
-			t = t.top + (img.height()/s)/2
+		// XXX need to make this sync and not animate...
+		this.setOrigin(img)
+
+		setElementScale(ribbon_set, scale)
+		return this
+	},
+
+	getOrigin: function(){
+		return getElementOrigin(this.viewer.find('.ribbon-set'))
+	},
+	// Set ribbon set origin...
+	//
+	//	Set origin to center of current image
+	//	.setOrigin()
+	//		-> ribbons
+	//
+	//	Set origin to center of elment:
+	//	.setOrigin(elem)
+	//		-> ribbons
+	//
+	//	Set origin to screen coordinates:
+	//	.setOrigin(x, y)
+	//		-> ribbons
+	//
+	// XXX this appears not to be scale-neutral -- it gets a different 
+	// 		set of numbers in ribbons >0 after doing .centerRibbon(..)
+	// 		...but before calling .centerRibbon(..) this does everything
+	// 		quite correctly...
+	//
+	// 		...this mutual dependency between this and .centerRibbon(..)
+	// 		makes it really hards to find where exactly the problem is...
+	//
+	// XXX should this also update offset????
+	/*
+	setOrigin: function(a, b){
+		var s = this.getScale()
+		var ribbon_set = this.viewer.find('.ribbon-set')
+
+		if(typeof(a) == typeof(123) && typeof(b) == typeof(123)){
+			var t = a
+			var l = b
+
+		} else {
+			if(a == null){
+				var img = this.getImage()
+			} else {
+				var img = this.getImage(a)
+			}
+			var io = img.offset()
+			var vo = this.viewer.offset()
+
+			// get distance from center of image to top left corner of 
+			// screen...
+			// NOTE: the result should be scale-neutral.
+			var l = (io.left - vo.left) + (img.width()*s)/2
+			var t = (io.top - vo.top) + (img.height()*s)/2
 		}
 
-		var ro = ribbon_set.offset()
+		var rs = getElementOffset(ribbon_set)
+
+		var ot = t - rs.top
+		var ol = l - rs.left
+
+		var ro = this.getOrigin()
+
+		console.log('### origin:', ol, ot)
 
-		var ot = t - ro.top
-		var ol = l - ro.left
 		setElementOrigin(ribbon_set, ol+'px', ot+'px')
-			
-		setElementScale(ribbon_set, scale)
+
+		//setElementOffset(ribbon_set,
+		//	rs.left + (ro.left - ro.left*s) - (l - l*s),
+		//	rs.top + (ro.top - ro.top*s) - (t - t*s))
+
+		return this
+	},
+	*/
+	setOrigin: function(a, b){
+		var ribbon_set = this.viewer.find('.ribbon-set')
+
+		if(typeof(a) == typeof(123) && typeof(b) == typeof(123)){
+			var t = a
+			var l = b
+
+		} else {
+			if(a == null){
+				var img = this.getImage()
+			} else {
+				var img = this.getImage(a)
+			}
+
+			var s = this.getScale()
+			var io = img.offset()
+			var vo = this.viewer.offset()
+
+			// get distance from center of image to top left corner of 
+			// screen...
+			// NOTE: the result should be scale-neutral.
+			var l = (io.left - vo.left) + (img.width()*s)/2
+			var t = (io.top - vo.top) + (img.height()*s)/2
+		}
+
+		var rs = getElementOffset(ribbon_set)
+
+		var ot = t - rs.top
+		var ol = l - rs.left
+
+		console.log('### origin:', ol, ot)
+
+		shiftOriginTo(ribbon_set, ol, ot)
+
 		return this
 	},
 
@@ -1309,6 +1407,8 @@ module.RibbonsPrototype = {
 	// 		implicitly (i.e. the default)
 	// NOTE: this will get absolute results relative to screen, view 
 	// 		scaling will have no effect...
+	//
+	// XXX split this in two...(???)
 	_getOffset: function(target, vertical, horizontal, image_offset, scale){
 		vertical = vertical == null ? 'center' : vertical
 		horizontal = horizontal == null ? 'center' : horizontal
@@ -1333,8 +1433,12 @@ module.RibbonsPrototype = {
 		var rl = ribbon.offset().left
 		var rst = ribbon_set.offset().top
 
-		var W = viewer.width()
-		var H = viewer.height()
+		// NOTE: not quite sure why need to multiply this by scale but
+		// 		without it this does not work with origin/translate but 
+		// 		does fine with top/left offsets...
+		var W = viewer.width() * scale
+		var H = viewer.height() * scale
+
 		var w = image.width() * scale
 		var h = image.height() * scale
 
@@ -1368,15 +1472,25 @@ module.RibbonsPrototype = {
 	// center a ribbon vertically...
 	// 
 	centerRibbon: function(target, offset, scale){
-		offset = offset == null 
-			? this._getOffset(target, null, null, null, scale) 
-			: offset
+		scale = scale == null ? this.getScale() : scale
+		// NOTE: when woring with origin we do not care about scale...
+		//scale = scale == null ? 1 : scale
 
-		// vertical offset...
-		this.viewer.find('.ribbon-set')
-			.css({
-				top: offset.top,
-			})
+		offset = offset == null 
+			// XXX this should not get affected by scale or origin...
+			// XXX this gives correct resolts ONLY when we got scaled when
+			// 		focused on ribbon 0, in other cases it's messed up...
+			? this._getOffset(target, null, null, null, 1).top
+			: offset.top
+
+		var ot = this.getOrigin().top
+		// XXX something is still missing here...
+		// 		...it's getting closer when enlarging and blows up when scale -> 0
+		offset -= (ot/scale - ot)
+
+		console.log('### offset-top:', offset)
+
+		setElementOffset(this.viewer.find('.ribbon-set'), 0, offset)
 
 		return this
 	},
@@ -1384,6 +1498,7 @@ module.RibbonsPrototype = {
 	// 
 	centerImage: function(target, mode, offset, scale){
 		scale = scale == null ? this.getScale() : scale
+	
 		offset = offset == null 
 			? this._getOffset(target, 'center', 'center', mode, scale) 
 			: offset
diff --git a/ui (gen4)/ui.js b/ui (gen4)/ui.js
index 77e508bc..63abe0d6 100755
--- a/ui (gen4)/ui.js	
+++ b/ui (gen4)/ui.js	
@@ -142,6 +142,10 @@ module.GLOBAL_KEYBOARD = {
 		'#3': function(){ a.fitThree() },
 		'#4': function(){ a.fitFour() },
 		'#5': function(){ a.fitFive() },
+		'#6': function(){ a.fitSix() },
+		'#7': function(){ a.fitSeven() },
+		'#8': function(){ a.fitEight() },
+		'#9': function(){ a.fitNine() },
 		
 
 	},