diff --git a/examples/libraries/overlayManager.js b/examples/libraries/overlayManager.js
new file mode 100644
index 0000000000..55575badee
--- /dev/null
+++ b/examples/libraries/overlayManager.js
@@ -0,0 +1,451 @@
+//
+//  overlayManager.js
+//  examples/libraries
+//
+//  Created by Zander Otavka on 7/24/15
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.
+//  Instead of:
+//
+//      var billboard = Overlays.addOverlay("billboard", { visible: false });
+//      ...
+//      Overlays.editOverlay(billboard, { visible: true });
+//      ...
+//      Overlays.deleteOverlay(billboard);
+//
+//  You can now do:
+//
+//      var billboard = new BillboardOverlay({ visible: false });
+//      ...
+//      billboard.visible = true;
+//      ...
+//      billboard.destroy();
+//
+//  See more on usage below.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+
+(function() {
+    // Delete `Overlays` from the global scope.
+    var Overlays = this.Overlays;
+    delete this.Overlays;
+
+    var overlays = {};
+    var panels = {};
+
+    var overlayTypes;
+    var Overlay, Overlay2D, Base3DOverlay, Planar3DOverlay, Volume3DOverlay;
+
+
+    //
+    //  Create a new JavaScript object for an overlay of given ID.
+    //
+    function makeOverlayFromId(id) {
+        var type = Overlays.getOverlayType(id);
+        if (!type) {
+            return null;
+        }
+        var overlay = new overlayTypes[type]();
+        overlay._id = id;
+        var panelID = Overlays.getAttachedPanel(id)
+        if (panelID && panelID in panels) {
+            panels[panelID].addChild(overlay);
+        }
+        overlays[id] = overlay;
+        return overlay;
+    }
+
+    //
+    //  Get or create an overlay object from the id.
+    //
+    //  @param knownOverlaysOnly (Optional: Boolean)
+    //      If true, a new object will not be created.
+    //  @param searchList (Optional: Object)
+    //      Map of overlay id's and overlay objects.  Can be generated with
+    //      `OverlayManager.makeSearchList`.
+    //
+    function findOverlay(id, knownOverlaysOnly, searchList) {
+        if (id > 0) {
+            knownOverlaysOnly = Boolean(knownOverlaysOnly) || Boolean(searchList);
+            searchList = searchList || overlays;
+            var foundOverlay = searchList[id];
+            if (foundOverlay) {
+                return foundOverlay;
+            }
+            if (!knownOverlaysOnly) {
+                return makeOverlayFromId(id);
+            }
+        }
+        return null;
+    }
+
+
+    //
+    //  Perform global scoped operations on overlays, such as finding by ray intersection.
+    //
+    OverlayManager = {
+        findOnRay: function(pickRay, knownOverlaysOnly, searchList) {
+            var rayPickResult = Overlays.findRayIntersection(pickRay);
+            print("raypick " + rayPickResult.overlayID);
+            if (rayPickResult.intersects) {
+                return findOverlay(rayPickResult.overlayID, knownOverlaysOnly, searchList);
+            }
+            return null;
+        },
+        findAtPoint: function(point, knownOverlaysOnly, searchList) {
+            var foundID = Overlays.getOverlayAtPoint(point);
+            print("at point " + foundID);
+            if (foundID) {
+                return findOverlay(foundID, knownOverlaysOnly, searchList);
+            } else {
+                var pickRay = Camera.computePickRay(point.x, point.y);
+                return OverlayManager.findOnRay(pickRay, knownOverlaysOnly, searchList);
+            }
+        },
+        makeSearchList: function(overlayArray) {
+            var searchList = {};
+            overlayArray.forEach(function(overlay){
+                searchList[overlay._id] = overlay;
+            });
+            return searchList;
+        }
+    };
+
+
+    //
+    //  Object oriented abstraction layer for overlays.
+    //
+    //  Usage:
+    //      // Create an overlay
+    //      var billboard = new BillboardOverlay({
+    //          visible: true,
+    //          isFacingAvatar: true,
+    //          ignoreRayIntersections: false
+    //      });
+    //
+    //      // Get a property
+    //      var isVisible = billboard.visible;
+    //
+    //      // Set a single property
+    //      billboard.position = { x: 1, y: 3, z: 2 };
+    //
+    //      // Set multiple properties at the same time
+    //      billboard.setProperties({
+    //          url: "http://images.com/overlayImage.jpg",
+    //          dimensions: { x: 2, y: 2 }
+    //      });
+    //
+    //      // Clone an overlay
+    //      var clonedBillboard = billboard.clone();
+    //
+    //      // Remove an overlay from the world
+    //      billboard.destroy();
+    //
+    //      // Remember, there is a poor orphaned JavaScript object left behind.  You should
+    //      // remove any references to it so you don't accidentally try to modify an overlay that
+    //      // isn't there.
+    //      billboard = undefined;
+    //
+    (function() {
+        var ABSTRACT = null;
+        overlayTypes = {};
+
+        function generateOverlayClass(superclass, type, properties) {
+            var that;
+            if (type == ABSTRACT) {
+                that = function(type, params) {
+                    superclass.call(this, type, params);
+                };
+            } else {
+                that = function(params) {
+                    superclass.call(this, type, params);
+                };
+                overlayTypes[type] = that;
+            }
+
+            that.prototype = new superclass();
+            that.prototype.constructor = that;
+
+            properties.forEach(function(prop) {
+                Object.defineProperty(that.prototype, prop, {
+                    get: function() {
+                        return Overlays.getProperty(this._id, prop);
+                    },
+                    set: function(newValue) {
+                        var keyValuePair = {};
+                        keyValuePair[prop] = newValue;
+                        this.setProperties(keyValuePair);
+                    },
+                    configurable: false
+                });
+            });
+
+            return that;
+        }
+
+        // Supports multiple inheritance of properties.  Just `concat` them onto the end of the
+        // properties list.
+        var PANEL_ATTACHABLE_FIELDS = ["offsetPosition", "facingRotation"];
+
+        Overlay = (function() {
+            var that = function(type, params) {
+                if (type && params) {
+                    this._id = Overlays.addOverlay(type, params);
+                    overlays[this._id] = this;
+                } else {
+                    this._id = 0;
+                }
+                this._attachedPanelPointer = null;
+            };
+
+            that.prototype.constructor = that;
+
+            Object.defineProperty(that.prototype, "isLoaded", {
+                get: function() {
+                    return Overlays.isLoaded(this._id);
+                }
+            });
+
+            Object.defineProperty(that.prototype, "attachedPanel", {
+                get: function() {
+                    return this._attachedPanelPointer;
+                }
+            });
+
+            that.prototype.getTextSize = function(text) {
+                return Overlays.textSize(this._id, text);
+            };
+
+            that.prototype.setProperties = function(properties) {
+                Overlays.editOverlay(this._id, properties);
+            };
+
+            that.prototype.clone = function() {
+                return makeOverlayFromId(Overlays.cloneOverlay(this._id));
+            };
+
+            that.prototype.destroy = function() {
+                Overlays.deleteOverlay(this._id);
+            };
+
+            return generateOverlayClass(that, ABSTRACT, [
+                "alpha", "glowLevel", "pulseMax", "pulseMin", "pulsePeriod", "glowLevelPulse",
+                "alphaPulse", "colorPulse", "visible", "anchor"
+            ]);
+        })();
+
+        Overlay2D = generateOverlayClass(Overlay, ABSTRACT, [
+            "bounds", "x", "y", "width", "height"
+        ]);
+
+        Base3DOverlay = generateOverlayClass(Overlay, ABSTRACT, [
+            "position", "lineWidth", "rotation", "isSolid", "isFilled", "isWire", "isDashedLine",
+            "ignoreRayIntersection", "drawInFront", "drawOnHUD"
+        ]);
+
+        Planar3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
+            "dimensions"
+        ]);
+
+        Volume3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
+            "dimensions"
+        ]);
+
+        generateOverlayClass(Overlay2D, "image", [
+            "subImage", "imageURL"
+        ]);
+
+        generateOverlayClass(Overlay2D, "text", [
+            "font", "text", "backgroundColor", "backgroundAlpha", "leftMargin", "topMargin"
+        ]);
+
+        generateOverlayClass(Planar3DOverlay, "text3d", [
+            "text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin",
+            "rightMargin", "bottomMargin", "isFacingAvatar"
+        ]);
+
+        generateOverlayClass(Volume3DOverlay, "cube", [
+            "borderSize"
+        ]);
+
+        generateOverlayClass(Volume3DOverlay, "sphere", [
+        ]);
+
+        generateOverlayClass(Planar3DOverlay, "circle3d", [
+            "startAt", "endAt", "outerRadius", "innerRadius", "hasTickMarks",
+            "majorTickMarksAngle", "minorTickMarksAngle", "majorTickMarksLength",
+            "minorTickMarksLength", "majorTickMarksColor", "minorTickMarksColor"
+        ]);
+
+        generateOverlayClass(Planar3DOverlay, "rectangle3d", [
+        ]);
+
+        generateOverlayClass(Base3DOverlay, "line3d", [
+            "start", "end"
+        ]);
+
+        generateOverlayClass(Planar3DOverlay, "grid", [
+            "minorGridWidth", "majorGridEvery"
+        ]);
+
+        generateOverlayClass(Volume3DOverlay, "localmodels", [
+        ]);
+
+        generateOverlayClass(Volume3DOverlay, "model", [
+            "url", "dimensions", "textures"
+        ]);
+
+        generateOverlayClass(Planar3DOverlay, "billboard", [
+            "url", "subImage", "isFacingAvatar"
+        ].concat(PANEL_ATTACHABLE_FIELDS));
+    })();
+
+    ImageOverlay = overlayTypes["image"];
+    TextOverlay = overlayTypes["text"];
+    Text3DOverlay = overlayTypes["text3d"];
+    Cube3DOverlay = overlayTypes["cube"];
+    Sphere3DOverlay = overlayTypes["sphere"];
+    Circle3DOverlay = overlayTypes["circle3d"];
+    Rectangle3DOverlay = overlayTypes["rectangle3d"];
+    Line3DOverlay = overlayTypes["line3d"];
+    Grid3DOverlay = overlayTypes["grid"];
+    LocalModelsOverlay = overlayTypes["localmodels"];
+    ModelOverlay = overlayTypes["model"];
+    BillboardOverlay = overlayTypes["billboard"];
+
+
+    //
+    //  Object oriented abstraction layer for panels.
+    //
+    FloatingUIPanel = (function() {
+        var that = function(params) {
+            this._id = Overlays.addPanel(params);
+            this._children = [];
+            this._visible = Boolean(params.visible);
+            panels[this._id] = this;
+            this._attachedPanelPointer = null;
+        };
+
+        that.prototype.constructor = that;
+
+        var FIELDS = ["offsetPosition", "offsetRotation", "facingRotation"];
+        FIELDS.forEach(function(prop) {
+            Object.defineProperty(that.prototype, prop, {
+                get: function() {
+                    return Overlays.getPanelProperty(this._id, prop);
+                },
+                set: function(newValue) {
+                    var keyValuePair = {};
+                    keyValuePair[prop] = newValue;
+                    this.setProperties(keyValuePair);
+                },
+                configurable: false
+            });
+        });
+
+        var PSEUDO_FIELDS = [];
+
+        PSEUDO_FIELDS.push("children");
+        Object.defineProperty(that.prototype, "children", {
+            get: function() {
+                return this._children.slice();
+            }
+        });
+
+        PSEUDO_FIELDS.push("visible");
+        Object.defineProperty(that.prototype, "visible", {
+            get: function() {
+                return this._visible;
+            },
+            set: function(visible) {
+                this._visible = visible;
+                this._children.forEach(function(child) {
+                    child.visible = visible;
+                });
+            }
+        });
+
+        that.prototype.addChild = function(child) {
+            if (child instanceof Overlay) {
+                Overlays.setAttachedPanel(child._id, this._id);
+            } else if (child instanceof FloatingUIPanel) {
+                child.setProperties({
+                    anchorPosition: {
+                        bind: "panel",
+                        value: this._id
+                    },
+                    offsetRotation: {
+                        bind: "panel",
+                        value: this._id
+                    }
+                });
+            }
+            child._attachedPanelPointer = this;
+            child.visible = this.visible;
+            this._children.push(child);
+            return child;
+        };
+
+        that.prototype.removeChild = function(child) {
+            var i = this._children.indexOf(child);
+            if (i >= 0) {
+                if (child instanceof Overlay) {
+                    Overlays.setAttachedPanel(child._id, 0);
+                } else if (child instanceof FloatingUIPanel) {
+                    child.setProperties({
+                        anchorPosition: {
+                            bind: "myAvatar"
+                        },
+                        offsetRotation: {
+                            bind: "myAvatar"
+                        }
+                    });
+                }
+                child._attachedPanelPointer = null;
+                this._children.splice(i, 1);
+            }
+        };
+
+        that.prototype.setProperties = function(properties) {
+            for (var i in PSEUDO_FIELDS) {
+                if (properties[PSEUDO_FIELDS[i]] !== undefined) {
+                    this[PSEUDO_FIELDS[i]] = properties[PSEUDO_FIELDS[i]];
+                }
+            }
+            Overlays.editPanel(this._id, properties);
+        };
+
+        that.prototype.destroy = function() {
+            Overlays.deletePanel(this._id);
+        };
+
+        return that;
+    })();
+
+
+    function onOverlayDeleted(id) {
+        if (id in overlays) {
+            if (overlays[id]._attachedPanelPointer) {
+                overlays[id]._attachedPanelPointer.removeChild(overlays[id]);
+            }
+            delete overlays[id];
+        }
+    }
+
+    function onPanelDeleted(id) {
+        if (id in panels) {
+            panels[id]._children.forEach(function(child) {
+                print(JSON.stringify(child.destroy));
+                child.destroy();
+            });
+            delete panels[id];
+        }
+    }
+
+    Overlays.overlayDeleted.connect(onOverlayDeleted);
+    Overlays.panelDeleted.connect(onPanelDeleted);
+})();
diff --git a/examples/libraries/overlayUtils.js b/examples/libraries/overlayUtils.js
index 3acab0103b..a5622ec435 100644
--- a/examples/libraries/overlayUtils.js
+++ b/examples/libraries/overlayUtils.js
@@ -2,39 +2,16 @@
 //  overlayUtils.js
 //  examples/libraries
 //
-//  Modified by Zander Otavka on 7/15/15
-//  Copyright 2014 High Fidelity, Inc.
-//
-//  Manage overlays with object oriented goodness, instead of ugly `Overlays.h` methods.
-//  Instead of:
-//
-//      var billboard = Overlays.addOverlay("billboard", { visible: false });
-//      ...
-//      Overlays.editOverlay(billboard, { visible: true });
-//      ...
-//      Overlays.deleteOverlay(billboard);
-//
-//  You can now do:
-//
-//      var billboard = new BillboardOverlay({ visible: false });
-//      ...
-//      billboard.visible = true;
-//      ...
-//      billboard.destroy();
-//
-//  See more on usage below.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//  Copyright 2015 High Fidelity, Inc.
 //
 
 
-/**
- *  DEPRECATION WARNING: Will be deprecated soon in favor of FloatingUIPanel.
- *
- *  OverlayGroup provides a way to create composite overlays and control their
- *  position relative to a settable rootPosition and rootRotation.
- */
+//
+//  DEPRECATION WARNING: Will be deprecated soon in favor of FloatingUIPanel.
+//
+//  OverlayGroup provides a way to create composite overlays and control their
+//  position relative to a settable rootPosition and rootRotation.
+//
 OverlayGroup = function(opts) {
     var that = {};
 
@@ -92,226 +69,6 @@ OverlayGroup = function(opts) {
         }
         overlays = {};
     }
-    
+
     return that;
 };
-
-
-/**
- *  Object oriented abstraction layer for overlays.
- *
- *  Usage:
- *      // Create an overlay
- *      var billboard = new BillboardOverlay({
- *          visible: true,
- *          isFacingAvatar: true,
- *          ignoreRayIntersections: false
- *      });
- *
- *      // Get a property
- *      var isVisible = billboard.visible;
- *
- *      // Set a single property
- *      billboard.position = { x: 1, y: 3, z: 2 };
- *
- *      // Set multiple properties at the same time
- *      billboard.setProperties({
- *          url: "http://images.com/overlayImage.jpg",
- *          dimensions: { x: 2, y: 2 }
- *      });
- *
- *      // Clone an overlay
- *      var clonedBillboard = billboard.clone();
- *
- *      // Remove an overlay from the world
- *      billboard.destroy();
- *
- *      // Remember, there is a poor orphaned JavaScript object left behind.  You should remove any
- *      // references to it so you don't accidentally try to modify an overlay that isn't there.
- *      billboard = undefined;
- */
-(function() {
-    var ABSTRACT = null;
-
-    function generateOverlayClass(superclass, type, properties) {
-        var that;
-        if (type == ABSTRACT) {
-            that = function(type, params) {
-                superclass.apply(this, [type, params]);
-            };
-        } else {
-            that = function(params) {
-                superclass.apply(this, [type, params]);
-            };
-        }
-
-        that.prototype = new superclass();
-        that.prototype.constructor = that;
-
-        properties.forEach(function(prop) {
-            Object.defineProperty(that.prototype, prop, {
-                get: function() {
-                    return Overlays.getProperty(this._id, prop);
-                },
-                set: function(newValue) {
-                    var keyValuePair = {};
-                    keyValuePair[prop] = newValue;
-                    this.setProperties(keyValuePair);
-                },
-                configurable: true
-            });
-        });
-
-        return that;
-    }
-
-
-    // Supports multiple inheritance of properties.  Just `concat` them onto the end of the
-    // properties list.
-    var PANEL_ATTACHABLE_FIELDS = ["attachedPanel"];
-
-    // TODO: finish exposing all overlay classes.
-
-    var Overlay = (function() {
-        var BaseOverlay = (function() {
-            var that = function(type, params) {
-                Object.apply(this, []);
-                if (type && params) {
-                    this._type = type;
-                    this._id = Overlays.addOverlay(type, params);
-                } else {
-                    this._type = "";
-                    this._id = 0;
-                }
-                this._attachedPanelPointer = null;
-            };
-
-            that.prototype = new Object();
-            that.prototype.constructor = that;
-
-            Object.defineProperty(that.prototype, "overlayType", {
-                get: function() {
-                    return this._type;
-                }
-            });
-
-            that.prototype.setProperties = function(properties) {
-                Overlays.editOverlay(this._id, properties);
-            };
-
-            that.prototype.clone = function() {
-                var clone = new this.constructor();
-                clone._type = this._type;
-                clone._id = Overlays.cloneOverlay(this._id);
-                if (this._attachedPanelPointer) {
-                    this._attachedPanelPointer.addChild(clone);
-                }
-                return clone;
-            };
-
-            that.prototype.destroy = function() {
-                Overlays.deleteOverlay(this._id);
-            };
-
-            return that;
-        }());
-
-        return generateOverlayClass(BaseOverlay, ABSTRACT, [
-            "alpha", "glowLevel", "pulseMax", "pulseMin", "pulsePeriod", "glowLevelPulse",
-            "alphaPulse", "colorPulse", "visible", "anchor"
-        ]);
-    }());
-
-    var Base3DOverlay = generateOverlayClass(Overlay, ABSTRACT, [
-        "position", "lineWidth", "rotation", "isSolid", "isFilled", "isWire", "isDashedLine",
-        "ignoreRayIntersection", "drawInFront", "drawOnHUD"
-    ]);
-
-    var Planar3DOverlay = generateOverlayClass(Base3DOverlay, ABSTRACT, [
-        "dimensions"
-    ]);
-
-    BillboardOverlay = generateOverlayClass(Planar3DOverlay, "billboard", [
-        "url", "subImage", "isFacingAvatar", "offsetPosition"
-    ].concat(PANEL_ATTACHABLE_FIELDS));
-}());
-
-
-/**
- *  Object oriented abstraction layer for panels.
- */
-FloatingUIPanel = (function() {
-    var that = function(params) {
-        this._id = Overlays.addPanel(params);
-        this._children = [];
-    };
-
-    var FIELDS = ["offsetPosition", "offsetRotation", "facingRotation"];
-    FIELDS.forEach(function(prop) {
-        Object.defineProperty(that.prototype, prop, {
-            get: function() {
-                return Overlays.getPanelProperty(this._id, prop);
-            },
-            set: function(newValue) {
-                var keyValuePair = {};
-                keyValuePair[prop] = newValue;
-                this.setProperties(keyValuePair);
-            },
-            configurable: false
-        });
-    });
-
-    Object.defineProperty(that.prototype, "children", {
-        get: function() {
-            return this._children.slice();
-        }
-    })
-
-    that.prototype.addChild = function(overlay) {
-        overlay.attachedPanel = this._id;
-        overlay._attachedPanelPointer = this;
-        this._children.push(overlay);
-        return overlay;
-    };
-
-    that.prototype.removeChild = function(overlay) {
-        var i = this._children.indexOf(overlay);
-        if (i >= 0) {
-            overlay.attachedPanel = 0;
-            overlay._attachedPanelPointer = null;
-            this._children.splice(i, 1);
-        }
-    };
-
-    that.prototype.setVisible = function(visible) {
-        for (var i in this._children) {
-            this._children[i].visible = visible;
-        }
-    };
-
-    that.prototype.setProperties = function(properties) {
-        Overlays.editPanel(this._id, properties);
-    };
-
-    that.prototype.destroy = function() {
-        Overlays.deletePanel(this._id);
-        var i = _panels.indexOf(this);
-        if (i >= 0) {
-            _panels.splice(i, 1);
-        }
-    };
-
-    that.prototype.findRayIntersection = function(pickRay) {
-        var rayPickResult = Overlays.findRayIntersection(pickRay);
-        if (rayPickResult.intersects) {
-            for (var i in this._children) {
-                if (this._children[i]._id == rayPickResult.overlayID) {
-                    return this._children[i];
-                }
-            }
-        }
-        return null;
-    };
-
-    return that;
-}());