diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index d6858fc25d2c152df0d775c0590b4b7df249a3a7..9203ddec11d5972bd515d88cabe518281765a226 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -74,7 +74,7 @@ jobs:
 
     - name: Set output when workflow fails
       if: failure()
-      run: echo '::set-output name=failure-state::true'
+      run: echo "failure-state=true" >> $GITHUB_OUTPUT
       id: failure-state-step
 
     - name: Define screenshot artefact
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ab32b4c8b1c72ec36e2357c4aa01792734e10cbd..bf45ae2f90ca8e5f77b188d7ea25a08611187221 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,7 +17,7 @@ jobs:
       id: set-version
       run: |
         PACKAGEJSON_VER=v$(cat package.json | jq -r '.version')
-        echo "::set-output name=package-version-from-json::$PACKAGEJSON_VER"
+        echo "package-version-from-json=$PACKAGEJSON_VER" >> $GITHUB_OUTPUT
       
   create-release:
     needs: check-version
diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html
index 1095b2dd6ede917c1a36f2768a39d6198d500716..4fc7d43c724b20c459f30fe30003336909a341a5 100644
--- a/.storybook/preview-head.html
+++ b/.storybook/preview-head.html
@@ -15,5 +15,5 @@
   }
 </style>
 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
-<script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.5/dist/connectivity-component/connectivity-component.js" defer></script>
+<script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.6/dist/connectivity-component/connectivity-component.js" defer></script>
 <link rel="stylesheet" href="icons/iav-icons.css">
diff --git a/deploy/csp/index.js b/deploy/csp/index.js
index 4905289c335c2a0af1495eed901cc9f66c1aba93..1d67da419baa8f3c60bb7e93893ce5939f9d5ee2 100644
--- a/deploy/csp/index.js
+++ b/deploy/csp/index.js
@@ -116,7 +116,7 @@ module.exports = {
           'https://unpkg.com/mathjax@3.1.2/', // math jax
           'https://unpkg.com/three-surfer@0.0.13/dist/bundle.js', // for threeSurfer (freesurfer support in browser)
           'https://unpkg.com/ng-layer-tune@0.0.6/dist/ng-layer-tune/', // needed for ng layer control
-          'https://unpkg.com/hbp-connectivity-component@0.6.5/', // needed for connectivity component
+          'https://unpkg.com/hbp-connectivity-component@0.6.6/', // needed for connectivity component
           (req, res) => res.locals.nonce ? `'nonce-${res.locals.nonce}'` : null,
           ...SCRIPT_SRC,
           ...WHITE_LIST_SRC,
diff --git a/docs/releases/v2.10.1.md b/docs/releases/v2.10.1.md
new file mode 100644
index 0000000000000000000000000000000000000000..43b34eb46b24731a77b07733f201507b58eec49e
--- /dev/null
+++ b/docs/releases/v2.10.1.md
@@ -0,0 +1,12 @@
+# v2.10.1
+
+## Bugfix
+
+- fsaverage on change variant, showing multiple meshes
+- fsaverage erroneous URL encoding of selected region
+- some annotations no longe rwork properly
+
+## Behind the scenes
+
+- Housekeeping CI/CD
+- Simplify some behind the scenes code
diff --git a/mkdocs.yml b/mkdocs.yml
index 930e1107660415acb1e6e21ed42719ef4a11dd28..4bc43ba5039d6018e642df3e329279aba41773c0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -33,6 +33,7 @@ nav:
     - Fetching datasets: 'advanced/datasets.md'
     - Display non-atlas volumes: 'advanced/otherVolumes.md'
   - Release notes:
+    - v2.10.1: 'releases/v2.10.1.md'
     - v2.10.0: 'releases/v2.10.0.md'
     - v2.9.1: 'releases/v2.9.1.md'
     - v2.9.0: 'releases/v2.9.0.md'
diff --git a/package.json b/package.json
index 816cf85477e6fec9ec48d807c098cd7559b25529..2ee728b99bcd28332fe61fd2bd853037bae814ac 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "siibra-explorer",
-  "version": "2.10.0",
+  "version": "2.10.1",
   "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular",
   "scripts": {
     "lint": "eslint src --ext .ts",
@@ -11,7 +11,7 @@
     "watch": "ng build --watch --configuration development",
     "test": "ng test",
     "test-ci": "ng test --progress false --watch false --browsers=ChromeHeadless",
-    "sapi-schema": "npx openapi-typescript@6.1.0 https://siibra-api-latest.apps-dev.hbp.eu/v3_0/openapi.json --output ./src/atlasComponents/sapi/schemaV3.ts && eslint ./src/atlasComponents/sapi/schemaV3.ts --no-ignore --fix",
+    "sapi-schema": "npx openapi-typescript@6.1.0 https://siibra-api-stable.apps-dev.hbp.eu/v3_0/openapi.json --output ./src/atlasComponents/sapi/schemaV3.ts && eslint ./src/atlasComponents/sapi/schemaV3.ts --no-ignore --fix",
     "api-schema": "node src/plugin/generateTypes.js",
     "docs:json": "compodoc -p ./tsconfig.json -e json -d .",
     "storybook": "npm run docs:json && start-storybook -p 6006",
diff --git a/src/atlasComponents/sapi/constants.ts b/src/atlasComponents/sapi/constants.ts
index c558e1726cbcb629e302f4122dddcd600607ea5d..da2294c69e9db1351e9c7f2d8606e9879abb7e99 100644
--- a/src/atlasComponents/sapi/constants.ts
+++ b/src/atlasComponents/sapi/constants.ts
@@ -9,6 +9,7 @@ export const IDS = {
     COLIN27: "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992",
     WAXHOLM: "minds/core/referencespace/v1.0.0/d5717c4a-0fa1-46e6-918c-b8003069ade8",
     MEBRAINS: "minds/core/referencespace/v1.0.0/MEBRAINS",
+    FSAVERAGE: 'minds/core/referencespace/v1.0.0/tmp-fsaverage'
   },
   PARCELLATION: {
     JBA29: "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-290",
diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts
index 8b9206271330d02c016324e967eea2b2693eeccb..65a12c19b1c460020327b4fbb6346c933e240294 100644
--- a/src/atlasComponents/sapi/sapi.service.ts
+++ b/src/atlasComponents/sapi/sapi.service.ts
@@ -22,7 +22,7 @@ export const useViewer = {
 } as const
 
 export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version'
-export const EXPECTED_SIIBRA_API_VERSION = '0.3.0'
+export const EXPECTED_SIIBRA_API_VERSION = '0.3.1'
 
 let BS_ENDPOINT_CACHED_VALUE: Observable<string> = null
 
diff --git a/src/atlasComponents/sapi/schemaV3.ts b/src/atlasComponents/sapi/schemaV3.ts
index 7c926b526224af5d5bc4ccdff711341591591ce3..c6740c619bf9de58fed30778b672d8996cb46ea6 100644
--- a/src/atlasComponents/sapi/schemaV3.ts
+++ b/src/atlasComponents/sapi/schemaV3.ts
@@ -489,11 +489,11 @@ export interface components {
       /** @Type */
       "@type": string
       /** Index */
-      index: string[]
+      index: unknown[]
       /** Dtype */
       dtype: string
       /** Columns */
-      columns: string[]
+      columns: unknown[]
       /** Ndim */
       ndim: number
       /** Data */
@@ -510,7 +510,7 @@ export interface components {
       /** Urls */
       urls: (components["schemas"]["EbrainsDsUrl"])[]
       /** Description */
-      description: string
+      description?: string
       /** Contributors */
       contributors: (components["schemas"]["EbrainsDsPerson"])[]
       /** Ebrains Page */
@@ -722,6 +722,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[FeatureMetaModel] */
     Page_FeatureMetaModel_: {
@@ -733,6 +735,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[ParcellationEntityVersionModel] */
     Page_ParcellationEntityVersionModel_: {
@@ -744,6 +748,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraAtlasModel] */
     Page_SiibraAtlasModel_: {
@@ -755,6 +761,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraCorticalProfileModel] */
     Page_SiibraCorticalProfileModel_: {
@@ -766,6 +774,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraEbrainsDataFeatureModel] */
     Page_SiibraEbrainsDataFeatureModel_: {
@@ -777,6 +787,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraParcellationModel] */
     Page_SiibraParcellationModel_: {
@@ -788,6 +800,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraRegionalConnectivityModel] */
     Page_SiibraRegionalConnectivityModel_: {
@@ -799,6 +813,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraTabularModel] */
     Page_SiibraTabularModel_: {
@@ -810,6 +826,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraVoiModel] */
     Page_SiibraVoiModel_: {
@@ -821,6 +839,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[Union[SiibraCorticalProfileModel, SiibraReceptorDensityFp, SiibraTabularModel]] */
     Page_Union_SiibraCorticalProfileModel__SiibraReceptorDensityFp__SiibraTabularModel__: {
@@ -832,6 +852,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** ParcellationEntityVersionModel */
     ParcellationEntityVersionModel: {
@@ -985,7 +1007,8 @@ export interface components {
     SiibraAnchorModel: {
       /** @Type */
       "@type": string
-      location?: components["schemas"]["LocationModel"]
+      /** Location */
+      location?: components["schemas"]["LocationModel"] | components["schemas"]["CoordinatePointModel"]
       /** Regions */
       regions: (components["schemas"]["SiibraRegionAssignmentQual"])[]
     }
diff --git a/src/atlasComponents/sapi/sxplrTypes.ts b/src/atlasComponents/sapi/sxplrTypes.ts
index 0fcf7abfe9067e80de67b0ec59c788d47632c77b..ef556f25eb9c77344aa826d7b6d88e1e478c1227 100644
--- a/src/atlasComponents/sapi/sxplrTypes.ts
+++ b/src/atlasComponents/sapi/sxplrTypes.ts
@@ -125,8 +125,8 @@ export type CorticalFeature<T extends CorticalDataType, IndexType extends string
 type TabularDataType = number | string | number[]
 
 export type TabularFeature<T extends TabularDataType> = {
-  index: string[]
-  columns: string[]
+  index: unknown[]
+  columns: unknown[]
   data?: T[][]
 } & Feature
 
diff --git a/src/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts b/src/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
index 05ffb3f2c9f303055796d1a14f31653bf222db40..dbc546a7ead3d44685043b5654767b8499debe28 100644
--- a/src/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
+++ b/src/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
@@ -1,387 +1,554 @@
-import {AfterViewInit, Component, ElementRef, OnDestroy, ViewChild, Input, ChangeDetectorRef} from "@angular/core";
-import {select, Store} from "@ngrx/store";
-import {fromEvent, Subscription, BehaviorSubject, Observable} from "rxjs";
-import {catchError, take, switchMap} from "rxjs/operators";
+import {  Component, ElementRef, OnDestroy, ViewChild, Input, SimpleChanges, HostListener, OnChanges } from "@angular/core";
+import { Store, select} from "@ngrx/store";
+import { Subscription, BehaviorSubject, combineLatest, merge, concat, NEVER} from "rxjs";
+import { switchMap, map, tap, shareReplay, distinctUntilChanged, withLatestFrom, filter, finalize } from "rxjs/operators";
 
-import { atlasAppearance } from "src/state";
-import {SAPI} from "src/atlasComponents/sapi/sapi.service";
+import { atlasAppearance, atlasSelection } from "src/state";
+import { SAPI } from "src/atlasComponents/sapi/sapi.service";
 import { of } from "rxjs";
-import { HttpClient } from "@angular/common/http";
 import { SxplrAtlas, SxplrParcellation, SxplrRegion, SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes";
-import { actions, selectors } from "src/state/atlasSelection";
+import { actions } from "src/state/atlasSelection";
 import { translateV3Entities } from "src/atlasComponents/sapi/translateV3";
+import { DS } from "src/features/filterCategories.pipe";
+import { FormControl, FormGroup } from "@angular/forms";
+import { PathReturn } from "src/atlasComponents/sapi/typeV3";
+import { arrayEqual } from "src/util/array";
+import { switchMapWaitFor } from "src/util/fn";
+
+type PathParam = DS['value'][number]
+type ConnFeat = PathReturn<"/feature/RegionalConnectivity/{feature_id}">
 
 @Component({
   selector: 'sxplr-features-connectivity-browser',
   templateUrl: './connectivityBrowser.template.html',
   styleUrls: ['./connectivityBrowser.style.scss']
 })
-export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
+export class ConnectivityBrowserComponent implements OnChanges, OnDestroy {
 
+  @Input('sxplr-features-connectivity-browser-atlas')
+  atlas: SxplrAtlas
 
-    @Input('sxplr-features-connectivity-browser-atlas')
-    atlas: SxplrAtlas
+  @Input('sxplr-features-connectivity-browser-template')
+  template: SxplrTemplate
 
-    @Input('sxplr-features-connectivity-browser-template')
-    template: SxplrTemplate
+  @Input('sxplr-features-connectivity-browser-parcellation')
+  parcellation: SxplrParcellation
 
-    @Input('sxplr-features-connectivity-browser-parcellation')
-    parcellation: SxplrParcellation
+  parcellation$ = new BehaviorSubject<SxplrParcellation>(null)
 
-    /**
-     * accordion expansion should only toggle the clearviewqueue state
-     * which should be the single source of truth
-     * setcolormaps$ is set by the presence/absence of clearviewqueue[CONNECTIVITY_NAME_PLATE]
-     */
-    private _isFirstUpdate = true
-    @Input()
-    set accordionExpanded(flag: boolean) {
-      /**
-         * ignore first update
-         */
-      if (this._isFirstUpdate) {
-        this._isFirstUpdate = false
-        return
-      }
+  #accordionExpanded$ = new BehaviorSubject<boolean>(null)
+  @Input()
+  set accordionExpanded(flag: boolean) {
+    this.#accordionExpanded$.next(flag)
+  }
+  
+  region$ = new BehaviorSubject<SxplrRegion>(null)
+  @Input()
+  set region(region: SxplrRegion) {
+    this.region$.next(region)
+  }
 
-      if (this.types.length && !this.selectedType) this.selectType(this._types[0])
+  types$ = new BehaviorSubject<PathParam[]>(null)
+  @Input()
+  types: PathParam[]
 
-      if (flag) {
-        if (this.selectedSubjectIndex >= 0 && this.allRegions.length) {
-          this.setCustomLayer()
-        } else {
-          this.setCustomLayerOnLoad = true
-        }
-      } else {
-        this.removeCustomLayer()
-      }
+  connectivityFilterForm = new FormGroup({
+    selectedType: new FormControl<PathParam>(null),
+    selectedView: new FormControl<'average'|'subject'>('subject'),
+    selectedCohort: new FormControl<string>(null),
+    selectedDatasetIndex: new FormControl<number>(0),
+    selectedSubjectIndex: new FormControl<number>(0),
+  })
 
-    }
-    
-    private _region: SxplrRegion
-    @Input()
-    set region(region) {
-      this._region = region
-      this.regionName = region.name
-    }
+  displayForm = new FormGroup({
+    logChecked: new FormControl<boolean>(false)
+  })
 
-    get region() {
-      return this._region
-    }
+  formValue$ = this.connectivityFilterForm.valueChanges.pipe(
+    shareReplay(1),
+  )
 
-    
-    private _types: any[] = []
-    @Input()
-    set types(val) {
-      this._types = val.map(t => ({...t, shortName: t.name.split('.').pop()}))
-    }
-    get types() {
-      return this._types
-    }
+  private subscriptions: Subscription[] = []
 
+  static LayerId = 'connectivity-colormap-id'
 
-    public selectedType: any
-    public selectedCohort: string
-
-    public cohortDatasets: any[]
-
-    public selectedSubjectIndex = null
-    public selectedCohortDatasetIndex: any
-    public selectedCohortSubjects: any
-    public fetchedItems: any[] = []
-    public cohorts: string[]
-    public selectedView: 'subject' | 'average' | null
-    public averageDisabled: boolean = true
-    public subjectsDisabled: boolean = true
-
-    public regionName: string
-
-    public selectedDataset: any
-    public connectionsString: string
-    public pureConnections: { [key: string]: number }
-    public connectedAreas: BehaviorSubject<ConnectedArea[]> = new BehaviorSubject([])
-    public noConnectivityForRegion: boolean
-    private subscriptions: Subscription[] = []
-    public allRegions: SxplrRegion[] = []
-    private regionIndexInMatrix = -1
-    public defaultColorMap: Map<string, Map<number, { red: number, green: number, blue: number }>>
-    public matrixString: string
-    public fetchingPreData: boolean
-    public fetching: boolean
-    public connectivityLayerId = 'connectivity-colormap-id'
-    private setCustomLayerOnLoad = false
-    private customLayerEnabled: boolean
-
-    public logDisabled: boolean = true
-    public logChecked: boolean = true
-
-    private endpoint: string
-
-
-    @ViewChild('connectivityComponent') public connectivityComponentElement: ElementRef<any>
-    @ViewChild('fullConnectivityGrid') public fullConnectivityGridElement: ElementRef<any>
-
-    constructor(
-        private store$: Store,
-        private http: HttpClient,
-        private changeDetectionRef: ChangeDetectorRef,
-        protected sapi: SAPI
-    ) {
-      SAPI.BsEndpoint$.pipe(take(1)).subscribe(en => this.endpoint = `${en}/feature/RegionalConnectivity`)
-    }
+  @ViewChild('connectivityComponent') public connectivityComponentElement: ElementRef<any>
+  @ViewChild('fullConnectivityGrid') public fullConnectivityGridElement: ElementRef<any>
 
-    public ngAfterViewInit(): void {
-      this.subscriptions.push(
-
-        this.store$.pipe(
-          select(selectors.selectedParcAllRegions)
-        ).subscribe(flattenedRegions => {
-          this.defaultColorMap = null
-          this.allRegions = flattenedRegions
-          if (this.setCustomLayerOnLoad) {
-            this.setCustomLayer()
-            this.setCustomLayerOnLoad = false
-          }
-        }),
-      )
+  constructor(
+    private store$: Store,
+    protected sapi: SAPI
+  ) {
 
-      this.subscriptions.push(
-        fromEvent(this.connectivityComponentElement.nativeElement, 'connectedRegionClicked', {capture: true})
-          .subscribe((e: CustomEvent) => {
-            this.navigateToRegion(e.detail.name)
-          }),
-      )
-    }
-
-    setCustomLayer() {
-      if (this.customLayerEnabled) {
-        this.removeCustomLayer()
-      }
-      const map = new Map<SxplrRegion, number[]>()
-      const areas = this.connectedAreas.value
-      for (const region of this.allRegions) {
-        const area = areas.find(a => a.name === region.name)
-        if (area) {
-          map.set(region, Object.values(area.color))
-        } else {
-          map.set(region, [255,255,255,0.1])
+    this.subscriptions.push(
+      /**
+       * on accordion expansion, if nothing is selected, select default (0) type
+       */
+      combineLatest([
+        this.#accordionExpanded$,
+        this.types$,
+        concat(
+          of(null as PathParam),
+          this.formValue$.pipe(
+            map(v => v.selectedType),
+            distinctUntilChanged((n, o) => n.name === o.name)
+          )
+        ),
+      ]).pipe(
+      ).subscribe(([flag, types, selectedType]) => {
+        if (flag && !selectedType) {
+          this.connectivityFilterForm.patchValue({
+            selectedType: types[0]
+          })
         }
-      }
-      this.customLayerEnabled = true
-      const customLayer: atlasAppearance.const.CustomLayer = {
-        clType: 'customlayer/colormap',
-        id: this.connectivityLayerId,
-        colormap: map
-      }
-
-      this.store$.dispatch(
-        atlasAppearance.actions.addCustomLayer({customLayer})
-      )
-    }
-
-    removeCustomLayer() {
-      this.store$.dispatch(
-        atlasAppearance.actions.removeCustomLayer({
-          id: this.connectivityLayerId
+      }),
+      /**
+       * on set log
+       */
+      this.displayForm.valueChanges.pipe(
+        map(v => v.logChecked),
+        switchMap(switchMapWaitFor({
+          condition: () => !!this.connectivityComponentElement,
+          leading: true
+        }))
+      ).subscribe(flag => {
+        const el = this.connectivityComponentElement
+        el.nativeElement.setShowLog(flag)
+      }),
+      /**
+       * on type selection, select first cohort
+       */
+      this.formValue$.pipe(
+        map(v => v.selectedType),
+        distinctUntilChanged((n, o) => n.name === o.name),
+        switchMap(() =>
+          this.cohorts$.pipe(
+            /**
+             * it's important to not use distinctUntilChanged
+             * new corhots emit should always trigger this flow
+             */
+          )
+        )
+      ).subscribe(cohorts => {
+        if (cohorts.length > 0) {
+          this.connectivityFilterForm.patchValue({
+            selectedCohort: cohorts[0]
+          })
+        }
+      }),
+      /**
+       * on select cohort
+       */
+      
+      this.selectedCohort$.pipe(
+        switchMap(() => this.cohortDatasets$.pipe(
+          map(dss => dss.length),
+          distinctUntilChanged(),
+          filter(length => length > 0),
+        ))
+      ).subscribe(() => {
+        this.connectivityFilterForm.patchValue({
+          selectedDatasetIndex: 0,
+          selectedSubjectIndex: 0,
         })
-      )
-    }
-
-    clearCohortSelection() {
-      this.fetchedItems = []
-      this.selectedCohort = null
-      this.cohorts = []
-      this.selectedCohort = null
-      this.selectedCohortDatasetIndex = null
-      this.selectedCohortSubjects = null
-
-      this.selectedSubjectIndex = null
-    }
-
-    selectType(type) {
-      this.clearCohortSelection()
-      this.selectedType = type
-      this.removeCustomLayer()
-      this.getModality()
-    }
-
-
-    getModality() {
-      this.fetchingPreData = true
-      this.fetchModality().subscribe((res: any) => {
+      }),
+      /**
+       * on
+       * - accordion update
+       * - colormap change
+       * - fetching matrix
+       * remove custom layer
+       */
+      merge(
+        this.#accordionExpanded$,
+        this.colormap$,
+        this.#fetchingMatrix$,
+      ).subscribe(() => {
+        this.removeCustomLayer()
+      }),
+      /**
+       * on update colormap, add new custom layer
+       */
+      combineLatest([
+        this.#accordionExpanded$,
+        this.colormap$,
+      ]).pipe(
+        withLatestFrom(
+          this.store$.pipe(
+            select(atlasSelection.selectors.selectedParcAllRegions)
+          )
+        )
+      ).subscribe(([[accordionExpanded, conn], allregions]) => {
+        if (!accordionExpanded || !conn) {
+          return
+        }
 
-        this.fetchedItems.push(...res.items)
+        const map = new Map<SxplrRegion, number[]>()
+        for (const region of allregions) {
+          const area = conn.find(a => a.name === region.name)
+          if (area) {
+            map.set(region, Object.values(area.color))
+          } else {
+            map.set(region, [255,255,255,0.1])
+          }
+        }
         
-        this.cohorts = [...new Set(this.fetchedItems.map(item => item.cohort))]
-        this.fetchingPreData = false
-        this.changeDetectionRef.detectChanges()
-        this.selectCohort(this.cohorts[0])
-      
+        this.store$.dispatch(
+          atlasAppearance.actions.addCustomLayer({
+            customLayer: {
+              clType: 'customlayer/colormap',
+              id: ConnectivityBrowserComponent.LayerId,
+              colormap: map
+            }
+          })
+        )
+      }),
+      /**
+       * on pure connection update, update logchecked box
+       */
+      this.#pureConnections$.subscribe(v => {
+        for (const val of Object.values(v)) {
+          if (val > 1) {
+            this.displayForm.get("logChecked").enable()
+            return
+          }
+        }
+        this.displayForm.get("logChecked").patchValue(false)
+        this.displayForm.get("logChecked").disable()
       })
-    }
-
-    public fetchModality = (): Observable<any> => {
-      const url = `${this.endpoint}?parcellation_id=${encodeURIComponent(this.parcellation.id)}&type=${encodeURIComponent(this.selectedType.shortName)}`
-      return this.http.get(url)
-    }
-
-    selectCohort(cohort: string) {
-      this.selectedCohort = cohort
-      this.averageDisabled = !this.fetchedItems.find(s => s.cohort === this.selectedCohort && !s.subjects.length)
-      this.subjectsDisabled = !this.fetchedItems.find(s => s.cohort === this.selectedCohort && s.subjects.length > 0)
-      this.selectedView = !this.averageDisabled? 'average' : 'subject'
-
-      this.cohortDatasets = this.fetchedItems.filter(i => this.selectedCohort === i.cohort)
-      
-      this.selectedCohortDatasetChanged(0)
-    }
-
-    selectedCohortDatasetChanged(index) {
-      this.selectedCohortDatasetIndex = index
-      this.selectedCohortSubjects = this.cohortDatasets[index].subjects
+    )
+  }
 
-      this.selectedDataset = this.cohortDatasets[index].datasets[0]
-
-      
-      const keepSubject = this.selectedSubjectIndex >= 0 && this.cohortDatasets[this.selectedCohortDatasetIndex].subjects
-        .includes(this.selectedCohortSubjects[this.selectedSubjectIndex])
-
-      this.subjectSliderChanged(keepSubject? this.selectedSubjectIndex : 0)
-    }
-
-    subjectSliderChanged(index: number) {
-      this.selectedSubjectIndex = index
-      this.fetchConnectivity()
+  public ngOnChanges(changes: SimpleChanges): void {
+    const { parcellation, types } = changes
+    if (parcellation) {
+      this.parcellation$.next(parcellation.currentValue)
     }
-
-    fetchConnectivity() {
-      const subject = this.selectedCohortSubjects[this.selectedSubjectIndex]
-      const dataset = this.cohortDatasets[this.selectedCohortDatasetIndex]
-
-      this.fetching = true
-      const url = `${this.endpoint}/${dataset.id}?parcellation_id=${this.parcellation.id}&subject=${subject}&type=${this.selectedType.shortName}`
-
-      this.http.get(url).pipe(catchError(() => {
-        this.fetching = false
-        return of(null)
-      })).subscribe(ds => {
-        this.fetching = false
-        this.setMatrixData(ds.matrices[subject])
+    if (types) [
+      this.types$.next(types.currentValue)
+    ]
+  }
+
+  removeCustomLayer() {
+    this.store$.dispatch(
+      atlasAppearance.actions.removeCustomLayer({
+        id: ConnectivityBrowserComponent.LayerId
       })
-    }
-
-    setMatrixData(data) {
-      this.regionIndexInMatrix = data.columns.findIndex(re => this.region.id === re['@id'])
-
-      if (this.regionIndexInMatrix < 0) {
-        this.noConnectivityForRegion = true
-        this.changeDetectionRef.detectChanges()
-        return
-      } else if (this.noConnectivityForRegion) {
-        this.noConnectivityForRegion = false
-      }
-
-      const regionProfile = data.data[this.regionIndexInMatrix]
-
-      const maxStrength = Math.max(...regionProfile)
-
-      this.logChecked = maxStrength > 1
-      this.logDisabled = maxStrength <= 1
-      const areas = regionProfile.reduce((p, c, i) => {
-        return {
-          ...p,
-          [data.columns[i].name]: c
+    )
+  }
+
+  busy$ = new BehaviorSubject<boolean>(false)
+
+  #selectedType$ = this.formValue$.pipe(
+    map(v => v.selectedType),
+    distinctUntilChanged((o, n) => o?.name === n?.name),
+    shareReplay(1),
+  )
+
+  #connFeatures$ = this.parcellation$.pipe(
+    switchMap(parc => concat(
+      of(null as PathParam),
+      this.#selectedType$,
+    ).pipe(
+      switchMap(selectedType => {
+        if (!selectedType || !parc) {
+          return of([] as ConnFeat[])
         }
-      }, {})
 
-      this.pureConnections = areas
-      this.connectionsString = JSON.stringify(areas)
-      this.connectedAreas.next(this.formatConnections(areas))
-
-      this.setCustomLayer()
-      this.matrixString = JSON.stringify(data.columns.map((mc, i) => ([mc.name, ...data.data[i]])))
-      this.changeDetectionRef.detectChanges()
-
-        
-      return data
-    }
-
-
-    changeLog(checked: boolean) {
-      this.logChecked = checked
-      this.connectedAreas.next(this.formatConnections(this.pureConnections))
-      this.connectivityComponentElement.nativeElement.toggleShowLog()
-      this.setCustomLayer()
-    }
+        const typedName = getType(selectedType.name)
+        if (!guardType(typedName)) {
+          throw new Error(`type ${typedName} is not in ${validTypes.join(',')}`)
+        }
+        const query = {
+          parcellation_id: parc.id,
+          type: typedName
+        }
+        this.busy$.next(true)
+        return this.sapi.v3Get(
+          "/feature/RegionalConnectivity",
+          { query }
+        ).pipe(
+          switchMap(resp =>
+            this.sapi.iteratePages(
+              resp,
+              page => this.sapi.v3Get(
+                "/feature/RegionalConnectivity",
+                { query: { ...query, page } }
+              )
+            )
+          ),
+          finalize(() => {
+            this.busy$.next(false)
+          })
+        )
+      })
+    )),
+  )
+
+  cohorts$ = this.#connFeatures$.pipe(
+    map(v => {
+      const cohorts: string[] = []
+      for (const item of v) {
+        if (!cohorts.includes(item.cohort)) {
+          cohorts.push(item.cohort)
+        }
+      }
+      return cohorts
+    })
+  )
+
+  selectedCohort$ = this.formValue$.pipe(
+    map(v => v.selectedCohort),
+    distinctUntilChanged()
+  )
+
+  cohortDatasets$ = combineLatest([
+    this.#connFeatures$,
+    this.formValue$.pipe(
+      map(v => v.selectedCohort),
+      distinctUntilChanged()
+    ),
+  ]).pipe(
+    map(([ features, selectedCohort ]) => features.filter(f => f.cohort === selectedCohort)),
+    distinctUntilChanged(
+      arrayEqual((o, n) => o?.id === n?.id)
+    ),
+    shareReplay(1),
+  )
+
+  selectedDataset$ = this.cohortDatasets$.pipe(
+    switchMap(features => this.formValue$.pipe(
+      map(v => v.selectedDatasetIndex),
+      distinctUntilChanged(),
+      map(dsIdx =>  features[dsIdx]),
+      shareReplay(1),
+    )),
+  )
+  
+  displaySubject$ = this.selectedDataset$.pipe(
+    distinctUntilChanged((o, n) => o?.id === n?.id),
+    map(ds => {
+      return (idx: number) => ds.subjects[idx]
+    })  
+  )
+
+  selectedDatasetAdditionalInfos$ = this.selectedDataset$.pipe(
+    map(ds => ds ? ds.datasets : [])
+  )
+
+  #fetchingMatrix$ = new BehaviorSubject<boolean>(true)
+
+  #matrixInput$ = combineLatest([
+    this.parcellation$,
+    this.formValue$,
+    this.cohortDatasets$,
+  ]).pipe(
+    map(([ parcellation, form, dss ]) => {
+      const {
+        selectedDatasetIndex: dsIdx,
+        selectedSubjectIndex: subIdx
+      } = form
+      const ds = dss[dsIdx]
+      if (!ds) {
+        return null
+      }
 
-    navigateToRegion(regionName: string) {
-        this.sapi.v3Get("/regions/{region_id}", {
-          path: {region_id: regionName},
+      const subject = ds.subjects[subIdx]
+      if (!subject) {
+        return null
+      }
+      return {
+        parcellation,
+        feature_id: ds.id,
+        subject
+      }
+    }),
+    shareReplay(1),
+  )
+
+  #selectedMatrix$ = this.#matrixInput$.pipe(
+    switchMap(input => {
+      if (!input) {
+        return NEVER
+      }
+      const { parcellation, feature_id, subject } = input
+      
+      this.#fetchingMatrix$.next(true)
+      return this.sapi.v3Get(
+        "/feature/RegionalConnectivity/{feature_id}",
+        {
           query: {
-            parcellation_id: this.parcellation.id,
-            space_id: this.template.id
+            parcellation_id: parcellation.id,
+            subject,
+          },
+          path: {
+            feature_id
           }
-        }).pipe(
-          switchMap(r => translateV3Entities.translateRegion(r))
-        ).subscribe(region => {
-          const centroid = region.centroid?.loc
-          if (centroid) {
-            this.store$.dispatch(
-              actions.navigateTo({
-                navigation: {
-                  position: centroid.map(v => v*1e6),
-                },
-                animation: true
-              })
-            )
+        }
+      )
+    }),
+    tap(() => this.#fetchingMatrix$.next(false)),
+    shareReplay(1),
+  )
+
+  #pureConnections$ = this.#matrixInput$.pipe(
+    filter(v => !!v),
+    switchMap(({ subject }) =>
+      this.#selectedMatrix$.pipe(
+        filter(v => !!v.matrices[subject]),
+        withLatestFrom(this.region$),
+        map(([ v, region ]) => {
+          const b = v.matrices[subject]
+          const foundIdx = b.columns.findIndex(v => v['name'] === region.name)
+          if (typeof foundIdx !== 'number') {
+            return null
           }
+          const profile = b.data[foundIdx]
+          if (!profile) {
+            return null
+          }
+          const rObj: Record<string, number> = {}
+          b.columns.reduce((acc, curr, idx) => {
+            const rName = curr['name'] as string
+            acc[rName] = profile[idx] as number
+            return acc
+          }, rObj)
+          return rObj
         })
-    }
-
-    getRegionWithName(region: string) {
-      return this.allRegions.find(r => r.name === region)
-    }
+      ),
+    ),
+  )
+
+  colormap$ = this.#matrixInput$.pipe(
+    switchMap(() => concat(
+      of(null as ConnectedArea[]),
+      combineLatest([
+        this.#pureConnections$,
+        this.displayForm.valueChanges.pipe(
+          map(v => v.logChecked),
+          distinctUntilChanged()
+        )
+      ]).pipe(
+        map(([ conn, flag ]) => processProfile(conn, flag))
+      )
+    ))
+  )
+  
+  view$ = combineLatest([
+    this.selectedDataset$,
+    this.formValue$,
+    this.#fetchingMatrix$,
+    concat(
+      of(null as Record<string, number>),
+      this.#pureConnections$,
+    ),
+    this.region$,
+  ]).pipe(
+    map(([sDs, form, fetchingMatrix, pureConnections, region]) => {
+      return {
+        showSubject: sDs && form.selectedView === "subject",
+        numSubjects: sDs?.subjects.length,
+        fetchingMatrix,
+        connections: pureConnections,
+        region,
+      }
+    }),
+    shareReplay(1),
+  )
+
+  @HostListener('connectedRegionClicked', ['$event'])
+  onRegionClicked(event: CustomEvent) {
+    const regionName = event.detail.name as string
+    this.sapi.v3Get("/regions/{region_id}", {
+      path: {region_id: regionName},
+      query: {
+        parcellation_id: this.parcellation.id,
+        space_id: this.template.id
+      }
+    }).pipe(
+      switchMap(r => translateV3Entities.translateRegion(r))
+    ).subscribe(region => {
+      const centroid = region.centroid?.loc
+      if (centroid) {
+        this.store$.dispatch(
+          actions.navigateTo({
+            navigation: {
+              position: centroid.map(v => v*1e6),
+            },
+            animation: true
+          })
+        )
+      }
+    })
+  }
+
+  exportConnectivityProfile() {
+    const a = document.querySelector('hbp-connectivity-matrix-row');
+    (a as any).downloadCSV()
+  }
+
+  public exportFullConnectivity() {
+    this.fullConnectivityGridElement?.nativeElement['downloadCSV']()
+  }
+
+  public ngOnDestroy(): void {
+    this.removeCustomLayer()
+    this.subscriptions.forEach(s => s.unsubscribe())
+  }
+}
 
-    exportConnectivityProfile() {
-      const a = document.querySelector('hbp-connectivity-matrix-row');
-      (a as any).downloadCSV()
-    }
+function clamp(min: number, max: number) {
+  return function(val: number) {
+    return Math.max(min, Math.min(max, val))
+  }
+}
+const clamp01 = clamp(0, 1)
+function interpolate255(val: number) {
+  return Math.round(clamp01(val) * 255)
+}
+function jet(val: number) {
+  return {
+    r: val < 0.7 
+      ? interpolate255(4 * val - 1.5)
+      : interpolate255(-4.0 * val + 4.5),
+    g: val < 0.5
+      ? interpolate255(4.0 * val - 0.5)
+      : interpolate255(-4.0 * val + 3.5),
+    b: val < 0.3
+      ? interpolate255(4.0 * val + 0.5)
+      : interpolate255(-4.0 * val + 2.5)
+  }
+}
 
-    public exportFullConnectivity() {
-      this.fullConnectivityGridElement?.nativeElement['downloadCSV']()
-    }
+function processProfile(areas: Record<string, number>, logFlag=false): ConnectedArea[] {
+  const returnValue: Omit<ConnectedArea, "color">[] = []
+  for (const areaname in areas) {
+    returnValue.push({
+      name: areaname,
+      numberOfConnections: areas[areaname],
+    })
+  }
+  returnValue.sort((a, b) => b.numberOfConnections - a.numberOfConnections)
+  if (returnValue.length === 0) {
+    return []
+  }
+  const preprocess = (v: number) => logFlag ? Math.log10(v) : v
+  return returnValue.map(v => ({
+    ...v,
+    color: jet(
+      preprocess(v.numberOfConnections) / preprocess(returnValue[0].numberOfConnections)
+    )
+  }))
+}
 
-    public ngOnDestroy(): void {
-      this.removeCustomLayer()
-      this.subscriptions.forEach(s => s.unsubscribe())
-    }
+function getType(name: string) {
+  return name.split(".").slice(-1)[0]
+}
 
-    private formatConnections(areas: { [key: string]: number }) {
-      const cleanedObj = Object.keys(areas)
-        .map(key => ({name: key, numberOfConnections: areas[key]}))
-        .filter(f => f.numberOfConnections > 0)
-        .sort((a, b) => +b.numberOfConnections - +a.numberOfConnections)
-
-      const logMax = this.logChecked ? Math.log(cleanedObj[0].numberOfConnections) : cleanedObj[0].numberOfConnections
-      const colorAreas = []
-
-      cleanedObj.forEach((a) => {
-        colorAreas.push({
-          ...a,
-          color: {
-            r: this.colormap_red((this.logChecked ? Math.log(a.numberOfConnections) : a.numberOfConnections) / logMax ),
-            g: this.colormap_green((this.logChecked ? Math.log(a.numberOfConnections) : a.numberOfConnections) / logMax ),
-            b: this.colormap_blue((this.logChecked ? Math.log(a.numberOfConnections) : a.numberOfConnections) / logMax )
-          },
-        })
-      })
-      return colorAreas
-    }
-    private clamp = val => Math.round(Math.max(0, Math.min(1.0, val)) * 255)
-    private colormap_red = x => x < 0.7? this.clamp(4.0 * x - 1.5) : this.clamp(-4.0 * x + 4.5)
-    private colormap_green = x => x < 0.5? this.clamp(4.0 * x - 0.5) : this.clamp(-4.0 * x + 3.5)
-    private colormap_blue = x => x < 0.3? this.clamp(4.0 * x + 0.5) : this.clamp(-4.0 * x + 2.5)
+const validTypes = ["FunctionalConnectivity", "StreamlineCounts", "StreamlineLengths"]
 
+function guardType(name: unknown): name is "FunctionalConnectivity" | "StreamlineCounts" | "StreamlineLengths" {
+  return typeof name === "string" && validTypes.includes(name)
 }
 
 type ConnectedArea = {
diff --git a/src/features/connectivity/connectivityBrowser/connectivityBrowser.template.html b/src/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
index 87e51584a0f6b4daf50190cf72221eec4ba185d2..a7061fe7a83fedfb63c776e39deb613d1c5008dd 100644
--- a/src/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
+++ b/src/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
@@ -1,104 +1,142 @@
 <div class="w-100 h-100 d-block d-flex flex-column sxplr-pb-2">
-    <div>
-        <div *ngIf="types && types.length"
-            class="flex-grow-0 flex-shrink-0 d-flex flex-row flex-nowrap d-flex flex-column">
-            <mat-form-field class="flex-grow-1 flex-shrink-1 w-100">
-                <mat-label>
-                    Modality
-                </mat-label>
-                <mat-select [value]="selectedType" (selectionChange)="selectType($event.value)">
-                    <mat-option *ngFor="let type of types" [value]="type">
-                        {{ type.shortName }}
-                    </mat-option>
-                </mat-select>
-            </mat-form-field>
+    <form [formGroup]="connectivityFilterForm">
+        
+        <ng-template [ngIf]="types$ | async" let-types>
 
-            <mat-form-field *ngIf="!fetchingPreData && selectedType" class="flex-grow-1 flex-shrink-1 w-100">
-                <mat-label>
-                    Cohort
-                </mat-label>
-                <mat-select [value]="selectedCohort" (selectionChange)="selectCohort($event.value)">
-                    <mat-option *ngFor="let cohort of cohorts" [value]="cohort">
-                        {{ cohort }}
-                    </mat-option>
-                </mat-select>
-            </mat-form-field>
-        </div>
+            <div
+                class="flex-grow-0 flex-shrink-0 d-flex flex-row flex-nowrap d-flex flex-column">
+                <mat-form-field class="flex-grow-1 flex-shrink-1 w-100">
+                    <mat-label>
+                        Modality
+                    </mat-label>
+                    <mat-select formControlName="selectedType">
+                        <mat-option *ngFor="let type of types" [value]="type">
+                            {{ type.display_name }}
+                        </mat-option>
+                    </mat-select>
+                </mat-form-field>
 
-        <mat-radio-group *ngIf="selectedCohort" [(ngModel)]="selectedView">
-            <mat-radio-button value="average" class="m-2" [disabled]="averageDisabled" color="primary">
-                Average
-            </mat-radio-button>
-            <mat-radio-button value="subject" class="m-2" [disabled]="subjectsDisabled" color="primary">
-                Subject
-            </mat-radio-button>
-        </mat-radio-group>
-
-        <div *ngIf="cohortDatasets && cohortDatasets.length > 1"
-            class="flex-grow-0 flex-shrink-0 d-flex flex-nowrap align-items-center">
-            <div class="flex-grow-1 flex-shrink-1 w-100">
-                <mat-label>
-                    Dataset
-                </mat-label>
-                <mat-slider [min]="0" [max]="cohortDatasets.length - 1" (change)="selectedCohortDatasetChanged($event.value)"
-                    [value]="selectedCohortDatasetIndex" thumbLabel step="1" class="w-100">
-                </mat-slider>
+                <mat-form-field *ngIf="!(busy$ | async) && (formValue$ | async | getProperty : 'selectedType')" class="flex-grow-1 flex-shrink-1 w-100">
+                    <mat-label>
+                        Cohort
+                    </mat-label>
+                    <mat-select formControlName="selectedCohort">
+                        <mat-option *ngFor="let cohort of cohorts$ | async"
+                            [value]="cohort">
+                            {{ cohort }}
+                        </mat-option>
+                    </mat-select>
+                </mat-form-field>
             </div>
-        </div>
+        </ng-template>
+
+        <ng-template [ngIf]="formValue$ | async | getProperty : 'selectedCohort'">
+            <mat-radio-group formControlName="selectedView">
+                <mat-radio-button value="average" class="m-2" color="primary">
+                    Average
+                </mat-radio-button>
+                <mat-radio-button value="subject" class="m-2" color="primary">
+                    Subject
+                </mat-radio-button>
+            </mat-radio-group>
+        </ng-template>
+
+        <ng-template [ngIf]="cohortDatasets$ | async" let-cohortDatasets>
+            <ng-template [ngIf]="cohortDatasets.length > 1">
+                <div class="flex-grow-0 flex-shrink-0 d-flex flex-nowrap align-items-center">
+                    <div class="flex-grow-1 flex-shrink-1 w-100">
+                        <mat-label>
+                            Dataset
+                        </mat-label>
+                        <mat-slider [min]="0"
+                            [max]="cohortDatasets.length - 1"
+                            step="1"
+                            formControlName="selectedDatasetIndex"
+                            thumbLabel
+                            class="w-100">
+                        </mat-slider>
+                    </div>
+                </div>
+            </ng-template>
+        </ng-template>
 
-        <div *ngIf="selectedCohortDatasetIndex >= 0 && selectedCohortSubjects"
+        <div *ngIf="view$ | async | getProperty : 'showSubject'"
             class="flex-grow-0 flex-shrink-0 d-flex flex-nowrap align-items-center">
             <div class="flex-grow-1 flex-shrink-1 w-100">
                 <mat-label>
                     Subject
                 </mat-label>
-                <mat-slider [min]="0" [max]="selectedCohortSubjects.length - 1"
-                    (change)="subjectSliderChanged($event.value)" [value]="selectedSubjectIndex"
-                    thumbLabel step="1" class="w-100">
+                <mat-slider [min]="0"
+                    [max]="(view$ | async | getProperty : 'numSubjects') - 1"
+                    thumbLabel
+                    [displayWith]="displaySubject$ | async"
+                    step="1"
+                    formControlName="selectedSubjectIndex"
+                    class="w-100">
                 </mat-slider>
             </div>
         </div>
-    </div>
 
-    <div class="d-flex justify-content-center">
-        <mat-spinner *ngIf="fetching"></mat-spinner>
-    </div>
+    </form>
 
-    <div *ngIf="regionName && !fetching"
-        [style.visibility]="selectedCohort && (selectedSubjectIndex >= 0 || !averageDisabled)? 'visible' : 'hidden'"
-        class="d-flex align-items-center">
-        <mat-checkbox class="mr-2" [checked]="logChecked" (change)="changeLog($event.checked)"
-            [disabled]="logDisabled || noConnectivityForRegion">Log 10</mat-checkbox>
-        <button mat-button [matMenuTriggerFor]="exportMenu" [disabled]="!connectedAreas.value">
-            <i class="fas fa-download mr-2"></i>
-            <span>Export</span>
-        </button>
-        <button *ngIf="selectedDataset" iav-stop="mousedown click" class="icons" mat-icon-button sxplr-dialog
-            [sxplr-dialog-size]="null" [sxplr-dialog-data]="{
-                  title: selectedDataset?.name,
-                  descMd: selectedDataset?.description + '' + (selectedDataset?.authors && selectedDataset?.authors.join()),
-                  actions: [selectedDataset.ebrains_page]
-                }">
-            <i class="fas fa-info"></i>
-        </button>
-    </div>
+    <ng-template [ngIf]="view$ | async | getProperty : 'region'" let-region>
+
+        <!-- loading spinner -->
+        <ng-template [ngIf]="view$ | async | getProperty : 'fetchingMatrix'"
+            [ngIfElse]="profileTmpl">
+            <div class="d-flex justify-content-center" id = 'blabla'>
+                <mat-spinner></mat-spinner>
+            </div>
+        </ng-template>
 
-    <hbp-connectivity-matrix-row #connectivityComponent
-        [style.visibility]="regionName && !fetching && !noConnectivityForRegion && selectedCohort
-                             && (selectedSubjectIndex >= 0 || !averageDisabled)? 'visible' : 'hidden'"
-        [region]="regionName"
-        [connections]="connectionsString"
-        show-export="true" hide-export-view="true" theme="dark">
-    </hbp-connectivity-matrix-row>
-    <div *ngIf="noConnectivityForRegion">No connectivity for the region.</div>
+        <!-- profile -->
+        <!-- <pre>{{ view$ | async | json }}</pre> -->
+        <ng-template #profileTmpl>
+            <ng-template [ngIf]="view$ | async | getProperty : 'connections'" let-conn>
+                <div class="d-flex align-items-center">
+                    <form [formGroup]="displayForm">
+                        <mat-checkbox
+                            class="mr-2"
+                            formControlName="logChecked">
+                            Log 10
+                        </mat-checkbox>
+                    </form>
+                    <button mat-button [matMenuTriggerFor]="exportMenu">
+                        <i class="fas fa-download mr-2"></i>
+                        <span>Export</span>
+                    </button>
+                    <ng-template ngFor [ngForOf]="selectedDatasetAdditionalInfos$ | async" let-info>
+                        <button class="icons"
+                            mat-icon-button
+                            sxplr-dialog
+                            [sxplr-dialog-size]="null"
+                            [sxplr-dialog-data]="{
+                                title: info?.name,
+                                descMd: info?.description,
+                                actions: [info.ebrains_page]
+                            }">
+                            <i class="fas fa-info"></i>
+                        </button>
+                    </ng-template>
+                </div>
+            
+                <hbp-connectivity-matrix-row #connectivityComponent
+                    [region]="region.name"
+                    [connections]="conn | json"
+                    show-export="true"
+                    hide-export-view="true"
+                    theme="dark">
+                </hbp-connectivity-matrix-row>
+            </ng-template>
+        </ng-template>
+    </ng-template>
+</div>
 
-    <full-connectivity-grid #fullConnectivityGrid [matrix]="matrixString" [datasetName]="selectedDataset?.name"
-        [datasetDescription]="selectedDataset?.description" only-export="true">
-    </full-connectivity-grid>
 
-    <mat-menu #exportMenu="matMenu">
-        <button mat-menu-item [disabled]="noConnectivityForRegion"
-            (click)="exportConnectivityProfile()">Regional</button>
-        <button mat-menu-item (click)="exportFullConnectivity()">Dataset</button>
-    </mat-menu>
-</div>
\ No newline at end of file
+<mat-menu #exportMenu="matMenu">
+    <button mat-menu-item
+        (click)="exportConnectivityProfile()">
+        Regional
+    </button>
+    <button mat-menu-item (click)="exportFullConnectivity()">Dataset</button>
+</mat-menu>
diff --git a/src/features/connectivity/module.ts b/src/features/connectivity/module.ts
index 97a7793ff41ee74247aa5de2a506d12763828dea..221ad467e3b1e8b9402ab9d9f2e5a1a8ada90b07 100644
--- a/src/features/connectivity/module.ts
+++ b/src/features/connectivity/module.ts
@@ -1,19 +1,31 @@
 import { CommonModule } from "@angular/common";
 import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from "@angular/core";
 import { SAPI } from "src/atlasComponents/sapi";
-
-import {AngularMaterialModule} from "src/sharedModules";
-import {FormsModule} from "@angular/forms";
-import { DialogModule } from "src/ui/dialogInfo";
-
 import { ConnectivityBrowserComponent } from "./connectivityBrowser/connectivityBrowser.component";
+import { ReactiveFormsModule } from "@angular/forms";
+import { DialogModule } from "src/ui/dialogInfo";
+import { MatSelectModule } from "@angular/material/select";
+import { MatRadioModule } from "@angular/material/radio";
+import { MatSliderModule } from "@angular/material/slider";
+import { MatMenuModule } from "@angular/material/menu";
+import { UtilModule } from "src/util";
+import { MatCheckboxModule } from "@angular/material/checkbox";
+import { MatButtonModule } from "@angular/material/button";
+import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
 
 @NgModule({
   imports: [
     CommonModule,
-    FormsModule,
-    AngularMaterialModule,
-    DialogModule
+    ReactiveFormsModule,
+    MatSelectModule,
+    MatRadioModule,
+    MatSliderModule,
+    MatMenuModule,
+    DialogModule,
+    UtilModule,
+    MatCheckboxModule,
+    MatButtonModule,
+    MatProgressSpinnerModule,
   ],
   declarations: [
     ConnectivityBrowserComponent,
diff --git a/src/features/feature-view/feature-view.component.ts b/src/features/feature-view/feature-view.component.ts
index 400644f14c73fe60a0292c13ceb41916b96280c4..3d9f1cdc9e68f8804c728a71f1a378db5a259331 100644
--- a/src/features/feature-view/feature-view.component.ts
+++ b/src/features/feature-view/feature-view.component.ts
@@ -43,7 +43,7 @@ export class FeatureViewComponent implements OnChanges {
   voi$ = new BehaviorSubject<VoiFeature>(null)
   columns$: Observable<string[]> = this.tabular$.pipe(
     map(data => data
-      ? ['index', ...data.columns]
+      ? ['index', ...data.columns] as string[]
       : []),
   )
 
@@ -52,7 +52,7 @@ export class FeatureViewComponent implements OnChanges {
     map(v => {
       return v.index.map((receptor, idx) => ({
         receptor: {
-          label: receptor
+          label: receptor as string
         },
         density: {
           mean: v.data[idx][0] as number,
diff --git a/src/features/filterCategories.pipe.ts b/src/features/filterCategories.pipe.ts
index 8f103328732218fd6a28717eedfc6eaf87baaa30..8521c7454e6589e123e6aaa92efd77bdbdadb704 100644
--- a/src/features/filterCategories.pipe.ts
+++ b/src/features/filterCategories.pipe.ts
@@ -2,7 +2,7 @@ import { KeyValue } from "@angular/common"
 import { Pipe, PipeTransform } from "@angular/core"
 import { PathReturn } from "src/atlasComponents/sapi/typeV3"
 
-type DS = KeyValue<string, PathReturn<"/feature/_types">["items"]>
+export type DS = KeyValue<string, PathReturn<"/feature/_types">["items"]>
 
 @Pipe({
   name: 'filterCategory',
diff --git a/src/features/transform-pd-to-ds.pipe.ts b/src/features/transform-pd-to-ds.pipe.ts
index 09f598d9d6ceea05a41c7599d5ea90a45b32b5b0..c0cc94e292ffa751b4f0d979e58d05ade128ce3e 100644
--- a/src/features/transform-pd-to-ds.pipe.ts
+++ b/src/features/transform-pd-to-ds.pipe.ts
@@ -2,6 +2,14 @@ import { CdkTableDataSourceInput } from '@angular/cdk/table';
 import { Pipe, PipeTransform } from '@angular/core';
 import { TabularFeature } from 'src/atlasComponents/sapi/sxplrTypes';
 
+function typeGuard(input: unknown): input is string | number | number[]{
+  return typeof input === "string" || typeof input === "number" || (Array.isArray(input) && input.every(v => typeof v === "number"))
+}
+
+function isString(input: unknown): input is string {
+  return typeof input === "string"
+}
+
 @Pipe({
   name: 'transformPdToDs',
   pure: true
@@ -10,11 +18,19 @@ export class TransformPdToDsPipe implements PipeTransform {
 
   transform(pd: TabularFeature<string|number|number[]>): CdkTableDataSourceInput<unknown> {
     return pd.data.map((arr, idx) => {
+      const val = pd.index[idx]
+      if (!typeGuard(val)) {
+        throw new Error(`Expected val to be of type string, number or number[], but was none.`)
+      }
       const returnVal: Record<string, string|number|number[]> = {
-        index: pd.index[idx],
+        index: val,
       }
       arr.forEach((val, colIdx) => {
-        returnVal[pd.columns[colIdx]] = val
+        const key = pd.columns[colIdx]
+        if (!isString(key)) {
+          throw new Error(`Expected key to be of type string,  number or number[], but was not`)
+        }
+        returnVal[key] = val
       })
       return returnVal
     })
diff --git a/src/index.html b/src/index.html
index 8b04e68c01a64a496496ff53735756fd2166b36d..0f009f4f2d5ab33219754015cfc136a5c8758899 100644
--- a/src/index.html
+++ b/src/index.html
@@ -15,7 +15,7 @@
   <script src="https://unpkg.com/kg-dataset-previewer@1.2.0/dist/kg-dataset-previewer/kg-dataset-previewer.js" defer></script>
   <script src="https://unpkg.com/three-surfer@0.0.13/dist/bundle.js" defer></script>
   <script type="module" src="https://unpkg.com/ng-layer-tune@0.0.6/dist/ng-layer-tune/ng-layer-tune.esm.js"></script>
-  <script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.5/dist/connectivity-component/connectivity-component.js" ></script>
+  <script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.6/dist/connectivity-component/connectivity-component.js" ></script>
   <script defer src="https://unpkg.com/mathjax@3.1.2/es5/tex-svg.js"></script>
   <script defer src="https://unpkg.com/d3@6.2.0/dist/d3.min.js"></script>
   <title>Siibra Explorer</title>
diff --git a/src/routerModule/routeStateTransform.service.ts b/src/routerModule/routeStateTransform.service.ts
index bbc9c3ab99f3cb27af71e07c49ceb4aa3ca225b4..1032448ec67ea1c9bf80d3f18f82f901bf7c6057 100644
--- a/src/routerModule/routeStateTransform.service.ts
+++ b/src/routerModule/routeStateTransform.service.ts
@@ -77,7 +77,6 @@ export class RouteStateTransformSvc {
       }
       
       const regionMap = new Map<string, SxplrRegion>(allParcellationRegions.map(region => [region.name, region]))
-      const ngIdToRegionMap: Map<string, Map<number, SxplrRegion[]>> = new Map()
 
       const [ ngMap, threeMap ] = await Promise.all([
         this.sapi.getTranslatedLabelledNgMap(selectedParcellation, selectedTemplate),
diff --git a/src/state/annotations/selectors.ts b/src/state/annotations/selectors.ts
index 5504a6bb1fb7ab03a4053a365c24d55290a50036..9de6923bec414ecf52d1f1d1d5cf8b374b4348ca 100644
--- a/src/state/annotations/selectors.ts
+++ b/src/state/annotations/selectors.ts
@@ -14,7 +14,7 @@ export const spaceFilteredAnnotations = createSelector(
   selectStore,
   atlasSelectionSelectors.selectStore,
   (annState, atlasSelState) => annState.annotations.filter(ann => {
-    const spaceId = atlasSelState.selectedTemplate['@id']
+    const spaceId = atlasSelState.selectedTemplate.id
     if (ann['openminds']) {
       return (ann as Annotation<'openminds'>).openminds.coordinateSpace['@id'] === spaceId
     }
diff --git a/src/state/atlasSelection/effects.spec.ts b/src/state/atlasSelection/effects.spec.ts
index a1a820f677b1449d1ce4a3ebaa1a5d44e2e89c51..603c1c4ec5b13f3dea3c66ad13e8002dfedd2823 100644
--- a/src/state/atlasSelection/effects.spec.ts
+++ b/src/state/atlasSelection/effects.spec.ts
@@ -12,14 +12,67 @@ import { Effect } from "./effects"
 import * as mainActions from "../actions"
 import { atlasSelection } from ".."
 import { BrowserAnimationsModule } from "@angular/platform-browser/animations"
+import { translateV3Entities } from "src/atlasComponents/sapi/translateV3"
+import { PathReturn } from "src/atlasComponents/sapi/typeV3"
 
 describe("> effects.ts", () => {
   describe("> Effect", () => {
 
     let actions$ = new Observable<Action>()
-    let hoc1left: SxplrRegion
-    let hoc1leftCentroid: SxplrRegion
-    let hoc1leftCentroidWrongSpc: SxplrRegion
+
+    let simpleHoc1: SxplrRegion = {
+      name: 'foo',
+      id: '',
+      type: "SxplrRegion",
+      parentIds: [],
+    }
+
+    let hoc1LeftMni152: PathReturn<"/regions/{region_id}"> = {
+      "@id": "",
+      versionIdentifier: '',
+      "@type": '',
+      hasAnnotation: {
+        criteriaQualityType: {},
+        internalIdentifier: "",
+        bestViewPoint: {
+          coordinateSpace: {
+            "@id": IDS.TEMPLATES.MNI152
+          } as any,
+          coordinates: [
+            {
+              value: 1,
+            },{
+              value: 2,
+            },{
+              value: 3,
+            }
+          ]
+        }
+      }
+    }
+    let hoc1LeftColin27: PathReturn<"/regions/{region_id}"> = {
+      "@id": "",
+      versionIdentifier: '',
+      "@type": '',
+      hasAnnotation: {
+        criteriaQualityType: {},
+        internalIdentifier: "",
+        bestViewPoint: {
+          coordinateSpace: {
+            "@id": IDS.TEMPLATES.COLIN27
+          } as any,
+          coordinates: [
+            {
+              value: 1,
+            },{
+              value: 2,
+            },{
+              value: 3,
+            }
+          ]
+        }
+      }
+    }
 
     beforeEach(async () => {
       TestBed.configureTestingModule({
@@ -34,26 +87,6 @@ describe("> effects.ts", () => {
           provideMockActions(() => actions$)
         ]
       })
-
-      /**
-       * only need to populate hoc1 left once
-       */
-      if (!hoc1left) {
-
-        const sapisvc = TestBed.inject(SAPI)
-        const regions = await sapisvc.getParcRegions(IDS.PARCELLATION.JBA29).toPromise()
-        hoc1left = regions.find(r => /hoc1/i.test(r.name) && /left/i.test(r.name))
-        if (!hoc1left) throw new Error(`cannot find hoc1 left`)
-        hoc1leftCentroid = JSON.parse(JSON.stringify(hoc1left)) 
-        hoc1leftCentroid.centroid = {
-          space: {
-            id: IDS.TEMPLATES.BIG_BRAIN
-          } as SxplrTemplate,
-          loc: [1, 2, 3]
-        }
-        hoc1leftCentroidWrongSpc = JSON.parse(JSON.stringify(hoc1leftCentroid))
-        hoc1leftCentroidWrongSpc.centroid.space.id = IDS.TEMPLATES.COLIN27
-      }
     })
 
     it('> can be init', () => {
@@ -229,10 +262,39 @@ describe("> effects.ts", () => {
     })
 
     describe('> onNavigateToRegion', () => {
+
+      const translatedRegion = {
+        "@id": "",
+        versionIdentifier: '',
+        "@type": '',
+        hasAnnotation: {
+          criteriaQualityType: {},
+          internalIdentifier: "",
+          bestViewPoint: {
+            coordinateSpace: {
+              "@id": IDS.TEMPLATES.MNI152
+            } as any,
+            coordinates: [
+              {
+                value: 1,
+              },{
+                value: 2,
+              },{
+                value: 3,
+              }
+            ]
+          }
+        }
+      } as PathReturn<"/regions/{region_id}">
+
+      let retrieveRegionSpy: jasmine.Spy
+
       beforeEach(async () => {
+        retrieveRegionSpy = spyOn(translateV3Entities, 'retrieveRegion')
+        
         actions$ = hot('a', {
           a: actions.navigateToRegion({
-            region: hoc1left
+            region: simpleHoc1
           })
         })
         const mockStore = TestBed.inject(MockStore)
@@ -264,6 +326,7 @@ describe("> effects.ts", () => {
             beforeEach(() => {
               const mockStore = TestBed.inject(MockStore)
               mockStore.overrideSelector(atpSelector, null)
+              retrieveRegionSpy.and.
             })
 
             it('> returns general error', () => {
@@ -302,16 +365,7 @@ describe("> effects.ts", () => {
       })
 
       describe('> if inputs are fine', () => {
-        let regionGetDetailSpy: jasmine.Spy = jasmine.createSpy()
-        beforeEach(() => {
-          const sapi = TestBed.inject(SAPI)
-          regionGetDetailSpy.and.returnValue(
-            of(hoc1leftCentroid)
-          )
-        })
-        afterEach(() => {
-          if (regionGetDetailSpy) regionGetDetailSpy.calls.reset()
-        })
+
         it('> getRegionDetailSpy is called, and calls navigateTo', () => {
           const eff = TestBed.inject(Effect)
           expect(eff.onNavigateToRegion).toBeObservable(
@@ -330,9 +384,6 @@ describe("> effects.ts", () => {
           describe('> returns null', () => {
             beforeEach(() => {
 
-              regionGetDetailSpy.and.returnValue(
-                of(null)
-              )
             })
             it('> generalactionerror', () => {
 
@@ -348,9 +399,7 @@ describe("> effects.ts", () => {
           })
           describe('> general throw', () => {
             beforeEach(() => {
-              regionGetDetailSpy.and.returnValue(
-                throwError(`oh noes`)
-              )
+
             })
             it('> generalactionerror', () => {
 
@@ -358,7 +407,7 @@ describe("> effects.ts", () => {
               expect(eff.onNavigateToRegion).toBeObservable(
                 hot(`a`, {
                   a: mainActions.generalActionError({
-                    message: `Error getting region centroid`
+                    message: `getting region detail error! cannot get coordinates`
                   })
                 })
               )
@@ -368,9 +417,7 @@ describe("> effects.ts", () => {
           describe('> does not contain props attr', () => {
 
             beforeEach(() => {
-              regionGetDetailSpy.and.returnValue(
-                of(hoc1left)
-              )
+              
             })
             it('> generalactionerror', () => {
 
diff --git a/src/state/atlasSelection/effects.ts b/src/state/atlasSelection/effects.ts
index 673a54d0fdfc6fefa2fce02bf5571bb6ee2492d8..601ea9f8edddebcb88ffab46159b4dfd5f660e2b 100644
--- a/src/state/atlasSelection/effects.ts
+++ b/src/state/atlasSelection/effects.ts
@@ -1,7 +1,7 @@
 import { Injectable } from "@angular/core";
 import { Actions, createEffect, ofType } from "@ngrx/effects";
 import { forkJoin, merge, NEVER, Observable, of } from "rxjs";
-import { filter, map, mapTo, switchMap, switchMapTo, take, withLatestFrom } from "rxjs/operators";
+import { catchError, filter, map, mapTo, switchMap, switchMapTo, take, withLatestFrom } from "rxjs/operators";
 import { SAPI, SAPIRegion } from "src/atlasComponents/sapi";
 import * as mainActions from "../actions"
 import { select, Store } from "@ngrx/store";
@@ -346,27 +346,35 @@ export class Effect {
         select(selectors.selectedParcellation)
       )
     ),
-    map(([{ region: _region }, selectedTemplate, selectedAtlas, selectedParcellation]) => {
+    switchMap(([{ region: _region }, selectedTemplate, selectedAtlas, selectedParcellation]) => {
       if (!selectedAtlas || !selectedTemplate || !selectedParcellation || !_region)  {
-        return mainActions.generalActionError({
-          message: `atlas, template, parcellation or region not set`
-        })
+        return of(
+          mainActions.generalActionError({
+            message: `atlas, template, parcellation or region not set`
+          })
+        )
       }
-
-      const region = translateV3Entities.retrieveRegion(_region)
-
-      if (region.hasAnnotation?.bestViewPoint && region.hasAnnotation.bestViewPoint.coordinateSpace['@id'] === selectedTemplate["@id"]) {
-        return actions.navigateTo({
+      return this.sapiSvc.v3Get("/regions/{region_id}", {
+        path: {
+          region_id: _region.name
+        },
+        query: {
+          parcellation_id: selectedParcellation.id,
+          space_id: selectedTemplate.id
+        }
+      }).pipe(
+        map(reg => actions.navigateTo({
           animation: true,
           navigation: {
-            position: region.hasAnnotation.bestViewPoint.coordinates.map(v => v.value * 1e6)
+            position: reg.hasAnnotation.bestViewPoint.coordinates.map(v => v.value * 1e6)
           }
-        })
-      }
-      
-      return mainActions.generalActionError({
-        message: `getting region detail error! cannot get coordinates`
-      })
+        })),
+        catchError(() => of(
+          mainActions.generalActionError({
+            message: `getting region detail error! cannot get coordinates`
+          })
+        )),
+      )
     })
   ))
 
diff --git a/src/viewerModule/nehuba/config.service/util.ts b/src/viewerModule/nehuba/config.service/util.ts
index fa76f139af7aed4ffb7b21b97e87f7c39caf4633..ddc82c6482332f12aeb7adef4013e51bb442217f 100644
--- a/src/viewerModule/nehuba/config.service/util.ts
+++ b/src/viewerModule/nehuba/config.service/util.ts
@@ -174,7 +174,7 @@ export function getParcNgId(atlas: SxplrAtlas, tmpl: SxplrTemplate, parc: SxplrP
       : null
   }
 
-  if (parc.id === IDS.PARCELLATION.JBA30) {
+  if (parc.id === IDS.PARCELLATION.JBA30 && tmpl.id !== IDS.TEMPLATES.FSAVERAGE) {
     return `_${MultiDimMap.GetKey(atlas.id, tmpl.id, parc.id, "whole brain")}`
   }
 
diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts
index 45a5aee2d56784a90c6d75c72d4d1b0e3ab2cd83..e29f976cfbf97399cc3592d480fbd49841cd8081 100644
--- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts
+++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts
@@ -10,12 +10,17 @@ import {
 import { LayerCtrlEffects } from "./layerCtrl.effects"
 import { NEVER } from "rxjs"
 import { RouterService } from "src/routerModule/router.service"
+import { HttpClientModule } from "@angular/common/http"
+import { BaseService } from "../base.service/base.service"
 
 describe('> layerctrl.service.ts', () => {
   describe('> NehubaLayerControlService', () => {
     let mockStore: MockStore
     beforeEach(() => {
       TestBed.configureTestingModule({
+        imports:[
+          HttpClientModule,
+        ],
         providers: [
           {
             provide: RouterService,
@@ -30,6 +35,13 @@ describe('> layerctrl.service.ts', () => {
             useValue: {
               onATPDebounceNgLayers$: NEVER
             }
+          },
+          {
+            provide: BaseService,
+            useValue: {
+              selectedATPR$: NEVER,
+              completeNgIdLabelRegionMap$: NEVER,
+            }
           }
         ]
       })
diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
index 971f599b69ece635aab52fc9290c3ae4b954703d..f68170be4a59e2610000d997b852084512529dc4 100644
--- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
+++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
@@ -32,8 +32,6 @@ export class NehubaLayerControlService implements OnDestroy{
 
   private defaultNgLayers$ = this.layerEffects.onATPDebounceNgLayers$
 
-  private selectedATP$ = this.baseService.selectedATP$
-
   public selectedATPR$ = this.baseService.selectedATPR$
 
   private customLayers$ = this.store$.pipe(
diff --git a/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts b/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts
index 0b7d702369e87a97b70b8bfa1057a83e274d08f1..1cc0bdc7fb1d52813ff0ea1fa58a6ff9bdfadbf0 100644
--- a/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts
+++ b/src/viewerModule/nehuba/mesh.service/mesh.service.spec.ts
@@ -9,6 +9,8 @@ import { LayerCtrlEffects } from "../layerCtrl.service/layerCtrl.effects"
 import { NEVER, of, pipe } from "rxjs"
 import { mapTo, take } from "rxjs/operators"
 import { selectorAuxMeshes } from "../store"
+import { HttpClientModule } from "@angular/common/http"
+import { BaseService } from "../base.service/base.service"
 
 
 const fits1 = {} as SxplrRegion
@@ -59,6 +61,9 @@ describe('> mesh.service.ts', () => {
   describe('> NehubaMeshService', () => {
     beforeEach(() => {
       TestBed.configureTestingModule({
+        imports: [
+          HttpClientModule,
+        ],
         providers: [
           provideMockStore(),
           NehubaMeshService,
@@ -67,6 +72,12 @@ describe('> mesh.service.ts', () => {
             useValue: {
               onATPDebounceNgLayers$: NEVER
             }
+          },
+          {
+            provide: BaseService,
+            useValue: {
+              completeNgIdLabelRegionMap$: NEVER
+            }
           }
         ]
       })
@@ -151,11 +162,18 @@ describe('> mesh.service.ts', () => {
          * in the case of julich brain 2.9 in colin 27, we expect selecting a region will hide meshes from all relevant ngIds (both left and right)
          */
         it('> expect the emitted value to be incl all ngIds', () => {
+          const bService = TestBed.inject(BaseService)
+          bService.completeNgIdLabelRegionMap$ = of({
+            [ngId1]: {},
+            [ngId2]: {
+              [labelIndex2]: fits1
+            }
+          })
           const service = TestBed.inject(NehubaMeshService)
           expect(
             service.loadMeshes$
           ).toBeObservable(
-            hot('(ab)', {
+            hot('abc', {
               a: {
                 layer: {
                   name: ngId1
@@ -167,6 +185,12 @@ describe('> mesh.service.ts', () => {
                   name: ngId2
                 },
                 labelIndicies: [ labelIndex2 ]
+              },
+              c: {
+                layer: {
+                  name: auxMesh.ngId
+                },
+                labelIndicies: auxMesh.labelIndicies
               }
             })
           )
diff --git a/src/viewerModule/nehuba/store/store.ts b/src/viewerModule/nehuba/store/store.ts
index 0dd7043f3ac0da58ad43d7211fcce3983d6b85d2..33f4275ebab27bc960ced88c92265794d494f4dc 100644
--- a/src/viewerModule/nehuba/store/store.ts
+++ b/src/viewerModule/nehuba/store/store.ts
@@ -20,7 +20,6 @@ const defaultState: INehubaFeature = {
   panelMode: EnumPanelMode.FOUR_PANEL,
   panelOrder: '0123',
   octantRemoval: true,
-  clearViewQueue: {},
   auxMeshes: []
 }
 
diff --git a/src/viewerModule/nehuba/store/type.ts b/src/viewerModule/nehuba/store/type.ts
index a55be8ced700fb825deb317904573577a0c8c7fb..7908af13aaee35fdd228773f51bc50739a9fba49 100644
--- a/src/viewerModule/nehuba/store/type.ts
+++ b/src/viewerModule/nehuba/store/type.ts
@@ -16,8 +16,5 @@ export interface INehubaFeature {
   panelMode: string
   panelOrder: string
   octantRemoval: boolean
-  clearViewQueue: {
-    [key: string]: boolean
-  }
   auxMeshes: IAuxMesh[]
 }
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
index 7d6634342b3daf28b948e97a7d6fcca9d6b9310f..e4e729b1cfcf6817d00afd57681e2bbc9c817e9c 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
@@ -1,13 +1,13 @@
 import { Component, Output, EventEmitter, ElementRef, OnDestroy, AfterViewInit, Inject, Optional, ChangeDetectionStrategy } from "@angular/core";
 import { EnumViewerEvt, IViewer, TViewerEvent } from "src/viewerModule/viewer.interface";
-import { combineLatest, from, merge, NEVER, Observable, Subject } from "rxjs";
-import { catchError, debounceTime, distinctUntilChanged, filter, map, scan, shareReplay, switchMap } from "rxjs/operators";
+import { combineLatest, concat, forkJoin, from, merge, NEVER, Observable, of, Subject } from "rxjs";
+import { catchError, debounceTime, distinctUntilChanged, filter, map, scan, shareReplay, switchMap, withLatestFrom } from "rxjs/operators";
 import { ComponentStore } from "src/viewerModule/componentStore";
 import { select, Store } from "@ngrx/store";
 import { ClickInterceptor, CLICK_INTERCEPTOR_INJECTOR } from "src/util";
 import { MatSnackBar } from "@angular/material/snack-bar";
 import { CONST } from 'common/constants'
-import { getUuid } from "src/util/fn";
+import { getUuid, switchMapWaitFor } from "src/util/fn";
 import { AUTO_ROTATE, TInteralStatePayload, ViewerInternalStateSvc } from "src/viewerModule/viewerInternalState.service";
 import { atlasAppearance, atlasSelection } from "src/state";
 import { ThreeSurferCustomLabelLayer, ThreeSurferCustomLayer, ColorMapCustomLayer } from "src/state/atlasAppearance/const";
@@ -38,6 +38,48 @@ type THandlingCustomEv = {
   }
 }
 
+type TLatVtxIdxRecord = LateralityRecord<{
+  indexLayer: ThreeSurferCustomLabelLayer
+  vertexIndices: number[]
+}>
+
+type TLatMeshRecord = LateralityRecord<{
+  meshLayer: ThreeSurferCustomLayer
+  mesh: TThreeGeometry
+}>
+
+type MeshVisOp = 'toggle' | 'noop'
+
+type TApplyColorArg = LateralityRecord<{
+  labelIndices: number[]
+  idxReg: Record<number, SxplrRegion>
+  isBaseCm: boolean
+  showDelin: boolean
+  selectedRegions: SxplrRegion[]
+  mesh: TThreeGeometry
+  vertexIndices: number[]
+  map?: Map<number, number[]>
+}>
+
+type THandleCustomMouseEv = {
+  latMeshRecord: TLatMeshRecord
+  latLblIdxRecord: TLatVtxIdxRecord
+  evDetail: any
+  latLblIdxReg: TLatIdxReg
+  meshVisibility: {
+    label: string
+    visible: boolean
+    mesh: TThreeGeometry
+  }[]
+}
+
+type TLatIdxReg = LateralityRecord<Record<number, SxplrRegion>>
+
+type TLatCm = LateralityRecord<{
+  labelIndices: number[]
+  map: Map<number, number[]>
+}>
+
 type TCameraOrientation = {
   perspectiveOrientation: number[]
   perspectiveZoom: number
@@ -92,6 +134,8 @@ function cameraNavsAreSimilar(c1: TCameraOrientation, c2: TCameraOrientation){
 
 export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit, OnDestroy {
 
+  #cameraEv$ = new Subject<{ position: { x: number, y: number, z: number }, zoom: number }>()
+  #mouseEv$ = new Subject()
   
   @Output()
   viewerEvent = new EventEmitter<TViewerEvent<'threeSurfer'>>()
@@ -100,44 +144,106 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
   private mainStoreCameraNav: TCameraOrientation = null
   private localCameraNav: TCameraOrientation = null
 
-  public lateralityMeshRecord: LateralityRecord<{
-    visible: boolean
-    meshLayer: ThreeSurferCustomLayer
-    mesh: TThreeGeometry
-  }> = {}
 
-  public latLblIdxRecord: LateralityRecord<{
-    indexLayer: ThreeSurferCustomLabelLayer
-    labelIndices: number[]
-  }> = {}
   private internalStateNext: (arg: TInteralStatePayload<TInternalState>) => void
 
   private mouseoverRegions: SxplrRegion[] = []
-  
-  private selectedRegions$ = this.store$.pipe(
-    select(atlasSelection.selectors.selectedRegions)
-  )
 
   private customLayers$ = this.store$.pipe(
     select(atlasAppearance.selectors.customLayers),
     distinctUntilChanged(arrayEqual((o, n) => o.id === n.id)),
     shareReplay(1)
   )
-  public meshLayers$: Observable<ThreeSurferCustomLayer[]> = this.customLayers$.pipe(
+  #meshLayers$: Observable<ThreeSurferCustomLayer[]> = this.customLayers$.pipe(
     map(layers => layers.filter(l => l.clType === "baselayer/threesurfer") as ThreeSurferCustomLayer[]),
     distinctUntilChanged(arrayEqual((o, n) => o.id === n.id)),
   )
 
+  #lateralMeshRecord$ = new Subject<TLatMeshRecord>()
+  lateralMeshRecord$ = concat(
+    of({} as TLatMeshRecord),
+    this.#lateralMeshRecord$.asObservable()
+  )
+
+  #meshVisOp$ = new Subject<{ op: MeshVisOp, label?: string }>()
+  meshVisible$ = this.lateralMeshRecord$.pipe(
+    map(v => {
+      const returnVal: {
+        label: string
+        visible: boolean
+        mesh: TThreeGeometry
+      }[] = []
+      for (const lat in v) {
+        returnVal.push({
+          visible: true,
+          mesh: v[lat].mesh,
+          label: lat
+        })
+      }
+      return returnVal
+    }),
+    switchMap(arr => concat(
+      of({ op: 'noop', label: null }),
+      this.#meshVisOp$
+    ).pipe(
+      map(({ op, label }) => arr.map(v => {
+        if (label !== v.label) {
+          return v
+        }
+        if (op === "toggle") {
+          v.visible = !v.visible
+        }
+        return v
+      }))
+    ))
+  )
+
   private vertexIndexLayers$: Observable<ThreeSurferCustomLabelLayer[]> = this.customLayers$.pipe(
     map(layers => layers.filter(l => l.clType === "baselayer/threesurfer-label") as ThreeSurferCustomLabelLayer[]),
     distinctUntilChanged(arrayEqual((o, n) => o.id === n.id)),
   )
 
+  #latVtxIdxRecord$: Observable<TLatVtxIdxRecord> = this.vertexIndexLayers$.pipe(
+    switchMap(
+      switchMapWaitFor({
+        condition: () => !!this.tsRef,
+        leading: true
+      })
+    ),
+    switchMap(layers => 
+      forkJoin(
+        layers.map(layer => 
+          from(
+            this.tsRef.loadColormap(layer.source)
+          ).pipe(
+            map(giiInstance => {
+              let vertexIndices: number[] = giiInstance[0].getData()
+              if (giiInstance[0].attributes.DataType === 'NIFTI_TYPE_INT16') {
+                vertexIndices = (window as any).ThreeSurfer.GiftiBase.castF32UInt16(vertexIndices)
+              }
+              return {
+                indexLayer: layer,
+                vertexIndices
+              }
+            })
+          )
+        )
+      )
+    ),
+    map(layers => {
+      const returnObj = {}
+      for (const { indexLayer, vertexIndices } of layers) {
+        returnObj[indexLayer.laterality] = { indexLayer, vertexIndices }
+      }
+      return returnObj
+    })
+  )
+
   /**
    * maps laterality to label index to sapi region
    */
-  private latLblIdxToRegionRecord: LateralityRecord<Record<number, SxplrRegion>> = {}
-  private latLblIdxToRegionRecord$: Observable<LateralityRecord<Record<number, SxplrRegion>>> = combineLatest([
+  
+  #latLblIdxToRegionRecord$: Observable<TLatIdxReg> = combineLatest([
     this.store$.pipe(
       atlasSelection.fromRootStore.distinctATP()
     ),
@@ -183,15 +289,43 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
    * colormap in use (both base & custom)
    */
 
-  private colormapInUse: ColorMapCustomLayer
-  private colormaps$: Observable<ColorMapCustomLayer[]> = this.customLayers$.pipe(
+  #colormaps$: Observable<ColorMapCustomLayer[]> = this.customLayers$.pipe(
     map(layers => layers.filter(l => l.clType === "baselayer/colormap" || l.clType === "customlayer/colormap") as ColorMapCustomLayer[]),
+    distinctUntilChanged(arrayEqual((o, n) => o.id === n.id))
+  )
+
+  #latLblIdxToCm$ = combineLatest([
+    this.#latLblIdxToRegionRecord$,
+    this.#colormaps$
+  ]).pipe(
+    map(([ latIdxReg, cms ]) => {
+      const cm = cms[0]
+      const returnValue: TLatCm = {}
+      for (const lat in latIdxReg) {
+        returnValue[lat] = {
+          labelIndices: [],
+          map: new Map()
+        }
+        for (const lblIdx in latIdxReg[lat]) {
+          returnValue[lat].labelIndices.push(Number(lblIdx))
+          const reg = latIdxReg[lat][lblIdx]
+          returnValue[lat].map.set(
+            Number(lblIdx), (cm.colormap.get(reg) || [255, 255, 255]).map(v => v/255)
+          )
+        }
+      }
+      return returnValue
+    })
   )
 
   /**
-   * show delination map
+   * when do we need to call apply color?
+   * - when mesh loads
+   * - when vertex index layer changes
+   * - selected region changes
+   * - custom color map added (by plugin, etc)
+   * - show delineation updates
    */
-  private showDelineation: boolean = true
 
   public threeSurferSurfaceVariants$ = this.effect.onATPDebounceThreeSurferLayers$.pipe(
     map(({ surfaces }) => surfaces.reduce((acc, val) => acc.includes(val.variant) ? acc : [...acc, val.variant] ,[] as string[]))
@@ -275,7 +409,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
     /**
      * subscribe to camera custom event
      */
-    const cameraSub = this.cameraEv$.pipe(
+    const cameraSub = this.#cameraEv$.pipe(
       filter(v => !!v),
       debounceTime(160)
     ).subscribe(() => {
@@ -378,7 +512,6 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
   }
 
   private tsRef: TThreeSurfer
-  private selectedRegions: SxplrRegion[] = []
 
   private relayStoreLock: () => void = null
   private tsRefInitCb: ((tsRef: any) => void)[] = []
@@ -390,47 +523,67 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
     this.tsRefInitCb.push(callback)
   }
 
-  private async loadMeshes(layers: ThreeSurferCustomLayer[]) {
+  async #loadMeshes(layers: ThreeSurferCustomLayer[], currMeshRecord: TLatMeshRecord) {
     if (!this.tsRef) throw new Error(`loadMeshes error: this.tsRef is not defined!!`)
-
+    const copiedCurrMeshRecord: TLatMeshRecord = {...currMeshRecord}
     /**
      * remove the layers... 
      */
     for (const layer of layers) {
-      if (!!this.lateralityMeshRecord[layer.laterality]) {
-        this.tsRef.unloadMesh(this.lateralityMeshRecord[layer.laterality].mesh)
+      if (!!copiedCurrMeshRecord[layer.laterality]) {
+        this.tsRef.unloadMesh(copiedCurrMeshRecord[layer.laterality].mesh)
       }
     }
 
     for (const layer of layers) {
       const threeMesh = await this.tsRef.loadMesh(layer.source)
-      this.lateralityMeshRecord[layer.laterality] = {
-        visible: true,
+      copiedCurrMeshRecord[layer.laterality] = {
         meshLayer: layer,
         mesh: threeMesh
       }
     }
-    this.applyColor()
+    this.#lateralMeshRecord$.next(copiedCurrMeshRecord)
   }
 
-  private async loadVertexIndexMap(layers: ThreeSurferCustomLabelLayer[]) {
-    if (!this.tsRef) throw new Error(`loadVertexIndexMap error: this.tsRef is not defined!!`)
-    for (const layer of layers) {
-      const giiInstance = await this.tsRef.loadColormap(layer.source)
-
-      let labelIndices: number[] = giiInstance[0].getData()
-      if (giiInstance[0].attributes.DataType === 'NIFTI_TYPE_INT16') {
-        labelIndices = (window as any).ThreeSurfer.GiftiBase.castF32UInt16(labelIndices)
-      }
-      this.latLblIdxRecord[layer.laterality] = {
-        indexLayer: layer,
-        labelIndices
+  #applyColor$ = combineLatest([
+    combineLatest([
+      this.lateralMeshRecord$,
+      this.store$.pipe(
+        select(atlasSelection.selectors.selectedRegions),
+        distinctUntilChanged(arrayEqual((o, n) => o.name === n.name))
+      ),
+      this.#colormaps$.pipe(
+        map(cms => cms[0]),
+        distinctUntilChanged((o, n) => o?.id === n?.id)
+      ),
+      this.store$.pipe(
+        select(atlasAppearance.selectors.showDelineation),
+        distinctUntilChanged()
+      ),
+      this.#latLblIdxToCm$,
+      this.#latLblIdxToRegionRecord$,
+    ]),
+    this.#latVtxIdxRecord$
+  ]).pipe(
+    debounceTime(16),
+    map(([[ latMeshDict, selReg, cm, showDelFlag, latLblIdxToCm, latLblIdxToRegionRecord ], latVtxIdx]) => {
+      const arg: TApplyColorArg = {}
+      for (const lat in latMeshDict) {
+        arg[lat] = {
+          mesh: latMeshDict[lat].mesh,
+          selectedRegions: selReg,
+          showDelin: showDelFlag,
+          isBaseCm: cm.clType === "baselayer/colormap",
+          labelIndices: latLblIdxToCm[lat].labelIndices,
+          idxReg: latLblIdxToRegionRecord[lat],
+          map: latLblIdxToCm[lat].map,
+          vertexIndices: latVtxIdx[lat].vertexIndices
+        }
       }
-    }
-    this.applyColor()
-  }
-
-  private applyColor() {
+      return arg
+    })
+  )
+  private applyColor(applyArg: TApplyColorArg) {
     /**
      * on apply color map, reset mesh visibility
      * this issue is more difficult to solve than first anticiplated.
@@ -440,41 +593,81 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
      * 2/ hide hemisphere, select region, unhide hemisphere
      * 3/ select region, hide hemisphere, deselect region
      */
-    if (!this.colormapInUse) return
+    
     if (!this.tsRef) return
     
-    const isBaseCM = this.colormapInUse?.clType === "baselayer/colormap"
-
-    for (const laterality in this.lateralityMeshRecord) {
-      const { mesh } = this.lateralityMeshRecord[laterality]
-      if (!this.latLblIdxRecord[laterality]) continue
-      const { labelIndices } = this.latLblIdxRecord[laterality]
+    for (const laterality in applyArg) {
+      const { labelIndices, map, mesh, showDelin, selectedRegions, isBaseCm, idxReg, vertexIndices } = applyArg[laterality]
 
-      const lblIdxToRegionRecord = this.latLblIdxToRegionRecord[laterality]
-      if (!lblIdxToRegionRecord) {
-        this.tsRef.applyColorMap(mesh, labelIndices)
+      if (!map) {
+        this.tsRef.applyColorMap(mesh, vertexIndices)
         continue
       }
-      const map = new Map<number, number[]>()
-      for (const lblIdx in lblIdxToRegionRecord) {
-        const region = lblIdxToRegionRecord[lblIdx]
-        let color: number[]
-        if (!this.showDelineation) {
-          color = [1,1,1]
-        } else if (isBaseCM && this.selectedRegions.length > 0 && !this.selectedRegions.includes(region)) {
-          color = [1,1,1]
-        } else {
-          color = (this.colormapInUse.colormap.get(region) || [255, 255, 255]).map(v => v/255)
+
+      const actualApplyMap = new Map<number, number[]>()
+
+      if (!showDelin) {
+        for (const lblIdx of labelIndices){
+          actualApplyMap.set(lblIdx, [1, 1, 1])
+        }
+        this.tsRef.applyColorMap(mesh, vertexIndices, {
+          custom: actualApplyMap
+        })
+        return
+      }
+
+      const highlightIdx = new Set<number>()
+      if (isBaseCm && selectedRegions.length > 0) {
+        for (const [idx, region] of Object.entries(idxReg)) {
+          if (selectedRegions.findIndex(r => r.name === region.name) >= 0) {
+            highlightIdx.add(Number(idx))
+          }
+        }
+      }
+      if (isBaseCm && selectedRegions.length > 0) {
+        for (const lblIdx of labelIndices) {
+          actualApplyMap.set(
+            Number(lblIdx),
+            highlightIdx.has(lblIdx)
+            ? map.get(lblIdx) || [1, 0.8, 0.8]
+            : [1, 1, 1]
+          )
+        }
+      } else {
+        for (const lblIdx of labelIndices) {
+          actualApplyMap.set(
+            Number(lblIdx),
+            map.get(lblIdx) || [1, 0.8, 0.8]
+          )
         }
-        map.set(Number(lblIdx), color)
       }
-      this.tsRef.applyColorMap(mesh, labelIndices, {
-        custom: map
+      this.tsRef.applyColorMap(mesh, vertexIndices, {
+        custom: actualApplyMap
       })
     }
   }
 
-  private handleCustomMouseEv(detail: any){
+  #handleCustomMouseEv$ = this.#mouseEv$.pipe(
+    withLatestFrom(
+      this.lateralMeshRecord$,
+      this.#latLblIdxToRegionRecord$,
+      this.meshVisible$,
+      this.#latVtxIdxRecord$,
+    )
+  ).pipe(
+    map(([ evDetail, latMeshRecord, latLblIdxReg, meshVis, latVtxIdx ]) => {
+      const returnVal: THandleCustomMouseEv = {
+        evDetail,
+        meshVisibility: meshVis,
+        latLblIdxReg: latLblIdxReg,
+        latMeshRecord: latMeshRecord,
+        latLblIdxRecord: latVtxIdx
+      }
+      return returnVal
+    })
+  )
+  #handleCustomMouseEv(arg: THandleCustomMouseEv){
+    const { evDetail: detail, latMeshRecord, latLblIdxRecord, latLblIdxReg, meshVisibility } = arg
     const evMesh = detail.mesh && {
       faceIndex: detail.mesh.faceIndex,
       // typo in three-surfer
@@ -495,25 +688,26 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
       verticesIdicies: evVerticesIndicies,
     } = detail.mesh as { geometry: TThreeGeometry, verticesIdicies: number[] }
 
-    for (const laterality in this.lateralityMeshRecord) {
-      const meshRecord = this.lateralityMeshRecord[laterality]
+    for (const laterality in latMeshRecord) {
+      const meshRecord = latMeshRecord[laterality]
       if (meshRecord.mesh !== evGeometry) {
         continue
       }
       /**
        * if either labelindex record or colormap record is undefined for this laterality, emit empty event
        */
-      if (!this.latLblIdxRecord[laterality] || !this.latLblIdxToRegionRecord[laterality]) {
+      if (!latLblIdxRecord[laterality] || !latLblIdxReg[laterality]) {
         return this.handleMouseoverEvent(custEv)
       }
-      const labelIndexRecord = this.latLblIdxRecord[laterality]
-      const regionRecord = this.latLblIdxToRegionRecord[laterality]
+      const labelIndexRecord = latLblIdxRecord[laterality]
+      const regionRecord = latLblIdxReg[laterality]
 
       /**
        * check if the mesh is toggled off
        * if so, do not proceed
        */
-      if (!meshRecord.visible) {
+      const mVis = meshVisibility.filter(({ mesh }) => mesh === meshRecord.mesh)
+      if (!mVis.every(m => m.visible)) {
         return
       }
 
@@ -522,7 +716,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
        */
       const labelIndexSet = new Set<number>()
       for (const idx of evVerticesIndicies){
-        const labelOfInterest = labelIndexRecord.labelIndices[idx]
+        const labelOfInterest = labelIndexRecord.vertexIndices[idx]
         if (!labelOfInterest) {
           continue
         }
@@ -551,31 +745,28 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
     }
   }
 
-  private cameraEv$ = new Subject<{ position: { x: number, y: number, z: number }, zoom: number }>()
-  private handleCustomCameraEvent(detail: any){
-    if (this.internalStateNext) {
-      this.internalStateNext({
-        "@id": getUuid(),
-        "@type": 'TViewerInternalStateEmitterEvent',
-        viewerType,
-        payload: {
-          mode: '',
-          camera: detail.position,
-          hemisphere: 'both'
-        }
-      })
-    }
-    this.cameraEv$.next(detail)
-  }
-
   ngAfterViewInit(): void{
     const customEvHandler = (ev: CustomEvent) => {
       const { type, data } = ev.detail
       if (type === 'mouseover') {
-        return this.handleCustomMouseEv(data)
+        this.#mouseEv$.next(data)
+        return
       }
       if (type === 'camera') {
-        return this.handleCustomCameraEvent(data)
+        if (this.internalStateNext) {
+          this.internalStateNext({
+            "@id": getUuid(),
+            "@type": 'TViewerInternalStateEmitterEvent',
+            viewerType,
+            payload: {
+              mode: '',
+              camera: data.position,
+              hemisphere: 'both'
+            }
+          })
+        }
+        this.#cameraEv$.next(data)
+        return
       }
     }
     this.domEl.addEventListener((window as any).ThreeSurfer.CUSTOM_EVENTNAME_UPDATED, customEvHandler)
@@ -596,40 +787,46 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
       tsCb(this.tsRef)
     }
 
-    const meshSub = this.meshLayers$.pipe(
-      distinctUntilChanged(),
+    const meshSub = this.#meshLayers$.pipe(
+      switchMap(
+        switchMapWaitFor({
+          condition: () => !!this.tsRef,
+          leading: true
+        })
+      ),
       debounceTime(16),
-    ).subscribe(layers => {
-      this.loadMeshes(layers)
+      withLatestFrom(
+        this.lateralMeshRecord$
+      )
+    ).subscribe(([layers, currMeshRecord]) => {
+      this.#loadMeshes(layers, currMeshRecord)
     })
-    const vertexIdxSub = this.vertexIndexLayers$.subscribe(layers => this.loadVertexIndexMap(layers))
-    const roiSelectedSub = this.selectedRegions$.subscribe(regions => {
-      this.selectedRegions = regions
-      this.applyColor()
+    
+    const applyColorSub = this.#applyColor$.subscribe(arg => {
+      this.applyColor(arg)
     })
-    const colormapSub = this.colormaps$.subscribe(cm => {
-      this.colormapInUse = cm[0] || null
-      this.applyColor()
+
+    const mouseSub = this.#handleCustomMouseEv$.subscribe(arg => {
+      this.#handleCustomMouseEv(arg)
     })
-    const recordToRegionSub = this.latLblIdxToRegionRecord$.subscribe(val => this.latLblIdxToRegionRecord = val)
-    const hideDelineationSub = this.store$.pipe(
-      select(atlasAppearance.selectors.showDelineation)
-    ).subscribe(flag => {
-      this.showDelineation = flag
-      this.applyColor()
-      /**
-       * apply color resets mesh visibility
-       */
-      this.updateMeshVisibility()
+
+    const visibilitySub = this.meshVisible$.subscribe(arr => {
+      for (const { visible, mesh } of arr) {
+        mesh.visible = visible
+        
+        const meshObj = this.tsRef.customColormap.get(mesh)
+        if (!meshObj) {
+          throw new Error(`mesh obj not found!`)
+        }
+        meshObj.mesh.visible = visible
+      }
     })
 
     this.onDestroyCb.push(() => {
       meshSub.unsubscribe()
-      vertexIdxSub.unsubscribe()
-      roiSelectedSub.unsubscribe()
-      colormapSub.unsubscribe()
-      recordToRegionSub.unsubscribe()
-      hideDelineationSub.unsubscribe()
+      applyColorSub.unsubscribe()
+      mouseSub.unsubscribe()
+      visibilitySub.unsubscribe()
     })
 
     this.viewerEvent.emit({
@@ -666,20 +863,11 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
     if (this.mouseoverText === '') this.mouseoverText = null
   }
 
-  public updateMeshVisibility(): void{
-
-    for (const key in this.lateralityMeshRecord) {
-
-      const latMeshRecord = this.lateralityMeshRecord[key]
-      if (!latMeshRecord) {
-        return
-      }
-      const meshObj = this.tsRef.customColormap.get(latMeshRecord.mesh)
-      if (!meshObj) {
-        throw new Error(`mesh obj not found!`)
-      }
-      meshObj.mesh.visible = latMeshRecord.visible
-    }
+  public toggleMeshVis(label: string) {
+    this.#meshVisOp$.next({
+      label,
+      op: 'toggle'
+    })
   }
 
   switchSurfaceLayer(variant: string): void{
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html
index fcef001a1ff56073a379a11d82573f85b109f069..778626e2c267217735a3664b82e5644e6a14e1fc 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html
@@ -19,12 +19,12 @@
 <mat-menu #fsModeSelMenu="matMenu">
 
   <div class="sxplr-custom-cmp text sxplr-pl-2 m-2">
-    <mat-checkbox *ngFor="let item of lateralityMeshRecord | keyvalue"
+    <mat-checkbox *ngFor="let item of meshVisible$ | async "
       class="d-block"
       iav-stop="click"
-      (change)="updateMeshVisibility()"
-      [(ngModel)]="item.value.visible">
-      {{ item.key }}
+      (change)="toggleMeshVis(item.label)"
+      [checked]="item.visible">
+      {{ item.label }}
     </mat-checkbox>
   </div>
   <mat-divider></mat-divider>