diff --git a/Nasal/view.nas b/Nasal/view.nas
index 8decf1d24..9d7b8094b 100644
--- a/Nasal/view.nas
+++ b/Nasal/view.nas
@@ -192,7 +192,7 @@ var manager = {
 	},
 	register : func(which, handler = nil) {
 		if (num(which) == nil)
-			which = view.indexof(which);
+			which = indexof(which);
 		if (handler == nil)
 			handler = default_handler;
 		me.views[which]["handler"] = handler;
@@ -204,7 +204,7 @@ var manager = {
 		if (which == nil)
 			which = index;
 		elsif (num(which) == nil)
-			which = view.indexof(which);
+			which = indexof(which);
 
 		me.loopid += 1;
 		if (contains(me.current.handler, "stop"))
@@ -303,7 +303,7 @@ var fly_by_view_handler = {
 		me.latN.setValue(lat);
 		me.lonN.setValue(lon);
 		me.altN.setValue(alt * geo.M2FT);
-		return 9.3;
+		return 8.3;
 	},
 	update : func {
 		return me.setpos();
@@ -311,6 +311,69 @@ var fly_by_view_handler = {
 };
 
 
+var pilot_view_limiter = {
+	init : func {
+		me.hdgN = props.globals.getNode("/sim/current-view/heading-offset-deg");
+		me.xoffsetN = props.globals.getNode("/sim/current-view/x-offset-m");
+		me.xoffset_lowpass = aircraft.lowpass.new(0.1);
+		me.old_offset = 0;
+	},
+	start : func {
+		var limits = current.getNode("config/limits", 1);
+		me.heading_min = limits.getNode("heading-min-deg", 1).getValue();
+		me.heading_max = limits.getNode("heading-max-deg", 1).getValue();
+		me.max_xoffset = limits.getNode("x-offset-max-m", 1).getValue() or 0;
+		me.threshold_min = limits.getNode("x-offset-heading-min-deg", 1).getValue() or 0;
+		me.threshold_max = limits.getNode("x-offset-heading-max-deg", 1).getValue() or 0;
+
+		if (me.heading_max == nil)
+			me.heading_max = 1000;
+		if (me.heading_min == nil)
+			me.heading_min = -1000;
+	},
+	update : func {
+		var hdg = normdeg(me.hdgN.getValue());
+
+		if (hdg > me.heading_max)
+			me.hdgN.setDoubleValue(hdg = me.heading_max);
+		elsif (hdg < me.heading_min)
+			me.hdgN.setDoubleValue(hdg = me.heading_min);
+
+		# translate view on X axis to look far right or far left
+		if (me.max_xoffset) {
+			var norm = 0;
+			if (hdg <= me.threshold_min)
+				norm = (hdg - me.threshold_min) / (me.heading_min - me.threshold_min);
+			elsif (hdg >= me.threshold_max)
+				norm = -(hdg - me.threshold_max) / (me.heading_max - me.threshold_max);
+
+			var new_offset = me.xoffset_lowpass.filter(norm * me.max_xoffset);
+			me.xoffsetN.setDoubleValue(me.xoffsetN.getValue() - me.old_offset + new_offset);
+			me.old_offset = new_offset;
+		}
+		return 0;
+	},
+};
+
+
+var panViewDir = func(step) {	# FIXME overrides panViewDir function from above; needs better integration
+	if (getprop("/sim/freeze/master"))
+		var prop = "/sim/current-view/heading-offset-deg";
+	else
+		var prop = "/sim/current-view/goal-heading-offset-deg";
+	var viewVal = getprop(prop);
+	var delta = step * VIEW_PAN_RATE * getprop("/sim/time/delta-realtime-sec");
+	var viewValSlew = normdeg(viewVal + delta);
+	var headingMax = current.getNode("config/limits/heading-max-deg", 1).getValue() or 1000;
+	var headingMin = current.getNode("config/limits/heading-min-deg", 1).getValue() or -1000;
+	if (viewValSlew > headingMax)
+		viewValSlew = headingMax;
+	elsif (viewValSlew < headingMin)
+		viewValSlew = headingMin;
+	setprop(prop, viewValSlew);
+}
+
+
 #------------------------------------------------------------------------------
 #
 # Saves/restores/moves the view point (position, orientation, field-of-view).
@@ -485,6 +548,18 @@ _setlistener("/sim/signals/fdm-initialized", func {
 
 	manager.init();
 	manager.register("Fly-By View", fly_by_view_handler);
+
+	forindex (var i; views) {
+		var limits = views[i].getNode("config/limits/enabled");
+		if (limits != nil) {
+			func (index) {
+				setlistener(limits, func(n) {
+					manager.register(index, n.getValue() ? pilot_view_limiter : nil);
+					manager.set_view();
+				}, 1);
+			}(i);
+		}
+	}
 });
 
 
diff --git a/preferences.xml b/preferences.xml
index d23d07362..9916e5668 100644
--- a/preferences.xml
+++ b/preferences.xml
@@ -282,6 +282,14 @@ Started September 2000 by David Megginson, david@megginson.com
       <right-direction-deg type="double">270</right-direction-deg>
       <front-right-direction-deg type="double">315</front-right-direction-deg>
       <dynamic-view type="bool">true</dynamic-view>
+      <limits>
+        <enabled type="bool">false</enabled>
+        <heading-min-deg type="double">-140</heading-min-deg>
+        <heading-max-deg type="double">140</heading-max-deg>
+        <x-offset-max-m type="double">0.15</x-offset-max-m>
+        <x-offset-heading-min-deg type="double">-65</x-offset-heading-min-deg>
+        <x-offset-heading-max-deg type="double">65</x-offset-heading-max-deg>
+      </limits>
     </config>
   </view>