diff --git a/src/ui/UIContext.ts b/src/ui/UIContext.ts
index 36b18c9..56be2b2 100644
--- a/src/ui/UIContext.ts
+++ b/src/ui/UIContext.ts
@@ -44,7 +44,7 @@ class UIContext {
       for (const { template } of templates) {
         // TODO: Does this bit require lock/release of templates?
         if (template && !template.locked) {
-          parentName = node.attributes.get('parent');
+          parentName = template.node.attributes.get('parent');
         }
       }
     }
@@ -187,7 +187,7 @@ class UIContext {
             }
           } else {
             this.createFrame(child, null, status);
-            // TODO: Re-layout
+            LayoutFrame.resizePending();
           }
         }
       }
diff --git a/src/ui/components/UIRoot.ts b/src/ui/components/UIRoot.ts
index 8f6e810..f381943 100644
--- a/src/ui/components/UIRoot.ts
+++ b/src/ui/components/UIRoot.ts
@@ -109,6 +109,17 @@ class UIRoot extends LayoutFrame {
     strata.batchDirty = 1;
   }
 
+  notifyFrameMovedOrResized(frame: Frame) {
+    const strata = this.strata[frame.strataType];
+    strata.levelsDirty = 1;
+
+    if (this.layout.frame) {
+      this.raiseFrame(this.layout.frame, false);
+    }
+
+    // TODO: Focus check
+  }
+
   onLayerUpdate(elapsedSecs: number) {
     // TODO: Clean-up destroyed frames
 
diff --git a/src/ui/components/abstract/FramePoint.ts b/src/ui/components/abstract/FramePoint.ts
index f1bc47b..38405fd 100644
--- a/src/ui/components/abstract/FramePoint.ts
+++ b/src/ui/components/abstract/FramePoint.ts
@@ -72,8 +72,18 @@ class FramePoint {
     return rect;
   }
 
-  setRelative(_relative: LayoutFrame, _relativePoint: Type, _offsetX: number, _offsetY: number) {
-    // TODO: Implement
+  markUnused() {
+    this.type = Type.TOPLEFT - 1;
+    this.offset.setElements(0.0, 0.0);
+    // this.relative = null;
+    this.flags = this.flags & 0x2 ? 0x2 | 0x4 | 0x8 : 0x8;
+  }
+
+  setRelative(relative: LayoutFrame, relativePoint: Type, offsetX: number, offsetY: number) {
+    this.type = relativePoint;
+    this.offset.setElements(offsetX, offsetY);
+    this.relative = relative;
+    this.flags = this.flags & 0x2 ? 0x2 | 0x4 : 0x0;
   }
 
   x(scale: number) {
diff --git a/src/ui/components/abstract/LayoutFrame.ts b/src/ui/components/abstract/LayoutFrame.ts
index 8038222..b497004 100644
--- a/src/ui/components/abstract/LayoutFrame.ts
+++ b/src/ui/components/abstract/LayoutFrame.ts
@@ -1,4 +1,3 @@
-import ScriptRegion from './ScriptRegion';
 import XMLNode from '../../XMLNode';
 import { stringToFramePointType } from '../../utils';
 import {
@@ -81,7 +80,7 @@ class LayoutFrame {
     };
 
     this.resizeList = LinkedList.using('link');
-    this.resizeCounter = NaN;
+    this.resizeCounter = 0;
 
     this.points = [
       null, null, null,
@@ -329,10 +328,21 @@ class LayoutFrame {
     return true;
   }
 
+  clearAllPoints() {
+    this.freePoints();
+  }
+
   freePoints() {
+    let i = 0;
     for (const point of this.points) {
-      // TODO: Implementation
-      console.error('freeing point', point);
+      if (point && !(point.flags & 0x8)) {
+        if (point.relative) {
+          point.relative.unregisterResize(this, 1 << i);
+        }
+
+        point.markUnused();
+      }
+      ++i;
     }
   }
 
@@ -357,6 +367,10 @@ class LayoutFrame {
     return FramePoint.UNDEFINED;
   }
 
+  getLayoutFrameByName(_name: string): LayoutFrame | null {
+    return null;
+  }
+
   getRect() {
     if (!(this.layoutFlags & 0x1)) {
       return undefined;
@@ -367,6 +381,11 @@ class LayoutFrame {
     return rect;
   }
 
+  isResizeDependency(_dependentFrame: LayoutFrame) {
+    // TODO: Implementation
+    return false;
+  }
+
   loadXML(node: XMLNode, status: Status) {
     const size = node.getChildByName('Size');
     if (size) {
@@ -413,8 +432,7 @@ class LayoutFrame {
 
         let relative = layoutParent;
         if (relativeValue) {
-          const fqname = this.fullyQualifyName(relativeValue)!;
-          relative = ScriptRegion.getObjectByName(fqname);
+          relative = this.getLayoutFrameByName(relativeValue);
           if (!relative) {
             status.warning(`could not find relative frame: ${relativeValue}`);
             continue;
@@ -554,6 +572,10 @@ class LayoutFrame {
     }
   }
 
+  setLayoutScale(_scale: number, _force: boolean) {
+    // TODO: Implementation
+  }
+
   setPoint(pointType: FramePointType, relative: LayoutFrame | null, relativePointType: FramePointType, offsetX = 0, offsetY = 0, resize = false) {
     if (!relative || !relative.canBeAnchorFor(this)) {
       return;
diff --git a/src/ui/components/abstract/ScriptObject.ts b/src/ui/components/abstract/ScriptObject.ts
index f768db8..3432534 100644
--- a/src/ui/components/abstract/ScriptObject.ts
+++ b/src/ui/components/abstract/ScriptObject.ts
@@ -17,10 +17,6 @@ class ScriptObject extends FrameScriptObject {
     this._name = null;
   }
 
-  get displayName() {
-    return this.name || '<unnamed>';
-  }
-
   get name() {
     return this._name;
   }
diff --git a/src/ui/components/abstract/ScriptRegion.ts b/src/ui/components/abstract/ScriptRegion.ts
index 58fa87a..c0988f5 100644
--- a/src/ui/components/abstract/ScriptRegion.ts
+++ b/src/ui/components/abstract/ScriptRegion.ts
@@ -34,10 +34,15 @@ class ScriptRegion extends multipleClasses(ScriptObject, LayoutFrame) {
   }
 
   get layoutParent(): LayoutFrame {
-    if (this.width === 0.0 || !this.parent) {
+    if (!this._parent || this._parent.layoutScale === 0.0) {
       return UIRoot.instance;
     }
-    return this.parent;
+    return this._parent;
+  }
+
+  getLayoutFrameByName(name: string): LayoutFrame | null {
+    const fqname = this.fullyQualifyName(name);
+    return ScriptRegion.getObjectByName(fqname);
   }
 
   loadXML(node: XMLNode, status: Status) {
diff --git a/src/ui/components/simple/Frame.ts b/src/ui/components/simple/Frame.ts
index bd95463..6f3ad6b 100644
--- a/src/ui/components/simple/Frame.ts
+++ b/src/ui/components/simple/Frame.ts
@@ -53,6 +53,7 @@ class Frame extends ScriptRegion {
   visible: boolean;
   strataType: FrameStrataType;
   level: number;
+  frameScale: number;
 
   layersEnabled: EnumRecord<DrawLayerType, boolean>;
   backdrop: Backdrop | null;
@@ -77,6 +78,7 @@ class Frame extends ScriptRegion {
     this.visible = false;
     this.strataType = FrameStrataType.MEDIUM;
     this.level = 0;
+    this.frameScale = 1.0;
 
     this.layersEnabled = [
       true,
@@ -210,11 +212,13 @@ class Frame extends ScriptRegion {
     if (parent) {
       this.setFrameStrataType(parent.strataType);
       this.setFrameLevel(parent.level + 1, true);
+      this.updateScale(false);
 
       // TODO: Alpha and scrolling adjustments
     } else {
       this.setFrameStrataType(FrameStrataType.MEDIUM);
       this.setFrameLevel(0, true);
+      this.updateScale(false);
 
       // TODO: Alpha and scrolling adjustments
     }
@@ -222,7 +226,7 @@ class Frame extends ScriptRegion {
     if (parent) {
       // TODO: Parent attachment protection
       const node = new FrameNode(this);
-      parent.children.linkToHead(node);
+      parent.children.linkToTail(node);
     }
 
     if (this.shown) {
@@ -482,7 +486,7 @@ class Frame extends ScriptRegion {
       return false;
     }
 
-    if (this.parent && !this.parent.visible) {
+    if (this._parent && !this._parent.visible) {
       return false;
     }
 
@@ -604,11 +608,23 @@ class Frame extends ScriptRegion {
 
     // TODO: Set hit rect
 
-    if (this.backdrop) {
-      this.backdrop.update(this.rect);
+    if (!areClose(rect.minX, this.rect.maxX) || !areClose(rect.minY, this.rect.maxY)) {
+      if (this.backdrop) {
+        this.backdrop.update(this.rect);
+      }
+
+      const ratio = 1.0 / this.layoutScale;
+      const width = ratio * (this.rect.maxX - this.rect.minX);
+      const height = ratio * (this.rect.maxY - this.rect.minY);
+
+      this.onFrameSizeChangedRange(width, height);
     }
 
-    // TODO: Remaining implementation
+    UIRoot.instance.notifyFrameMovedOrResized(this);
+  }
+
+  onFrameSizeChangedRange(_width: number, _height: number) {
+    // TODO
   }
 
   onLayerShow() {
@@ -648,6 +664,29 @@ class Frame extends ScriptRegion {
       this.runScript('OnShow');
     }
   }
+
+  updateScale(force: boolean) {
+    let scale = this.frameScale;
+    if (this.parent) {
+      scale *= this.parent.layoutScale;
+    }
+
+    if ((!force && areClose(scale, this.layoutScale, EPSILON1)) || scale === 0.0) {
+      return false;
+    }
+
+    this.setLayoutScale(scale, force);
+
+    for (const region of this.regions) {
+        region.setLayoutScale(scale, force);
+    }
+
+    for (const child of this.children) {
+        child.frame.updateScale(false);
+    }
+
+    return true;
+  }
 }
 
 export default Frame;
diff --git a/src/ui/components/simple/Texture.ts b/src/ui/components/simple/Texture.ts
index 9359763..2cc4b10 100644
--- a/src/ui/components/simple/Texture.ts
+++ b/src/ui/components/simple/Texture.ts
@@ -73,9 +73,9 @@ class Texture extends Region {
   }
 
   get width() {
-    const layoutwidth = super.width;
-    if (layoutwidth !== 0.0) {
-      return layoutwidth;
+    const layoutWidth = super.width;
+    if (layoutWidth !== 0.0) {
+      return layoutWidth;
     }
 
     if (this.texture && this.texture.isLoaded) {
@@ -253,7 +253,20 @@ class Texture extends Region {
   }
 
   postLoadXML(_node: XMLNode) {
-    // TODO
+    if (this._parent) {
+      let i = 0;
+      for (const point of this.points) {
+        if (point && !(point.flags & 0x8)) {
+          break;
+        }
+
+        if (i + 1 === this.points.length) {
+          this.setAllPoints(this._parent, true);
+          break;
+        }
+        ++i;
+      }
+    }
   }
 
   onFrameSizeChanged(rect: Rect) {
diff --git a/src/ui/scripting/FrameScriptObject.ts b/src/ui/scripting/FrameScriptObject.ts
index 49aca39..2fae107 100644
--- a/src/ui/scripting/FrameScriptObject.ts
+++ b/src/ui/scripting/FrameScriptObject.ts
@@ -41,10 +41,18 @@ class FrameScriptObject {
     );
   }
 
+  get displayName() {
+    return this.name || '<unnamed>';
+  }
+
   get isLuaRegistered() {
     return this.luaRef !== null;
   }
 
+  get name(): string | null {
+    return null;
+  }
+
   register(name: string | null = null) {
     const L = ScriptingContext.instance.state;