diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc
index 1d7b4959e..adfa66189 100644
--- a/common/src/app/common/data.cljc
+++ b/common/src/app/common/data.cljc
@@ -884,3 +884,13 @@
    (extend-protocol ICloseable
      AutoCloseable
      (close! [this] (.close this))))
+
+(defn take-until
+  "Returns a lazy sequence of successive items from coll until
+  (pred item) returns true, including that item"
+  ([pred]
+   (halt-when pred (fn [r h] (conj r h))))
+
+  ([pred coll]
+   (transduce (take-until pred) conj [] coll)))
+
diff --git a/common/src/app/common/geom/bounds_map.cljc b/common/src/app/common/geom/bounds_map.cljc
new file mode 100644
index 000000000..eebf4dd63
--- /dev/null
+++ b/common/src/app/common/geom/bounds_map.cljc
@@ -0,0 +1,133 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.common.geom.bounds-map
+  (:require
+   [app.common.data :as d]
+   [app.common.data.macros :as dm]
+   [app.common.geom.shapes.common :as gco]
+   [app.common.geom.shapes.points :as gpo]
+   [app.common.geom.shapes.transforms :as gtr]
+   [app.common.math :as mth]
+   [app.common.pages.helpers :as cph]
+   [app.common.types.modifiers :as ctm]
+   [app.common.uuid :as uuid]))
+
+(defn objects->bounds-map
+  [objects]
+  (d/lazy-map
+   (keys objects)
+   #(gco/shape->points (get objects %))))
+
+(defn- create-bounds
+  "Create the bounds object for the current shape in this context"
+  ([shape bounds-map objects]
+   (create-bounds shape bounds-map objects nil nil))
+
+  ([shape bounds-map objects modif-tree]
+   (create-bounds shape bounds-map objects modif-tree nil))
+
+  ([{:keys [id] :as shape} bounds-map objects modif-tree current-ref]
+   (cond
+     (and (cph/mask-shape? shape) (d/not-empty? (:shapes shape)))
+     (create-bounds (get objects (first (:shapes shape))) bounds-map objects modif-tree)
+
+     (cph/group-shape? shape)
+     (let [modifiers (dm/get-in modif-tree [id :modifiers])
+           children (cph/get-immediate-children objects id)
+           shape-bounds (if current-ref @current-ref @(get bounds-map id))
+           current-bounds
+           (cond-> shape-bounds
+             (not (ctm/empty? modifiers))
+             (gtr/transform-bounds modifiers))
+
+           children-bounds
+           (->> children
+                (mapv #(deref (get bounds-map (:id %)))))]
+       (gpo/merge-parent-coords-bounds children-bounds current-bounds))
+
+     :else
+     (let [modifiers (dm/get-in modif-tree [id :modifiers])
+           shape-bounds (if current-ref @current-ref @(get bounds-map id))]
+       (cond-> shape-bounds
+         (not (ctm/empty? modifiers))
+         (gtr/transform-bounds modifiers))))))
+
+#?(:clj
+   (defn- resolve-modif-tree-ids
+     [objects modif-tree]
+     ;; These are the new bounds calculated. Are the "modified" plus any groups they belong to
+     (let [ids (keys modif-tree)]
+       (into (set ids)
+             (mapcat #(->> (cph/get-parent-ids-seq objects %)
+                           (take-while (partial cph/group-like-shape? objects))))
+             ids)))
+
+   :cljs
+   ;; More performant version using javascript mutable sets
+   (defn- resolve-modif-tree-ids
+     [objects modif-tree]
+
+     (let [base-ids (keys modif-tree)
+           ids (js/Set. base-ids)]
+       (loop [base-ids (seq base-ids)]
+         (when (some? base-ids)
+           (let [cid (first base-ids)]
+             (loop [new-ids
+                    (->> (cph/get-parent-seq objects cid)
+                         (take-while #(and (cph/group-like-shape? %)
+                                           (not (.has ids %))))
+                         (seq))]
+               (when (some? new-ids)
+                 (.add ids (first new-ids))
+                 (recur (next new-ids))))
+             (recur (next base-ids)))))
+       ids)))
+
+(defn transform-bounds-map
+  ([bounds-map objects modif-tree]
+   (transform-bounds-map bounds-map objects modif-tree nil))
+  ([bounds-map objects modif-tree ids]
+   ;; We use the volatile in order to solve the dependencies problem. We want the groups to reference the new
+   ;; bounds instead of the old ones. The current as last parameter is to fix a possible infinite loop
+   ;; with self-references
+   (let [bm-holder (volatile! nil)
+
+         ids (or ids (resolve-modif-tree-ids objects modif-tree))
+
+         new-bounds-map
+         (loop [tr-bounds-map (transient bounds-map)
+                ids (seq ids)]
+           (if (not ids)
+             (persistent! tr-bounds-map)
+             (let [shape-id (first ids)]
+               (recur
+                (cond-> tr-bounds-map
+                  (not= uuid/zero shape-id)
+                  (assoc! shape-id
+                          (delay (create-bounds (get objects shape-id)
+                                                @bm-holder
+                                                objects
+                                                modif-tree
+                                                (get bounds-map shape-id)))))
+                (next ids)))))]
+     (vreset! bm-holder new-bounds-map)
+     new-bounds-map)))
+
+;; Tool for debugging
+(defn bounds-map
+  [objects bounds-map]
+  (letfn [(parse-bound [[id bounds*]]
+            (let [bounds (deref bounds*)
+                  shape (get objects id)]
+              (when (and shape bounds)
+                [(:name shape)
+                 {:x (mth/round (:x (gpo/origin bounds)) 2)
+                  :y (mth/round (:y (gpo/origin bounds)) 2)
+                  :width (mth/round (gpo/width-points bounds) 2)
+                  :height (mth/round (gpo/height-points bounds) 2)}])))]
+
+    (into {} (keep parse-bound) bounds-map)))
diff --git a/common/src/app/common/geom/modif_tree.cljc b/common/src/app/common/geom/modif_tree.cljc
new file mode 100644
index 000000000..709012d7d
--- /dev/null
+++ b/common/src/app/common/geom/modif_tree.cljc
@@ -0,0 +1,56 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.common.geom.modif-tree
+  (:require
+   [app.common.data.macros :as dm]
+   [app.common.geom.shapes.min-size-layout]
+   [app.common.pages.helpers :as cph]
+   [app.common.types.modifiers :as ctm]))
+
+(defn add-modifiers
+  "Add the given modifiers to the map of modifiers."
+  [modif-tree id modifiers]
+  (if (ctm/empty? modifiers)
+    modif-tree
+    (let [old-modifiers
+          (dm/get-in modif-tree [id :modifiers])
+          new-modifiers
+          (ctm/add-modifiers old-modifiers modifiers)]
+      (cond-> modif-tree
+        (ctm/empty? new-modifiers)
+        (dissoc id)
+        
+        (not (ctm/empty? new-modifiers))
+        (assoc-in [id :modifiers] new-modifiers)))))
+
+(defn merge-modif-tree
+  "Merge two maps of modifiers into a single one"
+  [modif-tree other-tree]
+  (reduce
+   (fn [modif-tree [id {:keys [modifiers]}]]
+     (add-modifiers modif-tree id modifiers))
+   modif-tree
+   other-tree))
+
+(defn apply-structure-modifiers
+  "Only applies the structure modifiers to the objects tree map"
+  [objects modif-tree]
+  (letfn [(update-children-structure-modifiers
+            [objects ids modifiers]
+            (reduce #(update %1 %2 ctm/apply-structure-modifiers modifiers) objects ids))
+
+          (apply-shape [objects [id {:keys [modifiers]}]]
+            (cond-> objects
+              (ctm/has-structure? modifiers)
+              (update id ctm/apply-structure-modifiers modifiers)
+
+              (and (ctm/has-structure? modifiers)
+                   (ctm/has-structure-child? modifiers))
+              (update-children-structure-modifiers
+               (cph/get-children-ids objects id)
+               (ctm/select-child-structre-modifiers modifiers))))]
+    (reduce apply-shape objects modif-tree)))
diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc
index 9b3e9d0e1..995d97541 100644
--- a/common/src/app/common/geom/shapes/constraints.cljc
+++ b/common/src/app/common/geom/shapes/constraints.cljc
@@ -280,11 +280,11 @@
                   (/ (gpo/height-points child-bb-before) (max 0.01 (gpo/height-points child-bb-after))))
 
         resize-vector (gpt/point scale-x scale-y)
-        resize-origin (gpo/origin transformed-child-bounds)
+        resize-origin (gpo/origin child-bb-after)
 
-        center            (gco/points->center transformed-child-bounds)
-        selrect           (gtr/calculate-selrect transformed-child-bounds center)
-        transform         (gtr/calculate-transform transformed-child-bounds center selrect)
+        center            (gco/points->center child-bb-after)
+        selrect           (gtr/calculate-selrect child-bb-after center)
+        transform         (gtr/calculate-transform child-bb-after center selrect)
         transform-inverse (when (some? transform) (gmt/inverse transform))]
 
     (ctm/resize modifiers resize-vector resize-origin transform transform-inverse)))
diff --git a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc
index 17fe918c0..4bf564565 100644
--- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc
+++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc
@@ -7,6 +7,7 @@
 (ns app.common.geom.shapes.flex-layout.bounds
   (:require
    [app.common.data :as d]
+   [app.common.data.macros :as dm]
    [app.common.geom.point :as gpt]
    [app.common.geom.shapes.points :as gpo]
    [app.common.types.shape.layout :as ctl]))
@@ -31,7 +32,6 @@
    (child-layout-bound-points parent child parent-bounds child-bounds (gpt/point) bounds objects))
 
   ([parent child parent-bounds child-bounds correct-v bounds objects]
-
    (let [row? (ctl/row? parent)
          col? (ctl/col? parent)
 
@@ -56,18 +56,19 @@
          ;; This is the leftmost (when row) or topmost (when col) point
          ;; Will be added always to the bounds and then calculated the other limits
          ;; from there
-         base-p (cond-> base-p
-                  (and row? v-center?)
-                  (gpt/add (vv (/ height 2)))
+         base-p
+         (cond-> base-p
+           (and row? v-center?)
+           (gpt/add (vv (/ height 2)))
 
-                  (and row? v-end?)
-                  (gpt/add (vv height))
+           (and row? v-end?)
+           (gpt/add (vv height))
 
-                  (and col? h-center?)
-                  (gpt/add (hv (/ width 2)))
+           (and col? h-center?)
+           (gpt/add (hv (/ width 2)))
 
-                  (and col? h-end?)
-                  (gpt/add (hv width)))
+           (and col? h-end?)
+           (gpt/add (hv width)))
 
          ;; We need some height/width to calculate the bounds. We stablish the minimum
          min-width (max min-width 0.01)
@@ -76,10 +77,12 @@
          base-p (gpt/add base-p correct-v)
 
          result
-         (cond-> [base-p
-                  (gpt/add base-p (hv 0.01))
-                  (gpt/add base-p (vv 0.01))]
+         [base-p
+          (gpt/add base-p (hv 0.01))
+          (gpt/add base-p (vv 0.01))]
 
+         result
+         (cond-> result
            col?
            (conj (gpt/add base-p (vv min-height)))
 
@@ -112,41 +115,42 @@
            (gpt/subtract (hv (+ width min-width)))
 
            (and col? (ctl/fill-height? child))
-           (gpt/subtract (vv (+ height min-height)))
-           )]
+           (gpt/subtract (vv (+ height min-height))))]
      [result correct-v])))
 
 (defn layout-content-points
   [bounds parent children objects]
 
-  (let [parent-id (:id parent)
+  (let [parent-id     (dm/get-prop parent :id)
         parent-bounds @(get bounds parent-id)
-        get-child-bounds
-        (fn [[result correct-v] child]
-          (let [child-id (:id child)
-                child-bounds @(get bounds child-id)
-                [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
-
-                [child-bounds correct-v]
-                (if (or (ctl/fill-width? child) (ctl/fill-height? child))
-                  (child-layout-bound-points parent child parent-bounds child-bounds correct-v bounds objects)
-                  [(->> child-bounds (map #(gpt/add % correct-v))) correct-v])
-
-                child-bounds
-                (when (d/not-empty? child-bounds)
-                  (-> (gpo/parent-coords-bounds child-bounds parent-bounds)
-                      (gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))]
-
-            [(cond-> result (some? child-bounds) (conj child-bounds))
-             correct-v]))
-
         reverse?      (ctl/reverse? parent)
         children      (cond->> children (not reverse?) reverse)]
 
-    (->> children
-         (remove ctl/layout-absolute?)
-         (reduce get-child-bounds [[] (gpt/point 0)])
-         (first))))
+    (loop [children  (seq children)
+           result    (transient [])
+           correct-v (gpt/point 0)]
+
+      (if (not children)
+        (persistent! result)
+
+        (let [child (first children)
+              child-id (dm/get-prop child :id)
+              child-bounds @(get bounds child-id)
+              [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
+
+              [child-bounds correct-v]
+              (if (or (ctl/fill-width? child) (ctl/fill-height? child))
+                (child-layout-bound-points parent child parent-bounds child-bounds correct-v bounds objects)
+                [(->> child-bounds (map #(gpt/add % correct-v))) correct-v])
+
+              child-bounds
+              (when (d/not-empty? child-bounds)
+                (-> (gpo/parent-coords-bounds child-bounds parent-bounds)
+                    (gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))]
+
+          (recur (next children)
+                 (cond-> result (some? child-bounds) (conj! child-bounds))
+                 correct-v))))))
 
 (defn layout-content-bounds
   [bounds {:keys [layout-padding] :as parent} children objects]
diff --git a/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc
index d0cacd31d..ed818c66b 100644
--- a/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc
+++ b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc
@@ -53,11 +53,11 @@
         layout-height (gpo/height-points layout-bounds)]
 
     (loop [line-data    nil
-           result       []
+           result       (transient [])
            children     (seq children)]
 
-      (if (empty? children)
-        (cond-> result (some? line-data) (conj line-data))
+      (if (not children)
+        (persistent! (cond-> result (some? line-data) (conj! line-data)))
 
         (let [[child-bounds child] (first children)
               {:keys [line-min-width line-min-height
@@ -91,25 +91,27 @@
               next-max-width   (+ child-margin-width (:child-max-width child-data))
               next-max-height  (+ child-margin-height (:child-max-height child-data))
 
-              total-gap-col (cond
-                              space-evenly?
-                              (* layout-gap-col (+ num-children 2))
+              total-gap-col
+              (cond
+                space-evenly?
+                (* layout-gap-col (+ num-children 2))
 
-                              space-around?
-                              (* layout-gap-col (+ num-children 1))
+                space-around?
+                (* layout-gap-col (+ num-children 1))
 
-                              :else
-                              (* layout-gap-col num-children))
+                :else
+                (* layout-gap-col num-children))
 
-              total-gap-row (cond
-                              space-evenly?
-                              (* layout-gap-row (+ num-children 2))
+              total-gap-row
+              (cond
+                space-evenly?
+                (* layout-gap-row (+ num-children 2))
 
-                              space-around?
-                              (* layout-gap-row (+ num-children 1))
+                space-around?
+                (* layout-gap-row (+ num-children 1))
 
-                              :else
-                              (* layout-gap-row num-children))
+                :else
+                (* layout-gap-row num-children))
 
               next-line-min-width  (+ line-min-width  next-min-width  total-gap-col)
               next-line-min-height (+ line-min-height next-min-height total-gap-row)]
@@ -128,7 +130,7 @@
                     :num-children    (inc num-children)
                     :children-data   (conjv children-data child-data)}
                    result
-                   (rest children))
+                   (next children))
 
             (recur {:line-min-width  next-min-width
                     :line-min-height next-min-height
@@ -136,29 +138,31 @@
                     :line-max-height next-max-height
                     :num-children    1
                     :children-data   [child-data]}
-                   (cond-> result (some? line-data) (conj line-data))
-                   (rest children))))))))
+                   (cond-> result (some? line-data) (conj! line-data))
+                   (next children))))))))
 
 (defn add-space-to-items
   ;; Distributes the remainder space between the lines
   [prop prop-min prop-max to-share items]
   (let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count)
         per-line-target (/ to-share num-items)]
-    (loop [current (first items)
-           items   (rest items)
+
+    (loop [items (seq items)
            remainder to-share
-           result []]
-      (if (nil? current)
-        [result remainder]
-        (let [cur-val (or (get current prop) (get current prop-min) 0)
+           result (transient [])]
+
+      (if (not items)
+        [(persistent! result) remainder]
+
+        (let [current (first items)
+              cur-val (or (get current prop) (get current prop-min) 0)
               max-val (get current prop-max)
               cur-inc (if (> (+ cur-val per-line-target) max-val)
                         (- max-val cur-val)
                         per-line-target)
               current (assoc current prop (+ cur-val cur-inc))
-              remainder (- remainder cur-inc)
-              result (conj result current)]
-          (recur (first items) (rest items) remainder result))))))
+              remainder (- remainder cur-inc)]
+          (recur (next items) remainder (conj! result current)))))))
 
 (defn distribute-space
   [prop prop-min prop-max min-value bound-value items]
@@ -200,36 +204,24 @@
             (add-starts [total-width total-height num-lines [result base-p] layout-line]
               (let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines)
                     next-p  (flp/get-next-line  parent layout-bounds layout-line base-p total-width total-height num-lines)]
+                [(-> result (conj! (assoc layout-line :start-p start-p)))
+                 next-p]))
 
-                [(conj result (assoc layout-line :start-p start-p))
-                 next-p]))]
+            (get-layout-width [{:keys [num-children]}]
+              (let [num-gap (cond space-evenly? (inc num-children)
+                                  space-around? num-children
+                                  :else         (dec num-children))]
+                (- layout-width (* layout-gap-col num-gap))))
+
+            (get-layout-height [{:keys [num-children]}]
+              (let [num-gap (cond space-evenly? (inc num-children)
+                                  space-around? num-children
+                                  :else         (dec num-children))]
+                (- layout-height (* layout-gap-row num-gap))))]
 
       (let [[total-min-width total-min-height total-max-width total-max-height]
             (->> layout-lines (reduce add-ranges [0 0 0 0]))
 
-            get-layout-width (fn [{:keys [num-children]}]
-                               (let [num-gap (cond
-                                               space-evenly?
-                                               (inc num-children)
-
-                                               space-around?
-                                               num-children
-
-                                               :else
-                                               (dec num-children))]
-                                 (- layout-width (* layout-gap-col num-gap))))
-            get-layout-height (fn [{:keys [num-children]}]
-                                (let [num-gap (cond
-                                                space-evenly?
-                                                (inc num-children)
-
-                                                space-around?
-                                                num-children
-
-                                                :else
-                                                (dec num-children))]
-                                  (- layout-height (* layout-gap-row num-gap))))
-
             num-lines (count layout-lines)
 
             ;; When align-items is stretch we need to adjust the main axis size to grow for the full content
@@ -247,6 +239,7 @@
             rest-layout-width  (- layout-width (* (dec num-lines) layout-gap-col))
 
             ;; Distributes the space between the layout lines based on its max/min constraints
+
             layout-lines
             (cond->> layout-lines
               row?
@@ -267,14 +260,16 @@
               (and row? (<= total-max-height rest-layout-height) (not auto-height?))
               (map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix)))
 
-              (and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
-              (distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
-
               (and col? (or (>= total-min-width rest-layout-width) auto-width?))
               (map #(assoc % :line-width (:line-min-width %)))
 
               (and col? (<= total-max-width rest-layout-width) (not auto-width?))
-              (map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix)))
+              (map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))))
+
+            layout-lines
+            (cond->> layout-lines
+              (and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
+              (distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
 
               (and col? (< total-min-width rest-layout-width total-max-width) (not auto-width?))
               (distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width))
@@ -286,19 +281,21 @@
               (->> layout-lines
                    (reduce
                     (fn [[result rest-layout-height] {:keys [line-height] :as line}]
-                      [(conj result (assoc line :to-bound-height rest-layout-height))
+                      [(conj! result (assoc line :to-bound-height rest-layout-height))
                        (- rest-layout-height line-height layout-gap-row)])
-                    [[] layout-height])
-                   (first))
+                    [(transient []) layout-height])
+                   (first)
+                   (persistent!))
 
               col?
               (->> layout-lines
                    (reduce
                     (fn [[result rest-layout-width] {:keys [line-width] :as line}]
-                      [(conj result (assoc line :to-bound-width rest-layout-width))
+                      [(conj! result (assoc line :to-bound-width rest-layout-width))
                        (- rest-layout-width line-width layout-gap-col)])
-                    [[] layout-width])
-                   (first))
+                    [(transient []) layout-width])
+                   (first)
+                   (persistent!))
 
               :else
               layout-lines)
@@ -307,7 +304,10 @@
 
             base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)]
 
-        (first (reduce (partial add-starts total-width total-height num-lines) [[] base-p] layout-lines))))))
+        (->> layout-lines
+             (reduce (partial add-starts total-width total-height num-lines) [(transient []) base-p])
+             (first)
+             (persistent!))))))
 
 (defn add-line-spacing
   "Calculates the baseline for a flex layout"
diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc
index bbc07180e..40727cf44 100644
--- a/common/src/app/common/geom/shapes/modifiers.cljc
+++ b/common/src/app/common/geom/shapes/modifiers.cljc
@@ -8,6 +8,8 @@
   (:require
    [app.common.data :as d]
    [app.common.data.macros :as dm]
+   [app.common.geom.bounds-map :as cgb]
+   [app.common.geom.modif-tree :as cgt]
    [app.common.geom.point :as gpt]
    [app.common.geom.shapes.common :as gco]
    [app.common.geom.shapes.constraints :as gct]
@@ -17,6 +19,7 @@
    [app.common.geom.shapes.pixel-precision :as gpp]
    [app.common.geom.shapes.points :as gpo]
    [app.common.geom.shapes.transforms :as gtr]
+   [app.common.geom.shapes.tree-seq :as cgst]
    [app.common.pages.helpers :as cph]
    [app.common.types.modifiers :as ctm]
    [app.common.types.shape.layout :as ctl]
@@ -30,74 +33,6 @@
 ;;                           [(get-in objects [k :name]) v]))
 ;;                    modif-tree))))
 
-(defn- get-children-seq
-  "Given an id returns a sequence of its children"
-  [id objects]
-
-  (->> (tree-seq
-        #(d/not-empty? (dm/get-in objects [% :shapes]))
-        #(dm/get-in objects [% :shapes])
-        id)
-       (map #(get objects %))))
-
-(defn- resolve-tree
-  "Given the ids that have changed search for layout roots to recalculate"
-  [ids objects]
-  (dm/assert! (or (nil? ids) (set? ids)))
-
-  (let [;; Finds the tree root for the current id
-        get-tree-root
-        (fn [id]
-          (loop [current id
-                 result  id]
-            (let [shape (get objects current)]
-              (if (or (not ^boolean shape) (= uuid/zero current))
-                result
-                (let [parent-id (dm/get-prop shape :parent-id)
-                      parent    (get objects parent-id)]
-                  (cond
-                    ;; Frame found, but not layout we return the last layout found (or the id)
-                    (and ^boolean (cph/frame-shape? parent)
-                         (not ^boolean (ctl/any-layout? parent)))
-                    result
-
-                    ;; Layout found. We continue upward but we mark this layout
-                    (ctl/any-layout? parent)
-                    (recur parent-id parent-id)
-
-                    ;; If group or boolean or other type of group we continue with the last result
-                    :else
-                    (recur parent-id result)))))))
-
-        ;; Given some roots retrieves the minimum number of tree roots
-        search-common-roots
-        (fn [result id]
-          (if (= id uuid/zero)
-            result
-            (let [root (get-tree-root id)
-
-                  ;; Remove the children from the current root
-                  result
-                  (if ^boolean (cph/has-children? objects root)
-                    (into #{} (remove (partial cph/is-child? objects root)) result)
-                    result)
-
-                  contains-parent?
-                  (->> (cph/get-parent-ids objects root)
-                       (some (partial contains? result)))]
-
-              (if (not contains-parent?)
-                (conj result root)
-                result))))
-
-        result
-        (->> (reduce search-common-roots #{} ids)
-             (mapcat #(get-children-seq % objects)))]
-
-    (if (contains? ids uuid/zero)
-      (cons (get objects uuid/zero) result)
-      result)))
-
 (defn- set-children-modifiers
   "Propagates the modifiers from a parent too its children applying constraints if necesary"
   [modif-tree children objects bounds parent transformed-parent-bounds ignore-constraints]
@@ -108,85 +43,48 @@
       modif-tree
 
       (ctm/only-move? modifiers)
-      (loop [modif-tree modif-tree
-             children (seq children)]
-        (if-let [current (first children)]
-          (recur (update-in modif-tree [current :modifiers] ctm/add-modifiers modifiers)
-                 (rest children))
-          modif-tree))
+      (reduce #(cgt/add-modifiers %1 %2 modifiers) modif-tree children)
 
       ;; Check the constraints, then resize
       :else
       (let [parent-id (:id parent)
             parent-bounds (gtr/transform-bounds @(get bounds parent-id) (ctm/select-parent modifiers))]
-        (loop [modif-tree modif-tree
-               children (seq children)]
-          (if (empty? children)
-            modif-tree
-            (let [child-id        (first children)
-                  child           (get objects child-id)]
-              (if (some? child)
-                (let [child-bounds    @(get bounds child-id)
-                      child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints child-bounds parent-bounds transformed-parent-bounds)]
-                  (recur (cond-> modif-tree
-                           (not (ctm/empty? child-modifiers))
-                           (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))
-                         (rest children)))
-                (recur modif-tree (rest children))))))))))
+        (->> children
+             (reduce
+              (fn [modif-tree child-id]
+                (if-let [child (get objects child-id)]
+                  (let [child-bounds @(get bounds child-id)
+                        child-modifiers
+                        (gct/calc-child-modifiers
+                         parent child modifiers ignore-constraints
+                         child-bounds
+                         parent-bounds transformed-parent-bounds)]
 
-(defn get-group-bounds
-  [objects bounds modif-tree shape]
-  (let [shape-id (:id shape)
-        modifiers (-> (dm/get-in modif-tree [shape-id :modifiers])
-                      (ctm/select-geometry))
-
-        children (cph/get-immediate-children objects shape-id)]
-
-    (cond
-      (and (cph/mask-shape? shape) (seq children))
-      (get-group-bounds objects bounds modif-tree (-> children first))
-
-      (cph/group-shape? shape)
-      (let [;; Transform here to then calculate the bounds relative to the transform
-            current-bounds
-            (cond-> @(get bounds shape-id)
-              (not (ctm/empty? modifiers))
-              (gtr/transform-bounds modifiers))
-
-            children-bounds
-            (->> children
-                 (mapv #(get-group-bounds objects bounds modif-tree %)))]
-        (gpo/merge-parent-coords-bounds children-bounds current-bounds))
-
-      :else
-      (cond-> @(get bounds shape-id)
-        (not (ctm/empty? modifiers))
-        (gtr/transform-bounds modifiers)))))
+                    (cgt/add-modifiers modif-tree child-id child-modifiers))
+                  modif-tree))
+              modif-tree))))))
 
 (defn- set-flex-layout-modifiers
   [modif-tree children objects bounds parent transformed-parent-bounds]
 
-  (letfn [(apply-modifiers [child]
-            [(-> (get-group-bounds objects bounds modif-tree child)
+  (letfn [(apply-modifiers [bounds child]
+            [(-> @(get bounds (:id child))
                  (gpo/parent-coords-bounds @transformed-parent-bounds))
              child])
 
           (set-child-modifiers [[layout-line modif-tree] [child-bounds child]]
             (let [[modifiers layout-line]
-                  (gcfl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line)
+                  (gcfl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line)]
+              [layout-line (cgt/add-modifiers modif-tree (:id child) modifiers)]))]
 
-                  modif-tree
-                  (cond-> modif-tree
-                    (d/not-empty? modifiers)
-                    (update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))]
+    (let [bounds (cgb/transform-bounds-map bounds objects modif-tree children)
 
-              [layout-line modif-tree]))]
-
-    (let [children     (->> children
-                            (keep (d/getf objects))
-                            (remove :hidden)
-                            (remove gco/invalid-geometry?)
-                            (map apply-modifiers))
+          children
+          (->> children
+               (keep (d/getf objects))
+               (remove :hidden)
+               (remove gco/invalid-geometry?)
+               (map (partial apply-modifiers bounds)))
 
           layout-data  (gcfl/calc-layout-data parent @transformed-parent-bounds children bounds objects)
           children     (into [] (cond-> children (not (:reverse? layout-data)) reverse))
@@ -209,24 +107,21 @@
 (defn- set-grid-layout-modifiers
   [modif-tree objects bounds parent transformed-parent-bounds]
 
-  (letfn [(apply-modifiers [child]
-            [(-> (get-group-bounds objects bounds modif-tree child)
+  (letfn [(apply-modifiers [bounds child]
+            [(-> @(get bounds (:id child))
                  (gpo/parent-coords-bounds @transformed-parent-bounds))
              child])
 
           (set-child-modifiers [modif-tree grid-data cell-data [child-bounds child]]
             (let [modifiers
-                  (gcgl/child-modifiers parent transformed-parent-bounds child child-bounds grid-data cell-data)
+                  (gcgl/child-modifiers parent transformed-parent-bounds child child-bounds grid-data cell-data)]
+              (cgt/add-modifiers modif-tree (:id child) modifiers)))]
 
-                  modif-tree
-                  (cond-> modif-tree
-                    (d/not-empty? modifiers)
-                    (update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))]
-              modif-tree))]
-    (let [children     (->> (cph/get-immediate-children objects (:id parent))
-                            (remove :hidden)
-                            (remove gco/invalid-geometry?)
-                            (map apply-modifiers))
+    (let [bounds (cgb/transform-bounds-map bounds objects modif-tree (:shapes parent))
+
+          children
+          (->> (cph/get-immediate-children objects (:id parent) {:remove-hidden true})
+               (map (partial apply-modifiers bounds)))
           grid-data    (gcgl/calc-layout-data parent @transformed-parent-bounds children bounds objects)]
       (loop [modif-tree modif-tree
              bound+child (first children)
@@ -239,6 +134,71 @@
             (recur modif-tree (first pending) (rest pending)))
           modif-tree)))))
 
+(defn- set-modifiers-constraints
+  "Propagate modifiers to its children"
+  [objects bounds ignore-constraints modif-tree parent]
+  (let [parent-id      (:id parent)
+        children       (:shapes parent)
+        root?          (= uuid/zero parent-id)
+        modifiers      (-> (dm/get-in modif-tree [parent-id :modifiers])
+                           (ctm/select-geometry))
+        has-modifiers? (ctm/child-modifiers? modifiers)
+        parent?        (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
+        transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))]
+
+    (cond-> modif-tree
+      (and has-modifiers? parent? (not root?))
+      (set-children-modifiers children objects bounds parent transformed-parent-bounds ignore-constraints))))
+
+(defn- set-modifiers-layout
+  "Propagate modifiers to its children"
+  ([objects bounds ignore-constraints parent]
+   (set-modifiers-layout objects bounds ignore-constraints {} parent))
+  ([objects bounds ignore-constraints modif-tree parent]
+   (let [parent-id       (:id parent)
+         root?           (= uuid/zero parent-id)
+         modifiers       (-> (dm/get-in modif-tree [parent-id :modifiers])
+                             (ctm/select-geometry))
+         has-modifiers?  (ctm/child-modifiers? modifiers)
+         flex-layout?    (ctl/flex-layout? parent)
+         grid-layout?    (ctl/grid-layout? parent)
+         parent?         (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
+
+         transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))
+
+         children-modifiers
+         (if (or flex-layout? grid-layout?)
+           (->> (:shapes parent)
+                (filter #(ctl/layout-absolute? objects %)))
+           (:shapes parent))
+
+         children-layout
+         (when (or flex-layout? grid-layout?)
+           (->> (:shapes parent)
+                (remove #(ctl/layout-absolute? objects %))))]
+
+     (cond-> modif-tree
+       (and has-modifiers? parent? (not root?))
+       (set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints)
+
+       flex-layout?
+       (set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)
+
+       grid-layout?
+       (set-grid-layout-modifiers objects bounds parent transformed-parent-bounds)))))
+
+(defn propagate-modifiers-constraints
+  ([objects bounds ignore-constraints shapes]
+   (propagate-modifiers-constraints objects bounds ignore-constraints {} shapes))
+  ([objects bounds ignore-constraints modif-tree shapes]
+   (reduce #(set-modifiers-constraints objects bounds ignore-constraints %1 %2) modif-tree shapes)))
+
+(defn propagate-modifiers-layouts
+  ([objects bounds ignore-constraints shapes]
+   (propagate-modifiers-layouts objects bounds ignore-constraints {} shapes))
+  ([objects bounds ignore-constraints modif-tree shapes]
+   (reduce #(set-modifiers-layout objects bounds ignore-constraints %1 %2) modif-tree shapes)))
+
 (defn- calc-auto-modifiers
   "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes"
   [objects bounds parent]
@@ -248,14 +208,16 @@
         set-parent-auto-width
         (fn [modifiers auto-width]
           (let [origin        (gpo/origin @parent-bounds)
-                scale-width   (/ auto-width (gpo/width-points @parent-bounds))]
+                current-width  (gpo/width-points @parent-bounds)
+                scale-width   (/ auto-width current-width)]
             (-> modifiers
                 (ctm/resize (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
 
         set-parent-auto-height
         (fn [modifiers auto-height]
           (let [origin        (gpo/origin @parent-bounds)
-                scale-height (/ auto-height (gpo/height-points @parent-bounds))]
+                current-height (gpo/height-points @parent-bounds)
+                scale-height (/ auto-height current-height)]
             (-> modifiers
                 (ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))
 
@@ -264,7 +226,7 @@
                       (remove gco/invalid-geometry?))
 
         content-bounds
-        (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
+        (when (and (d/not-empty? children) (ctl/auto? parent))
           (cond
             (ctl/flex-layout? parent)
             (gcfl/layout-content-bounds bounds parent children objects)
@@ -285,189 +247,54 @@
       (and (some? auto-height) (ctl/auto-height? parent))
       (set-parent-auto-height auto-height))))
 
-(defn- propagate-modifiers-constraints
-  "Propagate modifiers to its children"
-  [objects bounds ignore-constraints modif-tree parent]
-  (let [parent-id      (:id parent)
-        children       (:shapes parent)
-        root?          (= uuid/zero parent-id)
-        modifiers      (-> (dm/get-in modif-tree [parent-id :modifiers])
-                           (ctm/select-geometry))
-        has-modifiers? (ctm/child-modifiers? modifiers)
-        parent?        (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
-        transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))]
+(defn find-auto-layouts
+  [objects shapes]
 
-    (cond-> modif-tree
-      (and has-modifiers? parent? (not root?))
-      (set-children-modifiers children objects bounds parent transformed-parent-bounds ignore-constraints))))
-
-(defn- propagate-modifiers-layout
-  "Propagate modifiers to its children"
-  [objects bounds ignore-constraints [modif-tree autolayouts] parent]
-  (let [parent-id      (:id parent)
-        root?          (= uuid/zero parent-id)
-        modifiers      (-> (dm/get-in modif-tree [parent-id :modifiers])
-                           (ctm/select-geometry))
-        has-modifiers? (ctm/child-modifiers? modifiers)
-        flex-layout?   (ctl/flex-layout? parent)
-        grid-layout?   (ctl/grid-layout? parent)
-        auto?          (or (ctl/auto-height? parent) (ctl/auto-width? parent))
-        fill-with-grid? (and (ctl/grid-layout? objects (:parent-id parent))
-                             (or (ctl/fill-width? parent) (ctl/fill-height? parent)))
-        parent?        (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
-
-        transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))
-
-        children-modifiers
-        (if (or flex-layout? grid-layout?)
-          (->> (:shapes parent)
-               (filter #(ctl/layout-absolute? objects %)))
-          (:shapes parent))
-
-        children-layout
-        (when (or flex-layout? grid-layout?)
-          (->> (:shapes parent)
-               (remove #(ctl/layout-absolute? objects %))))]
-
-    [(cond-> modif-tree
-       (and has-modifiers? parent? (not root?))
-       (set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints)
-
-       flex-layout?
-       (set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)
-
-       grid-layout?
-       (set-grid-layout-modifiers objects bounds parent transformed-parent-bounds))
-
-     ;; Auto-width/height can change the positions in the parent so we need to recalculate
-     ;; also if the child is fill width/height inside a grid layout
-     (cond-> autolayouts (or auto? fill-with-grid?) (conj (:id parent)))]))
-
-(defn- apply-structure-modifiers
-  [objects modif-tree]
-  (letfn [(update-children-structure-modifiers
-            [objects ids modifiers]
-            (reduce #(update %1 %2 ctm/apply-structure-modifiers modifiers) objects ids))
-
-          (apply-shape [objects [id {:keys [modifiers]}]]
-            (cond-> objects
-              (ctm/has-structure? modifiers)
-              (update id ctm/apply-structure-modifiers modifiers)
-
-              (and (ctm/has-structure? modifiers)
-                   (ctm/has-structure-child? modifiers))
-              (update-children-structure-modifiers
-               (cph/get-children-ids objects id)
-               (ctm/select-child-structre-modifiers modifiers))))]
-    (reduce apply-shape objects modif-tree)))
-
-(defn merge-modif-tree
-  [modif-tree other-tree]
-  (reduce (fn [modif-tree [id {:keys [modifiers]}]]
-            (update-in modif-tree [id :modifiers] ctm/add-modifiers modifiers))
-          modif-tree
-          other-tree))
-
-(defn transform-bounds
-  ([bounds objects modif-tree]
-   (transform-bounds bounds objects modif-tree (->> (keys modif-tree) (map #(get objects %)))))
-  ([bounds objects modif-tree tree-seq]
-
-   (loop [result bounds
-          shapes (reverse tree-seq)]
-     (if (empty? shapes)
-       result
-
-       (let [shape (first shapes)
-             new-bounds (delay (get-group-bounds objects bounds modif-tree shape))
-             result (assoc result (:id shape) new-bounds)]
-         (recur result (rest shapes)))))))
-
-(defn reflow-layout
-  [objects old-modif-tree bounds ignore-constraints id]
-
-  (let [tree-seq (get-children-seq id objects)
-
-        [modif-tree _]
-        (reduce
-         #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
-         tree-seq)
-
-        bounds (transform-bounds bounds objects modif-tree tree-seq)
-
-        modif-tree (merge-modif-tree old-modif-tree modif-tree)]
-    [modif-tree bounds]))
+  (letfn [(mk-check-auto-layout [objects]
+            (fn [shape]
+              ;; Auto-width/height can change the positions in the parent so we need to recalculate
+              ;; also if the child is fill width/height inside a grid layout
+              (when (or (ctl/auto? shape)
+                        (and (ctl/grid-layout? objects (:parent-id shape)) (ctl/fill? shape)))
+                (:id shape))))]
+    (into (d/ordered-set)
+          (keep (mk-check-auto-layout objects))
+          shapes)))
 
 (defn sizing-auto-modifiers
   "Recalculates the layouts to adjust the sizing: auto new sizes"
   [modif-tree sizing-auto-layouts objects bounds ignore-constraints]
-  (let [;; Step-1 resize the auto-width/height. Reflow the parents if they are also auto-width/height
-        [modif-tree bounds to-reflow]
-        (loop [modif-tree modif-tree
-               bounds bounds
-               sizing-auto-layouts (reverse sizing-auto-layouts)
-               to-reflow #{}]
-          (if-let [current (first sizing-auto-layouts)]
-            (let [parent-base (get objects current)
 
-                  [modif-tree bounds]
-                  (if (contains? to-reflow current)
-                    (reflow-layout objects modif-tree bounds ignore-constraints current)
-                    [modif-tree bounds])
+  (let [calculate-modifiers
+        (fn [[modif-tree bounds] layout-id]
+          (let [layout (get objects layout-id)
+                auto-modifiers (calc-auto-modifiers objects bounds layout)]
 
-                  auto-resize-modifiers
-                  (calc-auto-modifiers objects bounds parent-base)
+            (if (and (ctm/empty? auto-modifiers) (not (ctl/grid-layout? layout)))
+              [modif-tree bounds]
 
-                  to-reflow
-                  (cond-> to-reflow
-                    (contains? to-reflow current)
-                    (disj current))]
+              (let [from-layout
+                    (->> (cph/get-parent-ids objects layout-id)
+                         (d/seek sizing-auto-layouts))
 
-              (if (and (ctm/empty? auto-resize-modifiers)
-                       (not (ctl/grid-layout? objects (:parent-id parent-base))))
-                (recur modif-tree
-                       bounds
-                       (rest sizing-auto-layouts)
-                       to-reflow)
+                    shapes
+                    (if from-layout
+                      (cgst/resolve-subtree from-layout layout-id objects)
+                      (cgst/resolve-tree #{layout-id} objects))
 
-                (let [resize-modif-tree {current {:modifiers auto-resize-modifiers}}
+                    auto-modif-tree {layout-id {:modifiers auto-modifiers}}
+                    auto-modif-tree (propagate-modifiers-layouts objects bounds ignore-constraints auto-modif-tree shapes)
 
-                      tree-seq (get-children-seq current objects)
-
-                      [resize-modif-tree _]
-                      (reduce
-                       #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [resize-modif-tree #{}]
-                       tree-seq)
-
-                      bounds (transform-bounds bounds objects resize-modif-tree tree-seq)
-
-                      modif-tree (merge-modif-tree modif-tree resize-modif-tree)
-
-                      to-reflow
-                      (cond-> to-reflow
-                        (and (ctl/any-layout-descent? objects parent-base)
-                             (not= uuid/zero (:frame-id parent-base)))
-                        (conj (:frame-id parent-base)))]
-                  (recur modif-tree
-                         bounds
-                         (rest sizing-auto-layouts)
-                         to-reflow))))
-            [modif-tree bounds to-reflow]))
-
-        ;; Step-2: After resizing we still need to reflow the layout parents that are not auto-width/height
-
-        tree-seq (resolve-tree to-reflow objects)
-
-        [reflow-modif-tree _]
-        (reduce
-         #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
-         tree-seq)
-
-        result (merge-modif-tree modif-tree reflow-modif-tree)]
-
-    result))
+                    bounds (cgb/transform-bounds-map bounds objects auto-modif-tree)
+                    modif-tree (cgt/merge-modif-tree modif-tree auto-modif-tree)]
+                [modif-tree bounds]))))]
+    (->> sizing-auto-layouts
+         (reverse)
+         (reduce calculate-modifiers [modif-tree bounds])
+         (first))))
 
 (defn set-objects-modifiers
+  "Applies recursively the modifiers and calculate the layouts and constraints for all the items to be placed correctly"
   ([modif-tree objects]
    (set-objects-modifiers modif-tree objects nil))
 
@@ -476,43 +303,59 @@
 
   ([old-modif-tree modif-tree objects
     {:keys [ignore-constraints snap-pixel? snap-precision snap-ignore-axis]
-     :or {ignore-constraints false snap-pixel? false snap-precision 1 snap-ignore-axis nil}}]
+     :or {ignore-constraints false
+          snap-pixel? false
+          snap-precision 1
+          snap-ignore-axis nil}}]
 
-   (let [objects (-> objects
-                     (cond-> (some? old-modif-tree)
-                       (apply-structure-modifiers old-modif-tree))
-                     (apply-structure-modifiers modif-tree))
+   (let [;; Apply structure modifiers. Things that are not related to geometry
+         objects
+         (-> objects
+             (cond-> (some? old-modif-tree)
+               (cgt/apply-structure-modifiers old-modif-tree))
+             (cgt/apply-structure-modifiers modif-tree))
 
+         ;; Creates the sequence of shapes with the shapes that are modified
+         shapes-tree
+         (cgst/resolve-tree (-> modif-tree keys set) objects)
+
+         bounds-map
+         (cond-> (cgb/objects->bounds-map objects)
+           (some? old-modif-tree)
+           (cgb/transform-bounds-map objects old-modif-tree))
+
+         ;; Round the transforms if the snap-to-pixel is active
          modif-tree
          (cond-> modif-tree
-           snap-pixel? (gpp/adjust-pixel-precision objects snap-precision snap-ignore-axis))
+           snap-pixel?
+           (gpp/adjust-pixel-precision objects snap-precision snap-ignore-axis))
 
-         bounds (d/lazy-map (keys objects) #(gco/shape->points (get objects %)))
-         bounds (cond-> bounds
-                  (some? old-modif-tree)
-                  (transform-bounds objects old-modif-tree))
+         ;; Propagates the modifiers to the normal shapes with constraints
+         modif-tree
+         (propagate-modifiers-constraints objects bounds-map ignore-constraints modif-tree shapes-tree)
 
-         shapes-tree (resolve-tree (-> modif-tree keys set) objects)
+         bounds-map
+         (cgb/transform-bounds-map bounds-map objects modif-tree)
 
-         ;; Calculate the input transformation and constraints
-         modif-tree (reduce #(propagate-modifiers-constraints objects bounds ignore-constraints %1 %2) modif-tree shapes-tree)
-         bounds (transform-bounds bounds objects modif-tree shapes-tree)
-
-         [modif-tree-layout sizing-auto-layouts]
-         (reduce #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}] shapes-tree)
-
-         modif-tree (merge-modif-tree modif-tree modif-tree-layout)
-
-         ;; Calculate hug layouts positions
-         bounds (transform-bounds bounds objects modif-tree-layout shapes-tree)
+         modif-tree-layout
+         (propagate-modifiers-layouts objects bounds-map ignore-constraints shapes-tree)
 
          modif-tree
-         (-> modif-tree
-             (sizing-auto-modifiers sizing-auto-layouts objects bounds ignore-constraints))
+         (cgt/merge-modif-tree modif-tree modif-tree-layout)
+
+         ;; Calculate hug layouts positions
+         bounds-map
+         (cgb/transform-bounds-map bounds-map objects modif-tree-layout)
+
+         ;; Find layouts with auto width/height
+         sizing-auto-layouts (find-auto-layouts objects shapes-tree)
+
+         modif-tree
+         (sizing-auto-modifiers modif-tree sizing-auto-layouts objects bounds-map ignore-constraints)
 
          modif-tree
          (if old-modif-tree
-           (merge-modif-tree old-modif-tree modif-tree)
+           (cgt/merge-modif-tree old-modif-tree modif-tree)
            modif-tree)]
 
      ;;#?(:cljs
diff --git a/common/src/app/common/geom/shapes/points.cljc b/common/src/app/common/geom/shapes/points.cljc
index 8783d76f3..83c110bb7 100644
--- a/common/src/app/common/geom/shapes/points.cljc
+++ b/common/src/app/common/geom/shapes/points.cljc
@@ -116,45 +116,47 @@
   (if (empty? child-bounds)
     parent-bounds
 
-    (let [rh [p1 p2]
-          rv [p1 p4]
+    (if (and (axis-aligned? child-bounds) (axis-aligned? parent-bounds))
+      child-bounds
 
-          hv (gpt/to-vec p1 p2)
-          vv (gpt/to-vec p1 p4)
+      (let [rh [p1 p2]
+            rv [p1 p4]
 
-          ph #(gpt/add p1 (gpt/scale hv %))
-          pv #(gpt/add p1 (gpt/scale vv %))
+            hv (gpt/to-vec p1 p2)
+            vv (gpt/to-vec p1 p4)
 
-          find-boundary-ts
-          (fn [[th-min th-max tv-min tv-max] current-point]
-            (let [cth (project-t current-point rh vv)
-                  ctv (project-t current-point rv hv)]
-              [(mth/min th-min cth)
-               (mth/max th-max cth)
-               (mth/min tv-min ctv)
-               (mth/max tv-max ctv)]))
+            ph #(gpt/add p1 (gpt/scale hv %))
+            pv #(gpt/add p1 (gpt/scale vv %))
 
-          [th-min th-max tv-min tv-max]
-          (->> child-bounds
-               (filter #(and (d/num? (:x %)) (d/num? (:y %))))
-               (reduce find-boundary-ts [##Inf ##-Inf ##Inf ##-Inf]))
+            find-boundary-ts
+            (fn [[th-min th-max tv-min tv-max] current-point]
+              (let [cth (project-t current-point rh vv)
+                    ctv (project-t current-point rv hv)]
+                [(mth/min th-min cth)
+                 (mth/max th-max cth)
+                 (mth/min tv-min ctv)
+                 (mth/max tv-max ctv)]))
 
-          minv-start (pv tv-min)
-          minv-end   (gpt/add minv-start hv)
-          minh-start (ph th-min)
-          minh-end   (gpt/add minh-start vv)
+            [th-min th-max tv-min tv-max]
+            (->> child-bounds
+                 (filter #(and (d/num? (:x %)) (d/num? (:y %))))
+                 (reduce find-boundary-ts [##Inf ##-Inf ##Inf ##-Inf]))
 
-          maxv-start (pv tv-max)
-          maxv-end   (gpt/add maxv-start hv)
-          maxh-start (ph th-max)
-          maxh-end   (gpt/add maxh-start vv)
+            minv-start (pv tv-min)
+            minv-end   (gpt/add minv-start hv)
+            minh-start (ph th-min)
+            minh-end   (gpt/add minh-start vv)
 
-          i1 (gsi/line-line-intersect minv-start minv-end minh-start minh-end)
-          i2 (gsi/line-line-intersect minv-start minv-end maxh-start maxh-end)
-          i3 (gsi/line-line-intersect maxv-start maxv-end maxh-start maxh-end)
-          i4 (gsi/line-line-intersect maxv-start maxv-end minh-start minh-end)]
+            maxv-start (pv tv-max)
+            maxv-end   (gpt/add maxv-start hv)
+            maxh-start (ph th-max)
+            maxh-end   (gpt/add maxh-start vv)
 
-      [i1 i2 i3 i4])))
+            i1 (gsi/line-line-intersect minv-start minv-end minh-start minh-end)
+            i2 (gsi/line-line-intersect minv-start minv-end maxh-start maxh-end)
+            i3 (gsi/line-line-intersect maxv-start maxv-end maxh-start maxh-end)
+            i4 (gsi/line-line-intersect maxv-start maxv-end minh-start minh-end)]
+        [i1 i2 i3 i4]))))
 
 (defn merge-parent-coords-bounds
   [bounds parent-bounds]
diff --git a/common/src/app/common/geom/shapes/tree_seq.cljc b/common/src/app/common/geom/shapes/tree_seq.cljc
new file mode 100644
index 000000000..77932154b
--- /dev/null
+++ b/common/src/app/common/geom/shapes/tree_seq.cljc
@@ -0,0 +1,93 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.common.geom.shapes.tree-seq
+  (:require
+   [app.common.data :as d]
+   [app.common.data.macros :as dm]
+   [app.common.geom.shapes.min-size-layout]
+   [app.common.pages.helpers :as cph]
+   [app.common.types.shape.layout :as ctl]
+   [app.common.uuid :as uuid]))
+
+(defn get-children-seq
+  "Given an id returns a sequence of its children"
+  [id objects]
+  (->> (tree-seq
+        #(d/not-empty? (dm/get-in objects [% :shapes]))
+        #(dm/get-in objects [% :shapes])
+        id)
+       (map #(get objects %))))
+
+;; Finds the tree root for the current id
+(defn get-reflow-root
+  ([id objects]
+   (get-reflow-root id id objects))
+
+  ([current last-root objects]
+   (let [shape (get objects current)]
+     (if (or (not ^boolean shape) (= uuid/zero current))
+       last-root
+       (let [parent-id (dm/get-prop shape :parent-id)
+             parent    (get objects parent-id)]
+         (cond
+           ;; Frame found, but not layout we return the last layout found (or the id)
+           (and ^boolean (cph/frame-shape? parent)
+                (not ^boolean (ctl/any-layout? parent)))
+           last-root
+
+           ;; Auto-Layout found. We continue upward but we mark this layout
+           (and (ctl/any-layout? parent) (ctl/auto? parent))
+           (recur parent-id parent-id objects)
+
+           (ctl/any-layout? parent)
+           parent-id
+
+           ;; If group or boolean or other type of group we continue with the last result
+           :else
+           (recur parent-id last-root objects)))))))
+
+;; Given some roots retrieves the minimum number of tree roots
+(defn search-common-roots
+  [ids objects]
+  (let [find-root
+        (fn [roots id]
+          (if (= id uuid/zero)
+            roots
+            (let [root (get-reflow-root id objects)
+                  ;; Remove the children from the current root
+                  roots
+                  (if ^boolean (cph/has-children? objects root)
+                    (into #{} (remove (partial cph/is-child? objects root)) roots)
+                    roots)
+
+                  contains-parent?
+                  (->> (cph/get-parent-ids objects root)
+                       (some (partial contains? roots)))]
+
+              (cond-> roots
+                (not contains-parent?)
+                (conj root)))))]
+    (reduce find-root #{} ids)))
+
+(defn resolve-tree
+  "Given the ids that have changed search for layout roots to recalculate"
+  [ids objects]
+  (dm/assert! (or (nil? ids) (set? ids)))
+
+  (let [child-seq
+        (->> (search-common-roots ids objects)
+             (mapcat #(get-children-seq % objects)))]
+
+    (if (contains? ids uuid/zero)
+      (cons (get objects uuid/zero) child-seq)
+      child-seq)))
+
+(defn resolve-subtree
+  "Resolves the subtree but only partialy from-to the parameters"
+  [from-id to-id objects]
+  (->> (get-children-seq from-id objects)
+       (d/take-until #(= (:id %) to-id))))
diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc
index b8e9eee42..be402f5f1 100644
--- a/common/src/app/common/pages/helpers.cljc
+++ b/common/src/app/common/pages/helpers.cljc
@@ -68,9 +68,11 @@
        (= :bool (dm/get-prop shape :type))))
 
 (defn group-like-shape?
-  [shape]
-  (or ^boolean (group-shape? shape)
-      ^boolean (bool-shape? shape)))
+  ([objects id]
+   (group-like-shape? (get objects id)))
+  ([shape]
+   (or ^boolean (group-shape? shape)
+       ^boolean (bool-shape? shape))))
 
 (defn text-shape?
   [shape]
@@ -160,6 +162,13 @@
         (recur (conj result parent-id) parent-id)
         result))))
 
+(defn get-parent-ids-seq
+  "Returns a vector of parents of the specified shape."
+  [objects shape-id]
+  (let [parent-id (get-parent-id objects shape-id)]
+    (when (and (some? parent-id) (not= parent-id shape-id))
+      (lazy-seq (cons parent-id (get-parent-ids-seq objects parent-id))))))
+
 (defn get-parents
   "Returns a vector of parents of the specified shape."
   [objects shape-id]
@@ -169,6 +178,17 @@
         (recur (conj result (get objects parent-id)) parent-id)
         result))))
 
+(defn get-parent-seq
+  "Returns a vector of parents of the specified shape."
+  ([objects shape-id]
+   (get-parent-seq objects (get objects shape-id) shape-id))
+
+  ([objects shape shape-id]
+   (let [parent-id (dm/get-prop shape :parent-id)
+         parent    (get objects parent-id)]
+     (when (and (some? parent) (not= parent-id shape-id))
+       (lazy-seq (cons parent (get-parent-seq objects parent parent-id)))))))
+
 (defn get-parents-with-self
   [objects id]
   (let [lookup (d/getf objects)]
diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc
index 7c0b6a97a..45e041a80 100644
--- a/common/src/app/common/types/shape/layout.cljc
+++ b/common/src/app/common/types/shape/layout.cljc
@@ -277,6 +277,12 @@
   ([child]
    (= :fill (:layout-item-v-sizing child))))
 
+(defn fill?
+  ([objects id]
+   (or (fill-height? objects id) (fill-width? objects id)))
+  ([shape]
+   (or (fill-height? shape) (fill-width? shape))))
+
 (defn auto-width?
   ([objects id]
    (= :auto (dm/get-in objects [id :layout-item-h-sizing])))
@@ -289,6 +295,12 @@
   ([child]
    (= :auto (:layout-item-v-sizing child))))
 
+(defn auto?
+  ([objects id]
+   (or (auto-height? objects id) (auto-width? objects id)))
+  ([shape]
+   (or (auto-height? shape) (auto-width? shape))))
+
 (defn col?
   ([objects id]
    (col? (get objects id)))