diff --git a/docs/data/bioentities.md b/docs/plugins/data/bioentities.md
similarity index 100%
rename from docs/data/bioentities.md
rename to docs/plugins/data/bioentities.md
diff --git a/docs/plugins/errors.md b/docs/plugins/errors.md
index fca95f8b1558a7e48087d53b5a8b736cc549eea8..fd7d29c75311eb1ca2028e60e570e57e7955e371 100644
--- a/docs/plugins/errors.md
+++ b/docs/plugins/errors.md
@@ -17,3 +17,9 @@
 ## Project Errors
 
 - **Project does not exist**: This error occurs when the project data is not available.
+
+## Zoom errors
+
+- **Provided zoom value exeeds max zoom of ...**: This error occurs when `zoom` param of `setZoom` exeeds max zoom value of the selected map
+
+- **Provided zoom value exceeds min zoom of ...**: This error occurs when `zoom` param of `setZoom` exceeds min zoom value of the selected map
diff --git a/docs/plugins/map/position.md b/docs/plugins/map/position.md
new file mode 100644
index 0000000000000000000000000000000000000000..a08872c6e6c00f67b041ef4b97641ef3ff84580e
--- /dev/null
+++ b/docs/plugins/map/position.md
@@ -0,0 +1,63 @@
+### Map positon
+
+With use of the methods below plugins can access and modify user position data.
+
+#### Get zoom
+
+To get current zoom value, plugins can use the `window.minerva.map.getZoom()` method, which returns current zoom value as a number.
+
+**Example:**
+
+```ts
+const currentZoom = window.minerva.map.getZoom();
+console.log(currentZoom); // 5
+```
+
+#### Set zoom
+
+To modify current zoom value, plugins can use the `window.minerva.map.setZoom(zoom)` method. This function accepts non-negative number as an argument and returns nothing. If argument is invalid, `setZoom` method throws an error.
+
+**Valid example:**
+
+```ts
+window.minerva.map.setZoom(7.54);
+console.log(window.minerva.map.getZoom()); // 7.54
+```
+
+**Invalid example:**
+
+```ts
+window.minerva.map.setZoom(-14);
+// Uncaught ZodError: [...]
+```
+
+#### Get center
+
+User position is defined as center coordinate. It's value is defined as x/y/z points of current viewport center translated to map position. Plugins can access center value and modify it.
+
+To get current position value, plugins can use the `window.minerva.map.getCenter()` method which returns current position value as an object containing `x`, `y` and `z` fields. All of them are non-negative numbers but `z` is an optional field and it defines current zoom value. If argument is invalid, `getCenter` method throws an error.
+
+**Valid example:**
+
+```ts
+const currentCenter = window.minerva.map.getCenter();
+console.log(currentCenter); // {x: 13256, y: 8118, z: 5}
+```
+
+#### Set center
+
+To modify position center value plugins can use `window.minerva.map.setCenter(positionObject)` which accepts single object as an argument and returns nothing. This object should contain `x`, `y` fields and `z` optionally. All of them are non-negative numbers. If argument is invalid, `setCenter` method throws an error.
+
+**Valid example:**
+
+```ts
+window.minerva.map.setCenter({ x: 13256, y: 8118, z: 5 });
+console.log(window.minerva.map.getCenter()); // {x: 13256, y: 8118, z: 5}
+```
+
+**Invalid example:**
+
+```ts
+window.minerva.map.setCenter({ x: 13256, y: 8118, z: -5 });
+// Uncaught ZodError: [...]
+```
diff --git a/docs/plugins/overview-images.md b/docs/plugins/overview-images.md
new file mode 100644
index 0000000000000000000000000000000000000000..b425d071b1aa1cdbf327a383e28b986e51a1eb91
--- /dev/null
+++ b/docs/plugins/overview-images.md
@@ -0,0 +1,46 @@
+### Overview images
+
+The methods contained within 'Overview images' are used to access data on Overview images and modify behavior of Overview images modal.
+
+Below is a description of the methods, as well as the types they return. description of the object types can be found in folder `/docs/types/`.
+
+**Available data access methods include:**
+
+- `getCurrentOverviewImage`
+  - gets currently selected overview image
+  - returns `OverviewImageView` or `undefined`
+- `getOverviewImage`
+  - gets all loaded overview images
+  - returns array of `OverviewImageView`
+
+**Available data modify methods include:**
+
+##### `hideOverviewImageModal`
+
+- accepts no arguments
+- hides overview image modal if opened
+- returns nothing
+- example:
+  ```ts
+  window.minerva.overviewImage.hideOverviewImageModal();
+  ```
+
+##### `selectOverviewImage`
+
+- accepts single argument of number representing id of one of loaded overview images
+- selects overview image of provided id as current, if image does not exists throws an error
+- returns nothing
+- example:
+  ```ts
+  window.minerva.overviewImage.selectOverviewImage(42);
+  ```
+
+##### `showOverviewImageModal`
+
+- accepts single argument of number representing id of one of loaded overview images
+- selects overview image of provided id as current and opens overview image modal, if image does not exists throws an error
+- returns nothing
+- example:
+  ```ts
+  window.minerva.overviewImage.showOverviewImageModal(24);
+  ```
diff --git a/docs/types/OverviewImageView.md b/docs/types/OverviewImageView.md
new file mode 100644
index 0000000000000000000000000000000000000000..33cf4cce60d81e907af4d6cd37132b2e1aff6347
--- /dev/null
+++ b/docs/types/OverviewImageView.md
@@ -0,0 +1,88 @@
+```json
+{
+  "type": "object",
+  "properties": {
+    "idObject": {
+      "type": "number"
+    },
+    "filename": {
+      "type": "string"
+    },
+    "width": {
+      "type": "number"
+    },
+    "height": {
+      "type": "number"
+    },
+    "links": {
+      "type": "array",
+      "items": {
+        "anyOf": [
+          {
+            "type": "object",
+            "properties": {
+              "idObject": {
+                "type": "number"
+              },
+              "polygon": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "x": {
+                      "type": "number"
+                    },
+                    "y": {
+                      "type": "number"
+                    }
+                  },
+                  "required": ["x", "y"],
+                  "additionalProperties": false
+                }
+              },
+              "imageLinkId": {
+                "type": "number"
+              },
+              "type": {
+                "type": "string"
+              }
+            },
+            "required": ["idObject", "polygon", "imageLinkId", "type"],
+            "additionalProperties": false
+          },
+          {
+            "type": "object",
+            "properties": {
+              "idObject": {
+                "type": "number"
+              },
+              "polygon": {
+                "type": "array",
+                "items": {
+                  "$ref": "#/definitions/overviewImageView/properties/links/items/anyOf/0/properties/polygon/items"
+                }
+              },
+              "zoomLevel": {
+                "type": "number"
+              },
+              "modelPoint": {
+                "$ref": "#/definitions/overviewImageView/properties/links/items/anyOf/0/properties/polygon/items"
+              },
+              "modelLinkId": {
+                "type": "number"
+              },
+              "type": {
+                "type": "string"
+              }
+            },
+            "required": ["idObject", "polygon", "zoomLevel", "modelPoint", "modelLinkId", "type"],
+            "additionalProperties": false
+          }
+        ]
+      }
+    }
+  },
+  "required": ["idObject", "filename", "width", "height", "links"],
+  "additionalProperties": false
+}
+```
diff --git a/index.d.ts b/index.d.ts
index 3cd0efd1a8805d41f089cca9aa3f9a7fd87171d8..fcac0d8b269f59bfa4610ff8051b1266636ba44f 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -5,10 +5,13 @@ import { triggerSearch } from '@/services/pluginsManager/map/triggerSearch';
 import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
 import { MapInstance } from '@/types/map';
 import { getModels } from '@/services/pluginsManager/map/models/getModels';
-import { OpenMapArgs, openMap } from '@/services/pluginsManager/map/openMap';
+import { openMap } from '@/services/pluginsManager/map/openMap';
+import { getCenter } from '@/services/pluginsManager/map/position/getCenter';
+import { setCenter } from '@/services/pluginsManager/map/position/setCenter';
 import { triggerSearch } from '@/services/pluginsManager/map/triggerSearch';
+import { getZoom } from '@/services/pluginsManager/map/zoom/getZoom';
+import { setZoom } from '@/services/pluginsManager/map/zoom/setZoom';
 import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
-import { MapModel } from '@/types/models';
 import { getDisease } from '@/services/pluginsManager/project/data/getDisease';
 import { getName } from '@/services/pluginsManager/project/data/getName';
 import { getOrganism } from '@/services/pluginsManager/project/data/getOrganism';
@@ -49,6 +52,17 @@ declare global {
         fitBounds: typeof fitBounds;
         openMap: typeof openMap;
         triggerSearch: typeof triggerSearch;
+        getZoom: typeof getZoom;
+        setZoom: typeof setZoom;
+        getCenter: typeof getCenter;
+        setCenter: typeof setCenter;
+      };
+      overviewImage: {
+        getCurrentOverviewImage: typeof getCurrentOverviewImage;
+        getOverviewImages: typeof getOverviewImages;
+        hideOverviewImageModal: typeof hideOverviewImageModal;
+        selectOverviewImage: typeof selectOverviewImage;
+        showOverviewImageModal: typeof showOverviewImageModal;
       };
       project: {
         data: {
diff --git a/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx
index d944235a29d04b7a1c376869c37cdc29e502ed2d..4fae37530de53dd219cd0d5118bbe12aded2d3ae 100644
--- a/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx
+++ b/src/components/FunctionalArea/MapNavigation/MapNavigation.component.test.tsx
@@ -1,14 +1,14 @@
 /* eslint-disable no-magic-numbers */
+import { MODELS_MOCK } from '@/redux/compartmentPathways/compartmentPathways.mock';
+import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
+import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
+import { StoreType } from '@/redux/store';
+import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import {
   InitialStoreState,
   getReduxWrapperWithStore,
 } from '@/utils/testing/getReduxWrapperWithStore';
-import { StoreType } from '@/redux/store';
-import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
 import { act, render, screen, within } from '@testing-library/react';
-import { MODELS_MOCK } from '@/redux/compartmentPathways/compartmentPathways.mock';
-import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
-import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import { MapNavigation } from './MapNavigation.component';
 
 const MAIN_MAP_ID = 5053;
diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts
index 55c6230d3e238a7a7595957d217c1025aafaaa65..609cc0f5ceaf38a4ee64f1433e553e11ea9bf7ce 100644
--- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts
+++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts
@@ -12,11 +12,11 @@ import {
 } from '@/redux/map/map.fixtures';
 import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock';
 import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock';
+import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import { OverviewImageLink } from '@/types/models';
 import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook } from '@testing-library/react';
-import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import {
   FIRST_ARRAY_ELEMENT,
   NOOP,
@@ -313,7 +313,6 @@ describe('useOverviewImageLinkActions - hook', () => {
       jest.clearAllMocks();
     });
     it('should dispatch event if coordinates changed', () => {
-      const dispatchEventMock = jest.spyOn(PluginsEventBus, 'dispatchEvent');
       const { Wrapper } = getReduxStoreWithActionsListener({
         project: {
           data: {
@@ -361,14 +360,6 @@ describe('useOverviewImageLinkActions - hook', () => {
       });
 
       handleLinkClick(OVERVIEW_LINK_MODEL_MOCK);
-
-      expect(dispatchEventMock).toHaveBeenCalledTimes(2);
-      expect(dispatchEventMock).toHaveBeenCalledWith('onZoomChanged', { modelId: 5053, zoom: 7 });
-      expect(dispatchEventMock).toHaveBeenCalledWith('onCenterChanged', {
-        modelId: 5053,
-        x: 15570,
-        y: 3016,
-      });
     });
     it('should not dispatch event if coordinates do not changed', () => {
       const dispatchEventMock = jest.spyOn(PluginsEventBus, 'dispatchEvent');
diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.ts
index 8a8689aa8029ca6877508bd0c00bea85cc350571..5059ea594c02245a181a02f3e0fe8e00407c82db 100644
--- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.ts
+++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.ts
@@ -1,13 +1,13 @@
 import { NOOP } from '@/constants/common';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { mapDataLastPositionSelector, mapOpenedMapsSelector } from '@/redux/map/map.selectors';
+import { mapOpenedMapsSelector } from '@/redux/map/map.selectors';
 import { openMapAndSetActive, setActiveMap, setMapPosition } from '@/redux/map/map.slice';
 import { closeModal, setOverviewImageId } from '@/redux/modal/modal.slice';
 import { currentModelIdSelector, modelsDataSelector } from '@/redux/models/models.selectors';
 import { projectOverviewImagesSelector } from '@/redux/project/project.selectors';
-import { MapModel, OverviewImageLink, OverviewImageLinkModel } from '@/types/models';
 import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
+import { MapModel, OverviewImageLink, OverviewImageLinkModel } from '@/types/models';
 import {
   OverviewImageLinkImageHandler,
   OverviewImageLinkModelHandler,
@@ -23,7 +23,6 @@ export const useOverviewImageLinkActions = (): UseOverviewImageLinkActionsResult
   const models = useAppSelector(modelsDataSelector);
   const overviewImages = useAppSelector(projectOverviewImagesSelector);
   const currentMapModelId = useAppSelector(currentModelIdSelector);
-  const mapLastPosition = useAppSelector(mapDataLastPositionSelector);
 
   const checkIfImageIsAvailable = (imageId: number): boolean =>
     overviewImages.some(image => image.idObject === imageId);
@@ -55,21 +54,6 @@ export const useOverviewImageLinkActions = (): UseOverviewImageLinkActionsResult
     const { x } = link.modelPoint;
     const { y } = link.modelPoint;
 
-    if (mapLastPosition.z !== zoom) {
-      PluginsEventBus.dispatchEvent('onZoomChanged', {
-        modelId: currentMapModelId,
-        zoom,
-      });
-    }
-
-    if (mapLastPosition.x !== x || mapLastPosition.y !== y) {
-      PluginsEventBus.dispatchEvent('onCenterChanged', {
-        modelId: currentMapModelId,
-        x,
-        y,
-      });
-    }
-
     dispatch(
       setMapPosition({
         x,
diff --git a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
index 209499399e2e28b88e311ca935895b0a1304e076..e80346b5d069b42e41ffaa1d690248fa91ad6497 100644
--- a/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
+++ b/src/components/Map/MapAdditionalActions/utils/useAdditionalActions.ts
@@ -1,14 +1,12 @@
+import { DEFAULT_ZOOM } from '@/constants/map';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { setMapPosition, varyPositionZoom } from '@/redux/map/map.slice';
+import { currentModelIdSelector, modelByIdSelector } from '@/redux/models/models.selectors';
 import { SetBoundsResult, useSetBounds } from '@/utils/map/useSetBounds';
 import { useCallback } from 'react';
 import { useDispatch } from 'react-redux';
-import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import { currentModelIdSelector, modelByIdSelector } from '@/redux/models/models.selectors';
-import { DEFAULT_ZOOM } from '@/constants/map';
-import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
-import { mapDataLastPositionSelector } from '@/redux/map/map.selectors';
-import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates';
 import { MAP_ZOOM_IN_DELTA, MAP_ZOOM_OUT_DELTA } from '../MappAdditionalActions.constants';
+import { useVisibleBioEntitiesPolygonCoordinates } from './useVisibleBioEntitiesPolygonCoordinates';
 
 interface UseAddtionalActionsResult {
   zoomIn(): void;
@@ -22,7 +20,6 @@ export const useAddtionalActions = (): UseAddtionalActionsResult => {
   const polygonCoordinates = useVisibleBioEntitiesPolygonCoordinates();
   const currentMapModelId = useAppSelector(currentModelIdSelector);
   const currentModel = useAppSelector(state => modelByIdSelector(state, currentMapModelId));
-  const currentModelLastPostiion = useAppSelector(mapDataLastPositionSelector);
 
   const zoomInToBioEntities = (): SetBoundsResult | undefined => {
     if (polygonCoordinates) {
@@ -38,24 +35,6 @@ export const useAddtionalActions = (): UseAddtionalActionsResult => {
       };
 
       dispatch(setMapPosition(defaultPosition));
-
-      if (currentModelLastPostiion.z !== defaultPosition.z) {
-        PluginsEventBus.dispatchEvent('onZoomChanged', {
-          modelId: currentMapModelId,
-          zoom: defaultPosition.z,
-        });
-      }
-
-      if (
-        currentModelLastPostiion.x !== defaultPosition.x ||
-        currentModelLastPostiion.y !== defaultPosition.y
-      ) {
-        PluginsEventBus.dispatchEvent('onCenterChanged', {
-          modelId: currentMapModelId,
-          x: defaultPosition.x,
-          y: defaultPosition.y,
-        });
-      }
     }
 
     return undefined;
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.ts
index 174d0a138eab987b1fb7b3019f34b8659a6efea4..ffa0b76e1564bd0fbcd0c638744ef529a650a27b 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapView.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapView.ts
@@ -56,9 +56,11 @@ export const useOlMapView = ({ mapInstance }: UseOlMapViewInput): MapConfig['vie
       center: [center.x, center.y],
       zoom: mapInitialPosition.z,
       showFullExtent: OPTIONS.showFullExtent,
+      maxZoom: mapSize.maxZoom,
+      minZoom: mapSize.minZoom,
       extent,
     }),
-    [mapInitialPosition.z, center, extent],
+    [mapInitialPosition.z, mapSize.maxZoom, mapSize.minZoom, center, extent],
   );
 
   const view = useMemo(() => new View(viewConfig), [viewConfig]);
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
index bc9228f024b01e1369e832ae32a93dcbf16c1b3d..295b91d1aad607f60565dbb88c33f6bc043659a0 100644
--- a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.test.ts
@@ -16,8 +16,6 @@ const getEvent = (targetValues: ObjectEvent['target']['values_']): ObjectEvent =
 
 /* eslint-disable no-magic-numbers */
 describe('onMapPositionChange - util', () => {
-  const MAP_ID = 52;
-  const LAST_ZOOM = 4;
   const cases: [MapSize, ObjectEvent['target']['values_'], Point][] = [
     [
       {
@@ -65,7 +63,7 @@ describe('onMapPositionChange - util', () => {
       const dispatch = result.current;
       const event = getEvent(targetValues);
 
-      onMapPositionChange(mapSize, dispatch, MAP_ID, LAST_ZOOM)(event);
+      onMapPositionChange(mapSize, dispatch)(event);
 
       const { position } = mapDataSelector(store.getState());
       expect(position.last).toMatchObject(lastPosition);
diff --git a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
index d49f6f3edfd3d4a108619cf890fbc45a90a68d56..7102fec7fdecfd1f771295030dd82e30c42bc767 100644
--- a/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onMapPositionChange.ts
@@ -1,33 +1,19 @@
 import { setMapPosition } from '@/redux/map/map.slice';
 import { MapSize } from '@/redux/map/map.types';
 import { AppDispatch } from '@/redux/store';
-import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import { latLngToPoint } from '@/utils/map/latLngToPoint';
 import { toLonLat } from 'ol/proj';
 import { ObjectEvent } from 'openlayers';
 
 /* prettier-ignore */
 export const onMapPositionChange =
-  (mapSize: MapSize, dispatch: AppDispatch, modelId: number, mapLastZoomValue: number | undefined) =>
+  (mapSize: MapSize, dispatch: AppDispatch) =>
     (e: ObjectEvent): void => {
       // eslint-disable-next-line no-underscore-dangle
       const { center, zoom } = e.target.values_;
       const [lng, lat] = toLonLat(center);
       const { x, y } = latLngToPoint([lat, lng], mapSize, { rounded: true });
 
-      if (mapLastZoomValue !== zoom) {
-        PluginsEventBus.dispatchEvent('onZoomChanged', {
-          modelId,
-          zoom,
-        });
-      }
-
-      PluginsEventBus.dispatchEvent('onCenterChanged', {
-        modelId,
-        x,
-        y
-      });
-
       dispatch(
         setMapPosition({
           x,
diff --git a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
index 7ca778b5965bafa6ac38cae39e887afbb5cc6c21..72016ec314a2fcfbdd4c31adf3b79416cc99fcb1 100644
--- a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
+++ b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
@@ -1,6 +1,6 @@
 import { OPTIONS } from '@/constants/map';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
-import { mapDataLastZoomValue, mapDataSizeSelector } from '@/redux/map/map.selectors';
+import { mapDataSizeSelector } from '@/redux/map/map.selectors';
 import { currentModelIdSelector } from '@/redux/models/models.selectors';
 import { MapInstance } from '@/types/map';
 import { View } from 'ol';
@@ -23,7 +23,6 @@ interface UseOlMapListenersInput {
 export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput): void => {
   const mapSize = useSelector(mapDataSizeSelector);
   const modelId = useSelector(currentModelIdSelector);
-  const mapLastZoomValue = useSelector(mapDataLastZoomValue);
   const coordinate = useRef<Coordinate>([]);
   const pixel = useRef<Pixel>([]);
   const dispatch = useAppDispatch();
@@ -37,7 +36,7 @@ export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput)
   );
 
   const handleChangeCenter = useDebouncedCallback(
-    onMapPositionChange(mapSize, dispatch, modelId, mapLastZoomValue),
+    onMapPositionChange(mapSize, dispatch),
     OPTIONS.queryPersistTime,
     { leading: false },
   );
diff --git a/src/constants/errors.ts b/src/constants/errors.ts
index 887f64f35d00d60ce428da9f5b4239c0d8c6cbaa..cba5c0d0c5954b0a36f8b40c6188afbb20117dd1 100644
--- a/src/constants/errors.ts
+++ b/src/constants/errors.ts
@@ -1 +1,12 @@
 export const DEFAULT_ERROR: Error = { message: '', name: '' };
+
+export const OVERVIEW_IMAGE_ERRORS = {
+  IMAGE_ID_IS_INVALID: "Image id is invalid. There's no such image in overview images list",
+};
+
+export const ZOOM_ERRORS = {
+  ZOOM_VALUE_TOO_HIGH: (maxZoom: number): string =>
+    `Provided zoom value exeeds max zoom of ${maxZoom}`,
+  ZOOM_VALUE_TOO_LOW: (minZoom: number): string =>
+    `Provided zoom value exceeds min zoom of ${minZoom}`,
+};
diff --git a/src/models/pointSchema.ts b/src/models/pointSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b097ef8235bf4e2a0a27698337828153a62c553
--- /dev/null
+++ b/src/models/pointSchema.ts
@@ -0,0 +1,9 @@
+import { z } from 'zod';
+
+export const zPointSchema = z.number().nonnegative('z should be non negative').optional();
+
+export const pointSchema = z.object({
+  x: z.number().nonnegative('x should be non negative'),
+  y: z.number().nonnegative('y should be non negative'),
+  z: zPointSchema,
+});
diff --git a/src/redux/map/map.reducers.ts b/src/redux/map/map.reducers.ts
index 362745fc00327c7fff640f6d74c388b85400bb07..b2fbff2d89f78e038e0f995d85b1641031d1907d 100644
--- a/src/redux/map/map.reducers.ts
+++ b/src/redux/map/map.reducers.ts
@@ -1,6 +1,6 @@
 import { DEFAULT_ZOOM } from '@/constants/map';
-import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
 import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
+import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
 import { getPointMerged } from '../../utils/object/getPointMerged';
 import {
   initMapBackground,
@@ -16,6 +16,7 @@ import {
   SetActiveMapAction,
   SetBackgroundAction,
   SetLastPositionZoomAction,
+  SetLastPositionZoomWithDeltaAction,
   SetMapDataAction,
   SetMapPositionDataAction,
 } from './map.types';
@@ -32,19 +33,38 @@ export const setMapDataReducer = (state: MapState, action: SetMapDataAction): vo
 export const setMapPositionReducer = (state: MapState, action: SetMapPositionDataAction): void => {
   const position = action.payload || {};
   const statePosition = state.data.position;
+  const lastPosition = statePosition.last;
+  const lastZoom = lastPosition.z;
+  const finalPosition = getPointMerged(position || {}, lastPosition);
+  const { modelId } = state.data;
+
+  if (lastPosition?.x !== finalPosition.x || lastPosition?.y !== finalPosition.y) {
+    PluginsEventBus.dispatchEvent('onCenterChanged', {
+      modelId,
+      x: finalPosition.x,
+      y: finalPosition.y,
+    });
+  }
+
+  if (position?.z && lastZoom && lastZoom !== position?.z) {
+    PluginsEventBus.dispatchEvent('onZoomChanged', {
+      modelId,
+      zoom: position?.z,
+    });
+  }
 
   state.data = {
     ...state.data,
     position: {
-      initial: getPointMerged(position || {}, statePosition.initial),
-      last: getPointMerged(position || {}, statePosition.last),
+      initial: finalPosition,
+      last: finalPosition,
     },
   };
 };
 
 export const varyPositionZoomReducer = (
   state: MapState,
-  action: SetLastPositionZoomAction,
+  action: SetLastPositionZoomWithDeltaAction,
 ): void => {
   const { minZoom, maxZoom } = state.data.size;
   const { delta } = action.payload;
@@ -63,6 +83,23 @@ export const varyPositionZoomReducer = (
   state.data.position.initial.z = newZLimited;
 };
 
+export const setLastPositionZoomReducer = (
+  state: MapState,
+  action: SetLastPositionZoomAction,
+): void => {
+  const { zoom } = action.payload;
+
+  if (state.data.position.last.z !== zoom) {
+    PluginsEventBus.dispatchEvent('onZoomChanged', {
+      modelId: state.data.modelId,
+      zoom,
+    });
+  }
+
+  state.data.position.last.z = zoom;
+  state.data.position.initial.z = zoom;
+};
+
 const updateLastPositionOfCurrentlyActiveMap = (state: MapState): void => {
   const currentMapId = state.data.modelId;
   const currentOpenedMap = state.openedMaps.find(openedMap => openedMap.modelId === currentMapId);
diff --git a/src/redux/map/map.slice.ts b/src/redux/map/map.slice.ts
index 8fc687b9fb29301fc18cc15579ca40b6caef893f..02e8a878292906e9894c26fe8f841dd5219fbbc8 100644
--- a/src/redux/map/map.slice.ts
+++ b/src/redux/map/map.slice.ts
@@ -9,6 +9,7 @@ import {
   initOpenedMapsReducer,
   openMapAndSetActiveReducer,
   setActiveMapReducer,
+  setLastPositionZoomReducer,
   setMapBackgroundReducer,
   setMapDataReducer,
   setMapPositionReducer,
@@ -27,6 +28,7 @@ const mapSlice = createSlice({
     setMapPosition: setMapPositionReducer,
     varyPositionZoom: varyPositionZoomReducer,
     setMapBackground: setMapBackgroundReducer,
+    setLastPositionZoom: setLastPositionZoomReducer,
   },
   extraReducers: builder => {
     initMapPositionReducers(builder);
@@ -45,6 +47,7 @@ export const {
   setMapPosition,
   setMapBackground,
   varyPositionZoom,
+  setLastPositionZoom,
 } = mapSlice.actions;
 
 export default mapSlice.reducer;
diff --git a/src/redux/map/map.types.ts b/src/redux/map/map.types.ts
index b11c5cfefe794fb850de5629934e181c4f94877d..727df76f71b29da80f9690edcc3e9e86c9888d12 100644
--- a/src/redux/map/map.types.ts
+++ b/src/redux/map/map.types.ts
@@ -88,10 +88,17 @@ export type GetUpdatedMapDataResult = Pick<
 
 export type SetMapPositionDataAction = PayloadAction<Point>;
 
-export type SetLastPositionZoomActionPayload = {
+export type SetLastPositionZoomWithDeltaActionPayload = {
   delta: number;
 };
 
+export type SetLastPositionZoomWithDeltaAction =
+  PayloadAction<SetLastPositionZoomWithDeltaActionPayload>;
+
+export type SetLastPositionZoomActionPayload = {
+  zoom: number;
+};
+
 export type SetLastPositionZoomAction = PayloadAction<SetLastPositionZoomActionPayload>;
 
 export type InitMapDataActionPayload = {
diff --git a/src/services/pluginsManager/map/position/getCenter.test.ts b/src/services/pluginsManager/map/position/getCenter.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f9d9dd545bda215f262f039e2d9c5f2ae7349ab5
--- /dev/null
+++ b/src/services/pluginsManager/map/position/getCenter.test.ts
@@ -0,0 +1,39 @@
+import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
+import { RootState, store } from '@/redux/store';
+import { getCenter } from './getCenter';
+
+jest.mock('../../../../redux/store');
+
+describe('getCenter - plugin method', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  getStateSpy.mockImplementation(
+    () =>
+      ({
+        map: {
+          data: {
+            ...initialMapDataFixture,
+            position: {
+              ...initialMapDataFixture.position,
+              last: {
+                x: 2137,
+                y: 420,
+                z: 1.488,
+              },
+            },
+          },
+          loading: 'succeeded',
+          error: { message: '', name: '' },
+          openedMaps: openedMapsThreeSubmapsFixture,
+        },
+      }) as RootState,
+  );
+
+  it('should return last position from Redux', () => {
+    expect(getCenter()).toStrictEqual({
+      x: 2137,
+      y: 420,
+      z: 1.488,
+    });
+  });
+});
diff --git a/src/services/pluginsManager/map/position/getCenter.ts b/src/services/pluginsManager/map/position/getCenter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ccf28579481881132d6677d2a982a465321ddac0
--- /dev/null
+++ b/src/services/pluginsManager/map/position/getCenter.ts
@@ -0,0 +1,10 @@
+import { mapDataLastPositionSelector } from '@/redux/map/map.selectors';
+import { store } from '@/redux/store';
+import { Point } from '@/types/map';
+
+export const getCenter = (): Point => {
+  const { getState } = store;
+  const lastPosition = mapDataLastPositionSelector(getState());
+
+  return lastPosition;
+};
diff --git a/src/services/pluginsManager/map/position/setCenter.test.ts b/src/services/pluginsManager/map/position/setCenter.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef26567b20576c97982dd6385a71829b534d4249
--- /dev/null
+++ b/src/services/pluginsManager/map/position/setCenter.test.ts
@@ -0,0 +1,55 @@
+import { setMapPosition } from '@/redux/map/map.slice';
+import { store } from '@/redux/store';
+import { Point } from '@/types/map';
+import { ZodError } from 'zod';
+import { setCenter } from './setCenter';
+
+jest.mock('../../../../redux/store');
+
+describe('setCenter - plugin method', () => {
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
+
+  describe('when position is invalid', () => {
+    const invalidPositions = [
+      {
+        x: -1,
+        y: 1,
+        z: 1,
+      },
+      {
+        x: 1,
+        y: -1,
+        z: 1,
+      },
+      {
+        x: 1,
+        y: 1,
+        z: -1,
+      },
+      {
+        y: 1,
+      },
+      {
+        x: 1,
+      },
+    ] as Point[];
+
+    it.each(invalidPositions)('should throw error', position => {
+      expect(() => setCenter(position)).toThrow(ZodError);
+    });
+  });
+
+  describe('when position is valid', () => {
+    const position: Point = {
+      x: 500,
+      y: 200,
+      z: 2,
+    };
+
+    it('should set map position', () => {
+      setCenter(position);
+
+      expect(dispatchSpy).toHaveBeenCalledWith(setMapPosition(position));
+    });
+  });
+});
diff --git a/src/services/pluginsManager/map/position/setCenter.ts b/src/services/pluginsManager/map/position/setCenter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a32717df9b4897e0136f3d461d26779a9e5480ab
--- /dev/null
+++ b/src/services/pluginsManager/map/position/setCenter.ts
@@ -0,0 +1,11 @@
+import { pointSchema } from '@/models/pointSchema';
+import { setMapPosition } from '@/redux/map/map.slice';
+import { store } from '@/redux/store';
+import { Point } from '@/types/map';
+
+export const setCenter = (position: Point): void => {
+  const { dispatch } = store;
+  pointSchema.parse(position);
+
+  dispatch(setMapPosition(position));
+};
diff --git a/src/services/pluginsManager/map/zoom/getZoom.test.ts b/src/services/pluginsManager/map/zoom/getZoom.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7808d53163d34fa802f14c8e090119590c3c11f
--- /dev/null
+++ b/src/services/pluginsManager/map/zoom/getZoom.test.ts
@@ -0,0 +1,69 @@
+/* eslint-disable no-magic-numbers */
+import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
+import { RootState, store } from '@/redux/store';
+import { getZoom } from './getZoom';
+
+jest.mock('../../../../redux/store');
+
+describe('getZoom - plugin method', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  describe('when last position zoom is present', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            map: {
+              data: {
+                ...initialMapDataFixture,
+                position: {
+                  ...initialMapDataFixture.position,
+                  last: {
+                    x: 2137,
+                    y: 420,
+                    z: 1.488,
+                  },
+                },
+              },
+              loading: 'succeeded',
+              error: { message: '', name: '' },
+              openedMaps: openedMapsThreeSubmapsFixture,
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should return last position from Redux', () => {
+      expect(getZoom()).toEqual(1.488);
+    });
+  });
+
+  describe('when last position zoom is NOT present', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            map: {
+              data: {
+                ...initialMapDataFixture,
+                position: {
+                  ...initialMapDataFixture.position,
+                  last: {
+                    x: 2137,
+                    y: 420,
+                  },
+                },
+              },
+              loading: 'succeeded',
+              error: { message: '', name: '' },
+              openedMaps: openedMapsThreeSubmapsFixture,
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should return undefined', () => {
+      expect(getZoom()).toBeUndefined();
+    });
+  });
+});
diff --git a/src/services/pluginsManager/map/zoom/getZoom.ts b/src/services/pluginsManager/map/zoom/getZoom.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fee865408304b40d1f3ea5d614d39c2315b32123
--- /dev/null
+++ b/src/services/pluginsManager/map/zoom/getZoom.ts
@@ -0,0 +1,9 @@
+import { mapDataLastPositionSelector } from '@/redux/map/map.selectors';
+import { store } from '@/redux/store';
+
+export const getZoom = (): number | undefined => {
+  const { getState } = store;
+  const lastPosition = mapDataLastPositionSelector(getState());
+
+  return lastPosition?.z;
+};
diff --git a/src/services/pluginsManager/map/zoom/setZoom.test.ts b/src/services/pluginsManager/map/zoom/setZoom.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..55502f302a70e74e6e7b7983e1bc12601e1071d9
--- /dev/null
+++ b/src/services/pluginsManager/map/zoom/setZoom.test.ts
@@ -0,0 +1,77 @@
+/* eslint-disable no-magic-numbers */
+import { ZOOM_ERRORS } from '@/constants/errors';
+import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
+import { setLastPositionZoom } from '@/redux/map/map.slice';
+import { RootState, store } from '@/redux/store';
+import { ZodError } from 'zod';
+import { setZoom } from './setZoom';
+
+jest.mock('../../../../redux/store');
+
+describe('setZoom - plugin method', () => {
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  beforeEach(() => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          map: {
+            data: {
+              ...initialMapDataFixture,
+              position: {
+                ...initialMapDataFixture.position,
+                last: {
+                  x: 2137,
+                  y: 420,
+                  z: 1.488,
+                },
+              },
+              size: {
+                ...initialMapDataFixture.size,
+                minZoom: 2,
+                maxZoom: 8,
+              },
+            },
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+            openedMaps: openedMapsThreeSubmapsFixture,
+          },
+        }) as RootState,
+    );
+  });
+
+  describe('when zoom value type is invalid', () => {
+    const invalidZoom = [-1, -123, '-123'] as number[];
+
+    it.each(invalidZoom)('should throw error', zoom => {
+      expect(() => setZoom(zoom)).toThrow(ZodError);
+    });
+  });
+
+  describe('when zoom value value exeeds max zoom', () => {
+    const invalidZoom = [444, 21, 9] as number[];
+
+    it.each(invalidZoom)('should throw error', zoom => {
+      expect(() => setZoom(zoom)).toThrow(ZOOM_ERRORS.ZOOM_VALUE_TOO_HIGH(8));
+    });
+  });
+
+  describe('when zoom value value exeeds min zoom', () => {
+    const invalidZoom = [1, 0] as number[];
+
+    it.each(invalidZoom)('should throw error', zoom => {
+      expect(() => setZoom(zoom)).toThrow(ZOOM_ERRORS.ZOOM_VALUE_TOO_LOW(2));
+    });
+  });
+
+  describe('when zoom is valid', () => {
+    const zoom = 2;
+
+    it('should set map zoom', () => {
+      setZoom(zoom);
+
+      expect(dispatchSpy).toHaveBeenCalledWith(setLastPositionZoom({ zoom }));
+    });
+  });
+});
diff --git a/src/services/pluginsManager/map/zoom/setZoom.ts b/src/services/pluginsManager/map/zoom/setZoom.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f161d1c0588e5010c701d4e64ed2e6a7e83f7f5a
--- /dev/null
+++ b/src/services/pluginsManager/map/zoom/setZoom.ts
@@ -0,0 +1,21 @@
+import { ZOOM_ERRORS } from '@/constants/errors';
+import { zPointSchema } from '@/models/pointSchema';
+import { mapDataSizeSelector } from '@/redux/map/map.selectors';
+import { setLastPositionZoom } from '@/redux/map/map.slice';
+import { store } from '@/redux/store';
+
+export const setZoom = (zoom: number): void => {
+  const { dispatch, getState } = store;
+  const { minZoom, maxZoom } = mapDataSizeSelector(getState());
+  zPointSchema.parse(zoom);
+
+  if (zoom < minZoom) {
+    throw Error(ZOOM_ERRORS.ZOOM_VALUE_TOO_LOW(minZoom));
+  }
+
+  if (zoom > maxZoom) {
+    throw Error(ZOOM_ERRORS.ZOOM_VALUE_TOO_HIGH(maxZoom));
+  }
+
+  dispatch(setLastPositionZoom({ zoom }));
+};
diff --git a/src/services/pluginsManager/overviewImage/getCurrentOverviewImage.ts b/src/services/pluginsManager/overviewImage/getCurrentOverviewImage.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9d54c9aad16354024f9efbf5e9f487e182926eb
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/getCurrentOverviewImage.ts
@@ -0,0 +1,10 @@
+import { currentOverviewImageSelector } from '@/redux/project/project.selectors';
+import { store } from '@/redux/store';
+import { OverviewImageView } from '@/types/models';
+
+export const getCurrentOverviewImage = (): OverviewImageView | undefined => {
+  const { getState } = store;
+  const overviewImage = currentOverviewImageSelector(getState());
+
+  return overviewImage;
+};
diff --git a/src/services/pluginsManager/overviewImage/getOverviewImages.ts b/src/services/pluginsManager/overviewImage/getOverviewImages.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8e2e19c189033e08f86b97d4a0b983d6cca30cb3
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/getOverviewImages.ts
@@ -0,0 +1,10 @@
+import { projectOverviewImagesSelector } from '@/redux/project/project.selectors';
+import { store } from '@/redux/store';
+import { OverviewImageView } from '@/types/models';
+
+export const getOverviewImages = (): OverviewImageView[] => {
+  const { getState } = store;
+  const overviewImages = projectOverviewImagesSelector(getState());
+
+  return overviewImages;
+};
diff --git a/src/services/pluginsManager/overviewImage/hideOverviewImageModal.test.ts b/src/services/pluginsManager/overviewImage/hideOverviewImageModal.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..25eb34afffd19c5809906d2adc013892927dc3e7
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/hideOverviewImageModal.test.ts
@@ -0,0 +1,60 @@
+import { closeModal } from '@/redux/modal/modal.slice';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { RootState, store } from '@/redux/store';
+import { hideOverviewImageModal } from './hideOverviewImageModal';
+
+jest.mock('../../../redux/store');
+
+describe('hideOverviewImageModal - util', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  beforeEach(() => {
+    jest.resetAllMocks();
+  });
+
+  describe('when opened modal is overview image', () => {
+    const dispatchSpy = jest.spyOn(store, 'dispatch');
+
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            modal: {
+              ...INITIAL_STORE_STATE_MOCK.modal,
+              modalName: 'overview-images',
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should close modal', () => {
+      hideOverviewImageModal();
+
+      expect(dispatchSpy).toHaveBeenCalledWith(closeModal());
+    });
+  });
+
+  describe('when opened modal is NOT overview image', () => {
+    const dispatchSpy = jest.spyOn(store, 'dispatch');
+
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            modal: {
+              ...INITIAL_STORE_STATE_MOCK.modal,
+              modalName: 'login',
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should not close modal', () => {
+      hideOverviewImageModal();
+
+      expect(dispatchSpy).not.toHaveBeenCalledWith(closeModal());
+    });
+  });
+});
diff --git a/src/services/pluginsManager/overviewImage/hideOverviewImageModal.ts b/src/services/pluginsManager/overviewImage/hideOverviewImageModal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..47652cd524a0fb8a0851ad730d280085d3105559
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/hideOverviewImageModal.ts
@@ -0,0 +1,14 @@
+import { modalSelector } from '@/redux/modal/modal.selector';
+import { closeModal } from '@/redux/modal/modal.slice';
+import { store } from '@/redux/store';
+
+export const hideOverviewImageModal = (): void => {
+  const { getState, dispatch } = store;
+  const { modalName } = modalSelector(getState());
+
+  if (modalName !== 'overview-images') {
+    return;
+  }
+
+  dispatch(closeModal());
+};
diff --git a/src/services/pluginsManager/overviewImage/selectOverviewImage.test.ts b/src/services/pluginsManager/overviewImage/selectOverviewImage.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..500bfae94ebce30954ce2b772a67a4c12b224917
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/selectOverviewImage.test.ts
@@ -0,0 +1,63 @@
+import { OVERVIEW_IMAGE_ERRORS } from '@/constants/errors';
+import { setOverviewImageId } from '@/redux/modal/modal.slice';
+import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { RootState, store } from '@/redux/store';
+import { selectOverviewImage } from './selectOverviewImage';
+
+jest.mock('../../../redux/store');
+
+describe('selectOverviewImage - plugin method', () => {
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  describe('when image id is valid', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            project: {
+              ...INITIAL_STORE_STATE_MOCK.project,
+              data: {
+                ...INITIAL_STORE_STATE_MOCK.project.data,
+                overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK],
+              },
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should dispatch action set overview image', () => {
+      selectOverviewImage(PROJECT_OVERVIEW_IMAGE_MOCK.idObject);
+
+      expect(dispatchSpy).toHaveBeenCalledWith(
+        setOverviewImageId(PROJECT_OVERVIEW_IMAGE_MOCK.idObject),
+      );
+    });
+  });
+
+  describe('when image id is NOT valid', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            project: {
+              ...INITIAL_STORE_STATE_MOCK.project,
+              data: {
+                ...INITIAL_STORE_STATE_MOCK.project.data,
+                overviewImageViews: [],
+              },
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should throw error', () => {
+      expect(() => selectOverviewImage(PROJECT_OVERVIEW_IMAGE_MOCK.idObject)).toThrow(
+        OVERVIEW_IMAGE_ERRORS.IMAGE_ID_IS_INVALID,
+      );
+    });
+  });
+});
diff --git a/src/services/pluginsManager/overviewImage/selectOverviewImage.ts b/src/services/pluginsManager/overviewImage/selectOverviewImage.ts
new file mode 100644
index 0000000000000000000000000000000000000000..71ef40f1ff80adc6892ac6621a62562750cd3be4
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/selectOverviewImage.ts
@@ -0,0 +1,17 @@
+import { OVERVIEW_IMAGE_ERRORS } from '@/constants/errors';
+import { setOverviewImageId } from '@/redux/modal/modal.slice';
+import { projectOverviewImagesSelector } from '@/redux/project/project.selectors';
+import { store } from '@/redux/store';
+
+export const selectOverviewImage = (imageId: number): void => {
+  const { dispatch, getState } = store;
+  const overviewImages = projectOverviewImagesSelector(getState());
+  const foundOverviewImage = overviewImages.find(o => o.idObject === imageId);
+  const isImageIdValid = Boolean(foundOverviewImage);
+
+  if (!isImageIdValid) {
+    throw new Error(OVERVIEW_IMAGE_ERRORS.IMAGE_ID_IS_INVALID);
+  }
+
+  dispatch(setOverviewImageId(imageId));
+};
diff --git a/src/services/pluginsManager/overviewImage/showOverviewImageModal.test.ts b/src/services/pluginsManager/overviewImage/showOverviewImageModal.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f829470b22eb062f67a5e17a6641ffdbde72cbe7
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/showOverviewImageModal.test.ts
@@ -0,0 +1,105 @@
+import { OVERVIEW_IMAGE_ERRORS } from '@/constants/errors';
+import { openOverviewImagesModalById } from '@/redux/modal/modal.slice';
+import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { RootState, store } from '@/redux/store';
+import { showOverviewImageModal } from './showOverviewImageModal';
+
+jest.mock('../../../redux/store');
+
+describe('showOverviewImageModal - plugin method', () => {
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
+  const getStateSpy = jest.spyOn(store, 'getState');
+
+  beforeEach(() => {
+    jest.resetAllMocks();
+  });
+
+  describe('when image id is not provided', () => {
+    const defaultImageId = 23332;
+
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            project: {
+              ...INITIAL_STORE_STATE_MOCK.project,
+              data: {
+                ...INITIAL_STORE_STATE_MOCK.project.data,
+                overviewImageViews: [
+                  PROJECT_OVERVIEW_IMAGE_MOCK,
+                  {
+                    ...PROJECT_OVERVIEW_IMAGE_MOCK,
+                    idObject: defaultImageId,
+                  },
+                ],
+                topOverviewImage: {
+                  ...PROJECT_OVERVIEW_IMAGE_MOCK,
+                  idObject: defaultImageId,
+                },
+              },
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should dispatch action set overview image with defaultImageId', () => {
+      showOverviewImageModal();
+
+      expect(dispatchSpy).toHaveBeenCalledWith(openOverviewImagesModalById(defaultImageId));
+    });
+  });
+
+  describe('when image id is valid', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            project: {
+              ...INITIAL_STORE_STATE_MOCK.project,
+              data: {
+                ...INITIAL_STORE_STATE_MOCK.project.data,
+                overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK],
+                topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK,
+              },
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should dispatch action set overview image', () => {
+      showOverviewImageModal(PROJECT_OVERVIEW_IMAGE_MOCK.idObject);
+
+      expect(dispatchSpy).toHaveBeenCalledWith(
+        openOverviewImagesModalById(PROJECT_OVERVIEW_IMAGE_MOCK.idObject),
+      );
+    });
+  });
+
+  describe('when image id is NOT valid', () => {
+    beforeEach(() => {
+      getStateSpy.mockImplementation(
+        () =>
+          ({
+            ...INITIAL_STORE_STATE_MOCK,
+            project: {
+              ...INITIAL_STORE_STATE_MOCK.project,
+              data: {
+                ...INITIAL_STORE_STATE_MOCK.project.data,
+                overviewImageViews: [],
+                topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK,
+              },
+            },
+          }) as RootState,
+      );
+    });
+
+    it('should throw error', () => {
+      expect(() => showOverviewImageModal(PROJECT_OVERVIEW_IMAGE_MOCK.idObject)).toThrow(
+        OVERVIEW_IMAGE_ERRORS.IMAGE_ID_IS_INVALID,
+      );
+    });
+  });
+});
diff --git a/src/services/pluginsManager/overviewImage/showOverviewImageModal.ts b/src/services/pluginsManager/overviewImage/showOverviewImageModal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ac4351069bceb73d3a136dfe8a11d357ee7ba165
--- /dev/null
+++ b/src/services/pluginsManager/overviewImage/showOverviewImageModal.ts
@@ -0,0 +1,23 @@
+import { OVERVIEW_IMAGE_ERRORS } from '@/constants/errors';
+import { openOverviewImagesModalById } from '@/redux/modal/modal.slice';
+import {
+  projectDefaultOverviewImageIdSelector,
+  projectOverviewImagesSelector,
+} from '@/redux/project/project.selectors';
+import { store } from '@/redux/store';
+
+export const showOverviewImageModal = (imageId?: number): void => {
+  const { dispatch, getState } = store;
+  const overviewImages = projectOverviewImagesSelector(getState());
+  const defaultImageId = projectDefaultOverviewImageIdSelector(getState());
+  const selectedImageId = imageId || defaultImageId;
+
+  const foundOverviewImage = overviewImages.find(o => o.idObject === selectedImageId);
+  const isImageIdValid = Boolean(foundOverviewImage);
+
+  if (!isImageIdValid) {
+    throw new Error(OVERVIEW_IMAGE_ERRORS.IMAGE_ID_IS_INVALID);
+  }
+
+  dispatch(openOverviewImagesModalById(selectedImageId));
+};
diff --git a/src/services/pluginsManager/pluginsManager.ts b/src/services/pluginsManager/pluginsManager.ts
index c0b7bd2b474b3c61cce3aa8fdfcd2de6d3cf2e54..f432527ab6e8e1f97755f1864745abb1819a687a 100644
--- a/src/services/pluginsManager/pluginsManager.ts
+++ b/src/services/pluginsManager/pluginsManager.ts
@@ -2,18 +2,27 @@ import { PLUGINS_CONTENT_ELEMENT_ATTR_NAME, PLUGINS_CONTENT_ELEMENT_ID } from '@
 import { registerPlugin } from '@/redux/plugins/plugins.thunks';
 import { store } from '@/redux/store';
 import md5 from 'crypto-js/md5';
+import { bioEntitiesMethods } from './bioEntities';
 import { getModels } from './map/models/getModels';
 import { openMap } from './map/openMap';
-import { bioEntitiesMethods } from './bioEntities';
+import { getCenter } from './map/position/getCenter';
+import { setCenter } from './map/position/setCenter';
 import { triggerSearch } from './map/triggerSearch';
+import { getZoom } from './map/zoom/getZoom';
+import { setZoom } from './map/zoom/setZoom';
+import { getCurrentOverviewImage } from './overviewImage/getCurrentOverviewImage';
+import { getOverviewImages } from './overviewImage/getOverviewImages';
+import { hideOverviewImageModal } from './overviewImage/hideOverviewImageModal';
+import { selectOverviewImage } from './overviewImage/selectOverviewImage';
+import { showOverviewImageModal } from './overviewImage/showOverviewImageModal';
 import { PluginsEventBus } from './pluginsEventBus';
-import { getProjectId } from './project/data/getProjectId';
-import { getName } from './project/data/getName';
-import { getVersion } from './project/data/getVersion';
-import { getDisease } from './project/data/getDisease';
-import { getOrganism } from './project/data/getOrganism';
 import type { PluginsManagerType } from './pluginsManager.types';
 import { configurationMapper } from './pluginsManager.utils';
+import { getDisease } from './project/data/getDisease';
+import { getName } from './project/data/getName';
+import { getOrganism } from './project/data/getOrganism';
+import { getProjectId } from './project/data/getProjectId';
+import { getVersion } from './project/data/getVersion';
 
 import { getBounds } from './map/data/getBounds';
 import { fitBounds } from './map/fitBounds';
@@ -45,6 +54,17 @@ export const PluginsManager: PluginsManagerType = {
         fitBounds,
         openMap,
         triggerSearch,
+        getZoom,
+        setZoom,
+        getCenter,
+        setCenter,
+      },
+      overviewImage: {
+        getCurrentOverviewImage,
+        getOverviewImages,
+        hideOverviewImageModal,
+        selectOverviewImage,
+        showOverviewImageModal,
       },
       project: {
         data: {
diff --git a/src/types/error.ts b/src/types/error.ts
new file mode 100644
index 0000000000000000000000000000000000000000..48e6926ad764eeb1355d602ced1e5d149bcea3dc
--- /dev/null
+++ b/src/types/error.ts
@@ -0,0 +1,3 @@
+export interface PluginError {
+  message: string;
+}