diff --git a/src/calng/CalibrationManager.py b/src/calng/CalibrationManager.py
index a8367b125a3381efe53c432a075311781eeb02f0..4213660758b6690a9ba4c8c46a9653c3c4040427 100644
--- a/src/calng/CalibrationManager.py
+++ b/src/calng/CalibrationManager.py
@@ -377,8 +377,8 @@ class CalibrationManager(DeviceClientBase, Device):
 
     geometryDevice = String(
         displayedName='Geometry device',
-        description='[NYI] Device ID for a geometry device defining the '
-                    'detector layout and module positions.',
+        description='Device ID for a geometry device defining the detector '
+                    'layout and module positions.',
         accessMode=AccessMode.INITONLY,
         assignment=Assignment.MANDATORY)
 
@@ -1281,7 +1281,6 @@ class CalibrationManager(DeviceClientBase, Device):
                     background(_activate_matcher(matcher_device_id))
 
         # Instantiate preview layer assemblers.
-        geometry_device_id = self.geometryDevice.value
         for layer, output_pipeline, server in self.previewLayers.value:
             assembler_device_id = device_id_templates['assembler'].format(
                 layer=layer)
@@ -1295,8 +1294,7 @@ class CalibrationManager(DeviceClientBase, Device):
                      f'@{device_id}:{output_pipeline}')
                 for (virtual_id, device_id)
                 in correct_device_id_by_module.items()]
-            config['geometryInput.connectedOutputChannels'] = [
-                f'{geometry_device_id}:geometryOutput']
+            config['geometryDevice'] = self.geometryDevice.value
 
             if not await self._instantiate_device(
                 server, class_ids['assembler'], assembler_device_id, config
diff --git a/src/calng/DetectorAssembler.py b/src/calng/DetectorAssembler.py
index 7da3cc2efa5ba9174d71df31160e04032cab7b52..94418b1a621e101cff0925e27727835c8938d5cb 100644
--- a/src/calng/DetectorAssembler.py
+++ b/src/calng/DetectorAssembler.py
@@ -1,15 +1,13 @@
 import enum
 import functools
+import gzip
 import pickle
 import re
-import threading
-import time
 
 import numpy as np
 from karabo.bound import (
     FLOAT_ELEMENT,
     IMAGEDATA_ELEMENT,
-    INPUT_CHANNEL,
     NDARRAY_ELEMENT,
     NODE_ELEMENT,
     KARABO_CLASSINFO,
@@ -161,9 +159,15 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
             .reconfigurable()
             .commit(),
 
-            INPUT_CHANNEL(expected)
-            .key("geometryInput")
-            .displayedName("Geometry input")
+            STRING_ELEMENT(expected)
+            .key("geometryDevice")
+            .displayedName("Geometry device")
+            .description(
+                "The name of the device which will provide geometries. The device is "
+                "expected to provide a current geometry as a VectorChar (gzipped "
+                "pickled extra-geom geometry) element named pickledGeometry"
+            )
+            .assignmentMandatory()
             .commit(),
         )
 
@@ -180,10 +184,25 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
         self._geometry = None
         self._stack_input_buffer = None
 
-        self.KARABO_ON_DATA("geometryInput", self.receive_geometry)
         self.KARABO_SLOT(self.requestScene)
 
-        self.ask_for_geometry()
+        geometry_device = self.get("geometryDevice")
+        client = self.remote()
+        try:
+            initial_geometry = client.get(geometry_device, "pickledGeometry")
+        except RuntimeError:
+            self.log.WARN(
+                f"Failed to get initial geometry, maybe geometry device is down"
+            )
+        else:
+            self.log.INFO("Got geometry immediately after init :D")
+            self._receive_geometry(
+                geometry_device,
+                Hash("pickledGeometry", initial_geometry),
+            )
+
+        self.remote().registerDeviceMonitor(geometry_device, self._receive_geometry)
+
         self.assembled_output = self.signalSlotable.getOutputChannel("assembledOutput")
         self.preview_output = self.signalSlotable.getOutputChannel("preview.output")
         self.start()
@@ -194,10 +213,7 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
         if scene_name == "overview":
             payload = Hash("name", scene_name, "success", True)
             payload["data"] = scenes.detector_assembler_overview(
-                device_id=self.getInstanceId(),
-                geometry_device_id=self.get("geometryInput.connectedOutputChannels")[
-                    0
-                ].split(":")[0],
+                device_id=self.getInstanceId()
             )
             self.reply(
                 Hash(
@@ -213,44 +229,18 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
             params["name"] = "scene"
             return super().requestScene(params)
 
-    def receive_geometry(self, data, metadata):
-        self.log.INFO("Received a new geometry")
-        self._geometry = pickle.loads(data.get("pickledGeometry"))
+    def _receive_geometry(self, device_id, config):
+        if not config.has("pickledGeometry"):
+            return
+        self.log.INFO(f"Found geometry on {device_id}")
+        zipped_geometry = config["pickledGeometry"]
+        if len(zipped_geometry) == 0:
+            self.log.INFO("New geometry empty, will ignore update.")
+            return
+        self._geometry = pickle.loads(gzip.decompress(zipped_geometry))
         # TODO: allow multiple memory cells (extra geom notion of extra dimensions)
         self._stack_input_buffer = np.zeros(self._geometry.expected_data_shape)
 
-    def ask_for_geometry(self):
-        def runner():
-            self.log.INFO("Will ask around for a geometry")
-            max_tries = 10
-            for i in range(max_tries):
-                time.sleep(np.random.random() * 10)
-                if self._geometry is None:
-                    geometry_device_list = list(
-                        self.get("geometryInput.connectedOutputChannels")
-                    )
-                    # first check if geometry device not even connected
-                    missing_connections = set(
-                        self.get("geometryInput.missingConnections")
-                    )
-                    geometry_device_list = [
-                        channel
-                        for channel in geometry_device_list
-                        if channel not in missing_connections
-                    ]
-                    if not geometry_device_list:
-                        self.log.INFO("No geometry device connected")
-                        continue
-                    geometry_device = geometry_device_list[0].split(":")[0]
-                    self.log.INFO(f"Asking {geometry_device} for a geometry")
-                    self.signalSlotable.call(geometry_device, "sendGeometry")
-                    time.sleep(1)
-
-                if self._geometry is not None:
-                    return
-            self.log.INFO(f"Failed to get geometry in {max_tries} tries, need help")
-        threading.Thread(target=runner, daemon=True).start()
-
     def on_matched_data(self, train_id, sources):
         if self._geometry is None:
             self.log.WARN("Have not received a geometry yet, will not send anything")
@@ -344,8 +334,8 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
         self.info["timeOfFlight"] = (
             Timestamp().toTimestamp() - earliest_source_timestamp
         ) * 1000
-        self.info['sent'] += 1
-        self.info['trainId'] = train_id
+        self.info["sent"] += 1
+        self.info["trainId"] = train_id
         self.rate_out.update()
 
     def on_new_data(self, channel, data, meta):
@@ -382,19 +372,22 @@ def downsample_2d(arr, factor, reduction_fun=np.nanmax):
             (
                 arr[:-1:2],
                 arr[1::2],
-            ), axis=0
+            ),
+            axis=0,
         )
         arr = reduction_fun(
             (
                 arr[:, :-1:2],
                 arr[:, 1::2],
-            ), axis=0
+            ),
+            axis=0,
         )
     return arr
 
 
 # forward-compatible unsafe_get proposed by @haufs
 if not hasattr(DetectorAssembler, "unsafe_get"):
+
     def unsafe_get(self, key):
         """See base_correction.py"""
         return self._parameters.get(key)
diff --git a/src/calng/base_geometry.py b/src/calng/base_geometry.py
index 6ae36b7952f9342d76c37e7669330d78f4c42e18..f566e95e0a173c83631c414210e691d1f9b512b9 100644
--- a/src/calng/base_geometry.py
+++ b/src/calng/base_geometry.py
@@ -1,4 +1,5 @@
 import contextlib
+import gzip
 import logging
 import pickle
 
@@ -19,13 +20,14 @@ from karabo.middlelayer import (
     ImageData,
     Int32,
     Node,
-    OutputChannel,
     Slot,
     State,
     String,
     Unit,
     VectorChar,
+    VectorHash,
     VectorString,
+    get_instance_parent,
     slot,
 )
 from matplotlib.backends.backend_agg import FigureCanvasAgg
@@ -34,15 +36,7 @@ from ._version import version as deviceVersion
 from . import scenes
 
 
-class GeometrySchema(Configurable):
-    pickledGeometry = VectorChar(
-        displayedName="Pickled geometry",
-        assignment=Assignment.OPTIONAL,
-        defaultValue=[],
-    )
-
-
-def makeXYCoordinateNode(
+def make_x_y_coordinate_node(
     default_x, default_y, x_args=None, y_args=None, node_args=None
 ):
     class XYCoordinate(Configurable):
@@ -62,8 +56,8 @@ def makeXYCoordinateNode(
     return Node(XYCoordinate, **({} if node_args is None else node_args))
 
 
-def makeXYOffsetNode():
-    return makeXYCoordinateNode(
+def make_x_y_offset_node():
+    return make_x_y_coordinate_node(
         0,
         0,
         x_args={"unitSymbol": Unit.METER},
@@ -78,6 +72,87 @@ def makeXYOffsetNode():
     )
 
 
+def get_my_device(me):
+    parent = me
+    while not isinstance(parent, Device):
+        new_parent = get_instance_parent(parent)
+        assert new_parent is not parent, "Circular parent reference"
+        parent = new_parent
+    return parent
+
+
+# TODO: consider other history models (could be fun)
+class TweakGeometryNode(Configurable):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self._undo_stack = []
+        self._redo_stack = []
+
+    def _reset(self):
+        # clear history when new geometry is set from manual / file
+        self._undo_stack.clear()
+        self._redo_stack.clear()
+        self.undoLength = 0
+        self.redoLength = 0
+
+    @Slot(displayedName="Undo")
+    async def undo(self):
+        assert len(self._undo_stack) > 0
+        parent = get_my_device(self)
+        self._redo_stack.append(parent.geometry)
+        await parent._set_geometry(self._undo_stack.pop())
+        self.undoLength = len(self._undo_stack)
+        self.redoLength = len(self._redo_stack)
+
+    @Slot(displayedName="Redo")
+    async def redo(self):
+        parent = get_my_device(self)
+        assert len(self._redo_stack) > 0
+        self._undo_stack.append(parent.geometry)
+        await parent._set_geometry(self._redo_stack.pop())
+        self.undoLength = len(self._undo_stack)
+        self.redoLength = len(self._redo_stack)
+
+    offset = make_x_y_offset_node()
+
+    @Slot(displayedName="Add offset")
+    async def add(self):
+        parent = get_my_device(self)
+        current_geometry = parent.geometry
+        new_geometry = current_geometry.offset(
+            (self.offset.x.value, self.offset.y.value)
+        )
+        self._undo_stack.append(current_geometry)
+        self.undoLength = len(self._undo_stack)
+        await parent._set_geometry(new_geometry)
+        if self._redo_stack:
+            self._redo_stack.clear()
+            self.redoLength = 0
+
+    undoLength = Int32(
+        displayedName="Undo length",
+        defaultValue=0,
+        accessMode=AccessMode.READONLY,
+    )
+
+    redoLength = Int32(
+        displayedName="Redo length",
+        defaultValue=0,
+        accessMode=AccessMode.READONLY,
+    )
+
+
+class BaseManualGeometryConfigNode(Configurable):
+    offset = make_x_y_offset_node()
+
+    @Slot(
+        displayedName="Set manual geometry",
+        allowedStates=[State.ACTIVE],
+    )
+    async def setManual(self):
+        await get_my_device(self)._set_from_manual_config()
+
+
 class GeometryFileNode(Configurable):
     filePath = String(
         defaultValue="",
@@ -88,7 +163,7 @@ class GeometryFileNode(Configurable):
         assignment=Assignment.OPTIONAL,
         accessMode=AccessMode.RECONFIGURABLE,
     )
-    offset = makeXYOffsetNode()
+    offset = make_x_y_offset_node()
     updateManualOnLoad = Bool(
         defaultValue=True,
         displayedName="Update manual settings",
@@ -100,11 +175,18 @@ class GeometryFileNode(Configurable):
         accessMode=AccessMode.RECONFIGURABLE,
     )
 
+    @Slot(
+        displayedName="Load from file",
+        allowedStates=[State.ACTIVE],
+    )
+    async def loadFromFile(self):
+        await get_my_device(self)._load_from_file()
+
 
 class ManualGeometryBase(Device):
     __version__ = deviceVersion
     geometry_class = None  # subclass must set
-    # subclass must add slot setManual
+    # subclass must add slot manualConfigsetManual
 
     availableScenes = VectorString(
         displayedName="Available scenes",
@@ -117,31 +199,28 @@ class ManualGeometryBase(Device):
         daqPolicy=DaqPolicy.OMIT,
     )
 
+    pickledGeometry = VectorChar(
+        displayedName="Pickled geometry",
+        defaultValue=[],
+        accessMode=AccessMode.READONLY,
+    )
+
     geometryPreview = Image(
         ImageData(np.empty(0, dtype=np.uint32)),
         displayedName="Geometry preview",
         encoding=EncodingType.RGBA,
     )
 
-    geometryOutput = OutputChannel(GeometrySchema)
-
     geometryFile = Node(
         GeometryFileNode,
         displayedName="Geometry file",
         description="Allows loading geometry from CrystFEL geometry file",
     )
 
-    @Slot(
-        displayedName="Send geometry",
-        description="Send current geometry on output channel. This output channel is "
-        "typically used by assembler devices waiting for new geometries. Updating the "
-        "geometry will usually automatically cause update, but hit this slot in case "
-        "geometry is missing somewhere.",
-        allowedStates=[State.ACTIVE],
+    tweakGeometry = Node(
+        TweakGeometryNode,
+        displayedName="Tweak geometry",
     )
-    async def sendGeometry(self):
-        self.geometryOutput.schema.pickledGeometry = self.pickled_geometry
-        await self.geometryOutput.writeData()
 
     @Slot(
         displayedName="Update preview",
@@ -163,11 +242,7 @@ class ManualGeometryBase(Device):
         )
         self._set_status("Preview updated")
 
-    @Slot(
-        displayedName="Load from file",
-        allowedStates=[State.ACTIVE],
-    )
-    async def loadFromFile(self):
+    async def _load_from_file(self):
         with self.push_state(State.CHANGING):
             geometry = None
 
@@ -189,7 +264,7 @@ class ManualGeometryBase(Device):
                 )
             else:
                 geometry = geometry.offset(
-                    (self.geometryFile.offset.x, self.geometryFile.offset.y)
+                    (self.geometryFile.offset.x.value, self.geometryFile.offset.y.value)
                 )
                 await self._set_geometry(geometry)
                 self._set_status("Successfully loaded geometry from file")
@@ -198,6 +273,7 @@ class ManualGeometryBase(Device):
                         "Updating manual settings on device to reflect loaded geometry"
                     )
                     self._update_manual_from_current()
+                self.tweakGeometry._clear()
                 return True
 
         return False
@@ -206,13 +282,11 @@ class ManualGeometryBase(Device):
         # subclass should implement (neat when loading from CrystFEL geom)
         raise NotImplementedError()
 
-    async def _set_geometry(self, geometry, update_preview=True, send=True):
+    async def _set_geometry(self, geometry, update_preview=True):
         self.geometry = geometry
-        self.pickled_geometry = pickle.dumps(self.geometry)
+        self.pickledGeometry = gzip.compress(pickle.dumps(self.geometry))
         if update_preview:
             await self.updatePreview()
-        if send:
-            await self.sendGeometry()
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -220,8 +294,10 @@ class ManualGeometryBase(Device):
 
     async def onInitialization(self):
         self.state = State.INIT
-        # TODO: try to load file if set
-        await self.setManual()
+        if self.geometryFile.filePath.value and await self._load_from_file():
+            ...
+        else:
+            await self._set_from_manual_config()
         self.state = State.ACTIVE
 
     @contextlib.contextmanager
@@ -243,16 +319,15 @@ class ManualGeometryBase(Device):
         self.logger.log(level, text)
 
 
-def makeQuadrantCornersNode(default_values):
+def make_quadrant_corners_node(default_values):
     assert len(default_values) == 4
     assert all(len(x) == 2 for x in default_values)
 
-    class QuadrantCornersNode(Configurable):
-        Q1 = makeXYCoordinateNode(*default_values[0])
-        Q2 = makeXYCoordinateNode(*default_values[1])
-        Q3 = makeXYCoordinateNode(*default_values[2])
-        Q4 = makeXYCoordinateNode(*default_values[3])
-        offset = makeXYOffsetNode()
+    class QuadrantCornersNode(BaseManualGeometryConfigNode):
+        Q1 = make_x_y_coordinate_node(*default_values[0])
+        Q2 = make_x_y_coordinate_node(*default_values[1])
+        Q3 = make_x_y_coordinate_node(*default_values[2])
+        Q4 = make_x_y_coordinate_node(*default_values[3])
 
     return Node(QuadrantCornersNode)
 
@@ -281,11 +356,7 @@ class ManualQuadrantsGeometryBase(ManualGeometryBase):
 
         return Hash("type", "deviceScene", "origin", self.deviceId, "payload", payload)
 
-    @Slot(
-        displayedName="Set from device",
-        allowedStates=[State.ACTIVE],
-    )
-    async def setManual(self):
+    async def _set_from_manual_config(self):
         self._set_status("Updating geometry from manual configuration")
         with self.push_state(State.CHANGING):
             geometry = self.geometry_class.from_quad_positions(
@@ -297,6 +368,7 @@ class ManualQuadrantsGeometryBase(ManualGeometryBase):
                 )
             )
             await self._set_geometry(geometry)
+            self.tweakGeometry._clear()
 
     def _update_manual_from_current(self):
         # TODO: consider what to do about offset
@@ -322,9 +394,21 @@ class ModuleListItem(Configurable):
     orientY = Int32(assignment=Assignment.OPTIONAL, defaultValue=1)
 
 
+def make_manual_module_list_node(defaults):
+    class ManualModuleListNode(BaseManualGeometryConfigNode):
+        modules = VectorHash(
+            displayedName="Modules",
+            rows=ModuleListItem,
+            defaultValue=defaults,
+            accessMode=AccessMode.RECONFIGURABLE,
+            assignment=Assignment.OPTIONAL,
+        )
+
+    return Node(ManualModuleListNode)
+
+
 class ManualModuleListGeometryBase(ManualGeometryBase):
     moduleList = None  # subclass must define (with nice defaults)
-    offset = makeXYOffsetNode()
 
     @slot
     def requestScene(self, params):
@@ -342,14 +426,15 @@ class ManualModuleListGeometryBase(ManualGeometryBase):
         displayedName="Set from device",
         allowedStates=[State.ACTIVE],
     )
-    async def setManual(self):
+    async def _set_from_manual_config(self):
         self._set_status("Updating geometry from manual configuration")
         with self.push_state(State.CHANGING):
             geometry = self.geometry_class.from_module_positions(
-                [(x, y) for (x, y, _, _) in self.moduleList.value],
+                [(x, y) for (x, y, _, _) in self.moduleList.modules.value],
                 [
                     (orient_x, orient_y)
-                    for (_, _, orient_x, orient_y) in self.moduleList.value
+                    for (_, _, orient_x, orient_y) in self.moduleList.modules.value
                 ],
-            ).offset((self.offset.x.value, self.offset.y.value))
+            ).offset((self.moduleList.offset.x.value, self.moduleList.offset.y.value))
             await self._set_geometry(geometry)
+            self.tweakGeometry._clear()
diff --git a/src/calng/scenes.py b/src/calng/scenes.py
index 5db57128e160cedf8df3a141cac0c47324573980..f528427206368eec128304b7fab43a5f319caa10 100644
--- a/src/calng/scenes.py
+++ b/src/calng/scenes.py
@@ -630,7 +630,7 @@ class ManualQuadrantGeometrySettings(VerticalLayout):
         )
         self.children.append(
             DisplayCommandModel(
-                keys=[f"{device_id}.setManual"],
+                keys=[f"{device_id}.quadrantCorners.setManual"],
                 width=6 * BASE_INC,
                 height=BASE_INC,
             ),
@@ -644,7 +644,7 @@ class ManualModulesGeometrySettings(VerticalLayout):
         super().__init__(padding=0)
         self.children.append(
             TableElementModel(
-                keys=[f"{device_id}.moduleList"],
+                keys=[f"{device_id}.moduleList.modules"],
                 klass="EditableTableElement",
                 width=14 * BASE_INC,
                 height=10 * BASE_INC,
@@ -654,12 +654,12 @@ class ManualModulesGeometrySettings(VerticalLayout):
             HorizontalLayout(
                 LabelModel(text="Offset", width=3 * BASE_INC, height=BASE_INC),
                 DoubleLineEditModel(
-                    keys=[f"{device_id}.offset.x"],
+                    keys=[f"{device_id}.moduleList.offset.x"],
                     width=4 * BASE_INC,
                     height=BASE_INC,
                 ),
                 DoubleLineEditModel(
-                    keys=[f"{device_id}.offset.y"],
+                    keys=[f"{device_id}.moduleList.offset.y"],
                     width=4 * BASE_INC,
                     height=BASE_INC,
                 ),
@@ -667,7 +667,7 @@ class ManualModulesGeometrySettings(VerticalLayout):
         )
         self.children.append(
             DisplayCommandModel(
-                keys=[f"{device_id}.setManual"],
+                keys=[f"{device_id}.moduleList.setManual"],
                 width=6 * BASE_INC,
                 height=BASE_INC,
             ),
@@ -692,28 +692,54 @@ class TweakCurrentGeometry(VerticalLayout):
                     width=4 * BASE_INC,
                     height=BASE_INC,
                 ),
-            )
+            ),
+        )
+        self.children.append(
+            DisplayCommandModel(
+                keys=[f"{device_id}.tweakGeometry.add"],
+                width=6 * BASE_INC,
+                height=BASE_INC,
+            ),
         )
-
-
-@titled("Geometry preview")
-@boxed
-class GeometryPreview(VerticalLayout):
-    def __init__(self, device_id):
-        super().__init__(padding=0)
         self.children.append(
             HorizontalLayout(
+                DisplayLabelModel(
+                    keys=[f"{device_id}.tweakGeometry.undoLength"],
+                    width=2 * BASE_INC,
+                    height=BASE_INC,
+                    font_size=9,
+                ),
                 DisplayCommandModel(
-                    keys=[f"{device_id}.updatePreview"],
-                    width=6 * BASE_INC,
+                    keys=[f"{device_id}.tweakGeometry.undo"],
+                    width=4 * BASE_INC,
                     height=BASE_INC,
                 ),
+                DisplayLabelModel(
+                    keys=[f"{device_id}.tweakGeometry.redoLength"],
+                    width=2 * BASE_INC,
+                    height=BASE_INC,
+                    font_size=9,
+                ),
                 DisplayCommandModel(
-                    keys=[f"{device_id}.sendGeometry"],
-                    width=6 * BASE_INC,
+                    keys=[f"{device_id}.tweakGeometry.redo"],
+                    width=4 * BASE_INC,
                     height=BASE_INC,
                 ),
-            )
+            ),
+        )
+
+
+@titled("Geometry preview")
+@boxed
+class GeometryPreview(VerticalLayout):
+    def __init__(self, device_id):
+        super().__init__(padding=0)
+        self.children.append(
+            DisplayCommandModel(
+                keys=[f"{device_id}.updatePreview"],
+                width=6 * BASE_INC,
+                height=BASE_INC,
+            ),
         )
         self.children.append(
             WebCamGraphModel(
@@ -776,7 +802,7 @@ class GeometryFromFileSettings(VerticalLayout):
         )
         self.children.append(
             DisplayCommandModel(
-                keys=[f"{device_id}.loadFromFile"],
+                keys=[f"{device_id}.geometryFile.loadFromFile"],
                 width=6 * BASE_INC,
                 height=BASE_INC,
             ),
@@ -989,26 +1015,16 @@ def correction_constant_dashboard(
 
 
 @scene_generator
-def detector_assembler_overview(device_id, geometry_device_id):
+def detector_assembler_overview(device_id):
     return VerticalLayout(
         HorizontalLayout(
             AssemblerDeviceStatus(device_id),
             titled("My geometry device")(boxed(VerticalLayout))(
-                DeviceSceneLinkModel(
-                    text=f"Geometry device: {geometry_device_id}",
-                    keys=[f"{geometry_device_id}.availableScenes"],
-                    target="overview",
-                    target_window=SceneTargetWindow.Dialog,
-                    frame_width=1,
-                    width=14 * BASE_INC,
-                    height=BASE_INC,
-                ),
-                DisplayCommandModel(
-                    keys=[f"{geometry_device_id}.sendGeometry"],
-                    width=14 * BASE_INC,
+                DisplayLabelModel(
+                    keys=[f"{device_id}.geometryDevice"],
+                    width=6 * BASE_INC,
                     height=BASE_INC,
-                ),
-                padding=0,
+                )
             ),
         ),
         titled("Preview image")(boxed(dummy_wrap(DetectorGraphModel)))(
@@ -1028,6 +1044,7 @@ def quadrant_geometry_overview(device_id):
         HorizontalLayout(
             ManualQuadrantGeometrySettings(device_id),
             GeometryFromFileSettings(device_id),
+            TweakCurrentGeometry(device_id),
         ),
         GeometryPreview(device_id),
     )
@@ -1039,6 +1056,7 @@ def modules_geometry_overview(device_id):
         HorizontalLayout(
             ManualModulesGeometrySettings(device_id),
             GeometryFromFileSettings(device_id),
+            TweakCurrentGeometry(device_id),
         ),
         GeometryPreview(device_id),
     )