diff --git a/src/lib/vRemixicon.js b/src/lib/vRemixicon.js
index 432e66a1..1b6faeb0 100644
--- a/src/lib/vRemixicon.js
+++ b/src/lib/vRemixicon.js
@@ -137,6 +137,7 @@ import {
   riCheckboxCircleLine,
   riLightbulbFlashLine,
   riIncreaseDecreaseLine,
+  riRoundedCorner,
 } from 'v-remixicon/icons';
 
 export const icons = {
@@ -277,6 +278,7 @@ export const icons = {
   riCheckboxCircleLine,
   riLightbulbFlashLine,
   riIncreaseDecreaseLine,
+  riRoundedCorner,
   mdiEqual: 'M19,10H5V8H19V10M19,16H5V14H19V16Z',
   mdiPackageVariantClosed:
     'M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L10.11,5.22L16,8.61L17.96,7.5L12,4.15M6.04,7.5L12,10.85L13.96,9.75L8.08,6.35L6.04,7.5M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z',
diff --git a/src/locales/en/newtab.json b/src/locales/en/newtab.json
index 2cf0a726..22877782 100644
--- a/src/locales/en/newtab.json
+++ b/src/locales/en/newtab.json
@@ -250,6 +250,9 @@
     "autoAlign": {
       "title": "Auto-align"
     },
+    "snakeIt": {
+      "title": "snake-it"
+    },
     "blocksFolder": {
       "title": "Blocks folder",
       "add": "Add blocks to folder",
diff --git a/src/newtab/pages/workflows/[id].vue b/src/newtab/pages/workflows/[id].vue
index 00f4f1e3..3a1ecb2e 100644
--- a/src/newtab/pages/workflows/[id].vue
+++ b/src/newtab/pages/workflows/[id].vue
@@ -219,6 +219,13 @@
               >
                 <v-remixicon name="riMagicLine" />
               </button>
+              <button
+                v-tooltip="t('workflow.snakeIt.title')"
+                class="control-button hoverable ml-2"
+                @click="snakeIt"
+              >
+                <v-remixicon name="riRoundedCorner" />
+              </button>
             </template>
           </workflow-editor>
           <editor-local-saved-blocks
@@ -1030,13 +1037,80 @@ function autoAlign() {
   });
 
   editor.value.applyNodeChanges(nodeChanges);
-  editor.value.fitView();
+  setTimeout(() => {
+    editor.value.fitView();
+  }, 0);
 
   setTimeout(() => {
     state.dataChanged = true;
     state.animateBlocks = false;
   }, 500);
 }
+async function snakeIt() {
+  state.animateBlocks = true;
+
+  const maxStepsPerRow = 4;
+  const stepWidth = 300;
+  const stepHeight = 150;
+  let currentRow = 0;
+  let currentCol = 0;
+
+  const graph = new dagre.graphlib.Graph();
+  graph.setGraph({
+    rankdir: 'LR',
+    ranksep: 100,
+    ranker: 'tight-tree',
+  });
+  graph.setDefaultEdgeLabel(() => ({}));
+
+  const nodes = editor.value.getNodes.value.filter(
+    ({ label, parentNode }) => label !== 'blocks-group-2' && !parentNode
+  );
+
+  nodes.forEach(({ id, dimensions }) => {
+    graph.setNode(id, {
+      width: dimensions.width,
+      height: dimensions.height,
+    });
+  });
+
+  editor.value.getEdges.value.forEach(({ source, target, id }) => {
+    graph.setEdge(source, target, { id });
+  });
+
+  const nodeChanges = nodes.map(({ id }) => {
+    const x = currentCol * stepWidth;
+    const y = currentRow * stepHeight;
+
+    if (editorCommands.state.nodes[id]) {
+      editorCommands.state.nodes[id].position = { x, y };
+    }
+
+    currentCol = (currentCol + 1) % maxStepsPerRow;
+    if (currentCol === 0) currentRow += 1;
+
+    return {
+      id,
+      type: 'position',
+      dragging: false,
+      position: { x, y },
+    };
+  });
+
+  editor.value.applyNodeChanges(nodeChanges);
+
+  await new Promise((resolve) => {
+    setTimeout(resolve, 0);
+  });
+  editor.value.fitView();
+
+  await new Promise((resolve) => {
+    setTimeout(resolve, 500);
+  });
+  state.dataChanged = true;
+  state.animateBlocks = false;
+}
+
 function toggleSidebar() {
   state.showSidebar = !state.showSidebar;
   localStorage.setItem('workflow:sidebar', state.showSidebar);