diff --git a/docs/releases/v2.13.4.md b/docs/releases/v2.13.4.md
new file mode 100644
index 0000000000000000000000000000000000000000..d91f822860eae0e66df37e5343a397043cec012f
--- /dev/null
+++ b/docs/releases/v2.13.4.md
@@ -0,0 +1,16 @@
+# v2.13.4
+
+## Feature
+
+- Properly navigate to volume of interest based on volume meta:
+    - properly calculate the orientation
+    - properly calculate enclosed, and navigate to closest point if outside
+
+## Bugfix
+
+- Fixed expected siibra-api version
+
+## Behind the scenes
+
+- Temporary workaround for volume meta
+- More efficient caching of meta retrieval
diff --git a/mkdocs.yml b/mkdocs.yml
index 6693def5a5de6dd4dd664a5ff073f6a16b5c66bc..dd014bb59f47efbe81010951fd0be4d184404be6 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.13.4: 'releases/v2.13.4.md'
     - v2.13.3: 'releases/v2.13.3.md'
     - v2.13.2: 'releases/v2.13.2.md'
     - v2.13.1: 'releases/v2.13.1.md'
diff --git a/package.json b/package.json
index f66269cfca6562943068403b7a67a4d53e9a7ac4..1bbda561272633686c7c388c68220cff4f83c4ed 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "siibra-explorer",
-  "version": "2.13.3",
+  "version": "2.13.4",
   "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/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts
index c3543e08c2ed155d20de261fc0eb74321dcf9bfd..f2b2050ff889ab7d1590ab57280cb5e050831f5d 100644
--- a/src/atlasComponents/sapi/sapi.service.ts
+++ b/src/atlasComponents/sapi/sapi.service.ts
@@ -1,7 +1,7 @@
 import { Injectable } from "@angular/core";
 import { HttpClient } from '@angular/common/http';
 import { catchError, map, shareReplay, switchMap, take, tap } from "rxjs/operators";
-import { getExportNehuba, noop } from "src/util/fn";
+import { CachedFunction, getExportNehuba, noop } from "src/util/fn";
 import { MatSnackBar } from "@angular/material/snack-bar";
 import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
 import { EnumColorMapName } from "src/util/colorMaps";
@@ -22,7 +22,7 @@ export const useViewer = {
 } as const
 
 export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version'
-export const EXPECTED_SIIBRA_API_VERSION = '0.3.13'
+export const EXPECTED_SIIBRA_API_VERSION = '0.3.14'
 
 let BS_ENDPOINT_CACHED_VALUE: Observable<string> = null
 
@@ -34,6 +34,7 @@ type PaginatedResponse<T> = {
   pages?: number
 }
 
+const serialization = (sxplr: SxplrTemplate) => sxplr?.id
 
 @Injectable({
   providedIn: 'root'
@@ -208,6 +209,9 @@ export class SAPI{
     })
   }
 
+  @CachedFunction({
+    serialization: (id, params) => `featDetail:${id}:${Object.entries(params || {}).map(([key, val]) => `${key},${val}`).join('.')}`
+  })
   getV3FeatureDetailWithId(id: string, params: Record<string,  string> = {}) {
     return this.v3Get("/feature/{feature_id}", {
       path: {
@@ -215,7 +219,8 @@ export class SAPI{
       },
       query_param: params
     } as any).pipe(
-      switchMap(val => translateV3Entities.translateFeature(val))
+      switchMap(val => translateV3Entities.translateFeature(val)),
+      shareReplay(1),
     )
   }
 
@@ -446,7 +451,10 @@ export class SAPI{
     }).toPromise()
   }
 
-  public useViewer(template: SxplrTemplate) {
+  // useViewer is debouncely called everytime user updates the url
+  // caches the response
+  @CachedFunction({ serialization }) 
+  useViewer(template: SxplrTemplate) {
     if (!template) {
       return of(null as keyof typeof useViewer)
     }
diff --git a/src/atlasComponents/sapi/translateV3.ts b/src/atlasComponents/sapi/translateV3.ts
index dabec3badf48d08d9e8a739459ebe5b1a5985f97..666f24b5246b56d704451a9090feb5f2b3a233e9 100644
--- a/src/atlasComponents/sapi/translateV3.ts
+++ b/src/atlasComponents/sapi/translateV3.ts
@@ -14,6 +14,92 @@ const BIGBRAIN_XZ = [
   [68.533, 62.222],
 ]
 
+const TMP_META_REGISTRY: Record<string, MetaV1Schema> = {
+  "https://data-proxy.ebrains.eu/api/v1/public/buckets/tanner-test/fullSharded_v1": {
+    version: 1,
+    preferredColormap: ["greyscale"],
+    data: {
+      type: "image/1d",
+      range: [{
+        min: 0.2,
+        max: 0.4
+      }]
+    },
+    transform: [[-1,0,0,5662500],[0,0,1,-6562500],[0,-1,0,3962500],[0,0,0,1]]
+  },
+  "https://1um.brainatlas.eu/pli-bigbrain/fom/precomputed": {
+    version: 1,
+    data: {
+      type: "image/3d"
+    },
+    bestViewPoints: [{
+      type: "enclosed",
+      points: [{
+        type: "point",
+        value: [-16.625, -80.813, 41.801]
+      },{
+        type: "point",
+        value: [-16.625, -64.293, -66.562]
+      },{
+        type: "point",
+        value: [-16.625, 86.557, -42.685]
+      },{
+        type: "point",
+        value: [-16.625, 69.687, 63.015]
+      }]
+    }],
+    transform: [[7.325973427896315e-8,2.866510051546811e-8,-1,-16600000],[-0.9899035692214966,0.14174138009548187,-6.845708355740499e-8,70884888],[-0.14174138009548187,-0.9899035692214966,-3.875962661936683e-8,64064704],[0,0,0,1]]
+  },
+  "https://1um.brainatlas.eu/cyto_reconstructions/ebrains_release/BB_1um/VOI_1/precomputed": {
+    version: 1,
+    data: {
+      type: "image/1d"
+    },
+    preferredColormap: ["greyscale"],
+    bestViewPoints: [{
+      type: "enclosed",
+      points: [{
+        type: "point",
+        value: [-11.039, -58.450, 4.311]
+      },{
+        type: "point",
+        value: [-9.871, -58.450, -1.649]
+      },{
+        type: "point",
+        value: [-3.947, -58.450, -0.377]
+      },{
+        type: "point",
+        value: [-5.079, -58.450, 5.496]
+      }]
+    }],
+    transform: [[0.9986788630485535,0.1965026557445526,0.27269935607910156,-11887736],[0,0,1,-61450000],[0.20538295805454254,-0.9990047812461853,0.052038706839084625,4165836.25],[0,0,0,1]]
+  },
+  "https://1um.brainatlas.eu/cyto_reconstructions/ebrains_release/BB_1um/VOI_2/precomputed": {
+    version: 1,
+    data: {
+      type: "image/1d"
+    },
+    preferredColormap: ["greyscale"],
+    bestViewPoints: [{
+      type: "enclosed",
+      points: [{
+        type: "point",
+        value: [-10.011, -58.450, -2.879]
+      },{
+        type: "point",
+        value: [-8.707, -58.450, -8.786]
+      },{
+        type: "point",
+        value: [-3.305, -58.450, -7.728]
+      },{
+        type: "point",
+        value: [-4.565, -58.450, -1.703]
+      }]
+    }],
+    transform: [[0.9199221134185791,0.22926874458789825,0.2965584993362427,-10976869],[0,0,1,-61450000],[0.18267445266246796,-1.0079853534698486,0.01068924367427826,-2853557],[0,0,0,1]]
+  },
+}
+
 class TranslateV3 {
   
   #atlasMap: Map<string, PathReturn<"/atlases/{atlas_id}">> = new Map()
@@ -365,6 +451,9 @@ class TranslateV3 {
   }
 
   async fetchMeta(url: string): Promise<MetaV1Schema|null> {
+    if (url in TMP_META_REGISTRY) {
+      return TMP_META_REGISTRY[url]
+    }
     const is1umRegisteredSlices = url.startsWith("https://1um.brainatlas.eu/registered_sections/bigbrain")
     if (is1umRegisteredSlices) {
       const found = /B20_([0-9]{4})/.exec(url)
diff --git a/src/util/colorMaps.ts b/src/util/colorMaps.ts
index e62b785434757f3e36bf1c28cc92e401fa9b2a50..ff2a9454644ff79443482d0a4cbf02f591e414d8 100644
--- a/src/util/colorMaps.ts
+++ b/src/util/colorMaps.ts
@@ -22,6 +22,13 @@ export enum EnumColorMapName{
   RGB="rgb (3 channel)"
 }
 
+export const CMByName: Record<string, EnumColorMapName> = {}
+
+for (const [key, value] of Object.entries(EnumColorMapName)) {
+  CMByName[key] = value
+  CMByName[value as string] = value
+}
+
 interface IColorMap{
   /**
    * header
diff --git a/src/util/constants.ts b/src/util/constants.ts
index da2e383309c9b2493780cb429a65b669ccb65941..2023510adb1789be8083d72880400c3569e8f6ad 100644
--- a/src/util/constants.ts
+++ b/src/util/constants.ts
@@ -71,48 +71,8 @@ export const getHttpHeader: () => HttpHeaders = () => {
 }
 
 export const COLORMAP_IS_JET = `// iav-colormap-is-jet`
-import { EnumColorMapName, mapKeyColorMap } from './colorMaps'
 import { InjectionToken } from "@angular/core"
 
-export const getShader = ({
-  colormap = EnumColorMapName.GREYSCALE,
-  lowThreshold = 0,
-  highThreshold = 1,
-  brightness = 0,
-  contrast = 0,
-  removeBg = false
-} = {}): string => {
-  const { header, main, premain, override } = mapKeyColorMap.get(colormap) || (() => {
-    return mapKeyColorMap.get(EnumColorMapName.GREYSCALE)
-  })()
-
-  if (override) {
-    return override()
-  }
-
-  // so that if lowthreshold is defined to be 0, at least some background removal will be done
-  const _lowThreshold = lowThreshold + 1e-10
-  return `${header}
-${premain}
-void main() {
-  float raw_x = toNormalized(getDataValue());
-  float x = (raw_x - ${_lowThreshold.toFixed(10)}) / (${highThreshold - _lowThreshold}) ${ brightness > 0 ? '+' : '-' } ${Math.abs(brightness).toFixed(10)};
-
-  ${ removeBg ? 'if(x>1.0){emitTransparent();}else if(x<0.0){emitTransparent();}else{' : '' }
-    vec3 rgb;
-    ${main}
-    emitRGB(rgb*exp(${contrast.toFixed(10)}));
-  ${ removeBg ? '}' : '' }
-}
-`
-}
-
-export const PMAP_DEFAULT_CONFIG = {
-  colormap: EnumColorMapName.VIRIDIS,
-  lowThreshold: 0.05,
-  removeBg: true
-}
-
 export const CYCLE_PANEL_MESSAGE = `[spacebar] to cycle through views`
 
 export const UNSUPPORTED_PREVIEW = [{
diff --git a/src/util/fn.ts b/src/util/fn.ts
index 1508dc6303509477d45e744e28f23d5e1ae9d1eb..c8467e55d899bf5e65f7b6dafcb8196e2d470a0b 100644
--- a/src/util/fn.ts
+++ b/src/util/fn.ts
@@ -1,5 +1,7 @@
 import { interval, Observable, of } from 'rxjs'
 import { filter, mapTo, take } from 'rxjs/operators'
+import { CMByName, EnumColorMapName, mapKeyColorMap } from './colorMaps'
+import { MetaV1Schema } from 'src/atlasComponents/sapi/typeV3'
 
 
 // eslint-disable-next-line  @typescript-eslint/no-empty-function
@@ -443,3 +445,139 @@ export async function waitFor(predicate: () => boolean) {
     await wait(16)
   }
 }
+/**
+ * copied from ng-layer-tune@0.0.22
+ * TODO export to an individual component/library
+ * OR use monorepo
+ */
+const cmEncodingVersion = 'encodedCmState-0.1'
+
+type TGetShaderCfg = {
+  colormap: EnumColorMapName
+  lowThreshold: number
+  highThreshold: number
+  brightness: number
+  contrast: number
+  removeBg: boolean
+  hideZero: boolean
+  opacity: number
+}
+
+function encodeBool(...flags: boolean[]) {
+  if (flags.length > 8) {
+    throw new Error(`encodeBool can only handle upto 8 bools`)
+  }
+  let rValue = 0
+  flags.forEach((flag, idx) => {
+    if (flag) {
+      rValue += (1 << idx)
+    }
+  })
+  return rValue
+}
+
+
+export function encodeState(cfg: TGetShaderCfg): string {
+  const {
+    brightness,
+    colormap,
+    contrast,
+    hideZero,
+    highThreshold,
+    lowThreshold,
+    opacity,
+    removeBg
+  } = cfg
+
+  /**
+   * encode Enum as key of Enum
+   */
+  const cmstring = Object.keys(EnumColorMapName).find(v => EnumColorMapName[v] === colormap)
+
+  const array = new Float32Array([
+    brightness,
+    contrast,
+    lowThreshold,
+    highThreshold,
+    opacity,
+    encodeBool(hideZero, removeBg)
+  ])
+  
+  const encodedVal = window.btoa(new Uint8Array(array.buffer).reduce((data, v) => data + String.fromCharCode(v), ''))
+  return `${cmEncodingVersion}:${cmstring}:${encodedVal}`
+}
+
+export const getShader = ({
+  colormap = EnumColorMapName.GREYSCALE,
+  lowThreshold = 0,
+  highThreshold = 1,
+  brightness = 0,
+  contrast = 0,
+  removeBg = false
+} = {}): string => {
+  const { header, main, premain, override } = mapKeyColorMap.get(colormap) || (() => {
+    return mapKeyColorMap.get(EnumColorMapName.GREYSCALE)
+  })()
+
+  const encodedStr = encodeState({
+    colormap,
+    brightness,
+    highThreshold,
+    lowThreshold,
+    contrast,
+    hideZero: false,
+    opacity: 1.0,
+    removeBg: false
+  })
+
+  if (override) {
+    return `// ${encodedStr}\n${override()}`
+  }
+
+  // so that if lowthreshold is defined to be 0, at least some background removal will be done
+  const _lowThreshold = lowThreshold + 1e-10
+  return `// ${encodedStr}
+${header}
+${premain}
+void main() {
+  float raw_x = toNormalized(getDataValue());
+  float x = (raw_x - ${_lowThreshold.toFixed(10)}) / (${highThreshold - _lowThreshold}) ${ brightness > 0 ? '+' : '-' } ${Math.abs(brightness).toFixed(10)};
+
+  ${ removeBg ? 'if(x>1.0){emitTransparent();}else if(x<0.0){emitTransparent();}else{' : '' }
+    vec3 rgb;
+    ${main}
+    emitRGB(rgb*exp(${contrast.toFixed(10)}));
+  ${ removeBg ? '}' : '' }
+}
+`
+}
+
+export function getShaderFromMeta(meta: MetaV1Schema){
+  let colormap = EnumColorMapName.GREYSCALE
+
+  if (meta?.data?.type === "image/3d") {
+    colormap = EnumColorMapName.RGB
+  } else {
+    for (const _colormap of meta?.preferredColormap || []) {
+      if (_colormap in CMByName) {
+        colormap = CMByName[_colormap]
+        break
+      }
+    }
+  }
+
+  let low: number = 0
+  let high: number = 1
+
+  if (meta?.data?.type === "image/1d") {
+    const { max, min } = meta.data.range?.[0] || { min: 0, max: 1 }
+    low = min
+    high = max
+  }
+  
+  return getShader({
+    colormap,
+    lowThreshold: low,
+    highThreshold: high
+  })
+}
diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.effects.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.effects.ts
index d0f4bd4c9b4a8cd93c5eb724dc74fb4f4170faf2..eece084e4da29edeebd662ffc53811db49557e67 100644
--- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.effects.ts
+++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.effects.ts
@@ -8,7 +8,7 @@ import { SAPI } from "src/atlasComponents/sapi"
 import { atlasAppearance, atlasSelection } from "src/state";
 import { arrayEqual } from "src/util/array";
 import { EnumColorMapName } from "src/util/colorMaps";
-import { getShader } from "src/util/constants";
+import { getShader } from "src/util/fn";
 import { PMAP_LAYER_NAME } from "../constants";
 import { QuickHash } from "src/util/fn";
 import { getParcNgId } from "../config.service";
diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
index dffa37da9a7f919967e83b9a3af061b1d3ce72a9..38d24aea975caaec215434de964f940741640c33 100644
--- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
+++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts
@@ -10,7 +10,7 @@ import { arrayEqual } from "src/util/array";
 import { SxplrRegion } from "src/atlasComponents/sapi/sxplrTypes";
 import { AnnotationLayer } from "src/atlasComponents/annotations";
 import { PMAP_LAYER_NAME } from "../constants"
-import { getShader } from "src/util/constants";
+import { getShader } from "src/util/fn";
 import { BaseService } from "../base.service/base.service";
 
 export const BACKUP_COLOR = {
diff --git a/src/viewerModule/nehuba/ngLayerCtlModule/ngLayerCtl/ngLayerCtrl.component.ts b/src/viewerModule/nehuba/ngLayerCtlModule/ngLayerCtl/ngLayerCtrl.component.ts
index 9ddf114f71c86ee55bfbcf0c9b85d186bb7c496b..42c0c7264c3b5d63b9a87e7cb41ece949b3db698 100644
--- a/src/viewerModule/nehuba/ngLayerCtlModule/ngLayerCtl/ngLayerCtrl.component.ts
+++ b/src/viewerModule/nehuba/ngLayerCtlModule/ngLayerCtl/ngLayerCtrl.component.ts
@@ -5,9 +5,7 @@ import { CONST } from "common/constants"
 import { Observable } from "rxjs";
 import { atlasAppearance, atlasSelection } from "src/state";
 import { NehubaViewerUnit, NEHUBA_INSTANCE_INJTKN } from "src/viewerModule/nehuba";
-import { getExportNehuba } from "src/util/fn";
-import { getShader } from "src/util/constants";
-import { EnumColorMapName } from "src/util/colorMaps";
+import { getExportNehuba, getShaderFromMeta } from "src/util/fn";
 import { MetaV1Schema, isEnclosed } from "src/atlasComponents/sapi/typeV3";
 
 type Vec4 = [number, number, number, number]
@@ -122,17 +120,7 @@ export class NgLayerCtrlCmp implements OnChanges, OnDestroy{
         this.removeLayer()
         this.removeLayer = null
       }
-      try {
-        const resp = await fetch(`${this.source}/meta.json`)
-        const metaJson = await resp.json()
-        const is3D = metaJson?.data?.type === "image/3d"
-        if (is3D) {
-          this.shader = getShader({
-            colormap: EnumColorMapName.RGB
-          })
-        }
-        // eslint-disable-next-line no-empty
-      } catch (e) {}
+      this.shader = getShaderFromMeta(this.meta)
       
       this.store.dispatch(
         atlasAppearance.actions.addCustomLayer({
@@ -187,21 +175,70 @@ export class NgLayerCtrlCmp implements OnChanges, OnDestroy{
       const pt2 = vec3.fromValues(...enclosed.points[2].value)
       vec3.sub(pt1, pt1, pt0)
       vec3.sub(pt2, pt2, pt0)
+
+      /**
+       * pt1 and pt2 now unit vectors going from pt0 to pt1 and pt0 to pt2 respectively
+       */
       vec3.normalize(pt1, pt1)
       vec3.normalize(pt2, pt2)
 
+      /**
+       * calculate rotation first
+       */
+      const z0 = vec3.fromValues(0, 0, 1)
+      const cross = vec3.cross(vec3.create(), z0, pt1)
+      const w = Math.sqrt(2) + vec3.dot(z0, pt1)
+      quat.set(q, ...cross, w)
+      quat.normalize(q, q)
+
+      /**
+       * curr is now vector going from pt0 to current navigation position
+       */
       vec3.sub(curr, curr, pt0)
 
-      vec3.mul(pt1, pt1, curr)
-      vec3.mul(pt2, pt2, curr)
+      const normal = vec3.cross(vec3.create(), pt1, pt2)
+      vec3.normalize(normal, normal)
+      vec3.mul(normal, normal, curr)
+
+      const inPlaneDisplacement = vec3.sub(vec3.create(), curr, normal)
+
+      /**
+       * check enclosedness
+       * also caches the closes point
+       */
+      const ipdCoord = vec3.add(vec3.create(), pt0, inPlaneDisplacement)
+      const allPoints = enclosed.points.map(v => vec3.fromValues(...v.value))
+      let sum = 0
+      let minDist: number = Number.POSITIVE_INFINITY
+      let pos: any
+      for (let i = 0; i < allPoints.length; i++) {
+        const a = vec3.sub(vec3.create(), allPoints[i], ipdCoord)
+        const b = vec3.sub(vec3.create(), allPoints[(i + 1) % allPoints.length], ipdCoord)
+        const angle = vec3.angle(a, b)
+        sum += angle
 
-      const resultant = vec3.add(vec3.create(), pt1, pt2)
-      vec3.add(resultant, resultant, pt0)
+        const dist = vec3.length(a)
+        if (dist < minDist) {
+          minDist = dist
+          pos = allPoints[i]
+        }
+      }
+
+      /**
+       * Since inPlaneDisplacement is a point on the plane
+       * If the sum of all points == PI, then the point is enclosed
+       * Assuming simple concave shapes
+       */
+      const isEnclosed = Math.abs(sum - (2 * Math.PI)) < 0.05
+
+      const resultant = isEnclosed
+        ? vec3.add(vec3.create(), inPlaneDisplacement, pt0)
+        : pos
       vec3.scale(resultant, resultant, 1e6)
       position = Array.from(resultant)
     }
     
-    
+
     this.store.dispatch(
       atlasSelection.actions.navigateTo({
         navigation: {
diff --git a/src/viewerModule/nehuba/userLayers/service.ts b/src/viewerModule/nehuba/userLayers/service.ts
index 65bbcebb2e1a705310769f949217d6badf9bfe6e..5f9c1e130ce2ea589b26293292ccefe2be0ae915 100644
--- a/src/viewerModule/nehuba/userLayers/service.ts
+++ b/src/viewerModule/nehuba/userLayers/service.ts
@@ -1,8 +1,8 @@
 import { Injectable, OnDestroy } from "@angular/core"
 import { MatDialog } from "@angular/material/dialog"
 import { select, Store } from "@ngrx/store"
-import { concat, from, of, Subscription } from "rxjs"
-import { catchError, map, pairwise, switchMap } from "rxjs/operators"
+import { concat, forkJoin, from, of, Subscription } from "rxjs"
+import { map, pairwise, switchMap } from "rxjs/operators"
 import {
   linearTransform,
   TVALID_LINEAR_XFORM_DST,
@@ -12,9 +12,11 @@ import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.se
 import { RouterService } from "src/routerModule/router.service"
 import * as atlasAppearance from "src/state/atlasAppearance"
 import { EnumColorMapName } from "src/util/colorMaps"
-import { getShader } from "src/util/constants"
+import { getShader, getShaderFromMeta } from "src/util/fn"
 import { getExportNehuba, getUuid } from "src/util/fn"
 import { UserLayerInfoCmp } from "./userlayerInfo/userlayerInfo.component"
+import { translateV3Entities } from "src/atlasComponents/sapi/translateV3"
+import { MetaV1Schema } from "src/atlasComponents/sapi/typeV3"
 
 type OmitKeys = "clType" | "id" | "source"
 type Meta = {
@@ -214,17 +216,36 @@ export class UserLayerService implements OnDestroy {
            * if so, try to fetch it, and set it as transform
            */
           if (!curr) {
-            return of([prev, curr, null])
+            return of({ prev, curr, meta: null as MetaV1Schema })
           }
           if (!curr.startsWith("precomputed://")) {
-            return of([prev, curr, null])
+            return of({ prev, curr, meta: null as MetaV1Schema })
           }
-          return from(fetch(`${curr.replace('precomputed://', '')}/transform.json`).then(res => res.json())).pipe(
-            catchError(() => of([prev, curr, null])),
-            map(transform => [prev, curr, transform])
+          const url = curr.replace("precomputed://", "")
+          
+          
+          return forkJoin({
+            transform: fetch(`${url}/transform.json`)
+              .then(res => res.json() as Promise<MetaV1Schema["transform"]>)
+              .catch(_e => null as MetaV1Schema["transform"]),
+            meta: from(
+              translateV3Entities.fetchMeta(url)
+              .catch(_e => null as MetaV1Schema)  
+            )
+          }).pipe(
+            map(({ transform, meta }) => {
+              return {
+                prev,
+                curr,
+                meta: {
+                  ...meta,
+                  transform: meta?.transform || transform
+                }
+              }
+            }),
           )
         })
-      ).subscribe(([prev, curr, transform]) => {
+      ).subscribe(({ prev, curr, meta }) => {
         if (prev) {
           this.removeUserLayer(prev)
         }
@@ -236,10 +257,8 @@ export class UserLayerService implements OnDestroy {
               message: `Overlay layer populated in URL`,
             },
             {
-              shader: getShader({
-                colormap: EnumColorMapName.MAGMA,
-              }),
-              transform
+              shader: getShaderFromMeta(meta),
+              transform: meta.transform
             }
           )
         }