diff --git a/Dockerfile b/Dockerfile
index 4d675f5e6a84c83977a4773c87014f9b013ae99f..70b8bf7263a68fe846bc69ab285d306153e8f54f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:12 as builder
+FROM node:14 as builder
 
 ARG BACKEND_URL
 ENV BACKEND_URL=${BACKEND_URL}
diff --git a/README.md b/README.md
index c6e738a0957b6dc71ebe988167863aff00f053a6..51cec074433d368be8beb1ad7ab6cb472f09074d 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ A live version of the Interactive Atlas Viewer is available at [https://interact
 
 ### General information
 
-Interactive atlas viewer is built with [Angular (v9.0)](https://angular.io/), [Bootstrap (v4)](http://getbootstrap.com/), and [fontawesome icons](https://fontawesome.com/). Some other notable packages used are [ngrx/store](https://github.com/ngrx/platform) for state management. 
+Interactive atlas viewer is built with [Angular (v12.0)](https://angular.io/), [Bootstrap (v4)](http://getbootstrap.com/), and [fontawesome icons](https://fontawesome.com/). Some other notable packages used are [ngrx/store](https://github.com/ngrx/platform) for state management. 
 
 Releases newer than [v0.2.9](https://github.com/HumanBrainProject/interactive-viewer/tree/v0.2.9) also uses a nodejs backend, which uses [passportjs](http://www.passportjs.org/) for user authentication, [express](https://expressjs.com/) as a http framework.
 
@@ -16,7 +16,7 @@ Releases newer than [v0.2.9](https://github.com/HumanBrainProject/interactive-vi
 
 #### Prerequisites
 
-- node >= 12
+- latest version of node 12.x.x or node 14.x.x
 
 #### Environments
 
diff --git a/docs/releases/v2.5.0.md b/docs/releases/v2.5.0.md
index 0f7dfbe92b89bba34755d8e89b1c1c16cc9c8660..2bea69f5eca6f1006eb8f5b768bbda696e033cac 100644
--- a/docs/releases/v2.5.0.md
+++ b/docs/releases/v2.5.0.md
@@ -7,3 +7,4 @@
 ## Under the hood stuff
 
 - refactor: remove unneeded code
+- upgrade to angular v12
diff --git a/package.json b/package.json
index 727a42e219e5fd0d8134afb03c133e93a9543179..658bddf3a53cce05cc9d0ea5ecf19a6264c062ad 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "description": "HBP interactive atlas viewer. Integrating KG query, dataset previews & more. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular",
   "scripts": {
     "build-aot": "PRODUCTION=true GIT_HASH=`node -e 'console.log(require(\"./package.json\").version)'` webpack --config ./webpack/webpack.aot.js && node ./third_party/matomo/processMatomo.js",
-    "dev-server-aot": "BACKEND_URL=${BACKEND_URL:-http://localhost:3000/} PRODUCTION=true GIT_HASH=`node -e 'console.log(require(\"./package.json\").version)'` webpack-dev-server --config ./webpack/webpack.dev-aot.js",
+    "dev-server-aot": "BACKEND_URL=${BACKEND_URL:-http://localhost:3000/} PRODUCTION=true GIT_HASH=`node -e 'console.log(require(\"./package.json\").version)'` webpack serve --config ./webpack/webpack.dev-aot.js --progress",
     "test": "karma start spec/karma.conf.js",
     "e2e": "protractor e2e/protractor.conf",
     "lint": "eslint src --ext .ts",
@@ -15,74 +15,71 @@
   "author": "FZJ-INM1-BDA <inm1-bda@fz-juelich.de>",
   "license": "apache-2.0",
   "devDependencies": {
-    "@angular/animations": "^9.0.0",
-    "@angular/cdk": "^9.0.0",
-    "@angular/common": "^9.0.0",
-    "@angular/compiler": "^9.0.0",
-    "@angular/compiler-cli": "^9.1.4",
-    "@angular/core": "^9.0.0",
-    "@angular/elements": "^9.0.0",
-    "@angular/forms": "^9.0.0",
-    "@angular/language-service": "^9.0.0",
-    "@angular/material": "^9.0.0",
-    "@angular/platform-browser": "^9.0.0",
-    "@angular/platform-browser-dynamic": "^9.0.0",
-    "@material/dialog": "^4.0.0",
-    "@ngtools/webpack": "^9.0.1",
+    "@angular/animations": "^12.0.0",
+    "@angular/cdk": "^12.0.0",
+    "@angular/common": "^12.0.0",
+    "@angular/compiler": "^12.0.0",
+    "@angular/compiler-cli": "^12.1.4",
+    "@angular/core": "^12.0.0",
+    "@angular/elements": "^12.0.0",
+    "@angular/forms": "^12.0.0",
+    "@angular/language-service": "^12.0.0",
+    "@angular/material": "^12.0.0",
+    "@angular/platform-browser": "^12.0.0",
+    "@angular/platform-browser-dynamic": "^12.0.0",
+    "@angular/router": "^12.0.0",
+    "@ngtools/webpack": "^12.2.1",
     "@types/jasmine": "^3.5.0",
     "@types/webpack-env": "^1.13.6",
-    "@typescript-eslint/eslint-plugin": "^2.12.0",
-    "@typescript-eslint/parser": "^2.12.0",
+    "@typescript-eslint/eslint-plugin": "^4.29.2",
+    "@typescript-eslint/parser": "^4.29.2",
     "angular2-template-loader": "^0.6.2",
     "browserstack-local": "^1.4.5",
     "codelyzer": "^5.0.1",
     "core-js": "^3.0.1",
     "css-loader": "^3.2.0",
-    "eslint": "^6.8.0",
+    "eslint": "^7.32.0",
     "eslint-plugin-html": "^6.0.0",
     "file-loader": "^1.1.11",
     "glob": "^7.1.6",
     "hammerjs": "^2.0.8",
-    "html-webpack-plugin": "^3.2.0",
+    "html-webpack-plugin": "^5.3.2",
     "jasmine": "^3.1.0",
     "jasmine-core": "^3.5.0",
     "jasmine-marbles": "^0.6.0",
     "jasmine-spec-reporter": "^4.2.1",
     "json-loader": "^0.5.7",
-    "karma": "^4.1.0",
-    "karma-chrome-launcher": "^2.2.0",
+    "karma": "^6.3.4",
+    "karma-chrome-launcher": "^3.1.0",
     "karma-cli": "^2.0.0",
-    "karma-jasmine": "^2.0.1",
-    "karma-typescript": "^4.1.1",
-    "karma-webpack": "^3.0.0",
-    "lodash.merge": "^4.6.2",
+    "karma-jasmine": "^4.0.1",
+    "karma-typescript": "^5.5.1",
+    "karma-webpack": "^5.0.0",
     "mini-css-extract-plugin": "^0.8.0",
-    "node-sass": "^4.14.1",
-    "protractor": "^6.0.0",
+    "protractor": "^7.0.0",
     "raw-loader": "^0.5.1",
     "reflect-metadata": "^0.1.12",
-    "rxjs": "6.5.4",
-    "sass-loader": "^7.2.0",
+    "rxjs": "^6.6.0",
+    "sass": "^1.38.0",
+    "sass-loader": "^12.1.0",
     "showdown": "^1.9.1",
     "terser-webpack-plugin": "^3.0.1",
     "ts-loader": "^4.3.0",
     "ts-node": "^8.1.0",
-    "typescript": "~3.7.5",
-    "uglifyjs-webpack-plugin": "^1.2.5",
-    "webpack": "^4.41.2",
-    "webpack-cli": "^3.3.2",
+    "typescript": "^4.3.5",
+    "webpack": "^5.50.0",
+    "webpack-cli": "^4.8.0",
     "webpack-closure-compiler": "^2.1.6",
     "webpack-dev-server": "^3.11.2",
     "webpack-merge": "^4.1.2"
   },
   "dependencies": {
-    "@angular/router": "^9.1.13",
-    "@ngrx/effects": "^9.1.1",
-    "@ngrx/store": "^9.1.1",
+    "@ngrx/effects": "^12.0.0",
+    "@ngrx/store": "^12.0.0",
     "@types/node": "12.12.39",
     "export-nehuba": "0.0.12",
     "hbp-connectivity-component": "^0.4.9",
     "jszip": "^3.6.0",
-    "zone.js": "^0.10.2"
+    "zone.js": "^0.11.4"
   }
 }
diff --git a/spec/karma.conf.js b/spec/karma.conf.js
index 76c12d0cbd668862a62d60ff9377427005964bc1..b2559dbe9d5bbcd6c6245cad2b283c70aeeece0a 100644
--- a/spec/karma.conf.js
+++ b/spec/karma.conf.js
@@ -3,8 +3,17 @@
 
 const merge = require('webpack-merge')
 const webpackTest = require('../webpack/webpack.test')
-const webpackConfig = require('../webpack/webpack.dev')
-const fullWebpack = merge(webpackTest, webpackConfig)
+const webpackConfig = require('../webpack/webpack.aot-common')
+const { AngularWebpackPlugin } = require('@ngtools/webpack')
+const fullWebpack = merge(webpackTest, webpackConfig, {
+  plugins: [
+    new AngularWebpackPlugin({
+      tsConfigPath: 'tsconfig.spec.json',
+      // entryModule: 'src/main.module#MainModule',
+      // directTemplateLoading: true
+    }),
+  ]
+})
 
 const singleRun = process.env.NODE_ENV === 'test'
 const browsers = process.env.NODE_ENV === 'test'
@@ -22,6 +31,13 @@ module.exports = function(config) {
     // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
     frameworks: ['jasmine'],
 
+    client: {
+      jasmine: {},
+      clearContext: false
+    },
+    jasmineHtmlReporter: {
+      suppressAll: true // removes the duplicated traces
+    },
 
     // list of files / patterns to load in the browser
     files: [
@@ -67,6 +83,8 @@ module.exports = function(config) {
     // available reporters: https://npmjs.org/browse/keyword/karma-reporter
     reporters: ['progress'],
 
+    restartOnFileChange: true,
+
 
     // web server port
     port: 9876,
diff --git a/spec/test.ts b/spec/test.ts
index 478be25bbf91e4b0d442d079f8bc81bd0d868493..79e84c02ff647ce35089fd404ba0593f3afd89c3 100644
--- a/spec/test.ts
+++ b/spec/test.ts
@@ -10,13 +10,12 @@ import {
   platformBrowserDynamicTesting
 } from '@angular/platform-browser-dynamic/testing';
 
-declare const require: any;
-
 // First, initialize the Angular testing environment.
 getTestBed().initTestEnvironment(
   BrowserDynamicTestingModule,
-  platformBrowserDynamicTesting()
-);
+  platformBrowserDynamicTesting(),
+  { teardown: { destroyAfterEach: true }},
+)
 
 const testContext = require.context('../src', true, /\.spec\.ts$/)
 testContext.keys().map(testContext)
diff --git a/src/atlasComponents/parcellationRegion/region.base.ts b/src/atlasComponents/parcellationRegion/region.base.ts
index c69a2f94658760f599f896f16affca4a70ab277c..a16995b9af3a98b69c44f0577e2f6e1226b087df 100644
--- a/src/atlasComponents/parcellationRegion/region.base.ts
+++ b/src/atlasComponents/parcellationRegion/region.base.ts
@@ -1,4 +1,4 @@
-import { EventEmitter, Input, Output, Pipe, PipeTransform } from "@angular/core";
+import { Directive, EventEmitter, Input, Output, Pipe, PipeTransform } from "@angular/core";
 import { select, Store, createSelector } from "@ngrx/store";
 import { uiStateOpenSidePanel, uiStateExpandSidePanel, uiActionShowSidePanelConnectivity } from 'src/services/state/uiState.store.helper'
 import { distinctUntilChanged, switchMap, filter, map, withLatestFrom, tap } from "rxjs/operators";
@@ -9,6 +9,7 @@ import { viewerStateFetchedTemplatesSelector, viewerStateGetSelectedAtlas, viewe
 import { strToRgb, verifyPositionArg, getRegionHemisphere } from 'common/util'
 import { getPosFromRegion } from "src/util/siibraApiConstants/fn";
 
+@Directive()
 export class RegionBase {
 
   public rgbString: string
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/bsRegionInputBase.ts b/src/atlasComponents/regionalFeatures/bsFeatures/bsRegionInputBase.ts
index 6eed3fb1bcc28e7f59b3133acb4b354a90b5a0e7..85d2e6d005bca99c7d003f148bc6a93fe7e2acb7 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/bsRegionInputBase.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/bsRegionInputBase.ts
@@ -3,8 +3,9 @@ import { map, switchMap } from "rxjs/operators";
 import { TRegion, IBSSummaryResponse, IBSDetailResponse } from "./type";
 import { BsFeatureService, TFeatureCmpInput } from "./service";
 import { flattenReducer } from 'common/util'
-import { Input } from "@angular/core";
+import { Directive, Input } from "@angular/core";
 
+@Directive()
 export class BsRegionInputBase{
 
   protected region$ = new BehaviorSubject<TRegion>(null)
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts
index f4e418aa320f7d2e201955b5ab9a56e22ec39e78..b149e359d7dca68da294e98e9138a557bfedf41a 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts
@@ -1,6 +1,7 @@
-import { Input } from "@angular/core";
+import { Directive, Input } from "@angular/core";
 import { TBSDetail } from "./type";
 
+@Directive()
 export class BsFeatureReceptorBase {
   @Input()
   bsFeature: TBSDetail
diff --git a/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts
index 627b097c977eb8fbef6171fb205a0b6f690abd6e..6821e237ff0aae95e6eaa42c99989dec7d5e9b65 100644
--- a/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts
+++ b/src/atlasComponents/regionalFeatures/featureContainer/featureContainer.component.spec.ts
@@ -42,40 +42,26 @@ const serviceStub = {
   ])
 }
 
-@NgModule({
-  declarations: [
-    FeatureContainer,
-    DummyComponent,
-  ],
-  entryComponents: [
-    DummyComponent
-  ],
-  providers: [
-    {
-      provide: RegionalFeaturesService,
-      useValue: serviceStub
-    }
-  ],
-  exports: [
-    FeatureContainer,
-    DummyComponent,
-  ]
-})
-
-class DummyModule{}
-
 describe('> featureContainer.component.ts', () => {
   describe('> FeatureContainer', () => {
 
-    beforeEach(async(() => {
-      TestBed.configureTestingModule({
+    beforeEach(async () => {
+
+      await TestBed.configureTestingModule({
         imports: [
           CommonModule,
-          DummyModule,
         ],
         declarations: [
+          FeatureContainer,
+          DummyComponent,
           HostCmp,
         ],
+        providers: [
+          {
+            provide: RegionalFeaturesService,
+            useValue: serviceStub
+          }
+        ]
       }).overrideComponent(HostCmp, {
         set: {
           template: `
@@ -87,7 +73,7 @@ describe('> featureContainer.component.ts', () => {
         }
       }).compileComponents()
 
-    }))
+    })
 
     it('> can be created', () => {
       const fixture = TestBed.createComponent(HostCmp)
diff --git a/src/atlasComponents/regionalFeatures/singleFeatures/base/regionFeature.base.ts b/src/atlasComponents/regionalFeatures/singleFeatures/base/regionFeature.base.ts
index 6755dfca6a92819dd831118c13ef09b48f66c2c4..21dde06920b0ddf29f384683c5851de9a171445f 100644
--- a/src/atlasComponents/regionalFeatures/singleFeatures/base/regionFeature.base.ts
+++ b/src/atlasComponents/regionalFeatures/singleFeatures/base/regionFeature.base.ts
@@ -1,9 +1,10 @@
-import { EventEmitter, Input, Output, SimpleChanges } from "@angular/core"
+import { Directive, EventEmitter, Input, Output, SimpleChanges } from "@angular/core"
 import { BehaviorSubject, forkJoin, Observable, of } from "rxjs"
 import { catchError, shareReplay, switchMap, tap } from "rxjs/operators"
 import { IHasId } from "src/util/interfaces"
 import { IFeature, RegionalFeaturesService } from "../../regionalFeature.service"
 
+@Directive()
 export class RegionFeatureBase{
 
   private _feature: IFeature
diff --git a/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts b/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts
index eb9e3c32e9d0ad71e1cd57c5ab1c33157eeae450..11fd197fbd45b569e35f15f5a9ae54ab13f07777 100644
--- a/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts
+++ b/src/atlasComponents/regionalFeatures/singleFeatures/iEEGRecordings/iEEGRecordings/iEEGRecordings.component.ts
@@ -20,7 +20,7 @@ const selectedColor = [ 255, 0, 0 ]
 
 export class IEEGRecordingsCmp extends RegionFeatureBase implements ISingleFeature{
   private landmarksLoaded: IHasId[] = []
-  private onDestroyCb: Function[] = []
+  private onDestroyCb: (() => void)[] = []
   private sub: Subscription[] = []
 
   constructor(
diff --git a/src/atlasComponents/userAnnotations/annotationMode/annotationMode.component.ts b/src/atlasComponents/userAnnotations/annotationMode/annotationMode.component.ts
index 0bacfe6b2d2d0f92d2b292429dcc4682bd05f1f3..38eae7e8134c3e7c87fa16722f1a2e248a929718 100644
--- a/src/atlasComponents/userAnnotations/annotationMode/annotationMode.component.ts
+++ b/src/atlasComponents/userAnnotations/annotationMode/annotationMode.component.ts
@@ -22,10 +22,10 @@ export class AnnotationMode implements OnDestroy{
       name: string
       iconClass: string
     }
-    onClick: Function
+    onClick: () => void
   }[] = []
 
-  private onDestroyCb: Function[] = []
+  private onDestroyCb: (() => void)[] = []
 
   constructor(
     private store$: Store<any>,
diff --git a/src/atlasComponents/userAnnotations/tools/delete.ts b/src/atlasComponents/userAnnotations/tools/delete.ts
index dc817a65012bd3dbe5409fb8656d5b9d5bcb9990..b1658e9cc44f91dc68ed41a5bd1bfe7bd49d0f5c 100644
--- a/src/atlasComponents/userAnnotations/tools/delete.ts
+++ b/src/atlasComponents/userAnnotations/tools/delete.ts
@@ -1,9 +1,10 @@
-import { OnDestroy } from "@angular/core";
+import { Directive, OnDestroy } from "@angular/core";
 import { Observable, Subject, Subscription } from "rxjs";
 import { filter, switchMapTo, takeUntil, withLatestFrom } from "rxjs/operators";
 import { Point } from "./point";
 import { AbsToolClass, IAnnotationEvents, IAnnotationGeometry, IAnnotationTools, TAnnotationEvent, TCallbackFunction, TNgAnnotationPoint, TToolType } from "./type";
 
+@Directive()
 export class ToolDelete extends AbsToolClass<Point> implements IAnnotationTools, OnDestroy {
 
   public subs: Subscription[] = []
diff --git a/src/atlasComponents/userAnnotations/tools/line.ts b/src/atlasComponents/userAnnotations/tools/line.ts
index 1303612f991d1cadc53a1ce73ddf9f043babca52..644258af23408c6edb3b0c03054ad92c400333d4 100644
--- a/src/atlasComponents/userAnnotations/tools/line.ts
+++ b/src/atlasComponents/userAnnotations/tools/line.ts
@@ -12,7 +12,7 @@ import {
   TCallbackFunction,
 } from "./type";
 import { Point, TPointJsonSpec } from './point'
-import { OnDestroy } from "@angular/core";
+import { Directive, Injectable, OnDestroy } from "@angular/core";
 import { Observable, Subject, Subscription } from "rxjs";
 import { filter, switchMapTo, takeUntil } from "rxjs/operators";
 import { getUuid } from "src/util/fn";
@@ -182,6 +182,7 @@ export class Line extends IAnnotationGeometry{
 
 export const LINE_ICON_CLASS = 'fas fa-slash'
 
+@Directive()
 export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, OnDestroy {
   static PREVIEW_ID='tool_line_preview'
   public name = 'Line'
diff --git a/src/atlasComponents/userAnnotations/tools/point.ts b/src/atlasComponents/userAnnotations/tools/point.ts
index 2dcafc2490a82b2dacb3bf5180b7457947de2770..e6fd9fee4f42d8535bd8998b0ffb471e211e0eec 100644
--- a/src/atlasComponents/userAnnotations/tools/point.ts
+++ b/src/atlasComponents/userAnnotations/tools/point.ts
@@ -1,6 +1,6 @@
 import { AbsToolClass, getCoord, IAnnotationEvents, IAnnotationGeometry, IAnnotationTools, INgAnnotationTypes, TAnnotationEvent, TBaseAnnotationGeomtrySpec, TCallbackFunction, TNgAnnotationEv, TSandsPoint, TToolType } from "./type";
-import { merge, Observable, Subject, Subscription } from "rxjs";
-import { OnDestroy } from "@angular/core";
+import { Observable, Subject, Subscription } from "rxjs";
+import { Directive, OnDestroy } from "@angular/core";
 import { filter, switchMapTo, takeUntil } from "rxjs/operators";
 
 export type TPointJsonSpec = {
@@ -101,6 +101,7 @@ export class Point extends IAnnotationGeometry {
 
 export const POINT_ICON_CLASS='fas fa-circle'
 
+@Directive()
 export class ToolPoint extends AbsToolClass<Point> implements IAnnotationTools, OnDestroy {
   static PREVIEW_ID='tool_point_preview'
   public name = 'Point'
diff --git a/src/atlasComponents/userAnnotations/tools/poly.ts b/src/atlasComponents/userAnnotations/tools/poly.ts
index c33662c2afc022ae8240884c629946587057b662..d226021de999af7b27ae98815f7fb34176f97ff5 100644
--- a/src/atlasComponents/userAnnotations/tools/poly.ts
+++ b/src/atlasComponents/userAnnotations/tools/poly.ts
@@ -1,6 +1,6 @@
 import { IAnnotationTools, IAnnotationGeometry, TAnnotationEvent, IAnnotationEvents, AbsToolClass, INgAnnotationTypes, TNgAnnotationEv, TToolType, TBaseAnnotationGeomtrySpec, TSandsPolyLine, getCoord, TCallbackFunction } from "./type";
 import { Point, TPointJsonSpec } from './point'
-import { OnDestroy } from "@angular/core";
+import { Directive, OnDestroy } from "@angular/core";
 import { merge, Observable, Subject, Subscription } from "rxjs";
 import { filter, switchMapTo, takeUntil, withLatestFrom } from "rxjs/operators";
 import { getUuid } from "src/util/fn";
@@ -22,7 +22,7 @@ export class Polygon extends IAnnotationGeometry{
   }
 
   private ptWkMp = new WeakMap<Point, {
-    onremove: Function
+    onremove: () => void
   }>()
 
   public removePoint(p: Point) {
@@ -223,6 +223,7 @@ export class Polygon extends IAnnotationGeometry{
 
 export const POLY_ICON_CLASS = 'fas fa-draw-polygon'
 
+@Directive()
 export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationTools, OnDestroy {
   static PREVIEW_ID='tool_poly_preview'
 
diff --git a/src/atlasComponents/userAnnotations/tools/select.ts b/src/atlasComponents/userAnnotations/tools/select.ts
index 38a0b11ba39ec9df2ddbb20b875f01cd48575257..fd947eb34e813a956f21349dfd319898ba469fd0 100644
--- a/src/atlasComponents/userAnnotations/tools/select.ts
+++ b/src/atlasComponents/userAnnotations/tools/select.ts
@@ -1,9 +1,10 @@
-import { OnDestroy } from "@angular/core";
+import { Directive, OnDestroy } from "@angular/core";
 import { Observable, Subject, Subscription } from "rxjs";
 import { filter } from 'rxjs/operators'
 import { Point } from "./point";
 import { AbsToolClass, IAnnotationEvents, IAnnotationGeometry, IAnnotationTools, TAnnotationEvent, TCallbackFunction, TNgAnnotationPoint, TToolType } from "./type";
 
+@Directive()
 export class ToolSelect extends AbsToolClass<Point> implements IAnnotationTools, OnDestroy {
 
   public subs: Subscription[] = []
diff --git a/src/atlasComponents/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts
index fde183e33b5d8fd56059d857f4c5dfb600502350..b402976d9817885523a442f28bb9c13299744cfe 100644
--- a/src/atlasComponents/userAnnotations/tools/service.ts
+++ b/src/atlasComponents/userAnnotations/tools/service.ts
@@ -80,7 +80,7 @@ export class ModularUserAnnotationToolService implements OnDestroy{
   private selectedTmpl$ = this.store.pipe(
     select(viewerStateSelectedTemplatePureSelector),
   )
-  public moduleAnnotationTypes: {instance: {name: string, iconClass: string, toolSelected$: Observable<boolean>}, onClick: Function}[] = []
+  public moduleAnnotationTypes: {instance: {name: string, iconClass: string, toolSelected$: Observable<boolean>}, onClick: () => void}[] = []
   private managedAnnotationsStream$ = new Subject<{
     tool: string
     annotations: IAnnotationGeometry[]
@@ -157,7 +157,7 @@ export class ModularUserAnnotationToolService implements OnDestroy{
     editCmp?: ClassInterface<any>
   }): AbsToolClass<any>{
     const { toolCls: Cls, target, editCmp } = arg
-    const newTool = new Cls(this.annotnEvSubj, arg => this.handleToolCallback(arg)) as T & { ngOnDestroy?: Function }
+    const newTool = new Cls(this.annotnEvSubj, arg => this.handleToolCallback(arg)) as T & { ngOnDestroy?: () => void }
     const { name, iconClass, onMouseMoveRenderPreview } = newTool
     
     this.moduleAnnotationTypes.push({
diff --git a/src/atlasComponents/userAnnotations/tools/type.ts b/src/atlasComponents/userAnnotations/tools/type.ts
index 1716457a166eea87cc6b9943b4c3ebed3538c03a..efb1d9136c74e1f55497efc62b5fda6798b9afbb 100644
--- a/src/atlasComponents/userAnnotations/tools/type.ts
+++ b/src/atlasComponents/userAnnotations/tools/type.ts
@@ -6,6 +6,8 @@ import { TLineJsonSpec } from "./line"
 import { TPointJsonSpec } from "./point"
 import { TPolyJsonSpec } from "./poly"
 
+type TRecord = Record<string, unknown>
+
 /**
  * base class to be extended by all annotation tools
  * TODO perhaps split into drawing subclass/utility subclass
@@ -158,11 +160,11 @@ export type TToolType = 'selecting' | 'drawing' | 'deletion'
 
 export type TCallback = {
   paintingEnd: {
-    callArg: {}
+    callArg: TRecord
     returns: void
   }
   requestManAnnStream: {
-    callArg: {}
+    callArg: TRecord
     returns: Observable<IAnnotationGeometry[]>
   }
   message: {
@@ -174,7 +176,7 @@ export type TCallback = {
     returns: void
   }
   showList: {
-    callArg: {}
+    callArg: TRecord
     returns: void
   }
 }
@@ -273,7 +275,7 @@ export abstract class IAnnotationGeometry extends Highlightable {
 
   abstract getNgAnnotationIds(): string[]
   abstract toNgAnnotation(): INgAnnotationTypes[keyof INgAnnotationTypes][]
-  abstract toJSON(): object
+  abstract toJSON(): TRecord
   abstract toString(): string
   abstract toSands(): ISandsAnnotation[keyof ISandsAnnotation]
 
diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts
index 20b08137b3f5b196d360aa858c20d4a367243140..9ee73c58689f765e94e54829a1b9138e43f38f86 100644
--- a/src/atlasViewer/atlasViewer.apiService.service.ts
+++ b/src/atlasViewer/atlasViewer.apiService.service.ts
@@ -44,7 +44,7 @@ export class AtlasViewerAPIServices implements OnDestroy{
 
   public loadMesh$ = new Subject<ILoadMesh>()
 
-  private onDestoryCb: Function[] = []
+  private onDestoryCb: (() => void)[] = []
   private loadedTemplates$: Observable<any>
   private selectParcellation$: Observable<any>
   public interactiveViewer: IInteractiveViewerInterface
@@ -64,7 +64,7 @@ export class AtlasViewerAPIServices implements OnDestroy{
 
   }
 
-  private dismissDialog: Function
+  private dismissDialog: () => void
   public getUserToSelectRegion: IGetUserSelectRegionPr[] = []
   public getUserToSelectRegionUI$: Subject<IGetUserSelectRegionPr[]> = new Subject()
 
diff --git a/src/contextMenuModule/service.ts b/src/contextMenuModule/service.ts
index be34051f9cfe3f5cc59a71f9707e62289a8bc8d7..a35798d79ecbaa790598842007bc10fc002d44df 100644
--- a/src/contextMenuModule/service.ts
+++ b/src/contextMenuModule/service.ts
@@ -18,7 +18,7 @@ type TSimple = {
 
 type TTmplRef = (TTmpl | TSimple) & {
   order?: number
-  onClick?: Function
+  onClick?: (...arg: any) => void
 }
 
 type CtxMenuInterArg<T> = {
diff --git a/src/messagingGlue.ts b/src/messagingGlue.ts
index 443b58db56cfe20fcfcbe871232f6a11177977a4..80e459157a717ec90b21f426596e531acbb48843 100644
--- a/src/messagingGlue.ts
+++ b/src/messagingGlue.ts
@@ -1,4 +1,4 @@
-import { OnDestroy } from "@angular/core";
+import { Injectable, OnDestroy } from "@angular/core";
 import { select, Store } from "@ngrx/store";
 import { IMessagingActionTmpl, IWindowMessaging } from "./messaging/types";
 import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer } from "./services/state/ngViewerState/actions";
@@ -6,6 +6,7 @@ import { viewerStateSelectAtlas } from "./services/state/viewerState/actions";
 import { viewerStateFetchedAtlasesSelector } from "./services/state/viewerState/selectors";
 import { generalActionError } from "./services/stateStore.helper";
 
+@Injectable()
 export class MessagingGlue implements IWindowMessaging, OnDestroy {
 
   private onDestroyCb: (() => void)[] = []
diff --git a/src/plugin/atlasViewer.pluginService.service.spec.ts b/src/plugin/atlasViewer.pluginService.service.spec.ts
index 2c2c9c83620cd239009daa4f781bb0e159ef0653..41e342b8bf77d8941eb731554972b71217e75b73 100644
--- a/src/plugin/atlasViewer.pluginService.service.spec.ts
+++ b/src/plugin/atlasViewer.pluginService.service.spec.ts
@@ -11,6 +11,7 @@ import { PureContantService } from "src/util"
 import { APPEND_SCRIPT_TOKEN, REMOVE_SCRIPT_TOKEN } from "src/util/constants"
 import { WidgetModule, WidgetServices } from "src/widget"
 import { PluginServices } from "./atlasViewer.pluginService.service"
+import { PluginModule } from "./plugin.module"
 import { PluginUnit } from "./pluginUnit/pluginUnit.component"
 
 const MOCK_PLUGIN_MANIFEST = {
@@ -19,20 +20,6 @@ const MOCK_PLUGIN_MANIFEST = {
   scriptURL: 'http://localhost:10001/script.js'
 }
 
-@NgModule({
-  declarations: [
-    PluginUnit,
-  ],
-  entryComponents: [
-    PluginUnit
-  ],
-  exports: [
-    PluginUnit
-  ]
-})
-
-class PluginUnitModule{}
-
 const spyfn = {
   appendSrc: jasmine.createSpy('appendSrc')
 }
@@ -52,7 +39,7 @@ describe('> atlasViewer.pluginService.service.ts', () => {
           AngularMaterialModule,
           CommonModule,
           WidgetModule,
-          PluginUnitModule,
+          PluginModule,
           HttpClientTestingModule,
           ComponentsModule,
         ],
diff --git a/src/routerModule/parseRouteToTmplParcReg.ts b/src/routerModule/parseRouteToTmplParcReg.ts
index d626e279fea18182e480a76e39204b633d4f6231..a1ed2a7c47003fbaae169cc49bdd0b7e8be0e3bb 100644
--- a/src/routerModule/parseRouteToTmplParcReg.ts
+++ b/src/routerModule/parseRouteToTmplParcReg.ts
@@ -18,7 +18,7 @@ export const PARSE_ERROR = {
 export const encodeId = (id: string) => id && id.replace(/\//g, ':')
 export const decodeId = (codedId: string) => codedId && codedId.replace(/:/g, '/')
 
-export function parseSearchParamForTemplateParcellationRegion(obj: TUrlPathObj<string[], TUrlAtlas<string[]>>, fullPath: UrlTree, state: any, warnCb: Function) {
+export function parseSearchParamForTemplateParcellationRegion(obj: TUrlPathObj<string[], TUrlAtlas<string[]>>, fullPath: UrlTree, state: any, warnCb: (arg: string) => void) {
 
   /**
    * TODO if search param of either template or parcellation is incorrect, wrong things are searched
diff --git a/src/routerModule/util.ts b/src/routerModule/util.ts
index 224458c860b9ae37073a4ee40a8dd839e7f3ddca..21ccdc6e7bbbb9bab69a399a96ac388d5fbc7439 100644
--- a/src/routerModule/util.ts
+++ b/src/routerModule/util.ts
@@ -34,7 +34,7 @@ const decodePath = (path: string) => {
   }
 }
 
-export const cvtFullRouteToState = (fullPath: UrlTree, state: any, _warnCb?: Function) => {
+export const cvtFullRouteToState = (fullPath: UrlTree, state: any, _warnCb?: (arg: string) => void) => {
 
   const warnCb = _warnCb || ((...e: any[]) => console.warn(...e))
   const pathFragments: UrlSegment[] = fullPath.root.hasChildren()
diff --git a/src/screenshot/util.ts b/src/screenshot/util.ts
index 5a84dc7f1b76e9a420c3d311d1b7dfdd34e42439..8b8532ddf77a0e8b2a48de2bf082e2caaeb9bbfb 100644
--- a/src/screenshot/util.ts
+++ b/src/screenshot/util.ts
@@ -10,5 +10,5 @@ interface IScrnShot{
 /**
  * if param is not provided, screenshot entire screen
  */
-export type TypeHandleScrnShotPromise = (param?: IScrnShot) => Promise<{ revoke: Function, url: string }>
+export type TypeHandleScrnShotPromise = (param?: IScrnShot) => Promise<{ revoke: () => void, url: string }>
 export const HANDLE_SCREENSHOT_PROMISE = new InjectionToken('HANDLE_SCREENSHOT_PROMISE')
\ No newline at end of file
diff --git a/src/services/dialogService.service.ts b/src/services/dialogService.service.ts
index c202eda5884ab18cc47d194d931504e19af11202..ee06d2a91e6a63d5b3e075d6e7cf7a05676108ca 100644
--- a/src/services/dialogService.service.ts
+++ b/src/services/dialogService.service.ts
@@ -22,7 +22,7 @@ export class DialogService {
     })
     return new Promise((resolve, reject) => this.confirmDialogRef.afterClosed()
       .subscribe(val => {
-        if (val) { resolve() } else { reject('User cancelled') }
+        if (val) { resolve('Success') } else { reject('User cancelled') }
       },
       reject,
       () => this.confirmDialogRef = null))
diff --git a/src/theme.scss b/src/theme.scss
index f311da58eb993b86a235179246c4ab88dcbc79c1..5d8358d9b5f293359edd5bddb5fa63b09daab771 100644
--- a/src/theme.scss
+++ b/src/theme.scss
@@ -1,17 +1,17 @@
-@import '~@angular/material/theming';
-@import '~@angular/cdk/overlay-prebuilt.css';
+@use 'sass:map';
+@use '~@angular/material' as mat;
 
-@include  mat-core();
+@include mat.core();
 
 @mixin custom-cmp($theme) {
+  $color-config: mat.get-color-config($theme);
 
   $foreground: map-get($theme, foreground);
   $background: map-get($theme, background);
-  $background-color: map-get($background, background);
 
-  $primary: map-get($theme, primary);
-  $accent: map-get($theme, accent);
-  $warn: map-get($theme, warn);
+  $primary: map-get($color-config, primary);
+  $accent: map-get($color-config, accent);
+  $warn: map-get($color-config, warn);
 
   [iv-custom-comp],
   .iv-custom-comp
@@ -40,62 +40,75 @@
     &[bg],
     &.bg
     {
-      background-color: mat-color($background, background);
+      background-color: mat.get-color-from-palette($background, background);
     }
 
     &[darker-bg],
     &.darker-bg
     {
-      background-color: $background-color;
+      background-color: mat.get-color-from-palette($background, background);
     }
 
     &[text],
     &.text
     {
-      color: mat-color($foreground, text);
+      color: mat.get-color-from-palette($foreground, text);
     }
     &[primary],
     &.primary
     {
-      color: mat-color($primary);
+      color: mat.get-color-from-palette($primary, 500);
     }
 
     &[accent],
     &.accent
     {
-      color: mat-color($accent);
+      color: mat.get-color-from-palette($accent, 500);
     }
 
     &[warn],
     &.warn
     {
-      color: mat-color($warn);
+      color: mat.get-color-from-palette($warn, 500);
     }
 
     &.hoverable
     {
       &:hover
       {
-        background-color: mat-color($background, hover);
+        // background-color: mat-color($background, hover);
         cursor: pointer;
       }
     }
   }
 }
 
-$iv-theme-primary: mat-palette($mat-indigo);
-$iv-theme-accent: mat-palette($mat-amber);
-$iv-theme-warn: mat-palette($mat-red);
+$iv-theme-primary:  mat.define-palette(mat.$indigo-palette);
+$iv-theme-accent:   mat.define-palette(mat.$amber-palette);
+$iv-theme-warn:     mat.define-palette(mat.$red-palette);
 
-$iv-theme: mat-light-theme($iv-theme-primary, $iv-theme-accent, $iv-theme-warn);
+$iv-theme: mat.define-light-theme((
+  color: (
+    primary: $iv-theme-primary,
+    accent: $iv-theme-accent,
+    warn: $iv-theme-warn,
+  )
+));
 
-@include angular-material-theme($iv-theme);
+@include mat.all-component-themes($iv-theme);
 @include custom-cmp($iv-theme);
 
-$iv-dark-theme-primary: mat-palette($mat-blue);
-$iv-dark-theme-accent:  mat-palette($mat-amber, A200, A100, A400);
-$iv-dark-theme-warn:    mat-palette($mat-red);
-$iv-dark-theme:   mat-dark-theme($iv-dark-theme-primary, $iv-dark-theme-accent, $iv-dark-theme-warn);
+$iv-dark-theme-primary: mat.define-palette(mat.$blue-palette);
+$iv-dark-theme-accent:  mat.define-palette(mat.$amber-palette, A200, A100, A400);
+$iv-dark-theme-warn:    mat.define-palette(mat.$red-palette);
+
+$iv-dark-theme:   mat.define-dark-theme((
+  color: (
+    primary: $iv-dark-theme-primary,
+    accent: $iv-dark-theme-accent,
+    warn: $iv-dark-theme-warn,
+  )
+));
 
 /**
   * attribute has lower priority than class
@@ -105,14 +118,14 @@ $iv-dark-theme:   mat-dark-theme($iv-dark-theme-primary, $iv-dark-theme-accent,
 [darktheme=true],
 .darktheme.darktheme
 {
-  @include angular-material-theme($iv-dark-theme);
+  @include mat.all-component-themes($iv-dark-theme);
   @include custom-cmp($iv-dark-theme);
 }
 
 [darktheme=false],
 .lighttheme.lighttheme
 {
-  @include angular-material-theme($iv-theme);
+  @include mat.all-component-themes($iv-theme);
   @include custom-cmp($iv-theme);
 }
 
diff --git a/src/ui/help/helpOnePager/helpOnePager.component.spec.ts b/src/ui/help/helpOnePager/helpOnePager.component.spec.ts
index d591437defa2372454759049e7fe2e916fbec29f..08f17969c3656fb5d3d73ca8a6adf6270d605eae 100644
--- a/src/ui/help/helpOnePager/helpOnePager.component.spec.ts
+++ b/src/ui/help/helpOnePager/helpOnePager.component.spec.ts
@@ -1,14 +1,16 @@
 import { CommonModule } from '@angular/common'
-import { async, TestBed } from '@angular/core/testing'
+import { TestBed } from '@angular/core/testing'
 import { ComponentsModule } from 'src/components'
 import { AngularMaterialModule } from 'src/sharedModules'
-import { PureContantService, UtilModule } from 'src/util'
+import { QuickTourModule } from 'src/ui/quickTour'
+import { PureContantService } from 'src/util'
+import { UtilModule } from 'src/util/util.module'
 import { HelpOnePager } from './helpOnePager.component'
 
 describe('> helpOnePager.component.ts', () => {
   describe('> HelpOnePager', () => {
-    beforeEach(async(() => {
-      TestBed.configureTestingModule({
+    beforeEach(async() => {
+      await TestBed.configureTestingModule({
         imports: [
           ComponentsModule,
           CommonModule,
@@ -17,6 +19,7 @@ describe('> helpOnePager.component.ts', () => {
            */
           UtilModule,
           AngularMaterialModule,
+          QuickTourModule
         ],
         declarations: [
           HelpOnePager,
@@ -28,7 +31,7 @@ describe('> helpOnePager.component.ts', () => {
           }
         ]
       }).compileComponents()
-    }))
+    })
     it('> should render a table', () => {
       const fixture = TestBed.createComponent(HelpOnePager)
       fixture.detectChanges()
diff --git a/src/ui/nehubaContainer/2dLandmarks/landmark.base.ts b/src/ui/nehubaContainer/2dLandmarks/landmark.base.ts
index 9d424edba5344b152eb561d4f8e3b92a0414925e..953c75ed49d956b42023822fec53daea65adcec7 100644
--- a/src/ui/nehubaContainer/2dLandmarks/landmark.base.ts
+++ b/src/ui/nehubaContainer/2dLandmarks/landmark.base.ts
@@ -1,5 +1,6 @@
-import { Input } from "@angular/core"
+import { Directive, Input } from "@angular/core"
 
+@Directive()
 export class LandmarkUnitBase{
   @Input() public positionX: number = 0
   @Input() public positionY: number = 0
diff --git a/src/util/LinkedList.ts b/src/util/LinkedList.ts
index 77e8e21e553ee16d74aebd343ee1c1ff6a81b3d9..6d468df6497abfa3ead5aa81fbffa1f1b6dc9b45 100644
--- a/src/util/LinkedList.ts
+++ b/src/util/LinkedList.ts
@@ -1,4 +1,7 @@
-export interface IDoublyLinkedItem<T extends object> {
+// eslint-disable-next-line @typescript-eslint/ban-types
+type TNonePrimitive = object
+
+export interface IDoublyLinkedItem<T extends TNonePrimitive> {
   next: IDoublyLinkedItem<T>
   prev: IDoublyLinkedItem<T>
   thisObj: T
@@ -6,7 +9,7 @@ export interface IDoublyLinkedItem<T extends object> {
   list: DoublyLinkedList<T>
 }
 
-export class DoublyLinkedList<T extends object>{
+export class DoublyLinkedList<T extends TNonePrimitive>{
   
   public first: IDoublyLinkedItem<T>
   public last: IDoublyLinkedItem<T>
@@ -99,7 +102,7 @@ export class DoublyLinkedList<T extends object>{
   }
 }
 
-export function FindInLinkedList<T extends object>(list: DoublyLinkedList<T>, predicate: (element: IDoublyLinkedItem<T>) => boolean){
+export function FindInLinkedList<T extends TNonePrimitive>(list: DoublyLinkedList<T>, predicate: (element: IDoublyLinkedItem<T>) => boolean){
   let compareObj = list.first,
     returnObj: IDoublyLinkedItem<T> = null
 
diff --git a/src/util/injectionTokens.ts b/src/util/injectionTokens.ts
index eed3fbcb10bfe65e71ca23dfab5c3db621778159..f8720f5d6ce4ca2e19c473799afb695bee18be05 100644
--- a/src/util/injectionTokens.ts
+++ b/src/util/injectionTokens.ts
@@ -8,7 +8,7 @@ export type TClickInterceptorConfig = {
 
 export interface ClickInterceptor{
   register: (interceptorFunction: (ev: any) => boolean, config?: TClickInterceptorConfig) => void
-  deregister: (interceptorFunction: Function) => void
+  deregister: (interceptorFunction: (ev: any) => any) => void
 }
 
 export const CONTEXT_MENU_ITEM_INJECTOR = new InjectionToken('CONTEXT_MENU_ITEM_INJECTOR')
diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
index 3dfad4e558d68a7ca22f97c78d6c6985b8dc8157..d6371324add9456c8600470a775a110490afa0e6 100644
--- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
+++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts
@@ -134,8 +134,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy {
 
   public ondestroySubscriptions: Subscription[] = []
 
-  private createNehubaPromiseRs: Function
-  private createNehubaPromise = new Promise(rs => {
+  private createNehubaPromiseRs: () => void
+  private createNehubaPromise = new Promise<void>(rs => {
     this.createNehubaPromiseRs = rs
   })
 
diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.spec.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.spec.ts
index 258c8ccdde186a21fdce5363df728073c65311c1..74176bf7d66e14e882fdba09ec35fc4b5a191db6 100644
--- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.spec.ts
+++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.spec.ts
@@ -55,8 +55,8 @@ describe('> nehubaViewerGlue.component.ts', () => {
   let mockStore: MockStore
   let rootLoader: HarnessLoader
   let fixture: ComponentFixture<NehubaGlueCmp>
-  beforeEach( async(() => {
-    TestBed.configureTestingModule({
+  beforeEach( async () => {
+    await TestBed.configureTestingModule({
       imports: [
         CommonModule,
         AngularMaterialModule,
@@ -116,7 +116,7 @@ describe('> nehubaViewerGlue.component.ts', () => {
         }
       ]
     }).compileComponents()
-  }))
+  })
 
   beforeEach(() => {
     mockStore = TestBed.inject(MockStore)
diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
index 665d7a33b321f34d66f362c1a23492b7653351ec..21b11a8d5f56ac41c444856ca99f88d0a4133cd7 100644
--- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
+++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
@@ -84,7 +84,7 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnChanges, OnDestroy, A
   public viewerLoaded: boolean = false
 
   private onhoverSegments = []
-  private onDestroyCb: Function[] = []
+  private onDestroyCb: (() => void)[] = []
   private viewerUnit: NehubaViewerUnit
   private multiNgIdsRegionsLabelIndexMap: Map<string, Map<number, any>>
 
diff --git a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts
index 42c350441b7aba57d1a3d15eece54a238e25b2a7..84a54b7e24da734f57683c6981203d4516dea27a 100644
--- a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts
+++ b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerInterface.directive.spec.ts
@@ -33,12 +33,6 @@ describe('> nehubaViewerInterface.directive.ts', () => {
         providers: [
           provideMockStore({ initialState: {} })
         ]
-      }).overrideModule(BrowserDynamicTestingModule,{
-        set: {
-          entryComponents: [
-            NehubaViewerUnit
-          ]
-        }
       }).overrideComponent(DummyCmp, {
         set: {
           template: `
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
index c720fb1a073c5432924cc527d8192c5ca376806b..852a10faa56829c7ab8da8b87cbb749a19e04cc4 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
@@ -231,7 +231,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
       const { register, deregister } = clickInterceptor
       register(handleClick)
       this.onDestroyCb.push(
-        () => deregister(register)
+        () => { deregister(register) }
       )
     }
     
diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts
index f0eb2af8c0f4b65ef971973b6b979ab7a36b203c..1426fc874577952974e87f3ecc347ee632004db2 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.component.ts
+++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts
@@ -212,7 +212,7 @@ export class ViewerCmp implements OnDestroy {
 
   public context: TContextArg<TSupportedViewers>
   private templateSelected: any
-  private getRegionFromlabelIndexId: Function
+  private getRegionFromlabelIndexId: (arg: {labelIndexId: string}) => any
 
   private genericInfoCF: ComponentFactory<GenericInfoCmp>
   constructor(
diff --git a/tsconfig-aot.json b/tsconfig-aot.json
deleted file mode 100644
index 827ddbeb6dbb12d543ea1678d2c99ffa4389cbad..0000000000000000000000000000000000000000
--- a/tsconfig-aot.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "exclude": [
-    "**/*.spec.ts",
-    "./spec/*",
-    "src/atlasViewerExports/*"
-  ],
-  "compilerOptions": {
-    "experimentalDecorators": true,
-    "emitDecoratorMetadata": true,
-    "moduleResolution": "node",
-    "module": "esnext",
-    "target": "es2015",
-    "sourceMap": false,
-    "baseUrl": ".",
-    "paths": {
-      "third_party/*" : ["third_party/*"],
-      "src/*" : ["src/*"],
-      "common/*": ["common/*"]
-    }
-  },
-  "angularCompilerOptions":{
-    "fullTemplateTypeCheck": true,
-    "strictInjectionParameters": true,
-    "annotateForClosureCompiler" : true
-  }
-}
\ No newline at end of file
diff --git a/tsconfig-dev-aot.json b/tsconfig-dev-aot.json
deleted file mode 100644
index eb54150de482bdbe847a4f3348affe156f9e8b2e..0000000000000000000000000000000000000000
--- a/tsconfig-dev-aot.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "compilerOptions": {
-    "experimentalDecorators": true,
-    "emitDecoratorMetadata": true,
-    "moduleResolution": "node",
-    "module": "esnext",
-    "target": "es2015",
-    "sourceMap": true,
-    "baseUrl": ".",
-    "paths": {
-      "third_party/*" : ["third_party/*"],
-      "src/*" : ["src/*"],
-      "common/*": ["common/*"]
-    }
-  },
-  "angularCompilerOptions":{
-    "fullTemplateTypeCheck": true,
-    "strictInjectionParameters": true,
-    "annotateForClosureCompiler" : true
-  }
-}
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000000000000000000000000000000000000..9eecf098ab9df8a94086e9c511f3800652f701c8
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": [
+    "**/*.spec.ts",
+    "./spec/*",
+    "src/atlasViewerExports/*"
+  ],
+  "files": [
+    "src/main-aot.ts"
+  ]
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 1833901f2db9f5097d430a3b428314d13b8cb904..15a0003e484369a70d602ca95fa1c95174849205 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,12 +5,17 @@
     "moduleResolution": "node",
     "module": "esnext",
     "target": "es2015",
-    "sourceMap": true,
+    "sourceMap": false,
     "baseUrl": ".",
     "paths": {
       "third_party/*" : ["third_party/*"],
       "src/*" : ["src/*"],
       "common/*": ["common/*"]
     }
+  },
+  "angularCompilerOptions":{
+    "fullTemplateTypeCheck": true,
+    "strictInjectionParameters": true,
+    "annotateForClosureCompiler" : true
   }
 }
\ No newline at end of file
diff --git a/tsconfig.spec.json b/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..1397650afa3da693dcb51c426556decae59707d9
--- /dev/null
+++ b/tsconfig.spec.json
@@ -0,0 +1,9 @@
+{
+  "extends": "./tsconfig.json",
+  "files": [
+    "spec/test.ts"
+  ],
+  "include": [
+    "src/**/*.spec.ts"
+  ]
+}
\ No newline at end of file
diff --git a/webpack/webpack.aot-common.js b/webpack/webpack.aot-common.js
index 6c98c2f7cec402bdf5868eeaeec3db463ca331c8..3cff3bcc1f16439e218094165d762af1003718a8 100644
--- a/webpack/webpack.aot-common.js
+++ b/webpack/webpack.aot-common.js
@@ -1,73 +1,10 @@
 const webpack = require('webpack')
 const path = require('path')
 const HtmlWebpackPlugin = require('html-webpack-plugin')
-const ngtools = require('@ngtools/webpack')
-const AngularCompilerPlugin = ngtools.AngularCompilerPlugin
 const merge = require('webpack-merge')
 const staticAssets = require('./webpack.staticassets')
 
-const compileQuickOnePager = async () => {
-
-  const TITLE = 'Interactive Atlas Viewer Quickstart'
-
-  const showdown = require('showdown')
-  
-  const fs = require('fs')
-  const { promisify } = require('util')
-  const asyncReadfile = promisify(fs.readFile)
-  
-  const mdConverter = new showdown.Converter({
-    tables: true
-  })
-  
-  const pathToMd = path.join(__dirname, '../common/helpOnePager.md')
-  const mdData = await asyncReadfile(pathToMd, 'utf-8')
-  return `
-<!DOCTYPE html>
-<html lang="en">
-<head>
-  <meta charset="UTF-8">
-  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
-  <script src="https://unpkg.com/dompurify@latest/dist/purify.min.js"></script>
-  <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>${TITLE}</title>
-</head>
-<body class="p-4">
-  
-</body>
-<script>
-(() => {
-  const dirty = \`${mdConverter.makeHtml(mdData).replace(/\`/g, '\\`')}\`
-  const clean = DOMPurify.sanitize(dirty)
-  document.body.innerHTML = clean
-})()
-</script>
-</html>
-`
-}
-const outputPath = path.resolve(__dirname,'../dist/aot')
-
-compileQuickOnePager()
-  .then(html => {
-    const fs = require('fs')
-    const { execSync } = require('child_process')
-    const { promisify } = require('util')
-    const asyncWrite = promisify(fs.writeFile)
-    execSync(`mkdir -p ${outputPath}`)
-    return asyncWrite(path.join(outputPath, 'quickstart.html'), html, 'utf-8')
-  })
-  .catch(e => {
-    console.warn(e)
-  })
-
 const commonAot = {
-  entry: {
-    main: './src/main-aot.ts'
-  },
-  output : {
-    filename : '[name].js',
-    path : outputPath
-  },
   module: {
     rules: [
       {
@@ -80,7 +17,8 @@ const commonAot = {
         }
       },
       {
-        test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
+        // test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
+        test: /\.ts$/,
         loader: '@ngtools/webpack',
         exclude : /third_party|plugin_example|spec\.ts|test\.ts/
       },
@@ -106,11 +44,6 @@ const commonAot = {
     new HtmlWebpackPlugin({
       template : 'src/index.html'
     }),
-    new AngularCompilerPlugin({
-      tsConfigPath: 'tsconfig-aot.json',
-      entryModule: 'src/main.module#MainModule',
-      directTemplateLoading: true
-    }),
     new webpack.DefinePlugin({
       // TODO have to figure out how to set this properly
       // needed to avoid inline eval
diff --git a/webpack/webpack.aot.js b/webpack/webpack.aot.js
index 0660ec650c1501aea74a41d9e617bb4fc2d9f005..f283f84473616846b11dc1801de3f301b619bb34 100644
--- a/webpack/webpack.aot.js
+++ b/webpack/webpack.aot.js
@@ -1,6 +1,6 @@
 const merge = require('webpack-merge')
 const aotCommon = require('./webpack.aot-common')
-
-module.exports = merge(aotCommon, {
+const inputOutput = require('./webpack.entry-output')
+module.exports = merge(inputOutput, aotCommon, {
   mode: 'production',
 })
diff --git a/webpack/webpack.dev-aot.js b/webpack/webpack.dev-aot.js
index cca9f12439dd89e528541f7e5cf2edb764df26b1..c04cc954db94b630fa0fa20bf501bbcade50125f 100644
--- a/webpack/webpack.dev-aot.js
+++ b/webpack/webpack.dev-aot.js
@@ -1,8 +1,9 @@
 const merge = require('webpack-merge')
 const aotCommon = require('./webpack.aot-common')
 const path = require('path')
+const inputOutput = require('./webpack.entry-output')
 
-module.exports = merge(aotCommon, {
+module.exports = merge(inputOutput, aotCommon, {
   mode: 'development',
   devtool:'source-map',
   devServer: {
diff --git a/webpack/webpack.entry-output.js b/webpack/webpack.entry-output.js
new file mode 100644
index 0000000000000000000000000000000000000000..724913798492d58541b34c110f4685623921bb74
--- /dev/null
+++ b/webpack/webpack.entry-output.js
@@ -0,0 +1,75 @@
+const path = require('path')
+
+const compileQuickOnePager = async () => {
+
+  const TITLE = 'Interactive Atlas Viewer Quickstart'
+
+  const showdown = require('showdown')
+  
+  const fs = require('fs')
+  const { promisify } = require('util')
+  const asyncReadfile = promisify(fs.readFile)
+  
+  const mdConverter = new showdown.Converter({
+    tables: true
+  })
+  
+  const pathToMd = path.join(__dirname, '../common/helpOnePager.md')
+  const mdData = await asyncReadfile(pathToMd, 'utf-8')
+  return `
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
+  <script src="https://unpkg.com/dompurify@latest/dist/purify.min.js"></script>
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>${TITLE}</title>
+</head>
+<body class="p-4">
+  
+</body>
+<script>
+(() => {
+  const dirty = \`${mdConverter.makeHtml(mdData).replace(/\`/g, '\\`')}\`
+  const clean = DOMPurify.sanitize(dirty)
+  document.body.innerHTML = clean
+})()
+</script>
+</html>
+`
+}
+
+const outputPath = path.resolve(__dirname,'../dist/aot')
+
+compileQuickOnePager()
+  .then(html => {
+    const fs = require('fs')
+    const { execSync } = require('child_process')
+    const { promisify } = require('util')
+    const asyncWrite = promisify(fs.writeFile)
+    execSync(`mkdir -p ${outputPath}`)
+    return asyncWrite(path.join(outputPath, 'quickstart.html'), html, 'utf-8')
+  })
+  .catch(e => {
+    console.warn(e)
+  })
+
+const { AngularWebpackPlugin } = require('@ngtools/webpack')
+
+module.exports = {
+  entry: {
+    main: './src/main-aot.ts'
+  },
+  output : {
+    filename : '[name].js',
+    path : outputPath
+  },
+  plugins: [
+    new AngularWebpackPlugin({
+      tsConfigPath: 'tsconfig.app.json',
+      // entryModule: 'src/main.module#MainModule',
+      directTemplateLoading: true
+    }),
+  ]
+}
\ No newline at end of file
diff --git a/webpack/webpack.export.aot.js b/webpack/webpack.export.aot.js
deleted file mode 100644
index 2612d09449efa54b3a1e4f3bbbd16aceb4744c4b..0000000000000000000000000000000000000000
--- a/webpack/webpack.export.aot.js
+++ /dev/null
@@ -1,47 +0,0 @@
-const common = require('./webpack.common.js')
-const path = require('path')
-const ngtools = require('@ngtools/webpack')
-const HtmlWebpackPlugin = require('html-webpack-plugin')
-const AngularCompilerPlugin = ngtools.AngularCompilerPlugin
-const ClosureCompilerPlugin = require('webpack-closure-compiler')
-
-module.exports = {
-
-  entry : './src/main-aot.ts',
-  output : {
-    filename : 'main.js',
-    path : path.resolve(__dirname,'../dist/export-aot')
-  },
-  module: {
-    rules: [
-      {
-        test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
-        // test : /\.ts$/,
-        loader: '@ngtools/webpack',
-        exclude : /third_party/
-      },
-      {
-        test : /\.(html|css)$/,
-        use : {
-          loader : 'raw-loader',
-        }
-      }
-    ]
-  },
-  plugins : [
-    new HtmlWebpackPlugin({
-      template : './src/atlasViewerExports/export.html'
-    }),
-    new AngularCompilerPlugin({
-      tsConfigPath: 'tsconfig-aot.json',
-      entryModule: 'src/atlasViewerExports/export.module#ExportModule'
-    })
-  ],
-  resolve : {
-    extensions : [
-      '.ts',
-      '.js',
-      '.json'
-    ]
-  }
-}
\ No newline at end of file
diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js
index 325cdd3de8dfd4631952fe887994ab13bd5000f5..63e48c203bc1c9f34c1b540ec6e3060517e67955 100644
--- a/webpack/webpack.prod.js
+++ b/webpack/webpack.prod.js
@@ -1,6 +1,5 @@
 const common = require('./webpack.common.js')
 const merge = require('webpack-merge')
-const Uglify = require('uglifyjs-webpack-plugin')
 const path = require('path')
 const ClosureCompilerPlugin = require('webpack-closure-compiler')
 const ngAssets = require('./webpack.ngassets')
diff --git a/webpack/webpack.test.js b/webpack/webpack.test.js
index 713c1d28d4bf1a6638fbb0f1c9f61235c8fb0e8d..971e133e612a7a68a769ea79d16a2e9de4058a63 100644
--- a/webpack/webpack.test.js
+++ b/webpack/webpack.test.js
@@ -1,8 +1,8 @@
 module.exports = {
   module : {
     rules : [{
-      test: /spec\.ts$|test/,
-      loaders : ['ts-loader'],
+      test: /spec\.ts$/,
+      loader : 'ts-loader',
       exclude : /node_modules|third_party/
     }]
   },