diff --git a/docs/releases/v2.14.4.md b/docs/releases/v2.14.4.md
index 09ba75e4890ffe86a72f422ef1290d0da532b3b2..c6ba74a276d284dd2f32a7b2d115ebe2f04c0566 100644
--- a/docs/releases/v2.14.4.md
+++ b/docs/releases/v2.14.4.md
@@ -4,6 +4,7 @@
 
 - Sagittal view of perspective PiP changes hemisphere when user navigates to the otehr hemisphere
 - Adds an additional degree adjustment to perspective PiP
+- Encode maximised panel state
 
 ## Behind the Scenes
 
diff --git a/src/routerModule/routeStateTransform.service.ts b/src/routerModule/routeStateTransform.service.ts
index 3e1b4b110af41530ae2a154a49503e17f71038ba..63e326041b9f6402a0798e24b3f22a246f84745f 100644
--- a/src/routerModule/routeStateTransform.service.ts
+++ b/src/routerModule/routeStateTransform.service.ts
@@ -4,13 +4,20 @@ import { map } from "rxjs/operators";
 import { SAPI } from "src/atlasComponents/sapi";
 import { translateV3Entities } from "src/atlasComponents/sapi/translateV3";
 import { SxplrRegion } from "src/atlasComponents/sapi/sxplrTypes"
-import { atlasSelection, defaultState, MainState, plugins, userInteraction } from "src/state";
+import { atlasAppearance, atlasSelection, defaultState, MainState, plugins, userInteraction, userInterface } from "src/state";
 import { decodeToNumber, encodeNumber, encodeURIFull, separator } from "./cipher";
 import { TUrlAtlas, TUrlPathObj, TUrlStandaloneVolume } from "./type";
 import { decodePath, encodeId, decodeId, encodePath } from "./util";
-import { QuickHash } from "src/util/fn";
+import { QuickHash, decodeBool, encodeBool, isNullish } from "src/util/fn";
 import { NEHUBA_CONFIG_SERVICE_TOKEN, NehubaConfigSvc } from "src/viewerModule/nehuba/config.service";
 
+type ViewerConfigState = {
+  panelMode: userInterface.PanelMode
+  panelOrder: string
+  octantRemoval: boolean
+  showDelineation: boolean
+}
+
 @Injectable()
 export class RouteStateTransformSvc {
 
@@ -181,7 +188,22 @@ export class RouteStateTransformSvc {
         console.error(`cannot parse navigation state`, e)
       }
     }
+    const viewerConfigState = returnObj['vs'] && returnObj['vs'][0]
+    if (viewerConfigState) {
+
+      const { panelMode, panelOrder } = !!viewerConfigState
+      ? this.decodeMiscState(viewerConfigState)
+      : { panelMode: "FOUR_PANEL" as const, panelOrder: "0123" }
+  
+      returnState['[state.ui]'].panelMode = panelMode
+      returnState['[state.ui]'].panelOrder = panelOrder
 
+      // TODO restoring octant removal and hidedelination is still quite buggy
+      // enable in future update
+      // returnState["[state.atlasAppearance]"].showDelineation = showDelineation
+      // returnState["[state.atlasAppearance]"].octantRemoval = octantRemoval  
+  
+    }
     // pluginState should always be defined, regardless if standalone volume or not
     const pluginStates = fullPath.queryParams['pl']
     if (pluginStates) {
@@ -245,6 +267,74 @@ export class RouteStateTransformSvc {
     return returnState
   }
 
+  public stateVersion = 'v1'
+
+  encodeMiscState(config: ViewerConfigState): string {
+    const { panelMode, panelOrder, octantRemoval, showDelineation } = config
+    if (isNullish(panelOrder) && isNullish(panelMode)) {
+      return null
+    }
+    let panelModeVal = 1
+    if (panelMode === "PIP_PANEL") {
+      panelModeVal = 2
+    }
+    let panelOrderVal = 4
+    if (("0123".split("")).includes(panelOrder[0])){
+      panelOrderVal = parseInt(panelOrder[0])
+    }
+    const encodedBools = encodeBool(octantRemoval, showDelineation)
+    const array = new Uint8Array([
+      panelModeVal,
+      panelOrderVal,
+      encodedBools
+    ])
+    const encodedVal = window.btoa(new Uint8Array(array.buffer).reduce((data, v) => data + String.fromCharCode(v), ''))
+    return `${this.stateVersion}-${encodedVal}`
+  }
+
+  decodeMiscState(val: string){
+    if (!val.startsWith(`${this.stateVersion}-`)) {
+      throw new Error(`version must start with "${this.stateVersion}-"`)
+    }
+    const trimStart = new RegExp(`^${this.stateVersion}-`)
+    const encodedVal = val.replace(trimStart, "")
+    const array = Uint8Array.from(window.atob(encodedVal), v => v.charCodeAt(0))
+
+    let returnVal: Partial<ViewerConfigState> = {}
+
+    const panelModeVal = array[0]
+    if (panelModeVal === 1) {
+      returnVal.panelMode = "FOUR_PANEL"
+    } else if (panelModeVal) {
+      returnVal.panelMode = "PIP_PANEL"
+    } else {
+      console.warn(`panelmode set to ${panelModeVal}, which is unknown, set to default (4 panel)`)
+      returnVal.panelMode = "FOUR_PANEL"
+    }
+    
+    let panelOrderVal = array[1]
+    let panelOrder = ""
+    while (panelOrder.length < 4) {
+      panelOrder += `${panelOrderVal % 4}`
+      panelOrderVal ++
+    }
+    if (
+      panelOrder.split("").some(
+        v => !("0123".split("")).includes(v)
+      )
+    ) {
+      console.warn(`panelOrder=${panelOrder} contains strings that is not in 0123, set to default (0123)`)
+      panelOrder = "0123"
+    }
+    returnVal.panelOrder = panelOrder
+
+    const [ octantRemoval, showDelineation ] = decodeBool(array[2])
+    returnVal.octantRemoval = octantRemoval
+    returnVal.showDelineation = showDelineation
+    
+    return returnVal
+  }
+
   async cvtStateToRoute(_state: MainState) {
     
     /**
@@ -262,6 +352,11 @@ export class RouteStateTransformSvc {
     const navigation = atlasSelection.selectors.navigation(state)
     const selectedFeature = userInteraction.selectors.selectedFeature(state)
 
+    const panelMode = userInterface.selectors.panelMode(state)
+    const panelOrder = userInterface.selectors.panelOrder(state)
+    const octantRemoval = atlasAppearance.selectors.octantRemoval(state)
+    const showDelineation = !(atlasAppearance.selectors.showDelineation(state))
+
     const searchParam = new URLSearchParams()
   
     let cNavString: string
@@ -301,7 +396,8 @@ export class RouteStateTransformSvc {
               .replace(/:/g, '~')
           )
         )
-      })()
+      })(),
+      vs: this.encodeMiscState({ octantRemoval, panelMode, panelOrder, showDelineation })
     }
   
     /**
diff --git a/src/routerModule/type.ts b/src/routerModule/type.ts
index 284b5e7a9441fd52be9281ad3dec5c749e390993..da828b1e6a77b25e9bfecdd8c2aee45e15bfce7a 100644
--- a/src/routerModule/type.ts
+++ b/src/routerModule/type.ts
@@ -16,6 +16,7 @@ export type TUrlPlugin<T> = {
 
 export type TUrlNav<T> = {
   ['@']: T // navstring
+  vs?: T
 }
 
 export type TUrlViewFeat<T> = {
diff --git a/src/state/userInterface/store.ts b/src/state/userInterface/store.ts
index cc854e820d61e94cbee9b5b95f988dbe9db0ec58..321e92c8806bd08930a59ef4a8c6a2e6cfac36f6 100644
--- a/src/state/userInterface/store.ts
+++ b/src/state/userInterface/store.ts
@@ -5,15 +5,11 @@ import { PanelMode } from "./const"
 export type UiStore = {
   panelMode: PanelMode
   panelOrder: string // permutation of 0123
-  octantRemoval: boolean
-  showDelineation: boolean
 }
 
 export const defaultState: UiStore = {
-  panelMode: 'FOUR_PANEL',
-  panelOrder: '0123',
-  octantRemoval: false,
-  showDelineation: true,
+  panelMode: null,
+  panelOrder: null,
 }
 
 export const reducer = createReducer(
diff --git a/src/util/fn.ts b/src/util/fn.ts
index 5a041b905ba4e7c1b0298c4a23e23de48993a65f..86b7ecf6236cfb0acf7f68d23e42e08f9dd587e3 100644
--- a/src/util/fn.ts
+++ b/src/util/fn.ts
@@ -463,7 +463,15 @@ type TGetShaderCfg = {
   opacity: number
 }
 
-function encodeBool(...flags: boolean[]) {
+export function decodeBool(num: number) {
+  const rBool: boolean[] = []
+  for (let i = 0; i < 8; i ++) {
+    rBool.push( ((num >> i) & 1) === 1 )
+  }
+  return rBool
+}
+
+export function encodeBool(...flags: boolean[]) {
   if (flags.length > 8) {
     throw new Error(`encodeBool can only handle upto 8 bools`)
   }
diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
index 118031cc0806bb692dead3bff0f7811adae32759..4abf5d72a4a3cbb34a0e52e024729a7f6845b19b 100644
--- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
+++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
@@ -1,13 +1,14 @@
 import { ChangeDetectorRef, Component, Inject, OnDestroy } from "@angular/core";
 import { select, Store } from "@ngrx/store";
-import { combineLatest, fromEvent, interval, merge, Observable, of, Subject, Subscription } from "rxjs";
+import { combineLatest, fromEvent, merge, Observable, of, Subject, Subscription } from "rxjs";
 import { userInterface } from "src/state";
 import { NehubaViewerUnit } from "../../nehubaViewer/nehubaViewer.component";
 import { NEHUBA_INSTANCE_INJTKN, takeOnePipe, getFourPanel, getHorizontalOneThree, getSinglePanel, getPipPanel, getVerticalOneThree } from "../../util";
 import { QUICKTOUR_DESC, QUICKTOUR_DESC_MD, ARIA_LABELS, IDS } from 'common/constants'
 import { IQuickTourData } from "src/ui/quickTour/constrants";
-import { debounce, debounceTime, distinctUntilChanged, filter, map, mapTo, switchMap, take } from "rxjs/operators";
+import { debounceTime, distinctUntilChanged, map, mapTo, switchMap, take } from "rxjs/operators";
 import {panelOrder} from "src/state/userInterface/selectors";
+import { switchMapWaitFor } from "src/util/fn";
 
 @Component({
   selector: `nehuba-layout-overlay`,
@@ -104,17 +105,20 @@ export class NehubaLayoutOverlay implements OnDestroy{
   }
 
   public panelMode$ = this.store$.pipe(
-    select(userInterface.selectors.panelMode)
+    select(userInterface.selectors.panelMode),
+    map(v => v || "FOUR_PANEL")
   )
 
   public panelOrder$ = this.store$.pipe(
     select(userInterface.selectors.panelOrder),
+    map(v => v || "0123")
   )
 
   public volumeChunkLoading$: Subject<boolean> = new Subject()
 
   public showPipPerspectiveView$ = this.store$.pipe(
     select(panelOrder),
+    map(v => v || "0123"),
     distinctUntilChanged(),
     map(po => po[0] !== '3')
   )
@@ -231,13 +235,12 @@ export class NehubaLayoutOverlay implements OnDestroy{
         this.panelMode$,
         this.panelOrder$,
       ]).pipe(
-        debounce(() =>
-          nehubaUnit?.nehubaViewer?.ngviewer
-            ? of(true)
-            : interval(16).pipe(
-              filter(() => nehubaUnit?.nehubaViewer?.ngviewer),
-              take(1)
-            )
+        switchMap(
+          switchMapWaitFor({
+            leading: true,
+            interval: 16,
+            condition: () => "0123".split("").every(v => !!this.nehubaViewPanels[Number(v)])
+          })
         )
       ).subscribe(([mode, panelOrder]) => {
 
@@ -246,13 +249,6 @@ export class NehubaLayoutOverlay implements OnDestroy{
 
         const viewPanels = panelOrder.split('').map(v => Number(v)).map(idx => this.nehubaViewPanels[idx]) as [HTMLElement, HTMLElement, HTMLElement, HTMLElement]
 
-        /**
-         * TODO smarter with event stream
-         */
-        if (!viewPanels.every(v => !!v)) {
-          return
-        }
-
         switch (this.currentPanelMode) {
         case "H_ONE_THREE": {
           const element = removeExistingPanels()
diff --git a/src/viewerModule/nehuba/viewerCtrl/effects.ts b/src/viewerModule/nehuba/viewerCtrl/effects.ts
deleted file mode 100644
index 5eeaafed8eaf61c7d03a5ddee0cb55759b39a8e6..0000000000000000000000000000000000000000
--- a/src/viewerModule/nehuba/viewerCtrl/effects.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Injectable } from "@angular/core";
-import { createEffect } from "@ngrx/effects";
-import { Store } from "@ngrx/store";
-import { of } from "rxjs";
-import { switchMap } from "rxjs/operators";
-import { atlasSelection, userInterface } from "src/state";
-
-@Injectable()
-export class ViewerCtrlEffects {
-  onTemplateChangeResetLayout$ = createEffect(() => this.store$.pipe(
-    atlasSelection.fromRootStore.distinctATP(),
-    switchMap(() => of(
-      userInterface.actions.setPanelMode({
-        panelMode: "FOUR_PANEL"
-      }),
-      userInterface.actions.setPanelOrder({
-        order: '0123'
-      }),
-    ))
-  ))
-
-  constructor(private store$: Store){}
-}
diff --git a/src/viewerModule/nehuba/viewerCtrl/module.ts b/src/viewerModule/nehuba/viewerCtrl/module.ts
index 082107630ef288fa064e13bb3ec779094ee2abe3..f4af0bbd3fcfdf847bb31a34fa27a66469b80938 100644
--- a/src/viewerModule/nehuba/viewerCtrl/module.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/module.ts
@@ -8,8 +8,6 @@ import { ViewerCtrlCmp } from "./viewerCtrlCmp/viewerCtrlCmp.component";
 import { PerspectiveViewSlider } from "./perspectiveViewSlider/perspectiveViewSlider.component";
 import { SnapPerspectiveOrientationCmp } from "src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component";
 import { WindowResizeModule } from "src/util/windowResize";
-import { EffectsModule } from "@ngrx/effects";
-import { ViewerCtrlEffects } from "./effects"
 
 @NgModule({
   imports: [
@@ -20,9 +18,6 @@ import { ViewerCtrlEffects } from "./effects"
     ReactiveFormsModule,
     ComponentsModule,
     WindowResizeModule,
-    EffectsModule.forFeature([
-      ViewerCtrlEffects
-    ])
   ],
   declarations: [
     ViewerCtrlCmp,
diff --git a/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts
index b73e082c07a55af21c7f148352956946e4157355..890e01b2eed7242f6249dfc512591ae9c1e6d865 100644
--- a/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts
@@ -15,7 +15,7 @@ import { atlasSelection } from "src/state";
 import { floatEquality } from "common/util"
 import { CURRENT_TEMPLATE_DIM_INFO, TemplateInfo } from "../../layerCtrl.service/layerCtrl.util";
 import { DestroyDirective } from "src/util/directives/destroy.directive";
-import { isNullish, isWheelEvent } from "src/util/fn"
+import { isNullish, isWheelEvent, switchMapWaitFor } from "src/util/fn"
 
 const MAX_DIM = 200
 
@@ -242,6 +242,11 @@ export class PerspectiveViewSlider {
       switchMap(templateSize => {
         return this.rangeControlSetting$.pipe(
           switchMap(orientation => this.navPosition$.pipe(
+            switchMap(
+              switchMapWaitFor({
+                condition: nav => !!nav && !!nav.real
+              })
+            ),
             take(1),
             map(nav => {
               if (!nav || !orientation || !templateSize) return null