diff --git a/__tests__/src/actions/window.test.js b/__tests__/src/actions/window.test.js
index 2dde5c7c11ba78e4f83b9e9cc8e93b369f3dbf30..7776bb9567d57ad31721232f9ef9f5bfd8b6661a 100644
--- a/__tests__/src/actions/window.test.js
+++ b/__tests__/src/actions/window.test.js
@@ -19,7 +19,10 @@ describe('window actions', () => {
           manifestId: null,
           rangeId: null,
           thumbnailNavigationPosition: 'bottom',
-          xywh: [0, 0, 400, 400],
+          x: 2700,
+          y: 2700,
+          width: 400,
+          height: 400,
           rotation: null,
           view: 'single',
         },
@@ -141,4 +144,48 @@ describe('window actions', () => {
       });
     });
   });
+
+  describe('setWindowSize', () => {
+    it('returns the appropriate action type', () => {
+      const id = 'abc123';
+      const expectedAction = {
+        type: ActionTypes.SET_WINDOW_SIZE,
+        payload: {
+          windowId: id,
+          size: {
+            x: 20,
+            y: 20,
+            width: 200,
+            height: 200,
+          },
+        },
+      };
+      expect(actions.setWindowSize(id, {
+        x: 20,
+        y: 20,
+        width: 200,
+        height: 200,
+      })).toEqual(expectedAction);
+    });
+  });
+
+  describe('updateWindowPosition', () => {
+    it('returns the appropriate action type', () => {
+      const id = 'abc123';
+      const expectedAction = {
+        type: ActionTypes.UPDATE_WINDOW_POSITION,
+        payload: {
+          windowId: id,
+          position: {
+            x: 20,
+            y: 20,
+          },
+        },
+      };
+      expect(actions.updateWindowPosition(id, {
+        x: 20,
+        y: 20,
+      })).toEqual(expectedAction);
+    });
+  });
 });
diff --git a/__tests__/src/actions/workspace.test.js b/__tests__/src/actions/workspace.test.js
index 587f6709bda3cea36d6bcde701c6a0ec42cc362e..5f430096a1d0c3daf2baad8fa41da608b1a886ce 100644
--- a/__tests__/src/actions/workspace.test.js
+++ b/__tests__/src/actions/workspace.test.js
@@ -49,4 +49,29 @@ describe('workspace actions', () => {
       expect(actions.setWorkspaceAddVisibility(true)).toEqual(expectedAction);
     });
   });
+  describe('setWorkspaceViewportPosition', () => {
+    it('should set the workspace add visibility', () => {
+      const expectedAction = {
+        type: ActionTypes.SET_WORKSPACE_VIEWPORT_POSITION,
+        payload: {
+          position: {
+            x: 20,
+            y: 20,
+          },
+        },
+      };
+      expect(actions.setWorkspaceViewportPosition({
+        x: 20,
+        y: 20,
+      })).toEqual(expectedAction);
+    });
+  });
+  describe('toggleWorkspaceExposeMode', () => {
+    it('should set the exposeMode to true', () => {
+      const expectedAction = {
+        type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE,
+      };
+      expect(actions.toggleWorkspaceExposeMode()).toEqual(expectedAction);
+    });
+  });
 });
diff --git a/__tests__/src/components/App.test.js b/__tests__/src/components/App.test.js
index 4a9b939663e61883d499bdd2edd2fefe41e1bdeb..3c34047dc72e8fa014b904e6bc8eae46d4669540 100644
--- a/__tests__/src/components/App.test.js
+++ b/__tests__/src/components/App.test.js
@@ -28,7 +28,7 @@ function createWrapper(props) {
 describe('App', () => {
   it('should render outer element correctly', () => {
     const wrapper = createWrapper();
-    expect(wrapper.find('div.mirador-app').length).toBe(1);
+    expect(wrapper.find('div.mirador-viewer').length).toBe(1);
   });
 
   it('should render all needed elements ', () => {
diff --git a/__tests__/src/components/Window.test.js b/__tests__/src/components/Window.test.js
index 301b75b7852431700caa2758cd6a6463c80cf1a1..da8c84ca4ee286e648a1c10a5caabe6d050a8d17 100644
--- a/__tests__/src/components/Window.test.js
+++ b/__tests__/src/components/Window.test.js
@@ -17,7 +17,13 @@ function createWrapper(props, context) {
 
 describe('Window', () => {
   let wrapper;
-  const window = { id: 123, xywh: [0, 0, 400, 500] };
+  const window = {
+    id: 123,
+    x: 2700,
+    y: 2700,
+    width: 400,
+    height: 400,
+  };
   it('should render nothing, if provided with no window data', () => {
     wrapper = shallow(<Window />);
     expect(wrapper.find('.mirador-window')).toHaveLength(0);
diff --git a/__tests__/src/components/Workspace.test.js b/__tests__/src/components/Workspace.test.js
index 83ff8808fdcaaf11e049ba712369c2a867d7c740..92c40025b979cf528eb3d06b5fea170556005890 100644
--- a/__tests__/src/components/Workspace.test.js
+++ b/__tests__/src/components/Workspace.test.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import WorkspaceMosaic from '../../../src/containers/WorkspaceMosaic';
+import WorkspaceElastic from '../../../src/containers/WorkspaceElastic';
 import Window from '../../../src/containers/Window';
 import { Workspace } from '../../../src/components/Workspace';
 
@@ -22,12 +23,23 @@ function createWrapper(props) {
 }
 
 describe('Workspace', () => {
+  describe('if workspace type is elastic', () => {
+    it('should render <WorkspaceElastic/> properly', () => {
+      const wrapper = createWrapper({ workspaceType: 'elastic' });
+
+      expect(wrapper.matchesElement(
+        <div className="mirador-workspace-viewport mirador-workspace-with-control-panel">
+          <WorkspaceElastic />
+        </div>,
+      )).toBe(true);
+    });
+  });
   describe('if workspace type is mosaic', () => {
     it('should render <WorkspaceMosaic/> properly', () => {
       const wrapper = createWrapper();
 
       expect(wrapper.matchesElement(
-        <div className="mirador-workspace mirador-workspace-with-control-panel">
+        <div className="mirador-workspace-viewport mirador-workspace-with-control-panel">
           <WorkspaceMosaic windows={windows} />
         </div>,
       )).toBe(true);
@@ -38,7 +50,7 @@ describe('Workspace', () => {
       const wrapper = createWrapper({ workspaceType: 'bubu' });
 
       expect(wrapper.matchesElement(
-        <div className="mirador-workspace mirador-workspace-with-control-panel">
+        <div className="mirador-workspace-viewport mirador-workspace-with-control-panel">
           <Window window={{ id: 1 }} />
           <Window window={{ id: 2 }} />
         </div>,
diff --git a/__tests__/src/components/WorkspaceElastic.test.js b/__tests__/src/components/WorkspaceElastic.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9efa1145efdb0192ca3d6d06d5b2979f08f147d7
--- /dev/null
+++ b/__tests__/src/components/WorkspaceElastic.test.js
@@ -0,0 +1,137 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { Rnd } from 'react-rnd';
+import WorkspaceElastic from '../../../src/components/WorkspaceElastic';
+
+/** create wrapper */
+function createWrapper(props) {
+  return shallow(
+    <WorkspaceElastic
+      windows={{}}
+      workspace={{
+        viewportPosition: {
+          x: 20,
+          y: 20,
+        },
+      }}
+      setWorkspaceViewportPosition={() => {}}
+      setWindowSize={() => {}}
+      updateWindowPosition={() => {}}
+      {...props}
+    />,
+  );
+}
+
+describe('WorkspaceElastic', () => {
+  const windows = {
+    1: {
+      id: 1,
+      x: 20,
+      y: 20,
+      width: 200,
+      height: 200,
+    },
+    2: {
+      id: 2,
+      x: 25,
+      y: 25,
+      width: 300,
+      height: 400,
+    },
+  };
+  let wrapper;
+  beforeEach(() => {
+    wrapper = createWrapper({ windows });
+  });
+  it('should render properly with an initialValue', () => {
+    expect(wrapper.find(Rnd).length).toBe(3);
+    expect(wrapper
+      .find(Rnd)
+      .at(1)
+      .props().size)
+      .toEqual({
+        width: 200,
+        height: 200,
+      });
+    expect(wrapper
+      .find(Rnd)
+      .at(2)
+      .props().position)
+      .toEqual({
+        x: 25,
+        y: 25,
+      });
+    expect(wrapper
+      .find(Rnd)
+      .at(2)
+      .props().size)
+      .toEqual({
+        width: 300,
+        height: 400,
+      });
+  });
+  describe('window behaviour', () => {
+    it('when windows are dragged', () => {
+      const mockDragStop = jest.fn();
+      wrapper = createWrapper({
+        windows,
+        updateWindowPosition: mockDragStop,
+      });
+      wrapper
+        .find(Rnd)
+        .at(1)
+        .props()
+        .onDragStop('myevent', {
+          x: 200,
+          y: 200,
+        });
+      expect(mockDragStop).toHaveBeenCalledWith(1, {
+        x: 200,
+        y: 200,
+      });
+    });
+    it('when windows are resized', () => {
+      const mockOnResize = jest.fn();
+      wrapper = createWrapper({
+        windows,
+        setWindowSize: mockOnResize,
+      });
+      wrapper
+        .find(Rnd)
+        .at(1)
+        .props()
+        .onResize('myevent', 'direction', {
+          style: {
+            width: 400,
+            height: 200,
+          },
+        });
+      expect(mockOnResize).toHaveBeenCalledWith(1, {
+        width: 400,
+        height: 200,
+      });
+    });
+  });
+
+  describe('workspace behaviour', () => {
+    it('when workspace itself is dragged', () => {
+      const mockDragStop = jest.fn();
+      wrapper = createWrapper({
+        windows,
+        setWorkspaceViewportPosition: mockDragStop,
+      });
+      wrapper
+        .find(Rnd)
+        .at(0)
+        .props()
+        .onDragStop('myevent', {
+          x: 200,
+          y: 200,
+        });
+      expect(mockDragStop).toHaveBeenCalledWith({
+        x: 200,
+        y: 200,
+      });
+    });
+  });
+});
diff --git a/__tests__/src/reducers/windows.test.js b/__tests__/src/reducers/windows.test.js
index b70ba0c023a0724110b23ecdf9e22afa4fe9a30a..4107847164b411a87a5a14bb3f69f81307a7e0e1 100644
--- a/__tests__/src/reducers/windows.test.js
+++ b/__tests__/src/reducers/windows.test.js
@@ -170,4 +170,66 @@ describe('windows reducer', () => {
       expect(windowsReducer(beforeState, action)).toEqual(expectedState);
     });
   });
+
+  it('should handle SET_WINDOW_SIZE', () => {
+    expect(windowsReducer({
+      abc123: {
+        id: 'abc123',
+      },
+      def456: {
+        id: 'def456',
+      },
+    }, {
+      type: ActionTypes.SET_WINDOW_SIZE,
+      payload: {
+        windowId: 'abc123',
+        size: {
+          x: 20,
+          y: 20,
+          width: 200,
+          height: 200,
+        },
+      },
+    })).toEqual({
+      abc123: {
+        id: 'abc123',
+        x: 20,
+        y: 20,
+        width: 200,
+        height: 200,
+      },
+      def456: {
+        id: 'def456',
+      },
+    });
+  });
+
+  it('should handle UPDATE_WINDOW_POSITION', () => {
+    expect(windowsReducer({
+      abc123: {
+        id: 'abc123',
+      },
+      def456: {
+        id: 'def456',
+      },
+    }, {
+      type: ActionTypes.UPDATE_WINDOW_POSITION,
+      payload: {
+        windowId: 'abc123',
+        position: {
+          x: 20,
+          y: 20,
+        },
+      },
+    })).toEqual({
+      abc123: {
+        id: 'abc123',
+        x: 20,
+        y: 20,
+      },
+      def456: {
+        id: 'def456',
+      },
+    });
+  });
 });
diff --git a/__tests__/src/reducers/workspace.test.js b/__tests__/src/reducers/workspace.test.js
index 26e02a0d877cb6704844bbe21a9319c369fd4e01..9873e434d0160319f421233d64e25bcfc374382f 100644
--- a/__tests__/src/reducers/workspace.test.js
+++ b/__tests__/src/reducers/workspace.test.js
@@ -42,4 +42,27 @@ describe('workspace reducer', () => {
       isWorkspaceAddVisible: true,
     });
   });
+  it('should handle SET_WORKSPACE_VIEWPORT_POSITION', () => {
+    expect(workspaceReducer([], {
+      type: ActionTypes.SET_WORKSPACE_VIEWPORT_POSITION,
+      payload: {
+        position: {
+          x: 50,
+          y: 50,
+        },
+      },
+    })).toEqual({
+      viewportPosition: {
+        x: 50,
+        y: 50,
+      },
+    });
+  });
+  it('should handle TOGGLE_WORKSPACE_EXPOSE_MODE', () => {
+    expect(workspaceReducer([], {
+      type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE,
+    })).toEqual({
+      exposeModeOn: true,
+    });
+  });
 });
diff --git a/package.json b/package.json
index 2e30890ca30358fee9349ff9d5229dff6f098b93..7b64a3c3730e104bdf203d3a4d1451f69dfb0953 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
     "react-mosaic-component": "^2.1.0",
     "react-placeholder": "^3.0.1",
     "react-redux": "^6.0.0",
+    "react-rnd": "^9.1.1",
     "react-virtualized": "^9.21.0",
     "redux": "4.0.1",
     "redux-devtools-extension": "^2.13.2",
@@ -85,6 +86,7 @@
     "jest": "^24.1.0",
     "jest-fetch-mock": "^2.1.1",
     "jest-puppeteer": "^4.0.0",
+    "jsdom": "13.2.0",
     "json-server": "^0.14.2",
     "puppeteer": "^1.12.0",
     "react-dev-utils": "^7.0.3",
diff --git a/src/components/App.js b/src/components/App.js
index 41712e1e7e3316f44d072a5cdfaaa67e11218842..44c84b0301c4155a8d7c4f0205099307f2085ac7 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -57,7 +57,7 @@ export class App extends Component {
     });
 
     return (
-      <div className={classNames(classes.background, ns('app'))}>
+      <div className={classNames(classes.background, ns('viewer'))}>
         <I18nextProvider i18n={this.i18n}>
           <MuiThemeProvider theme={createMuiTheme(theme)}>
             <Fullscreen
diff --git a/src/components/Workspace.js b/src/components/Workspace.js
index 8de5b49767c52ee79eb5a3997dd393bac49b0b44..bc8deccf68bf624f5bbb2fe8eff41dbd5cd6bf12 100644
--- a/src/components/Workspace.js
+++ b/src/components/Workspace.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import Window from '../containers/Window';
 import WorkspaceMosaic from '../containers/WorkspaceMosaic';
+import WorkspaceElastic from '../containers/WorkspaceElastic';
 import ns from '../config/css-ns';
 
 /**
@@ -17,6 +18,8 @@ export class Workspace extends React.Component {
   workspaceByType() {
     const { workspaceType, windows } = this.props;
     switch (workspaceType) {
+      case 'elastic':
+        return <WorkspaceElastic />;
       case 'mosaic':
         return <WorkspaceMosaic windows={windows} />;
       default:
@@ -39,7 +42,7 @@ export class Workspace extends React.Component {
       <div
         className={
           classNames(
-            ns('workspace'),
+            ns('workspace-viewport'),
             (isWorkspaceControlPanelVisible && ns('workspace-with-control-panel')),
           )
         }
diff --git a/src/components/WorkspaceElastic.js b/src/components/WorkspaceElastic.js
new file mode 100644
index 0000000000000000000000000000000000000000..65de11c19693ac3567cfcba6aaed850c3d346357
--- /dev/null
+++ b/src/components/WorkspaceElastic.js
@@ -0,0 +1,84 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Rnd } from 'react-rnd';
+import Window from '../containers/Window';
+import ns from '../config/css-ns';
+
+/**
+ * Represents a work area that contains any number of windows
+ * @memberof Workspace
+ * @private
+ */
+class WorkspaceElastic extends React.Component {
+  /**
+   */
+  render() {
+    const {
+      workspace,
+      windows,
+      setWorkspaceViewportPosition,
+      updateWindowPosition,
+      setWindowSize,
+    } = this.props;
+    return (
+      <Rnd
+        default={{
+          width: 5000,
+          height: 5000,
+        }}
+        position={{ x: workspace.viewportPosition.x, y: workspace.viewportPosition.y }}
+        enableResizing={{
+          top: false,
+          right: false,
+          bottom: false,
+          left: false,
+          topRight: false,
+          bottomRight: false,
+          bottomLeft: false,
+          topLeft: false,
+        }}
+        onDragStop={(e, d) => {
+          setWorkspaceViewportPosition({ x: d.x, y: d.y });
+        }}
+        cancel={`.${ns('window')}`}
+        className={ns('workspace')}
+      >
+        {
+          Object.values(windows).map(window => (
+            <Rnd
+              key={window.id}
+              size={{ width: window.width, height: window.height }}
+              position={{ x: window.x, y: window.y }}
+              bounds="parent"
+              onDragStop={(e, d) => {
+                updateWindowPosition(window.id, { x: d.x, y: d.y });
+              }}
+              onResize={(e, direction, ref, delta, position) => {
+                setWindowSize(window.id, {
+                  width: ref.style.width,
+                  height: ref.style.height,
+                  ...position,
+                });
+              }}
+              dragHandleClassName={ns('window-top-bar')}
+            >
+              <Window
+                window={window}
+              />
+            </Rnd>
+          ))
+        }
+      </Rnd>
+    );
+  }
+}
+
+WorkspaceElastic.propTypes = {
+  setWorkspaceViewportPosition: PropTypes.func.isRequired,
+  windows: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
+  workspace: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
+  updateWindowPosition: PropTypes.func.isRequired,
+  setWindowSize: PropTypes.func.isRequired,
+};
+
+export default WorkspaceElastic;
diff --git a/src/config/settings.js b/src/config/settings.js
index 5cb87c448822c6eaa14ce75caa9c31eb786ae7a1..bbb9561d623d4830efbb965786ffb42c1b60cfb7 100644
--- a/src/config/settings.js
+++ b/src/config/settings.js
@@ -44,5 +44,5 @@ export default {
   },
   workspaceControlPanel: {
     enabled: true,
-  }
+  },
 };
diff --git a/src/containers/Window.js b/src/containers/Window.js
index a3e940cf00ed0ac34f67a9c8f9017c1be59d0a59..a6de2f96331d7cfec0f22fadae6f72b81921189a 100644
--- a/src/containers/Window.js
+++ b/src/containers/Window.js
@@ -2,6 +2,7 @@ import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { Window } from '../components/Window';
 
+
 /**
  * mapStateToProps - used to hook up connect to action creators
  * @memberof Window
diff --git a/src/containers/WorkspaceElastic.js b/src/containers/WorkspaceElastic.js
new file mode 100644
index 0000000000000000000000000000000000000000..8c0b8d714bb1d69c700178fd79aefac3612b1288
--- /dev/null
+++ b/src/containers/WorkspaceElastic.js
@@ -0,0 +1,50 @@
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import * as actions from '../state/actions';
+import WorkspaceElastic from '../components/WorkspaceElastic';
+
+/**
+ * mapStateToProps - to hook up connect
+ * @memberof Workspace
+ * @private
+ */
+const mapStateToProps = state => (
+  {
+    workspace: state.workspace,
+    windows: state.windows,
+  }
+);
+
+
+/**
+ * mapDispatchToProps - used to hook up connect to action creators
+ * @memberof Workspace
+ * @private
+ */
+const mapDispatchToProps = (dispatch, props) => ({
+  setWorkspaceViewportPosition: (position) => {
+    dispatch(
+      actions.setWorkspaceViewportPosition(position),
+    );
+  },
+  toggleWorkspaceExposeMode: size => dispatch(
+    actions.toggleWorkspaceExposeMode(),
+  ),
+  updateWindowPosition: (windowId, position) => {
+    dispatch(
+      actions.updateWindowPosition(windowId, position),
+    );
+  },
+  setWindowSize: (windowId, size) => {
+    dispatch(
+      actions.setWindowSize(windowId, size),
+    );
+  },
+});
+
+const enhance = compose(
+  connect(mapStateToProps, mapDispatchToProps),
+  // further HOC go here
+);
+
+export default enhance(WorkspaceElastic);
diff --git a/src/state/actions/action-types.js b/src/state/actions/action-types.js
index 6b72b8683796702452ba033cdd9fccf33d84e801..e6ebd50c6d6f7f35894f7e334631411df9afac2c 100644
--- a/src/state/actions/action-types.js
+++ b/src/state/actions/action-types.js
@@ -6,9 +6,13 @@ const ActionTypes = {
 
   FOCUS_WINDOW: 'FOCUS_WINDOW',
   SET_WORKSPACE_FULLSCREEN: 'SET_WORKSPACE_FULLSCREEN',
+  SET_WORKSPACE_VIEWPORT_POSITION: 'SET_WORKSPACE_VIEWPORT_POSITION',
+  TOGGLE_WORKSPACE_EXPOSE_MODE: 'TOGGLE_WORKSPACE_EXPOSE_MODE',
   ADD_MANIFEST: 'ADD_MANIFEST',
   ADD_WINDOW: 'ADD_WINDOW',
   SET_CANVAS: 'SET_CANVAS',
+  UPDATE_WINDOW_POSITION: 'UPDATE_WINDOW_POSITION',
+  SET_WINDOW_SIZE: 'SET_WINDOW_SIZE',
   REMOVE_WINDOW: 'REMOVE_WINDOW',
   PICK_WINDOWING_SYSTEM: 'PICK_WINDOWING_SYSTEM',
   REQUEST_MANIFEST: 'REQUEST_MANIFEST',
diff --git a/src/state/actions/window.js b/src/state/actions/window.js
index afb5c766f61eaea98e0ec3b6c4edca3861826e80..6df55824032c41bcea503d2082db2bc8dcda54bd 100644
--- a/src/state/actions/window.js
+++ b/src/state/actions/window.js
@@ -26,7 +26,10 @@ export function addWindow(options) {
     manifestId: null,
     rangeId: null,
     thumbnailNavigationPosition: 'bottom', // bottom by default in settings.js
-    xywh: [0, 0, 400, 400],
+    width: 400,
+    height: 400,
+    x: 2700,
+    y: 2700,
     companionWindowIds: [],
     rotation: null,
     view: 'single',
@@ -138,3 +141,37 @@ export function setWindowThumbnailPosition(windowId, position) {
 export function setWindowViewType(windowId, viewType) {
   return { type: ActionTypes.SET_WINDOW_VIEW_TYPE, windowId, viewType };
 }
+
+/**
+ * updateWindowPosition - action creator
+ *
+ * @param  {String} windowId
+ * @param  {Array} position
+ * @memberof ActionCreators
+ */
+export function updateWindowPosition(windowId, position) {
+  return {
+    type: ActionTypes.UPDATE_WINDOW_POSITION,
+    payload: {
+      windowId,
+      position,
+    },
+  };
+}
+
+/**
+ * setWindowSize - action creator
+ *
+ * @param  {String} windowId
+ * @param  {Object} size
+ * @memberof ActionCreators
+ */
+export function setWindowSize(windowId, size) {
+  return {
+    type: ActionTypes.SET_WINDOW_SIZE,
+    payload: {
+      windowId,
+      size,
+    },
+  };
+}
diff --git a/src/state/actions/workspace.js b/src/state/actions/workspace.js
index b8b03d96e4f23a21d85adc75c38f1fda046cb511..6da0e4898d127da4000cf334164bc1f670a71f1d 100644
--- a/src/state/actions/workspace.js
+++ b/src/state/actions/workspace.js
@@ -1,6 +1,5 @@
 import ActionTypes from './action-types';
 
-/* eslint-disable import/prefer-default-export */
 /**
  * setWorkspaceFullscreen - action creator
  *
@@ -39,3 +38,33 @@ export function updateWorkspaceMosaicLayout(layout) {
 export function setWorkspaceAddVisibility(isWorkspaceAddVisible) {
   return { type: ActionTypes.SET_WORKSPACE_ADD_VISIBILITY, isWorkspaceAddVisible };
 }
+
+/**
+ * setWorkspaceViewportPosition - action creator
+ *
+ * @param  {Object} position
+ * @memberof ActionCreators
+ */
+export function setWorkspaceViewportPosition(position) {
+  return {
+    type: ActionTypes.SET_WORKSPACE_VIEWPORT_POSITION,
+    payload: {
+      position: {
+        x: position.x,
+        y: position.y,
+      },
+    },
+  };
+}
+
+/**
+ * toggleWorkspaceExposeMode - action creator
+ *
+ * @param  {Object} position
+ * @memberof ActionCreators
+ */
+export function toggleWorkspaceExposeMode() {
+  return {
+    type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE,
+  };
+}
diff --git a/src/state/reducers/windows.js b/src/state/reducers/windows.js
index b5e0a2ba4bfb530900205452034e4a1c2f54496d..96a95cd8102517997298af7c850699ebcdcb0bfc 100644
--- a/src/state/reducers/windows.js
+++ b/src/state/reducers/windows.js
@@ -55,6 +55,30 @@ export const windowsReducer = (state = {}, action) => {
           ),
         },
       };
+    case ActionTypes.UPDATE_WINDOW_POSITION:
+      return {
+        ...state,
+        [action.payload.windowId]: {
+          ...state[action.payload.windowId],
+          x: action.payload.position.x,
+          y: action.payload.position.y,
+        },
+      };
+    case ActionTypes.SET_WINDOW_SIZE:
+      return {
+        ...state,
+        [action.payload.windowId]: {
+          ...state[action.payload.windowId],
+          width: action.payload.size.width,
+          height: action.payload.size.height,
+          x: action.payload.size.x,
+          y: action.payload.size.y,
+        },
+      };
+    case ActionTypes.NEXT_CANVAS:
+      return setCanvasIndex(state, action.windowId, currentIndex => currentIndex + 1);
+    case ActionTypes.PREVIOUS_CANVAS:
+      return setCanvasIndex(state, action.windowId, currentIndex => currentIndex - 1);
     case ActionTypes.SET_CANVAS:
       return setCanvasIndex(state, action.windowId, currentIndex => action.canvasIndex);
     default:
@@ -66,7 +90,7 @@ export const windowsReducer = (state = {}, action) => {
  * @param {Object} state
  * @param {String} windowId
  * @param {Function} getIndex - gets curent canvas index passed and should return new index
-*/
+ */
 function setCanvasIndex(state, windowId, getIndex) {
   return Object.values(state).reduce((object, window) => {
     if (window.id === windowId) {
diff --git a/src/state/reducers/workspace.js b/src/state/reducers/workspace.js
index 52a339a47828859267cab9085cf36b26890e7c95..6abaeb93abc2395bb2cf99343aa8cdaf5b67a3c2 100644
--- a/src/state/reducers/workspace.js
+++ b/src/state/reducers/workspace.js
@@ -3,7 +3,16 @@ import ActionTypes from '../actions/action-types';
 /**
  * workspaceReducer
  */
-export const workspaceReducer = (state = {}, action) => {
+export const workspaceReducer = (
+  state = { // we'll need to abstract this more, methinks.
+    viewportPosition: {
+      x: -2500,
+      y: -2500,
+    },
+    exposeModeOn: false,
+  },
+  action,
+) => {
   switch (action.type) {
     case ActionTypes.FOCUS_WINDOW:
       return { ...state, focusedWindowId: action.windowId };
@@ -15,6 +24,10 @@ export const workspaceReducer = (state = {}, action) => {
       return { ...state, layout: action.layout };
     case ActionTypes.SET_WORKSPACE_ADD_VISIBILITY:
       return { ...state, isWorkspaceAddVisible: action.isWorkspaceAddVisible };
+    case ActionTypes.SET_WORKSPACE_VIEWPORT_POSITION:
+      return { ...state, viewportPosition: action.payload.position };
+    case ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE:
+      return { ...state, exposeModeOn: !state.exposeModeOn };
     default:
       return state;
   }
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 60c03c799e62218a620bcd7e758537546a9f7101..97ac3b29902deed7ee26d88118f0b11b18492fef 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -1,10 +1,13 @@
 @import 'variables';
 
 .mirador {
-  &-app {
-    height: 100%;
-    position: relative;
-    width: 100%;
+  &-viewer {
+    bottom: 0;
+    left: 0;
+    overflow: hidden;
+    position: absolute;
+    right: 0;
+    top: 0;
 
     .mosaic-window-toolbar {
       display: none;
@@ -17,17 +20,22 @@
     }
   }
 
-  &-workspace {
+  &-workspace-viewport {
     bottom: 0;
-    box-sizing: border-box;
     left: 0;
-    margin: 0;
-    overflow: scroll;
+    overflow: hidden;
     position: absolute;
     right: 0;
     top: 0;
   }
 
+  &-workspace {
+    box-sizing: border-box;
+    margin: 0;
+    overflow: scroll;
+    position: absolute;
+  }
+
   &-workspace-with-control-panel {
     padding-left: 100px; // The width of the control panel
   }
@@ -48,6 +56,7 @@
     display: flex;
     flex-direction: column;
     height: 100%;
+    width: 100%;
   }
 
   &-osd-container {