diff --git a/docs/releases/v2.12.2.md b/docs/releases/v2.12.2.md
new file mode 100644
index 0000000000000000000000000000000000000000..e232505af83b9698261e761af4e89fdccc42f7cc
--- /dev/null
+++ b/docs/releases/v2.12.2.md
@@ -0,0 +1,8 @@
+# v2.12.2
+
+## Bugfixes
+
+- fixes screenshot in fsaverage
+- on hover region label in fsaverage now display properly
+- fixes annotation mode (export annotations, annotations fail to render in viewer on startup (via shared link, local storage etc))
+- fixes an issue where region definition in full assignment table can also be clicked to select the region
diff --git a/mkdocs.yml b/mkdocs.yml
index 207b2580cd9132c87e0721534a3a192cbbfd4711..3b54fefc8324bbd99777bc67e61f5ec46d8865c2 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -33,6 +33,7 @@ nav:
     - Fetching datasets: 'advanced/datasets.md'
     - Display non-atlas volumes: 'advanced/otherVolumes.md'
   - Release notes:
+    - v2.12.2: 'releases/v2.12.2.md'
     - v2.12.1: 'releases/v2.12.1.md'
     - v2.12.0: 'releases/v2.12.0.md'
     - v2.11.4: 'releases/v2.11.4.md'
diff --git a/package.json b/package.json
index 5314a2daa6a1cc8d13088e24bd5568e42ab66b97..5746b8bb314805db1ef23fd255cbd2cfc2f07315 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "siibra-explorer",
-  "version": "2.12.1",
+  "version": "2.12.2",
   "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/atlasComponents/annotations/annotation.service.ts b/src/atlasComponents/annotations/annotation.service.ts
index 543271a3a11ac766c9f194152d06b3c497a26a4f..d133671c3682ccf16c5af36271a12b90fbb4cf73 100644
--- a/src/atlasComponents/annotations/annotation.service.ts
+++ b/src/atlasComponents/annotations/annotation.service.ts
@@ -1,6 +1,6 @@
 import { BehaviorSubject, Observable } from "rxjs";
 import { distinctUntilChanged } from "rxjs/operators";
-import { getUuid } from "src/util/fn";
+import { getUuid, waitFor } from "src/util/fn";
 import { PeriodicSvc } from "src/util/periodic.service";
 
 export type TNgAnnotationEv = {
@@ -144,8 +144,8 @@ export class AnnotationLayer {
       return false
     })
   }
-  removeAnnotation(spec: { id: string }) {
-    if (!this.nglayer) return
+  async removeAnnotation(spec: { id: string }) {
+    await waitFor(() => !!this.nglayer?.layer?.localAnnotations)
     const { localAnnotations } = this.nglayer.layer
     this.idset.delete(spec.id)
     const ref = localAnnotations.references.get(spec.id)
@@ -155,8 +155,8 @@ export class AnnotationLayer {
     }
   }
   async updateAnnotation(spec: AnnotationSpec) {
-    const localAnnotations = this.nglayer?.layer?.localAnnotations
-    if (!localAnnotations) return
+    await waitFor(() => !!this.nglayer?.layer?.localAnnotations)
+    const { localAnnotations } = this.nglayer.layer
     const ref = localAnnotations.references.get(spec.id)
     const _spec = this.parseNgSpecType(spec)
     if (ref) {
diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html
index 59694f74a9f84f067a93a56eb0f0d9988895d8e1..f031edbf5a99879f0041c02a545f234d0b4cd71a 100644
--- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html
+++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html
@@ -58,15 +58,31 @@
             #comphTableSort="matSort"
             matSortActive="map value"
             matSortDirection="desc">
-            <ng-container *ngFor="let column of columns$ | async"
-                [matColumnDef]="column">
+            
+            <ng-container matColumnDef="region">
                 <th mat-header-cell *matHeaderCellDef mat-sort-header>
-                    {{ column }}
+                    region
                 </th>
                 <td mat-cell *matCellDef="let element">
-                    {{ element[column] | prettyPresent }}
+                    <button mat-button (click)="selectRegion(element['region'], $event)">
+                        {{ element['region'].name }}
+                    </button>
                 </td>
             </ng-container>
+
+            <ng-template ngFor [ngForOf]="columns$ | async" let-column>
+                <ng-template [ngIf]="column !== 'region'">
+                    <ng-container [matColumnDef]="column">
+                        <th mat-header-cell *matHeaderCellDef mat-sort-header>
+                            {{ column }}
+                        </th>
+                        <td mat-cell *matCellDef="let element">
+                            {{ element[column] | prettyPresent }}
+                        </td>
+                    </ng-container>
+                </ng-template>
+            </ng-template>
+            
         
             <tr mat-header-row *matHeaderRowDef="columns$ | async"></tr>
             <tr mat-row *matRowDef="let row; columns: columns$ | async;"></tr>
diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts
index 64b0ebdb1a71bdbf9baf0d0d4c687df6afa71cae..00ee69f552743fe8cd9a771dbfb44e6cd00ced89 100644
--- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts
+++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts
@@ -1,5 +1,5 @@
 import { Component, Input, OnDestroy, Output, TemplateRef, EventEmitter } from '@angular/core';
-import { MatDialog } from '@angular/material/dialog';
+import { MatDialog, MatDialogRef } from '@angular/material/dialog';
 import { BehaviorSubject, EMPTY, Observable, Subscription, combineLatest, concat, of } from 'rxjs';
 import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators';
 import { SAPI, EXPECTED_SIIBRA_API_VERSION } from 'src/atlasComponents/sapi/sapi.service';
@@ -114,8 +114,12 @@ export class PointAssignmentComponent implements OnDestroy {
 
   constructor(private sapi: SAPI, private dialog: MatDialog) {}
 
+  #dialogRef: MatDialogRef<unknown>
   openDialog(tmpl: TemplateRef<unknown>){
-    this.dialog.open(tmpl)
+    this.#dialogRef = this.dialog.open(tmpl)
+    this.#dialogRef.afterClosed().subscribe(() => {
+      this.#dialogRef = null
+    })
   }
 
   #sub: Subscription[] = []
@@ -125,6 +129,9 @@ export class PointAssignmentComponent implements OnDestroy {
   async selectRegion(region: PathReturn<"/regions/{region_id}">, event: MouseEvent){
     const sxplrReg = await translateV3Entities.translateRegion(region)
     this.clickOnRegion.emit({ target: sxplrReg, event })
+    if (this.#dialogRef) {
+      this.#dialogRef.close()
+    }
   }
 
   zipfileConfig$: Observable<TZipFileConfig[]> = combineLatest([
diff --git a/src/atlasComponents/userAnnotations/annotationList/annotationList.component.spec.ts b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23662fcfdf9d305ec6daa00710944996af46b7fd
--- /dev/null
+++ b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.spec.ts
@@ -0,0 +1,117 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing"
+import { AnnotationList } from "./annotationList.component"
+import { FileInputModule } from "src/getFileInput/module"
+import { CommonModule } from "@angular/common"
+import { ModularUserAnnotationToolService } from "../tools/service"
+import { NoopAnimationsModule } from "@angular/platform-browser/animations"
+import { MatDialogModule } from "@angular/material/dialog"
+import { ComponentStore } from "@ngrx/component-store"
+import { NEVER, of } from "rxjs"
+import { MatSnackBarModule } from "@angular/material/snack-bar"
+import { StateModule } from "src/state"
+import { hot } from "jasmine-marbles"
+import { IAnnotationGeometry } from "../tools/type"
+import { MatTooltipModule } from "@angular/material/tooltip"
+import { MatButtonModule } from "@angular/material/button"
+import { MatCardModule } from "@angular/material/card"
+import { ZipFilesOutputModule } from "src/zipFilesOutput/module"
+import { AnnotationVisiblePipe } from "../annotationVisible.pipe"
+import { SingleAnnotationClsIconPipe, SingleAnnotationNamePipe } from "../singleAnnotationUnit/singleAnnotationUnit.component"
+import { MatExpansionModule } from "@angular/material/expansion"
+
+class MockModularUserAnnotationToolService {
+  hiddenAnnotations$ = of([])
+  toggleAnnotationVisibilityById = jasmine.createSpy()
+  parseAnnotationObject = jasmine.createSpy()
+  importAnnotation = jasmine.createSpy()
+  spaceFilteredManagedAnnotations$ = NEVER
+  rSpaceManagedAnnotations$ = NEVER
+  otherSpaceManagedAnnotations$ = NEVER
+}
+
+const readmeContent = `{id}.sands.json file contains the data of annotations. {id}.desc.json contains the metadata of annotations.`
+
+describe("annotationList.component.ts", () => {
+  let component: AnnotationList;
+  let fixture: ComponentFixture<AnnotationList>;
+
+  describe("AnnotationList", () => {
+    beforeEach(async () => {
+      await TestBed.configureTestingModule({
+        imports: [
+          CommonModule,
+          FileInputModule,
+          NoopAnimationsModule,
+          MatDialogModule,
+          MatSnackBarModule,
+          StateModule, // needed for iavStateAggregator directive
+          MatTooltipModule,
+          MatButtonModule,
+          MatCardModule,
+          MatExpansionModule,
+          ZipFilesOutputModule,
+        ],
+        providers: [
+          ComponentStore,
+          {
+            provide: ModularUserAnnotationToolService,
+            useClass: MockModularUserAnnotationToolService
+          }
+        ],
+        declarations: [
+          AnnotationList,
+          AnnotationVisiblePipe,
+          SingleAnnotationNamePipe,
+          SingleAnnotationClsIconPipe,
+        ]
+      }).compileComponents()
+    })
+    it("> can be init", () => {
+      
+      fixture = TestBed.createComponent(AnnotationList)
+      component = fixture.componentInstance
+      fixture.detectChanges()
+      expect(component).toBeTruthy()
+    })
+
+    describe("> filesExport$", () => {
+      beforeEach(() => {
+        const svc = TestBed.inject(ModularUserAnnotationToolService)
+
+        const dummyGeom: Partial<IAnnotationGeometry> = {
+          id: 'foo',
+          toSands() {
+            return {} as any
+          },
+          toMetadata() {
+            return {} as any
+          },
+          toJSON() {
+            return {}
+          }
+        }
+        svc.spaceFilteredManagedAnnotations$ = of([dummyGeom] as IAnnotationGeometry[])
+      })
+      it("> do not emit duplicated values", () => {
+        
+        fixture = TestBed.createComponent(AnnotationList)
+        component = fixture.componentInstance
+        
+        expect(component.filesExport$).toBeObservable(
+          hot('(a|)', {
+            a: [{
+              filename: 'README.md',
+              filecontent: readmeContent
+            }, {
+              filename: `foo.sands.json`,
+              filecontent: '{}'
+            }, {
+              filename: `foo.desc.json`,
+              filecontent: '{}'
+            }],
+          })
+        )
+      })
+    })
+  })
+})
diff --git a/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts
index bad568f3822e640174da67c0162142b3a2188894..7463f9a105d179f96eb273d1880e2facda9a9155 100644
--- a/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts
+++ b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts
@@ -3,8 +3,8 @@ import { ARIA_LABELS, CONST } from "common/constants";
 import { ModularUserAnnotationToolService } from "../tools/service";
 import { IAnnotationGeometry, TExportFormats } from "../tools/type";
 import { ComponentStore } from "src/viewerModule/componentStore";
-import { map, shareReplay, startWith } from "rxjs/operators";
-import { combineLatest, Observable, Subscription } from "rxjs";
+import { debounceTime, map, shareReplay, startWith } from "rxjs/operators";
+import { combineLatest, concat, Observable, of, Subscription } from "rxjs";
 import { TZipFileConfig } from "src/zipFilesOutput/type";
 import { TFileInputEvent } from "src/getFileInput/type";
 import { FileInputDirective } from "src/getFileInput/getFileInput.directive";
@@ -44,9 +44,11 @@ export class AnnotationList {
     startWith(false)
   )
 
-  public filesExport$: Observable<TZipFileConfig[]> = this.managedAnnotations$.pipe(
-    startWith([] as IAnnotationGeometry[]),
-    shareReplay(1),
+  public filesExport$: Observable<TZipFileConfig[]> = concat(
+    of([] as IAnnotationGeometry[]),
+    this.managedAnnotations$
+  ).pipe(
+    debounceTime(0),
     map(manAnns => {
       const readme = {
         filename: 'README.md',
@@ -61,11 +63,12 @@ export class AnnotationList {
       const annotationDesc = manAnns.map(ann => {
         return {
           filename: `${ann.id}.desc.json`,
-          filecontent: JSON.stringify(this.annotSvc.exportAnnotationMetadata(ann), null, 2)
+          filecontent: JSON.stringify(ann.toMetadata(), null, 2)
         }
       })
       return [ readme, ...annotationSands, ...annotationDesc ]
-    })
+    }),
+    shareReplay(1),
   )
   constructor(
     private annotSvc: ModularUserAnnotationToolService,
@@ -82,10 +85,10 @@ export class AnnotationList {
       this.managedAnnotations$.subscribe(anns => this.managedAnnotations = anns),
       combineLatest([
         this.managedAnnotations$.pipe(
-          startWith([])
+          startWith([] as IAnnotationGeometry[])
         ),
         this.annotationInOtherSpaces$.pipe(
-          startWith([])
+          startWith([] as IAnnotationGeometry[])
         )
       ]).subscribe(([ann, annOther]) => {
         this.userAnnRoute = {
diff --git a/src/atlasComponents/userAnnotations/tools/line.ts b/src/atlasComponents/userAnnotations/tools/line.ts
index c156a9e09544fb3e82b50820f49d50668a4ea094..9223b1d989aacccab83e470f9145aca1b81674a9 100644
--- a/src/atlasComponents/userAnnotations/tools/line.ts
+++ b/src/atlasComponents/userAnnotations/tools/line.ts
@@ -78,11 +78,12 @@ export class Line extends IAnnotationGeometry{
       x: x1, y: y1, z: z1
     } = this.points[1]
 
+    const { id } = this.space
     return {
       '@id': this.id,
       '@type': "tmp/line",
       coordinateSpace: {
-        '@id': this.space["@id"]
+        '@id': id
       },
       coordinatesFrom: [getCoord(x0/1e6), getCoord(y0/1e6), getCoord(z0/1e6)],
       coordinatesTo: [getCoord(x1/1e6), getCoord(y1/1e6), getCoord(z1/1e6)],
diff --git a/src/atlasComponents/userAnnotations/tools/point.ts b/src/atlasComponents/userAnnotations/tools/point.ts
index 58d8cdde8acd05863e682814e37f8d667124e36e..5086a30459665423439da1b8ee6cbb2fe51d35df 100644
--- a/src/atlasComponents/userAnnotations/tools/point.ts
+++ b/src/atlasComponents/userAnnotations/tools/point.ts
@@ -82,12 +82,13 @@ export class Point extends IAnnotationGeometry {
   }
 
   toSands(): TSandsPoint{
+    const { id } = this.space
     const {x, y, z} = this
     return {
       '@id': this.id,
       '@type': 'https://openminds.ebrains.eu/sands/CoordinatePoint',
       coordinateSpace: {
-        '@id': this.space["@id"]
+        '@id': id
       },
       coordinates:[ getCoord(x/1e6), getCoord(y/1e6), getCoord(z/1e6) ]
     }
diff --git a/src/atlasComponents/userAnnotations/tools/poly.ts b/src/atlasComponents/userAnnotations/tools/poly.ts
index 244c71a6a2d11163ba70af11727adcefd1ac399f..4bc86182aa6849161b384923cabd24d76534f502 100644
--- a/src/atlasComponents/userAnnotations/tools/poly.ts
+++ b/src/atlasComponents/userAnnotations/tools/poly.ts
@@ -94,11 +94,12 @@ export class Polygon extends IAnnotationGeometry{
   }
 
   toSands(): TSandsPolyLine{
+    const { id } = this.space
     return {
       "@id": this.id,
       "@type": 'tmp/poly',
       coordinateSpace: {
-        '@id': this.space["@id"],
+        '@id': id,
       },
       coordinates: this.points.map(p => {
         const { x, y, z } = p
diff --git a/src/atlasComponents/userAnnotations/tools/service.spec.ts b/src/atlasComponents/userAnnotations/tools/service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fdeacfde828aff2d09b31c81fd9b7e2de5baae63
--- /dev/null
+++ b/src/atlasComponents/userAnnotations/tools/service.spec.ts
@@ -0,0 +1,43 @@
+import { TestBed } from "@angular/core/testing"
+import { ModularUserAnnotationToolService } from "./service"
+import { MockStore, provideMockStore } from "@ngrx/store/testing"
+import { NoopAnimationsModule } from "@angular/platform-browser/animations"
+import { MatSnackBarModule } from "@angular/material/snack-bar"
+import { ANNOTATION_EVENT_INJ_TOKEN, INJ_ANNOT_TARGET } from "./type"
+import { NEVER, Subject } from "rxjs"
+import { atlasSelection } from "src/state"
+
+describe("userAnnotations/service.ts", () => {
+
+  describe("ModularUserAnnotationToolService", () => {
+    let service: ModularUserAnnotationToolService
+    beforeEach(() => {
+      TestBed.configureTestingModule({
+        imports: [
+          NoopAnimationsModule,
+          MatSnackBarModule,
+        ],
+        providers: [
+          provideMockStore(),
+          {
+            provide: INJ_ANNOT_TARGET,
+            useValue: NEVER
+          },
+          {
+            provide: ANNOTATION_EVENT_INJ_TOKEN,
+            useValue: new Subject()
+          },
+          ModularUserAnnotationToolService
+        ]
+      })
+
+      const mStore = TestBed.inject(MockStore)
+      mStore.overrideSelector(atlasSelection.selectors.selectedTemplate, null)
+      mStore.overrideSelector(atlasSelection.selectors.viewerMode, null)
+    })
+    it("> can be init", () => {
+      const svc = TestBed.inject(ModularUserAnnotationToolService)
+      expect(svc).toBeDefined()
+    })
+  })
+})
diff --git a/src/atlasComponents/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts
index 03f0f060e620f05897e380044ef381bea50c5c71..9ef8d363ac2a1201e28854b1b940d44967f5def6 100644
--- a/src/atlasComponents/userAnnotations/tools/service.ts
+++ b/src/atlasComponents/userAnnotations/tools/service.ts
@@ -6,7 +6,7 @@ import { BehaviorSubject, combineLatest, fromEvent, merge, Observable, of, Subje
 import {map, switchMap, filter, shareReplay, pairwise, withLatestFrom } from "rxjs/operators";
 import { NehubaViewerUnit } from "src/viewerModule/nehuba";
 import { NEHUBA_INSTANCE_INJTKN } from "src/viewerModule/nehuba/util";
-import { AbsToolClass, ANNOTATION_EVENT_INJ_TOKEN, IAnnotationEvents, IAnnotationGeometry, INgAnnotationTypes, INJ_ANNOT_TARGET, TAnnotationEvent, ClassInterface, TCallbackFunction, TSands, TGeometryJson, TCallback } from "./type";
+import { AbsToolClass, ANNOTATION_EVENT_INJ_TOKEN, IAnnotationEvents, IAnnotationGeometry, INgAnnotationTypes, INJ_ANNOT_TARGET, TAnnotationEvent, ClassInterface, TCallbackFunction, TSands, TGeometryJson, TCallback, DESC_TYPE } from "./type";
 import { getExportNehuba, switchMapWaitFor } from "src/util/fn";
 import { Polygon } from "./poly";
 import { Line } from "./line";
@@ -27,7 +27,6 @@ type TAnnotationMetadata = {
   desc: string
 }
 
-const descType = 'siibra-ex/meta/desc' as const
 type TTypedAnnMetadata = {
   '@type': 'siibra-ex/meta/desc'
 } & TAnnotationMetadata
@@ -325,21 +324,22 @@ export class ModularUserAnnotationToolService implements OnDestroy{
     /**
      * on new nehubaViewer, unset annotationLayer
      */
-    this.subscription.push(
-      nehubaViewer$.subscribe(() => {
-        this.annotationLayer = null
-      })
-    )
-
-    /**
-     * get mouse real position
-     */
-    this.subscription.push(
-      nehubaViewer$.pipe(
-        switchMap(v => v?.mousePosInReal$ || of(null))
-      ).subscribe(v => this.mousePosReal = v)
-    )
-
+    if (!!nehubaViewer$) {
+      this.subscription.push(
+        nehubaViewer$.subscribe(() => {
+          this.annotationLayer = null
+        })
+      )
+  
+      /**
+       * get mouse real position
+       */
+      this.subscription.push(
+        nehubaViewer$.pipe(
+          switchMap(v => v?.mousePosInReal$ || of(null))
+        ).subscribe(v => this.mousePosReal = v)
+      )  
+    }
     /**
      * on mouse move, render preview annotation
      */
@@ -410,13 +410,9 @@ export class ModularUserAnnotationToolService implements OnDestroy{
         })),
       )
     ]).pipe(
-      map(([_, annts]) => {
-        const out = []
-        for (const ann of annts) {
-          out.push(...ann.toNgAnnotation())
-        }
-        return out
-      }),
+      map(([_, annts]) => 
+        annts.map(ann => ann.toNgAnnotation()).flatMap(v => v)
+      ),
       shareReplay(1),
     )
     this.subscription.push(
@@ -552,15 +548,6 @@ export class ModularUserAnnotationToolService implements OnDestroy{
     }
   }
 
-  public exportAnnotationMetadata(ann: IAnnotationGeometry): TAnnotationMetadata & { '@type': 'siibra-ex/meta/desc' } {
-    return {
-      '@type': descType,
-      id: ann.id,
-      name: ann.name,
-      desc: ann.desc,
-    }
-  }
-
   /**
    * stop gap measure when exporting/import annotations in sands format
    * metadata (name/desc) will be saved in a separate metadata file
@@ -650,7 +637,7 @@ export class ModularUserAnnotationToolService implements OnDestroy{
     if (json['@type'] === 'siibra-ex/annotation/polyline') {
       returnObj = Polygon.fromJSON(json)
     }
-    if (json['@type'] === descType) {
+    if (json['@type'] === DESC_TYPE) {
       const existingAnn = this.managedAnnotations.find(ann => json.id === ann.id)
       if (existingAnn) {
 
diff --git a/src/atlasComponents/userAnnotations/tools/type.ts b/src/atlasComponents/userAnnotations/tools/type.ts
index e2abb6f9cf4b745180c5d971ccd8a36178637388..d54b231afd55ca503430125855acdc6701c3fb72 100644
--- a/src/atlasComponents/userAnnotations/tools/type.ts
+++ b/src/atlasComponents/userAnnotations/tools/type.ts
@@ -9,6 +9,8 @@ import { TSandsCoord, TSandsPoint } from "src/util/types"
 
 export { getCoord, TSandsPoint } from "src/util/types"
 
+export const DESC_TYPE = 'siibra-ex/meta/desc' as const
+
 type TRecord = Record<string, unknown>
 
 /**
@@ -311,6 +313,15 @@ export abstract class IAnnotationGeometry extends Highlightable {
   abstract toString(): string
   abstract toSands(): ISandsAnnotation[keyof ISandsAnnotation]
 
+  toMetadata(){
+    return {
+      '@type': DESC_TYPE,
+      id: this.id,
+      name: this.name,
+      desc: this.desc,
+    }
+  }
+
   public remove() {
     throw new Error(`The remove method needs to be overwritten by the tool manager`)
   }
diff --git a/src/ui/ui.module.ts b/src/ui/ui.module.ts
index 2e083c87bbc17a268a43c2aba3cf1dd90acc5018..98efd3854b801b7cffe5d1720ffc32fab5ea32d7 100644
--- a/src/ui/ui.module.ts
+++ b/src/ui/ui.module.ts
@@ -40,11 +40,21 @@ import { HANDLE_SCREENSHOT_PROMISE, TypeHandleScrnShotPromise } from "../screens
     {
       provide: HANDLE_SCREENSHOT_PROMISE,
       useValue: ((param) => {
-        const canvas: HTMLCanvasElement = document.querySelector('#neuroglancer-container canvas')
+        const ngCanvas: HTMLCanvasElement = document.querySelector('#neuroglancer-container canvas')
+        const threeSurferCanvas: HTMLCanvasElement = document.querySelector('three-surfer-glue-cmp canvas')
+        
+        if (threeSurferCanvas) {
+          const tsViewer = window['tsViewer']
+          tsViewer.renderer.render(tsViewer.scene, tsViewer.camera)
+        }
+        if (ngCanvas) {
+          window['viewer'].display.draw()
+        }
+        const canvas = ngCanvas || threeSurferCanvas
         if (!canvas) {
-          return Promise.reject(`element '#neuroglancer-container canvas' not found`)
+          return Promise.reject(`element '#neuroglancer-container canvas' or 'three-surfer-glue-cmp canvas' not found`)
         }
-        (window as any).viewer.display.draw()
+        
         if (!param) {
           return new Promise(rs => {
             canvas.toBlob(blob => {
diff --git a/src/util/fn.ts b/src/util/fn.ts
index a859bad0898788e5c06c1e8292ddf2c66cafb452..c7edd341b1bad2170efa8a0f0cb51712885180d5 100644
--- a/src/util/fn.ts
+++ b/src/util/fn.ts
@@ -419,3 +419,15 @@ export function wait(ms: number){
     rs(null)
   }, ms))
 }
+
+/**
+ * @description Wait until predicate returns true. Tries once every 16 ms.
+ * @param predicate 
+ */
+export async function waitFor(predicate: () => boolean) {
+  // eslint-disable-next-line no-constant-condition
+  while (true) {
+    if (predicate()) break
+    await wait(16)
+  }
+}
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
index 522d54c51836e83527b2742b529f3f39a946fa26..275b12b736715e33fa95f0854a0dd677b32baab7 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
@@ -824,11 +824,13 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
       () => this.domEl.removeEventListener((window as any).ThreeSurfer.CUSTOM_EVENTNAME_UPDATED, customEvHandler)
     )
     this.tsRef = new (window as any).ThreeSurfer(this.domEl, {highlightHovered: true})
+    window['tsViewer'] = this.tsRef
 
     this.onDestroyCb.push(
       () => {
         this.tsRef.dispose()
         this.tsRef = null
+        window['tsViewer'] = null
       }
     )
     this.tsRef.control.enablePan = false
@@ -904,13 +906,9 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, AfterViewInit
       }
     })
     this.mouseoverText = ''
-    if (mouseover.length > 0) {
-      this.mouseoverText += mouseover.map(el => el.name).join(' / ')
-    }
     if (error) {
       this.mouseoverText += `::error: ${error}`
     }
-    if (this.mouseoverText === '') this.mouseoverText = null
   }
 
   public toggleMeshVis(label: string) {
diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts
index b0d53ca1162ec2a39f94a90a091c32dbd5ea3663..75f18fd1e32b272b33b510222e3d11f9e71ffee6 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.component.ts
+++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts
@@ -405,6 +405,14 @@ export class ViewerCmp implements OnDestroy {
           )
         }
       }
+      if (event.data.viewerType === "threeSurfer") {
+        const { regions=[] } = (event.data as TContextArg<"threeSurfer">).payload
+        this.store$.dispatch(
+          userInteraction.actions.mouseoverRegions({
+            regions: regions as SxplrRegion[]
+          })
+        )
+      }
       break
     default:
     }