diff --git a/devTools/canvasmodel/model.d.ts b/devTools/canvasmodel/model.d.ts
index 0a186715981d22320cb89819f27c9337471a8f6b..69e625dfe592629b702717ec7394ee08293e37ca 100644
--- a/devTools/canvasmodel/model.d.ts
+++ b/devTools/canvasmodel/model.d.ts
@@ -39,6 +39,7 @@ declare interface BlendPatternSpec {
 declare type BlendSpec = string | BlendGradientSpec | BlendPatternSpec;
 
 declare interface CompositeLayerParams {
+	model?: any;
 	/**
 	 * Render the layer. Default true, only exact `false` value disables rendering
 	 */
@@ -70,7 +71,7 @@ declare interface CompositeLayerParams {
 	/**
 	 * Mask, a stencil image to cut out and display only select parts of this layer.
 	 */
-	masksrc?: string;
+	masksrc?: string | HTMLCanvasElement;
 	/**
 	 * Alpha, 0-1. Default 1
 	 */
@@ -101,13 +102,14 @@ declare interface CompositeLayerParams {
 	 * Animation name
 	 */
 	animation?: string;
+	scale?: boolean;
 }
 declare interface CompositeLayerSpec extends CompositeLayerParams {
 	name?: string;
 	/**
 	 * Image URL
 	 */
-	src: string;
+	src: string | HTMLCanvasElement;
 }
 
 declare interface KeyframeSpec {
diff --git a/devTools/canvasmodel/renderer.d.ts b/devTools/canvasmodel/renderer.d.ts
index 4713d4bec0f64ba2cfd140001e5df71e7b9378db..dff16002b448e1fe9a2c616d4d2bba175f7beff6 100644
--- a/devTools/canvasmodel/renderer.d.ts
+++ b/devTools/canvasmodel/renderer.d.ts
@@ -1,8 +1,6 @@
-/// <reference path="model.d.ts" />
-/// <reference types="tinycolor2" />
 declare namespace Renderer {
     export interface LayerImageLoader {
-        loadImage(src: string, layer: CompositeLayer, successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement) => any, errorCallback: (src: string, layer: CompositeLayer, error: any) => any): any;
+        loadImage(src: string, layer: CompositeLayer, successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement | HTMLCanvasElement) => any, errorCallback: (src: string, layer: CompositeLayer, error: any) => any): any;
     }
     export const DefaultImageLoader: LayerImageLoader;
     export let ImageLoader: LayerImageLoader;
@@ -52,7 +50,7 @@ declare namespace Renderer {
     /**
      * Creates a cutout of color in shape of sourceImage
      */
-    export function cutout(sourceImage: CanvasImageSource, color: string | CanvasGradient | CanvasPattern, canvas?: CanvasRenderingContext2D): CanvasRenderingContext2D;
+    export function cutout(sourceImage: CanvasImageSource, color: string, canvas?: CanvasRenderingContext2D): CanvasRenderingContext2D;
     /**
      * Cuts out from base a shape in form of stencil.
      * Modifies and returns base.
@@ -61,7 +59,7 @@ declare namespace Renderer {
     /**
      * Paints sourceImage over cutout of it filled with color.
      */
-    export function composeOverCutout(sourceImage: CanvasImageSource, color: string | CanvasGradient | CanvasPattern, blendMode?: GlobalCompositeOperation, canvas?: CanvasRenderingContext2D): CanvasRenderingContext2D;
+    export function composeOverCutout(sourceImage: CanvasImageSource, color: string, blendMode?: GlobalCompositeOperation, canvas?: CanvasRenderingContext2D): CanvasRenderingContext2D;
     /**
      * Repeatedly fill all sub-frames of canvas with same style.
      * (Makes sense with gradient and pattern fills, to keep consistents across all sub-frames)
@@ -216,6 +214,10 @@ declare namespace Renderer {
         start(): void;
         stop(): void;
     }
+    export function refresh(model: {
+        layerList: CompositeLayerSpec[];
+        redraw: () => void;
+    }): void;
     export function invalidateLayerCaches(layers: CompositeLayer[]): void;
     export function animateLayersAgain(): any;
     export let Animations: Dict<AnimationSpec>;
diff --git a/devTools/canvasmodel/renderer.ts b/devTools/canvasmodel/renderer.ts
index bff18cb37550ce49c89e9237d5d52160e1eff15c..6899b60b190f1e9bd564b4e1c62f0c31aae4bbfb 100644
--- a/devTools/canvasmodel/renderer.ts
+++ b/devTools/canvasmodel/renderer.ts
@@ -11,26 +11,41 @@ namespace Renderer {
 			return new Date().getTime()
 		};
 
+	function rescaleImageToCanvasHeight(image: HTMLImageElement, targetHeight: number): HTMLCanvasElement {
+		const aspectRatio = image.width / image.height;
+		const scaledWidth = targetHeight * aspectRatio;
+		const i2 = createCanvas(scaledWidth, targetHeight);
+		i2.imageSmoothingEnabled = false;
+		i2.drawImage(image, 0, 0, scaledWidth, targetHeight);
+		return i2.canvas;
+	}
+
 	export interface LayerImageLoader {
 		loadImage(src: string,
-		          layer: CompositeLayer,
-		          successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement) => any,
-		          errorCallback: (src: string, layer: CompositeLayer, error: any) => any
+			layer: CompositeLayer,
+			successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement | HTMLCanvasElement) => any,
+			errorCallback: (src: string, layer: CompositeLayer, error: any) => any
 		);
 	}
 	export const DefaultImageLoader: LayerImageLoader = {
 		loadImage(src: string,
-		          layer: CompositeLayer,
-		          successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement) => any,
-		          errorCallback: (src: string, layer: CompositeLayer, error: any) => any) {
-			const image = new Image();
-			image.onload = () => {
-				successCallback(src, layer, image);
-			}
-			image.onerror = (event) => {
-				errorCallback(src, layer, event);
+			layer: CompositeLayer,
+			successCallback: (src: string, layer: CompositeLayer, image: HTMLImageElement | HTMLCanvasElement) => any,
+			errorCallback: (src: string, layer: CompositeLayer, error: any) => any) {
+			if (src instanceof HTMLCanvasElement) {
+				successCallback(src, layer, src);
+			} else {
+				const image = new Image();
+				image.onload = () => {
+					// Rescale the image to the canvas height, if layer.scale is true
+					const rescaledImage = layer.scale ? rescaleImageToCanvasHeight(image, layer.model.height) : image;
+					successCallback(src, layer, rescaledImage);
+				};
+				image.onerror = (event) => {
+					errorCallback(src, layer, event);
+				};
+				image.src = src;
 			}
-			image.src = src;
 		}
 	}
 	export let ImageLoader: LayerImageLoader = DefaultImageLoader;
@@ -989,7 +1004,9 @@ namespace Renderer {
 					}
 					layer.image = image;
 					layer.imageSrc = src;
-					ImageCaches[src] = image;
+					if (!(layer.src instanceof HTMLCanvasElement)) {
+						ImageCaches[src] = image as HTMLImageElement;
+					}
 					maybeRenderResult();
 				},
 				(src,layer,error)=>{
@@ -1016,7 +1033,9 @@ namespace Renderer {
 					}
 					layer.mask = image;
 					layer.cachedMaskSrc = src;
-					ImageCaches[src] = image;
+					if (!(layer.src instanceof HTMLCanvasElement)) {
+						ImageCaches[src] = image as HTMLImageElement;
+					}
 					maybeRenderResult();
 				},
 				(src,layer,error)=>{
@@ -1036,7 +1055,7 @@ namespace Renderer {
 		for (const layer of layers) {
 			let needImage = true;
 			if (layer.image) {
-				if (layer.imageSrc === layer.src) {
+				if (layer.imageSrc === layer.src || layer.src instanceof HTMLCanvasElement) {
 					needImage = false;
 				} else {
 					// Layer was loaded in previous render, but then its src was changed - purge cache
@@ -1057,7 +1076,7 @@ namespace Renderer {
 			}
 			let needMask = !!layer.masksrc;
 			if (layer.mask) {
-				if (layer.cachedMaskSrc === layer.masksrc) {
+				if (layer.cachedMaskSrc === layer.masksrc || layer.masksrc instanceof HTMLCanvasElement) {
 					needMask = false;
 				} else {
 					// Layer mask was loaded in previous render, but then its masksrc was changed - purge cache
@@ -1129,6 +1148,13 @@ namespace Renderer {
 		stop(): void;
 	}
 
+	export function refresh(model: { layerList: CompositeLayerSpec[], redraw: () => void }) {
+		ImageCaches = {};
+		ImageErrors = {};
+		invalidateLayerCaches(model.layerList);
+		model.redraw();
+	}
+
 	export function invalidateLayerCaches(layers: CompositeLayer[]) {
 		for (let layer of layers) {
 			delete layer.image;
diff --git a/devTools/canvasmodel/tsconfig.json b/devTools/canvasmodel/tsconfig.json
index 387538205dbd4a87fc4cb368e5c8dc74173390c2..ee91c9ca13969e7b512269d41e20219117846fc4 100644
--- a/devTools/canvasmodel/tsconfig.json
+++ b/devTools/canvasmodel/tsconfig.json
@@ -1,7 +1,6 @@
 {
   "compilerOptions": {
-    "target": "ES2015",
-    "lib": ["DOM", "ES2015", "ES2017.Object"],
+    "target": "ES2020",
     "module": "None",
     "moduleResolution": "Node",
     "outDir": ".",
diff --git a/game/03-JavaScript/00-libs/renderer.js b/game/03-JavaScript/00-libs/renderer.js
index a6141c90ef8d7c4434eef8a811a2cc7e16d76c96..ddc1454b452c3220aedb017ac18abe1d84f504f9 100644
--- a/game/03-JavaScript/00-libs/renderer.js
+++ b/game/03-JavaScript/00-libs/renderer.js
@@ -1,4 +1,6 @@
 /* eslint-disable jsdoc/require-param */
+/* eslint-disable spaced-comment */
+/* eslint-disable no-var */
 /* eslint-disable prettier/prettier */
 ///<reference path="model.d.ts"/>
 /*
@@ -10,33 +12,33 @@ var Renderer;
         function () {
             return performance.now();
         } : function () {
-            return new Date().getTime();
-        };
-
-	function rescaleImageToCanvasHeight(image, targetHeight) {
-		const aspectRatio = image.width / image.height;
-		const scaledWidth = targetHeight * aspectRatio;
-		const i2 = createCanvas(scaledWidth, targetHeight);
-		i2.imageSmoothingEnabled = false;
+        return new Date().getTime();
+    };
+    function rescaleImageToCanvasHeight(image, targetHeight) {
+        const aspectRatio = image.width / image.height;
+        const scaledWidth = targetHeight * aspectRatio;
+        const i2 = createCanvas(scaledWidth, targetHeight);
+        i2.imageSmoothingEnabled = false;
         i2.drawImage(image, 0, 0, scaledWidth, targetHeight);
         return i2.canvas;
-	}
+    }
     Renderer.DefaultImageLoader = {
         loadImage(src, layer, successCallback, errorCallback) {
-			if (src instanceof HTMLCanvasElement) {
-				successCallback(src, layer, src);
-			} else {
-				const image = new Image();
-				image.onload = () => {
-					// Rescale the image to the canvas height, if layer.scale is true
-					const rescaledImage = layer.scale ? rescaleImageToCanvasHeight(image, layer.model.height) : image;
-					successCallback(src, layer, rescaledImage);
-				};
-				image.onerror = (event) => {
-					errorCallback(src, layer, event);
-				};
-				image.src = src;
-			}
+            if (src instanceof HTMLCanvasElement) {
+                successCallback(src, layer, src);
+            }
+            else {
+                const image = new Image();
+                image.onload = () => {
+                    // Rescale the image to the canvas height, if layer.scale is true
+                    const rescaledImage = layer.scale ? rescaleImageToCanvasHeight(image, layer.model.height) : image;
+                    successCallback(src, layer, rescaledImage);
+                };
+                image.onerror = (event) => {
+                    errorCallback(src, layer, event);
+                };
+                image.src = src;
+            }
         }
     };
     Renderer.ImageLoader = Renderer.DefaultImageLoader;
@@ -319,7 +321,7 @@ var Renderer;
                 }
                 else if (typeof target.brightness === 'number' && typeof source.brightness === 'object') {
                     const brightnessToAdd = target.brightness;
-                    target.brightness = Object.assign({}, source.brightness);
+                    target.brightness = { ...source.brightness };
                     for (const [adjustmentIndex, adjustment] of target.brightness.adjustments.entries()) {
                         if (typeof adjustment === 'number') {
                             target.brightness.adjustments[adjustmentIndex] += brightnessToAdd;
@@ -418,24 +420,26 @@ var Renderer;
         if (gradientInitializations[0].blendMode != gradientInitializations[1].blendMode) {
             const gradients = [];
             for (const [i, gradientInit] of gradientInitializations.entries()) {
-                gradients.push(createGradient(Object.assign(Object.assign({}, brightness), {
+                gradients.push(createGradient({
+                    ...brightness,
                     colors: [
                         [gradientInitializations[0].offset, i === 0 ? gradientInit.grey : gradientInit.neutral],
                         [gradientInitializations[1].offset, i === 0 ? gradientInit.neutral : gradientInit.grey]
                     ]
-                })));
+                }));
             }
             const firstGradientApplied = composeUnderSpecialRect(image, gradients[0], gradientInitializations[0].blendMode, frameCount);
             const secondGradientApplied = composeUnderSpecialRect(firstGradientApplied.canvas, gradients[1], gradientInitializations[1].blendMode, frameCount, resultCanvas);
             return secondGradientApplied.canvas;
         }
         else {
-            const brightnessGradient = createGradient(Object.assign(Object.assign({}, brightness), {
+            const brightnessGradient = createGradient({
+                ...brightness,
                 colors: [
                     [gradientInitializations[0].offset, gradientInitializations[0].grey],
                     [gradientInitializations[1].offset, gradientInitializations[1].grey]
                 ]
-            }));
+            });
             return composeUnderSpecialRect(image, brightnessGradient, gradientInitializations[0].blendMode, frameCount, resultCanvas).canvas;
         }
     }
@@ -458,15 +462,15 @@ var Renderer;
         }
     }
     Renderer.adjustBrightness = adjustBrightness;
-    function adjustLevels(image,
-        /**
-         * scale factor, 1 - no change, >1 - higher contrast, <1 - lower contrast.
-         */
-        factor,
-        /**
-         * shift, 0 - no change, >0 - brighter, <0 - darker
-         */
-        shift, resultCanvas) {
+    function adjustLevels(image, 
+    /**
+     * scale factor, 1 - no change, >1 - higher contrast, <1 - lower contrast.
+     */
+    factor, 
+    /**
+     * shift, 0 - no change, >0 - brighter, <0 - darker
+     */
+    shift, resultCanvas) {
         if (factor >= 1) {
             /*
              color-dodge ( color, X ) = color / (1 - X) ; 0..(1-X) -> 0..1, (1-X) and brighter become white
@@ -700,20 +704,20 @@ var Renderer;
         // Sort layers by z-index, then array index
         const layers = layerSpecs
             .filter(layer => layer.show !== false
-                && !(typeof layer.alpha === 'number' && layer.alpha <= 0.0))
+            && !(typeof layer.alpha === 'number' && layer.alpha <= 0.0))
             .map((layer, i) => {
-                if (isNaN(layer.z)) {
-                    console.error("Layer " + (layer.name || layer.src) + " has z-index NaN");
-                    layer.z = 0;
-                }
-                return [layer, i];
-            }) // map to pairs [element, index]
+            if (isNaN(layer.z)) {
+                console.error("Layer " + (layer.name || layer.src) + " has z-index NaN");
+                layer.z = 0;
+            }
+            return [layer, i];
+        }) // map to pairs [element, index]
             .sort((a, b) => {
-                if (a[0].z === b[0].z)
-                    return a[1] - b[1];
-                else
-                    return a[0].z - b[0].z;
-            })
+            if (a[0].z === b[0].z)
+                return a[1] - b[1];
+            else
+                return a[0].z - b[0].z;
+        })
             .map(e => e[0]); // unwrap values;
         if (listener && listener.composeLayers)
             listener.composeLayers(layers);
@@ -787,9 +791,9 @@ var Renderer;
                 }
                 layer.image = image;
                 layer.imageSrc = src;
-				if (!(layer.src instanceof HTMLCanvasElement)) {
-					Renderer.ImageCaches[src] = image;
-				}
+                if (!(layer.src instanceof HTMLCanvasElement)) {
+                    Renderer.ImageCaches[src] = image;
+                }
                 maybeRenderResult();
             }, (src, layer, error) => {
                 // Mark this src as erroneous to avoid blinking due to reload attempts
@@ -812,9 +816,9 @@ var Renderer;
                 }
                 layer.mask = image;
                 layer.cachedMaskSrc = src;
-				if (!(layer.src instanceof HTMLCanvasElement)) {
-					Renderer.ImageCaches[src] = image;
-				}
+                if (!(layer.src instanceof HTMLCanvasElement)) {
+                    Renderer.ImageCaches[src] = image;
+                }
                 maybeRenderResult();
             }, (src, layer, error) => {
                 // Mark this src as erroneous to avoid blinking due to reload attempts
@@ -881,11 +885,11 @@ var Renderer;
         maybeRenderResult();
     }
     Renderer.composeLayers = composeLayers;
-	function refresh(model) {
-		Renderer.ImageCaches = {};
-		Renderer.ImageErrors = {};
-		Renderer.invalidateLayerCaches(model.layerList);
-		model.redraw();
+    function refresh(model) {
+        Renderer.ImageCaches = {};
+        Renderer.ImageErrors = {};
+        invalidateLayerCaches(model.layerList);
+        model.redraw();
     }
     Renderer.refresh = refresh;
     function invalidateLayerCaches(layers) {
@@ -998,10 +1002,8 @@ var Renderer;
                     if (listener && listener.keyframe)
                         listener.keyframe(animation.name, animation.keyframeIndex, animation.keyframe);
                 }
-                compose().catch((e) => {
-                    if (e)
-                        console.error(e);
-                });
+                compose().catch((e) => { if (e)
+                    console.error(e); });
             },
             stop() {
                 if (!this.playing)
@@ -1021,10 +1023,8 @@ var Renderer;
             invalidateCaches,
             time: 0,
             redraw() {
-                compose().catch((e) => {
-                    if (e)
-                        console.error(e);
-                });
+                compose().catch((e) => { if (e)
+                    console.error(e); });
             }
         };
         function genAnimationSpec() {
@@ -1052,10 +1052,8 @@ var Renderer;
                         animatingCanvas.time = Math.max(t1, animatingCanvas.time);
                         for (let task of tasks)
                             task();
-                        compose().catch((e) => {
-                            if (e)
-                                console.error(e);
-                        });
+                        compose().catch((e) => { if (e)
+                            console.error(e); });
                     }
                     catch (e) {
                         rendererError(listener, e);
diff --git a/game/03-JavaScript/02-Helpers/colour-utils.js b/game/03-JavaScript/02-Helpers/colour-utils.js
index bf2330d7c7d5410636fe86f48dd4cdb2e01a3182..5cbc9d6c425939b48af9893d2b2c7ec39c05bbe1 100644
--- a/game/03-JavaScript/02-Helpers/colour-utils.js
+++ b/game/03-JavaScript/02-Helpers/colour-utils.js
@@ -90,22 +90,6 @@ const ColourUtils = (() => {
 		return intToHex(invertInt(hexToInt(hex)));
 	}
 
-	function hexToRgba(hex, alpha) {
-		let r = 0;
-		let g = 0;
-		let b = 0;
-		if (hex.length === 7) {
-			r = parseInt(hex.slice(1, 3), 16);
-			g = parseInt(hex.slice(3, 5), 16);
-			b = parseInt(hex.slice(5, 7), 16);
-		} else if (hex.length === 4) {
-			r = parseInt(hex[1] + hex[1], 16);
-			g = parseInt(hex[2] + hex[2], 16);
-			b = parseInt(hex[3] + hex[3], 16);
-		}
-		return `rgba(${r}, ${g}, ${b}, ${alpha})`;
-	}
-
 	function rgbToHex(rgb) {
 		rgb = Object.assign({}, { r: 0, g: 0, b: 0 }, rgb);
 		const convert = num => {
@@ -225,7 +209,6 @@ const ColourUtils = (() => {
 		hexToInt,
 		rgbToHsl,
 		invertInt,
-		hexToRgba,
 		rgbToHex,
 		intToHex,
 		invertHex,
diff --git a/game/04-Variables/canvasmodel-main.js b/game/04-Variables/canvasmodel-main.js
index 4c57c39383dceb96f806293653bf87859bf68e09..9ddd4ec92632e329527d55c86b7c3c821433be71 100644
--- a/game/04-Variables/canvasmodel-main.js
+++ b/game/04-Variables/canvasmodel-main.js
@@ -3103,16 +3103,6 @@ Renderer.CanvasModels["main"] = {
 				return options.belly_mask_src;
 			}
 		}),
-		/*** Did not work
-		"upper_belly_shadow": genlayer_clothing_belly_highlight("upper", {
-			zfn(options) {
-				return options.zupper
-			},
-			masksrcfn(options) {
-				return options.belly_mask_upper_shadow_src;
-			}
-		}),
-		*/
 		"upper_belly_acc": genlayer_clothing_belly_acc("upper", {
 			zfn(options) {
 				return options.zupper