diff --git a/common/constants.js b/common/constants.js
index 47e4b0c7d9a31899a94972be2ebf96034a68ec6b..e2b47dec26803cfc3730f0c00d03837be6826e84 100644
--- a/common/constants.js
+++ b/common/constants.js
@@ -78,6 +78,8 @@
   }
 
   exports.CONST = {
+    CANNOT_DECIPHER_HEMISPHERE: 'Cannot decipher region hemisphere.',
+    DOES_NOT_SUPPORT_MULTI_REGION_SELECTION: `Please only select a single region.`,
     MULTI_REGION_SELECTION: `Multi region selection`,
     REGIONAL_FEATURES: 'Regional features',
     NO_ADDIONTAL_INFO_AVAIL: `Currently, no additional information is linked to this region.`,
diff --git a/src/state/effects/viewerState.useEffect.ts b/src/state/effects/viewerState.useEffect.ts
index 30bcb2d5f212b5203b546135595ac97b50b703bd..ee9b14a052cb904d319cac39aacf6c65847d14de 100644
--- a/src/state/effects/viewerState.useEffect.ts
+++ b/src/state/effects/viewerState.useEffect.ts
@@ -45,7 +45,7 @@ export const defaultNehubaConfigObject = {
 }
 
 export function cvtNehubaConfigToNavigationObj(nehubaConfig?){
-  const { navigation, perspectiveOrientation = [0, 0, 0, 1], perspectiveZoom = 1e6 } = nehubaConfig || {}
+  const { navigation, perspectiveOrientation = [0.5, -0.5, -0.5, 0.5], perspectiveZoom = 1e6 } = nehubaConfig || {}
   const { pose, zoomFactor = 1e6 } = navigation || {}
   const { position, orientation = [0, 0, 0, 1] } = pose || {}
   const { voxelSize = [1, 1, 1], voxelCoordinates = [0, 0, 0] } = position || {}
diff --git a/src/util/directives/captureClickListener.directive.ts b/src/util/directives/captureClickListener.directive.ts
index b8e04e77f862b0841fb23cac3b801b494a729809..1a9fb9b583b34f9c1c0c5d6cab929636951da35d 100644
--- a/src/util/directives/captureClickListener.directive.ts
+++ b/src/util/directives/captureClickListener.directive.ts
@@ -27,9 +27,9 @@ export class CaptureClickListenerDirective implements OnInit, OnDestroy {
   }
 
   public ngOnInit() {
-    const mouseDownObs$ = fromEvent(this.element, 'mousedown', { capture: this.captureDocument })
-    const mouseMoveObs$ = fromEvent(this.element, 'mousemove', { capture: this.captureDocument })
-    const mouseUpObs$ = fromEvent(this.element, 'mouseup', { capture: this.captureDocument })
+    const mouseDownObs$ = fromEvent(this.element, 'pointerdown', { capture: this.captureDocument })
+    const mouseMoveObs$ = fromEvent(this.element, 'pointermove', { capture: this.captureDocument })
+    const mouseUpObs$ = fromEvent(this.element, 'pointerup', { capture: this.captureDocument })
 
     this.subscriptions.push(
       mouseDownObs$.subscribe(event => {
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
index 206b18cef209fa3d70f4e9a3c412465eecf683ee..2d234be4c3a6f604524e764b46af44314d31bba2 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
@@ -1,14 +1,22 @@
-import { Component, Input, Output, EventEmitter, ElementRef, OnChanges, OnDestroy, AfterViewInit } from "@angular/core";
+import { Component, Input, Output, EventEmitter, ElementRef, OnChanges, OnDestroy, AfterViewInit, Inject, Optional } from "@angular/core";
 import { EnumViewerEvt, IViewer, TViewerEvent } from "src/viewerModule/viewer.interface";
 import { TThreeSurferConfig, TThreeSurferMode } from "../types";
 import { parseContext } from "../util";
 import { retry, flattenRegions } from 'common/util'
-import { Subject } from "rxjs";
-import { debounceTime, filter } from "rxjs/operators";
+import { BehaviorSubject, Observable, Subject } from "rxjs";
+import { debounceTime, filter, map, switchMap } from "rxjs/operators";
 import { ComponentStore } from "src/viewerModule/componentStore";
 import { select, Store } from "@ngrx/store";
-import { viewerStateChangeNavigation } from "src/services/state/viewerState/actions";
+import { viewerStateChangeNavigation, viewerStateSetSelectedRegions } from "src/services/state/viewerState/actions";
 import { viewerStateSelectorNavigation } from "src/services/state/viewerState/selectors";
+import { ClickInterceptor, CLICK_INTERCEPTOR_INJECTOR } from "src/util";
+import { REGION_OF_INTEREST } from "src/util/interfaces";
+import { MatSnackBar } from "@angular/material/snack-bar";
+import { CONST } from 'common/constants'
+import { API_SERVICE_SET_VIEWER_HANDLE_TOKEN, TSetViewerHandle } from "src/atlasViewer/atlasViewer.apiService.service";
+import { switchMapWaitFor } from "src/util/fn";
+
+const pZoomFactor = 5e3
 
 type THandlingCustomEv = {
   regions: ({ name?: string, error?: string })[]
@@ -25,6 +33,14 @@ type TCameraOrientation = {
 
 const threshold = 1e-3
 
+function getHemisphereKey(region: { name: string }){
+  return /left/.test(region.name)
+    ? 'left'
+    : /right/.test(region.name)
+      ? 'right'
+      : null
+}
+
 function cameraNavsAreSimilar(c1: TCameraOrientation, c2: TCameraOrientation){
   if (c1 === c2) return true
   if (!!c1 && !!c2) return true
@@ -72,11 +88,140 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
   public allKeys: {name: string, checked: boolean}[] = []
 
   private regionMap: Map<string, Map<number, any>> = new Map()
+  private mouseoverRegions = []
   constructor(
     private el: ElementRef,
     private store$: Store<any>,
     private navStateStoreRelay: ComponentStore<{ perspectiveOrientation: [number, number, number, number], perspectiveZoom: number }>,
+    private snackbar: MatSnackBar,
+    @Optional() @Inject(REGION_OF_INTEREST) private roi$: Observable<any>,
+    @Optional() @Inject(CLICK_INTERCEPTOR_INJECTOR) clickInterceptor: ClickInterceptor,
+    @Optional() @Inject(API_SERVICE_SET_VIEWER_HANDLE_TOKEN) setViewerHandle: TSetViewerHandle,
   ){
+
+    // set viewer handle
+    // the API won't be 100% compatible with ngviewer
+    if (setViewerHandle) {
+      const nyi = () => {
+        throw new Error(`Not yet implemented`)
+      }
+      setViewerHandle({
+        add3DLandmarks: nyi,
+        loadLayer: nyi,
+        applyLayersColourMap: (map: Map<string, Map<number, { red: number, green: number, blue: number }>>) => {
+          const applyCm = new Map()
+          for (const [hem, m] of map.entries()) {
+            const nMap = new Map()
+            applyCm.set(hem, nMap)
+            for (const [lbl, vals] of m.entries()) {
+              const { red, green, blue } = vals
+              nMap.set(lbl, [red/255, green/255, blue/255])
+            }
+          }
+          this.externalHemisphLblColorMap = applyCm
+        },
+        getLayersSegmentColourMap: () => {
+          const map = this.getColormapCopy()
+          const outmap = new Map<string, Map<number, { red: number, green: number, blue: number }>>()
+          for (const [ hem, m ] of map.entries()) {
+            const nMap = new Map<number, {red: number, green: number, blue: number}>()
+            outmap.set(hem, nMap)
+            for (const [ lbl, vals ] of m.entries()) {
+              nMap.set(lbl, {
+                red: vals[0] * 255,
+                green: vals[1] * 255,
+                blue: vals[2] * 255,
+              })
+            }
+          }
+          return outmap
+        },
+        getNgHash: nyi,
+        hideAllSegments: nyi,
+        hideSegment: nyi,
+        mouseEvent: null, 
+        mouseOverNehuba: null,
+        mouseOverNehubaLayers: null,
+        mouseOverNehubaUI: null,
+        moveToNavigationLoc: null,
+        moveToNavigationOri: null,
+        remove3DLandmarks: null,
+        removeLayer: null,
+        setLayerVisibility: null,
+        setNavigationLoc: null,
+        setNavigationOri: null,
+        showAllSegments: nyi,
+        showSegment: nyi,
+      })
+    }
+
+    if (this.roi$) {
+      const sub = this.roi$.pipe(
+        switchMap(switchMapWaitFor({
+          condition: () => this.colormapLoaded
+        }))
+      ).subscribe(r => {
+        try {
+          if (!r) throw new Error(`No region selected.`)
+          const cmap = this.getColormapCopy()
+          const hemisphere = getHemisphereKey(r)
+          if (!hemisphere) {
+            this.snackbar.open(CONST.CANNOT_DECIPHER_HEMISPHERE, 'Dismiss', {
+              duration: 3000
+            })
+            throw new Error(CONST.CANNOT_DECIPHER_HEMISPHERE)
+          }
+          for (const [ hem, m ] of cmap.entries()) {
+            for (const lbl of m.keys()) {
+              if (hem !== hemisphere || lbl !== r.labelIndex) {
+                m.set(lbl, [1, 1, 1])
+              }
+            }
+          }
+          this.internalHemisphLblColorMap = cmap
+        } catch (e) {
+          this.internalHemisphLblColorMap = null
+        }
+
+        this.applyColorMap()
+      })
+      this.onDestroyCb.push(
+        () => sub.unsubscribe()
+      )
+    }
+
+    /**
+     * intercept click and act
+     */
+    if (clickInterceptor) {
+      const handleClick = (ev: MouseEvent) => {
+
+        // if does not click inside container, ignore
+        if (!(this.el.nativeElement as HTMLElement).contains(ev.target as HTMLElement)) {
+          return true
+        }
+        
+        if (this.mouseoverRegions.length === 0) return true
+        if (this.mouseoverRegions.length > 1) {
+          this.snackbar.open(CONST.DOES_NOT_SUPPORT_MULTI_REGION_SELECTION, 'Dismiss', {
+            duration: 3000
+          })
+          return true
+        }
+        this.store$.dispatch(
+          viewerStateSetSelectedRegions({
+            selectRegions: this.mouseoverRegions
+          })
+        )
+        return true
+      }
+      const { register, deregister } = clickInterceptor
+      register(handleClick)
+      this.onDestroyCb.push(
+        () => deregister(register)
+      )
+    }
+    
     this.domEl = this.el.nativeElement
 
     /**
@@ -122,7 +267,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
             orientation: [0, 0, 0, 1],
             zoom: 1,
             perspectiveOrientation: v.perspectiveOrientation,
-            perspectiveZoom: v.perspectiveZoom
+            perspectiveZoom: v.perspectiveZoom * pZoomFactor
           }
         })
       )
@@ -149,7 +294,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
         const THREE = (window as any).ThreeSurfer.THREE
         
         const cameraQuat = new THREE.Quaternion(...this.mainStoreCameraNav.perspectiveOrientation)
-        const cameraPos = new THREE.Vector3(0, 0, this.mainStoreCameraNav.perspectiveZoom)
+        const cameraPos = new THREE.Vector3(0, 0, this.mainStoreCameraNav.perspectiveZoom / pZoomFactor)
         cameraPos.applyQuaternion(cameraQuat)
         this.toTsRef(tsRef => {
           tsRef.camera.position.copy(cameraPos)
@@ -171,7 +316,15 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
     hemisphere: string
     vIdxArr: number[]
   }[] = []
-
+  private hemisphLblColorMap: Map<string, Map<number, [number, number, number]>> = new Map()
+  private internalHemisphLblColorMap: Map<string, Map<number, [number, number, number]>>
+  private externalHemisphLblColorMap: Map<string, Map<number, [number, number, number]>>
+  
+  get activeColorMap() {
+    if (this.externalHemisphLblColorMap) return this.externalHemisphLblColorMap
+    if (this.internalHemisphLblColorMap) return this.internalHemisphLblColorMap
+    return this.hemisphLblColorMap
+  }
   private relayStoreLock: () => void = null
   private tsRefInitCb: ((tsRef: any) => void)[] = []
   private toTsRef(callback: (tsRef: any) => void) {
@@ -188,6 +341,8 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
       const m = this.loadedMeshes.pop()
       this.tsRef.unloadMesh(m.threeSurfer)
     }
+    this.hemisphLblColorMap.clear()
+    this.colormapLoaded = false
   }
 
   public async loadMode(mode: TThreeSurferMode) {
@@ -236,7 +391,32 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
         hemisphere,
         vIdxArr: colorIdx
       })
-      this.tsRef.applyColorMap(tsM, colorIdx, 
+
+      this.hemisphLblColorMap.set(hemisphere, applyCM)
+    }
+    this.colormapLoaded = true
+    this.applyColorMap()
+  }
+
+  private colormapLoaded = false
+
+  private getColormapCopy(): Map<string, Map<number, [number, number, number]>> {
+    const outmap = new Map()
+    for (const [key, value] of this.hemisphLblColorMap.entries()) {
+      outmap.set(key, new Map(value))
+    }
+    return outmap
+  }
+
+  /**
+   * TODO perhaps debounce calls to applycolormap
+   * so that the colormap doesn't "flick"
+   */
+  private applyColorMap(){
+    for (const mesh of this.loadedMeshes) {
+      const { hemisphere, threeSurfer, vIdxArr } = mesh
+      const applyCM = this.activeColorMap.get(hemisphere)
+      this.tsRef.applyColorMap(threeSurfer, vIdxArr, 
         {
           custom: applyCM
         }
@@ -279,11 +459,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
       const flattenedRegions = flattenRegions(this.selectedParcellation.regions)
       for (const region of flattenedRegions) {
         if (region.labelIndex) {
-          const hemisphere = /left/.test(region.name)
-            ? 'left'
-            : /right/.test(region.name)
-              ? 'right'
-              : null
+          const hemisphere = getHemisphereKey(region)
           if (!hemisphere) throw new Error(`region ${region.name} does not have hemisphere defined`)
           if (!this.regionMap.has(hemisphere)) {
             this.regionMap.set(hemisphere, new Map())
@@ -397,6 +573,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
   public mouseoverText: string
   private handleMouseoverEvent(ev: THandlingCustomEv){
     const { regions: mouseover, evMesh } = ev
+    this.mouseoverRegions = mouseover
     this.viewerEvent.emit({
       type: EnumViewerEvt.VIEWER_CTX,
       data: {