diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html
index e5e89a7790a51c3b1bce7558fb78339c5f9dc62e..094c5b3035c7835fef28ba1ee6c9f6326f3fd945 100644
--- a/src/atlasViewer/atlasViewer.template.html
+++ b/src/atlasViewer/atlasViewer.template.html
@@ -91,7 +91,7 @@
 
     <div resizeSliver>
       <span
-        *ngIf = "isMobile"
+        *ngIf = "isMobile || true"
         class = "tabContainer"
         (click) = "toggleSidePanel('menuBrowser')"
         [ngClass] = "{'active-tab' : (sidePanelView$ | async) === 'menuBrowser'}" >
diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css
index dec754ca211e5cba31b93b7ae89189566d67ab59..96f68781bdfb562b982f9809a96de6181d06e15d 100644
--- a/src/res/css/extra_styles.css
+++ b/src/res/css/extra_styles.css
@@ -224,4 +224,24 @@ markdown-dom pre code
   border: 0.2em rgba(128,128,128,0.2) solid;
   border-top: 0.2em rgba(128,128,128,0.99) solid;
   animation: spinning 700ms linear infinite running;
+}
+
+.theme-controlled.btn,
+.theme-controlled.btn,
+.theme-controlled.btn
+{
+  border-radius:0;
+  border: none;
+}
+
+[darktheme="true"] .theme-controlled.btn.btn-default
+{
+  background-color: rgba(50, 50 , 50, 1.0);
+  color: rgba(230, 230, 230, 1.0);
+}
+
+[darktheme="true"] .theme-controlled.btn.btn-default.active
+{
+  background-color: rgba(70, 70 , 70, 1.0);
+  color: rgba(255, 255, 255, 1.0);
 }
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.component.ts b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1435c56ec723cabacf6431c434df7a527f7a5174
--- /dev/null
+++ b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.component.ts
@@ -0,0 +1,185 @@
+import { Component, Input, Output,EventEmitter, ElementRef, ViewChild, AfterViewInit, ChangeDetectionStrategy, OnDestroy } from "@angular/core";
+import { fromEvent, Subject, Observable, merge, concat, of, combineLatest } from "rxjs";
+import { map, switchMap, takeUntil, filter, scan, take } from "rxjs/operators";
+
+@Component({
+  selector : 'mobile-overlay',
+  templateUrl : './mobileOverlay.template.html',
+  styleUrls : [
+    './mobileOverlay.style.css'
+  ],
+  styles : [
+    `
+div.active > span:before
+{
+  content: '\u2022';
+  width: 1em;
+  display: inline-block;
+  background:none;
+}
+div:not(.active) > span:before
+{
+  content : ' ';
+  width : 1em;
+  display: inline-block;
+}
+    `
+  ],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+
+export class MobileOverlay implements AfterViewInit, OnDestroy{
+  @Input() tunableProperties : string [] = []
+  @Output() deltaValue : EventEmitter<{delta:number, selectedProp : string}> = new EventEmitter() 
+  @ViewChild('initiator', {read: ElementRef}) initiator : ElementRef
+  @ViewChild('mobileMenuContainer', {read: ElementRef}) menuContainer : ElementRef
+
+  private _onDestroySubject : Subject<boolean> = new Subject()
+
+  private _focusedProperties : string
+  get focusedProperty(){
+    return this._focusedProperties
+      ? this._focusedProperties
+      : this.tunableProperties[0]
+  }
+
+  public showScreen$ : Observable<boolean>
+  public showProperties$ : Observable<boolean>
+  private _drag$ : Observable<any>
+
+  ngOnDestroy(){
+    this._onDestroySubject.next(true)
+    this._onDestroySubject.complete()
+  }
+
+  ngAfterViewInit(){
+
+    this.showScreen$ = merge(
+      fromEvent(this.initiator.nativeElement, 'touchstart'),
+      fromEvent(this.initiator.nativeElement, 'touchend'),
+    ).pipe(
+      map((ev:TouchEvent) => ev.touches.length === 1)
+    )
+
+    this._drag$ = fromEvent(this.initiator.nativeElement, 'touchmove').pipe(
+      takeUntil(fromEvent(this.initiator.nativeElement, 'touchend').pipe(
+        filter((ev:TouchEvent) => ev.touches.length === 0)
+      )),
+      map((ev:TouchEvent) => (ev.preventDefault(), ev.stopPropagation(), ev)),
+      filter((ev:TouchEvent) => ev.touches.length === 1),
+      scan((acc,curr) => acc.length < 2
+        ? acc.concat(curr)
+        : acc.slice(1).concat(curr), []),
+      filter(ev => ev.length === 2)
+    )
+
+    this.showProperties$ = fromEvent(this.initiator.nativeElement, 'touchstart').pipe(    
+      switchMap(() => concat(
+        this._drag$.pipe(
+          map(double => ({
+            deltaX : double[1].touches[0].screenX - double[0].touches[0].screenX,
+            deltaY : double[1].touches[0].screenY - double[0].touches[0].screenY
+          })),
+          scan((acc, _curr) => acc),
+          map(v => v.deltaY ** 2 > v.deltaX ** 2)
+        ),
+        of(false)
+        )
+      )
+    )
+
+    fromEvent(this.initiator.nativeElement, 'touchstart').pipe(
+      switchMap(() => this._drag$.pipe(
+        map(double => ({
+          deltaX : double[1].touches[0].screenX - double[0].touches[0].screenX,
+          deltaY : double[1].touches[0].screenY - double[0].touches[0].screenY
+        })),
+        scan((acc, curr:any) => ({
+          pass: acc.pass === null
+            ? curr.deltaX ** 2 > curr.deltaY ** 2
+            : acc.pass,
+          delta: curr.deltaX
+        }), {
+          pass: null,
+          delta : null
+        }),
+        filter(ev => ev.pass),
+        map(ev => ev.delta)
+      )),
+      takeUntil(this._onDestroySubject)
+    ).subscribe(ev => this.deltaValue.emit({
+      delta : ev,
+      selectedProp : this.focusedProperty
+    }))
+
+    const offsetObs$ = fromEvent(this.initiator.nativeElement, 'touchstart').pipe(
+      switchMap(() => concat(
+        this._drag$.pipe(
+          scan((acc,curr) => [acc[0], curr[1]]),
+          map(double => ({
+            deltaX : double[1].touches[0].screenX - double[0].touches[0].screenX,
+            deltaY : double[1].touches[0].screenY - double[0].touches[0].screenY
+          })),
+        )
+      ))
+    )
+    combineLatest(
+      this.showProperties$,
+      offsetObs$
+    ).pipe(
+      filter(v => v[0]),
+      map(v => v[1]),
+      takeUntil(this._onDestroySubject)
+    ).subscribe(v => this.scrollHeight = v.deltaY)
+
+    this.showProperties$.pipe(
+      takeUntil(this._onDestroySubject),
+      filter(v => !v)
+    ).subscribe(() => {
+      if(this.focusItemIndex >= 0){
+        this._focusedProperties = this.tunableProperties[this.focusItemIndex]
+      }
+      this.scrollHeight = 0
+    })
+  }
+
+  scrollHeight : number = 0
+
+  get defaultY(){
+    return this.tunableProperties.findIndex(p => p === this.focusedProperty) * this.menuCellHeight
+  }
+
+  get menuTransform(){
+    return `translate(0px, ${this.menuYTranslate}px)`
+  }
+
+  get menuYTranslate(){
+    return this.menuContainer
+      ? Math.max(
+          Math.min(
+            this.defaultY + this.scrollHeight, 
+            this.menuContainerHeight / 2 - this.menuCellHeight / 2
+            ),
+          - this.menuContainerHeight / 2 + this.menuCellHeight / 2
+          )
+      : this.defaultY
+  }
+
+  get menuContainerHeight(){
+    return this.menuContainer
+      ? this.menuContainer.nativeElement.offsetHeight
+      : 0
+  }
+
+  get menuCellHeight(){
+    return this.tunableProperties.length > 0
+      ? this.menuContainerHeight / this.tunableProperties.length
+      : 0
+  }
+
+  get focusItemIndex():number{
+    return this.menuContainer
+      ? Math.floor((this.menuContainerHeight / 2 - this.menuYTranslate) / this.menuCellHeight)
+      : -1
+  }
+}
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.style.css b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.style.css
new file mode 100644
index 0000000000000000000000000000000000000000..87cdcdb74678417815d754680476c1dedd767f37
--- /dev/null
+++ b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.style.css
@@ -0,0 +1,66 @@
+:host
+{
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  position: absolute;
+  z-index: 9999;
+
+  pointer-events: none;
+}
+
+:host [screen]
+{
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  position: absolute;
+
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  color : black;
+  background-color: rgba(255, 255, 255, 0.5);
+}
+
+:host-context([darktheme="true"]) [screen]
+{
+  color : white;
+  background-color: rgba(0, 0, 0, 0.5);
+}
+
+[mobileMenuContainer]
+{
+  z-index: 9999;
+  transform: translate(0, 155px);
+}
+
+.scrollFocus:after
+{
+  content: ' ';
+  position:absolute;
+  width:100%;
+  height:100%;
+  top: 0;
+  left: 0;
+  
+  background-color: rgba(0, 0, 128, 0.2);
+}
+
+:host-context([darktheme="true"]) .scrollFocus:after
+{
+  background-color: rgba(128, 128, 200, 0.2);
+}
+
+[guide]
+{
+  z-index:9999;
+}
+
+:host-context([darktheme="true"])
+{
+  /* color: white; */
+}
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.template.html b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.template.html
new file mode 100644
index 0000000000000000000000000000000000000000..541b687d8831e900e346db53607c2f14d812a67c
--- /dev/null
+++ b/src/ui/nehubaContainer/mobileOverlay/mobileOverlay.template.html
@@ -0,0 +1,18 @@
+<div screen *ngIf = "showProperties$ | async">
+  <div [style.transform] = "menuTransform" class = "btn-group-vertical" role = "group" mobileMenuContainer #mobileMenuContainer>
+    <div 
+      *ngFor = "let p of tunableProperties; let i = index"
+      [ngClass] = "{'active' : p === focusedProperty, 'scrollFocus' : i === focusItemIndex}" 
+      class = "btn btn-default theme-controlled">
+      <span>
+        {{ p }}
+      </span>
+    </div>
+  </div>
+</div>
+<ng-content *ngIf = "showScreen$ | async" select = "[guide]" guide>
+</ng-content>
+<div #initiator>
+  <ng-content select="[initiator]">
+  </ng-content>
+</div>
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index 65187a2d6b0b1a46607f33179d7ddc55af8ca6c8..133dcf08a529a664cb5ab5c31ce1370e62e1b432 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -24,8 +24,6 @@ export class NehubaContainer implements OnInit, OnDestroy{
   @ViewChild('[pos01]',{read:ElementRef}) topright : ElementRef
   @ViewChild('[pos10]',{read:ElementRef}) bottomleft : ElementRef
   @ViewChild('[pos11]',{read:ElementRef}) bottomright : ElementRef
-  @ViewChild('mobileObliqueCtrl', {read:ElementRef}) mobileObliqueCtrl : ElementRef
-  @ViewChild('mobileObliqueScreen', {read:ElementRef}) mobileObliqueScreen : ElementRef
 
   private nehubaViewerFactory : ComponentFactory<NehubaViewerUnit>
 
@@ -552,50 +550,69 @@ export class NehubaContainer implements OnInit, OnDestroy{
   }
 
   // datasetViewerRegistry : Set<string> = new Set()
-  public showObliqueScreen : Observable<boolean>
+  public showObliqueScreen$ : Observable<boolean>
+  public showObliqueSelection$ : Observable<boolean>
+  public showObliqueRotate$ : Observable<boolean>
 
   ngAfterViewInit(){
-    if(this.isMobile){
-
-      this.showObliqueScreen = merge(
-        fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchstart'),
-        fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchend')
-      ).pipe(
-        map((ev:TouchEvent) => ev.touches.length === 1)
-      )
-
-      fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchstart').pipe(
-        switchMap(() => fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchmove').pipe(
-          takeUntil(fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchend').pipe(
-            filter((ev:TouchEvent) => ev.touches.length === 0)
-          )),
-          map((ev:TouchEvent) => (ev.preventDefault(), ev.stopPropagation(), ev)),
-          filter((ev:TouchEvent) => ev.touches.length === 1),
-          map((ev:TouchEvent) => [ev.touches[0].screenX, ev.touches[0].screenY] ),
-
-          /* TODO reduce boiler plate, export */
-          scan((acc,curr) => acc.length < 2
-            ? acc.concat([curr])
-            : acc.slice(1).concat([curr]), []),
-          filter(isdouble => isdouble.length === 2),
-          map(double => ({
-            deltaX : double[1][0] - double[0][0],
-            deltaY : double[1][1] - double[0][1]
-          }))
-        ))
-      )
-        .subscribe(({deltaX, deltaY}) => {
-          const {navigationState} = this.nehubaViewer.nehubaViewer.ngviewer
-          navigationState.pose.rotateRelative(this.nehubaViewer.vec3([0, 1, 0]), -deltaX / 4.0 * Math.PI / 180.0)
-          navigationState.pose.rotateRelative(this.nehubaViewer.vec3([1, 0, 0]), deltaY / 4.0 * Math.PI / 180.0)
-        })
-  }
+    // if(this.isMobile){
+
+    //   this.showObliqueScreen$ = merge(
+    //     fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchstart'),
+    //     fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchend')
+    //   ).pipe(
+    //     map((ev:TouchEvent) => ev.touches.length === 1)
+    //   )
+
+    //   fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchstart').pipe(
+    //     switchMap(() => fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchmove').pipe(
+    //       takeUntil(fromEvent(this.mobileObliqueCtrl.nativeElement, 'touchend').pipe(
+    //         filter((ev:TouchEvent) => ev.touches.length === 0)
+    //       )),
+    //       map((ev:TouchEvent) => (ev.preventDefault(), ev.stopPropagation(), ev)),
+    //       filter((ev:TouchEvent) => ev.touches.length === 1),
+    //       map((ev:TouchEvent) => [ev.touches[0].screenX, ev.touches[0].screenY] ),
+
+    //       /* TODO reduce boiler plate, export */
+    //       scan((acc,curr) => acc.length < 2
+    //         ? acc.concat([curr])
+    //         : acc.slice(1).concat([curr]), []),
+    //       filter(isdouble => isdouble.length === 2),
+    //       map(double => ({
+    //         deltaX : double[1][0] - double[0][0],
+    //         deltaY : double[1][1] - double[0][1]
+    //       }))
+    //     ))
+    //   )
+    //     .subscribe(({deltaX, deltaY}) => {
+          
+          
+          
+    //     })
+    // }
   }
 
   ngOnDestroy(){
     this.subscriptions.forEach(s=>s.unsubscribe())
   }
 
+  get tunableMobileProperties(){
+    return ['Oblique Rotate X', 'Oblique Rotate Y', 'Oblique Rotate Z']
+  }
+
+  handleMobileOverlayEvent(obj:any){
+    const {delta, selectedProp} = obj
+
+    const idx = this.tunableMobileProperties.findIndex(p => p === selectedProp)
+    idx === 0
+      ? this.nehubaViewer.obliqueRotateX(delta)
+      : idx === 1
+        ? this.nehubaViewer.obliqueRotateY(delta)
+        : idx === 2
+          ? this.nehubaViewer.obliqueRotateZ(delta)
+          : console.warn('could not oblique rotate')
+  }
+
   returnTruePos(quadrant:number,data:any){
     const pos = quadrant > 2 ?
       [0,0,0] :
diff --git a/src/ui/nehubaContainer/nehubaContainer.style.css b/src/ui/nehubaContainer/nehubaContainer.style.css
index 6b12b3bb969276b7c57575f3b413cc1bac293bb5..13e9fe21bb986f3031f73b4ccbd69237d45369e3 100644
--- a/src/ui/nehubaContainer/nehubaContainer.style.css
+++ b/src/ui/nehubaContainer/nehubaContainer.style.css
@@ -167,4 +167,14 @@ div[mobileObliqueScreen]
   background-color:rgba(128,128,128,0.2);
   transition: all 0.5s linear;
   pointer-events: all;
+}
+
+div[mobileObliqueGuide]
+{
+  position : absolute;
+  top: 40%;
+  width: 100%;
+  display:flex;
+  flex-direction: column;
+  align-items: center;
 }
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html
index 9153ddd3d74ea7b1171c657744ff229479a9d7b5..b3158ad21a3fc38e1c2bc82db6547274eb9d457d 100644
--- a/src/ui/nehubaContainer/nehubaContainer.template.html
+++ b/src/ui/nehubaContainer/nehubaContainer.template.html
@@ -86,9 +86,7 @@
   </div>
 </div>
 
-<layout-floating-container
-  *ngIf = "viewerLoaded">
-
+<layout-floating-container *ngIf = "viewerLoaded">
 
   <div statusCard>
 
@@ -130,12 +128,19 @@
     </div>
   </div>
 </layout-floating-container>
-<layout-floating-container *ngIf = "isMobile" [show] = "viewerLoaded">
-
-  <div *ngIf = "showObliqueScreen | async" #mobileObliqueScreen mobileObliqueScreen>
-
+<mobile-overlay 
+  *ngIf = "isMobile && viewerLoaded" 
+  [tunableProperties] = "tunableMobileProperties" 
+  (deltaValue) = "handleMobileOverlayEvent($event)">
+  <div mobileObliqueGuide guide>
+    <div>
+      <i class="glyphicon glyphicon-resize-vertical"></i> oblique mode 
+    </div>
+    <div>
+      <i class="glyphicon glyphicon-resize-horizontal"></i> rotate slice
+    </div>
   </div>
-  <div mobileObliqueCtrl #mobileObliqueCtrl>
+  <div mobileObliqueCtrl initiator>
     <i class="glyphicon glyphicon-globe"></i>
   </div>
-</layout-floating-container>
\ No newline at end of file
+</mobile-overlay>
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
index 608c1b758250fc67d7607a19a44391c3c93e4285..4f2baf2f003492710399b52a59def3478a51a7d5 100644
--- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
+++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
@@ -344,6 +344,7 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
         this.nehubaViewer.ngviewer.navigationState.zoomBy(factor))
     )
   }
+
   ngOnDestroy(){
     this._s$.forEach(_s$=>{
       if(_s$) _s$.unsubscribe()
@@ -385,6 +386,7 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
             layerObj[key] == l[key])
   }
 
+  // TODO single landmark for user landmark
   public addUserLandmarks(landmarks:any[]){
     if(!this.nehubaViewer)
       return
@@ -406,6 +408,7 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
     this.loadLayer(_)
   }
 
+  // TODO single landmark for user landmark
   public removeUserLandmarks(){
     if(!this.nehubaViewer)
       return
@@ -535,6 +538,18 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
       this.nehubaViewer.setPosition( this.vec3(position) , positionReal ? true : false )
   }
 
+  public obliqueRotateX(amount:number){
+    this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([0, 1, 0]), -amount / 4.0 * Math.PI / 180.0)
+  }
+
+  public obliqueRotateY(amount:number){
+    this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([1, 0, 0]), amount / 4.0 * Math.PI / 180.0)
+  }
+
+  public obliqueRotateZ(amount:number){
+    this.nehubaViewer.ngviewer.navigationState.pose.rotateRelative(this.vec3([0, 0, 1]), amount / 4.0 * Math.PI / 180.0)
+  }
+
   private updateColorMap(arrayIdx:number[]){
     const set = new Set(arrayIdx)
     const newColorMap = new Map(
diff --git a/src/ui/ui.module.ts b/src/ui/ui.module.ts
index 9ac37e377aaf8afe762007bfd387a4cb55b632e6..b48c6e7de35192d8f489cc3b0ad08d48a6c24678 100644
--- a/src/ui/ui.module.ts
+++ b/src/ui/ui.module.ts
@@ -36,6 +36,7 @@ import { SpatialLandmarksToDataBrowserItemPipe } from "../util/pipes/spatialLand
 import { DownloadDirective } from "../util/directives/download.directive";
 import { LogoContainer } from "./logoContainer/logoContainer.component";
 import { TemplateParcellationCitationsContainer } from "./templateParcellationCitations/templateParcellationCitations.component";
+import { MobileOverlay } from "./nehubaContainer/mobileOverlay/mobileOverlay.component";
 
 
 @NgModule({
@@ -67,6 +68,7 @@ import { TemplateParcellationCitationsContainer } from "./templateParcellationCi
     DatasetViewerComponent,
     LogoContainer,
     TemplateParcellationCitationsContainer,
+    MobileOverlay,
 
     /* pipes */
     GroupDatasetByRegion,
@@ -104,7 +106,8 @@ import { TemplateParcellationCitationsContainer } from "./templateParcellationCi
     FileViewer,
     LogoContainer,
     DatasetViewerComponent,
-    TemplateParcellationCitationsContainer
+    TemplateParcellationCitationsContainer,
+    MobileOverlay,
   ]
 })