define([], function(){
  //TODO Optimisation memoise (area of valid camera, full result,...) or use a state object

  var zmax = function(area, tanAngle) {
    var m = function(min, max, tanAngle) {
      return (max - min) / (2 * tanAngle);
    };
    return Math.min(m(area.xmin, area.xmax, tanAngle), m(area.ymin, area.ymax, tanAngle));
  };

  /**
   * @param {{x : {Number}, y : {Number}} target
   * @param {Number} distance
   * @param {Camera} camera
   * @param {{xmin : {Number}, xmax : {Number}, ymin : {Number}, ymax : {Number}}} area
   */
  var follow = function(target, distance, camera, area){
    var tanAngle = Math.abs(Math.tan(camera.fov * Math.PI /(180 * 2 ))); // half of the fov
    var z = Math.max(0, Math.min(zmax(area, tanAngle), camera.position.z));
    var margin = z * tanAngle;
    var x = Math.max( area.xmin + margin, Math.min(area.xmax - margin, target.x));
    var y = Math.max( area.ymin + margin, Math.min(area.ymax - margin, target.y));
    camera.position.x = x;
    camera.position.y = y;
    camera.position.z = z;
    camera.lookAt({x : x, y :y, z: 0});
  };
  return follow;
});

@@ -137,32 +137,40 @@
 n(area, tanAngle
+, aspect
 ) %7B%0A    var m = 
@@ -182,16 +182,10 @@
 ion(
-min, max
+lg
 , ta
@@ -211,19 +211,10 @@
 urn 
-(max - min)
+lg
  / (
@@ -261,26 +261,28 @@
 n(m(
+(
 area.xm
-in,
+ax -
  area.xm
 ax, 
@@ -277,18 +277,26 @@
  area.xm
-ax
+in)/aspect
 , tanAng
@@ -306,26 +306,28 @@
 , m(
+(
 area.ym
-in,
+ax -
  area.ym
 ax, 
@@ -322,18 +322,19 @@
  area.ym
-ax
+in)
 , tanAng
@@ -753,16 +753,31 @@
 tanAngle
+, camera.aspect
 ), camer
@@ -800,16 +800,17 @@
     var 
+x
 margin =
@@ -810,16 +810,17 @@
 argin = 
+(
 z * tanA
@@ -823,16 +823,99 @@
 tanAngle
+) * camera.aspect * camera.scale.x;%0A    var ymargin = z * tanAngle * camera.scale.y
 ;%0A    va
@@ -938,24 +938,25 @@
 area.xmin + 
+x
 margin, Math
@@ -968,24 +968,25 @@
 area.xmax - 
+x
 margin, targ
@@ -1027,16 +1027,17 @@
 .ymin + 
+y
 margin, 
@@ -1057,16 +1057,17 @@
 .ymax - 
+y
 margin, 

fix computation of mode2d