diff --git a/package.json b/package.json
index 8b3f3a58a9110fbcb592137eda0ce04a153dc267..a0dd920987c7769ec25db9f5d9258fb416948396 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
     "jasmine": "^3.1.0",
     "jasmine-core": "^3.5.0",
     "jasmine-spec-reporter": "^4.2.1",
+    "json-loader": "^0.5.7",
     "karma": "^4.1.0",
     "karma-chrome-launcher": "^2.2.0",
     "karma-cli": "^2.0.0",
diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts
index 536a1760af1617ed1b9e1ff69b15c4706bc86d42..bbffae56c49aff6519c9724364975e0eb63e377e 100644
--- a/src/atlasViewer/atlasViewer.component.ts
+++ b/src/atlasViewer/atlasViewer.component.ts
@@ -24,11 +24,9 @@ import {
   concatMap,
   withLatestFrom,
 } from "rxjs/operators";
-import { AtlasViewerDataService } from "./atlasViewer.dataService.service";
 import { WidgetServices } from "./widgetUnit/widgetService.service";
 import { LayoutMainSide } from "../layouts/mainside/mainside.component";
 import { AtlasViewerConstantsServices, UNSUPPORTED_PREVIEW, UNSUPPORTED_INTERVAL } from "./atlasViewer.constantService.service";
-import { AtlasViewerURLService } from "./atlasViewer.urlService.service";
 import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service";
 
 import { NehubaContainer } from "../ui/nehubaContainer/nehubaContainer.component";
@@ -38,6 +36,7 @@ import { AGREE_COOKIE, AGREE_KG_TOS, SHOW_KG_TOS, SHOW_BOTTOM_SHEET } from "src/
 import { TabsetComponent } from "ngx-bootstrap/tabs";
 import { LocalFileService } from "src/services/localFile.service";
 import { MatDialog, MatDialogRef, MatSnackBar, MatSnackBarRef, MatBottomSheet, MatBottomSheetRef } from "@angular/material";
+import { isSame } from "src/util/fn";
 
 
 /**
@@ -120,10 +119,8 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
 
   constructor(
     private store: Store<IavRootStoreInterface>,
-    public dataService: AtlasViewerDataService,
     private widgetServices: WidgetServices,
     private constantsService: AtlasViewerConstantsServices,
-    public urlService: AtlasViewerURLService,
     public apiService: AtlasViewerAPIServices,
     private matDialog: MatDialog,
     private dispatcher$: ActionsSubject,
@@ -188,9 +185,8 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
 
     this.newViewer$ = this.store.pipe(
       select('viewerState'),
-      filter(state => isDefined(state) && isDefined(state.templateSelected)),
-      map(state => state.templateSelected),
-      distinctUntilChanged((t1, t2) => t1.name === t2.name)
+      select('templateSelected'),
+      distinctUntilChanged(isSame)
     )
 
     this.dedicatedView$ = this.store.pipe(
@@ -345,19 +341,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
     )
 
     this.subscriptions.push(
-      this.newViewer$.subscribe(template => {
-        this.darktheme = this.meetsRequirement ?
-          template.useTheme === 'dark' :
-          false
-
-        this.constantsService.darktheme = this.darktheme
-        
-        /* new viewer should reset the spatial data search */
-        this.store.dispatch({
-          type : FETCHED_SPATIAL_DATA,
-          fetchedDataEntries : []
-        })
-
+      this.newViewer$.subscribe(() => {
         this.widgetServices.clearAllWidgets()
       })
     )
diff --git a/src/atlasViewer/atlasViewer.constantService.service.ts b/src/atlasViewer/atlasViewer.constantService.service.ts
index cb6da036d05d4961dbccd1769c7ef5ca5a8c1576..bbe7dc29051b75331cbb9abd8c2ca0557e058303 100644
--- a/src/atlasViewer/atlasViewer.constantService.service.ts
+++ b/src/atlasViewer/atlasViewer.constantService.service.ts
@@ -1,12 +1,14 @@
 import { Injectable, OnDestroy } from "@angular/core";
 import { Store, select } from "@ngrx/store";
 import { IavRootStoreInterface } from "../services/stateStore.service";
-import { Observable, Subscription } from "rxjs";
-import { map, shareReplay, filter } from "rxjs/operators";
+import { Observable, Subscription, throwError, of, merge } from "rxjs";
+import { map, shareReplay, filter, switchMap, catchError, tap } from "rxjs/operators";
 import { SNACKBAR_MESSAGE } from "src/services/state/uiState.store";
+import { HttpClient } from "@angular/common/http";
 
 export const CM_THRESHOLD = `0.05`
 export const CM_MATLAB_JET = `float r;if( x < 0.7 ){r = 4.0 * x - 1.5;} else {r = -4.0 * x + 4.5;}float g;if (x < 0.5) {g = 4.0 * x - 0.5;} else {g = -4.0 * x + 3.5;}float b;if (x < 0.3) {b = 4.0 * x + 0.5;} else {b = -4.0 * x + 2.5;}float a = 1.0;`
+export const GLSL_COLORMAP_JET = `void main(){float x = toNormalized(getDataValue());${CM_MATLAB_JET}if(x>${CM_THRESHOLD}){emitRGB(vec3(r,g,b));}else{emitTransparent();}}`
 
 @Injectable({
   providedIn : 'root'
@@ -20,8 +22,6 @@ export class AtlasViewerConstantsServices implements OnDestroy {
   public useMobileUI$: Observable<boolean>
   public loadExportNehubaPromise : Promise<boolean>
 
-  public getActiveColorMapFragmentMain = ():string=>`void main(){float x = toNormalized(getDataValue());${CM_MATLAB_JET}if(x>${CM_THRESHOLD}){emitRGB(vec3(r,g,b));}else{emitTransparent();}}`
-
   public ngLandmarkLayerName = 'spatial landmark layer'
   public ngUserLandmarkLayerName = 'user landmark layer'
 
@@ -40,15 +40,6 @@ export class AtlasViewerConstantsServices implements OnDestroy {
    */
   private TIMEOUT = 16000
 
-  /**
-   * raceFetch 
-   */
-   public raceFetch = (url) => Promise.race([
-     fetch(url, this.getFetchOption()),
-     new Promise((_, reject) => setTimeout(() => {
-      reject(`fetch did not resolve under ${this.TIMEOUT} ms`)
-     }, this.TIMEOUT)) as Promise<Response>
-   ])
 
   /* TODO to be replaced by @id: Landmark/UNIQUE_ID in KG in the future */
   public testLandmarksChanged : (prevLandmarks : any[], newLandmarks : any[]) => boolean = (prevLandmarks:any[], newLandmarks:any[]) => {
@@ -60,6 +51,34 @@ export class AtlasViewerConstantsServices implements OnDestroy {
   // instead of using window.location.href, which includes query param etc
   public backendUrl = BACKEND_URL || `${window.location.origin}${window.location.pathname}`
 
+  private fetchTemplate = (templateUrl) => this.http.get(`${this.backendUrl}${templateUrl}`, { responseType: 'json' }).pipe(
+    switchMap((template:any) => {
+      if (template.nehubaConfig) return of(template)
+      if (template.nehubaConfigURL) return this.http.get(`${this.backendUrl}${template.nehubaConfigURL}`, { responseType: 'json' }).pipe(
+        map(nehubaConfig => {
+          return {
+            ...template,
+            nehubaConfig
+          }
+        })
+      )
+      throwError('neither nehubaConfig nor nehubaConfigURL defined')
+    })
+  )
+
+  public totalTemplates = null
+
+  public initFetchTemplate$ = this.http.get(`${this.backendUrl}templates`, { responseType: 'json' }).pipe(
+    tap((arr:any[]) => this.totalTemplates = arr.length),
+    switchMap((templates: string[]) => merge(
+      ...templates.map(this.fetchTemplate)
+    )),
+    catchError((err) => {
+      console.warn(`fetching templates error`, err)
+      return of(null)
+    })
+  )
+
   /* to be provided by KG in future */
   public templateUrlsPr : Promise<string[]> = new Promise((resolve, reject) => {
     fetch(`${this.backendUrl}templates`, this.getFetchOption())
@@ -233,14 +252,17 @@ Send us an email: <a target = "_blank" href = "mailto:${this.supportEmailAddress
   private repoUrl = `https://github.com/HumanBrainProject/interactive-viewer`
 
   constructor(
-    private store$: Store<IavRootStoreInterface>
+    private store$: Store<IavRootStoreInterface>,
+    private http: HttpClient,
   ){
 
     this.darktheme$ = this.store$.pipe(
       select('viewerState'),
       select('templateSelected'),
-      filter(v => !!v),
-      map(({useTheme}) => useTheme === 'dark'),
+      map(template => {
+        if (!template) return false
+        return template.useTheme === 'dark'
+      }),
       shareReplay(1)
     )
 
@@ -250,6 +272,10 @@ Send us an email: <a target = "_blank" href = "mailto:${this.supportEmailAddress
       shareReplay(1)
     )
 
+    this.subscriptions.push(
+      this.darktheme$.subscribe(flag => this.darktheme = flag)
+    )
+
     this.subscriptions.push(
       this.useMobileUI$.subscribe(bool => {
         if (bool) {
diff --git a/src/atlasViewer/atlasViewer.dataService.service.ts b/src/atlasViewer/atlasViewer.dataService.service.ts
deleted file mode 100644
index 31d9248911486947a0c7987e4d5e953ac8d132b4..0000000000000000000000000000000000000000
--- a/src/atlasViewer/atlasViewer.dataService.service.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { Injectable, OnDestroy } from "@angular/core";
-import { Store } from "@ngrx/store";
-import { FETCHED_TEMPLATE, IavRootStoreInterface } from "../services/stateStore.service";
-import { Subscription } from "rxjs";
-import { AtlasViewerConstantsServices } from "./atlasViewer.constantService.service";
-
-/**
- * TODO move constructor into else where and deprecate ASAP
- */
-
-@Injectable({
-  providedIn : 'root'
-})
-export class AtlasViewerDataService implements OnDestroy{
-  
-  private subscriptions : Subscription[] = []
-  
-  constructor(
-    private store: Store<IavRootStoreInterface>,
-    private constantService : AtlasViewerConstantsServices
-  ){
-    this.constantService.templateUrlsPr
-      .then(urls => 
-        urls.map(url => 
-          this.constantService.raceFetch(`${this.constantService.backendUrl}${url}`)
-            .then(res => res.json())
-            .then(json => new Promise((resolve, reject) => {
-              if(json.nehubaConfig)
-                resolve(json)
-              else if(json.nehubaConfigURL)
-                this.constantService.raceFetch(`${this.constantService.backendUrl}${json.nehubaConfigURL}`)
-                  .then(res => res.json())
-                  .then(json2 => resolve({
-                      ...json,
-                      nehubaConfig: json2
-                    }))
-                  .catch(reject)
-              else
-                reject('neither nehubaConfig nor nehubaConfigURL defined')
-            }))
-            .then(json => this.store.dispatch({
-              type: FETCHED_TEMPLATE,
-              fetchedTemplate: json
-            }))
-            .catch(e => {
-              console.warn('fetching template url failed', e)
-              this.store.dispatch({
-                type: FETCHED_TEMPLATE,
-                fetchedTemplate: null
-              })
-            })
-        ))
-  }
-
-  public searchDataset(){
-    
-  }
-
-  ngOnDestroy(){
-    this.subscriptions.forEach(s=>s.unsubscribe())
-  }
-}
\ No newline at end of file
diff --git a/src/atlasViewer/atlasViewer.history.service.ts b/src/atlasViewer/atlasViewer.history.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa676870381f32cb57feac78cdf54be0c8cf19ce
--- /dev/null
+++ b/src/atlasViewer/atlasViewer.history.service.ts
@@ -0,0 +1,126 @@
+import { Injectable, OnDestroy } from "@angular/core";
+import { Store } from "@ngrx/store";
+import { Effect, Actions, ofType } from '@ngrx/effects'
+import { IavRootStoreInterface, GENERAL_ACTION_TYPES, defaultRootState } from "src/services/stateStore.service";
+import { debounceTime, distinctUntilChanged, map, startWith, filter, withLatestFrom, switchMap, take, switchMapTo } from "rxjs/operators";
+import { Subscription, fromEvent, merge, of } from "rxjs";
+import { cvtStateToSearchParam, cvtSearchParamToState } from "./atlasViewer.urlUtil";
+import { AtlasViewerConstantsServices } from "src/ui/databrowserModule/singleDataset/singleDataset.base";
+
+const getSearchParamStringFromState = state => {
+  try {
+    return cvtStateToSearchParam(state).toString()
+  } catch (e) {
+    console.warn(`cvt state to search param error`, e)
+    return null
+  }
+}
+
+@Injectable({
+  providedIn: 'root'
+})
+
+export class AtlasViewerHistoryUseEffect implements OnDestroy{
+
+  // ensure that fetchedTemplates are all populated
+  @Effect()
+  parsingSearchUrlToState$ = this.store$.pipe(
+    filter(state => state.viewerState.fetchedTemplates.length === this.constantService.totalTemplates),
+    take(1),
+    switchMapTo(merge(
+      // parsing state can occur via 2 ways:
+      // either pop state event or on launch
+      fromEvent(window, 'popstate').pipe(
+        map(({ state } : PopStateEvent) => state)
+      ),
+      of(new URLSearchParams(window.location.search).toString())
+    ))
+  ).pipe(
+    withLatestFrom(this.store$),
+    map(([searchUrl, storeState]: [string, IavRootStoreInterface] ) => {
+      const search = new URLSearchParams(searchUrl)
+      try {
+        if (Array.from(search.keys()).length === 0) {
+          // if empty searchParam
+          return {
+            type: GENERAL_ACTION_TYPES.APPLY_STATE,
+            state: {
+              ...defaultRootState,
+              viewerState: {
+                ...defaultRootState.viewerState,
+                fetchedTemplates: storeState.viewerState.fetchedTemplates
+              }
+            }
+          }
+        } else {
+          // if non empty search param
+          const newState = cvtSearchParamToState(search, storeState)
+          return {
+            type: GENERAL_ACTION_TYPES.APPLY_STATE,
+            state: newState
+          }
+        }
+      } catch (e) {
+        // usually parsing error
+        // TODO should log 
+        return {
+          type: GENERAL_ACTION_TYPES.APPLY_STATE,
+          state: {
+            ...defaultRootState,
+            viewerState: {
+              ...defaultRootState.viewerState,
+              fetchedTemplates: storeState.viewerState.fetchedTemplates
+            }
+          }
+        }
+      }
+    })
+  )
+
+  private subscriptions: Subscription[] = []
+
+  private currentStateSearchParam$ = this.store$.pipe(
+    map(getSearchParamStringFromState),
+    filter(v => v !==  null)
+  )
+
+  constructor(
+    private store$: Store<IavRootStoreInterface>,
+    private actions$: Actions,
+    private constantService: AtlasViewerConstantsServices
+  ){
+    this.subscriptions.push(
+      
+      // GENERAL_ACTION_TYPES.APPLY_STATE is triggered by pop state or initial
+      // conventiently, the action has a state property
+      this.actions$.pipe(
+        ofType(GENERAL_ACTION_TYPES.APPLY_STATE),
+        // subscribe to inner obs on init
+        startWith({}),
+        switchMap(({ state } :any) => 
+          this.currentStateSearchParam$.pipe(
+            distinctUntilChanged(),
+            debounceTime(100),
+
+            // compares the searchParam triggerd by change of state with the searchParam generated by GENERAL_ACTION_TYPES.APPLY_STATE
+            // if the same, the change is induced by GENERAL_ACTION_TYPES.APPLY_STATE, and should NOT be pushed to history
+            filter((newSearchParam, index) => {
+              const oldSearchParam = (state && getSearchParamStringFromState(state)) || ''
+
+              // in the unlikely event that user returns to the exact same state without use forward/back button
+              return index > 0 || newSearchParam !== oldSearchParam
+            })
+          )
+        )
+      ).subscribe(newSearchString => {
+        const url = new URL(window.location.toString())
+        url.search = newSearchString
+        window.history.pushState(newSearchString, '', url.toString())
+      })
+    )
+  }
+
+  ngOnDestroy(){
+    while(this.subscriptions.length > 0) this.subscriptions.pop().unsubscribe()
+  }
+}
\ No newline at end of file
diff --git a/src/atlasViewer/atlasViewer.pluginService.service.ts b/src/atlasViewer/atlasViewer.pluginService.service.ts
index 3165a3f118de88a2352c0258213f75047de65fea..7fb7a085f0daae921386cb1a60d4825a26a0f7a7 100644
--- a/src/atlasViewer/atlasViewer.pluginService.service.ts
+++ b/src/atlasViewer/atlasViewer.pluginService.service.ts
@@ -8,10 +8,12 @@ import { WidgetServices } from "./widgetUnit/widgetService.service";
 
 import '../res/css/plugin_styles.css'
 import { BehaviorSubject, Observable, merge, of } from "rxjs";
-import { map, shareReplay } from "rxjs/operators";
-import { Store } from "@ngrx/store";
+import { map, shareReplay, filter, startWith } from "rxjs/operators";
+import { Store, select } from "@ngrx/store";
 import { WidgetUnit } from "./widgetUnit/widgetUnit.component";
 import { AtlasViewerConstantsServices } from "./atlasViewer.constantService.service";
+import { ACTION_TYPES as PLUGINSTORE_ACTION_TYPES, CONSTANTS as PLUGINSTORE_CONSTANTS } from 'src/services/state/pluginState.store'
+import { Effect } from "@ngrx/effects";
 
 @Injectable({
   providedIn : 'root'
@@ -40,6 +42,13 @@ export class PluginServices{
     private http: HttpClient
   ){
 
+    // TODO implement 
+    this.store.pipe(
+      select('pluginState'),
+      select('initManifests'),
+      filter(v => !!v)
+    )
+
     this.pluginUnitFactory = this.cfr.resolveComponentFactory( PluginUnit )
     this.apiService.interactiveViewer.uiHandle.launchNewWidget = this.launchNewWidget.bind(this) 
     
@@ -282,6 +291,49 @@ export class PluginServices{
   }
 }
 
+@Injectable({
+  providedIn: 'root'
+})
+
+export class PluginServiceuseEffect{
+
+  @Effect()
+  public initManifests$: Observable<any>
+
+  constructor(
+    store$: Store<IavRootStoreInterface>,
+    constantService: AtlasViewerConstantsServices,
+    pluginService: PluginServices
+  ){
+    this.initManifests$ = store$.pipe(
+      select('pluginState'),
+      select('initManifests'),
+      filter(v => !!v),
+      startWith([]),
+      map(arr => {
+        // only launch plugins that has init manifest src label on it
+        return arr.filter(([ source ]) => source === PLUGINSTORE_CONSTANTS.INIT_MANIFEST_SRC)
+      }),
+      filter(arr => arr.length > 0),
+      map((arr: [string, string|null][]) => {
+
+        for (const [source, url] of arr){
+          fetch(url, constantService.getFetchOption())
+            .then(res => res.json())
+            .then(json => pluginService.launchNewWidget(json))
+            .catch(console.error)
+        }
+
+        // clear init manifest
+        return {
+          type: PLUGINSTORE_ACTION_TYPES.CLEAR_INIT_PLUGIN
+        }
+      })
+    )
+  }
+}
+
+
 export class PluginHandler{
   onShutdown : (callback:()=>void)=>void = (_) => {}
   blink : (sec?:number)=>void = (_) => {}
diff --git a/src/atlasViewer/atlasViewer.urlService.service.ts b/src/atlasViewer/atlasViewer.urlService.service.ts
deleted file mode 100644
index f0ca872ceead6e378668d7ae422c95f5322eb05e..0000000000000000000000000000000000000000
--- a/src/atlasViewer/atlasViewer.urlService.service.ts
+++ /dev/null
@@ -1,408 +0,0 @@
-import { Injectable } from "@angular/core";
-import { Store, select } from "@ngrx/store";
-import { ViewerStateInterface, isDefined, NEWVIEWER, CHANGE_NAVIGATION, ADD_NG_LAYER } from "../services/stateStore.service";
-import { StateInterface as PluginStateInterface } from 'src/services/state/pluginState.store'
-import { Observable,combineLatest } from "rxjs";
-import { filter, map, scan, distinctUntilChanged, skipWhile, take } from "rxjs/operators";
-import { PluginServices } from "./atlasViewer.pluginService.service";
-import { AtlasViewerConstantsServices, encodeNumber, separator, decodeToNumber } from "./atlasViewer.constantService.service";
-import { SELECT_REGIONS_WITH_ID } from "src/services/state/viewerState.store";
-import { UIService } from "src/services/uiService.service";
-
-declare var window
-
-const parseQueryString = (searchparams: URLSearchParams) => {
-
-}
-
-@Injectable({
-  providedIn : 'root'
-})
-
-export class AtlasViewerURLService{
-  private changeQueryObservable$ : Observable<any>
-  private additionalNgLayers$ : Observable<any>
-  private pluginState$ : Observable<PluginStateInterface>
-
-  constructor(
-    private store : Store<ViewerStateInterface>,
-    private pluginService : PluginServices,
-    private constantService:AtlasViewerConstantsServices,
-    private uiService:UIService
-  ){
-
-    this.pluginState$ = this.store.pipe(
-      select('pluginState'),
-      distinctUntilChanged()
-    )
-
-    this.changeQueryObservable$ = this.store.pipe(
-      select('viewerState'),
-      filter(state=>
-        isDefined(state) && 
-        (isDefined(state.templateSelected) ||
-        isDefined(state.regionsSelected) || 
-        isDefined(state.navigation) || 
-        isDefined(state.parcellationSelected))),
-
-      /* map so that only a selection are serialized */
-      map(({templateSelected,regionsSelected,navigation,parcellationSelected})=>({
-        templateSelected,
-        regionsSelected,
-        navigation,
-        parcellationSelected
-      }))
-    ).pipe(
-      scan((acc,val)=>Object.assign({},acc,val),{})
-    )
-
-    /**
-     * TODO change additionalNgLayer to id, querying node backend for actual urls
-     */
-    this.additionalNgLayers$ = combineLatest(
-      this.changeQueryObservable$.pipe(
-        select('templateSelected'),
-        filter(v => !!v)
-      ),
-      /**
-       * TODO duplicated with viewerState.loadedNgLayers ?
-       */
-      this.store.pipe(
-        select('ngViewerState'),
-        select('layers')
-      )
-    ).pipe(
-      map(([templateSelected, layers])=>{
-        const state = templateSelected.nehubaConfig.dataset.initialNgState
-        /* TODO currently only parameterise nifti layer */
-        return layers.filter(layer => /^nifti\:\/\//.test(layer.source) && Object.keys(state.layers).findIndex(layerName => layerName === layer.name) < 0)
-      })
-    )
-
-    /* services has no ngOnInit lifecycle */
-    this.subscriptions()
-  }
-
-  private subscriptions(){
-
-    /* parse search url to state */
-    this.store.pipe(
-      select('viewerState'),
-      select('fetchedTemplates'),
-      filter(_=> !!_),
-      skipWhile(fetchedTemplates => fetchedTemplates.length !== this.constantService.templateUrls.length),
-      take(1),
-      map(ft => ft.filter(t => t !== null))
-    ).subscribe(fetchedTemplates=>{
-
-      /**
-       * TODO
-       * consider what to do when we have ill formed search params
-       * param validation?
-       */
-      const searchparams = new URLSearchParams(window.location.search)
- 
-      /**
-       * TODO
-       * triage: change of template and parcellation names is breaking old links
-       * change back when camilla/oli updated the links to new versions
-       */
-
-      /* first, check if any template and parcellations are to be loaded */
-      const searchedTemplatename = (() => {
-        const param = searchparams.get('templateSelected')
-        if (param === 'Allen Mouse') return `Allen adult mouse brain reference atlas V3`
-        if (param === 'Waxholm Rat V2.0') return 'Waxholm Space rat brain atlas v.2.0'
-        return param
-      })()
-      const searchedParcellationName = (() => {
-        const param = searchparams.get('parcellationSelected')
-        if (param === 'Allen Mouse Brain Atlas') return 'Allen adult mouse brain reference atlas V3 Brain Atlas'
-        if (param === 'Whole Brain (v2.0)') return 'Waxholm Space rat brain atlas v.2.0'
-        return param
-      })()
-
-      if (!searchedTemplatename) {
-        const urlString = window.location.href
-        /**
-         * TODO think of better way of doing this
-         */
-        history.replaceState(null, '', urlString.split('?')[0])
-        return
-      }
-      
-      const templateToLoad = fetchedTemplates.find(template=>template.name === searchedTemplatename)
-      if (!templateToLoad) {
-        this.uiService.showMessage(
-          this.constantService.incorrectTemplateNameSearchParam(searchedTemplatename),
-          null,
-          { duration: 5000 }
-        )
-        const urlString = window.location.href
-        /**
-         * TODO think of better way of doing this... maybe pushstate?
-         */
-        history.replaceState(null, '', urlString.split('?')[0])
-        return
-      }
-
-      /**
-       * TODO if search param of either template or parcellation is incorrect, wrong things are searched
-       */
-      const parcellationToLoad = templateToLoad.parcellations.find(parcellation=>parcellation.name === searchedParcellationName)
-
-      if (!parcellationToLoad) {
-        this.uiService.showMessage(
-          this.constantService.incorrectParcellationNameSearchParam(searchedParcellationName),
-          null,
-          { duration: 5000 }
-        )
-      }
-      
-      this.store.dispatch({
-        type : NEWVIEWER,
-        selectTemplate : templateToLoad,
-        selectParcellation : parcellationToLoad || templateToLoad.parcellations[0]
-      })
-
-      /* selected regions */
-      if (parcellationToLoad && parcellationToLoad.regions) {
-        /**
-         * either or both parcellationToLoad and .regions maybe empty
-         */
-        /**
-         * backwards compatibility
-         */
-        const selectedRegionsParam = searchparams.get('regionsSelected')
-        if(selectedRegionsParam){
-          const ids = selectedRegionsParam.split('_')
-
-          this.store.dispatch({
-            type : SELECT_REGIONS_WITH_ID,
-            selectRegionIds: ids
-          })
-        }
-
-        const cRegionsSelectedParam = searchparams.get('cRegionsSelected')
-        if (cRegionsSelectedParam) {
-          try {
-            const json = JSON.parse(cRegionsSelectedParam)
-  
-            const selectRegionIds = []
-  
-            for (let ngId in json) {
-              const val = json[ngId]
-              const labelIndicies = val.split(separator).map(n =>{
-                try{
-                  return decodeToNumber(n)
-                } catch (e) {
-                  /**
-                   * TODO poisonsed encoded char, send error message
-                   */
-                  this.uiService.showMessage(`cRegionSelectionParam is malformed: cannot decode ${n}`)
-                  return null
-                }
-              }).filter(v => !!v)
-              for (let labelIndex of labelIndicies) {
-                selectRegionIds.push(`${ngId}#${labelIndex}`)
-              }
-            }
-  
-            this.store.dispatch({
-              type: SELECT_REGIONS_WITH_ID,
-              selectRegionIds
-            })
-  
-          } catch (e) {
-            /**
-             * parsing cRegionSelected error
-             */
-            console.log('parsing cRegionSelected error', e)
-          }
-        }
-      }
-      
-      /* now that the parcellation is loaded, load the navigation state */
-      const viewerState = searchparams.get('navigation')
-      if(viewerState){
-        const [o,po,pz,p,z]  = viewerState.split('__')
-        this.store.dispatch({
-          type : CHANGE_NAVIGATION,
-          navigation : {
-            orientation : o.split('_').map(n=>Number(n)),
-            perspectiveOrientation : po.split('_').map(n=>Number(n)),
-            perspectiveZoom : Number(pz),
-            position : p.split('_').map(n=>Number(n)),
-            zoom : Number(z)
-          }
-        })
-      }
-
-      const cViewerState = searchparams.get('cNavigation')
-      if (cViewerState) {
-        try {
-          const [ cO, cPO, cPZ, cP, cZ ] = cViewerState.split(`${separator}${separator}`)
-          const o = cO.split(separator).map(s => decodeToNumber(s, {float: true}))
-          const po = cPO.split(separator).map(s => decodeToNumber(s, {float: true}))
-          const pz = decodeToNumber(cPZ)
-          const p = cP.split(separator).map(s => decodeToNumber(s))
-          const z = decodeToNumber(cZ)
-          this.store.dispatch({
-            type : CHANGE_NAVIGATION,
-            navigation : {
-              orientation: o,
-              perspectiveOrientation: po,
-              perspectiveZoom: pz,
-              position: p,
-              zoom: z
-            }
-          })
-        } catch (e) {
-          /**
-           * TODO Poisoned encoded char
-           * send error message
-           */
-        }
-      }
-
-      const niftiLayers = searchparams.get('niftiLayers')
-      if(niftiLayers){
-        const layers = niftiLayers.split('__')
-
-        layers.forEach(layer => this.store.dispatch({
-          type : ADD_NG_LAYER, 
-          layer : {
-            name : layer,
-            source : `nifti://${layer}`,
-            mixability : 'nonmixable',
-            shader : this.constantService.getActiveColorMapFragmentMain()
-          }
-        }))
-      }
-
-      const pluginStates = searchparams.get('pluginStates')
-      if(pluginStates){
-        const arrPluginStates = pluginStates.split('__')
-        arrPluginStates.forEach(url => fetch(url, this.constantService.getFetchOption()).then(res => res.json()).then(json => this.pluginService.launchNewWidget(json)).catch(console.error))
-      }
-    })
-
-    /* pushing state to url */
-    combineLatest(
-      combineLatest(
-        this.changeQueryObservable$,
-        this.store.pipe(
-          select('viewerState'),
-          select('parcellationSelected')
-        )
-      ).pipe(
-        map(([state, parcellationSelected])=>{
-          let _ = {}
-          for(const key in state){
-            if(isDefined(state[key])){
-              switch(key){
-                case 'navigation':
-                  if(
-                    isDefined(state[key].orientation) &&
-                    isDefined(state[key].perspectiveOrientation) &&
-                    isDefined(state[key].perspectiveZoom) &&
-                    isDefined(state[key].position) &&
-                    isDefined(state[key].zoom)
-                  ){
-                    const {
-                      orientation, 
-                      perspectiveOrientation, 
-                      perspectiveZoom, 
-                      position, 
-                      zoom
-                    } = state[key]
-
-                    _['cNavigation'] = [
-                      orientation.map(n => encodeNumber(n, {float: true})).join(separator),
-                      perspectiveOrientation.map(n => encodeNumber(n, {float: true})).join(separator),
-                      encodeNumber(Math.floor(perspectiveZoom)),
-                      Array.from(position).map((v:number) => Math.floor(v)).map(n => encodeNumber(n)).join(separator),
-                      encodeNumber(Math.floor(zoom)) 
-                    ].join(`${separator}${separator}`)
-                    
-                    _[key] = null
-                  }
-                  break;
-                case 'regionsSelected': {
-                  // _[key] = state[key].map(({ ngId, labelIndex })=> generateLabelIndexId({ ngId,labelIndex })).join('_')
-                  const ngIdLabelIndexMap : Map<string, number[]> = state[key].reduce((acc, curr) => {
-                    const returnMap = new Map(acc)
-                    const { ngId, labelIndex } = curr
-                    const existingArr = (returnMap as Map<string, number[]>).get(ngId)
-                    if (existingArr) {
-                      existingArr.push(labelIndex)
-                    } else {
-                      returnMap.set(ngId, [labelIndex])
-                    }
-                    return returnMap
-                  }, new Map())
-
-                  if (ngIdLabelIndexMap.size === 0) {
-                    _['cRegionsSelected'] = null
-                    _[key] = null
-                    break;
-                  }
-                  
-                  const returnObj = {}
-
-                  for (let entry of ngIdLabelIndexMap) {
-                    const [ ngId, labelIndicies ] = entry
-                    returnObj[ngId] = labelIndicies.map(n => encodeNumber(n)).join(separator)
-                  }
-                  
-                  _['cRegionsSelected'] = JSON.stringify(returnObj)
-                  _[key] = null
-                  break;
-                }
-                case 'templateSelected':
-                case 'parcellationSelected':
-                  _[key] = state[key].name
-                  break;
-                default:
-                  _[key] = state[key]
-              }
-            }
-          }
-          return _
-        })
-      ),
-      this.additionalNgLayers$.pipe(
-        map(layers => layers
-          .map(layer => layer.name)
-          .filter(layername => !/^blob\:/.test(layername)))
-      ),
-      this.pluginState$
-    ).pipe(
-      /* TODO fix encoding of nifti path. if path has double underscore, this encoding will fail */
-      map(([navigationState, niftiLayers, pluginState]) => {
-        return {
-          ...navigationState,
-          pluginState: Array.from(pluginState.initManifests.values()).filter(v => v !== null).length > 0 
-            ? Array.from(pluginState.initManifests.values()).filter(v => v !== null).join('__') 
-            : null,
-          niftiLayers : niftiLayers.length > 0
-            ? niftiLayers.join('__')
-            : null
-        }
-      })
-    ).subscribe(cleanedState=>{
-      const url = new URL(window.location)
-      const search = new URLSearchParams( window.location.search )
-      for (const key in cleanedState) {
-        if (cleanedState[key]) {
-          search.set(key, cleanedState[key])
-        } else {
-          search.delete(key)
-        }
-      }
-
-      url.search = search.toString()
-      history.replaceState(null, '', url.toString())
-    })
-  }
-}
\ No newline at end of file
diff --git a/src/atlasViewer/atlasViewer.urlUtil.spec.ts b/src/atlasViewer/atlasViewer.urlUtil.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e36c0c1cb70a7603d1473fac4faba5d039fcaa6d
--- /dev/null
+++ b/src/atlasViewer/atlasViewer.urlUtil.spec.ts
@@ -0,0 +1,69 @@
+import {} from 'jasmine'
+import { cvtSearchParamToState, PARSING_SEARCHPARAM_ERROR } from './atlasViewer.urlUtil'
+import { defaultRootState } from 'src/services/stateStore.service'
+
+const bigbrainJson = require('!json-loader!src/res/ext/bigbrain.json')
+const colin = require('!json-loader!src/res/ext/colin.json')
+const mni152 = require('!json-loader!src/res/ext/MNI152.json')
+const allen = require('!json-loader!src/res/ext/allenMouse.json')
+const waxholm = require('!json-loader!src/res/ext/waxholmRatV2_0.json')
+
+const { viewerState, ...rest } = defaultRootState
+const fetchedTemplateRootState = {
+  ...rest,
+  viewerState: {
+    ...viewerState,
+    fetchedTemplates: [ bigbrainJson, colin, mni152, allen, waxholm ]
+  }
+}
+
+describe('atlasViewer.urlService.service.ts', () => {
+  describe('cvtSearchParamToState', () => {
+    it('convert empty search param to empty state', () => {
+      const searchparam = new URLSearchParams()
+      expect(() => cvtSearchParamToState(searchparam, defaultRootState)).toThrow()
+    })
+
+    it('successfully converts with only template defined', () => {
+      const searchparam = new URLSearchParams('?templateSelected=Big+Brain+%28Histology%29')
+
+      const newState = cvtSearchParamToState(searchparam, fetchedTemplateRootState)
+
+      const { parcellationSelected, templateSelected } = newState.viewerState
+      expect(templateSelected.name).toEqual(bigbrainJson.name)
+      expect(parcellationSelected.name).toEqual(bigbrainJson.parcellations[0].name)
+    })
+
+    it('successfully converts with template AND parcellation defined', () => {
+      const searchparam = new URLSearchParams()
+      searchparam.set('templateSelected', mni152.name)
+      searchparam.set('parcellationSelected', mni152.parcellations[1].name)
+
+      const newState = cvtSearchParamToState(searchparam, fetchedTemplateRootState)
+
+      const { parcellationSelected, templateSelected } = newState.viewerState
+      expect(templateSelected.name).toEqual(mni152.name)
+      expect(parcellationSelected.name).toEqual(mni152.parcellations[1].name)
+    })
+
+    it('successfully converts with template, parcellation AND selected regions defined', () => {
+
+    })
+
+    it('parses cNavigation correctly', () => {
+
+    })
+
+    it('parses niftiLayers correctly', () => {
+
+    })
+
+    it('parses pluginStates correctly', () => {
+
+    })
+  })
+
+  describe('cvtStateToSearchParam', () => {
+    
+  })
+})
\ No newline at end of file
diff --git a/src/atlasViewer/atlasViewer.urlUtil.ts b/src/atlasViewer/atlasViewer.urlUtil.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2a7c38f1f6b886ba8d43bfe3412cc0eb7dbe46d7
--- /dev/null
+++ b/src/atlasViewer/atlasViewer.urlUtil.ts
@@ -0,0 +1,238 @@
+import { IavRootStoreInterface, generateLabelIndexId, getNgIdLabelIndexFromRegion } from "../services/stateStore.service";
+import { encodeNumber, separator, decodeToNumber, GLSL_COLORMAP_JET } from "./atlasViewer.constantService.service";
+import { mixNgLayers } from "src/services/state/ngViewerState.store";
+import { getGetRegionFromLabelIndexId } from "src/services/effect/effect";
+import { CONSTANTS as PLUGINSTORE_CONSTANTS } from 'src/services/state/pluginState.store'
+
+export const PARSING_SEARCHPARAM_ERROR = {
+  TEMPALTE_NOT_SET: 'TEMPALTE_NOT_SET',
+  TEMPLATE_NOT_FOUND: 'TEMPLATE_NOT_FOUND',
+  PARCELLATION_NOT_UPDATED: 'PARCELLATION_NOT_UPDATED'
+}
+const PARSING_SEARCHPARAM_WARNING = {
+  UNKNOWN_PARCELLATION: 'UNKNOWN_PARCELLATION',
+  DECODE_CIPHER_ERROR: 'DECODE_CIPHER_ERROR'
+}
+
+export const CVT_STATE_TO_SEARCHPARAM_ERROR = {
+  TEMPLATE_NOT_SELECTED: 'TEMPLATE_NOT_SELECTED'
+}
+
+export const cvtStateToSearchParam = (state: IavRootStoreInterface): URLSearchParams => {
+  const searchParam = new URLSearchParams()
+
+  const { viewerState, ngViewerState, pluginState } = state
+  const { templateSelected, parcellationSelected, navigation, regionsSelected } = viewerState
+
+  if (!templateSelected) throw new Error(CVT_STATE_TO_SEARCHPARAM_ERROR.TEMPLATE_NOT_SELECTED)
+
+  // encoding states
+  searchParam.set('templateSelected', templateSelected.name)
+  searchParam.set('parcellationSelected', parcellationSelected.name)
+
+  // encoding selected regions
+  const accumulatorMap = new Map<string, number[]>()
+  for (const region of regionsSelected) {
+    const { ngId, labelIndex } = getNgIdLabelIndexFromRegion({ region })
+    const existingEntry = accumulatorMap.get(ngId)
+    if (existingEntry) existingEntry.push(labelIndex)
+    else accumulatorMap.set(ngId, [ labelIndex ])
+  }
+  const cRegionObj = {}
+  for (const [key, arr] of accumulatorMap){
+    cRegionObj[key] = arr.map(n => encodeNumber(n)).join(separator)
+  }
+  searchParam.set('cRegionsSelected', JSON.stringify(cRegionObj))
+
+  // encoding navigation
+  const { orientation, perspectiveOrientation, perspectiveZoom, position, zoom } = navigation
+  const cNavString = [
+    orientation.map(n => encodeNumber(n, {float: true})).join(separator),
+    perspectiveOrientation.map(n => encodeNumber(n, {float: true})).join(separator),
+    encodeNumber(Math.floor(perspectiveZoom)),
+    Array.from(position).map((v:number) => Math.floor(v)).map(n => encodeNumber(n)).join(separator),
+    encodeNumber(Math.floor(zoom)) 
+  ].join(`${separator}${separator}`)
+  searchParam.set('cNavigation', cNavString)
+
+  // encode nifti layers
+  const initialNgState = templateSelected.nehubaConfig.dataset.initialNgState
+  const { layers } = ngViewerState
+  const additionalLayers = layers.filter(layer => 
+    /^blob\:/.test(layer.name) &&
+    Object.keys(initialNgState.layers).findIndex(layerName => layerName === layer.name) < 0
+  )
+  const niftiLayers = additionalLayers.filter(layer => /^nifti\:\/\//.test(layer.source))
+  if (niftiLayers.length > 0) searchParam.set('niftiLayers', niftiLayers.join('__'))
+
+  // plugin state
+  const { initManifests } = pluginState
+  const pluginStateParam = initManifests
+    .filter(([ src ]) => src !== PLUGINSTORE_CONSTANTS.INIT_MANIFEST_SRC)
+    .map(([ src, url]) => url)
+    .join('__')
+
+  if (initManifests.length > 0) searchParam.set('pluginState', pluginStateParam)
+
+  return searchParam
+}
+
+export const cvtSearchParamToState = (searchparams: URLSearchParams, state:IavRootStoreInterface, warningCb = (args) => {}): IavRootStoreInterface => {
+  
+  const returnState = JSON.parse(JSON.stringify(state)) as IavRootStoreInterface
+
+  const { TEMPLATE_NOT_FOUND, TEMPALTE_NOT_SET, PARCELLATION_NOT_UPDATED } = PARSING_SEARCHPARAM_ERROR
+  const { UNKNOWN_PARCELLATION, DECODE_CIPHER_ERROR } = PARSING_SEARCHPARAM_WARNING
+  const { fetchedTemplates } = state.viewerState
+
+  const searchedTemplatename = (() => {
+    const param = searchparams.get('templateSelected')
+    if (param === 'Allen Mouse') return `Allen adult mouse brain reference atlas V3`
+    if (param === 'Waxholm Rat V2.0') return 'Waxholm Space rat brain atlas v.2.0'
+    return param
+  })()
+  const searchedParcellationName = (() => {
+    const param = searchparams.get('parcellationSelected')
+    if (param === 'Allen Mouse Brain Atlas') return 'Allen adult mouse brain reference atlas V3 Brain Atlas'
+    if (param === 'Whole Brain (v2.0)') return 'Waxholm Space rat brain atlas v.2.0'
+    return param
+  })()
+
+  if (!searchedTemplatename) throw new Error(TEMPALTE_NOT_SET)
+  
+  const templateToLoad = fetchedTemplates.find(template=>template.name === searchedTemplatename)
+  if (!templateToLoad) throw new Error(TEMPLATE_NOT_FOUND)
+
+  /**
+   * TODO if search param of either template or parcellation is incorrect, wrong things are searched
+   */
+  const parcellationToLoad = templateToLoad.parcellations.find(parcellation=>parcellation.name === searchedParcellationName)
+  if (!parcellationToLoad) warningCb({ type: UNKNOWN_PARCELLATION })
+  
+  const { viewerState } = returnState
+  viewerState.templateSelected = templateToLoad
+  viewerState.parcellationSelected = parcellationToLoad || templateToLoad.parcellations[0]
+  
+  /* selected regions */
+
+  // TODO deprecate. Fallback (defaultNgId) (should) already exist
+  // if (!viewerState.parcellationSelected.updated) throw new Error(PARCELLATION_NOT_UPDATED)
+  
+  const getRegionFromlabelIndexId = getGetRegionFromLabelIndexId({ parcellation: viewerState.parcellationSelected })
+  /**
+   * either or both parcellationToLoad and .regions maybe empty
+   */
+  /**
+   * backwards compatibility
+   */
+  const selectedRegionsParam = searchparams.get('regionsSelected')
+  if(selectedRegionsParam){
+    const ids = selectedRegionsParam.split('_')
+    
+    viewerState.regionsSelected = ids.map(labelIndexId => getRegionFromlabelIndexId({ labelIndexId })) 
+  }
+
+  const cRegionsSelectedParam = searchparams.get('cRegionsSelected')
+  if (cRegionsSelectedParam) {
+    try {
+      const json = JSON.parse(cRegionsSelectedParam)
+
+      const selectRegionIds = []
+
+      for (let ngId in json) {
+        const val = json[ngId]
+        const labelIndicies = val.split(separator).map(n =>{
+          try{
+            return decodeToNumber(n)
+          } catch (e) {
+            /**
+             * TODO poisonsed encoded char, send error message
+             */
+            warningCb({ type: DECODE_CIPHER_ERROR, message: `cRegionSelectionParam is malformed: cannot decode ${n}` })
+            return null
+          }
+        }).filter(v => !!v)
+        for (let labelIndex of labelIndicies) {
+          selectRegionIds.push( generateLabelIndexId({ ngId, labelIndex }) )
+        }
+      }
+      viewerState.regionsSelected = selectRegionIds.map(labelIndexId => getRegionFromlabelIndexId({ labelIndexId })) 
+
+    } catch (e) {
+      /**
+       * parsing cRegionSelected error
+       */
+      warningCb({ type: DECODE_CIPHER_ERROR, message: `parsing cRegionSelected error ${e.toString()}` })
+    }
+  }
+
+  /* now that the parcellation is loaded, load the navigation state */
+  /* what to do with malformed navigation? */
+
+  // for backwards compatibility
+  const _viewerState = searchparams.get('navigation')
+  if(_viewerState){
+    const [o,po,pz,p,z] = _viewerState.split('__')
+    viewerState.navigation = {
+      orientation : o.split('_').map(n=>Number(n)),
+      perspectiveOrientation : po.split('_').map(n=>Number(n)),
+      perspectiveZoom : Number(pz),
+      position : p.split('_').map(n=>Number(n)),
+      zoom : Number(z),
+
+      // flag to allow for animation when enabled
+      animation: {}
+    }
+  }
+
+  const cViewerState = searchparams.get('cNavigation')
+  if (cViewerState) {
+    try {
+      const [ cO, cPO, cPZ, cP, cZ ] = cViewerState.split(`${separator}${separator}`)
+      const o = cO.split(separator).map(s => decodeToNumber(s, {float: true}))
+      const po = cPO.split(separator).map(s => decodeToNumber(s, {float: true}))
+      const pz = decodeToNumber(cPZ)
+      const p = cP.split(separator).map(s => decodeToNumber(s))
+      const z = decodeToNumber(cZ)
+      viewerState.navigation = {
+        orientation: o,
+        perspectiveOrientation: po,
+        perspectiveZoom: pz,
+        position: p,
+        zoom: z,
+        
+        // flag to allow for animation when enabled
+        animation: {}
+      }
+    } catch (e) {
+      /**
+       * TODO Poisoned encoded char
+       * send error message
+       */
+    }
+  }
+
+  const niftiLayers = searchparams.get('niftiLayers')
+  if(niftiLayers){
+    const layers = niftiLayers
+      .split('__')
+      .map(layer => {
+        return {
+          name : layer,
+          source : `nifti://${layer}`,
+          mixability : 'nonmixable',
+          shader : GLSL_COLORMAP_JET
+        } as any
+      })
+    const { ngViewerState } = returnState
+    ngViewerState.layers = mixNgLayers(ngViewerState.layers, layers)
+  }
+
+  const { pluginState } = returnState
+  const pluginStates = searchparams.get('pluginStates')
+  if(pluginStates){
+    const arrPluginStates = pluginStates.split('__')
+    pluginState.initManifests = arrPluginStates.map(url => [PLUGINSTORE_CONSTANTS.INIT_MANIFEST_SRC, url] as [string, string])
+  }
+  return returnState
+}
diff --git a/src/main.module.ts b/src/main.module.ts
index 076716937a6a011e39384792744bb50d042b95d2..352b25fa853b788a8e7e1a1f3a74ebe5a6c25cbb 100644
--- a/src/main.module.ts
+++ b/src/main.module.ts
@@ -12,14 +12,13 @@ import { GetNamePipe } from "./util/pipes/getName.pipe";
 import { FormsModule } from "@angular/forms";
 import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module'
 
-import { AtlasViewerDataService } from "./atlasViewer/atlasViewer.dataService.service";
 import { WidgetUnit } from "./atlasViewer/widgetUnit/widgetUnit.component";
 import { WidgetServices } from './atlasViewer/widgetUnit/widgetService.service'
+// TODO deprecate
 import { fasTooltipScreenshotDirective,fasTooltipInfoSignDirective,fasTooltipLogInDirective,fasTooltipNewWindowDirective,fasTooltipQuestionSignDirective,fasTooltipRemoveDirective,fasTooltipRemoveSignDirective } from "./util/directives/glyphiconTooltip.directive";
 import { TooltipModule } from "ngx-bootstrap/tooltip";
 import { TabsModule } from 'ngx-bootstrap/tabs'
 import { ModalUnit } from "./atlasViewer/modalUnit/modalUnit.component";
-import { AtlasViewerURLService } from "./atlasViewer/atlasViewer.urlService.service";
 import { ToastComponent } from "./components/toast/toast.component";
 import { AtlasViewerAPIServices } from "./atlasViewer/atlasViewer.apiService.service";
 import { PluginUnit } from "./atlasViewer/pluginUnit/pluginUnit.component";
@@ -47,13 +46,15 @@ import { NgViewerUseEffect } from "./services/state/ngViewerState.store";
 import { DatabrowserModule } from "./ui/databrowserModule/databrowser.module";
 import { UIService } from "./services/uiService.service";
 import { UtilModule } from "./util/util.module";
+import {CaptureClickListenerDirective} from "src/util/directives/captureClickListener.directive";
+import { PluginServiceuseEffect } from "./atlasViewer/atlasViewer.pluginService.service";
 
 import 'hammerjs'
 
 import 'src/res/css/version.css'
 import 'src/theme.scss'
 import 'src/res/css/extra_styles.css'
-import {CaptureClickListenerDirective} from "src/util/directives/captureClickListener.directive";
+import { AtlasViewerHistoryUseEffect } from "./atlasViewer/atlasViewer.history.service";
 
 @NgModule({
   imports : [
@@ -75,7 +76,9 @@ import {CaptureClickListenerDirective} from "src/util/directives/captureClickLis
       UserConfigStateUseEffect,
       ViewerStateControllerUseEffect,
       ViewerStateUseEffect,
-      NgViewerUseEffect
+      NgViewerUseEffect,
+      PluginServiceuseEffect,
+      AtlasViewerHistoryUseEffect
     ]),
     StoreModule.forRoot({
       pluginState,
@@ -124,9 +127,7 @@ import {CaptureClickListenerDirective} from "src/util/directives/captureClickLis
     ConfirmDialogComponent,
   ],
   providers : [
-    AtlasViewerDataService,
     WidgetServices,
-    AtlasViewerURLService,
     AtlasViewerAPIServices,
     AtlasWorkerService,
     AuthService,
diff --git a/src/res/ext/bigbrainNehubaConfig.json b/src/res/ext/bigbrainNehubaConfig.json
index 185ac5077ab33ef3004edf4e326602aefa446020..32046653e7a602f2f3a0d4c94e21b57554dfaecc 100644
--- a/src/res/ext/bigbrainNehubaConfig.json
+++ b/src/res/ext/bigbrainNehubaConfig.json
@@ -1 +1,334 @@
-{"configName":"","globals":{"hideNullImageValues":true,"useNehubaLayout":{"keepDefaultLayouts":false},"useNehubaMeshLayer":true,"rightClickWithCtrlGlobal":false,"zoomWithoutCtrlGlobal":false,"useCustomSegmentColors":true},"zoomWithoutCtrl":true,"hideNeuroglancerUI":true,"rightClickWithCtrl":true,"rotateAtViewCentre":true,"enableMeshLoadingControl":true,"zoomAtViewCentre":true,"restrictUserNavigation":true,"disableSegmentSelection":false,"dataset":{"imageBackground":[1,1,1,1],"initialNgState":{"showDefaultAnnotations":false,"layers":{" grey value: ":{"type":"image","source":"precomputed://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/8bit","transform":[[1,0,0,-70677184],[0,1,0,-70010000],[0,0,1,-58788284],[0,0,0,1]]}," tissue type: ":{"type":"segmentation","source":"precomputed://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/classif","segments":["0"],"selectedAlpha":0,"notSelectedAlpha":0,"transform":[[1,0,0,-70666600],[0,1,0,-72910000],[0,0,1,-58777700],[0,0,0,1]]},"v1":{"type":"segmentation","source":"precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_01_v1","segments":["0"],"selectedAlpha":0.45,"notSelectedAlpha":0,"transform":[[1,0,0,-70677184],[0,1,0,-69390000],[0,0,1,-58788284],[0,0,0,1]]},"v2":{"type":"segmentation","source":"precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_01_v2","segments":["0"],"selectedAlpha":0.45,"notSelectedAlpha":0,"transform":[[1,0,0,-70677184],[0,1,0,-69870000],[0,0,1,-58788284],[0,0,0,1]]},"interpolated":{"type":"segmentation","source":"precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_22_interpolated_areas","segments":["0"],"selectedAlpha":0.45,"notSelectedAlpha":0,"transform":[[1,0,0,-70677184],[0,1,0,-51990000],[0,0,1,-58788284],[0,0,0,1]]},"cortical layers":{"type":"segmentation","source":"precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_27_cortical_layers","selectedAlpha":0.5,"notSelectedAlpha":0,"transform":[[1,0,0,-70677184],[0,1,0,-70010000],[0,0,1,-58788284],[0,0,0,1]]}},"navigation":{"pose":{"position":{"voxelSize":[21166.666015625,20000,21166.666015625],"voxelCoordinates":[-21.8844051361084,16.288618087768555,28.418994903564453]}},"zoomFactor":350000},"perspectiveOrientation":[0.3140767216682434,-0.7418519854545593,0.4988985061645508,-0.3195493221282959],"perspectiveZoom":1922235.5293810747}},"layout":{"views":"hbp-neuro","planarSlicesBackground":[1,1,1,1],"useNehubaPerspective":{"enableShiftDrag":false,"doNotRestrictUserNavigation":false,"perspectiveSlicesBackground":[1,1,1,1],"removePerspectiveSlicesBackground":{"color":[1,1,1,1],"mode":"=="},"perspectiveBackground":[1,1,1,1],"fixedZoomPerspectiveSlices":{"sliceViewportWidth":300,"sliceViewportHeight":300,"sliceZoom":563818.3562426177,"sliceViewportSizeMultiplier":2},"mesh":{"backFaceColor":[1,1,1,1],"removeBasedOnNavigation":true,"flipRemovedOctant":true},"centerToOrigin":true,"drawSubstrates":{"color":[0,0,0.5,0.15]},"drawZoomLevels":{"cutOff":200000,"color":[0.5,0,0,0.15]},"hideImages":false,"waitForMesh":true,"restrictZoomLevel":{"minZoom":1200000,"maxZoom":3500000}}}}
\ No newline at end of file
+{
+  "configName": "",
+  "globals": {
+    "hideNullImageValues": true,
+    "useNehubaLayout": {
+      "keepDefaultLayouts": false
+    },
+    "useNehubaMeshLayer": true,
+    "rightClickWithCtrlGlobal": false,
+    "zoomWithoutCtrlGlobal": false,
+    "useCustomSegmentColors": true
+  },
+  "zoomWithoutCtrl": true,
+  "hideNeuroglancerUI": true,
+  "rightClickWithCtrl": true,
+  "rotateAtViewCentre": true,
+  "enableMeshLoadingControl": true,
+  "zoomAtViewCentre": true,
+  "restrictUserNavigation": true,
+  "disableSegmentSelection": false,
+  "dataset": {
+    "imageBackground": [
+      1,
+      1,
+      1,
+      1
+    ],
+    "initialNgState": {
+      "showDefaultAnnotations": false,
+      "layers": {
+        " grey value: ": {
+          "type": "image",
+          "source": "precomputed://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/8bit",
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70677184
+            ],
+            [
+              0,
+              1,
+              0,
+              -70010000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58788284
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        },
+        " tissue type: ": {
+          "type": "segmentation",
+          "source": "precomputed://https://neuroglancer.humanbrainproject.org/precomputed/BigBrainRelease.2015/classif",
+          "segments": [
+            "0"
+          ],
+          "selectedAlpha": 0,
+          "notSelectedAlpha": 0,
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70666600
+            ],
+            [
+              0,
+              1,
+              0,
+              -72910000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58777700
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        },
+        "v1": {
+          "type": "segmentation",
+          "source": "precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_01_v1",
+          "segments": [
+            "0"
+          ],
+          "selectedAlpha": 0.45,
+          "notSelectedAlpha": 0,
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70677184
+            ],
+            [
+              0,
+              1,
+              0,
+              -69390000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58788284
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        },
+        "v2": {
+          "type": "segmentation",
+          "source": "precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_01_v2",
+          "segments": [
+            "0"
+          ],
+          "selectedAlpha": 0.45,
+          "notSelectedAlpha": 0,
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70677184
+            ],
+            [
+              0,
+              1,
+              0,
+              -69870000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58788284
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        },
+        "interpolated": {
+          "type": "segmentation",
+          "source": "precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_22_interpolated_areas",
+          "segments": [
+            "0"
+          ],
+          "selectedAlpha": 0.45,
+          "notSelectedAlpha": 0,
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70677184
+            ],
+            [
+              0,
+              1,
+              0,
+              -51990000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58788284
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        },
+        "cortical layers": {
+          "type": "segmentation",
+          "source": "precomputed://https://neuroglancer-dev.humanbrainproject.org/precomputed/BigBrainRelease.2015/2019_05_27_cortical_layers",
+          "selectedAlpha": 0.5,
+          "notSelectedAlpha": 0,
+          "transform": [
+            [
+              1,
+              0,
+              0,
+              -70677184
+            ],
+            [
+              0,
+              1,
+              0,
+              -70010000
+            ],
+            [
+              0,
+              0,
+              1,
+              -58788284
+            ],
+            [
+              0,
+              0,
+              0,
+              1
+            ]
+          ]
+        }
+      },
+      "navigation": {
+        "pose": {
+          "position": {
+            "voxelSize": [
+              21166.666015625,
+              20000,
+              21166.666015625
+            ],
+            "voxelCoordinates": [
+              -21.8844051361084,
+              16.288618087768555,
+              28.418994903564453
+            ]
+          }
+        },
+        "zoomFactor": 350000
+      },
+      "perspectiveOrientation": [
+        0.3140767216682434,
+        -0.7418519854545593,
+        0.4988985061645508,
+        -0.3195493221282959
+      ],
+      "perspectiveZoom": 1922235.5293810747
+    }
+  },
+  "layout": {
+    "views": "hbp-neuro",
+    "planarSlicesBackground": [
+      1,
+      1,
+      1,
+      1
+    ],
+    "useNehubaPerspective": {
+      "enableShiftDrag": false,
+      "doNotRestrictUserNavigation": false,
+      "perspectiveSlicesBackground": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "removePerspectiveSlicesBackground": {
+        "color": [
+          1,
+          1,
+          1,
+          1
+        ],
+        "mode": "=="
+      },
+      "perspectiveBackground": [
+        1,
+        1,
+        1,
+        1
+      ],
+      "fixedZoomPerspectiveSlices": {
+        "sliceViewportWidth": 300,
+        "sliceViewportHeight": 300,
+        "sliceZoom": 563818.3562426177,
+        "sliceViewportSizeMultiplier": 2
+      },
+      "mesh": {
+        "backFaceColor": [
+          1,
+          1,
+          1,
+          1
+        ],
+        "removeBasedOnNavigation": true,
+        "flipRemovedOctant": true
+      },
+      "centerToOrigin": true,
+      "drawSubstrates": {
+        "color": [
+          0,
+          0,
+          0.5,
+          0.15
+        ]
+      },
+      "drawZoomLevels": {
+        "cutOff": 200000,
+        "color": [
+          0.5,
+          0,
+          0,
+          0.15
+        ]
+      },
+      "hideImages": false,
+      "waitForMesh": true,
+      "restrictZoomLevel": {
+        "minZoom": 1200000,
+        "maxZoom": 3500000
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/services/effect/effect.spec.ts b/src/services/effect/effect.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..622639671d92cb8fe9c98c4395f4994a2fa30961
--- /dev/null
+++ b/src/services/effect/effect.spec.ts
@@ -0,0 +1,37 @@
+import {} from 'jasmine'
+import { getGetRegionFromLabelIndexId } from './effect'
+const colinsJson = require('!json-loader!../../res/ext/colin.json')
+
+const hoc1 = {
+  "name": "Area hOc1 (V1, 17, CalcS) - left hemisphere",
+  "rgb": [
+    190,
+    132,
+    147
+  ],
+  "labelIndex": 8,
+  "ngId": "jubrain colin v18 left",
+  "children": [],
+  "status": "publicP",
+  "position": [
+    -8533787,
+    -84646549,
+    1855106
+  ]
+}
+
+describe('effect.ts', () => {
+  describe('getGetRegionFromLabelIndexId', () => {
+    it('translateds hoc1 from labelIndex to region', () => {
+
+      const getRegionFromlabelIndexId = getGetRegionFromLabelIndexId({ 
+        parcellation: {
+          ...colinsJson.parcellations[0],
+          updated: true
+        }
+      })
+      const fetchedRegion = getRegionFromlabelIndexId({ labelIndexId: 'jubrain colin v18 left#8' })
+      expect(fetchedRegion).toEqual(hoc1)
+    })
+  })
+})
\ No newline at end of file
diff --git a/src/services/effect/effect.ts b/src/services/effect/effect.ts
index 4354421dea75ce55508feed5b8d380903c9510c5..87cd072181691fe8e4a7a535964c097ea14c52e7 100644
--- a/src/services/effect/effect.ts
+++ b/src/services/effect/effect.ts
@@ -228,6 +228,12 @@ export class UseEffects implements OnDestroy{
   )
 }
 
+export const getGetRegionFromLabelIndexId = ({ parcellation }) => {
+  const { ngId: defaultNgId, regions } = parcellation
+  // if (!updated) throw new Error(`parcellation not yet updated`)
+  return ({ labelIndexId }) => recursiveFindRegionWithLabelIndexId({ regions, labelIndexId, inheritedNgId: defaultNgId })
+}
+
 export const compareRegions: (r1: any,r2: any) => boolean = (r1, r2) => {
   if (!r1) return !r2
   if (!r2) return !r1
diff --git a/src/services/state/dataStore.store.ts b/src/services/state/dataStore.store.ts
index b4a13defd1476c80838a409e12c8b3aade9cfc0d..5ebec4c8326ff95c886d722cdebf7c6d800fdf9e 100644
--- a/src/services/state/dataStore.store.ts
+++ b/src/services/state/dataStore.store.ts
@@ -10,37 +10,40 @@ export interface StateInterface{
   fetchedSpatialData: DataEntry[]
 }
 
-const defaultState = {
+export const defaultState = {
   fetchedDataEntries: [],
   favDataEntries: [],
   fetchedSpatialData: []
 }
 
-export function stateStore(state:StateInterface = defaultState, action:Partial<ActionInterface>){
+export const getStateStore = ({ state: state = defaultState } = {}) => (prevState:StateInterface = state, action:Partial<ActionInterface>) => {
+
   switch (action.type){
     case FETCHED_DATAENTRIES: {
       return {
-        ...state,
+        ...prevState,
         fetchedDataEntries : action.fetchedDataEntries
       }
     }
     case FETCHED_SPATIAL_DATA :{
       return {
-        ...state,
+        ...prevState,
         fetchedSpatialData : action.fetchedDataEntries
       }
     }
     case ACTION_TYPES.UPDATE_FAV_DATASETS: {
       const { favDataEntries = [] } = action
       return {
-        ...state,
+        ...prevState,
         favDataEntries
       }
     }
-    default: return state
+    default: return prevState
   }
 }
 
+export const stateStore = getStateStore()
+
 export interface ActionInterface extends Action{
   favDataEntries: DataEntry[]
   fetchedDataEntries : DataEntry[]
diff --git a/src/services/state/ngViewerState.store.ts b/src/services/state/ngViewerState.store.ts
index 2af420f1cd115744fe62bfbb0c698bf6f04c04a5..507c6cdc5dd9bf27064e3cfa69be97b6988c6c54 100644
--- a/src/services/state/ngViewerState.store.ts
+++ b/src/services/state/ngViewerState.store.ts
@@ -12,6 +12,19 @@ export const V_ONE_THREE = 'V_ONE_THREE'
 export const H_ONE_THREE = 'H_ONE_THREE'
 export const SINGLE_PANEL = 'SINGLE_PANEL'
 
+export function mixNgLayers(oldLayers:NgLayerInterface[], newLayers:NgLayerInterface|NgLayerInterface[]): NgLayerInterface[]{
+  if (newLayers instanceof Array) {
+    return oldLayers.concat(newLayers)
+  } else {
+    return oldLayers.concat({
+      ...newLayers,
+      ...( newLayers.mixability === 'nonmixable' && oldLayers.findIndex(l => l.mixability === 'nonmixable') >= 0
+            ? {visible: false}
+            : {})
+    })
+  }
+}
+
 export interface StateInterface{
   layers : NgLayerInterface[]
   forceShowSegment : boolean | null
@@ -31,7 +44,7 @@ export interface ActionInterface extends Action{
   payload: any
 }
 
-const defaultState:StateInterface = {
+export const defaultState:StateInterface = {
   layers:[],
   forceShowSegment:null,
   nehubaReady: false,
@@ -42,7 +55,7 @@ const defaultState:StateInterface = {
   showZoomlevel: null
 }
 
-export function stateStore(prevState:StateInterface = defaultState, action:ActionInterface):StateInterface{
+export const getStateStore = ({ state = defaultState } = {}) => (prevState:StateInterface = state, action:ActionInterface):StateInterface => {
   switch(action.type){
     case ACTION_TYPES.SET_PANEL_ORDER: {
       const { payload } = action
@@ -75,14 +88,16 @@ export function stateStore(prevState:StateInterface = defaultState, action:Actio
 
         /* this configuration allows the addition of multiple non mixables */
         // layers : prevState.layers.map(l => mapLayer(l, action.layer)).concat(action.layer)
-        layers : action.layer.constructor === Array 
-          ? prevState.layers.concat(action.layer)
-          : prevState.layers.concat({
-            ...action.layer,
-            ...( action.layer.mixability === 'nonmixable' && prevState.layers.findIndex(l => l.mixability === 'nonmixable') >= 0
-                  ? {visible: false}
-                  : {})
-          })
+        layers : mixNgLayers(prevState.layers, action.layer) 
+        
+        // action.layer.constructor === Array 
+        //   ? prevState.layers.concat(action.layer)
+        //   : prevState.layers.concat({
+        //     ...action.layer,
+        //     ...( action.layer.mixability === 'nonmixable' && prevState.layers.findIndex(l => l.mixability === 'nonmixable') >= 0
+        //           ? {visible: false}
+        //           : {})
+        //   })
       } 
     case REMOVE_NG_LAYERS:
       const { layers } = action
@@ -126,6 +141,8 @@ export function stateStore(prevState:StateInterface = defaultState, action:Actio
   }
 }
 
+export const stateStore = getStateStore()
+
 @Injectable({
   providedIn: 'root'
 })
@@ -369,11 +386,11 @@ export const HIDE_NG_LAYER = 'HIDE_NG_LAYER'
 export const FORCE_SHOW_SEGMENT = `FORCE_SHOW_SEGMENT`
 export const NEHUBA_READY = `NEHUBA_READY`
 
-interface NgLayerInterface{
+export interface NgLayerInterface{
   name : string
   source : string
   mixability : string // base | mixable | nonmixable
-  visible : boolean
+  visible? : boolean
   shader? : string
   transform? : any
 }
diff --git a/src/services/state/pluginState.store.ts b/src/services/state/pluginState.store.ts
index f9e3cea64b79a6013cc296215ce1c968520ae626..3170e228468c565ffa6a93b3b45f9d5320e37b29 100644
--- a/src/services/state/pluginState.store.ts
+++ b/src/services/state/pluginState.store.ts
@@ -1,8 +1,11 @@
 import { Action } from '@ngrx/store'
 
+export const defaultState: StateInterface = {
+  initManifests: []
+}
 
 export interface StateInterface{
-  initManifests : Map<string,string|null>
+  initManifests : [ string, string|null ][]
 }
 
 export interface ActionInterface extends Action{
@@ -13,18 +16,35 @@ export interface ActionInterface extends Action{
 }
 
 export const ACTION_TYPES = {
-  SET_INIT_PLUGIN: `SET_INIT_PLUGIN`
+  SET_INIT_PLUGIN: `SET_INIT_PLUGIN`,
+  CLEAR_INIT_PLUGIN: 'CLEAR_INIT_PLUGIN'
+}
+
+export const CONSTANTS = {
+  INIT_MANIFEST_SRC: 'INIT_MANIFEST_SRC'
 }
 
-export function stateStore(prevState:StateInterface = {initManifests : new Map()}, action:ActionInterface):StateInterface{
+export const getStateStore = ({ state = defaultState } = {}) => (prevState:StateInterface = state, action:ActionInterface):StateInterface => {
   switch(action.type){
     case ACTION_TYPES.SET_INIT_PLUGIN:
       const newMap = new Map(prevState.initManifests )
+
+      // reserved source label for init manifest
+      if (action.manifest.name !== CONSTANTS.INIT_MANIFEST_SRC) newMap.set(action.manifest.name, action.manifest.initManifestUrl)
       return {
         ...prevState,
-        initManifests: newMap.set(action.manifest.name, action.manifest.initManifestUrl)
+        initManifests: Array.from(newMap)
+      }
+    case ACTION_TYPES.CLEAR_INIT_PLUGIN:
+      const { initManifests } = prevState
+      const newManifests = initManifests.filter(([source]) => source !== CONSTANTS.INIT_MANIFEST_SRC)
+      return {
+        ...prevState,
+        initManifests: newManifests
       }
     default:
       return prevState
   }
 }
+
+export const stateStore = getStateStore()
diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts
index ecf896187c16ea6c3b21239d5f3a6240848d813f..e0a0b4202ddfe80b527880997d300d25e93f086a 100644
--- a/src/services/state/uiState.store.ts
+++ b/src/services/state/uiState.store.ts
@@ -2,8 +2,9 @@ import { Action } from '@ngrx/store'
 import { TemplateRef } from '@angular/core';
 
 import { LOCAL_STORAGE_CONST, COOKIE_VERSION, KG_TOS_VERSION } from 'src/util/constants'
+import { GENERAL_ACTION_TYPES } from '../stateStore.service'
 
-const defaultState: StateInterface = {
+export const defaultState: StateInterface = {
   mouseOverSegments: [],
   mouseOverSegment: null,
   
@@ -24,29 +25,29 @@ const defaultState: StateInterface = {
   agreedKgTos: localStorage.getItem(LOCAL_STORAGE_CONST.AGREE_KG_TOS) === KG_TOS_VERSION
 }
 
-export function stateStore(state:StateInterface = defaultState,action:ActionInterface){
+export const getStateStore = ({ state = defaultState } = {}) => (prevState:StateInterface = state,action:ActionInterface) => {
   switch(action.type){
     case MOUSE_OVER_SEGMENTS:
       const { segments } = action
       return {
-        ...state,
+        ...prevState,
         mouseOverSegments: segments
       }
     case MOUSE_OVER_SEGMENT:
       return {
-        ...state,
+        ...prevState,
         mouseOverSegment : action.segment
       }
     case MOUSEOVER_USER_LANDMARK:
       const { payload = {} } = action
       const { userLandmark: mouseOverUserLandmark = null } = payload
       return {
-        ...state,
+        ...prevState,
         mouseOverUserLandmark
       }
     case MOUSE_OVER_LANDMARK:
       return {
-        ...state,
+        ...prevState,
         mouseOverLandmark : action.landmark
       }
     case SNACKBAR_MESSAGE:
@@ -55,7 +56,7 @@ export function stateStore(state:StateInterface = defaultState,action:ActionInte
        * Need to use symbol here, or repeated snackbarMessage will not trigger new event
        */
       return {
-        ...state,
+        ...prevState,
         snackbarMessage: Symbol(snackbarMessage)
       }
     /**
@@ -64,17 +65,17 @@ export function stateStore(state:StateInterface = defaultState,action:ActionInte
      */
     case TOGGLE_SIDE_PANEL:
       return {
-        ...state,
-        sidePanelOpen: !state.sidePanelOpen
+        ...prevState,
+        sidePanelOpen: !prevState.sidePanelOpen
       }
     case OPEN_SIDE_PANEL:
       return {
-        ...state,
+        ...prevState,
         sidePanelOpen: true
       }
     case CLOSE_SIDE_PANEL:
       return {
-        ...state,
+        ...prevState,
         sidePanelOpen: false
       }
     case AGREE_COOKIE:
@@ -83,7 +84,7 @@ export function stateStore(state:StateInterface = defaultState,action:ActionInte
        */
       localStorage.setItem(LOCAL_STORAGE_CONST.AGREE_COOKIE, COOKIE_VERSION)
       return {
-        ...state,
+        ...prevState,
         agreedCookies: true
       }
     case AGREE_KG_TOS:
@@ -92,20 +93,22 @@ export function stateStore(state:StateInterface = defaultState,action:ActionInte
        */
       localStorage.setItem(LOCAL_STORAGE_CONST.AGREE_KG_TOS, KG_TOS_VERSION)
       return {
-        ...state,
+        ...prevState,
         agreedKgTos: true
       }
     case SHOW_BOTTOM_SHEET:
         const { bottomSheetTemplate } = action
         return {
-          ...state,
+          ...prevState,
           bottomSheetTemplate
         }
     default:
-      return state
+      return prevState
   }
 }
 
+export const stateStore = getStateStore()
+
 export interface StateInterface{
   mouseOverSegments: {
     layer: {
diff --git a/src/services/state/userConfigState.store.ts b/src/services/state/userConfigState.store.ts
index bd5f817f9ab46ced325b63c33804ddb0ddb68e89..d9304886915002991cca6540b53a2612d795a1db 100644
--- a/src/services/state/userConfigState.store.ts
+++ b/src/services/state/userConfigState.store.ts
@@ -42,7 +42,7 @@ interface UserConfigAction extends Action{
   payload?: any
 }
 
-const defaultUserConfigState: StateInterface = {
+export const defaultState: StateInterface = {
   savedRegionsSelection: []
 }
 
@@ -55,8 +55,7 @@ export const ACTION_TYPES = {
   LOAD_REGIONS_SELECTION: 'LOAD_REGIONS_SELECTION'
 }
 
-
-export function stateStore(prevState: StateInterface = defaultUserConfigState, action: UserConfigAction) {
+export const getStateStore = ({ state = defaultState } = {}) => (prevState: StateInterface = state, action: UserConfigAction) => {
   switch(action.type) {
     case ACTION_TYPES.UPDATE_REGIONS_SELECTIONS:
       const { config = {} } = action
@@ -72,6 +71,9 @@ export function stateStore(prevState: StateInterface = defaultUserConfigState, a
   }
 }
 
+export const stateStore = getStateStore()
+
+
 @Injectable({
   providedIn: 'root'
 })
diff --git a/src/services/state/viewerConfig.store.ts b/src/services/state/viewerConfig.store.ts
index 598f7d37298b6fb8345f5f7d444a1d2ae1cd41d5..7a3899744f7f69bd355f2044eda5adf8cf7ca85f 100644
--- a/src/services/state/viewerConfig.store.ts
+++ b/src/services/state/viewerConfig.store.ts
@@ -53,15 +53,15 @@ const getIsMobile = () => {
   /* https://stackoverflow.com/a/25394023/6059235 */
   return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i.test(ua)
 }
-const useMobileUIStroageValue = window.localStorage.getItem(LOCAL_STORAGE_CONST.MOBILE_UI) 
+const useMobileUIStroageValue = window && window.localStorage && window.localStorage.getItem(LOCAL_STORAGE_CONST.MOBILE_UI) 
 
-const onLoadViewerconfig: StateInterface = {
+export const defaultState: StateInterface = {
   animation,
   gpuLimit,
   useMobileUI: (useMobileUIStroageValue && useMobileUIStroageValue === 'true') || getIsMobile()
 }
 
-export function stateStore(prevState:StateInterface = onLoadViewerconfig, action:ViewerConfigurationAction) {
+export const getStateStore = ({ state = defaultState } = {}) => (prevState:StateInterface = state, action:ViewerConfigurationAction) => {
   switch (action.type) {
     case ACTION_TYPES.SET_MOBILE_UI:
       const { payload } = action
@@ -89,3 +89,5 @@ export function stateStore(prevState:StateInterface = onLoadViewerconfig, action
     default: return prevState
   }
 }
+
+export const stateStore = getStateStore()
diff --git a/src/services/state/viewerState.store.ts b/src/services/state/viewerState.store.ts
index 2b08a8b0c17a8dad9b6b6dd08287843edebd289b..b9be474d9b0f08174ff1b9938eeed8efce67fb32 100644
--- a/src/services/state/viewerState.store.ts
+++ b/src/services/state/viewerState.store.ts
@@ -7,6 +7,7 @@ import { withLatestFrom, map, shareReplay, startWith, filter, distinctUntilChang
 import { Observable } from 'rxjs';
 import { MOUSEOVER_USER_LANDMARK } from './uiState.store';
 import { generateLabelIndexId, IavRootStoreInterface } from '../stateStore.service';
+import { GENERAL_ACTION_TYPES } from '../stateStore.service'
 
 export interface StateInterface{
   fetchedTemplates : any[]
@@ -44,33 +45,37 @@ export interface ActionInterface extends Action{
   payload: any
 }
 
-export function stateStore(
-  state:Partial<StateInterface> = {
-    landmarksSelected : [],
-    fetchedTemplates : [],
-    loadedNgLayers: [],
-    regionsSelected: [],
-    userLandmarks: []
-  },
-  action:ActionInterface
-){
+export const defaultState:StateInterface = {
+
+  landmarksSelected : [],
+  fetchedTemplates : [],
+  loadedNgLayers: [],
+  regionsSelected: [],
+  userLandmarks: [],
+  dedicatedView: null,
+  navigation: null,
+  parcellationSelected: null,
+  templateSelected: null
+}
+
+export const getStateStore = ({ state = defaultState } = {}) => (prevState:Partial<StateInterface> = state, action:ActionInterface) => {
   switch(action.type){
     /**
      * TODO may be obsolete. test when nifti become available
      */
     case LOAD_DEDICATED_LAYER:
-      const dedicatedView = state.dedicatedView
-        ? state.dedicatedView.concat(action.dedicatedView)
+      const dedicatedView = prevState.dedicatedView
+        ? prevState.dedicatedView.concat(action.dedicatedView)
         : [action.dedicatedView]
       return {
-        ...state,
+        ...prevState,
         dedicatedView 
       }
     case UNLOAD_DEDICATED_LAYER:
       return {
-        ...state,
-        dedicatedView : state.dedicatedView
-          ? state.dedicatedView.filter(dv => dv !== action.dedicatedView)
+        ...prevState,
+        dedicatedView : prevState.dedicatedView
+          ? prevState.dedicatedView.filter(dv => dv !== action.dedicatedView)
           : []
       }
     case NEWVIEWER:
@@ -78,7 +83,7 @@ export function stateStore(
       // const parcellation = propagateNgId( selectParcellation ): parcellation
       const { regions, ...parcellationWORegions } = parcellation
       return {
-        ...state,
+        ...prevState,
         templateSelected : action.selectTemplate,
         parcellationSelected : {
           ...parcellationWORegions,
@@ -92,13 +97,13 @@ export function stateStore(
       }
     case FETCHED_TEMPLATE : {
       return {
-        ...state,
-        fetchedTemplates: state.fetchedTemplates.concat(action.fetchedTemplate)
+        ...prevState,
+        fetchedTemplates: prevState.fetchedTemplates.concat(action.fetchedTemplate)
       }
     }
     case CHANGE_NAVIGATION : {
       return {
-        ...state,
+        ...prevState,
         navigation : action.navigation
       }
     }
@@ -106,7 +111,7 @@ export function stateStore(
       const { selectParcellation:parcellation } = action
       const { regions, ...parcellationWORegions } = parcellation
       return {
-        ...state,
+        ...prevState,
         parcellationSelected: parcellationWORegions,
         // taken care of by effect.ts
         // regionsSelected: []
@@ -115,7 +120,7 @@ export function stateStore(
     case UPDATE_PARCELLATION: {
       const { updatedParcellation } = action
       return {
-        ...state,
+        ...prevState,
         parcellationSelected: {
           ...updatedParcellation,
           updated: true
@@ -125,24 +130,24 @@ export function stateStore(
     case SELECT_REGIONS:
       const { selectRegions } = action
       return {
-        ...state,
+        ...prevState,
         regionsSelected: selectRegions
       }
     case DESELECT_LANDMARKS : {
       return {
-        ...state,
-        landmarksSelected : state.landmarksSelected.filter(lm => action.deselectLandmarks.findIndex(dLm => dLm.name === lm.name) < 0)
+        ...prevState,
+        landmarksSelected : prevState.landmarksSelected.filter(lm => action.deselectLandmarks.findIndex(dLm => dLm.name === lm.name) < 0)
       }
     }
     case SELECT_LANDMARKS : {
       return {
-        ...state,
+        ...prevState,
         landmarksSelected : action.landmarks
       }
     }
     case USER_LANDMARKS : {
       return {
-        ...state,
+        ...prevState,
         userLandmarks: action.landmarks
       } 
     }
@@ -153,12 +158,12 @@ export function stateStore(
     case NEHUBA_LAYER_CHANGED: {
       if (!window['viewer']) {
         return {
-          ...state,
+          ...prevState,
           loadedNgLayers: []
         }
       } else {
         return {
-          ...state,
+          ...prevState,
           loadedNgLayers: (window['viewer'].layerManager.managedLayers as any[]).map(obj => ({
             name : obj.name,
             type : obj.initialSpecification.type,
@@ -168,11 +173,16 @@ export function stateStore(
         }
       }
     }
+    case GENERAL_ACTION_TYPES.APPLY_STATE:
+      const { viewerState } = (action as any).state
+      return viewerState
     default :
-      return state
+      return prevState
   }
 }
 
+export const stateStore = getStateStore()
+
 export const LOAD_DEDICATED_LAYER = 'LOAD_DEDICATED_LAYER'
 export const UNLOAD_DEDICATED_LAYER = 'UNLOAD_DEDICATED_LAYER'
 
diff --git a/src/services/stateStore.service.ts b/src/services/stateStore.service.ts
index c43fe0d6710f259a6a0c50eb37f6bccff25b95b0..9ce8ea1bec76f1f0972888942b56f12c11e74196 100644
--- a/src/services/stateStore.service.ts
+++ b/src/services/stateStore.service.ts
@@ -2,37 +2,52 @@ import { filter } from 'rxjs/operators';
 
 import { 
   StateInterface as PluginStateInterface,
-  stateStore as pluginState
+  stateStore as pluginState,
+  defaultState as pluginDefaultState,
+  getStateStore as pluginGetStateStore
 } from './state/pluginState.store'
 import { 
   StateInterface as ViewerConfigStateInterface,
-  stateStore as viewerConfigState
+  stateStore as viewerConfigState,
+  defaultState as viewerConfigDefaultState,
+  getStateStore as getViewerConfigStateStore
 } from './state/viewerConfig.store'
 import { 
   StateInterface as NgViewerStateInterface,
   ActionInterface as NgViewerActionInterface,
-  stateStore as ngViewerState
+  stateStore as ngViewerState,
+  defaultState as ngViewerDefaultState,
+  getStateStore as getNgViewerStateStore
 } from './state/ngViewerState.store'
 import {
   StateInterface as ViewerStateInterface,
   ActionInterface as ViewerActionInterface,
-  stateStore as viewerState
+  stateStore as viewerState,
+  defaultState as viewerDefaultState,
+  getStateStore as getViewerStateStore
 } from './state/viewerState.store'
 import {
   StateInterface as DataStateInterface,
   ActionInterface as DatasetAction,
-  stateStore as dataStore
+  stateStore as dataStore,
+  defaultState as dataStoreDefaultState,
+  getStateStore as getDatasetStateStore
 } from './state/dataStore.store'
 import {
   StateInterface as UIStateInterface,
   ActionInterface as UIActionInterface,
-  stateStore as uiState
+  stateStore as uiState,
+  defaultState as uiDefaultState,
+  getStateStore as getUiStateStore
 } from './state/uiState.store'
 import{
   stateStore as userConfigState,
   ACTION_TYPES as USER_CONFIG_ACTION_TYPES,
-  StateInterface as UserConfigStateInterface
+  StateInterface as UserConfigStateInterface,
+  defaultState as userConfigDefaultState,
+  getStateStore as getuserConfigStateStore
 } from './state/userConfigState.store'
+import { cvtSearchParamToState } from 'src/atlasViewer/atlasViewer.urlUtil';
 
 export { pluginState }
 export { viewerConfigState }
@@ -49,7 +64,8 @@ export { CLOSE_SIDE_PANEL, MOUSE_OVER_LANDMARK, MOUSE_OVER_SEGMENT, OPEN_SIDE_PA
 export { UserConfigStateUseEffect } from './state/userConfigState.store'
 
 export const GENERAL_ACTION_TYPES = {
-  ERROR: 'ERROR'
+  ERROR: 'ERROR',
+  APPLY_STATE: 'APPLY_STATE'
 }
 
 // TODO deprecate
@@ -75,6 +91,12 @@ const inheritNgId = (region:any) => {
   }
 }
 
+export function getNgIdLabelIndexFromRegion({ region }){
+  const { ngId, labelIndex } = region
+  if (ngId && labelIndex) return { ngId, labelIndex }
+  throw new Error(`ngId: ${ngId} or labelIndex: ${labelIndex} not defined`)
+}
+
 export function getMultiNgIdsRegionsLabelIndexMap(parcellation: any = {}):Map<string,Map<number, any>>{
   const map:Map<string,Map<number, any>> = new Map()
   const { ngId = 'root'} = parcellation
@@ -199,4 +221,20 @@ export interface IavRootStoreInterface{
   dataStore: DataStateInterface
   uiState: UIStateInterface
   userConfigState: UserConfigStateInterface
-}
\ No newline at end of file
+}
+
+export const defaultRootState: IavRootStoreInterface = {
+  pluginState: pluginDefaultState,
+  dataStore: dataStoreDefaultState,
+  ngViewerState: ngViewerDefaultState,
+  uiState: uiDefaultState,
+  userConfigState: userConfigDefaultState,
+  viewerConfigState: viewerConfigDefaultState,
+  viewerState: viewerDefaultState
+}
+
+
+// export const getInitialState = (): IavRootStoreInterface => {
+//   const search = new URLSearchParams( window.location.search )
+//   cvtSearchParamToState(search, defaultRootState)
+// }
\ No newline at end of file
diff --git a/src/ui/databrowserModule/kgSingleDatasetService.service.ts b/src/ui/databrowserModule/kgSingleDatasetService.service.ts
index 5a758272d1b9e16017c8efd51e63a4949f6da022..a636fc77ac88102fa2d2823c38835d4c8cf55fa4 100644
--- a/src/ui/databrowserModule/kgSingleDatasetService.service.ts
+++ b/src/ui/databrowserModule/kgSingleDatasetService.service.ts
@@ -1,5 +1,5 @@
 import { Injectable, TemplateRef, OnDestroy } from "@angular/core";
-import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service"
+import { AtlasViewerConstantsServices, GLSL_COLORMAP_JET } from "src/atlasViewer/atlasViewer.constantService.service"
 import { Store, select } from "@ngrx/store";
 import { SHOW_BOTTOM_SHEET } from "src/services/state/uiState.store";
 import { ViewerPreviewFile, DataEntry } from "src/services/state/dataStore.store";
@@ -130,7 +130,7 @@ export class KgSingleDatasetService implements OnDestroy{
       name : url,
       source : `nifti://${url}`,
       mixability : 'nonmixable',
-      shader : this.constantService.getActiveColorMapFragmentMain()
+      shader : GLSL_COLORMAP_JET
     }
     this.store$.dispatch({
       type: ADD_NG_LAYER,
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index fbbc509659c1cc4b6c9f8729283f1554e8393972..5b312c5794d474e5e3da488c500564a292b122ad 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -3,7 +3,7 @@ import { NehubaViewerUnit, computeDistance } from "./nehubaViewer/nehubaViewer.c
 import { Store, select } from "@ngrx/store";
 import { ViewerStateInterface, safeFilter, CHANGE_NAVIGATION, isDefined, ADD_NG_LAYER, REMOVE_NG_LAYER, NgViewerStateInterface, MOUSE_OVER_LANDMARK, Landmark, PointLandmarkGeometry, PlaneLandmarkGeometry, OtherLandmarkGeometry, getNgIds, getMultiNgIdsRegionsLabelIndexMap, generateLabelIndexId, DataEntry } from "src/services/stateStore.service";
 import { Observable, Subscription, fromEvent, combineLatest, merge, of } from "rxjs";
-import { filter,map, take, scan, debounceTime, distinctUntilChanged, switchMap, skip, buffer, tap, switchMapTo, shareReplay, mapTo, takeUntil, throttleTime } from "rxjs/operators";
+import { filter,map, take, scan, debounceTime, distinctUntilChanged, switchMap, skip, buffer, tap, switchMapTo, shareReplay, mapTo, takeUntil, throttleTime, withLatestFrom, startWith } from "rxjs/operators";
 import { AtlasViewerAPIServices, UserLandmark } from "../../atlasViewer/atlasViewer.apiService.service";
 import { timedValues } from "../../util/generator";
 import { AtlasViewerConstantsServices } from "../../atlasViewer/atlasViewer.constantService.service";
@@ -13,6 +13,7 @@ import { NEHUBA_READY, H_ONE_THREE, V_ONE_THREE, FOUR_PANEL, SINGLE_PANEL, NG_VI
 import { MOUSE_OVER_SEGMENTS } from "src/services/state/uiState.store";
 import { getHorizontalOneThree, getVerticalOneThree, getFourPanel, getSinglePanel } from "./util";
 import { SELECT_REGIONS_WITH_ID, NEHUBA_LAYER_CHANGED, VIEWERSTATE_ACTION_TYPES } from "src/services/state/viewerState.store";
+import { isSame } from "src/util/fn";
 
 const getProxyUrl = (ngUrl) => `nifti://${BACKEND_URL}preview/file?fileUrl=${encodeURIComponent(ngUrl.replace(/^nifti:\/\//,''))}`
 const getProxyOther = ({source}) => /AUTH_227176556f3c4bb38df9feea4b91200c/.test(source)
@@ -99,6 +100,7 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
   public sliceViewLoading2$: Observable<boolean>
   public perspectiveViewLoading$: Observable<string|null>
 
+  private templateSelected$: Observable<any>
   private newViewer$ : Observable<any>
   private selectedParcellation$ : Observable<any>
   private selectedRegions$ : Observable<any[]>
@@ -205,12 +207,14 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
 
     this.nehubaViewerFactory = this.csf.resolveComponentFactory(NehubaViewerUnit)
 
-    this.newViewer$ = this.store.pipe(
+    this.templateSelected$ = this.store.pipe(
       select('viewerState'),
-      filter(state=>isDefined(state) && isDefined(state.templateSelected)),
-      filter(state=>
-        !isDefined(this.selectedTemplate) || 
-        state.templateSelected.name !== this.selectedTemplate.name)
+      select('templateSelected'),
+      distinctUntilChanged(isSame)
+    )
+
+    this.newViewer$ = this.templateSelected$.pipe(
+      filter(v => !!v)
     )
 
     this.selectedParcellation$ = this.store.pipe(
@@ -592,33 +596,40 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
       })
     )
 
+    this.subscriptions.push(
+      this.templateSelected$.subscribe(() => this.destroynehuba())
+    )
+
     /* order of subscription will determine the order of execution */
     this.subscriptions.push(
       this.newViewer$.pipe(
-        map(state => {
-          const deepCopiedState = JSON.parse(JSON.stringify(state))
-          const navigation = deepCopiedState.templateSelected.nehubaConfig.dataset.initialNgState.navigation
+        map(templateSelected => {
+          const deepCopiedState = JSON.parse(JSON.stringify(templateSelected))
+          const navigation = deepCopiedState.nehubaConfig.dataset.initialNgState.navigation
           if (!navigation) {
             return deepCopiedState
           }
           navigation.zoomFactor = calculateSliceZoomFactor(navigation.zoomFactor)
-          deepCopiedState.templateSelected.nehubaConfig.dataset.initialNgState.navigation = navigation
+          deepCopiedState.nehubaConfig.dataset.initialNgState.navigation = navigation
           return deepCopiedState
-        })
-      ).subscribe((state)=>{
+        }),
+        withLatestFrom(this.selectedParcellation$.pipe(
+          startWith(null)
+        ))
+      ).subscribe(([templateSelected, parcellationSelected])=>{
         this.store.dispatch({
           type: NEHUBA_READY,
           nehubaReady: false
         })
         this.nehubaViewerSubscriptions.forEach(s=>s.unsubscribe())
 
-        this.selectedTemplate = state.templateSelected
-        this.createNewNehuba(state.templateSelected)
-        const foundParcellation = state.templateSelected.parcellations.find(parcellation=>
-          state.parcellationSelected.name === parcellation.name)
-        this.handleParcellation(foundParcellation ? foundParcellation : state.templateSelected.parcellations[0])
+        this.selectedTemplate = templateSelected
+        this.createNewNehuba(templateSelected)
+        const foundParcellation = parcellationSelected
+          && templateSelected.parcellations.find(parcellation=> parcellationSelected.name === parcellation.name)
+        this.handleParcellation(foundParcellation || templateSelected.parcellations[0])
 
-        const nehubaConfig = state.templateSelected.nehubaConfig
+        const nehubaConfig = templateSelected.nehubaConfig
         const initialSpec = nehubaConfig.dataset.initialNgState
         const {layers} = initialSpec
         
@@ -725,6 +736,8 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
     combineLatest(
       this.navigationChanges$,
       this.selectedRegions$,
+    ).pipe(
+      filter(() => !!this.nehubaViewer)
     ).subscribe(([navigation,regions])=>{
       this.nehubaViewer.initNav = {
         ...navigation,
@@ -966,18 +979,22 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
   oldNavigation : any = {}
   spatialSearchPagination : number = 0
 
-  private createNewNehuba(template:any){
-
+  private destroynehuba(){
     /**
      * TODO if plugin subscribes to viewerHandle, and then new template is selected, changes willl not be be sent
      * could be considered as a bug. 
      */
     this.apiService.interactiveViewer.viewerHandle = null
+    if( this.cr ) this.cr.destroy()
+    this.container.clear()
+
+    this.viewerLoaded = false
+    this.nehubaViewer = null
+  }
+
+  private createNewNehuba(template:any){
 
     this.viewerLoaded = true
-    if( this.cr )
-      this.cr.destroy()
-    this.container.clear()
     this.cr = this.container.createComponent(this.nehubaViewerFactory)
     this.nehubaViewer = this.cr.instance
 
@@ -986,6 +1003,21 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
      */
     const { gpuLimit = null } = this.viewerConfig
     const { nehubaConfig } = template
+    const { navigation = {}, perspectiveOrientation = [0, 0, 0, 1], perspectiveZoom = 1e7 } = nehubaConfig.dataset.initialNgState || {}
+    const { zoomFactor = 3e5, pose = {} } = navigation || {}
+    const { voxelSize = [1e6, 1e6, 1e6], voxelCoordinates = [0, 0, 0] } = (pose && pose.position) || {}
+
+    const initNavigation = {
+      orientation: [0, 0, 0, 1],
+      perspectiveOrientation,
+      perspectiveZoom,
+      position: [0, 1, 2].map(idx => voxelSize[idx] * voxelCoordinates[idx]),
+      zoom: zoomFactor
+    }
+
+    this.handleEmittedNavigationChange(initNavigation)
+
+    this.oldNavigation = initNavigation
     
     if (gpuLimit) {
       const initialNgState = nehubaConfig && nehubaConfig.dataset && nehubaConfig.dataset.initialNgState
@@ -1210,15 +1242,14 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
       As the viewer updates the dynamically changed navigation, it will emit the navigation state. 
       The emitted navigation state should be identical to this.oldnavigation */
 
-    const navigationChangedActively : boolean = Object.keys(this.oldNavigation).length === 0 || !Object.keys(this.oldNavigation).every(key=>{
+    const navigationChangedActively: boolean = Object.keys(this.oldNavigation).length === 0 || !Object.keys(this.oldNavigation).every(key=>{
       return this.oldNavigation[key].constructor === Number || this.oldNavigation[key].constructor === Boolean ?
         this.oldNavigation[key] === navigation[key] :
         this.oldNavigation[key].every((_,idx)=>this.oldNavigation[key][idx] === navigation[key][idx])
     })
 
     /* if navigation is changed dynamically (ie not actively), the state would have been propagated to the store already. Hence return */
-    if( !navigationChangedActively )
-      return
+    if( !navigationChangedActively ) return
     
     /* navigation changed actively (by user interaction with the viewer)
       probagate the changes to the store */
diff --git a/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts b/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts
index 9f7e287a841bae5eeb7822d2ab632b38008d114f..2b4fe6c2e0bd3573deb7cddaf942513ae265bfe6 100644
--- a/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts
+++ b/src/ui/nehubaContainer/splashScreen/splashScreen.component.ts
@@ -1,9 +1,9 @@
 import { Component, Pipe, PipeTransform, ElementRef, ViewChild, AfterViewInit } from "@angular/core";
 import { Observable, fromEvent, Subscription, Subject } from "rxjs";
 import { Store, select } from "@ngrx/store";
-import { switchMap, bufferTime, take, filter, withLatestFrom, map, tap } from 'rxjs/operators'
-import { ViewerStateInterface, NEWVIEWER } from "../../../services/stateStore.service";
-import { AtlasViewerConstantsServices } from "../../../atlasViewer/atlasViewer.constantService.service";
+import { switchMap, bufferTime, take, filter, withLatestFrom, map } from 'rxjs/operators'
+import { ViewerStateInterface, NEWVIEWER } from "src/services/stateStore.service";
+import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service";
 
 
 @Component({
diff --git a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
index 305da063db1bb578166affba4d3ef81ac7ba58ad..80a4cdb8b596d52f8daef7b20b8cdf06aefc5972 100644
--- a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
+++ b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
@@ -1,7 +1,7 @@
 import { Component, EventEmitter, Output, ViewChild, ElementRef, TemplateRef, Input, ChangeDetectionStrategy } from "@angular/core";
 import { Store, select } from "@ngrx/store";
 import { Observable, combineLatest } from "rxjs";
-import { map, distinctUntilChanged, startWith, debounceTime, shareReplay, take, tap } from "rxjs/operators";
+import { map, distinctUntilChanged, startWith, debounceTime, shareReplay, take, tap, filter } from "rxjs/operators";
 import { getMultiNgIdsRegionsLabelIndexMap, generateLabelIndexId, IavRootStoreInterface } from "src/services/stateStore.service";
 import { FormControl } from "@angular/forms";
 import { MatAutocompleteSelectedEvent, MatDialog } from "@angular/material";
@@ -52,6 +52,7 @@ export class RegionTextSearchAutocomplete{
     this.regionsWithLabelIndex$ = viewerState$.pipe(
       select('parcellationSelected'),
       distinctUntilChanged(),
+      filter(p => !!p),
       map(parcellationSelected => {
         const returnArray = []
         const ngIdMap = getMultiNgIdsRegionsLabelIndexMap(parcellationSelected)
diff --git a/src/ui/viewerStateController/viewerState.useEffect.ts b/src/ui/viewerStateController/viewerState.useEffect.ts
index 405d22b47bd47f7be70c84fbf0597d2760744207..5e7a3fc7fd6698ef1e517f3c74d7525570c749c0 100644
--- a/src/ui/viewerStateController/viewerState.useEffect.ts
+++ b/src/ui/viewerStateController/viewerState.useEffect.ts
@@ -4,9 +4,10 @@ import { Actions, ofType, Effect } from "@ngrx/effects";
 import { Store, select, Action } from "@ngrx/store";
 import { shareReplay, distinctUntilChanged, map, withLatestFrom, filter } from "rxjs/operators";
 import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "./viewerState.base";
-import { CHANGE_NAVIGATION, SELECT_REGIONS, NEWVIEWER, GENERAL_ACTION_TYPES, SELECT_PARCELLATION, isDefined, IavRootStoreInterface } from "src/services/stateStore.service";
+import { CHANGE_NAVIGATION, SELECT_REGIONS, NEWVIEWER, GENERAL_ACTION_TYPES, SELECT_PARCELLATION, isDefined, IavRootStoreInterface, FETCHED_TEMPLATE } from "src/services/stateStore.service";
 import { regionFlattener } from "src/util/regionFlattener";
 import { UIService } from "src/services/uiService.service";
+import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service";
 
 @Injectable({
   providedIn: 'root'
@@ -19,6 +20,16 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
   private selectedRegions$: Observable<any[]>
 
 
+  @Effect()
+  init$ = this.constantSerivce.initFetchTemplate$.pipe(
+    map(fetchedTemplate => {
+      return {
+        type: FETCHED_TEMPLATE,
+        fetchedTemplate
+      }
+    })
+  )
+
   @Effect()
   selectTemplateWithName$: Observable<any>
   
@@ -46,7 +57,8 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
   constructor(
     private actions$: Actions,
     private store$: Store<IavRootStoreInterface>,
-    private uiService: UIService
+    private uiService: UIService,
+    private constantSerivce: AtlasViewerConstantsServices
   ){
     const viewerState$ = this.store$.pipe(
       select('viewerState'),
diff --git a/src/util/fn.spec.ts b/src/util/fn.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1161a9fbaf2ec88409dd2b506b0977fbfca76410
--- /dev/null
+++ b/src/util/fn.spec.ts
@@ -0,0 +1,31 @@
+import {} from 'jasmine'
+import { isSame } from './fn'
+
+describe(`util/fn.ts`, () => {
+  describe(`#isSame`, () => {
+    it('should return true with null, null', () => {
+      expect(isSame(null, null)).toBe(true)
+    })
+
+    it('should return true with string', () => {
+      expect(isSame('test', 'test')).toBe(true)
+    })
+
+    it(`should return true with numbers`, () => {
+      expect(isSame(12, 12)).toBe(true)
+    })
+
+    it('should return true with obj with name attribute', () => {
+
+      const obj = {
+        name: 'hello'
+      }
+      const obj2 = {
+        name: 'hello',
+        world: 'world'
+      }
+      expect(isSame(obj, obj2)).toBe(true)
+      expect(obj).not.toEqual(obj2)
+    })
+  })
+})
\ No newline at end of file
diff --git a/src/util/fn.ts b/src/util/fn.ts
new file mode 100644
index 0000000000000000000000000000000000000000..efc9974787f07a51989bf59fc7c86d686562f37a
--- /dev/null
+++ b/src/util/fn.ts
@@ -0,0 +1,4 @@
+export function isSame (o, n) {
+  if (!o) return !n
+  return o === n || (o && n && o.name === n.name)
+}
\ No newline at end of file