diff --git a/deploy/package-lock.json b/deploy/package-lock.json
index 01318d6f2c5675ccc18f035b5cb0351b4825541f..b297a940a528a77b31bcfd3b70fe90ead1d08b91 100644
--- a/deploy/package-lock.json
+++ b/deploy/package-lock.json
@@ -5428,4 +5428,4 @@
       "dev": true
     }
   }
-}
+}
\ No newline at end of file
diff --git a/docs/releases/v2.8.1.md b/docs/releases/v2.9.0.md
similarity index 50%
rename from docs/releases/v2.8.1.md
rename to docs/releases/v2.9.0.md
index ef863e589530938ead7955d11b74eb65eaccdc42..3f29c6942d4a1844951eff0c209e36072c168021 100644
--- a/docs/releases/v2.8.1.md
+++ b/docs/releases/v2.9.0.md
@@ -1,4 +1,8 @@
-# v2.8.1
+# v2.9.0
+
+## Feature
+
+- Added minimap picture-in-picture in single panel mode
 
 ## Behind the scenes
 
@@ -7,4 +11,6 @@
 
 ## Bugfix
 
+- Select default connectivity profile
+- Show connectivity dataset info
 - Mini region search on Enter no longer resets the page
diff --git a/mkdocs.yml b/mkdocs.yml
index 1961c4105309dcac8b1afcd4a1d87fdef9c05f21..d6c7b67e173b7577f1e79a7a4fda0d59d92bcbfd 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -33,7 +33,7 @@ nav:
     - Fetching datasets: 'advanced/datasets.md'
     - Display non-atlas volumes: 'advanced/otherVolumes.md'
   - Release notes:
-    - v2.8.1: 'releases/v2.8.1.md'
+    - v2.9.0: 'releases/v2.9.0.md'
     - v2.8.0: 'releases/v2.8.0.md'
     - v2.7.7: 'releases/v2.7.7.md'
     - v2.7.6: 'releases/v2.7.6.md'
diff --git a/package.json b/package.json
index 5845f4d4767e0c564a10fd5ee5ee37009e7e586e..a38aed3a21dee98a92205763be72d4d0b0202e92 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "interactive-viewer",
-  "version": "2.8.1",
+  "version": "2.9.0",
   "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular",
   "scripts": {
     "lint": "eslint src --ext .ts",
diff --git a/src/assets/images/persp-view/bigbrain-axial.png b/src/assets/images/persp-view/bigbrain-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..6919293e6dfaa7c9c07e0a63429dcac06426f22b
Binary files /dev/null and b/src/assets/images/persp-view/bigbrain-axial.png differ
diff --git a/src/assets/images/persp-view/bigbrain-coronal.png b/src/assets/images/persp-view/bigbrain-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc1a13cd7002be2c84d5b49dd6ed93c429acec6f
Binary files /dev/null and b/src/assets/images/persp-view/bigbrain-coronal.png differ
diff --git a/src/assets/images/persp-view/bigbrain-sag.png b/src/assets/images/persp-view/bigbrain-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..5ccf92c68d491a5af4a9b932e1978dcb9888f0cd
Binary files /dev/null and b/src/assets/images/persp-view/bigbrain-sag.png differ
diff --git a/src/assets/images/persp-view/colin-axial.png b/src/assets/images/persp-view/colin-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ac1d819230a0044d59f66501d5a622a44eea319
Binary files /dev/null and b/src/assets/images/persp-view/colin-axial.png differ
diff --git a/src/assets/images/persp-view/colin-coronal.png b/src/assets/images/persp-view/colin-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..92162fdb35e24521572c48a26363ea67eea16aa1
Binary files /dev/null and b/src/assets/images/persp-view/colin-coronal.png differ
diff --git a/src/assets/images/persp-view/colin-sag.png b/src/assets/images/persp-view/colin-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..db5c471e8420b5c1df66418c3ec3fdb62dac2115
Binary files /dev/null and b/src/assets/images/persp-view/colin-sag.png differ
diff --git a/src/assets/images/persp-view/icbm152-axial.png b/src/assets/images/persp-view/icbm152-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7d915087410753129526540cf552b1df085f9e4
Binary files /dev/null and b/src/assets/images/persp-view/icbm152-axial.png differ
diff --git a/src/assets/images/persp-view/icbm152-coronal.png b/src/assets/images/persp-view/icbm152-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..627370ce455b8f22279f7cd7a3ade2ebfca92a26
Binary files /dev/null and b/src/assets/images/persp-view/icbm152-coronal.png differ
diff --git a/src/assets/images/persp-view/icbm152-sag.png b/src/assets/images/persp-view/icbm152-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..640419067e88b07c79154a9dea54ce30e143ccee
Binary files /dev/null and b/src/assets/images/persp-view/icbm152-sag.png differ
diff --git a/src/assets/images/persp-view/monkey-axial.png b/src/assets/images/persp-view/monkey-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff99d0987bc4d44c0572944cfcae326a85a5bbc6
Binary files /dev/null and b/src/assets/images/persp-view/monkey-axial.png differ
diff --git a/src/assets/images/persp-view/monkey-coronal.png b/src/assets/images/persp-view/monkey-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c4f1e9bca768968fdd9ea76bf5262b00d7f73a3
Binary files /dev/null and b/src/assets/images/persp-view/monkey-coronal.png differ
diff --git a/src/assets/images/persp-view/monkey-sag.png b/src/assets/images/persp-view/monkey-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..95333bc9fd2de694e5d99218d10b636160946c76
Binary files /dev/null and b/src/assets/images/persp-view/monkey-sag.png differ
diff --git a/src/assets/images/persp-view/mouse-axial.png b/src/assets/images/persp-view/mouse-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..86d952265b2edf0e355efb2bfd6eff382e971941
Binary files /dev/null and b/src/assets/images/persp-view/mouse-axial.png differ
diff --git a/src/assets/images/persp-view/mouse-coronal.png b/src/assets/images/persp-view/mouse-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..4503c53e7b97766a3aa97b3e35837e193c7ad4a1
Binary files /dev/null and b/src/assets/images/persp-view/mouse-coronal.png differ
diff --git a/src/assets/images/persp-view/mouse-sag.png b/src/assets/images/persp-view/mouse-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..345fa1ba683ca417a01cce73c521344a5334f3e8
Binary files /dev/null and b/src/assets/images/persp-view/mouse-sag.png differ
diff --git a/src/assets/images/persp-view/rat-axial.png b/src/assets/images/persp-view/rat-axial.png
new file mode 100644
index 0000000000000000000000000000000000000000..cbfc7e62f1ee0742f51ed7444b66904249e9952f
Binary files /dev/null and b/src/assets/images/persp-view/rat-axial.png differ
diff --git a/src/assets/images/persp-view/rat-coronal.png b/src/assets/images/persp-view/rat-coronal.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b6128b0c4a0b3f2850fcf92b066b4b15f6f777c
Binary files /dev/null and b/src/assets/images/persp-view/rat-coronal.png differ
diff --git a/src/assets/images/persp-view/rat-sag.png b/src/assets/images/persp-view/rat-sag.png
new file mode 100644
index 0000000000000000000000000000000000000000..3456b8f495cd764c8a36046774cd92ed84699c35
Binary files /dev/null and b/src/assets/images/persp-view/rat-sag.png differ
diff --git a/src/atlasComponents/constants.ts b/src/atlasComponents/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a06a57f2deb55d0d5714e340425d776fae9ce35
--- /dev/null
+++ b/src/atlasComponents/constants.ts
@@ -0,0 +1,5 @@
+export enum EnumClassicalView {
+  CORONAL = "Coronal",
+  SAGITTAL = "Sagittal",
+  AXIAL = "Axial",
+}
diff --git a/src/atlasComponents/sapi/core/sapiSpace.ts b/src/atlasComponents/sapi/core/sapiSpace.ts
index 5f61ae6f68240437d2a9510b4744d64d16e54977..af2171077788d7a8a879590e6c89305883f90e7c 100644
--- a/src/atlasComponents/sapi/core/sapiSpace.ts
+++ b/src/atlasComponents/sapi/core/sapiSpace.ts
@@ -1,4 +1,4 @@
-import { Observable } from "rxjs"
+import { Observable, throwError } from "rxjs"
 import { SAPI } from '../sapi.service'
 import { camelToSnake } from 'common/util'
 import {SapiQueryPriorityArg, SapiSpaceModel, SapiSpatialFeatureModel, SapiVolumeModel} from "../type"
@@ -84,4 +84,23 @@ export class SAPISpace{
       ))
     )
   }
+
+  getTemplateSize() {
+    return this.getVolumes().pipe(
+      switchMap(volumes => {
+        const ngVolumes = volumes.filter(vol => vol["@type"] === "spy/volume/neuroglancer/precomputed")
+        if (ngVolumes.length === 0) return throwError(`template ${this.id} has no ng volume.`)
+        return this.sapi.httpGet<any>(`${ngVolumes[0].data.url}/info`).pipe(
+          map(infoJson => {
+            const { resolution, size } = infoJson.scales[0]
+            return {
+              voxel: size as [number, number, number],
+              real: [0, 1, 2].map(idx => resolution[idx] * size[idx]) as [number, number, number],
+              transform: ngVolumes[0].data?.detail?.['neuroglancer/precomputed']?.['transform'] as number[][]
+            }
+          })
+        )
+      })
+    )
+  }
 }
diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
index 547567b429028c78987f822ea0f613b60b9446c5..18f77fc1b93f298b44f0a0abca283971145655fe 100644
--- a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
+++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
@@ -115,10 +115,10 @@
         <sxplr-sapiviews-features-connectivity-browser
           class="pe-all flex-shrink-1"
           [region]="region"
-          [types]="hasConnectivityDirective.availableModalities"
           [sxplr-sapiviews-features-connectivity-browser-atlas]="atlas"
           [sxplr-sapiviews-features-connectivity-browser-parcellation]="parcellation"
           [accordionExpanded]="expandedPanel === CONST.CONNECTIVITY"
+          [types]="hasConnectivityDirective.availableModalities"
         >
         </sxplr-sapiviews-features-connectivity-browser>
       </ng-template>
diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts
index 9442d04c0d9112715b020c7d5d8da535c31275bd..084a7ed862896c530146930484e131b488b06470 100644
--- a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts
+++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.spec.ts
@@ -108,7 +108,6 @@ describe('ConnectivityComponent', () => {
         beforeEach(async () => {
             fixture = TestBed.createComponent(ConnectivityBrowserComponent)
             component = fixture.componentInstance
-            component.types = types
 
             const atlas = 'atlases/juelich/iav/atlas/v1.0.0/1'
             const parcellation = 'minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-290'
@@ -116,8 +115,7 @@ describe('ConnectivityComponent', () => {
 
             component.atlas = { '@id': atlas } as SapiAtlasModel
             component.parcellation = { '@id': parcellation } as SapiParcellationModel
-
-            component.selectType('StreamlineCounts')
+            component.types = types
 
             const url = `${endp}/atlases/${encodeURIComponent(atlas)}/parcellations/${encodeURIComponent(parcellation)}/features?type=${component.selectedTypeId}&size=${100}&page=${1}`
 
diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
index 850d763b82a330e69d402ae769b4956c3c1ee57a..579e34570f4bb3d2abf69fe7af7d60ea9eefe433 100644
--- a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
+++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.component.ts
@@ -18,6 +18,7 @@ import { HttpClient } from "@angular/common/http";
 @Component({
   selector: 'sxplr-sapiviews-features-connectivity-browser',
   templateUrl: './connectivityBrowser.template.html',
+  styleUrls: ['./connectivityBrowser.style.scss']
 })
 export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
 
@@ -57,8 +58,6 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
 
     }
 
-    @Input() types: SapiModalityModel[] = []
-
     public selectedType: string
     public selectedTypeId: string
     public selectedCohort: string
@@ -105,6 +104,16 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
     public logDisabled: boolean = true
     public logChecked: boolean = true
 
+    private _types: SapiModalityModel[] = []
+    @Input()
+    set types(val) {
+      this._types = val
+      if (val && val.length) this.selectType(val[0].name)
+    }
+    get types() {
+      return this._types
+    }
+
     @ViewChild('connectivityComponent', {read: ElementRef}) public connectivityComponentElement: ElementRef<any>
     @ViewChild('fullConnectivityGrid') public fullConnectivityGridElement: ElementRef<any>
 
@@ -214,6 +223,7 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
           this.cohorts = [...new Set(this.fetchedItems.map(item => item.cohort))]
           this.fetching = false
           this.changeDetectionRef.detectChanges()
+          this.selectCohort(this.cohorts[0])
         }
       })
     }
@@ -265,20 +275,23 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy {
     }) : ds
 
     fetchConnectivity(datasetId=null) {
-      this.sapi.getParcellation(this.atlas["@id"], this.parcellation["@id"]).getFeatureInstance(datasetId || this.selectedDataset['@id'])
-        .pipe(catchError(() => {
-          this.fetching = false
-          return of(null)
-        }))
-        .subscribe(ds=> {
-          this.selectedDataset = this.fixDatasetFormat(ds)
-          this.setMatrixData(ds)
-          this.fetching = false
-        })
+      const parcellation = this.sapi.getParcellation(this.atlas["@id"], this.parcellation["@id"])
+      if (parcellation) {
+        parcellation.getFeatureInstance(datasetId || this.selectedDataset['@id'])
+          .pipe(catchError(() => {
+            this.fetching = false
+            return of(null)
+          }))
+          .subscribe(ds => {
+            this.selectedDataset = this.fixDatasetFormat(ds)
+            this.setMatrixData(ds)
+            this.fetching = false
+          })
+      }
     }
 
     // ToDo need to be fixed on configuration side
-    fixHemisphereNaming(area) {
+    fixHemisphereNaming(area: string) {
       if (area.includes(' - left hemisphere')) {
         return area.replace('- left hemisphere', 'left')
       } else if (area.includes(' - right hemisphere')) {
diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.style.scss b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.style.scss
new file mode 100644
index 0000000000000000000000000000000000000000..577f01f651e1919092957a31dd898c213594b00a
--- /dev/null
+++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.style.scss
@@ -0,0 +1,3 @@
+::ng-deep label {
+    margin-bottom: 0 !important;
+}
\ No newline at end of file
diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.template.html b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
index b59216a944a65d0001a2d0160035bde3b78e0f02..df2a233d6349bfe8de3b4e06ebca492e2d4695fa 100644
--- a/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
+++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityBrowser/connectivityBrowser.template.html
@@ -93,8 +93,16 @@
                       [disabled]="logDisabled || noConnectivityForRegion">Log 10</mat-checkbox>
         <button mat-button [matMenuTriggerFor]="exportMenu"
                 [disabled]="!connectedAreas.value">
-            <i class="fas fa-download mb-2 mr-2"></i>
-            <label>Export</label>
+            <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.join(),
+                  actions: selectedDataset | connectivityDoiPipe
+                }">
+            <i class="fas fa-info"></i>
         </button>
     </div>
 
diff --git a/src/atlasComponents/sapiViews/features/connectivity/connectivityDoi.pipe.ts b/src/atlasComponents/sapiViews/features/connectivity/connectivityDoi.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee527989cefa890fb8af7f1cf2fd8bc52411912b
--- /dev/null
+++ b/src/atlasComponents/sapiViews/features/connectivity/connectivityDoi.pipe.ts
@@ -0,0 +1,15 @@
+import { Pipe, PipeTransform } from "@angular/core"
+import { SapiParcellationFeatureModel } from "src/atlasComponents/sapi/type"
+
+@Pipe({
+    name: 'connectivityDoiPipe',
+    pure: true
+  })
+  
+  export class ConnectivityDoiPipe implements PipeTransform {
+    public transform(dataset: SapiParcellationFeatureModel): string[] {
+      const url = `https://search.kg.ebrains.eu/instances/${dataset['dataset_id']}`
+      return [url]
+    }
+  }
+  
\ No newline at end of file
diff --git a/src/atlasComponents/sapiViews/features/connectivity/module.ts b/src/atlasComponents/sapiViews/features/connectivity/module.ts
index 82134d44f1a4677d2c15ec0c9abcd225a33e73dc..d796c5f22ce7b132574eadbcda22f8a4f672d949 100644
--- a/src/atlasComponents/sapiViews/features/connectivity/module.ts
+++ b/src/atlasComponents/sapiViews/features/connectivity/module.ts
@@ -5,16 +5,20 @@ import {ConnectivityBrowserComponent} from "src/atlasComponents/sapiViews/featur
 import {HasConnectivity} from "src/atlasComponents/sapiViews/features/connectivity/hasConnectivity.directive";
 import {AngularMaterialModule} from "src/sharedModules";
 import {FormsModule} from "@angular/forms";
+import { DialogModule } from "src/ui/dialogInfo";
+import { ConnectivityDoiPipe } from "./connectivityDoi.pipe";
 
 @NgModule({
   imports: [
     CommonModule,
     FormsModule,
-    AngularMaterialModule
+    AngularMaterialModule,
+    DialogModule
   ],
   declarations: [
     ConnectivityBrowserComponent,
-    HasConnectivity
+    HasConnectivity,
+    ConnectivityDoiPipe
   ],
   exports: [
     ConnectivityBrowserComponent,
diff --git a/src/layouts/currentLayout/currentLayout.component.ts b/src/layouts/currentLayout/currentLayout.component.ts
index 0e6a4b56db66d3afbd888e7bb66a9bace4a0a8a5..90d5d25521d004456e845d1f697719ee1c543e52 100644
--- a/src/layouts/currentLayout/currentLayout.component.ts
+++ b/src/layouts/currentLayout/currentLayout.component.ts
@@ -19,6 +19,7 @@ export class CurrentLayout {
     FOUR_PANEL: "FOUR_PANEL",
     H_ONE_THREE: "H_ONE_THREE",
     SINGLE_PANEL: "SINGLE_PANEL",
+    PIP_PANEL: "PIP_PANEL",
     V_ONE_THREE: "V_ONE_THREE"
   }
 
diff --git a/src/layouts/currentLayout/currentLayout.template.html b/src/layouts/currentLayout/currentLayout.template.html
index 1079302ee3c7ae96177427ef21ad262d96f1a2ad..8ec0c59768885aeea52925836d939c79cadac61e 100644
--- a/src/layouts/currentLayout/currentLayout.template.html
+++ b/src/layouts/currentLayout/currentLayout.template.html
@@ -63,6 +63,25 @@
       <ng-content *ngTemplateOutlet="celliv"></ng-content>
     </ng-container>
   </layout-single-panel>
+  <picture-in-picture-panel
+    *ngSwitchCase="panelModes.PIP_PANEL"
+    class="d-block sxplr-w-100 sxplr-h-100">
+    <ng-container cell-i>
+      <ng-content *ngTemplateOutlet="celli"></ng-content>
+    </ng-container>
+    <ng-container cell-ii>
+      <ng-content *ngTemplateOutlet="cellii"></ng-content>
+    </ng-container>
+    <ng-container cell-iii>
+      <ng-content *ngTemplateOutlet="celliii"></ng-content>
+    </ng-container>
+    <ng-container cell-iv>
+      <ng-content *ngTemplateOutlet="celliv"></ng-content>
+    </ng-container>
+    <div picture-in-picture>
+      <ng-content *ngTemplateOutlet="pictureInPictureTmp"></ng-content>
+    </div>
+  </picture-in-picture-panel>
   <div *ngSwitchDefault>
     A panel mode which I have never seen before ... {{ useLayout }}
   </div>
@@ -79,4 +98,7 @@
 </ng-template>
 <ng-template #celliv>
   <ng-content select="[cell-iv]"></ng-content>
-</ng-template>
\ No newline at end of file
+</ng-template>
+<ng-template #pictureInPictureTmp>
+  <ng-content select="[picture-in-picture]"></ng-content>
+</ng-template>
diff --git a/src/layouts/layout.module.ts b/src/layouts/layout.module.ts
index 40cedc4f12736cadd766c749d55ab3e1139b4a43..773a1e5ab248c44e05479934243df5aefc1a233f 100644
--- a/src/layouts/layout.module.ts
+++ b/src/layouts/layout.module.ts
@@ -6,6 +6,7 @@ import { CurrentLayout } from "./currentLayout/currentLayout.component";
 import { FourCornersCmp } from "./fourCorners/fourCorners.component";
 import { FourPanelLayout } from "./layouts/fourPanel/fourPanel.component";
 import { HorizontalOneThree } from "./layouts/h13/h13.component";
+import { PictureInPicturePanel } from "./layouts/pip/pip.component";
 import { SinglePanel } from "./layouts/single/single.component";
 import { VerticalOneThree } from "./layouts/v13/v13.component";
 
@@ -22,6 +23,7 @@ import { VerticalOneThree } from "./layouts/v13/v13.component";
     FourPanelLayout,
     HorizontalOneThree,
     SinglePanel,
+    PictureInPicturePanel,
     VerticalOneThree,
   ],
   exports : [
@@ -31,6 +33,7 @@ import { VerticalOneThree } from "./layouts/v13/v13.component";
     FourPanelLayout,
     HorizontalOneThree,
     SinglePanel,
+    PictureInPicturePanel,
     VerticalOneThree,
   ],
 })
diff --git a/src/layouts/layouts/pip/pip.component.ts b/src/layouts/layouts/pip/pip.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2c6799dd183d377bd94c8359f64dc1822918821a
--- /dev/null
+++ b/src/layouts/layouts/pip/pip.component.ts
@@ -0,0 +1,13 @@
+import { Component } from "@angular/core";
+
+@Component({
+  selector: 'picture-in-picture-panel',
+  templateUrl: './pip.template.html',
+  styleUrls: [
+    './pip.style.css',
+  ],
+})
+
+export class PictureInPicturePanel {
+
+}
diff --git a/src/layouts/layouts/pip/pip.style.css b/src/layouts/layouts/pip/pip.style.css
new file mode 100644
index 0000000000000000000000000000000000000000..5bb8aef140d3082787c1dd336c3ab3d94eff99c5
--- /dev/null
+++ b/src/layouts/layouts/pip/pip.style.css
@@ -0,0 +1,12 @@
+.major-column
+{
+  flex: 0 0 100%;
+}
+.minor-column
+{
+  flex: 0 0 0%;
+}
+.picture-in-picture-margin {
+  bottom: 50px;
+  right: 50px;
+}
\ No newline at end of file
diff --git a/src/layouts/layouts/pip/pip.template.html b/src/layouts/layouts/pip/pip.template.html
new file mode 100644
index 0000000000000000000000000000000000000000..df1e76de3f5d77f0f1f52b064dbe302b72c02172
--- /dev/null
+++ b/src/layouts/layouts/pip/pip.template.html
@@ -0,0 +1,8 @@
+<div class="w-100 h-100">
+  <ng-content select="[cell-i]"></ng-content>
+
+  <div class="position-fixed picture-in-picture-margin">
+    <ng-content select="[picture-in-picture]"></ng-content>
+  </div>
+
+</div>
diff --git a/src/state/userInterface/const.ts b/src/state/userInterface/const.ts
index 929102239aefb764442a329351c02542a293fe8b..404a37241e3b3d1eb4d9581a8839c7517679b1da 100644
--- a/src/state/userInterface/const.ts
+++ b/src/state/userInterface/const.ts
@@ -2,4 +2,5 @@ export const nameSpace = `[state.ui]`
 export type PanelMode = 'FOUR_PANEL'
 | 'V_ONE_THREE'
 | 'H_ONE_THREE'
-| 'SINGLE_PANEL'
\ No newline at end of file
+| 'SINGLE_PANEL'
+| 'PIP_PANEL'
\ No newline at end of file
diff --git a/src/state/userInterface/effects.ts b/src/state/userInterface/effects.ts
index 6a213f60a78cb2d648badd77d56be1f4a1e1e65a..6b5d98bdd6ea423fd59f0450e1f577902b6e4c4c 100644
--- a/src/state/userInterface/effects.ts
+++ b/src/state/userInterface/effects.ts
@@ -72,7 +72,7 @@ export class Effects{
     ),
     switchMap(([ { targetIndex }, panelMode ]) => {
       const newMode: userInterface.PanelMode = panelMode === "FOUR_PANEL"
-        ? "SINGLE_PANEL"
+        ? "PIP_PANEL"
         : "FOUR_PANEL"
       const newOrder = newMode === "FOUR_PANEL"
         ? "0123"
@@ -98,7 +98,7 @@ export class Effects{
         select(userInterface.selectors.panelOrder)
       ),
     ),
-    filter(([_, panelMode, _1]) => panelMode === "SINGLE_PANEL"),
+    filter(([_, panelMode, _1]) => ['SINGLE_PANEL', 'PIP_PANEL'].includes(panelMode)),
     map(([_, _1, panelOrder]) => userInterface.actions.setPanelOrder({
       order: [
         ...panelOrder.split('').slice(1),
diff --git a/src/ui/config/configCmp/config.component.ts b/src/ui/config/configCmp/config.component.ts
index 494403b61842914fa93cfd377d8aa2ffe907ca5f..3d1dfdce600504a6fb92b684560e61adb749d26e 100644
--- a/src/ui/config/configCmp/config.component.ts
+++ b/src/ui/config/configCmp/config.component.ts
@@ -34,6 +34,7 @@ export class ConfigComponent implements OnInit, OnDestroy {
     FOUR_PANEL: "FOUR_PANEL",
     H_ONE_THREE: "H_ONE_THREE",
     SINGLE_PANEL: "SINGLE_PANEL",
+    PIP_PANEL: "PIP_PANEL",
     V_ONE_THREE: "V_ONE_THREE",
   }
 
diff --git a/src/ui/config/configCmp/config.template.html b/src/ui/config/configCmp/config.template.html
index eab836a149b2f949cd154ea2e49fe572a90dca6b..85bbb90d53f68e253e52e99407245283417d4945 100644
--- a/src/ui/config/configCmp/config.template.html
+++ b/src/ui/config/configCmp/config.template.html
@@ -222,6 +222,23 @@
           previewTmpl: singlePanelTmpl
         }">
       </ng-template>
+
+      <!-- picture-in-picture -->
+      <ng-template #pipPanelTmpl>
+        <picture-in-picture-panel class="d-block w-10em h-7em">
+          <div class="border chunky" cell-i></div>
+          <div class="border chunky" cell-ii></div>
+          <div class="border chunky" cell-iii></div>
+          <div class="border chunky" cell-iv></div>
+        </picture-in-picture-panel>
+      </ng-template>
+      <ng-template [ngTemplateOutlet]="panelModeBtnTmpl"
+        [ngTemplateOutletContext]="{
+          panelMode: panelModes.PIP_PANEL,
+          previewTmpl: pipPanelTmpl
+        }">
+      </ng-template>
+      
     </div>
   </mat-tab>
 </mat-tab-group>
diff --git a/src/viewerModule/nehuba/layoutOverlay/module.ts b/src/viewerModule/nehuba/layoutOverlay/module.ts
index 4160b8d12d401b9acd2d7a0fc65f3af288d9261d..b19dbd7041aea8a179e4647155a8bcaaee6fa3b1 100644
--- a/src/viewerModule/nehuba/layoutOverlay/module.ts
+++ b/src/viewerModule/nehuba/layoutOverlay/module.ts
@@ -9,7 +9,6 @@ import { UtilModule } from "src/util";
 import { WindowResizeModule } from "src/util/windowResize";
 import { LayoutModule } from "src/layouts/layout.module";
 import { MatButtonModule } from "@angular/material/button";
-import { MatTooltipModule } from "@angular/material/tooltip";
 
 @NgModule({
   imports: [
@@ -22,7 +21,7 @@ import { MatTooltipModule } from "@angular/material/tooltip";
     UtilModule,
     WindowResizeModule,
     MatButtonModule,
-    MatTooltipModule,
+    MatMenuModule
   ],
   declarations: [
     NehubaLayoutOverlay,
diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
index 2fcf3b824328773660a44e725872f1aafd36dfd5..a6e58b8462cb398d87f2f6b26b61607110950f2d 100644
--- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
+++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts
@@ -3,10 +3,11 @@ import { select, Store } from "@ngrx/store";
 import { combineLatest, fromEvent, interval, merge, Observable, of, Subject, Subscription } from "rxjs";
 import { userInterface } from "src/state";
 import { NehubaViewerUnit } from "../../nehubaViewer/nehubaViewer.component";
-import { NEHUBA_INSTANCE_INJTKN, takeOnePipe, getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree } from "../../util";
+import { NEHUBA_INSTANCE_INJTKN, takeOnePipe, getFourPanel, getHorizontalOneThree, getSinglePanel, getPipPanel, getVerticalOneThree } from "../../util";
 import { QUICKTOUR_DESC, ARIA_LABELS, IDS } from 'common/constants'
 import { IQuickTourData } from "src/ui/quickTour/constrants";
 import { debounce, debounceTime, distinctUntilChanged, filter, map, mapTo, switchMap, take } from "rxjs/operators";
+import {panelOrder} from "src/state/userInterface/selectors";
 
 @Component({
   selector: `nehuba-layout-overlay`,
@@ -45,7 +46,7 @@ export class NehubaLayoutOverlay implements OnDestroy{
   }
 
   handleCycleViewEvent(): void {
-    if (this.currentPanelMode !== "SINGLE_PANEL") return
+    if (!["SINGLE_PANEL", 'PIP_PANEL'].includes(this.currentPanelMode)) return
     this.store$.dispatch(
       userInterface.actions.cyclePanelMode()
     )
@@ -111,6 +112,12 @@ export class NehubaLayoutOverlay implements OnDestroy{
 
   public volumeChunkLoading$: Subject<boolean> = new Subject()
 
+  public showPipPerspectiveView$ = this.store$.pipe(
+    select(panelOrder),
+    distinctUntilChanged(),
+    map(po => po[0] !== '3')
+  )
+
   constructor(
     private store$: Store,
     private cdr: ChangeDetectorRef,
@@ -126,7 +133,7 @@ export class NehubaLayoutOverlay implements OnDestroy{
   }
 
   private onNewNehubaUnit(nehubaUnit: NehubaViewerUnit){
-    
+
     while(this.nehubaUnitSubs.length) this.nehubaUnitSubs.pop().unsubscribe()
     this.nehubaViewPanels = []
     this.nanometersToOffsetPixelsFn = []
@@ -223,7 +230,7 @@ export class NehubaLayoutOverlay implements OnDestroy{
         this.panelMode$,
         this.panelOrder$,
       ]).pipe(
-        debounce(() => 
+        debounce(() =>
           nehubaUnit?.nehubaViewer?.ngviewer
             ? of(true)
             : interval(16).pipe(
@@ -232,19 +239,19 @@ export class NehubaLayoutOverlay implements OnDestroy{
             )
         )
       ).subscribe(([mode, panelOrder]) => {
-        
+
         this.currentPanelMode = mode as userInterface.PanelMode
         this.currentOrder = panelOrder
 
         const viewPanels = panelOrder.split('').map(v => Number(v)).map(idx => this.nehubaViewPanels[idx]) as [HTMLElement, HTMLElement, HTMLElement, HTMLElement]
-  
+
         /**
          * TODO smarter with event stream
          */
         if (!viewPanels.every(v => !!v)) {
           return
         }
-  
+
         switch (this.currentPanelMode) {
         case "H_ONE_THREE": {
           const element = removeExistingPanels()
@@ -270,12 +277,18 @@ export class NehubaLayoutOverlay implements OnDestroy{
           element.appendChild(newEl)
           break;
         }
+        case "PIP_PANEL": {
+          const element = removeExistingPanels()
+          const newEl = getPipPanel(viewPanels)
+          element.appendChild(newEl)
+          break;
+        }
         default:
         }
         for (const panel of viewPanels) {
           (panel as HTMLElement).classList.add('neuroglancer-panel')
         }
-  
+
         this.detectChanges()
         nehubaUnit.redraw()
       })
@@ -287,7 +300,7 @@ export class NehubaLayoutOverlay implements OnDestroy{
   public detectChanges(): void {
     this.cdr.detectChanges()
   }
-  
+
   private nehubaUnit: NehubaViewerUnit
 
   private findPanelIndex = (panel: HTMLElement) => this.viewPanelWeakMap.get(panel)
diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.style.css b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.style.css
index beea6a73ad8a3e22daa03c55a5d6022f175edda4..6d42ed6d58d79788b5f4188be14cb21379bf4246 100644
--- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.style.css
+++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.style.css
@@ -38,4 +38,4 @@ current-layout
 {
   opacity: 1.0 !important;
   pointer-events: all !important;
-}
+}
\ No newline at end of file
diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
index e43354b855f1e5ef945172019993701c1b6e8fa3..5ae334a2db080f80a983734c1004c3e3e46e231b 100644
--- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
+++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
@@ -25,6 +25,9 @@
     [quick-tour-order]="quickTour3dViewSlide.order">
     <ng-content *ngTemplateOutlet="ngPanelOverlayTmpl; context: { panelIndex: currentOrder | getProperty : 3 | parseAsNumber }"></ng-content>
   </div>
+  <div *ngIf="showPipPerspectiveView$ | async" class="w-100 h-100 position-relative" style="z-index: 100" picture-in-picture >
+    <nehuba-perspective-view-slider class="pe-all"></nehuba-perspective-view-slider>
+  </div>
 </current-layout>
 
 <!-- slice view overlay tmpl -->
@@ -113,7 +116,7 @@
     color="primary"
     (click)="toggleMaximiseMinimise(panelIndex)">
     <ng-template
-      [ngIf]="currentPanelMode === 'SINGLE_PANEL'"
+      [ngIf]="currentPanelMode === 'SINGLE_PANEL' || currentPanelMode === 'PIP_PANEL'"
       [ngIfElse]="expandTmpl">
       <i class="fas fa-compress"></i>
     </ng-template>
diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
index 4d38f0487b48b24a678e8a34b454d521d102e94e..465d3144979c3e6997e4dbefcb12f6009ab9ea21 100644
--- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
+++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
@@ -64,8 +64,8 @@ export class NehubaViewerUnit implements OnDestroy {
   public ngIdSegmentsMap: Record<string, number[]> = {}
 
   public viewerPosInVoxel$ = new BehaviorSubject(null)
-  public viewerPosInReal$ = new BehaviorSubject(null)
-  public mousePosInVoxel$ = new BehaviorSubject(null)
+  public viewerPosInReal$ = new BehaviorSubject<[number, number, number]>(null)
+  public mousePosInVoxel$ = new BehaviorSubject<[number, number, number]>(null)
   public mousePosInReal$ = new BehaviorSubject(null)
 
   private exportNehuba: any
@@ -76,7 +76,7 @@ export class NehubaViewerUnit implements OnDestroy {
   @Output() public nehubaReady: EventEmitter<null> = new EventEmitter()
   @Output() public layersChanged: EventEmitter<null> = new EventEmitter()
   private layersChangedHandler: any
-  @Output() public viewerPositionChange: EventEmitter<any> = new EventEmitter()
+  @Output() public viewerPositionChange: EventEmitter<{ orientation: number[], perspectiveOrientation: number[], perspectiveZoom: number, zoom: number, position: number[], positionReal?: boolean }> = new EventEmitter()
   @Output() public mouseoverSegmentEmitter:
     EventEmitter<{
       segmentId: number | null
@@ -814,7 +814,7 @@ export class NehubaViewerUnit implements OnDestroy {
       .filter(v => typeof v !== 'undefined' && v !== null)
       .subscribe(v => {
         this.navPosReal = Array.from(v) as [number, number, number]
-        this.viewerPosInReal$.next(Array.from(v))
+        this.viewerPosInReal$.next(Array.from(v) as [number, number, number])
       })
     this._s5$ = this.nehubaViewer.navigationState.position.inVoxels
       .filter(v => typeof v !== 'undefined' && v !== null)
@@ -832,7 +832,7 @@ export class NehubaViewerUnit implements OnDestroy {
       .filter(v => typeof v !== 'undefined' && v !== null)
       .subscribe(v => {
         this.mousePosVoxel = Array.from(v) as [number, number, number]
-        this.mousePosInVoxel$.next(Array.from(v))
+        this.mousePosInVoxel$.next(Array.from(v) as [number, number, number] )
       })
   }
 
diff --git a/src/viewerModule/nehuba/store/store.ts b/src/viewerModule/nehuba/store/store.ts
index 6782fa77c723fe8457f268df1d74f63535556b58..0dd7043f3ac0da58ad43d7211fcce3983d6b85d2 100644
--- a/src/viewerModule/nehuba/store/store.ts
+++ b/src/viewerModule/nehuba/store/store.ts
@@ -7,11 +7,12 @@ import { INehubaFeature } from "./type";
  * TODO port from global store to feature store
  */
 
-enum EnumPanelMode {
+export enum EnumPanelMode {
   FOUR_PANEL = 'FOUR_PANEL',
   V_ONE_THREE = 'V_ONE_THREE',
   H_ONE_THREE = 'H_ONE_THREE',
   SINGLE_PANEL = 'SINGLE_PANEL',
+  PIP_PANEL = 'PIP_PANEL',
 }
 
 const defaultState: INehubaFeature = {
diff --git a/src/viewerModule/nehuba/util.ts b/src/viewerModule/nehuba/util.ts
index 71d7a985a09c1ecfa3dd79fdac4c75f3c380bef9..1073c1bde8e78db2c490b44ab6bc17c65b8aab92 100644
--- a/src/viewerModule/nehuba/util.ts
+++ b/src/viewerModule/nehuba/util.ts
@@ -60,6 +60,13 @@ mapModeIdxClass.set("SINGLE_PANEL", new Map([
   [3, {}],
 ]))
 
+mapModeIdxClass.set("PIP_PANEL", new Map([
+  [0, { top, left, right, bottom }],
+  [1, {}],
+  [2, {}],
+  [3, {}],
+]))
+
 mapModeIdxClass.set("H_ONE_THREE", new Map([
   [0, { top, left, bottom }],
   [1, { top, right }],
@@ -144,16 +151,26 @@ export const getFourPanel = (panels: [HTMLElement, HTMLElement, HTMLElement, HTM
 export const getSinglePanel = (panels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement]): HTMLDivElement => {
   washPanels(panels)
 
+  return getFullViewPanel(panels)
+}
+
+export const getPipPanel = (panels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement]): HTMLDivElement => {
+  washPanels(panels)
+  
+  return getFullViewPanel(panels)
+}
+
+const getFullViewPanel = (panels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement]): HTMLDivElement => {
+
   panels.forEach((panel, idx) => addTouchSideClasses(panel, idx, "SINGLE_PANEL"))
 
   const majorContainer = makeRow(panels[0])
-  const minorContainer = makeRow(panels[1], panels[2], panels[3])
-
   majorContainer.style.flexBasis = '100%'
-  minorContainer.style.flexBasis = '0%'
 
+  const minorContainer = makeRow(panels[1], panels[2], panels[3])
+  minorContainer.style.flexBasis = '0%'
   minorContainer.className = ''
-  minorContainer.style.height = '0px'
+
   return makeRow(majorContainer, minorContainer)
 }
 
diff --git a/src/viewerModule/nehuba/viewerCtrl/effects.ts b/src/viewerModule/nehuba/viewerCtrl/effects.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1e62acc8e260133181cff0412135ccdf2a7846f6
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/effects.ts
@@ -0,0 +1,17 @@
+import { Injectable } from "@angular/core";
+import { createEffect } from "@ngrx/effects";
+import { Store } from "@ngrx/store";
+import { mapTo } from "rxjs/operators";
+import { atlasSelection, userInterface } from "src/state";
+
+@Injectable()
+export class ViewerCtrlEffects {
+  onTemplateChangeResetLayout$ = createEffect(() => this.store$.pipe(
+    atlasSelection.fromRootStore.distinctATP(),
+    mapTo(userInterface.actions.setPanelMode({
+      panelMode: "FOUR_PANEL"
+    }))
+  ))
+
+  constructor(private store$: Store){}
+}
diff --git a/src/viewerModule/nehuba/viewerCtrl/module.ts b/src/viewerModule/nehuba/viewerCtrl/module.ts
index 4052de0ac81de5cc6dd9effc75163429de938b4b..082107630ef288fa064e13bb3ec779094ee2abe3 100644
--- a/src/viewerModule/nehuba/viewerCtrl/module.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/module.ts
@@ -5,7 +5,11 @@ import { ComponentsModule } from "src/components";
 import { AngularMaterialModule } from "src/sharedModules";
 import { UtilModule } from "src/util";
 import { ViewerCtrlCmp } from "./viewerCtrlCmp/viewerCtrlCmp.component";
+import { PerspectiveViewSlider } from "./perspectiveViewSlider/perspectiveViewSlider.component";
 import { SnapPerspectiveOrientationCmp } from "src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component";
+import { WindowResizeModule } from "src/util/windowResize";
+import { EffectsModule } from "@ngrx/effects";
+import { ViewerCtrlEffects } from "./effects"
 
 @NgModule({
   imports: [
@@ -15,13 +19,19 @@ import { SnapPerspectiveOrientationCmp } from "src/viewerModule/nehuba/viewerCtr
     FormsModule,
     ReactiveFormsModule,
     ComponentsModule,
+    WindowResizeModule,
+    EffectsModule.forFeature([
+      ViewerCtrlEffects
+    ])
   ],
   declarations: [
     ViewerCtrlCmp,
-    SnapPerspectiveOrientationCmp
+    PerspectiveViewSlider,
+    SnapPerspectiveOrientationCmp,
   ],
   exports: [
-    ViewerCtrlCmp
+    ViewerCtrlCmp,
+    PerspectiveViewSlider
   ]
 })
 
diff --git a/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..56a3621904da2da3743b66e6b415cca5c2d70724
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.component.ts
@@ -0,0 +1,403 @@
+import { Component, OnDestroy, Inject, ViewChild, ChangeDetectionStrategy } from "@angular/core";
+import { FormControl } from "@angular/forms";
+import { select, Store } from "@ngrx/store";
+import { combineLatest, concat, NEVER, Observable, of, Subject, Subscription } from "rxjs";
+import { switchMap, distinctUntilChanged, map, debounceTime, shareReplay, take, withLatestFrom } from "rxjs/operators";
+import { SAPI, SapiSpaceModel } from "src/atlasComponents/sapi";
+import { fromRootStore } from "src/state/atlasSelection";
+import { selectedTemplate } from "src/state/atlasSelection/selectors";
+import { panelMode, panelOrder } from "src/state/userInterface/selectors";
+import { ResizeObserverDirective } from "src/util/windowResize";
+import { NehubaViewerUnit } from "../../nehubaViewer/nehubaViewer.component";
+import { EnumPanelMode } from "../../store/store";
+import { NEHUBA_INSTANCE_INJTKN } from "../../util";
+import { EnumClassicalView } from "src/atlasComponents/constants"
+import { atlasSelection } from "src/state";
+import { floatEquality } from "common/util"
+
+const MAX_DIM = 200
+
+type AnatomicalOrientation = 'ap' | 'si' | 'rl' // anterior-posterior, superior-inferior, right-left
+type RangeOrientation = 'horizontal' | 'vertical'
+const anatOriToIdx: Record<AnatomicalOrientation, number> = {
+  'rl': 0,
+  'ap': 1,
+  'si': 2
+}
+
+function getDim(triplet: number[], view: EnumClassicalView) {
+  if (view === EnumClassicalView.AXIAL) {
+    return [triplet[0], triplet[1]]
+  }
+  if (view === EnumClassicalView.CORONAL) {
+    return [triplet[0], triplet[2]]
+  }
+  if (view === EnumClassicalView.SAGITTAL) {
+    return [triplet[1], triplet[2]]
+  }
+}
+
+@Component({
+  selector: 'nehuba-perspective-view-slider',
+  templateUrl: './perspectiveViewSlider.template.html',
+  styleUrls: ['./perspectiveViewSlider.style.css'],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+
+export class PerspectiveViewSlider implements OnDestroy {
+
+    @ViewChild(ResizeObserverDirective)
+    resizeDirective: ResizeObserverDirective
+
+    public minimapControl = new FormControl()
+    public recalcViewportSize$ = new Subject()
+
+    private selectedTemplate$ = this.store$.pipe(
+      select(selectedTemplate),
+      distinctUntilChanged((o, n) => o?.["@id"] === n?.["@id"]),
+    )
+    private subscriptions: Subscription[] = []
+    private maximisedPanelIndex$ = combineLatest([
+      this.store$.pipe(
+        select(panelMode),
+        distinctUntilChanged(),
+      ),
+      this.store$.pipe(
+        select(panelOrder),
+        distinctUntilChanged(),
+      ),
+    ]).pipe(
+      map(([ mode, order ]) => {
+        if (!([EnumPanelMode.PIP_PANEL, EnumPanelMode.SINGLE_PANEL].includes(mode as EnumPanelMode))) {
+          return null
+        }
+        return Number(order[0])
+      })
+    )
+
+    private viewportSize$ = concat(
+      of(null), // emit on init
+      this.recalcViewportSize$,
+    ).pipe(
+      debounceTime(160),
+      map(() => {
+        const panel = document.getElementsByClassName('neuroglancer-panel') as HTMLCollectionOf<HTMLElement>
+        if (!(panel?.[0])) {
+          return null
+        }
+        return {
+          width: panel[0].offsetWidth,
+          height: panel[0].offsetHeight
+        }
+      }),
+      shareReplay(1),
+    )
+
+    private navPosition$: Observable<{real: [number, number, number], voxel: [number, number, number]}> = this.nehubaViewer$.pipe(
+      switchMap(viewer => {
+        if (!viewer) return of(null)
+        return combineLatest([
+          viewer.viewerPosInReal$,
+          viewer.viewerPosInVoxel$,
+        ]).pipe(
+          map(([ real, voxel ]) => {
+            return { real, voxel }
+          })
+        )
+      }),
+      shareReplay(1)
+    )
+
+    private rangeControlSetting$ = this.maximisedPanelIndex$.pipe(
+      map(maximisedPanelIndex => {
+        let anatomicalOrientation: AnatomicalOrientation = null
+        let rangeOrientation: RangeOrientation = null
+        let minimapView: EnumClassicalView
+        let sliceView: EnumClassicalView
+        if (maximisedPanelIndex === 0) {
+          anatomicalOrientation = 'ap'
+          rangeOrientation = 'horizontal'
+          minimapView = EnumClassicalView.SAGITTAL
+          sliceView = EnumClassicalView.CORONAL
+        }
+        if (maximisedPanelIndex === 1) {
+          anatomicalOrientation = 'rl'
+          rangeOrientation = 'horizontal'
+          minimapView = EnumClassicalView.CORONAL
+          sliceView = EnumClassicalView.SAGITTAL
+        }
+        if (maximisedPanelIndex === 2) {
+          anatomicalOrientation = 'si'
+          rangeOrientation = 'vertical'
+          minimapView = EnumClassicalView.CORONAL
+          sliceView = EnumClassicalView.AXIAL
+        }
+        return {
+          anatomicalOrientation,
+          rangeOrientation,
+          minimapView,
+          sliceView
+        }
+      })
+    )
+
+    public rangeControlIsVertical$ = this.rangeControlSetting$.pipe(
+      map(ctrl => ctrl?.rangeOrientation === "vertical")
+    )
+
+    private currentTemplateSize$ = this.store$.pipe(
+      fromRootStore.distinctATP(),
+      switchMap(({ atlas, template }) => 
+        atlas && template
+          ? this.sapi.getSpace(atlas['@id'], template['@id']).getTemplateSize()
+          : NEVER),
+    )
+
+    private useMinimap$: Observable<EnumClassicalView> = this.maximisedPanelIndex$.pipe(
+      map(maximisedPanelIndex => {
+        if (maximisedPanelIndex === 0) return EnumClassicalView.SAGITTAL
+        if (maximisedPanelIndex === 1) return EnumClassicalView.CORONAL
+        if (maximisedPanelIndex === 2) return EnumClassicalView.CORONAL
+        return null
+      })
+    )
+
+
+    // this crazy hack is required since firefox support vertical-orient
+    // do not and -webkit-slider-thumb#apperance cannot be used to hide the thumb
+    public rangeInputStyle$ = this.rangeControlIsVertical$.pipe(
+      withLatestFrom(this.currentTemplateSize$, this.useMinimap$),
+      map(([ isVertical, templateSizes, useMinimap ]) => {
+        if (!isVertical) return {}
+        const { real } = templateSizes
+        const [ width, height ] = getDim(real, useMinimap)
+        const max = Math.max(width, height)
+        const useHeight = width/max*MAX_DIM
+        const useWidth = height/max*MAX_DIM
+
+        const xformOriginVal = Math.min(useHeight, useWidth)/2
+        const transformOrigin = `${xformOriginVal}px ${xformOriginVal}px`
+
+        return {
+          height: `${useHeight}px`,
+          width: `${useWidth}px`,
+          transformOrigin,
+        }
+      })
+    )
+
+    public rangeControlMinMaxValue$ = this.currentTemplateSize$.pipe(
+      switchMap(templateSize => {
+        return this.rangeControlSetting$.pipe(
+          switchMap(orientation => this.navPosition$.pipe(
+            take(1),
+            map(nav => {
+              if (!nav || !orientation || !templateSize) return null
+              
+              const { real: realPos } = nav
+
+              const { anatomicalOrientation: anatOri } = orientation
+              const idx = anatOriToIdx[anatOri]
+              
+              const { real, transform } = templateSize
+              if (!transform || !transform[idx]) return null
+              const min = Math.round(transform[idx][3])
+              const max = Math.round(real[idx] + transform[idx][3])
+
+              return {
+                min, max, value: realPos[idx]
+              }
+            })
+          ))
+        )
+      }),
+    )
+  
+    public previewImageUrl$ = combineLatest([
+      this.selectedTemplate$,
+      this.useMinimap$,
+    ]).pipe(
+      map(([template, view]) => {
+        const url = getScreenshotUrl(template, view)
+        if (!url) return null
+        return `assets/images/persp-view/${url}`
+      })
+    )
+
+    public sliceviewIsNormal$ = this.store$.pipe(
+      select(atlasSelection.selectors.navigation),
+      map(navigation => {
+        // if navigation in store is nullish, assume starting position, ie slice view is normal
+        if (!navigation) return true
+        return [0, 0, 0, 1].every((v, idx) => floatEquality(navigation.orientation[idx], v,  1e-3))})
+    )
+
+    public textToDisplay$ = combineLatest([
+      this.sliceviewIsNormal$,
+      this.navPosition$,
+      this.maximisedPanelIndex$,
+    ]).pipe(
+      map(([ sliceviewIsNormal, nav, maximisedIdx ]) => {
+        if (!sliceviewIsNormal) return null
+        if (!(nav?.real) || (maximisedIdx === null)) return null
+        return `${(nav.real[maximisedIdx === 0? 1 : maximisedIdx === 1? 0 : 2] / 1e6).toFixed(3)}mm`
+      })
+    )
+
+    public scrubberPosition$ = this.rangeControlMinMaxValue$.pipe(
+      switchMap(minmaxval => concat(
+        of(null),
+        this.minimapControl.valueChanges,
+      ).pipe(
+        map(newval => {
+          if (!minmaxval) return null
+          const { min, max, value } = minmaxval
+          if (min === null || max === null) return null
+          const useValue = newval ?? value
+          if (useValue === null) return null
+          const translate = 100 * (useValue - min) / (max - min)
+          return `translateX(${translate}%)`
+        })
+      ))
+    )
+
+    public scrubberHighlighter$ = this.nehubaViewer$.pipe(
+      switchMap(viewer => combineLatest([
+        // on component init, the viewerPositionChange would not have fired
+        // in this case. So we get the zoom from the store as the first value
+        concat(
+          this.store$.pipe(
+            select(atlasSelection.selectors.navigation),
+            take(1)
+          ),
+          viewer
+            ? viewer.viewerPositionChange
+            : NEVER,
+        ),
+        this.viewportSize$,
+        this.rangeControlSetting$,
+        this.currentTemplateSize$,
+        this.rangeControlIsVertical$,
+      ]).pipe(
+        map(([ navigation, viewportSize, ctrl, templateSize, isVertical ]) => {
+          if (!ctrl || !(templateSize?.real) || !navigation) return null
+
+          const { zoom, position } = navigation
+
+          let translate: number = null
+          const { sliceView } = ctrl
+
+          const getTranslatePc = (idx: number) => {
+            const trueCenter = templateSize.real[idx] / 2
+            const compensate = trueCenter + templateSize.transform[idx][3]
+            return (position[idx] - compensate) / templateSize.real[idx]
+          }
+
+          let scale: number = 2
+          const sliceviewDim = getDim(templateSize.real, sliceView)
+          if (!sliceviewDim) return null
+
+          if (sliceView === EnumClassicalView.CORONAL) {
+            // minimap is sagittal view, so interested in superior-inferior axis
+            translate = getTranslatePc(2)
+            scale = Math.min(scale, viewportSize.height * zoom / sliceviewDim[1])
+          }
+
+          if (sliceView === EnumClassicalView.SAGITTAL) {
+            // minimap is coronal view, so interested in superior-inferior axis
+            translate = getTranslatePc(2)
+            scale = Math.min(scale, viewportSize.height * zoom / sliceviewDim[1])
+          }
+
+          if (sliceView === EnumClassicalView.AXIAL) {
+            // minimap  is in coronal view, so interested in left-right axis
+            translate = getTranslatePc(0) * -1
+            scale = Math.min(scale, viewportSize.width * zoom / sliceviewDim[0])
+          }
+
+          /**
+           * calculate scale
+           */
+          const scaleString = `scaleY(${scale})`
+
+          /**
+           * calculate translation
+           */
+          const translateString = `translateY(${translate * -100}%)`
+
+          return `${translateString} ${scaleString}`
+        })
+      ))
+    )
+
+    constructor(
+      private store$: Store,
+      private sapi: SAPI,
+      @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaViewer$: Observable<NehubaViewerUnit>,
+    ) {
+
+      this.subscriptions.push(
+        combineLatest([
+          this.nehubaViewer$,
+          this.rangeControlSetting$,
+        ]).pipe(
+          switchMap(([ nehubaViewer, rangeCtrl ]) => this.minimapControl.valueChanges.pipe(
+            withLatestFrom(this.navPosition$.pipe(
+              map(value => value?.real)
+            )),
+            map(([newValue, currentPosition]) => ({ nehubaViewer, rangeCtrl, newValue, currentPosition }))
+          ))
+        ).subscribe(({ nehubaViewer, rangeCtrl, newValue, currentPosition }) => {
+          if (newValue === null) return
+          const { anatomicalOrientation } = rangeCtrl
+          if (!anatomicalOrientation) return
+          const idx = anatOriToIdx[anatomicalOrientation]
+          const newNavPosition = [...currentPosition]
+          newNavPosition[idx] = newValue
+          nehubaViewer.setNavigationState({
+            position: newNavPosition,
+            positionReal: true
+          })
+        }),
+      )
+    }
+
+    ngOnDestroy(): void {
+      this.subscriptions.forEach(s => s.unsubscribe());
+    }
+
+    resetSliceview() {
+      this.store$.dispatch(
+        atlasSelection.actions.navigateTo({
+          animation: true,
+          navigation: {
+            orientation: [0, 0, 0, 1]
+          }
+        })
+      )
+    }
+  
+}
+
+const spaceIdToPrefix = {
+  "minds/core/referencespace/v1.0.0/dafcffc5-4826-4bf1-8ff6-46b8a31ff8e2": "icbm152",
+  "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992": "colin",
+  "minds/core/referencespace/v1.0.0/a1655b99-82f1-420f-a3c2-fe80fd4c8588": "bigbrain",
+  "minds/core/referencespace/v1.0.0/MEBRAINS": "monkey",
+  "minds/core/referencespace/v1.0.0/265d32a0-3d84-40a5-926f-bf89f68212b9": "mouse",
+  "minds/core/referencespace/v1.0.0/d5717c4a-0fa1-46e6-918c-b8003069ade8": "rat"
+}
+
+const viewToSuffix = {
+  [EnumClassicalView.SAGITTAL]: 'sag',
+  [EnumClassicalView.AXIAL]: 'axial',
+  [EnumClassicalView.CORONAL]: 'coronal',
+}
+
+function getScreenshotUrl(space: SapiSpaceModel, requestedView: EnumClassicalView): string {
+  const prefix = spaceIdToPrefix[space?.['@id']]
+  if (!prefix) return null
+  const suffix = viewToSuffix[requestedView]
+  if (!suffix) return null
+  return `${prefix}-${suffix}.png`
+}
diff --git a/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.style.css b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.style.css
new file mode 100644
index 0000000000000000000000000000000000000000..bfd1bed6c8b4592410adbbec683998324635b60b
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.style.css
@@ -0,0 +1,100 @@
+:host
+{
+    display: inline-block;
+    background-size: cover;
+    position: relative;
+    overflow: hidden;
+
+    border: 1px solid rgba(200, 200, 200, 0.5);
+    border-radius: 0.25rem;
+
+    opacity: 0.7;
+    transition: all 160ms ease-in-out;
+}
+
+:host:hover
+{
+    opacity: 1.0;
+}
+
+img
+{
+    max-width: 200px;
+    max-height: 200px;
+    aspect-ratio: auto;
+}
+
+.range-container,
+.range-input-wrapper
+{
+    width: 100%;
+    height: 100%;
+}
+
+
+.anchored
+{
+    position: absolute;
+    left: 0;
+    top: 0;
+}
+
+.perspective-slider-range-input
+{
+    appearance: none;
+    width: 100%;
+    height: 100%;
+    
+    background: transparent;
+}
+
+.scrubber
+{
+    pointer-events: none;
+    width: 100%;
+    height: 100%;
+    display: inline-block;
+
+    border-style: solid;
+    border-width: 0 0 0 0.5rem;
+    margin-left: -0.25rem;
+
+    border-color: rgba(10, 10, 10, 0.5);
+}
+
+:host-context([darktheme="true"]) .scrubber
+{
+    border-color: rgba(200, 200, 200, 0.5);
+}
+
+.scrubber > .scrubber-highlight
+{
+    background-color: red;
+    display: inline-block;
+    height: 100%;
+    width: 0.5rem;
+    margin-left: -0.5rem;
+}
+
+
+.perspective-slider-range-input::-webkit-slider-thumb {
+    appearance: none;
+    height: 100%;
+    width: 1px;
+}
+
+.perspective-slider-range-input::-moz-range-thumb {
+    appearance: none;
+    height: 100%;
+    width: 1px;
+}
+.perspective-slider-range-input:focus {
+    outline: none; 
+}
+
+
+.range-value {
+    right: 10px;
+    bottom: 5px;
+}
+
diff --git a/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.template.html b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.template.html
new file mode 100644
index 0000000000000000000000000000000000000000..a439a62f03872271b8eba33222c732bfcdec1b42
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/perspectiveViewSlider/perspectiveViewSlider.template.html
@@ -0,0 +1,46 @@
+<div class="range-container"
+  *ngIf="sliceviewIsNormal$ | async else resetOrientationTmpl">
+  <img *ngIf="previewImageUrl$ | async as url" [src]="url">
+
+  <div class="range-input-wrapper anchored"
+    [style]="rangeInputStyle$ | async"
+    [ngClass]="{
+      'r-270': rangeControlIsVertical$ | async
+    }">
+
+    <input type="range"
+      *ngIf="rangeControlMinMaxValue$ | async as minMaxValue"
+      iav-window-resize
+      (iav-window-resize-event)="recalcViewportSize$.next($event)"
+      [min]="minMaxValue.min"
+      [max]="minMaxValue.max"
+      [value]="minMaxValue.value"
+      [formControl]="minimapControl"
+      class="anchored perspective-slider-range-input"
+      >
+
+    <div *ngIf="scrubberPosition$ | async as transform"
+      [style.transform]="transform"
+      class="anchored scrubber">
+      <div *ngIf="scrubberHighlighter$ | async as highlighter"
+        [style.transform]="highlighter" class="scrubber-highlight">
+      </div>
+    </div>
+  </div>
+</div>
+
+<ng-template #resetOrientationTmpl>
+  <div class="sxplr-custom-cmp text sxplr-p-2 bg">
+    Minimap disabled until orientation is reset.
+
+    <button mat-button
+      (click)="resetSliceview()">
+      Reset Orientation
+    </button>
+  </div>
+</ng-template>
+
+<div *ngIf="textToDisplay$ | async as textToDisplay"
+  class="position-absolute range-value sxplr-custom-cmp text">
+  {{ textToDisplay }}
+</div>
diff --git a/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts
index 6d936f0c3b2c62c21de377b7205676d56c2eee33..788341d055ef930840cbd23f39a5e324c0f9d58c 100644
--- a/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts
@@ -6,12 +6,7 @@ import { actions } from 'src/state/atlasSelection';
 import { VALUES } from "common/constants"
 import { floatEquality } from "common/util"
 import { filter, map } from 'rxjs/operators';
-
-enum EnumClassicalView {
-  CORONAL = "Coronal",
-  SAGITTAL = "Sagittal",
-  AXIAL = "Axial",
-}
+import { EnumClassicalView } from "src/atlasComponents/constants"
 
 const viewOrientations : Record<EnumClassicalView, number[][]> = {
   [EnumClassicalView.CORONAL]: [[0,-1 * VALUES.ROOT_2,VALUES.ROOT_2,0], [-1 * VALUES.ROOT_2,0,0,VALUES.ROOT_2]],