From 4e0a6f5a4005ca6f4df55cb170e7a573a476071c Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 20 Mar 2022 02:48:40 -0400
Subject: [PATCH 01/20] prep for multi pass. add alpha

---
 generators/sculpt.js | 57 ++++++++++++++++++++++++++++++++++++++------
 glsl/glsl-lib.js     |  2 ++
 2 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/generators/sculpt.js b/generators/sculpt.js
index 8eaf0eb..cadddc8 100644
--- a/generators/sculpt.js
+++ b/generators/sculpt.js
@@ -42,8 +42,8 @@ vec3 shade(vec3 p, vec3 normal) {
 	vec3 backgroundColor = vec3(1.0, 1.0, 1.0);
 	vec3 mouseIntersect = vec3(0.0,1.0,0.0);
 	#ifdef USE_PBR
-	Material material = Material(vec3(1.0),0.5,0.7,1.0);
-	Material selectedMaterial = Material(vec3(1.0),0.5,0.7,1.0);
+	Material material = Material(vec3(1.0),1.0,0.5,0.7,1.0);
+	Material selectedMaterial = Material(vec3(1.0),1.0,0.5,0.7,1.0);
 	#else
 	float light = 1.0;
 	float occ = 1.0;
@@ -188,6 +188,30 @@ export function bindStaticData(staticData, spCode) {
 	return `const staticData = JSON.parse(\`${JSON.stringify(staticData)}\`)\n` + spCode;
 }
 
+function errorMsg(err) {
+	console.error(err);
+	throw new Error(err);
+}
+
+export function spCodeToMultiPassGLSL(passes) {
+	if(typeof(passes) !== 'object') {
+		errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object')
+	}
+	let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = passes;
+
+	if (!common) {
+		common = '';
+	}
+	if (!finalImage) {
+		errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+	}
+	return [bufferA, bufferB, bufferC, bufferD, finalImage].map(pass => {
+		if (pass) {
+			return sculptToGLSL(common + '\n' + pass)
+		}
+	})
+}
+
 export function sculptToGLSL(userProvidedSrc) {
 	const PI = Math.PI;
 	const TWO_PI = Math.PI * 2;
@@ -668,8 +692,9 @@ export function sculptToGLSL(userProvidedSrc) {
 	}
 
 	function ensureScalar(funcName, val) {
-		let tp = typeof val;
-		if (typeof val !== 'number' && val.type !== 'float') {
+		if(typeof val === 'undefined') {
+			compileError("'"+funcName+"'" + " was given an undefined parameter");
+		} else if(typeof val !== 'number' && val.type !== 'float') {
 			compileError("'"+funcName+"'" + " accepts only a scalar. Was given: '" + val.type + "'");
 		}
 	}
@@ -995,19 +1020,37 @@ export function sculptToGLSL(userProvidedSrc) {
 	}
 
 	// Color/Lighting
+	function colorRGBA(col, green, blue, alpha) {
+
+	}
+
 
-	function color(col, green, blue) {
+	function color(col, green, blue, alpha = 1.0) {
 		if (green !== undefined) {
+			if(blue === undefined) {
+				compileError("color must be vec3, or vec4, or receive rgb, or rgba");
+			}
 			ensureScalar("color", col);
 			ensureScalar("color", green);
 			ensureScalar("color", blue);
+			ensureScalar("color", alpha);
+
 			appendColorSource(getCurrentMaterial() + ".albedo = vec3(" + 
 				collapseToString(col) + ", " + 
 				collapseToString(green) + ", " +
 				collapseToString(blue) + ");\n");
+			appendColorSource(getCurrentMaterial() + `.alpha = ${collapseToString(alpha)};\n`);
+
 		} else {
-			if (col.type !== 'vec3') compileError("albedo must be vec3");
-			appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+			if(col.type === 'vec3') {
+				appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+				appendColorSource(getCurrentMaterial() + `.alpha = ${collapseToString(alpha)};\n`);
+			} else if(col.type === 'vec4') {
+				appendColorSource(getCurrentMaterial() + `.albedo = ${collapseToString(col)}.rgb;\n`);
+				appendColorSource(getCurrentMaterial() + `.alpha = ${collapseToString(col)}.a;\n`);
+			} else {
+				compileError("color must be vec3, or vec4");
+			}
 		}
 	}
 
diff --git a/glsl/glsl-lib.js b/glsl/glsl-lib.js
index 338c0d6..d4c8e0f 100644
--- a/glsl/glsl-lib.js
+++ b/glsl/glsl-lib.js
@@ -67,6 +67,7 @@ const float intersection_threshold = 0.00001;
 
 struct Material {
     vec3 albedo;
+    float alpha;
     float metallic;
     float roughness;
     float ao;
@@ -75,6 +76,7 @@ struct Material {
 Material blendMaterial(Material a, Material b, float amount) {
     return Material(
         mix(a.albedo, b.albedo, amount), 
+        mix(a.alpha, b.alpha, amount),
         mix(a.metallic, b.metallic, amount), 
         mix(a.roughness, b.roughness, amount), 
         mix(a.ao, b.ao, amount)

From 91606d5a111f7518ed389eeffabb45c1cdf82226 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 20 Mar 2022 02:48:48 -0400
Subject: [PATCH 02/20] rm package lock

---
 package-lock.json | 3052 ---------------------------------------------
 1 file changed, 3052 deletions(-)
 delete mode 100644 package-lock.json

diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index e5661e6..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,3052 +0,0 @@
-{
-  "name": "shader-park-core",
-  "version": "0.1.11",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "@ampproject/remapping": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
-      "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/trace-mapping": "^0.3.0"
-      }
-    },
-    "@babel/code-frame": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
-      "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
-      "dev": true,
-      "requires": {
-        "@babel/highlight": "^7.16.7"
-      }
-    },
-    "@babel/compat-data": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz",
-      "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==",
-      "dev": true
-    },
-    "@babel/core": {
-      "version": "7.17.5",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz",
-      "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==",
-      "dev": true,
-      "requires": {
-        "@ampproject/remapping": "^2.1.0",
-        "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.3",
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helpers": "^7.17.2",
-        "@babel/parser": "^7.17.3",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.3",
-        "@babel/types": "^7.17.0",
-        "convert-source-map": "^1.7.0",
-        "debug": "^4.1.0",
-        "gensync": "^1.0.0-beta.2",
-        "json5": "^2.1.2",
-        "semver": "^6.3.0"
-      }
-    },
-    "@babel/generator": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz",
-      "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.17.0",
-        "jsesc": "^2.5.1",
-        "source-map": "^0.5.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "@babel/helper-annotate-as-pure": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
-      "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-builder-binary-assignment-operator-visitor": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz",
-      "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-explode-assignable-expression": "^7.16.7",
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-compilation-targets": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
-      "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
-      "dev": true,
-      "requires": {
-        "@babel/compat-data": "^7.16.4",
-        "@babel/helper-validator-option": "^7.16.7",
-        "browserslist": "^4.17.5",
-        "semver": "^6.3.0"
-      }
-    },
-    "@babel/helper-create-class-features-plugin": {
-      "version": "7.17.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz",
-      "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-member-expression-to-functions": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7"
-      }
-    },
-    "@babel/helper-create-regexp-features-plugin": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz",
-      "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "regexpu-core": "^5.0.1"
-      }
-    },
-    "@babel/helper-define-polyfill-provider": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz",
-      "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-compilation-targets": "^7.13.0",
-        "@babel/helper-module-imports": "^7.12.13",
-        "@babel/helper-plugin-utils": "^7.13.0",
-        "@babel/traverse": "^7.13.0",
-        "debug": "^4.1.1",
-        "lodash.debounce": "^4.0.8",
-        "resolve": "^1.14.2",
-        "semver": "^6.1.2"
-      }
-    },
-    "@babel/helper-environment-visitor": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
-      "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-explode-assignable-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz",
-      "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-function-name": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
-      "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-get-function-arity": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-get-function-arity": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
-      "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-hoist-variables": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
-      "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-member-expression-to-functions": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz",
-      "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-module-imports": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
-      "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-module-transforms": {
-      "version": "7.17.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz",
-      "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/helper-simple-access": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/helper-validator-identifier": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.3",
-        "@babel/types": "^7.17.0"
-      }
-    },
-    "@babel/helper-optimise-call-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz",
-      "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-plugin-utils": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
-      "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
-      "dev": true
-    },
-    "@babel/helper-remap-async-to-generator": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz",
-      "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-wrap-function": "^7.16.8",
-        "@babel/types": "^7.16.8"
-      }
-    },
-    "@babel/helper-replace-supers": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
-      "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-member-expression-to-functions": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/traverse": "^7.16.7",
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-simple-access": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
-      "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-skip-transparent-expression-wrappers": {
-      "version": "7.16.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz",
-      "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.0"
-      }
-    },
-    "@babel/helper-split-export-declaration": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
-      "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-validator-identifier": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
-      "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
-      "dev": true
-    },
-    "@babel/helper-validator-option": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
-      "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
-      "dev": true
-    },
-    "@babel/helper-wrap-function": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz",
-      "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.16.8",
-        "@babel/types": "^7.16.8"
-      }
-    },
-    "@babel/helpers": {
-      "version": "7.17.2",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz",
-      "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==",
-      "dev": true,
-      "requires": {
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.0",
-        "@babel/types": "^7.17.0"
-      }
-    },
-    "@babel/highlight": {
-      "version": "7.16.10",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
-      "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.16.7",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
-      }
-    },
-    "@babel/parser": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz",
-      "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==",
-      "dev": true
-    },
-    "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz",
-      "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz",
-      "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
-        "@babel/plugin-proposal-optional-chaining": "^7.16.7"
-      }
-    },
-    "@babel/plugin-proposal-async-generator-functions": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz",
-      "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-remap-async-to-generator": "^7.16.8",
-        "@babel/plugin-syntax-async-generators": "^7.8.4"
-      }
-    },
-    "@babel/plugin-proposal-class-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz",
-      "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-proposal-class-static-block": {
-      "version": "7.17.6",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz",
-      "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.17.6",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-class-static-block": "^7.14.5"
-      }
-    },
-    "@babel/plugin-proposal-dynamic-import": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz",
-      "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-dynamic-import": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-export-namespace-from": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz",
-      "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-json-strings": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz",
-      "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-json-strings": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-logical-assignment-operators": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz",
-      "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
-      }
-    },
-    "@babel/plugin-proposal-nullish-coalescing-operator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz",
-      "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-numeric-separator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz",
-      "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-numeric-separator": "^7.10.4"
-      }
-    },
-    "@babel/plugin-proposal-object-rest-spread": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz",
-      "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==",
-      "dev": true,
-      "requires": {
-        "@babel/compat-data": "^7.17.0",
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-        "@babel/plugin-transform-parameters": "^7.16.7"
-      }
-    },
-    "@babel/plugin-proposal-optional-catch-binding": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz",
-      "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-optional-chaining": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz",
-      "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
-        "@babel/plugin-syntax-optional-chaining": "^7.8.3"
-      }
-    },
-    "@babel/plugin-proposal-private-methods": {
-      "version": "7.16.11",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz",
-      "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.16.10",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-proposal-private-property-in-object": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz",
-      "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-create-class-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
-      }
-    },
-    "@babel/plugin-proposal-unicode-property-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz",
-      "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-syntax-async-generators": {
-      "version": "7.8.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
-      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-class-properties": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
-      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.12.13"
-      }
-    },
-    "@babel/plugin-syntax-class-static-block": {
-      "version": "7.14.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
-      "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.14.5"
-      }
-    },
-    "@babel/plugin-syntax-dynamic-import": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
-      "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-export-namespace-from": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
-      "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.3"
-      }
-    },
-    "@babel/plugin-syntax-json-strings": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
-      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-logical-assignment-operators": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
-      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
-      }
-    },
-    "@babel/plugin-syntax-nullish-coalescing-operator": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
-      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-numeric-separator": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
-      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
-      }
-    },
-    "@babel/plugin-syntax-object-rest-spread": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
-      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-optional-catch-binding": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
-      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-optional-chaining": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
-      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.8.0"
-      }
-    },
-    "@babel/plugin-syntax-private-property-in-object": {
-      "version": "7.14.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
-      "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.14.5"
-      }
-    },
-    "@babel/plugin-syntax-top-level-await": {
-      "version": "7.14.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
-      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.14.5"
-      }
-    },
-    "@babel/plugin-transform-arrow-functions": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz",
-      "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-async-to-generator": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz",
-      "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-remap-async-to-generator": "^7.16.8"
-      }
-    },
-    "@babel/plugin-transform-block-scoped-functions": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz",
-      "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-block-scoping": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz",
-      "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-classes": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz",
-      "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
-        "globals": "^11.1.0"
-      }
-    },
-    "@babel/plugin-transform-computed-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz",
-      "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-destructuring": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz",
-      "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-dotall-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz",
-      "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-duplicate-keys": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz",
-      "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-exponentiation-operator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz",
-      "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-for-of": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz",
-      "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-function-name": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz",
-      "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz",
-      "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-member-expression-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz",
-      "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-modules-amd": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz",
-      "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
-      }
-    },
-    "@babel/plugin-transform-modules-commonjs": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
-      "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-simple-access": "^7.16.7",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
-      }
-    },
-    "@babel/plugin-transform-modules-systemjs": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz",
-      "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-hoist-variables": "^7.16.7",
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-identifier": "^7.16.7",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
-      }
-    },
-    "@babel/plugin-transform-modules-umd": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz",
-      "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-named-capturing-groups-regex": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz",
-      "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-new-target": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz",
-      "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-object-super": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz",
-      "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-parameters": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz",
-      "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-property-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz",
-      "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-regenerator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz",
-      "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==",
-      "dev": true,
-      "requires": {
-        "regenerator-transform": "^0.14.2"
-      }
-    },
-    "@babel/plugin-transform-reserved-words": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz",
-      "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-shorthand-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz",
-      "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-spread": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz",
-      "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0"
-      }
-    },
-    "@babel/plugin-transform-sticky-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz",
-      "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-template-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz",
-      "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-typeof-symbol": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz",
-      "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-unicode-escapes": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz",
-      "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/plugin-transform-unicode-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz",
-      "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
-      }
-    },
-    "@babel/preset-env": {
-      "version": "7.16.11",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz",
-      "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==",
-      "dev": true,
-      "requires": {
-        "@babel/compat-data": "^7.16.8",
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-option": "^7.16.7",
-        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7",
-        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7",
-        "@babel/plugin-proposal-async-generator-functions": "^7.16.8",
-        "@babel/plugin-proposal-class-properties": "^7.16.7",
-        "@babel/plugin-proposal-class-static-block": "^7.16.7",
-        "@babel/plugin-proposal-dynamic-import": "^7.16.7",
-        "@babel/plugin-proposal-export-namespace-from": "^7.16.7",
-        "@babel/plugin-proposal-json-strings": "^7.16.7",
-        "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
-        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
-        "@babel/plugin-proposal-numeric-separator": "^7.16.7",
-        "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
-        "@babel/plugin-proposal-optional-catch-binding": "^7.16.7",
-        "@babel/plugin-proposal-optional-chaining": "^7.16.7",
-        "@babel/plugin-proposal-private-methods": "^7.16.11",
-        "@babel/plugin-proposal-private-property-in-object": "^7.16.7",
-        "@babel/plugin-proposal-unicode-property-regex": "^7.16.7",
-        "@babel/plugin-syntax-async-generators": "^7.8.4",
-        "@babel/plugin-syntax-class-properties": "^7.12.13",
-        "@babel/plugin-syntax-class-static-block": "^7.14.5",
-        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-        "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
-        "@babel/plugin-syntax-json-strings": "^7.8.3",
-        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
-        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
-        "@babel/plugin-syntax-numeric-separator": "^7.10.4",
-        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
-        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
-        "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
-        "@babel/plugin-syntax-top-level-await": "^7.14.5",
-        "@babel/plugin-transform-arrow-functions": "^7.16.7",
-        "@babel/plugin-transform-async-to-generator": "^7.16.8",
-        "@babel/plugin-transform-block-scoped-functions": "^7.16.7",
-        "@babel/plugin-transform-block-scoping": "^7.16.7",
-        "@babel/plugin-transform-classes": "^7.16.7",
-        "@babel/plugin-transform-computed-properties": "^7.16.7",
-        "@babel/plugin-transform-destructuring": "^7.16.7",
-        "@babel/plugin-transform-dotall-regex": "^7.16.7",
-        "@babel/plugin-transform-duplicate-keys": "^7.16.7",
-        "@babel/plugin-transform-exponentiation-operator": "^7.16.7",
-        "@babel/plugin-transform-for-of": "^7.16.7",
-        "@babel/plugin-transform-function-name": "^7.16.7",
-        "@babel/plugin-transform-literals": "^7.16.7",
-        "@babel/plugin-transform-member-expression-literals": "^7.16.7",
-        "@babel/plugin-transform-modules-amd": "^7.16.7",
-        "@babel/plugin-transform-modules-commonjs": "^7.16.8",
-        "@babel/plugin-transform-modules-systemjs": "^7.16.7",
-        "@babel/plugin-transform-modules-umd": "^7.16.7",
-        "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8",
-        "@babel/plugin-transform-new-target": "^7.16.7",
-        "@babel/plugin-transform-object-super": "^7.16.7",
-        "@babel/plugin-transform-parameters": "^7.16.7",
-        "@babel/plugin-transform-property-literals": "^7.16.7",
-        "@babel/plugin-transform-regenerator": "^7.16.7",
-        "@babel/plugin-transform-reserved-words": "^7.16.7",
-        "@babel/plugin-transform-shorthand-properties": "^7.16.7",
-        "@babel/plugin-transform-spread": "^7.16.7",
-        "@babel/plugin-transform-sticky-regex": "^7.16.7",
-        "@babel/plugin-transform-template-literals": "^7.16.7",
-        "@babel/plugin-transform-typeof-symbol": "^7.16.7",
-        "@babel/plugin-transform-unicode-escapes": "^7.16.7",
-        "@babel/plugin-transform-unicode-regex": "^7.16.7",
-        "@babel/preset-modules": "^0.1.5",
-        "@babel/types": "^7.16.8",
-        "babel-plugin-polyfill-corejs2": "^0.3.0",
-        "babel-plugin-polyfill-corejs3": "^0.5.0",
-        "babel-plugin-polyfill-regenerator": "^0.3.0",
-        "core-js-compat": "^3.20.2",
-        "semver": "^6.3.0"
-      }
-    },
-    "@babel/preset-modules": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
-      "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-plugin-utils": "^7.0.0",
-        "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
-        "@babel/plugin-transform-dotall-regex": "^7.4.4",
-        "@babel/types": "^7.4.4",
-        "esutils": "^2.0.2"
-      }
-    },
-    "@babel/runtime": {
-      "version": "7.17.2",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
-      "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
-      "dev": true,
-      "requires": {
-        "regenerator-runtime": "^0.13.4"
-      }
-    },
-    "@babel/template": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
-      "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.16.7",
-        "@babel/parser": "^7.16.7",
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/traverse": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
-      "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.3",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-hoist-variables": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/parser": "^7.17.3",
-        "@babel/types": "^7.17.0",
-        "debug": "^4.1.0",
-        "globals": "^11.1.0"
-      }
-    },
-    "@babel/types": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
-      "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.16.7",
-        "to-fast-properties": "^2.0.0"
-      }
-    },
-    "@jridgewell/resolve-uri": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
-      "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==",
-      "dev": true
-    },
-    "@jridgewell/sourcemap-codec": {
-      "version": "1.4.11",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
-      "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
-      "dev": true
-    },
-    "@jridgewell/trace-mapping": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
-      "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
-      "dev": true,
-      "requires": {
-        "@jridgewell/resolve-uri": "^3.0.3",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
-      }
-    },
-    "@rollup/plugin-commonjs": {
-      "version": "18.1.0",
-      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz",
-      "integrity": "sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg==",
-      "dev": true,
-      "requires": {
-        "@rollup/pluginutils": "^3.1.0",
-        "commondir": "^1.0.1",
-        "estree-walker": "^2.0.1",
-        "glob": "^7.1.6",
-        "is-reference": "^1.2.1",
-        "magic-string": "^0.25.7",
-        "resolve": "^1.17.0"
-      }
-    },
-    "@rollup/plugin-json": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz",
-      "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==",
-      "dev": true,
-      "requires": {
-        "@rollup/pluginutils": "^3.0.8"
-      }
-    },
-    "@rollup/plugin-node-resolve": {
-      "version": "11.2.1",
-      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
-      "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==",
-      "dev": true,
-      "requires": {
-        "@rollup/pluginutils": "^3.1.0",
-        "@types/resolve": "1.17.1",
-        "builtin-modules": "^3.1.0",
-        "deepmerge": "^4.2.2",
-        "is-module": "^1.0.0",
-        "resolve": "^1.19.0"
-      }
-    },
-    "@rollup/pluginutils": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
-      "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
-      "dev": true,
-      "requires": {
-        "@types/estree": "0.0.39",
-        "estree-walker": "^1.0.1",
-        "picomatch": "^2.2.2"
-      },
-      "dependencies": {
-        "estree-walker": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
-          "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
-          "dev": true
-        }
-      }
-    },
-    "@types/estree": {
-      "version": "0.0.39",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
-      "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
-      "dev": true
-    },
-    "@types/node": {
-      "version": "17.0.21",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
-      "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
-      "dev": true
-    },
-    "@types/resolve": {
-      "version": "1.17.1",
-      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
-      "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/yauzl": {
-      "version": "2.9.2",
-      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz",
-      "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@ungap/promise-all-settled": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
-      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
-      "dev": true
-    },
-    "agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-      "dev": true,
-      "requires": {
-        "debug": "4"
-      }
-    },
-    "ansi-colors": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
-      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
-      "dev": true
-    },
-    "ansi-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-      "dev": true
-    },
-    "ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
-      "requires": {
-        "color-convert": "^1.9.0"
-      }
-    },
-    "anymatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-      "dev": true,
-      "requires": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      }
-    },
-    "argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
-    },
-    "assertion-error": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
-      "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
-      "dev": true
-    },
-    "babel-plugin-dynamic-import-node": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
-      "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==",
-      "dev": true,
-      "requires": {
-        "object.assign": "^4.1.0"
-      }
-    },
-    "babel-plugin-polyfill-corejs2": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz",
-      "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==",
-      "dev": true,
-      "requires": {
-        "@babel/compat-data": "^7.13.11",
-        "@babel/helper-define-polyfill-provider": "^0.3.1",
-        "semver": "^6.1.1"
-      }
-    },
-    "babel-plugin-polyfill-corejs3": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz",
-      "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-define-polyfill-provider": "^0.3.1",
-        "core-js-compat": "^3.21.0"
-      }
-    },
-    "babel-plugin-polyfill-regenerator": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz",
-      "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-define-polyfill-provider": "^0.3.1"
-      }
-    },
-    "balanced-match": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true
-    },
-    "base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-      "dev": true
-    },
-    "binary-extensions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-      "dev": true
-    },
-    "bl": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
-      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
-      "dev": true,
-      "requires": {
-        "buffer": "^5.5.0",
-        "inherits": "^2.0.4",
-        "readable-stream": "^3.4.0"
-      }
-    },
-    "brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
-      "requires": {
-        "fill-range": "^7.0.1"
-      }
-    },
-    "browser-stdout": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
-      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
-      "dev": true
-    },
-    "browserslist": {
-      "version": "4.19.3",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz",
-      "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==",
-      "dev": true,
-      "requires": {
-        "caniuse-lite": "^1.0.30001312",
-        "electron-to-chromium": "^1.4.71",
-        "escalade": "^3.1.1",
-        "node-releases": "^2.0.2",
-        "picocolors": "^1.0.0"
-      }
-    },
-    "buffer": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
-      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
-      "dev": true,
-      "requires": {
-        "base64-js": "^1.3.1",
-        "ieee754": "^1.1.13"
-      }
-    },
-    "buffer-crc32": {
-      "version": "0.2.13",
-      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
-      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
-      "dev": true
-    },
-    "builtin-modules": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
-      "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
-      "dev": true
-    },
-    "call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
-      }
-    },
-    "camelcase": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
-      "dev": true
-    },
-    "caniuse-lite": {
-      "version": "1.0.30001313",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001313.tgz",
-      "integrity": "sha512-rI1UN0koZUiKINjysQDuRi2VeSCce3bYJNmDcj3PIKREiAmjakugBul1QSkg/fPrlULYl6oWfGg3PbgOSY9X4Q==",
-      "dev": true
-    },
-    "chai": {
-      "version": "4.3.6",
-      "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
-      "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
-      "dev": true,
-      "requires": {
-        "assertion-error": "^1.1.0",
-        "check-error": "^1.0.2",
-        "deep-eql": "^3.0.1",
-        "get-func-name": "^2.0.0",
-        "loupe": "^2.3.1",
-        "pathval": "^1.1.1",
-        "type-detect": "^4.0.5"
-      }
-    },
-    "chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
-      }
-    },
-    "check-error": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
-      "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
-      "dev": true
-    },
-    "chokidar": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
-      "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
-      "dev": true,
-      "requires": {
-        "anymatch": "~3.1.1",
-        "braces": "~3.0.2",
-        "fsevents": "~2.3.1",
-        "glob-parent": "~5.1.0",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.5.0"
-      }
-    },
-    "chownr": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
-      "dev": true
-    },
-    "cliui": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
-      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
-      "dev": true,
-      "requires": {
-        "string-width": "^4.2.0",
-        "strip-ansi": "^6.0.0",
-        "wrap-ansi": "^7.0.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.1"
-          }
-        }
-      }
-    },
-    "color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
-      "requires": {
-        "color-name": "1.1.3"
-      }
-    },
-    "color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
-    },
-    "commondir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-      "dev": true
-    },
-    "concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
-    },
-    "convert-source-map": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
-      "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.1"
-      }
-    },
-    "core-js-compat": {
-      "version": "3.21.1",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz",
-      "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.19.1",
-        "semver": "7.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
-          "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
-          "dev": true
-        }
-      }
-    },
-    "debug": {
-      "version": "4.3.3",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-      "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
-      "dev": true,
-      "requires": {
-        "ms": "2.1.2"
-      }
-    },
-    "decamelize": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
-      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
-      "dev": true
-    },
-    "deep-eql": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
-      "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
-      "dev": true,
-      "requires": {
-        "type-detect": "^4.0.0"
-      }
-    },
-    "deep-is": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
-    },
-    "deepmerge": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
-      "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
-      "dev": true
-    },
-    "define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
-      "dev": true,
-      "requires": {
-        "object-keys": "^1.0.12"
-      }
-    },
-    "devtools-protocol": {
-      "version": "0.0.854822",
-      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.854822.tgz",
-      "integrity": "sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==",
-      "dev": true
-    },
-    "diff": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
-      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
-      "dev": true
-    },
-    "electron-to-chromium": {
-      "version": "1.4.76",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.76.tgz",
-      "integrity": "sha512-3Vftv7cenJtQb+k00McEBZ2vVmZ/x+HEF7pcZONZIkOsESqAqVuACmBxMv0JhzX7u0YltU0vSqRqgBSTAhFUjA==",
-      "dev": true
-    },
-    "emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-      "dev": true
-    },
-    "end-of-stream": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
-      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
-      "dev": true,
-      "requires": {
-        "once": "^1.4.0"
-      }
-    },
-    "escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
-    },
-    "escodegen": {
-      "version": "1.14.3",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
-      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
-      "requires": {
-        "esprima": "^4.0.1",
-        "estraverse": "^4.2.0",
-        "esutils": "^2.0.2",
-        "optionator": "^0.8.1",
-        "source-map": "~0.6.1"
-      }
-    },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
-    },
-    "estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
-    },
-    "estree-walker": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
-      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
-    },
-    "extract-zip": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
-      "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
-      "dev": true,
-      "requires": {
-        "@types/yauzl": "^2.9.1",
-        "debug": "^4.1.1",
-        "get-stream": "^5.1.0",
-        "yauzl": "^2.10.0"
-      }
-    },
-    "fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
-    },
-    "fd-slicer": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
-      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
-      "dev": true,
-      "requires": {
-        "pend": "~1.2.0"
-      }
-    },
-    "fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-      "dev": true,
-      "requires": {
-        "to-regex-range": "^5.0.1"
-      }
-    },
-    "find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-      "dev": true,
-      "requires": {
-        "locate-path": "^6.0.0",
-        "path-exists": "^4.0.0"
-      }
-    },
-    "flat": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
-      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
-      "dev": true
-    },
-    "fs-constants": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
-      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
-      "dev": true
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
-    },
-    "fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "dev": true,
-      "optional": true
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "gensync": {
-      "version": "1.0.0-beta.2",
-      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
-      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
-      "dev": true
-    },
-    "get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "dev": true
-    },
-    "get-func-name": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
-      "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
-      "dev": true
-    },
-    "get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "get-stream": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
-      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
-      "dev": true,
-      "requires": {
-        "pump": "^3.0.0"
-      }
-    },
-    "glob": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
-      "dev": true,
-      "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      }
-    },
-    "glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "requires": {
-        "is-glob": "^4.0.1"
-      }
-    },
-    "globals": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "dev": true
-    },
-    "growl": {
-      "version": "1.10.5",
-      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
-      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
-      "dev": true
-    },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
-    "has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
-    },
-    "has-symbols": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-      "dev": true
-    },
-    "he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-      "dev": true
-    },
-    "https-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
-      "dev": true,
-      "requires": {
-        "agent-base": "6",
-        "debug": "4"
-      }
-    },
-    "ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "dev": true
-    },
-    "inflight": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "dev": true,
-      "requires": {
-        "once": "^1.3.0",
-        "wrappy": "1"
-      }
-    },
-    "inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "dev": true
-    },
-    "is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^2.0.0"
-      }
-    },
-    "is-core-module": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
-      "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.3"
-      }
-    },
-    "is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
-    },
-    "is-fullwidth-code-point": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-      "dev": true
-    },
-    "is-glob": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^2.1.1"
-      }
-    },
-    "is-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
-      "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
-      "dev": true
-    },
-    "is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true
-    },
-    "is-plain-obj": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
-      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
-      "dev": true
-    },
-    "is-reference": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
-      "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
-      "dev": true,
-      "requires": {
-        "@types/estree": "*"
-      }
-    },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-      "dev": true
-    },
-    "js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
-    "js-yaml": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
-      "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
-      "dev": true,
-      "requires": {
-        "argparse": "^2.0.1"
-      }
-    },
-    "jsesc": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "dev": true
-    },
-    "json5": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
-      "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.5"
-      }
-    },
-    "levn": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
-      "requires": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
-      }
-    },
-    "locate-path": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-      "dev": true,
-      "requires": {
-        "p-locate": "^5.0.0"
-      }
-    },
-    "lodash.debounce": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
-      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
-      "dev": true
-    },
-    "log-symbols": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
-      "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
-      "dev": true,
-      "requires": {
-        "chalk": "^4.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "4.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "loupe": {
-      "version": "2.3.4",
-      "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
-      "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
-      "dev": true,
-      "requires": {
-        "get-func-name": "^2.0.0"
-      }
-    },
-    "magic-string": {
-      "version": "0.25.9",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
-      "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
-      "dev": true,
-      "requires": {
-        "sourcemap-codec": "^1.4.8"
-      }
-    },
-    "minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
-      "requires": {
-        "brace-expansion": "^1.1.7"
-      }
-    },
-    "minimist": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-      "dev": true
-    },
-    "mkdirp-classic": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
-      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
-      "dev": true
-    },
-    "mocha": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz",
-      "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==",
-      "dev": true,
-      "requires": {
-        "@ungap/promise-all-settled": "1.1.2",
-        "ansi-colors": "4.1.1",
-        "browser-stdout": "1.3.1",
-        "chokidar": "3.5.1",
-        "debug": "4.3.1",
-        "diff": "5.0.0",
-        "escape-string-regexp": "4.0.0",
-        "find-up": "5.0.0",
-        "glob": "7.1.6",
-        "growl": "1.10.5",
-        "he": "1.2.0",
-        "js-yaml": "4.0.0",
-        "log-symbols": "4.0.0",
-        "minimatch": "3.0.4",
-        "ms": "2.1.3",
-        "nanoid": "3.1.20",
-        "serialize-javascript": "5.0.1",
-        "strip-json-comments": "3.1.1",
-        "supports-color": "8.1.1",
-        "which": "2.0.2",
-        "wide-align": "1.1.3",
-        "workerpool": "6.1.0",
-        "yargs": "16.2.0",
-        "yargs-parser": "20.2.4",
-        "yargs-unparser": "2.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          },
-          "dependencies": {
-            "ms": {
-              "version": "2.1.2",
-              "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-              "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-              "dev": true
-            }
-          }
-        },
-        "escape-string-regexp": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-          "dev": true
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "minimatch": {
-          "version": "3.0.4",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
-        "ms": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "8.1.1",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "ms": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-      "dev": true
-    },
-    "nanoid": {
-      "version": "3.1.20",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
-      "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
-      "dev": true
-    },
-    "node-fetch": {
-      "version": "2.6.7",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
-      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
-      "dev": true,
-      "requires": {
-        "whatwg-url": "^5.0.0"
-      }
-    },
-    "node-releases": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
-      "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==",
-      "dev": true
-    },
-    "normalize-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true
-    },
-    "object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true
-    },
-    "object.assign": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3",
-        "has-symbols": "^1.0.1",
-        "object-keys": "^1.1.1"
-      }
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "optionator": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
-      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
-      "requires": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.6",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "word-wrap": "~1.2.3"
-      }
-    },
-    "p-limit": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-      "dev": true,
-      "requires": {
-        "yocto-queue": "^0.1.0"
-      }
-    },
-    "p-locate": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-      "dev": true,
-      "requires": {
-        "p-limit": "^3.0.2"
-      }
-    },
-    "p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true
-    },
-    "path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true
-    },
-    "path-is-absolute": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-      "dev": true
-    },
-    "path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-      "dev": true
-    },
-    "pathval": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
-      "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
-      "dev": true
-    },
-    "pend": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
-      "dev": true
-    },
-    "picocolors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-      "dev": true
-    },
-    "picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true
-    },
-    "pkg-dir": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-      "dev": true,
-      "requires": {
-        "find-up": "^4.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        }
-      }
-    },
-    "png-js": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
-      "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==",
-      "dev": true
-    },
-    "prelude-ls": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
-    },
-    "progress": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
-      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
-      "dev": true
-    },
-    "proxy-from-env": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-      "dev": true
-    },
-    "pump": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "once": "^1.3.1"
-      }
-    },
-    "puppeteer": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-8.0.0.tgz",
-      "integrity": "sha512-D0RzSWlepeWkxPPdK3xhTcefj8rjah1791GE82Pdjsri49sy11ci/JQsAO8K2NRukqvwEtcI+ImP5F4ZiMvtIQ==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.0",
-        "devtools-protocol": "0.0.854822",
-        "extract-zip": "^2.0.0",
-        "https-proxy-agent": "^5.0.0",
-        "node-fetch": "^2.6.1",
-        "pkg-dir": "^4.2.0",
-        "progress": "^2.0.1",
-        "proxy-from-env": "^1.1.0",
-        "rimraf": "^3.0.2",
-        "tar-fs": "^2.0.0",
-        "unbzip2-stream": "^1.3.3",
-        "ws": "^7.2.3"
-      }
-    },
-    "randombytes": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.0"
-      }
-    },
-    "readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      }
-    },
-    "readdirp": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
-      "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
-      "dev": true,
-      "requires": {
-        "picomatch": "^2.2.1"
-      }
-    },
-    "regenerate": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
-      "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
-      "dev": true
-    },
-    "regenerate-unicode-properties": {
-      "version": "10.0.1",
-      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz",
-      "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==",
-      "dev": true,
-      "requires": {
-        "regenerate": "^1.4.2"
-      }
-    },
-    "regenerator-runtime": {
-      "version": "0.13.9",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-      "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
-      "dev": true
-    },
-    "regenerator-transform": {
-      "version": "0.14.5",
-      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz",
-      "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==",
-      "dev": true,
-      "requires": {
-        "@babel/runtime": "^7.8.4"
-      }
-    },
-    "regexpu-core": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz",
-      "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==",
-      "dev": true,
-      "requires": {
-        "regenerate": "^1.4.2",
-        "regenerate-unicode-properties": "^10.0.1",
-        "regjsgen": "^0.6.0",
-        "regjsparser": "^0.8.2",
-        "unicode-match-property-ecmascript": "^2.0.0",
-        "unicode-match-property-value-ecmascript": "^2.0.0"
-      }
-    },
-    "regjsgen": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz",
-      "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==",
-      "dev": true
-    },
-    "regjsparser": {
-      "version": "0.8.4",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz",
-      "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==",
-      "dev": true,
-      "requires": {
-        "jsesc": "~0.5.0"
-      },
-      "dependencies": {
-        "jsesc": {
-          "version": "0.5.0",
-          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
-          "dev": true
-        }
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.22.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-      "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
-      "dev": true,
-      "requires": {
-        "is-core-module": "^2.8.1",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      }
-    },
-    "rimraf": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.1.3"
-      }
-    },
-    "rollup": {
-      "version": "2.69.1",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.69.1.tgz",
-      "integrity": "sha512-xaQKTomUVZBopk38EIshM/kOoPFkKWisgBV7Emy80coP9MOSLUDrba1jKZhqH0iS5DoGcRbbcuyl/BzblV8w5w==",
-      "dev": true,
-      "requires": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "rollup-plugin-babel": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz",
-      "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-imports": "^7.0.0",
-        "rollup-pluginutils": "^2.8.1"
-      }
-    },
-    "rollup-pluginutils": {
-      "version": "2.8.2",
-      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
-      "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
-      "dev": true,
-      "requires": {
-        "estree-walker": "^0.6.1"
-      },
-      "dependencies": {
-        "estree-walker": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
-          "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
-          "dev": true
-        }
-      }
-    },
-    "safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
-    },
-    "semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-      "dev": true
-    },
-    "serialize-javascript": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
-      "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
-      "dev": true,
-      "requires": {
-        "randombytes": "^2.1.0"
-      }
-    },
-    "source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "optional": true
-    },
-    "sourcemap-codec": {
-      "version": "1.4.8",
-      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
-      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
-      "dev": true
-    },
-    "string-width": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-      "dev": true,
-      "requires": {
-        "is-fullwidth-code-point": "^2.0.0",
-        "strip-ansi": "^4.0.0"
-      }
-    },
-    "string_decoder": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.2.0"
-      },
-      "dependencies": {
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        }
-      }
-    },
-    "strip-ansi": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^3.0.0"
-      }
-    },
-    "strip-json-comments": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-      "dev": true
-    },
-    "supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
-      "requires": {
-        "has-flag": "^3.0.0"
-      }
-    },
-    "supports-preserve-symlinks-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-      "dev": true
-    },
-    "tar-fs": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
-      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
-      "dev": true,
-      "requires": {
-        "chownr": "^1.1.1",
-        "mkdirp-classic": "^0.5.2",
-        "pump": "^3.0.0",
-        "tar-stream": "^2.1.4"
-      }
-    },
-    "tar-stream": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
-      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
-      "dev": true,
-      "requires": {
-        "bl": "^4.0.3",
-        "end-of-stream": "^1.4.1",
-        "fs-constants": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^3.1.1"
-      }
-    },
-    "three": {
-      "version": "0.138.3",
-      "resolved": "https://registry.npmjs.org/three/-/three-0.138.3.tgz",
-      "integrity": "sha512-4t1cKC8gimNyJChJbaklg8W/qj3PpsLJUIFm5LIuAy/hVxxNm1ru2FGTSfbTSsuHmC/7ipsyuGKqrSAKLNtkzg=="
-    },
-    "through": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
-      "dev": true
-    },
-    "to-fast-properties": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
-    },
-    "to-regex-range": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
-      "requires": {
-        "is-number": "^7.0.0"
-      }
-    },
-    "tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
-      "dev": true
-    },
-    "type-check": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
-      "requires": {
-        "prelude-ls": "~1.1.2"
-      }
-    },
-    "type-detect": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
-      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
-      "dev": true
-    },
-    "unbzip2-stream": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
-      "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
-      "dev": true,
-      "requires": {
-        "buffer": "^5.2.1",
-        "through": "^2.3.8"
-      }
-    },
-    "unicode-canonical-property-names-ecmascript": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
-      "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
-      "dev": true
-    },
-    "unicode-match-property-ecmascript": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
-      "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
-      "dev": true,
-      "requires": {
-        "unicode-canonical-property-names-ecmascript": "^2.0.0",
-        "unicode-property-aliases-ecmascript": "^2.0.0"
-      }
-    },
-    "unicode-match-property-value-ecmascript": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz",
-      "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==",
-      "dev": true
-    },
-    "unicode-property-aliases-ecmascript": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz",
-      "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==",
-      "dev": true
-    },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
-      "dev": true
-    },
-    "webidl-conversions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
-      "dev": true
-    },
-    "whatwg-url": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
-      "dev": true,
-      "requires": {
-        "tr46": "~0.0.3",
-        "webidl-conversions": "^3.0.0"
-      }
-    },
-    "which": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.2 || 2"
-      }
-    },
-    "word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
-    },
-    "workerpool": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz",
-      "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==",
-      "dev": true
-    },
-    "wrap-ansi": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^4.0.0",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.1"
-          }
-        }
-      }
-    },
-    "wrappy": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
-    },
-    "ws": {
-      "version": "7.5.7",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
-      "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
-      "dev": true
-    },
-    "y18n": {
-      "version": "5.0.8",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-      "dev": true
-    },
-    "yargs": {
-      "version": "16.2.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
-      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
-      "dev": true,
-      "requires": {
-        "cliui": "^7.0.2",
-        "escalade": "^3.1.1",
-        "get-caller-file": "^2.0.5",
-        "require-directory": "^2.1.1",
-        "string-width": "^4.2.0",
-        "y18n": "^5.0.5",
-        "yargs-parser": "^20.2.2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-          "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-          "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.1"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.1"
-          }
-        }
-      }
-    },
-    "yargs-parser": {
-      "version": "20.2.4",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
-      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
-      "dev": true
-    },
-    "yargs-unparser": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
-      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^6.0.0",
-        "decamelize": "^4.0.0",
-        "flat": "^5.0.2",
-        "is-plain-obj": "^2.1.0"
-      }
-    },
-    "yauzl": {
-      "version": "2.10.0",
-      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
-      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
-      "dev": true,
-      "requires": {
-        "buffer-crc32": "~0.2.3",
-        "fd-slicer": "~1.1.0"
-      }
-    },
-    "yocto-queue": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-      "dev": true
-    }
-  }
-}

From b31f4b7b9de6fa5a66122eea1f6db3a34b66760c Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 20 Mar 2022 02:48:56 -0400
Subject: [PATCH 03/20] add postfx

---
 targets/multiPostFX.js | 174 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)
 create mode 100644 targets/multiPostFX.js

diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
new file mode 100644
index 0000000..e38b9c2
--- /dev/null
+++ b/targets/multiPostFX.js
@@ -0,0 +1,174 @@
+
+
+/**
+ * FROM https://github.com/martinlaxenaire/three-multipass-post-processing
+ *
+ * Add post processing to a scene
+ * Taken from https://medium.com/@luruke/simple-postprocessing-in-three-js-91936ecadfb7
+ * and improved to add the ability to handle multiple passes
+ *
+ * To use it, simply declare:
+ * `const post = new MultiPostFX({renderer: rendering});`
+ *
+ * Then on update, instead of:
+ * `rendering.render(scene, camera);`
+ * replace with:
+ * `post.render(scene, camera);`
+ *
+ * To resize it, just use:
+ * `post.resize();`
+ *
+ * To update a specific uniform just do:
+ * `post.passes.myPassName.material.uniforms.myUniform.value = value;`
+ *
+ * See init params below to see how to add passes with specific shaders, uniforms, etc.
+ *
+ */
+
+import {
+    WebGLRenderTarget,
+    OrthographicCamera,
+    RGBAFormat,
+    BufferGeometry,
+    BufferAttribute,
+    Mesh,
+    Scene,
+    RawShaderMaterial,
+    Vector2,
+} from 'three';
+
+/**
+ *
+ * @params: (object)
+ * renderer: (THREE.WebGLRenderer) renderer used to render your original scene
+ * passes: (object) object describing the passes applied consecutively
+ *  - passName (object):
+ *      - format: (THREE texture constants format, optionnal) format to use for your pass texure (default to THREE.RGBAFormat)
+ *      - uniforms: (object, optionnal) additional uniforms to use (see THREE Uniform)
+ *      - vertexShader: (string, optionnal) vertexShader to use. Use one if you want to specify varyings to your fragment shader. Uses the default const vertexShader if none specified
+ *      - fragmentShader: (string optionnal) fragmentShader to use. Uses the default const fragmentShader (that just display your scene) if none specified.
+ *
+ */
+export default class MultiPostFX {
+    constructor(params) {
+        this.renderer = params.renderer;
+
+        if(!this.renderer) return;
+
+        // three.js for .render() wants a camera, even if we're not using it :(
+        this.dummyCamera = new OrthographicCamera();
+        this.geometry = new BufferGeometry();
+
+        // Triangle expressed in clip space coordinates
+        const vertices = new Float32Array([
+            -1.0, -1.0,
+            3.0, -1.0,
+            -1.0, 3.0
+        ]);
+
+        this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+
+        this.resolution = new Vector2();
+        this.renderer.getDrawingBufferSize(this.resolution);
+
+        // default shaders
+        this.defaultVertexShader = `
+            precision highp float;
+            attribute vec2 position;
+            void main() {
+                gl_Position = vec4(position, 1.0, 1.0);
+            }
+        `;
+
+        this.defaultFragmentShader = `
+            precision highp float;
+            uniform sampler2D uScene;
+            uniform vec2 uResolution;
+            void main() {
+                vec2 uv = gl_FragCoord.xy / uResolution.xy;
+                gl_FragColor = texture2D(uScene, uv);
+            }
+        `;
+
+        // add our passes
+        this.nbPasses = 0;
+        this.passes = {};
+        params.passes = params.passes || {};
+
+        for(let passName in params.passes) {
+            this.addPass(passName, params.passes[passName]);
+        }
+    }
+
+    addPass(passName, passParams) {
+        // create a pass object that will contain a scene, a render target
+        // a material and its uniforms and finally a mesh
+        let pass = {
+            scene: new Scene(),
+            target: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+                format: passParams.format || RGBAFormat, // allow transparency
+                stencilBuffer: false,
+                depthBuffer: true,
+            }),
+        };
+
+        let uniforms = {
+            uScene: { value: pass.target.texture },
+            uResolution: { value: this.resolution },
+        };
+
+        // merge default uniforms with params
+        if(passParams.uniforms) {
+            uniforms = Object.assign(uniforms, passParams.uniforms);
+        }
+
+        pass.material = new RawShaderMaterial({
+            fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
+            vertexShader: passParams.vertexShader || this.defaultVertexShader,
+            uniforms: uniforms
+        });
+
+        pass.mesh = new Mesh(this.geometry, pass.material);
+        pass.mesh.frustumCulled = false;
+
+        pass.scene.add(pass.mesh);
+
+        this.passes[passName] = pass;
+        this.nbPasses++;
+    }
+
+    resize() {
+        this.renderer.getDrawingBufferSize(this.resolution);
+
+        // resize all passes
+        const passes = Object.keys(this.passes);
+        for(let i = 0; i < this.nbPasses; i++) {
+            this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+            this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+        }
+    }
+
+    render(scene, camera) {
+        if(this.nbPasses === 0) {
+            // no passes defined, just render the scene
+            this.renderer.render(scene, camera);
+        }
+        else {
+            const passes = Object.keys(this.passes);
+
+            // render the original scene in our first pass render target
+            this.renderer.setRenderTarget(this.passes[passes[0]].target);
+            this.renderer.render(scene, camera);
+
+            // render next passes
+            for(let i = 1; i < this.nbPasses; i++) {
+                this.renderer.setRenderTarget(this.passes[passes[i]].target);
+                this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
+            }
+
+            // render the last pass back to the canvas
+            this.renderer.setRenderTarget(null);
+            this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+        }
+    }
+}
\ No newline at end of file

From c60cbf259515d5f526133279a2ebbac747151d67 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 20 Mar 2022 02:49:16 -0400
Subject: [PATCH 04/20] start new multi pass func

---
 dist/shader-park-core.cjs.js | 723 +++++++++++++---------------------
 dist/shader-park-core.esm.js | 723 +++++++++++++---------------------
 dist/shader-park-core.umd.js | 729 +++++++++++++----------------------
 targets/threeJS.js           |  57 ++-
 4 files changed, 838 insertions(+), 1394 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 4f7bba1..40d9af9 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -2,406 +2,86 @@
 
 Object.defineProperty(exports, '__esModule', { value: true });
 
-function createMetadataMethodsForProperty(metadataMap, kind, property) {
-  return {
-    getMetadata: function (key) {
-      if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-      var metadataForKey = metadataMap[key];
-      if (void 0 !== metadataForKey) if (1 === kind) {
-        var pub = metadataForKey.public;
-        if (void 0 !== pub) return pub[property];
-      } else if (2 === kind) {
-        var priv = metadataForKey.private;
-        if (void 0 !== priv) return priv.get(property);
-      } else if (Object.hasOwnProperty.call(metadataForKey, "constructor")) return metadataForKey.constructor;
-    },
-    setMetadata: function (key, value) {
-      if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-      var metadataForKey = metadataMap[key];
-
-      if (void 0 === metadataForKey && (metadataForKey = metadataMap[key] = {}), 1 === kind) {
-        var pub = metadataForKey.public;
-        void 0 === pub && (pub = metadataForKey.public = {}), pub[property] = value;
-      } else if (2 === kind) {
-        var priv = metadataForKey.priv;
-        void 0 === priv && (priv = metadataForKey.private = new Map()), priv.set(property, value);
-      } else metadataForKey.constructor = value;
-    }
-  };
-}
-
-function convertMetadataMapToFinal(obj, metadataMap) {
-  var parentMetadataMap = obj[Symbol.metadata || Symbol.for("Symbol.metadata")],
-      metadataKeys = Object.getOwnPropertySymbols(metadataMap);
-
-  if (0 !== metadataKeys.length) {
-    for (var i = 0; i < metadataKeys.length; i++) {
-      var key = metadataKeys[i],
-          metaForKey = metadataMap[key],
-          parentMetaForKey = parentMetadataMap ? parentMetadataMap[key] : null,
-          pub = metaForKey.public,
-          parentPub = parentMetaForKey ? parentMetaForKey.public : null;
-      pub && parentPub && Object.setPrototypeOf(pub, parentPub);
-      var priv = metaForKey.private;
-
-      if (priv) {
-        var privArr = Array.from(priv.values()),
-            parentPriv = parentMetaForKey ? parentMetaForKey.private : null;
-        parentPriv && (privArr = privArr.concat(parentPriv)), metaForKey.private = privArr;
-      }
-
-      parentMetaForKey && Object.setPrototypeOf(metaForKey, parentMetaForKey);
-    }
+function _typeof(obj) {
+  "@babel/helpers - typeof";
 
-    parentMetadataMap && Object.setPrototypeOf(metadataMap, parentMetadataMap), obj[Symbol.metadata || Symbol.for("Symbol.metadata")] = metadataMap;
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function (obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function (obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
   }
-}
 
-function createAddInitializerMethod(initializers) {
-  return function (initializer) {
-    assertValidInitializer(initializer), initializers.push(initializer);
-  };
+  return _typeof(obj);
 }
 
-function memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate) {
-  var kindStr;
-
-  switch (kind) {
-    case 1:
-      kindStr = "accessor";
-      break;
-
-    case 2:
-      kindStr = "method";
-      break;
-
-    case 3:
-      kindStr = "getter";
-      break;
-
-    case 4:
-      kindStr = "setter";
-      break;
+var REACT_ELEMENT_TYPE;
 
-    default:
-      kindStr = "field";
+function _jsx(type, props, key, children) {
+  if (!REACT_ELEMENT_TYPE) {
+    REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol["for"] && Symbol["for"]("react.element") || 0xeac7;
   }
 
-  var metadataKind,
-      metadataName,
-      ctx = {
-    kind: kindStr,
-    name: isPrivate ? "#" + name : name,
-    isStatic: isStatic,
-    isPrivate: isPrivate
-  };
-
-  if (0 !== kind && (ctx.addInitializer = createAddInitializerMethod(initializers)), isPrivate) {
-    metadataKind = 2, metadataName = Symbol(name);
-    var access = {};
-    0 === kind ? (access.get = desc.get, access.set = desc.set) : 2 === kind ? access.get = function () {
-      return desc.value;
-    } : (1 !== kind && 3 !== kind || (access.get = function () {
-      return desc.get.call(this);
-    }), 1 !== kind && 4 !== kind || (access.set = function (v) {
-      desc.set.call(this, v);
-    })), ctx.access = access;
-  } else metadataKind = 1, metadataName = name;
-
-  return Object.assign(ctx, createMetadataMethodsForProperty(metadataMap, metadataKind, metadataName));
-}
-
-function assertValidInitializer(initializer) {
-  if ("function" != typeof initializer) throw new Error("initializers must be functions");
-}
-
-function assertValidReturnValue(kind, value) {
-  var type = typeof value;
-
-  if (1 === kind) {
-    if ("object" !== type || null === value) throw new Error("accessor decorators must return an object with get, set, or initializer properties or void 0");
-  } else if ("function" !== type) throw 0 === kind ? new Error("field decorators must return a initializer function or void 0") : new Error("method decorators must return a function or void 0");
-}
-
-function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers) {
-  var desc,
-      initializer,
-      value,
-      decs = decInfo[0];
-  isPrivate ? desc = 0 === kind || 1 === kind ? {
-    get: decInfo[3],
-    set: decInfo[4]
-  } : 3 === kind ? {
-    get: decInfo[3]
-  } : 4 === kind ? {
-    set: decInfo[3]
-  } : {
-    value: decInfo[3]
-  } : 0 !== kind && (desc = Object.getOwnPropertyDescriptor(base, name)), 1 === kind ? value = {
-    get: desc.get,
-    set: desc.set
-  } : 2 === kind ? value = desc.value : 3 === kind ? value = desc.get : 4 === kind && (value = desc.set);
-  var newValue,
-      get,
-      set,
-      ctx = memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate);
-  if ("function" == typeof decs) void 0 !== (newValue = decs(value, ctx)) && (assertValidReturnValue(kind, newValue), 0 === kind ? initializer = newValue : 1 === kind ? (initializer = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-    get: get,
-    set: set
-  }) : value = newValue);else for (var i = decs.length - 1; i >= 0; i--) {
-    var newInit;
-    if (void 0 !== (newValue = (0, decs[i])(value, ctx))) assertValidReturnValue(kind, newValue), 0 === kind ? newInit = newValue : 1 === kind ? (newInit = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-      get: get,
-      set: set
-    }) : value = newValue, void 0 !== newInit && (void 0 === initializer ? initializer = newInit : "function" == typeof initializer ? initializer = [initializer, newInit] : initializer.push(newInit));
-  }
-
-  if (0 === kind || 1 === kind) {
-    if (void 0 === initializer) initializer = function (instance, init) {
-      return init;
-    };else if ("function" != typeof initializer) {
-      var ownInitializers = initializer;
-
-      initializer = function (instance, init) {
-        for (var value = init, i = 0; i < ownInitializers.length; i++) value = ownInitializers[i].call(instance, value);
+  var defaultProps = type && type.defaultProps;
+  var childrenLength = arguments.length - 3;
 
-        return value;
-      };
-    } else {
-      var originalInitializer = initializer;
-
-      initializer = function (instance, init) {
-        return originalInitializer.call(instance, init);
-      };
-    }
-    ret.push(initializer);
+  if (!props && childrenLength !== 0) {
+    props = {
+      children: void 0
+    };
   }
 
-  0 !== kind && (1 === kind ? (desc.get = value.get, desc.set = value.set) : 2 === kind ? desc.value = value : 3 === kind ? desc.get = value : 4 === kind && (desc.set = value), isPrivate ? 1 === kind ? (ret.push(function (instance, args) {
-    return value.get.call(instance, args);
-  }), ret.push(function (instance, args) {
-    return value.set.call(instance, args);
-  })) : 2 === kind ? ret.push(value) : ret.push(function (instance, args) {
-    return value.call(instance, args);
-  }) : Object.defineProperty(base, name, desc));
-}
-
-function applyMemberDecs(ret, Class, protoMetadataMap, staticMetadataMap, decInfos) {
-  for (var protoInitializers = [], staticInitializers = [], existingProtoNonFields = new Map(), existingStaticNonFields = new Map(), i = 0; i < decInfos.length; i++) {
-    var decInfo = decInfos[i];
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = new Array(childrenLength);
 
-    if (Array.isArray(decInfo)) {
-      var base,
-          metadataMap,
-          initializers,
-          kind = decInfo[1],
-          name = decInfo[2],
-          isPrivate = decInfo.length > 3,
-          isStatic = kind >= 5;
-
-      if (isStatic ? (base = Class, metadataMap = staticMetadataMap, kind -= 5, initializers = staticInitializers) : (base = Class.prototype, metadataMap = protoMetadataMap, initializers = protoInitializers), 0 !== kind && !isPrivate) {
-        var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields,
-            existingKind = existingNonFields.get(name) || 0;
-        if (!0 === existingKind || 3 === existingKind && 4 !== kind || 4 === existingKind && 3 !== kind) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
-        !existingKind && kind > 2 ? existingNonFields.set(name, kind) : existingNonFields.set(name, !0);
-      }
-
-      applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 3];
     }
-  }
-
-  protoInitializers.length > 0 && pushInitializers(ret, protoInitializers), staticInitializers.length > 0 && pushInitializers(ret, staticInitializers);
-}
-
-function pushInitializers(ret, initializers) {
-  initializers.length > 0 ? (initializers = initializers.slice(), ret.push(function (instance) {
-    for (var i = 0; i < initializers.length; i++) initializers[i].call(instance, instance);
-
-    return instance;
-  })) : ret.push(function (instance) {
-    return instance;
-  });
-}
-
-function applyClassDecs(ret, targetClass, metadataMap, classDecs) {
-  for (var initializers = [], newClass = targetClass, name = targetClass.name, ctx = Object.assign({
-    kind: "class",
-    name: name,
-    addInitializer: createAddInitializerMethod(initializers)
-  }, createMetadataMethodsForProperty(metadataMap, 0, name)), i = classDecs.length - 1; i >= 0; i--) newClass = classDecs[i](newClass, ctx) || newClass;
-
-  ret.push(newClass), initializers.length > 0 ? ret.push(function () {
-    for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass, newClass);
-  }) : ret.push(function () {});
-}
-
-function _applyDecs(targetClass, memberDecs, classDecs) {
-  var ret = [],
-      staticMetadataMap = {};
-
-  if (memberDecs) {
-    var protoMetadataMap = {};
-    applyMemberDecs(ret, targetClass, protoMetadataMap, staticMetadataMap, memberDecs), convertMetadataMapToFinal(targetClass.prototype, protoMetadataMap);
-  }
 
-  return classDecs && applyClassDecs(ret, targetClass, staticMetadataMap, classDecs), convertMetadataMapToFinal(targetClass, staticMetadataMap), ret;
-}
-
-function _asyncIterator(iterable) {
-  var method,
-      async,
-      sync,
-      retry = 2;
-
-  for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) {
-    if (async && null != (method = iterable[async])) return method.call(iterable);
-    if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable));
-    async = "@@asyncIterator", sync = "@@iterator";
-  }
-
-  throw new TypeError("Object is not async iterable");
-}
-
-function AsyncFromSyncIterator(s) {
-  function AsyncFromSyncIteratorContinuation(r) {
-    if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
-    var done = r.done;
-    return Promise.resolve(r.value).then(function (value) {
-      return {
-        value: value,
-        done: done
-      };
-    });
+    props.children = childArray;
   }
 
-  return AsyncFromSyncIterator = function (s) {
-    this.s = s, this.n = s.next;
-  }, AsyncFromSyncIterator.prototype = {
-    s: null,
-    n: null,
-    next: function () {
-      return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
-    },
-    return: function (value) {
-      var ret = this.s.return;
-      return void 0 === ret ? Promise.resolve({
-        value: value,
-        done: !0
-      }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));
-    },
-    throw: function (value) {
-      var thr = this.s.return;
-      return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));
+  if (props && defaultProps) {
+    for (var propName in defaultProps) {
+      if (props[propName] === void 0) {
+        props[propName] = defaultProps[propName];
+      }
     }
-  }, new AsyncFromSyncIterator(s);
-}
-
-var REACT_ELEMENT_TYPE;
-
-function _jsx(type, props, key, children) {
-  REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103);
-  var defaultProps = type && type.defaultProps,
-      childrenLength = arguments.length - 3;
-  if (props || 0 === childrenLength || (props = {
-    children: void 0
-  }), 1 === childrenLength) props.children = children;else if (childrenLength > 1) {
-    for (var childArray = new Array(childrenLength), i = 0; i < childrenLength; i++) childArray[i] = arguments[i + 3];
-
-    props.children = childArray;
+  } else if (!props) {
+    props = defaultProps || {};
   }
-  if (props && defaultProps) for (var propName in defaultProps) void 0 === props[propName] && (props[propName] = defaultProps[propName]);else props || (props = defaultProps || {});
+
   return {
     $$typeof: REACT_ELEMENT_TYPE,
     type: type,
-    key: void 0 === key ? null : "" + key,
+    key: key === undefined ? null : '' + key,
     ref: null,
     props: props,
     _owner: null
   };
 }
 
-function ownKeys(object, enumerableOnly) {
-  var keys = Object.keys(object);
-
-  if (Object.getOwnPropertySymbols) {
-    var symbols = Object.getOwnPropertySymbols(object);
-    enumerableOnly && (symbols = symbols.filter(function (sym) {
-      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
-    })), keys.push.apply(keys, symbols);
-  }
-
-  return keys;
-}
-
-function _objectSpread2(target) {
-  for (var i = 1; i < arguments.length; i++) {
-    var source = null != arguments[i] ? arguments[i] : {};
-    i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
-      _defineProperty(target, key, source[key]);
-    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
-      Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
-    });
-  }
-
-  return target;
-}
-
-function _typeof(obj) {
-  "@babel/helpers - typeof";
-
-  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
-    return typeof obj;
-  } : function (obj) {
-    return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
-  }, _typeof(obj);
-}
-
-function _wrapRegExp() {
-  _wrapRegExp = function (re, groups) {
-    return new BabelRegExp(re, void 0, groups);
-  };
-
-  var _super = RegExp.prototype,
-      _groups = new WeakMap();
-
-  function BabelRegExp(re, flags, groups) {
-    var _this = new RegExp(re, flags);
-
-    return _groups.set(_this, groups || _groups.get(re)), _setPrototypeOf(_this, BabelRegExp.prototype);
-  }
-
-  function buildGroups(result, re) {
-    var g = _groups.get(re);
-
-    return Object.keys(g).reduce(function (groups, name) {
-      return groups[name] = result[g[name]], groups;
-    }, Object.create(null));
-  }
-
-  return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (str) {
-    var result = _super.exec.call(this, str);
-
-    return result && (result.groups = buildGroups(result, this)), result;
-  }, BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
-    if ("string" == typeof substitution) {
-      var groups = _groups.get(this);
+function _asyncIterator(iterable) {
+  var method;
 
-      return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
-        return "$" + groups[name];
-      }));
+  if (typeof Symbol !== "undefined") {
+    if (Symbol.asyncIterator) {
+      method = iterable[Symbol.asyncIterator];
+      if (method != null) return method.call(iterable);
     }
 
-    if ("function" == typeof substitution) {
-      var _this = this;
-
-      return _super[Symbol.replace].call(this, str, function () {
-        var args = arguments;
-        return "object" != typeof args[args.length - 1] && (args = [].slice.call(args)).push(buildGroups(args, _this)), substitution.apply(this, args);
-      });
+    if (Symbol.iterator) {
+      method = iterable[Symbol.iterator];
+      if (method != null) return method.call(iterable);
     }
+  }
 
-    return _super[Symbol.replace].call(this, str, substitution);
-  }, _wrapRegExp.apply(this, arguments);
+  throw new TypeError("Object is not async iterable");
 }
 
 function _AwaitValue(value) {
@@ -487,9 +167,11 @@ function _AsyncGenerator(gen) {
   }
 }
 
-_AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () {
-  return this;
-};
+if (typeof Symbol === "function" && Symbol.asyncIterator) {
+  _AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
+    return this;
+  };
+}
 
 _AsyncGenerator.prototype.next = function (arg) {
   return this._invoke("next", arg);
@@ -530,9 +212,11 @@ function _asyncGeneratorDelegate(inner, awaitWrap) {
 
   ;
 
-  iter[typeof Symbol !== "undefined" && Symbol.iterator || "@@iterator"] = function () {
-    return this;
-  };
+  if (typeof Symbol === "function" && Symbol.iterator) {
+    iter[Symbol.iterator] = function () {
+      return this;
+    };
+  }
 
   iter.next = function (value) {
     if (waiting) {
@@ -623,9 +307,6 @@ function _defineProperties(target, props) {
 function _createClass(Constructor, protoProps, staticProps) {
   if (protoProps) _defineProperties(Constructor.prototype, protoProps);
   if (staticProps) _defineProperties(Constructor, staticProps);
-  Object.defineProperty(Constructor, "prototype", {
-    writable: false
-  });
   return Constructor;
 }
 
@@ -706,7 +387,7 @@ function _objectSpread(target) {
     var ownKeys = Object.keys(source);
 
     if (typeof Object.getOwnPropertySymbols === 'function') {
-      ownKeys.push.apply(ownKeys, Object.getOwnPropertySymbols(source).filter(function (sym) {
+      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
         return Object.getOwnPropertyDescriptor(source, sym).enumerable;
       }));
     }
@@ -719,6 +400,40 @@ function _objectSpread(target) {
   return target;
 }
 
+function ownKeys(object, enumerableOnly) {
+  var keys = Object.keys(object);
+
+  if (Object.getOwnPropertySymbols) {
+    var symbols = Object.getOwnPropertySymbols(object);
+    if (enumerableOnly) symbols = symbols.filter(function (sym) {
+      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+    });
+    keys.push.apply(keys, symbols);
+  }
+
+  return keys;
+}
+
+function _objectSpread2(target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i] != null ? arguments[i] : {};
+
+    if (i % 2) {
+      ownKeys(Object(source), true).forEach(function (key) {
+        _defineProperty(target, key, source[key]);
+      });
+    } else if (Object.getOwnPropertyDescriptors) {
+      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+    } else {
+      ownKeys(Object(source)).forEach(function (key) {
+        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+      });
+    }
+  }
+
+  return target;
+}
+
 function _inherits(subClass, superClass) {
   if (typeof superClass !== "function" && superClass !== null) {
     throw new TypeError("Super expression must either be null or a function");
@@ -731,9 +446,6 @@ function _inherits(subClass, superClass) {
       configurable: true
     }
   });
-  Object.defineProperty(subClass, "prototype", {
-    writable: false
-  });
   if (superClass) _setPrototypeOf(subClass, superClass);
 }
 
@@ -842,17 +554,19 @@ function _interopRequireDefault(obj) {
   };
 }
 
-function _getRequireWildcardCache(nodeInterop) {
+function _getRequireWildcardCache() {
   if (typeof WeakMap !== "function") return null;
-  var cacheBabelInterop = new WeakMap();
-  var cacheNodeInterop = new WeakMap();
-  return (_getRequireWildcardCache = function (nodeInterop) {
-    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
-  })(nodeInterop);
+  var cache = new WeakMap();
+
+  _getRequireWildcardCache = function () {
+    return cache;
+  };
+
+  return cache;
 }
 
-function _interopRequireWildcard(obj, nodeInterop) {
-  if (!nodeInterop && obj && obj.__esModule) {
+function _interopRequireWildcard(obj) {
+  if (obj && obj.__esModule) {
     return obj;
   }
 
@@ -862,7 +576,7 @@ function _interopRequireWildcard(obj, nodeInterop) {
     };
   }
 
-  var cache = _getRequireWildcardCache(nodeInterop);
+  var cache = _getRequireWildcardCache();
 
   if (cache && cache.has(obj)) {
     return cache.get(obj);
@@ -872,7 +586,7 @@ function _interopRequireWildcard(obj, nodeInterop) {
   var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
 
   for (var key in obj) {
-    if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
       var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
 
       if (desc && (desc.get || desc.set)) {
@@ -949,8 +663,6 @@ function _assertThisInitialized(self) {
 function _possibleConstructorReturn(self, call) {
   if (call && (typeof call === "object" || typeof call === "function")) {
     return call;
-  } else if (call !== void 0) {
-    throw new TypeError("Derived constructors may only return object or undefined");
   }
 
   return _assertThisInitialized(self);
@@ -984,7 +696,7 @@ function _superPropBase(object, property) {
   return object;
 }
 
-function _get() {
+function _get(target, property, receiver) {
   if (typeof Reflect !== "undefined" && Reflect.get) {
     _get = Reflect.get;
   } else {
@@ -995,14 +707,14 @@ function _get() {
       var desc = Object.getOwnPropertyDescriptor(base, property);
 
       if (desc.get) {
-        return desc.get.call(arguments.length < 3 ? target : receiver);
+        return desc.get.call(receiver);
       }
 
       return desc.value;
     };
   }
 
-  return _get.apply(this, arguments);
+  return _get(target, property, receiver || target);
 }
 
 function set(target, property, value, receiver) {
@@ -1132,21 +844,18 @@ function _maybeArrayLike(next, arr, i) {
 }
 
 function _iterableToArray(iter) {
-  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
+  if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
 }
 
 function _iterableToArrayLimit(arr, i) {
-  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
-
-  if (_i == null) return;
+  if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
   var _arr = [];
   var _n = true;
   var _d = false;
-
-  var _s, _e;
+  var _e = undefined;
 
   try {
-    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
+    for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
       _arr.push(_s.value);
 
       if (i && _arr.length === i) break;
@@ -1166,12 +875,10 @@ function _iterableToArrayLimit(arr, i) {
 }
 
 function _iterableToArrayLimitLoose(arr, i) {
-  var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]);
-
-  if (_i == null) return;
+  if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
   var _arr = [];
 
-  for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) {
+  for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
     _arr.push(_step.value);
 
     if (i && _arr.length === i) break;
@@ -1206,9 +913,9 @@ function _nonIterableRest() {
 }
 
 function _createForOfIteratorHelper(o, allowArrayLike) {
-  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
+  var it;
 
-  if (!it) {
+  if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
     if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
       if (it) o = it;
       var i = 0;
@@ -1241,7 +948,7 @@ function _createForOfIteratorHelper(o, allowArrayLike) {
       err;
   return {
     s: function () {
-      it = it.call(o);
+      it = o[Symbol.iterator]();
     },
     n: function () {
       var step = it.next();
@@ -1263,24 +970,28 @@ function _createForOfIteratorHelper(o, allowArrayLike) {
 }
 
 function _createForOfIteratorHelperLoose(o, allowArrayLike) {
-  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
-  if (it) return (it = it.call(o)).next.bind(it);
+  var it;
 
-  if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
-    if (it) o = it;
-    var i = 0;
-    return function () {
-      if (i >= o.length) return {
-        done: true
-      };
-      return {
-        done: false,
-        value: o[i++]
+  if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
+    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
+      if (it) o = it;
+      var i = 0;
+      return function () {
+        if (i >= o.length) return {
+          done: true
+        };
+        return {
+          done: false,
+          value: o[i++]
+        };
       };
-    };
+    }
+
+    throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
   }
 
-  throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+  it = o[Symbol.iterator]();
+  return it.next.bind(it);
 }
 
 function _skipFirstGeneratorNext(fn) {
@@ -1889,30 +1600,73 @@ function _classPrivateMethodGet(receiver, privateSet, fn) {
   return fn;
 }
 
-function _checkPrivateRedeclaration(obj, privateCollection) {
-  if (privateCollection.has(obj)) {
-    throw new TypeError("Cannot initialize the same private elements twice on an object");
-  }
+function _classPrivateMethodSet() {
+  throw new TypeError("attempted to reassign private method");
 }
 
-function _classPrivateFieldInitSpec(obj, privateMap, value) {
-  _checkPrivateRedeclaration(obj, privateMap);
+function _wrapRegExp(re, groups) {
+  _wrapRegExp = function (re, groups) {
+    return new BabelRegExp(re, undefined, groups);
+  };
 
-  privateMap.set(obj, value);
-}
+  var _RegExp = _wrapNativeSuper(RegExp);
 
-function _classPrivateMethodInitSpec(obj, privateSet) {
-  _checkPrivateRedeclaration(obj, privateSet);
+  var _super = RegExp.prototype;
 
-  privateSet.add(obj);
-}
+  var _groups = new WeakMap();
 
-function _classPrivateMethodSet() {
-  throw new TypeError("attempted to reassign private method");
-}
+  function BabelRegExp(re, flags, groups) {
+    var _this = _RegExp.call(this, re, flags);
+
+    _groups.set(_this, groups || _groups.get(re));
+
+    return _this;
+  }
+
+  _inherits(BabelRegExp, _RegExp);
+
+  BabelRegExp.prototype.exec = function (str) {
+    var result = _super.exec.call(this, str);
+
+    if (result) result.groups = buildGroups(result, this);
+    return result;
+  };
+
+  BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
+    if (typeof substitution === "string") {
+      var groups = _groups.get(this);
+
+      return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
+        return "$" + groups[name];
+      }));
+    } else if (typeof substitution === "function") {
+      var _this = this;
+
+      return _super[Symbol.replace].call(this, str, function () {
+        var args = [];
+        args.push.apply(args, arguments);
+
+        if (typeof args[args.length - 1] !== "object") {
+          args.push(buildGroups(args, _this));
+        }
+
+        return substitution.apply(this, args);
+      });
+    } else {
+      return _super[Symbol.replace].call(this, str, substitution);
+    }
+  };
+
+  function buildGroups(result, re) {
+    var g = _groups.get(re);
+
+    return Object.keys(g).reduce(function (groups, name) {
+      groups[name] = result[g[name]];
+      return groups;
+    }, Object.create(null));
+  }
 
-function _identity(x) {
-  return x;
+  return _wrapRegExp.apply(this, arguments);
 }
 
 // Numbers represent type - 
@@ -12629,8 +12383,8 @@ var glslParser = createCommonjsModule(function (module, exports) {
         if (!entry
         /*|| !entry.type*/
         ) {
-          this.ir_error(util.format("%s is undefined", name));
-        }
+            this.ir_error(util.format("%s is undefined", name));
+          }
 
         this.Type = entry.type;
         this.Entry = entry;
@@ -30192,7 +29946,7 @@ var sdfs = {
   cappedTorus: "\nfloat sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)\n{\n    p.x = abs(p.x);\n    float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);\n    return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;\n}\n"
 };
 
-const _from$1="estraverse@^4.2.0";const _id$3="estraverse@4.3.0";const _inBundle$1=false;const _integrity$1="sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==";const _location$1="/estraverse";const _phantomChildren$1={};const _requested$1={type:"range",registry:true,raw:"estraverse@^4.2.0",name:"estraverse",escapedName:"estraverse",rawSpec:"^4.2.0",saveSpec:null,fetchSpec:"^4.2.0"};const _requiredBy$1=["/escodegen"];const _resolved$1="https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz";const _shasum$1="398ad3f3c5a24948be7725e83d11a7de28cdbd1d";const _spec$1="estraverse@^4.2.0";const _where$1="/Users/peterwhidden/Documents/sp_refactor/shader-park-core/node_modules/escodegen";const bugs$1={url:"https://github.com/estools/estraverse/issues"};const bundleDependencies$1=false;const deprecated$1=false;const description$1="ECMAScript JS AST traversal functions";const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const engines$1={node:">=4.0"};const homepage$1="https://github.com/estools/estraverse";const license$1="BSD-2-Clause";const main$1="estraverse.js";const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name$1="estraverse";const repository$1={type:"git",url:"git+ssh://git@github.com/estools/estraverse.git"};const scripts$1={lint:"jshint estraverse.js",test:"npm run-script lint && npm run-script unit-test","unit-test":"mocha --compilers js:babel-register"};const version$1="4.3.0";var require$$0 = {_from:_from$1,_id:_id$3,_inBundle:_inBundle$1,_integrity:_integrity$1,_location:_location$1,_phantomChildren:_phantomChildren$1,_requested:_requested$1,_requiredBy:_requiredBy$1,_resolved:_resolved$1,_shasum:_shasum$1,_spec:_spec$1,_where:_where$1,bugs:bugs$1,bundleDependencies:bundleDependencies$1,deprecated:deprecated$1,description:description$1,devDependencies:devDependencies$1,engines:engines$1,homepage:homepage$1,license:license$1,main:main$1,maintainers:maintainers$1,name:name$1,repository:repository$1,scripts:scripts$1,version:version$1};
+const name$1="estraverse";const description$1="ECMAScript JS AST traversal functions";const homepage$1="https://github.com/estools/estraverse";const main$1="estraverse.js";const version$1="4.3.0";const engines$1={node:">=4.0"};const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository$1={type:"git",url:"http://github.com/estools/estraverse.git"};const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const license$1="BSD-2-Clause";const scripts$1={test:"npm run-script lint && npm run-script unit-test",lint:"jshint estraverse.js","unit-test":"mocha --compilers js:babel-register"};var require$$0 = {name:name$1,description:description$1,homepage:homepage$1,main:main$1,version:version$1,engines:engines$1,maintainers:maintainers$1,repository:repository$1,devDependencies:devDependencies$1,license:license$1,scripts:scripts$1};
 
 /*
   Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -34645,7 +34399,7 @@ var sourceMap = {
 	SourceNode: SourceNode
 };
 
-const _from="escodegen@^1.11.1";const _id$2="escodegen@1.14.3";const _inBundle=false;const _integrity="sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==";const _location="/escodegen";const _phantomChildren={};const _requested={type:"range",registry:true,raw:"escodegen@^1.11.1",name:"escodegen",escapedName:"escodegen",rawSpec:"^1.11.1",saveSpec:null,fetchSpec:"^1.11.1"};const _requiredBy=["/"];const _resolved="https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz";const _shasum="4e7b81fba61581dc97582ed78cab7f0e8d63f503";const _spec="escodegen@^1.11.1";const _where="/Users/peterwhidden/Documents/sp_refactor/shader-park-core";const bin={esgenerate:"bin/esgenerate.js",escodegen:"bin/escodegen.js"};const bugs={url:"https://github.com/estools/escodegen/issues"};const bundleDependencies=false;const dependencies={esprima:"^4.0.1",estraverse:"^4.2.0",esutils:"^2.0.2",optionator:"^0.8.1","source-map":"~0.6.1"};const deprecated=false;const description="ECMAScript code generator";const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const engines={node:">=4.0"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const homepage="http://github.com/estools/escodegen";const license="BSD-2-Clause";const main="escodegen.js";const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name="escodegen";const optionalDependencies={"source-map":"~0.6.1"};const repository={type:"git",url:"git+ssh://git@github.com/estools/escodegen.git"};const scripts={build:"cjsify -a path: tools/entry-point.js > escodegen.browser.js","build-min":"cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",lint:"gulp lint",release:"node tools/release.js",test:"gulp travis","unit-test":"gulp test"};const version="1.14.3";var require$$3 = {_from:_from,_id:_id$2,_inBundle:_inBundle,_integrity:_integrity,_location:_location,_phantomChildren:_phantomChildren,_requested:_requested,_requiredBy:_requiredBy,_resolved:_resolved,_shasum:_shasum,_spec:_spec,_where:_where,bin:bin,bugs:bugs,bundleDependencies:bundleDependencies,dependencies:dependencies,deprecated:deprecated,description:description,devDependencies:devDependencies,engines:engines,files:files,homepage:homepage,license:license,main:main,maintainers:maintainers,name:name,optionalDependencies:optionalDependencies,repository:repository,scripts:scripts,version:version};
+const name="escodegen";const description="ECMAScript code generator";const homepage="http://github.com/estools/escodegen";const main="escodegen.js";const bin={esgenerate:"./bin/esgenerate.js",escodegen:"./bin/escodegen.js"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const version="1.14.1";const engines={node:">=4.0"};const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository={type:"git",url:"http://github.com/estools/escodegen.git"};const dependencies={estraverse:"^4.2.0",esutils:"^2.0.2",esprima:"^4.0.1",optionator:"^0.8.1"};const optionalDependencies={"source-map":"~0.6.1"};const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const license="BSD-2-Clause";const scripts={test:"gulp travis","unit-test":"gulp test",lint:"gulp lint",release:"node tools/release.js","build-min":"./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",build:"./node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js"};var require$$3 = {name:name,description:description,homepage:homepage,main:main,bin:bin,files:files,version:version,engines:engines,maintainers:maintainers,repository:repository,dependencies:dependencies,optionalDependencies:optionalDependencies,devDependencies:devDependencies,license:license,scripts:scripts};
 
 /*
   Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -35633,7 +35387,7 @@ var escodegen = createCommonjsModule(function (module, exports) {
             result.push('[');
         }
 
-        result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
+        result.push(this.generateExpression(expr, Precedence.Sequence, E_TTT));
 
         if (computed) {
             result.push(']');
@@ -36873,19 +36627,13 @@ var escodegen = createCommonjsModule(function (module, exports) {
             multiline = false;
             if (expr.properties.length === 1) {
                 property = expr.properties[0];
-                if (
-                    property.type === Syntax.Property
-                    && property.value.type !== Syntax.Identifier
-                ) {
+                if (property.value.type !== Syntax.Identifier) {
                     multiline = true;
                 }
             } else {
                 for (i = 0, iz = expr.properties.length; i < iz; ++i) {
                     property = expr.properties[i];
-                    if (
-                        property.type === Syntax.Property
-                        && !property.shorthand
-                    ) {
+                    if (!property.shorthand) {
                         multiline = true;
                         break;
                     }
@@ -43996,7 +43744,7 @@ function buildGeoSource(geo) {
 
 function buildColorSource(col, useLighting) {
   var lgt = useLighting ? '' : '    return scope_0_material.albedo;';
-  return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
+  return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
 } // Converts binary math operators to our own version
 
 
@@ -44152,6 +43900,38 @@ function bindStaticData(staticData, spCode) {
   spCode = convertFunctionToString(spCode);
   return "const staticData = JSON.parse(`".concat(JSON.stringify(staticData), "`)\n") + spCode;
 }
+
+function errorMsg(err) {
+  console.error(err);
+  throw new Error(err);
+}
+
+function spCodeToMultiPassGLSL(passes) {
+  if (_typeof(passes) !== 'object') {
+    errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+  }
+
+  var common = passes.common,
+      bufferA = passes.bufferA,
+      bufferB = passes.bufferB,
+      bufferC = passes.bufferC,
+      bufferD = passes.bufferD,
+      finalImage = passes.finalImage;
+
+  if (!common) {
+    common = '';
+  }
+
+  if (!finalImage) {
+    errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+  }
+
+  return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
+    if (pass) {
+      return sculptToGLSL(common + '\n' + pass);
+    }
+  });
+}
 function sculptToGLSL(userProvidedSrc) {
   var PI = Math.PI;
   var TWO_PI = Math.PI * 2;
@@ -44725,9 +44505,9 @@ function sculptToGLSL(userProvidedSrc) {
   }
 
   function ensureScalar(funcName, val) {
-    var tp = _typeof(val);
-
-    if (typeof val !== 'number' && val.type !== 'float') {
+    if (typeof val === 'undefined') {
+      compileError("'" + funcName + "'" + " was given an undefined parameter");
+    } else if (typeof val !== 'number' && val.type !== 'float') {
       compileError("'" + funcName + "'" + " accepts only a scalar. Was given: '" + val.type + "'");
     }
   }
@@ -45062,15 +44842,32 @@ function sculptToGLSL(userProvidedSrc) {
   } // Color/Lighting
 
 
+  function colorRGBA(col, green, blue, alpha) {}
+
   function color(col, green, blue) {
+    var alpha = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1.0;
+
     if (green !== undefined) {
+      if (blue === undefined) {
+        compileError("color must be vec3, or vec4, or receive rgb, or rgba");
+      }
+
       ensureScalar("color", col);
       ensureScalar("color", green);
       ensureScalar("color", blue);
+      ensureScalar("color", alpha);
       appendColorSource(getCurrentMaterial() + ".albedo = vec3(" + collapseToString(col) + ", " + collapseToString(green) + ", " + collapseToString(blue) + ");\n");
-    } else {
-      if (col.type !== 'vec3') compileError("albedo must be vec3");
-      appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+      appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+    } else {
+      if (col.type === 'vec3') {
+        appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+        appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+      } else if (col.type === 'vec4') {
+        appendColorSource(getCurrentMaterial() + ".albedo = ".concat(collapseToString(col), ".rgb;\n"));
+        appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(col), ".a;\n"));
+      } else {
+        compileError("color must be vec3, or vec4");
+      }
     }
   }
 
@@ -45278,7 +45075,7 @@ var threeHeader = "\nuniform mat4 projectionMatrix;\nuniform sampler2D msdf;\n\n
 var minimalHeader = "#version 300 es\nprecision highp float;\nuniform mat4 projectionMatrix;\nin vec3 sculptureCenter;\nout vec4 pc_fragColor;\n#define cameraPosition vec3(0.0,0.0,-2.0)\n#define vUv vec2(0.0)\n#define worldPos vec4(vec2((gl_FragCoord.x/resolution.x-0.5)*(resolution.x/resolution.y),gl_FragCoord.y/resolution.y-0.5)*1.75,0.0,0.0)\n";
 var usePBRHeader = '#define USE_PBR\n';
 var useHemisphereLight = '#define HEMISPHERE_LIGHT\n';
-var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
+var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float alpha;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.alpha, b.alpha, amount),\n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
 var fragFooter = "\n// For advanced users //\nvoid main() {\n\n    vec3 rayOrigin = (cameraPosition - sculptureCenter) / max(intersection_threshold, _scale);\n    vec3 rayDirection = getRayDirection();\n    float t = intersect(rayOrigin, rayDirection, stepSize);\n    if(t < max_dist) {\n        vec3 p = (rayOrigin + rayDirection*t);\n        //vec4 sp = projectionMatrix*viewMatrix*vec4(p,1.0); //could be used to set FragDepth\n        vec3 normal = calcNormal(p);\n        // p *= _scale;\n        vec3 col = shade(p, normal);\n        pc_fragColor = vec4(col, opacity);\n        \n    } else {\n        discard;\n    }\n}\n";
 
 /**
@@ -96465,7 +96262,7 @@ function sculptToTouchDesignerShaderSource(source) {
   };
 }
 
-console.log("using shader-park version: 0.1.10"); /// Generate code for various targets
+console.log("using shader-park version: 0.1.12"); /// Generate code for various targets
 
 exports.baseUniforms = baseUniforms;
 exports.bindStaticData = bindStaticData;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 7789f61..91cb627 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -1,403 +1,83 @@
-function createMetadataMethodsForProperty(metadataMap, kind, property) {
-  return {
-    getMetadata: function (key) {
-      if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-      var metadataForKey = metadataMap[key];
-      if (void 0 !== metadataForKey) if (1 === kind) {
-        var pub = metadataForKey.public;
-        if (void 0 !== pub) return pub[property];
-      } else if (2 === kind) {
-        var priv = metadataForKey.private;
-        if (void 0 !== priv) return priv.get(property);
-      } else if (Object.hasOwnProperty.call(metadataForKey, "constructor")) return metadataForKey.constructor;
-    },
-    setMetadata: function (key, value) {
-      if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-      var metadataForKey = metadataMap[key];
-
-      if (void 0 === metadataForKey && (metadataForKey = metadataMap[key] = {}), 1 === kind) {
-        var pub = metadataForKey.public;
-        void 0 === pub && (pub = metadataForKey.public = {}), pub[property] = value;
-      } else if (2 === kind) {
-        var priv = metadataForKey.priv;
-        void 0 === priv && (priv = metadataForKey.private = new Map()), priv.set(property, value);
-      } else metadataForKey.constructor = value;
-    }
-  };
-}
-
-function convertMetadataMapToFinal(obj, metadataMap) {
-  var parentMetadataMap = obj[Symbol.metadata || Symbol.for("Symbol.metadata")],
-      metadataKeys = Object.getOwnPropertySymbols(metadataMap);
-
-  if (0 !== metadataKeys.length) {
-    for (var i = 0; i < metadataKeys.length; i++) {
-      var key = metadataKeys[i],
-          metaForKey = metadataMap[key],
-          parentMetaForKey = parentMetadataMap ? parentMetadataMap[key] : null,
-          pub = metaForKey.public,
-          parentPub = parentMetaForKey ? parentMetaForKey.public : null;
-      pub && parentPub && Object.setPrototypeOf(pub, parentPub);
-      var priv = metaForKey.private;
-
-      if (priv) {
-        var privArr = Array.from(priv.values()),
-            parentPriv = parentMetaForKey ? parentMetaForKey.private : null;
-        parentPriv && (privArr = privArr.concat(parentPriv)), metaForKey.private = privArr;
-      }
-
-      parentMetaForKey && Object.setPrototypeOf(metaForKey, parentMetaForKey);
-    }
+function _typeof(obj) {
+  "@babel/helpers - typeof";
 
-    parentMetadataMap && Object.setPrototypeOf(metadataMap, parentMetadataMap), obj[Symbol.metadata || Symbol.for("Symbol.metadata")] = metadataMap;
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function (obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function (obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
   }
-}
 
-function createAddInitializerMethod(initializers) {
-  return function (initializer) {
-    assertValidInitializer(initializer), initializers.push(initializer);
-  };
+  return _typeof(obj);
 }
 
-function memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate) {
-  var kindStr;
-
-  switch (kind) {
-    case 1:
-      kindStr = "accessor";
-      break;
-
-    case 2:
-      kindStr = "method";
-      break;
-
-    case 3:
-      kindStr = "getter";
-      break;
-
-    case 4:
-      kindStr = "setter";
-      break;
+var REACT_ELEMENT_TYPE;
 
-    default:
-      kindStr = "field";
+function _jsx(type, props, key, children) {
+  if (!REACT_ELEMENT_TYPE) {
+    REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol["for"] && Symbol["for"]("react.element") || 0xeac7;
   }
 
-  var metadataKind,
-      metadataName,
-      ctx = {
-    kind: kindStr,
-    name: isPrivate ? "#" + name : name,
-    isStatic: isStatic,
-    isPrivate: isPrivate
-  };
-
-  if (0 !== kind && (ctx.addInitializer = createAddInitializerMethod(initializers)), isPrivate) {
-    metadataKind = 2, metadataName = Symbol(name);
-    var access = {};
-    0 === kind ? (access.get = desc.get, access.set = desc.set) : 2 === kind ? access.get = function () {
-      return desc.value;
-    } : (1 !== kind && 3 !== kind || (access.get = function () {
-      return desc.get.call(this);
-    }), 1 !== kind && 4 !== kind || (access.set = function (v) {
-      desc.set.call(this, v);
-    })), ctx.access = access;
-  } else metadataKind = 1, metadataName = name;
-
-  return Object.assign(ctx, createMetadataMethodsForProperty(metadataMap, metadataKind, metadataName));
-}
-
-function assertValidInitializer(initializer) {
-  if ("function" != typeof initializer) throw new Error("initializers must be functions");
-}
-
-function assertValidReturnValue(kind, value) {
-  var type = typeof value;
-
-  if (1 === kind) {
-    if ("object" !== type || null === value) throw new Error("accessor decorators must return an object with get, set, or initializer properties or void 0");
-  } else if ("function" !== type) throw 0 === kind ? new Error("field decorators must return a initializer function or void 0") : new Error("method decorators must return a function or void 0");
-}
-
-function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers) {
-  var desc,
-      initializer,
-      value,
-      decs = decInfo[0];
-  isPrivate ? desc = 0 === kind || 1 === kind ? {
-    get: decInfo[3],
-    set: decInfo[4]
-  } : 3 === kind ? {
-    get: decInfo[3]
-  } : 4 === kind ? {
-    set: decInfo[3]
-  } : {
-    value: decInfo[3]
-  } : 0 !== kind && (desc = Object.getOwnPropertyDescriptor(base, name)), 1 === kind ? value = {
-    get: desc.get,
-    set: desc.set
-  } : 2 === kind ? value = desc.value : 3 === kind ? value = desc.get : 4 === kind && (value = desc.set);
-  var newValue,
-      get,
-      set,
-      ctx = memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate);
-  if ("function" == typeof decs) void 0 !== (newValue = decs(value, ctx)) && (assertValidReturnValue(kind, newValue), 0 === kind ? initializer = newValue : 1 === kind ? (initializer = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-    get: get,
-    set: set
-  }) : value = newValue);else for (var i = decs.length - 1; i >= 0; i--) {
-    var newInit;
-    if (void 0 !== (newValue = (0, decs[i])(value, ctx))) assertValidReturnValue(kind, newValue), 0 === kind ? newInit = newValue : 1 === kind ? (newInit = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-      get: get,
-      set: set
-    }) : value = newValue, void 0 !== newInit && (void 0 === initializer ? initializer = newInit : "function" == typeof initializer ? initializer = [initializer, newInit] : initializer.push(newInit));
-  }
-
-  if (0 === kind || 1 === kind) {
-    if (void 0 === initializer) initializer = function (instance, init) {
-      return init;
-    };else if ("function" != typeof initializer) {
-      var ownInitializers = initializer;
-
-      initializer = function (instance, init) {
-        for (var value = init, i = 0; i < ownInitializers.length; i++) value = ownInitializers[i].call(instance, value);
+  var defaultProps = type && type.defaultProps;
+  var childrenLength = arguments.length - 3;
 
-        return value;
-      };
-    } else {
-      var originalInitializer = initializer;
-
-      initializer = function (instance, init) {
-        return originalInitializer.call(instance, init);
-      };
-    }
-    ret.push(initializer);
+  if (!props && childrenLength !== 0) {
+    props = {
+      children: void 0
+    };
   }
 
-  0 !== kind && (1 === kind ? (desc.get = value.get, desc.set = value.set) : 2 === kind ? desc.value = value : 3 === kind ? desc.get = value : 4 === kind && (desc.set = value), isPrivate ? 1 === kind ? (ret.push(function (instance, args) {
-    return value.get.call(instance, args);
-  }), ret.push(function (instance, args) {
-    return value.set.call(instance, args);
-  })) : 2 === kind ? ret.push(value) : ret.push(function (instance, args) {
-    return value.call(instance, args);
-  }) : Object.defineProperty(base, name, desc));
-}
-
-function applyMemberDecs(ret, Class, protoMetadataMap, staticMetadataMap, decInfos) {
-  for (var protoInitializers = [], staticInitializers = [], existingProtoNonFields = new Map(), existingStaticNonFields = new Map(), i = 0; i < decInfos.length; i++) {
-    var decInfo = decInfos[i];
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = new Array(childrenLength);
 
-    if (Array.isArray(decInfo)) {
-      var base,
-          metadataMap,
-          initializers,
-          kind = decInfo[1],
-          name = decInfo[2],
-          isPrivate = decInfo.length > 3,
-          isStatic = kind >= 5;
-
-      if (isStatic ? (base = Class, metadataMap = staticMetadataMap, kind -= 5, initializers = staticInitializers) : (base = Class.prototype, metadataMap = protoMetadataMap, initializers = protoInitializers), 0 !== kind && !isPrivate) {
-        var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields,
-            existingKind = existingNonFields.get(name) || 0;
-        if (!0 === existingKind || 3 === existingKind && 4 !== kind || 4 === existingKind && 3 !== kind) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
-        !existingKind && kind > 2 ? existingNonFields.set(name, kind) : existingNonFields.set(name, !0);
-      }
-
-      applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 3];
     }
-  }
-
-  protoInitializers.length > 0 && pushInitializers(ret, protoInitializers), staticInitializers.length > 0 && pushInitializers(ret, staticInitializers);
-}
-
-function pushInitializers(ret, initializers) {
-  initializers.length > 0 ? (initializers = initializers.slice(), ret.push(function (instance) {
-    for (var i = 0; i < initializers.length; i++) initializers[i].call(instance, instance);
-
-    return instance;
-  })) : ret.push(function (instance) {
-    return instance;
-  });
-}
-
-function applyClassDecs(ret, targetClass, metadataMap, classDecs) {
-  for (var initializers = [], newClass = targetClass, name = targetClass.name, ctx = Object.assign({
-    kind: "class",
-    name: name,
-    addInitializer: createAddInitializerMethod(initializers)
-  }, createMetadataMethodsForProperty(metadataMap, 0, name)), i = classDecs.length - 1; i >= 0; i--) newClass = classDecs[i](newClass, ctx) || newClass;
-
-  ret.push(newClass), initializers.length > 0 ? ret.push(function () {
-    for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass, newClass);
-  }) : ret.push(function () {});
-}
-
-function _applyDecs(targetClass, memberDecs, classDecs) {
-  var ret = [],
-      staticMetadataMap = {};
-
-  if (memberDecs) {
-    var protoMetadataMap = {};
-    applyMemberDecs(ret, targetClass, protoMetadataMap, staticMetadataMap, memberDecs), convertMetadataMapToFinal(targetClass.prototype, protoMetadataMap);
-  }
 
-  return classDecs && applyClassDecs(ret, targetClass, staticMetadataMap, classDecs), convertMetadataMapToFinal(targetClass, staticMetadataMap), ret;
-}
-
-function _asyncIterator(iterable) {
-  var method,
-      async,
-      sync,
-      retry = 2;
-
-  for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) {
-    if (async && null != (method = iterable[async])) return method.call(iterable);
-    if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable));
-    async = "@@asyncIterator", sync = "@@iterator";
-  }
-
-  throw new TypeError("Object is not async iterable");
-}
-
-function AsyncFromSyncIterator(s) {
-  function AsyncFromSyncIteratorContinuation(r) {
-    if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
-    var done = r.done;
-    return Promise.resolve(r.value).then(function (value) {
-      return {
-        value: value,
-        done: done
-      };
-    });
+    props.children = childArray;
   }
 
-  return AsyncFromSyncIterator = function (s) {
-    this.s = s, this.n = s.next;
-  }, AsyncFromSyncIterator.prototype = {
-    s: null,
-    n: null,
-    next: function () {
-      return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
-    },
-    return: function (value) {
-      var ret = this.s.return;
-      return void 0 === ret ? Promise.resolve({
-        value: value,
-        done: !0
-      }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));
-    },
-    throw: function (value) {
-      var thr = this.s.return;
-      return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));
+  if (props && defaultProps) {
+    for (var propName in defaultProps) {
+      if (props[propName] === void 0) {
+        props[propName] = defaultProps[propName];
+      }
     }
-  }, new AsyncFromSyncIterator(s);
-}
-
-var REACT_ELEMENT_TYPE;
-
-function _jsx(type, props, key, children) {
-  REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103);
-  var defaultProps = type && type.defaultProps,
-      childrenLength = arguments.length - 3;
-  if (props || 0 === childrenLength || (props = {
-    children: void 0
-  }), 1 === childrenLength) props.children = children;else if (childrenLength > 1) {
-    for (var childArray = new Array(childrenLength), i = 0; i < childrenLength; i++) childArray[i] = arguments[i + 3];
-
-    props.children = childArray;
+  } else if (!props) {
+    props = defaultProps || {};
   }
-  if (props && defaultProps) for (var propName in defaultProps) void 0 === props[propName] && (props[propName] = defaultProps[propName]);else props || (props = defaultProps || {});
+
   return {
     $$typeof: REACT_ELEMENT_TYPE,
     type: type,
-    key: void 0 === key ? null : "" + key,
+    key: key === undefined ? null : '' + key,
     ref: null,
     props: props,
     _owner: null
   };
 }
 
-function ownKeys(object, enumerableOnly) {
-  var keys = Object.keys(object);
-
-  if (Object.getOwnPropertySymbols) {
-    var symbols = Object.getOwnPropertySymbols(object);
-    enumerableOnly && (symbols = symbols.filter(function (sym) {
-      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
-    })), keys.push.apply(keys, symbols);
-  }
-
-  return keys;
-}
-
-function _objectSpread2(target) {
-  for (var i = 1; i < arguments.length; i++) {
-    var source = null != arguments[i] ? arguments[i] : {};
-    i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
-      _defineProperty(target, key, source[key]);
-    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
-      Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
-    });
-  }
-
-  return target;
-}
-
-function _typeof(obj) {
-  "@babel/helpers - typeof";
-
-  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
-    return typeof obj;
-  } : function (obj) {
-    return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
-  }, _typeof(obj);
-}
-
-function _wrapRegExp() {
-  _wrapRegExp = function (re, groups) {
-    return new BabelRegExp(re, void 0, groups);
-  };
-
-  var _super = RegExp.prototype,
-      _groups = new WeakMap();
-
-  function BabelRegExp(re, flags, groups) {
-    var _this = new RegExp(re, flags);
-
-    return _groups.set(_this, groups || _groups.get(re)), _setPrototypeOf(_this, BabelRegExp.prototype);
-  }
-
-  function buildGroups(result, re) {
-    var g = _groups.get(re);
-
-    return Object.keys(g).reduce(function (groups, name) {
-      return groups[name] = result[g[name]], groups;
-    }, Object.create(null));
-  }
-
-  return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (str) {
-    var result = _super.exec.call(this, str);
-
-    return result && (result.groups = buildGroups(result, this)), result;
-  }, BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
-    if ("string" == typeof substitution) {
-      var groups = _groups.get(this);
+function _asyncIterator(iterable) {
+  var method;
 
-      return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
-        return "$" + groups[name];
-      }));
+  if (typeof Symbol !== "undefined") {
+    if (Symbol.asyncIterator) {
+      method = iterable[Symbol.asyncIterator];
+      if (method != null) return method.call(iterable);
     }
 
-    if ("function" == typeof substitution) {
-      var _this = this;
-
-      return _super[Symbol.replace].call(this, str, function () {
-        var args = arguments;
-        return "object" != typeof args[args.length - 1] && (args = [].slice.call(args)).push(buildGroups(args, _this)), substitution.apply(this, args);
-      });
+    if (Symbol.iterator) {
+      method = iterable[Symbol.iterator];
+      if (method != null) return method.call(iterable);
     }
+  }
 
-    return _super[Symbol.replace].call(this, str, substitution);
-  }, _wrapRegExp.apply(this, arguments);
+  throw new TypeError("Object is not async iterable");
 }
 
 function _AwaitValue(value) {
@@ -483,9 +163,11 @@ function _AsyncGenerator(gen) {
   }
 }
 
-_AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () {
-  return this;
-};
+if (typeof Symbol === "function" && Symbol.asyncIterator) {
+  _AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
+    return this;
+  };
+}
 
 _AsyncGenerator.prototype.next = function (arg) {
   return this._invoke("next", arg);
@@ -526,9 +208,11 @@ function _asyncGeneratorDelegate(inner, awaitWrap) {
 
   ;
 
-  iter[typeof Symbol !== "undefined" && Symbol.iterator || "@@iterator"] = function () {
-    return this;
-  };
+  if (typeof Symbol === "function" && Symbol.iterator) {
+    iter[Symbol.iterator] = function () {
+      return this;
+    };
+  }
 
   iter.next = function (value) {
     if (waiting) {
@@ -619,9 +303,6 @@ function _defineProperties(target, props) {
 function _createClass(Constructor, protoProps, staticProps) {
   if (protoProps) _defineProperties(Constructor.prototype, protoProps);
   if (staticProps) _defineProperties(Constructor, staticProps);
-  Object.defineProperty(Constructor, "prototype", {
-    writable: false
-  });
   return Constructor;
 }
 
@@ -702,7 +383,7 @@ function _objectSpread(target) {
     var ownKeys = Object.keys(source);
 
     if (typeof Object.getOwnPropertySymbols === 'function') {
-      ownKeys.push.apply(ownKeys, Object.getOwnPropertySymbols(source).filter(function (sym) {
+      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
         return Object.getOwnPropertyDescriptor(source, sym).enumerable;
       }));
     }
@@ -715,6 +396,40 @@ function _objectSpread(target) {
   return target;
 }
 
+function ownKeys(object, enumerableOnly) {
+  var keys = Object.keys(object);
+
+  if (Object.getOwnPropertySymbols) {
+    var symbols = Object.getOwnPropertySymbols(object);
+    if (enumerableOnly) symbols = symbols.filter(function (sym) {
+      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+    });
+    keys.push.apply(keys, symbols);
+  }
+
+  return keys;
+}
+
+function _objectSpread2(target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i] != null ? arguments[i] : {};
+
+    if (i % 2) {
+      ownKeys(Object(source), true).forEach(function (key) {
+        _defineProperty(target, key, source[key]);
+      });
+    } else if (Object.getOwnPropertyDescriptors) {
+      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+    } else {
+      ownKeys(Object(source)).forEach(function (key) {
+        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+      });
+    }
+  }
+
+  return target;
+}
+
 function _inherits(subClass, superClass) {
   if (typeof superClass !== "function" && superClass !== null) {
     throw new TypeError("Super expression must either be null or a function");
@@ -727,9 +442,6 @@ function _inherits(subClass, superClass) {
       configurable: true
     }
   });
-  Object.defineProperty(subClass, "prototype", {
-    writable: false
-  });
   if (superClass) _setPrototypeOf(subClass, superClass);
 }
 
@@ -838,17 +550,19 @@ function _interopRequireDefault(obj) {
   };
 }
 
-function _getRequireWildcardCache(nodeInterop) {
+function _getRequireWildcardCache() {
   if (typeof WeakMap !== "function") return null;
-  var cacheBabelInterop = new WeakMap();
-  var cacheNodeInterop = new WeakMap();
-  return (_getRequireWildcardCache = function (nodeInterop) {
-    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
-  })(nodeInterop);
+  var cache = new WeakMap();
+
+  _getRequireWildcardCache = function () {
+    return cache;
+  };
+
+  return cache;
 }
 
-function _interopRequireWildcard(obj, nodeInterop) {
-  if (!nodeInterop && obj && obj.__esModule) {
+function _interopRequireWildcard(obj) {
+  if (obj && obj.__esModule) {
     return obj;
   }
 
@@ -858,7 +572,7 @@ function _interopRequireWildcard(obj, nodeInterop) {
     };
   }
 
-  var cache = _getRequireWildcardCache(nodeInterop);
+  var cache = _getRequireWildcardCache();
 
   if (cache && cache.has(obj)) {
     return cache.get(obj);
@@ -868,7 +582,7 @@ function _interopRequireWildcard(obj, nodeInterop) {
   var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
 
   for (var key in obj) {
-    if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
       var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
 
       if (desc && (desc.get || desc.set)) {
@@ -945,8 +659,6 @@ function _assertThisInitialized(self) {
 function _possibleConstructorReturn(self, call) {
   if (call && (typeof call === "object" || typeof call === "function")) {
     return call;
-  } else if (call !== void 0) {
-    throw new TypeError("Derived constructors may only return object or undefined");
   }
 
   return _assertThisInitialized(self);
@@ -980,7 +692,7 @@ function _superPropBase(object, property) {
   return object;
 }
 
-function _get() {
+function _get(target, property, receiver) {
   if (typeof Reflect !== "undefined" && Reflect.get) {
     _get = Reflect.get;
   } else {
@@ -991,14 +703,14 @@ function _get() {
       var desc = Object.getOwnPropertyDescriptor(base, property);
 
       if (desc.get) {
-        return desc.get.call(arguments.length < 3 ? target : receiver);
+        return desc.get.call(receiver);
       }
 
       return desc.value;
     };
   }
 
-  return _get.apply(this, arguments);
+  return _get(target, property, receiver || target);
 }
 
 function set(target, property, value, receiver) {
@@ -1128,21 +840,18 @@ function _maybeArrayLike(next, arr, i) {
 }
 
 function _iterableToArray(iter) {
-  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
+  if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
 }
 
 function _iterableToArrayLimit(arr, i) {
-  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
-
-  if (_i == null) return;
+  if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
   var _arr = [];
   var _n = true;
   var _d = false;
-
-  var _s, _e;
+  var _e = undefined;
 
   try {
-    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
+    for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
       _arr.push(_s.value);
 
       if (i && _arr.length === i) break;
@@ -1162,12 +871,10 @@ function _iterableToArrayLimit(arr, i) {
 }
 
 function _iterableToArrayLimitLoose(arr, i) {
-  var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]);
-
-  if (_i == null) return;
+  if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
   var _arr = [];
 
-  for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) {
+  for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
     _arr.push(_step.value);
 
     if (i && _arr.length === i) break;
@@ -1202,9 +909,9 @@ function _nonIterableRest() {
 }
 
 function _createForOfIteratorHelper(o, allowArrayLike) {
-  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
+  var it;
 
-  if (!it) {
+  if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
     if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
       if (it) o = it;
       var i = 0;
@@ -1237,7 +944,7 @@ function _createForOfIteratorHelper(o, allowArrayLike) {
       err;
   return {
     s: function () {
-      it = it.call(o);
+      it = o[Symbol.iterator]();
     },
     n: function () {
       var step = it.next();
@@ -1259,24 +966,28 @@ function _createForOfIteratorHelper(o, allowArrayLike) {
 }
 
 function _createForOfIteratorHelperLoose(o, allowArrayLike) {
-  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
-  if (it) return (it = it.call(o)).next.bind(it);
+  var it;
 
-  if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
-    if (it) o = it;
-    var i = 0;
-    return function () {
-      if (i >= o.length) return {
-        done: true
-      };
-      return {
-        done: false,
-        value: o[i++]
+  if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
+    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
+      if (it) o = it;
+      var i = 0;
+      return function () {
+        if (i >= o.length) return {
+          done: true
+        };
+        return {
+          done: false,
+          value: o[i++]
+        };
       };
-    };
+    }
+
+    throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
   }
 
-  throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+  it = o[Symbol.iterator]();
+  return it.next.bind(it);
 }
 
 function _skipFirstGeneratorNext(fn) {
@@ -1885,30 +1596,73 @@ function _classPrivateMethodGet(receiver, privateSet, fn) {
   return fn;
 }
 
-function _checkPrivateRedeclaration(obj, privateCollection) {
-  if (privateCollection.has(obj)) {
-    throw new TypeError("Cannot initialize the same private elements twice on an object");
-  }
+function _classPrivateMethodSet() {
+  throw new TypeError("attempted to reassign private method");
 }
 
-function _classPrivateFieldInitSpec(obj, privateMap, value) {
-  _checkPrivateRedeclaration(obj, privateMap);
+function _wrapRegExp(re, groups) {
+  _wrapRegExp = function (re, groups) {
+    return new BabelRegExp(re, undefined, groups);
+  };
 
-  privateMap.set(obj, value);
-}
+  var _RegExp = _wrapNativeSuper(RegExp);
 
-function _classPrivateMethodInitSpec(obj, privateSet) {
-  _checkPrivateRedeclaration(obj, privateSet);
+  var _super = RegExp.prototype;
 
-  privateSet.add(obj);
-}
+  var _groups = new WeakMap();
 
-function _classPrivateMethodSet() {
-  throw new TypeError("attempted to reassign private method");
-}
+  function BabelRegExp(re, flags, groups) {
+    var _this = _RegExp.call(this, re, flags);
+
+    _groups.set(_this, groups || _groups.get(re));
+
+    return _this;
+  }
+
+  _inherits(BabelRegExp, _RegExp);
+
+  BabelRegExp.prototype.exec = function (str) {
+    var result = _super.exec.call(this, str);
+
+    if (result) result.groups = buildGroups(result, this);
+    return result;
+  };
+
+  BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
+    if (typeof substitution === "string") {
+      var groups = _groups.get(this);
+
+      return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
+        return "$" + groups[name];
+      }));
+    } else if (typeof substitution === "function") {
+      var _this = this;
+
+      return _super[Symbol.replace].call(this, str, function () {
+        var args = [];
+        args.push.apply(args, arguments);
+
+        if (typeof args[args.length - 1] !== "object") {
+          args.push(buildGroups(args, _this));
+        }
+
+        return substitution.apply(this, args);
+      });
+    } else {
+      return _super[Symbol.replace].call(this, str, substitution);
+    }
+  };
+
+  function buildGroups(result, re) {
+    var g = _groups.get(re);
+
+    return Object.keys(g).reduce(function (groups, name) {
+      groups[name] = result[g[name]];
+      return groups;
+    }, Object.create(null));
+  }
 
-function _identity(x) {
-  return x;
+  return _wrapRegExp.apply(this, arguments);
 }
 
 // Numbers represent type - 
@@ -12625,8 +12379,8 @@ var glslParser = createCommonjsModule(function (module, exports) {
         if (!entry
         /*|| !entry.type*/
         ) {
-          this.ir_error(util.format("%s is undefined", name));
-        }
+            this.ir_error(util.format("%s is undefined", name));
+          }
 
         this.Type = entry.type;
         this.Entry = entry;
@@ -30188,7 +29942,7 @@ var sdfs = {
   cappedTorus: "\nfloat sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)\n{\n    p.x = abs(p.x);\n    float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);\n    return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;\n}\n"
 };
 
-const _from$1="estraverse@^4.2.0";const _id$3="estraverse@4.3.0";const _inBundle$1=false;const _integrity$1="sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==";const _location$1="/estraverse";const _phantomChildren$1={};const _requested$1={type:"range",registry:true,raw:"estraverse@^4.2.0",name:"estraverse",escapedName:"estraverse",rawSpec:"^4.2.0",saveSpec:null,fetchSpec:"^4.2.0"};const _requiredBy$1=["/escodegen"];const _resolved$1="https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz";const _shasum$1="398ad3f3c5a24948be7725e83d11a7de28cdbd1d";const _spec$1="estraverse@^4.2.0";const _where$1="/Users/peterwhidden/Documents/sp_refactor/shader-park-core/node_modules/escodegen";const bugs$1={url:"https://github.com/estools/estraverse/issues"};const bundleDependencies$1=false;const deprecated$1=false;const description$1="ECMAScript JS AST traversal functions";const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const engines$1={node:">=4.0"};const homepage$1="https://github.com/estools/estraverse";const license$1="BSD-2-Clause";const main$1="estraverse.js";const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name$1="estraverse";const repository$1={type:"git",url:"git+ssh://git@github.com/estools/estraverse.git"};const scripts$1={lint:"jshint estraverse.js",test:"npm run-script lint && npm run-script unit-test","unit-test":"mocha --compilers js:babel-register"};const version$1="4.3.0";var require$$0 = {_from:_from$1,_id:_id$3,_inBundle:_inBundle$1,_integrity:_integrity$1,_location:_location$1,_phantomChildren:_phantomChildren$1,_requested:_requested$1,_requiredBy:_requiredBy$1,_resolved:_resolved$1,_shasum:_shasum$1,_spec:_spec$1,_where:_where$1,bugs:bugs$1,bundleDependencies:bundleDependencies$1,deprecated:deprecated$1,description:description$1,devDependencies:devDependencies$1,engines:engines$1,homepage:homepage$1,license:license$1,main:main$1,maintainers:maintainers$1,name:name$1,repository:repository$1,scripts:scripts$1,version:version$1};
+const name$1="estraverse";const description$1="ECMAScript JS AST traversal functions";const homepage$1="https://github.com/estools/estraverse";const main$1="estraverse.js";const version$1="4.3.0";const engines$1={node:">=4.0"};const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository$1={type:"git",url:"http://github.com/estools/estraverse.git"};const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const license$1="BSD-2-Clause";const scripts$1={test:"npm run-script lint && npm run-script unit-test",lint:"jshint estraverse.js","unit-test":"mocha --compilers js:babel-register"};var require$$0 = {name:name$1,description:description$1,homepage:homepage$1,main:main$1,version:version$1,engines:engines$1,maintainers:maintainers$1,repository:repository$1,devDependencies:devDependencies$1,license:license$1,scripts:scripts$1};
 
 /*
   Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -34641,7 +34395,7 @@ var sourceMap = {
 	SourceNode: SourceNode
 };
 
-const _from="escodegen@^1.11.1";const _id$2="escodegen@1.14.3";const _inBundle=false;const _integrity="sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==";const _location="/escodegen";const _phantomChildren={};const _requested={type:"range",registry:true,raw:"escodegen@^1.11.1",name:"escodegen",escapedName:"escodegen",rawSpec:"^1.11.1",saveSpec:null,fetchSpec:"^1.11.1"};const _requiredBy=["/"];const _resolved="https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz";const _shasum="4e7b81fba61581dc97582ed78cab7f0e8d63f503";const _spec="escodegen@^1.11.1";const _where="/Users/peterwhidden/Documents/sp_refactor/shader-park-core";const bin={esgenerate:"bin/esgenerate.js",escodegen:"bin/escodegen.js"};const bugs={url:"https://github.com/estools/escodegen/issues"};const bundleDependencies=false;const dependencies={esprima:"^4.0.1",estraverse:"^4.2.0",esutils:"^2.0.2",optionator:"^0.8.1","source-map":"~0.6.1"};const deprecated=false;const description="ECMAScript code generator";const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const engines={node:">=4.0"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const homepage="http://github.com/estools/escodegen";const license="BSD-2-Clause";const main="escodegen.js";const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name="escodegen";const optionalDependencies={"source-map":"~0.6.1"};const repository={type:"git",url:"git+ssh://git@github.com/estools/escodegen.git"};const scripts={build:"cjsify -a path: tools/entry-point.js > escodegen.browser.js","build-min":"cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",lint:"gulp lint",release:"node tools/release.js",test:"gulp travis","unit-test":"gulp test"};const version="1.14.3";var require$$3 = {_from:_from,_id:_id$2,_inBundle:_inBundle,_integrity:_integrity,_location:_location,_phantomChildren:_phantomChildren,_requested:_requested,_requiredBy:_requiredBy,_resolved:_resolved,_shasum:_shasum,_spec:_spec,_where:_where,bin:bin,bugs:bugs,bundleDependencies:bundleDependencies,dependencies:dependencies,deprecated:deprecated,description:description,devDependencies:devDependencies,engines:engines,files:files,homepage:homepage,license:license,main:main,maintainers:maintainers,name:name,optionalDependencies:optionalDependencies,repository:repository,scripts:scripts,version:version};
+const name="escodegen";const description="ECMAScript code generator";const homepage="http://github.com/estools/escodegen";const main="escodegen.js";const bin={esgenerate:"./bin/esgenerate.js",escodegen:"./bin/escodegen.js"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const version="1.14.1";const engines={node:">=4.0"};const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository={type:"git",url:"http://github.com/estools/escodegen.git"};const dependencies={estraverse:"^4.2.0",esutils:"^2.0.2",esprima:"^4.0.1",optionator:"^0.8.1"};const optionalDependencies={"source-map":"~0.6.1"};const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const license="BSD-2-Clause";const scripts={test:"gulp travis","unit-test":"gulp test",lint:"gulp lint",release:"node tools/release.js","build-min":"./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",build:"./node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js"};var require$$3 = {name:name,description:description,homepage:homepage,main:main,bin:bin,files:files,version:version,engines:engines,maintainers:maintainers,repository:repository,dependencies:dependencies,optionalDependencies:optionalDependencies,devDependencies:devDependencies,license:license,scripts:scripts};
 
 /*
   Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -35629,7 +35383,7 @@ var escodegen = createCommonjsModule(function (module, exports) {
             result.push('[');
         }
 
-        result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
+        result.push(this.generateExpression(expr, Precedence.Sequence, E_TTT));
 
         if (computed) {
             result.push(']');
@@ -36869,19 +36623,13 @@ var escodegen = createCommonjsModule(function (module, exports) {
             multiline = false;
             if (expr.properties.length === 1) {
                 property = expr.properties[0];
-                if (
-                    property.type === Syntax.Property
-                    && property.value.type !== Syntax.Identifier
-                ) {
+                if (property.value.type !== Syntax.Identifier) {
                     multiline = true;
                 }
             } else {
                 for (i = 0, iz = expr.properties.length; i < iz; ++i) {
                     property = expr.properties[i];
-                    if (
-                        property.type === Syntax.Property
-                        && !property.shorthand
-                    ) {
+                    if (!property.shorthand) {
                         multiline = true;
                         break;
                     }
@@ -43992,7 +43740,7 @@ function buildGeoSource(geo) {
 
 function buildColorSource(col, useLighting) {
   var lgt = useLighting ? '' : '    return scope_0_material.albedo;';
-  return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
+  return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
 } // Converts binary math operators to our own version
 
 
@@ -44148,6 +43896,38 @@ function bindStaticData(staticData, spCode) {
   spCode = convertFunctionToString(spCode);
   return "const staticData = JSON.parse(`".concat(JSON.stringify(staticData), "`)\n") + spCode;
 }
+
+function errorMsg(err) {
+  console.error(err);
+  throw new Error(err);
+}
+
+function spCodeToMultiPassGLSL(passes) {
+  if (_typeof(passes) !== 'object') {
+    errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+  }
+
+  var common = passes.common,
+      bufferA = passes.bufferA,
+      bufferB = passes.bufferB,
+      bufferC = passes.bufferC,
+      bufferD = passes.bufferD,
+      finalImage = passes.finalImage;
+
+  if (!common) {
+    common = '';
+  }
+
+  if (!finalImage) {
+    errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+  }
+
+  return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
+    if (pass) {
+      return sculptToGLSL(common + '\n' + pass);
+    }
+  });
+}
 function sculptToGLSL(userProvidedSrc) {
   var PI = Math.PI;
   var TWO_PI = Math.PI * 2;
@@ -44721,9 +44501,9 @@ function sculptToGLSL(userProvidedSrc) {
   }
 
   function ensureScalar(funcName, val) {
-    var tp = _typeof(val);
-
-    if (typeof val !== 'number' && val.type !== 'float') {
+    if (typeof val === 'undefined') {
+      compileError("'" + funcName + "'" + " was given an undefined parameter");
+    } else if (typeof val !== 'number' && val.type !== 'float') {
       compileError("'" + funcName + "'" + " accepts only a scalar. Was given: '" + val.type + "'");
     }
   }
@@ -45058,15 +44838,32 @@ function sculptToGLSL(userProvidedSrc) {
   } // Color/Lighting
 
 
+  function colorRGBA(col, green, blue, alpha) {}
+
   function color(col, green, blue) {
+    var alpha = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1.0;
+
     if (green !== undefined) {
+      if (blue === undefined) {
+        compileError("color must be vec3, or vec4, or receive rgb, or rgba");
+      }
+
       ensureScalar("color", col);
       ensureScalar("color", green);
       ensureScalar("color", blue);
+      ensureScalar("color", alpha);
       appendColorSource(getCurrentMaterial() + ".albedo = vec3(" + collapseToString(col) + ", " + collapseToString(green) + ", " + collapseToString(blue) + ");\n");
-    } else {
-      if (col.type !== 'vec3') compileError("albedo must be vec3");
-      appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+      appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+    } else {
+      if (col.type === 'vec3') {
+        appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+        appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+      } else if (col.type === 'vec4') {
+        appendColorSource(getCurrentMaterial() + ".albedo = ".concat(collapseToString(col), ".rgb;\n"));
+        appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(col), ".a;\n"));
+      } else {
+        compileError("color must be vec3, or vec4");
+      }
     }
   }
 
@@ -45274,7 +45071,7 @@ var threeHeader = "\nuniform mat4 projectionMatrix;\nuniform sampler2D msdf;\n\n
 var minimalHeader = "#version 300 es\nprecision highp float;\nuniform mat4 projectionMatrix;\nin vec3 sculptureCenter;\nout vec4 pc_fragColor;\n#define cameraPosition vec3(0.0,0.0,-2.0)\n#define vUv vec2(0.0)\n#define worldPos vec4(vec2((gl_FragCoord.x/resolution.x-0.5)*(resolution.x/resolution.y),gl_FragCoord.y/resolution.y-0.5)*1.75,0.0,0.0)\n";
 var usePBRHeader = '#define USE_PBR\n';
 var useHemisphereLight = '#define HEMISPHERE_LIGHT\n';
-var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
+var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float alpha;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.alpha, b.alpha, amount),\n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
 var fragFooter = "\n// For advanced users //\nvoid main() {\n\n    vec3 rayOrigin = (cameraPosition - sculptureCenter) / max(intersection_threshold, _scale);\n    vec3 rayDirection = getRayDirection();\n    float t = intersect(rayOrigin, rayDirection, stepSize);\n    if(t < max_dist) {\n        vec3 p = (rayOrigin + rayDirection*t);\n        //vec4 sp = projectionMatrix*viewMatrix*vec4(p,1.0); //could be used to set FragDepth\n        vec3 normal = calcNormal(p);\n        // p *= _scale;\n        vec3 col = shade(p, normal);\n        pc_fragColor = vec4(col, opacity);\n        \n    } else {\n        discard;\n    }\n}\n";
 
 /**
@@ -96461,6 +96258,6 @@ function sculptToTouchDesignerShaderSource(source) {
   };
 }
 
-console.log("using shader-park version: 0.1.10"); /// Generate code for various targets
+console.log("using shader-park version: 0.1.12"); /// Generate code for various targets
 
 export { baseUniforms, bindStaticData, createSculpture, createSculptureWithGeometry, defaultFragSourceGLSL, fragFooter, glslToMinimalHTMLRenderer, glslToMinimalRenderer, glslToOfflineRenderer, glslToThreeJSMaterial, glslToThreeJSMesh, glslToThreeJSShaderSource, glslToTouchDesignerShaderSource, minimalHeader, minimalVertexSource, sculptToGLSL, sculptToMinimalHTMLRenderer, sculptToMinimalRenderer, sculptToOfflineRenderer, sculptToRawSDF4Meshing, sculptToThreeJSMaterial, sculptToThreeJSMesh, sculptToThreeJSShaderSource, sculptToTouchDesignerShaderSource, sculptureStarterCode, uniformsToGLSL, useHemisphereLight, usePBRHeader };
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 3b74175..61d9a50 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -1,409 +1,89 @@
 (function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
   typeof define === 'function' && define.amd ? define(['exports'], factory) :
-  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["shader-park-core"] = {}));
-})(this, (function (exports) { 'use strict';
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['shader-park-core'] = {}));
+}(this, (function (exports) { 'use strict';
 
-  function createMetadataMethodsForProperty(metadataMap, kind, property) {
-    return {
-      getMetadata: function (key) {
-        if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-        var metadataForKey = metadataMap[key];
-        if (void 0 !== metadataForKey) if (1 === kind) {
-          var pub = metadataForKey.public;
-          if (void 0 !== pub) return pub[property];
-        } else if (2 === kind) {
-          var priv = metadataForKey.private;
-          if (void 0 !== priv) return priv.get(property);
-        } else if (Object.hasOwnProperty.call(metadataForKey, "constructor")) return metadataForKey.constructor;
-      },
-      setMetadata: function (key, value) {
-        if ("symbol" != typeof key) throw new TypeError("Metadata keys must be symbols, received: " + key);
-        var metadataForKey = metadataMap[key];
-
-        if (void 0 === metadataForKey && (metadataForKey = metadataMap[key] = {}), 1 === kind) {
-          var pub = metadataForKey.public;
-          void 0 === pub && (pub = metadataForKey.public = {}), pub[property] = value;
-        } else if (2 === kind) {
-          var priv = metadataForKey.priv;
-          void 0 === priv && (priv = metadataForKey.private = new Map()), priv.set(property, value);
-        } else metadataForKey.constructor = value;
-      }
-    };
-  }
-
-  function convertMetadataMapToFinal(obj, metadataMap) {
-    var parentMetadataMap = obj[Symbol.metadata || Symbol.for("Symbol.metadata")],
-        metadataKeys = Object.getOwnPropertySymbols(metadataMap);
-
-    if (0 !== metadataKeys.length) {
-      for (var i = 0; i < metadataKeys.length; i++) {
-        var key = metadataKeys[i],
-            metaForKey = metadataMap[key],
-            parentMetaForKey = parentMetadataMap ? parentMetadataMap[key] : null,
-            pub = metaForKey.public,
-            parentPub = parentMetaForKey ? parentMetaForKey.public : null;
-        pub && parentPub && Object.setPrototypeOf(pub, parentPub);
-        var priv = metaForKey.private;
-
-        if (priv) {
-          var privArr = Array.from(priv.values()),
-              parentPriv = parentMetaForKey ? parentMetaForKey.private : null;
-          parentPriv && (privArr = privArr.concat(parentPriv)), metaForKey.private = privArr;
-        }
-
-        parentMetaForKey && Object.setPrototypeOf(metaForKey, parentMetaForKey);
-      }
+  function _typeof(obj) {
+    "@babel/helpers - typeof";
 
-      parentMetadataMap && Object.setPrototypeOf(metadataMap, parentMetadataMap), obj[Symbol.metadata || Symbol.for("Symbol.metadata")] = metadataMap;
+    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+      _typeof = function (obj) {
+        return typeof obj;
+      };
+    } else {
+      _typeof = function (obj) {
+        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+      };
     }
-  }
 
-  function createAddInitializerMethod(initializers) {
-    return function (initializer) {
-      assertValidInitializer(initializer), initializers.push(initializer);
-    };
+    return _typeof(obj);
   }
 
-  function memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate) {
-    var kindStr;
-
-    switch (kind) {
-      case 1:
-        kindStr = "accessor";
-        break;
-
-      case 2:
-        kindStr = "method";
-        break;
-
-      case 3:
-        kindStr = "getter";
-        break;
-
-      case 4:
-        kindStr = "setter";
-        break;
+  var REACT_ELEMENT_TYPE;
 
-      default:
-        kindStr = "field";
+  function _jsx(type, props, key, children) {
+    if (!REACT_ELEMENT_TYPE) {
+      REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol["for"] && Symbol["for"]("react.element") || 0xeac7;
     }
 
-    var metadataKind,
-        metadataName,
-        ctx = {
-      kind: kindStr,
-      name: isPrivate ? "#" + name : name,
-      isStatic: isStatic,
-      isPrivate: isPrivate
-    };
-
-    if (0 !== kind && (ctx.addInitializer = createAddInitializerMethod(initializers)), isPrivate) {
-      metadataKind = 2, metadataName = Symbol(name);
-      var access = {};
-      0 === kind ? (access.get = desc.get, access.set = desc.set) : 2 === kind ? access.get = function () {
-        return desc.value;
-      } : (1 !== kind && 3 !== kind || (access.get = function () {
-        return desc.get.call(this);
-      }), 1 !== kind && 4 !== kind || (access.set = function (v) {
-        desc.set.call(this, v);
-      })), ctx.access = access;
-    } else metadataKind = 1, metadataName = name;
-
-    return Object.assign(ctx, createMetadataMethodsForProperty(metadataMap, metadataKind, metadataName));
-  }
-
-  function assertValidInitializer(initializer) {
-    if ("function" != typeof initializer) throw new Error("initializers must be functions");
-  }
-
-  function assertValidReturnValue(kind, value) {
-    var type = typeof value;
-
-    if (1 === kind) {
-      if ("object" !== type || null === value) throw new Error("accessor decorators must return an object with get, set, or initializer properties or void 0");
-    } else if ("function" !== type) throw 0 === kind ? new Error("field decorators must return a initializer function or void 0") : new Error("method decorators must return a function or void 0");
-  }
-
-  function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers) {
-    var desc,
-        initializer,
-        value,
-        decs = decInfo[0];
-    isPrivate ? desc = 0 === kind || 1 === kind ? {
-      get: decInfo[3],
-      set: decInfo[4]
-    } : 3 === kind ? {
-      get: decInfo[3]
-    } : 4 === kind ? {
-      set: decInfo[3]
-    } : {
-      value: decInfo[3]
-    } : 0 !== kind && (desc = Object.getOwnPropertyDescriptor(base, name)), 1 === kind ? value = {
-      get: desc.get,
-      set: desc.set
-    } : 2 === kind ? value = desc.value : 3 === kind ? value = desc.get : 4 === kind && (value = desc.set);
-    var newValue,
-        get,
-        set,
-        ctx = memberDecCtx(base, name, desc, metadataMap, initializers, kind, isStatic, isPrivate);
-    if ("function" == typeof decs) void 0 !== (newValue = decs(value, ctx)) && (assertValidReturnValue(kind, newValue), 0 === kind ? initializer = newValue : 1 === kind ? (initializer = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-      get: get,
-      set: set
-    }) : value = newValue);else for (var i = decs.length - 1; i >= 0; i--) {
-      var newInit;
-      if (void 0 !== (newValue = (0, decs[i])(value, ctx))) assertValidReturnValue(kind, newValue), 0 === kind ? newInit = newValue : 1 === kind ? (newInit = newValue.initializer, get = newValue.get || value.get, set = newValue.set || value.set, value = {
-        get: get,
-        set: set
-      }) : value = newValue, void 0 !== newInit && (void 0 === initializer ? initializer = newInit : "function" == typeof initializer ? initializer = [initializer, newInit] : initializer.push(newInit));
-    }
-
-    if (0 === kind || 1 === kind) {
-      if (void 0 === initializer) initializer = function (instance, init) {
-        return init;
-      };else if ("function" != typeof initializer) {
-        var ownInitializers = initializer;
-
-        initializer = function (instance, init) {
-          for (var value = init, i = 0; i < ownInitializers.length; i++) value = ownInitializers[i].call(instance, value);
+    var defaultProps = type && type.defaultProps;
+    var childrenLength = arguments.length - 3;
 
-          return value;
-        };
-      } else {
-        var originalInitializer = initializer;
-
-        initializer = function (instance, init) {
-          return originalInitializer.call(instance, init);
-        };
-      }
-      ret.push(initializer);
+    if (!props && childrenLength !== 0) {
+      props = {
+        children: void 0
+      };
     }
 
-    0 !== kind && (1 === kind ? (desc.get = value.get, desc.set = value.set) : 2 === kind ? desc.value = value : 3 === kind ? desc.get = value : 4 === kind && (desc.set = value), isPrivate ? 1 === kind ? (ret.push(function (instance, args) {
-      return value.get.call(instance, args);
-    }), ret.push(function (instance, args) {
-      return value.set.call(instance, args);
-    })) : 2 === kind ? ret.push(value) : ret.push(function (instance, args) {
-      return value.call(instance, args);
-    }) : Object.defineProperty(base, name, desc));
-  }
-
-  function applyMemberDecs(ret, Class, protoMetadataMap, staticMetadataMap, decInfos) {
-    for (var protoInitializers = [], staticInitializers = [], existingProtoNonFields = new Map(), existingStaticNonFields = new Map(), i = 0; i < decInfos.length; i++) {
-      var decInfo = decInfos[i];
+    if (childrenLength === 1) {
+      props.children = children;
+    } else if (childrenLength > 1) {
+      var childArray = new Array(childrenLength);
 
-      if (Array.isArray(decInfo)) {
-        var base,
-            metadataMap,
-            initializers,
-            kind = decInfo[1],
-            name = decInfo[2],
-            isPrivate = decInfo.length > 3,
-            isStatic = kind >= 5;
-
-        if (isStatic ? (base = Class, metadataMap = staticMetadataMap, kind -= 5, initializers = staticInitializers) : (base = Class.prototype, metadataMap = protoMetadataMap, initializers = protoInitializers), 0 !== kind && !isPrivate) {
-          var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields,
-              existingKind = existingNonFields.get(name) || 0;
-          if (!0 === existingKind || 3 === existingKind && 4 !== kind || 4 === existingKind && 3 !== kind) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
-          !existingKind && kind > 2 ? existingNonFields.set(name, kind) : existingNonFields.set(name, !0);
-        }
-
-        applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, metadataMap, initializers);
+      for (var i = 0; i < childrenLength; i++) {
+        childArray[i] = arguments[i + 3];
       }
-    }
-
-    protoInitializers.length > 0 && pushInitializers(ret, protoInitializers), staticInitializers.length > 0 && pushInitializers(ret, staticInitializers);
-  }
-
-  function pushInitializers(ret, initializers) {
-    initializers.length > 0 ? (initializers = initializers.slice(), ret.push(function (instance) {
-      for (var i = 0; i < initializers.length; i++) initializers[i].call(instance, instance);
-
-      return instance;
-    })) : ret.push(function (instance) {
-      return instance;
-    });
-  }
-
-  function applyClassDecs(ret, targetClass, metadataMap, classDecs) {
-    for (var initializers = [], newClass = targetClass, name = targetClass.name, ctx = Object.assign({
-      kind: "class",
-      name: name,
-      addInitializer: createAddInitializerMethod(initializers)
-    }, createMetadataMethodsForProperty(metadataMap, 0, name)), i = classDecs.length - 1; i >= 0; i--) newClass = classDecs[i](newClass, ctx) || newClass;
-
-    ret.push(newClass), initializers.length > 0 ? ret.push(function () {
-      for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass, newClass);
-    }) : ret.push(function () {});
-  }
-
-  function _applyDecs(targetClass, memberDecs, classDecs) {
-    var ret = [],
-        staticMetadataMap = {};
-
-    if (memberDecs) {
-      var protoMetadataMap = {};
-      applyMemberDecs(ret, targetClass, protoMetadataMap, staticMetadataMap, memberDecs), convertMetadataMapToFinal(targetClass.prototype, protoMetadataMap);
-    }
 
-    return classDecs && applyClassDecs(ret, targetClass, staticMetadataMap, classDecs), convertMetadataMapToFinal(targetClass, staticMetadataMap), ret;
-  }
-
-  function _asyncIterator(iterable) {
-    var method,
-        async,
-        sync,
-        retry = 2;
-
-    for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) {
-      if (async && null != (method = iterable[async])) return method.call(iterable);
-      if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable));
-      async = "@@asyncIterator", sync = "@@iterator";
-    }
-
-    throw new TypeError("Object is not async iterable");
-  }
-
-  function AsyncFromSyncIterator(s) {
-    function AsyncFromSyncIteratorContinuation(r) {
-      if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
-      var done = r.done;
-      return Promise.resolve(r.value).then(function (value) {
-        return {
-          value: value,
-          done: done
-        };
-      });
+      props.children = childArray;
     }
 
-    return AsyncFromSyncIterator = function (s) {
-      this.s = s, this.n = s.next;
-    }, AsyncFromSyncIterator.prototype = {
-      s: null,
-      n: null,
-      next: function () {
-        return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
-      },
-      return: function (value) {
-        var ret = this.s.return;
-        return void 0 === ret ? Promise.resolve({
-          value: value,
-          done: !0
-        }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));
-      },
-      throw: function (value) {
-        var thr = this.s.return;
-        return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));
+    if (props && defaultProps) {
+      for (var propName in defaultProps) {
+        if (props[propName] === void 0) {
+          props[propName] = defaultProps[propName];
+        }
       }
-    }, new AsyncFromSyncIterator(s);
-  }
-
-  var REACT_ELEMENT_TYPE;
-
-  function _jsx(type, props, key, children) {
-    REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103);
-    var defaultProps = type && type.defaultProps,
-        childrenLength = arguments.length - 3;
-    if (props || 0 === childrenLength || (props = {
-      children: void 0
-    }), 1 === childrenLength) props.children = children;else if (childrenLength > 1) {
-      for (var childArray = new Array(childrenLength), i = 0; i < childrenLength; i++) childArray[i] = arguments[i + 3];
-
-      props.children = childArray;
+    } else if (!props) {
+      props = defaultProps || {};
     }
-    if (props && defaultProps) for (var propName in defaultProps) void 0 === props[propName] && (props[propName] = defaultProps[propName]);else props || (props = defaultProps || {});
+
     return {
       $$typeof: REACT_ELEMENT_TYPE,
       type: type,
-      key: void 0 === key ? null : "" + key,
+      key: key === undefined ? null : '' + key,
       ref: null,
       props: props,
       _owner: null
     };
   }
 
-  function ownKeys(object, enumerableOnly) {
-    var keys = Object.keys(object);
-
-    if (Object.getOwnPropertySymbols) {
-      var symbols = Object.getOwnPropertySymbols(object);
-      enumerableOnly && (symbols = symbols.filter(function (sym) {
-        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
-      })), keys.push.apply(keys, symbols);
-    }
-
-    return keys;
-  }
-
-  function _objectSpread2(target) {
-    for (var i = 1; i < arguments.length; i++) {
-      var source = null != arguments[i] ? arguments[i] : {};
-      i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
-        _defineProperty(target, key, source[key]);
-      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
-        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
-      });
-    }
-
-    return target;
-  }
-
-  function _typeof(obj) {
-    "@babel/helpers - typeof";
-
-    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
-      return typeof obj;
-    } : function (obj) {
-      return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
-    }, _typeof(obj);
-  }
-
-  function _wrapRegExp() {
-    _wrapRegExp = function (re, groups) {
-      return new BabelRegExp(re, void 0, groups);
-    };
-
-    var _super = RegExp.prototype,
-        _groups = new WeakMap();
-
-    function BabelRegExp(re, flags, groups) {
-      var _this = new RegExp(re, flags);
-
-      return _groups.set(_this, groups || _groups.get(re)), _setPrototypeOf(_this, BabelRegExp.prototype);
-    }
-
-    function buildGroups(result, re) {
-      var g = _groups.get(re);
-
-      return Object.keys(g).reduce(function (groups, name) {
-        return groups[name] = result[g[name]], groups;
-      }, Object.create(null));
-    }
-
-    return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (str) {
-      var result = _super.exec.call(this, str);
-
-      return result && (result.groups = buildGroups(result, this)), result;
-    }, BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
-      if ("string" == typeof substitution) {
-        var groups = _groups.get(this);
+  function _asyncIterator(iterable) {
+    var method;
 
-        return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
-          return "$" + groups[name];
-        }));
+    if (typeof Symbol !== "undefined") {
+      if (Symbol.asyncIterator) {
+        method = iterable[Symbol.asyncIterator];
+        if (method != null) return method.call(iterable);
       }
 
-      if ("function" == typeof substitution) {
-        var _this = this;
-
-        return _super[Symbol.replace].call(this, str, function () {
-          var args = arguments;
-          return "object" != typeof args[args.length - 1] && (args = [].slice.call(args)).push(buildGroups(args, _this)), substitution.apply(this, args);
-        });
+      if (Symbol.iterator) {
+        method = iterable[Symbol.iterator];
+        if (method != null) return method.call(iterable);
       }
+    }
 
-      return _super[Symbol.replace].call(this, str, substitution);
-    }, _wrapRegExp.apply(this, arguments);
+    throw new TypeError("Object is not async iterable");
   }
 
   function _AwaitValue(value) {
@@ -489,9 +169,11 @@
     }
   }
 
-  _AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () {
-    return this;
-  };
+  if (typeof Symbol === "function" && Symbol.asyncIterator) {
+    _AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
+      return this;
+    };
+  }
 
   _AsyncGenerator.prototype.next = function (arg) {
     return this._invoke("next", arg);
@@ -532,9 +214,11 @@
 
     ;
 
-    iter[typeof Symbol !== "undefined" && Symbol.iterator || "@@iterator"] = function () {
-      return this;
-    };
+    if (typeof Symbol === "function" && Symbol.iterator) {
+      iter[Symbol.iterator] = function () {
+        return this;
+      };
+    }
 
     iter.next = function (value) {
       if (waiting) {
@@ -625,9 +309,6 @@
   function _createClass(Constructor, protoProps, staticProps) {
     if (protoProps) _defineProperties(Constructor.prototype, protoProps);
     if (staticProps) _defineProperties(Constructor, staticProps);
-    Object.defineProperty(Constructor, "prototype", {
-      writable: false
-    });
     return Constructor;
   }
 
@@ -708,7 +389,7 @@
       var ownKeys = Object.keys(source);
 
       if (typeof Object.getOwnPropertySymbols === 'function') {
-        ownKeys.push.apply(ownKeys, Object.getOwnPropertySymbols(source).filter(function (sym) {
+        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
           return Object.getOwnPropertyDescriptor(source, sym).enumerable;
         }));
       }
@@ -721,6 +402,40 @@
     return target;
   }
 
+  function ownKeys(object, enumerableOnly) {
+    var keys = Object.keys(object);
+
+    if (Object.getOwnPropertySymbols) {
+      var symbols = Object.getOwnPropertySymbols(object);
+      if (enumerableOnly) symbols = symbols.filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
+      });
+      keys.push.apply(keys, symbols);
+    }
+
+    return keys;
+  }
+
+  function _objectSpread2(target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i] != null ? arguments[i] : {};
+
+      if (i % 2) {
+        ownKeys(Object(source), true).forEach(function (key) {
+          _defineProperty(target, key, source[key]);
+        });
+      } else if (Object.getOwnPropertyDescriptors) {
+        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
+      } else {
+        ownKeys(Object(source)).forEach(function (key) {
+          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
+        });
+      }
+    }
+
+    return target;
+  }
+
   function _inherits(subClass, superClass) {
     if (typeof superClass !== "function" && superClass !== null) {
       throw new TypeError("Super expression must either be null or a function");
@@ -733,9 +448,6 @@
         configurable: true
       }
     });
-    Object.defineProperty(subClass, "prototype", {
-      writable: false
-    });
     if (superClass) _setPrototypeOf(subClass, superClass);
   }
 
@@ -844,17 +556,19 @@
     };
   }
 
-  function _getRequireWildcardCache(nodeInterop) {
+  function _getRequireWildcardCache() {
     if (typeof WeakMap !== "function") return null;
-    var cacheBabelInterop = new WeakMap();
-    var cacheNodeInterop = new WeakMap();
-    return (_getRequireWildcardCache = function (nodeInterop) {
-      return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
-    })(nodeInterop);
+    var cache = new WeakMap();
+
+    _getRequireWildcardCache = function () {
+      return cache;
+    };
+
+    return cache;
   }
 
-  function _interopRequireWildcard(obj, nodeInterop) {
-    if (!nodeInterop && obj && obj.__esModule) {
+  function _interopRequireWildcard(obj) {
+    if (obj && obj.__esModule) {
       return obj;
     }
 
@@ -864,7 +578,7 @@
       };
     }
 
-    var cache = _getRequireWildcardCache(nodeInterop);
+    var cache = _getRequireWildcardCache();
 
     if (cache && cache.has(obj)) {
       return cache.get(obj);
@@ -874,7 +588,7 @@
     var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
 
     for (var key in obj) {
-      if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
         var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
 
         if (desc && (desc.get || desc.set)) {
@@ -951,8 +665,6 @@
   function _possibleConstructorReturn(self, call) {
     if (call && (typeof call === "object" || typeof call === "function")) {
       return call;
-    } else if (call !== void 0) {
-      throw new TypeError("Derived constructors may only return object or undefined");
     }
 
     return _assertThisInitialized(self);
@@ -986,7 +698,7 @@
     return object;
   }
 
-  function _get() {
+  function _get(target, property, receiver) {
     if (typeof Reflect !== "undefined" && Reflect.get) {
       _get = Reflect.get;
     } else {
@@ -997,14 +709,14 @@
         var desc = Object.getOwnPropertyDescriptor(base, property);
 
         if (desc.get) {
-          return desc.get.call(arguments.length < 3 ? target : receiver);
+          return desc.get.call(receiver);
         }
 
         return desc.value;
       };
     }
 
-    return _get.apply(this, arguments);
+    return _get(target, property, receiver || target);
   }
 
   function set(target, property, value, receiver) {
@@ -1134,21 +846,18 @@
   }
 
   function _iterableToArray(iter) {
-    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
+    if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
   }
 
   function _iterableToArrayLimit(arr, i) {
-    var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
-
-    if (_i == null) return;
+    if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
     var _arr = [];
     var _n = true;
     var _d = false;
-
-    var _s, _e;
+    var _e = undefined;
 
     try {
-      for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
+      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
         _arr.push(_s.value);
 
         if (i && _arr.length === i) break;
@@ -1168,12 +877,10 @@
   }
 
   function _iterableToArrayLimitLoose(arr, i) {
-    var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]);
-
-    if (_i == null) return;
+    if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
     var _arr = [];
 
-    for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) {
+    for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
       _arr.push(_step.value);
 
       if (i && _arr.length === i) break;
@@ -1208,9 +915,9 @@
   }
 
   function _createForOfIteratorHelper(o, allowArrayLike) {
-    var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
+    var it;
 
-    if (!it) {
+    if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
       if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
         if (it) o = it;
         var i = 0;
@@ -1243,7 +950,7 @@
         err;
     return {
       s: function () {
-        it = it.call(o);
+        it = o[Symbol.iterator]();
       },
       n: function () {
         var step = it.next();
@@ -1265,24 +972,28 @@
   }
 
   function _createForOfIteratorHelperLoose(o, allowArrayLike) {
-    var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
-    if (it) return (it = it.call(o)).next.bind(it);
+    var it;
 
-    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
-      if (it) o = it;
-      var i = 0;
-      return function () {
-        if (i >= o.length) return {
-          done: true
-        };
-        return {
-          done: false,
-          value: o[i++]
+    if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
+      if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
+        if (it) o = it;
+        var i = 0;
+        return function () {
+          if (i >= o.length) return {
+            done: true
+          };
+          return {
+            done: false,
+            value: o[i++]
+          };
         };
-      };
+      }
+
+      throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
     }
 
-    throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+    it = o[Symbol.iterator]();
+    return it.next.bind(it);
   }
 
   function _skipFirstGeneratorNext(fn) {
@@ -1891,30 +1602,73 @@
     return fn;
   }
 
-  function _checkPrivateRedeclaration(obj, privateCollection) {
-    if (privateCollection.has(obj)) {
-      throw new TypeError("Cannot initialize the same private elements twice on an object");
-    }
+  function _classPrivateMethodSet() {
+    throw new TypeError("attempted to reassign private method");
   }
 
-  function _classPrivateFieldInitSpec(obj, privateMap, value) {
-    _checkPrivateRedeclaration(obj, privateMap);
+  function _wrapRegExp(re, groups) {
+    _wrapRegExp = function (re, groups) {
+      return new BabelRegExp(re, undefined, groups);
+    };
 
-    privateMap.set(obj, value);
-  }
+    var _RegExp = _wrapNativeSuper(RegExp);
 
-  function _classPrivateMethodInitSpec(obj, privateSet) {
-    _checkPrivateRedeclaration(obj, privateSet);
+    var _super = RegExp.prototype;
 
-    privateSet.add(obj);
-  }
+    var _groups = new WeakMap();
 
-  function _classPrivateMethodSet() {
-    throw new TypeError("attempted to reassign private method");
-  }
+    function BabelRegExp(re, flags, groups) {
+      var _this = _RegExp.call(this, re, flags);
+
+      _groups.set(_this, groups || _groups.get(re));
+
+      return _this;
+    }
+
+    _inherits(BabelRegExp, _RegExp);
+
+    BabelRegExp.prototype.exec = function (str) {
+      var result = _super.exec.call(this, str);
+
+      if (result) result.groups = buildGroups(result, this);
+      return result;
+    };
+
+    BabelRegExp.prototype[Symbol.replace] = function (str, substitution) {
+      if (typeof substitution === "string") {
+        var groups = _groups.get(this);
+
+        return _super[Symbol.replace].call(this, str, substitution.replace(/\$<([^>]+)>/g, function (_, name) {
+          return "$" + groups[name];
+        }));
+      } else if (typeof substitution === "function") {
+        var _this = this;
+
+        return _super[Symbol.replace].call(this, str, function () {
+          var args = [];
+          args.push.apply(args, arguments);
+
+          if (typeof args[args.length - 1] !== "object") {
+            args.push(buildGroups(args, _this));
+          }
+
+          return substitution.apply(this, args);
+        });
+      } else {
+        return _super[Symbol.replace].call(this, str, substitution);
+      }
+    };
+
+    function buildGroups(result, re) {
+      var g = _groups.get(re);
+
+      return Object.keys(g).reduce(function (groups, name) {
+        groups[name] = result[g[name]];
+        return groups;
+      }, Object.create(null));
+    }
 
-  function _identity(x) {
-    return x;
+    return _wrapRegExp.apply(this, arguments);
   }
 
   // Numbers represent type - 
@@ -12631,8 +12385,8 @@
           if (!entry
           /*|| !entry.type*/
           ) {
-            this.ir_error(util.format("%s is undefined", name));
-          }
+              this.ir_error(util.format("%s is undefined", name));
+            }
 
           this.Type = entry.type;
           this.Entry = entry;
@@ -30194,7 +29948,7 @@
     cappedTorus: "\nfloat sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)\n{\n    p.x = abs(p.x);\n    float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);\n    return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;\n}\n"
   };
 
-  const _from$1="estraverse@^4.2.0";const _id$3="estraverse@4.3.0";const _inBundle$1=false;const _integrity$1="sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==";const _location$1="/estraverse";const _phantomChildren$1={};const _requested$1={type:"range",registry:true,raw:"estraverse@^4.2.0",name:"estraverse",escapedName:"estraverse",rawSpec:"^4.2.0",saveSpec:null,fetchSpec:"^4.2.0"};const _requiredBy$1=["/escodegen"];const _resolved$1="https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz";const _shasum$1="398ad3f3c5a24948be7725e83d11a7de28cdbd1d";const _spec$1="estraverse@^4.2.0";const _where$1="/Users/peterwhidden/Documents/sp_refactor/shader-park-core/node_modules/escodegen";const bugs$1={url:"https://github.com/estools/estraverse/issues"};const bundleDependencies$1=false;const deprecated$1=false;const description$1="ECMAScript JS AST traversal functions";const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const engines$1={node:">=4.0"};const homepage$1="https://github.com/estools/estraverse";const license$1="BSD-2-Clause";const main$1="estraverse.js";const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name$1="estraverse";const repository$1={type:"git",url:"git+ssh://git@github.com/estools/estraverse.git"};const scripts$1={lint:"jshint estraverse.js",test:"npm run-script lint && npm run-script unit-test","unit-test":"mocha --compilers js:babel-register"};const version$1="4.3.0";var require$$0 = {_from:_from$1,_id:_id$3,_inBundle:_inBundle$1,_integrity:_integrity$1,_location:_location$1,_phantomChildren:_phantomChildren$1,_requested:_requested$1,_requiredBy:_requiredBy$1,_resolved:_resolved$1,_shasum:_shasum$1,_spec:_spec$1,_where:_where$1,bugs:bugs$1,bundleDependencies:bundleDependencies$1,deprecated:deprecated$1,description:description$1,devDependencies:devDependencies$1,engines:engines$1,homepage:homepage$1,license:license$1,main:main$1,maintainers:maintainers$1,name:name$1,repository:repository$1,scripts:scripts$1,version:version$1};
+  const name$1="estraverse";const description$1="ECMAScript JS AST traversal functions";const homepage$1="https://github.com/estools/estraverse";const main$1="estraverse.js";const version$1="4.3.0";const engines$1={node:">=4.0"};const maintainers$1=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository$1={type:"git",url:"http://github.com/estools/estraverse.git"};const devDependencies$1={"babel-preset-env":"^1.6.1","babel-register":"^6.3.13",chai:"^2.1.1",espree:"^1.11.0",gulp:"^3.8.10","gulp-bump":"^0.2.2","gulp-filter":"^2.0.0","gulp-git":"^1.0.1","gulp-tag-version":"^1.3.0",jshint:"^2.5.6",mocha:"^2.1.0"};const license$1="BSD-2-Clause";const scripts$1={test:"npm run-script lint && npm run-script unit-test",lint:"jshint estraverse.js","unit-test":"mocha --compilers js:babel-register"};var require$$0 = {name:name$1,description:description$1,homepage:homepage$1,main:main$1,version:version$1,engines:engines$1,maintainers:maintainers$1,repository:repository$1,devDependencies:devDependencies$1,license:license$1,scripts:scripts$1};
 
   /*
     Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -34647,7 +34401,7 @@
   	SourceNode: SourceNode
   };
 
-  const _from="escodegen@^1.11.1";const _id$2="escodegen@1.14.3";const _inBundle=false;const _integrity="sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==";const _location="/escodegen";const _phantomChildren={};const _requested={type:"range",registry:true,raw:"escodegen@^1.11.1",name:"escodegen",escapedName:"escodegen",rawSpec:"^1.11.1",saveSpec:null,fetchSpec:"^1.11.1"};const _requiredBy=["/"];const _resolved="https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz";const _shasum="4e7b81fba61581dc97582ed78cab7f0e8d63f503";const _spec="escodegen@^1.11.1";const _where="/Users/peterwhidden/Documents/sp_refactor/shader-park-core";const bin={esgenerate:"bin/esgenerate.js",escodegen:"bin/escodegen.js"};const bugs={url:"https://github.com/estools/escodegen/issues"};const bundleDependencies=false;const dependencies={esprima:"^4.0.1",estraverse:"^4.2.0",esutils:"^2.0.2",optionator:"^0.8.1","source-map":"~0.6.1"};const deprecated=false;const description="ECMAScript code generator";const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const engines={node:">=4.0"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const homepage="http://github.com/estools/escodegen";const license="BSD-2-Clause";const main="escodegen.js";const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",url:"http://github.com/Constellation"}];const name="escodegen";const optionalDependencies={"source-map":"~0.6.1"};const repository={type:"git",url:"git+ssh://git@github.com/estools/escodegen.git"};const scripts={build:"cjsify -a path: tools/entry-point.js > escodegen.browser.js","build-min":"cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",lint:"gulp lint",release:"node tools/release.js",test:"gulp travis","unit-test":"gulp test"};const version="1.14.3";var require$$3 = {_from:_from,_id:_id$2,_inBundle:_inBundle,_integrity:_integrity,_location:_location,_phantomChildren:_phantomChildren,_requested:_requested,_requiredBy:_requiredBy,_resolved:_resolved,_shasum:_shasum,_spec:_spec,_where:_where,bin:bin,bugs:bugs,bundleDependencies:bundleDependencies,dependencies:dependencies,deprecated:deprecated,description:description,devDependencies:devDependencies,engines:engines,files:files,homepage:homepage,license:license,main:main,maintainers:maintainers,name:name,optionalDependencies:optionalDependencies,repository:repository,scripts:scripts,version:version};
+  const name="escodegen";const description="ECMAScript code generator";const homepage="http://github.com/estools/escodegen";const main="escodegen.js";const bin={esgenerate:"./bin/esgenerate.js",escodegen:"./bin/escodegen.js"};const files=["LICENSE.BSD","README.md","bin","escodegen.js","package.json"];const version="1.14.1";const engines={node:">=4.0"};const maintainers=[{name:"Yusuke Suzuki",email:"utatane.tea@gmail.com",web:"http://github.com/Constellation"}];const repository={type:"git",url:"http://github.com/estools/escodegen.git"};const dependencies={estraverse:"^4.2.0",esutils:"^2.0.2",esprima:"^4.0.1",optionator:"^0.8.1"};const optionalDependencies={"source-map":"~0.6.1"};const devDependencies={acorn:"^7.1.0",bluebird:"^3.4.7","bower-registry-client":"^1.0.0",chai:"^3.5.0","commonjs-everywhere":"^0.9.7",gulp:"^3.8.10","gulp-eslint":"^3.0.1","gulp-mocha":"^3.0.1",semver:"^5.1.0"};const license="BSD-2-Clause";const scripts={test:"gulp travis","unit-test":"gulp test",lint:"gulp lint",release:"node tools/release.js","build-min":"./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js",build:"./node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js"};var require$$3 = {name:name,description:description,homepage:homepage,main:main,bin:bin,files:files,version:version,engines:engines,maintainers:maintainers,repository:repository,dependencies:dependencies,optionalDependencies:optionalDependencies,devDependencies:devDependencies,license:license,scripts:scripts};
 
   /*
     Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com>
@@ -35635,7 +35389,7 @@
               result.push('[');
           }
 
-          result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
+          result.push(this.generateExpression(expr, Precedence.Sequence, E_TTT));
 
           if (computed) {
               result.push(']');
@@ -36875,19 +36629,13 @@
               multiline = false;
               if (expr.properties.length === 1) {
                   property = expr.properties[0];
-                  if (
-                      property.type === Syntax.Property
-                      && property.value.type !== Syntax.Identifier
-                  ) {
+                  if (property.value.type !== Syntax.Identifier) {
                       multiline = true;
                   }
               } else {
                   for (i = 0, iz = expr.properties.length; i < iz; ++i) {
                       property = expr.properties[i];
-                      if (
-                          property.type === Syntax.Property
-                          && !property.shorthand
-                      ) {
+                      if (!property.shorthand) {
                           multiline = true;
                           break;
                       }
@@ -43998,7 +43746,7 @@
 
   function buildColorSource(col, useLighting) {
     var lgt = useLighting ? '' : '    return scope_0_material.albedo;';
-    return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
+    return "\nvec3 shade(vec3 p, vec3 normal) {\n    float d = 100.0;\n    vec3 op = p;\n\tvec3 lightDirection = vec3(0.0, 1.0, 0.0);\n\tvec3 backgroundColor = vec3(1.0, 1.0, 1.0);\n\tvec3 mouseIntersect = vec3(0.0,1.0,0.0);\n\t#ifdef USE_PBR\n\tMaterial material = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\tMaterial selectedMaterial = Material(vec3(1.0),1.0,0.5,0.7,1.0);\n\t#else\n\tfloat light = 1.0;\n\tfloat occ = 1.0;\n    vec3 color = vec3(1.0,1.0,1.0);\n\tvec3 selectedColor = vec3(1.0,1.0,1.0);\n\t#endif\n".concat(col, "\n").concat(lgt, "\n\t#ifdef USE_PBR\n\treturn pbrLighting(\n\t\tworldPos.xyz,\n\t\tnormal,\n\t\tlightDirection,\n\t\tscope_0_material,\n\t\tbackgroundColor\n\t\t);\n\t#else\n\treturn scope_0_material.albedo*simpleLighting(p, normal, lightDirection, );*occ;\n\t#endif\n}");
   } // Converts binary math operators to our own version
 
 
@@ -44154,6 +43902,38 @@
     spCode = convertFunctionToString(spCode);
     return "const staticData = JSON.parse(`".concat(JSON.stringify(staticData), "`)\n") + spCode;
   }
+
+  function errorMsg(err) {
+    console.error(err);
+    throw new Error(err);
+  }
+
+  function spCodeToMultiPassGLSL(passes) {
+    if (_typeof(passes) !== 'object') {
+      errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+    }
+
+    var common = passes.common,
+        bufferA = passes.bufferA,
+        bufferB = passes.bufferB,
+        bufferC = passes.bufferC,
+        bufferD = passes.bufferD,
+        finalImage = passes.finalImage;
+
+    if (!common) {
+      common = '';
+    }
+
+    if (!finalImage) {
+      errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
+    }
+
+    return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
+      if (pass) {
+        return sculptToGLSL(common + '\n' + pass);
+      }
+    });
+  }
   function sculptToGLSL(userProvidedSrc) {
     var PI = Math.PI;
     var TWO_PI = Math.PI * 2;
@@ -44727,9 +44507,9 @@
     }
 
     function ensureScalar(funcName, val) {
-      var tp = _typeof(val);
-
-      if (typeof val !== 'number' && val.type !== 'float') {
+      if (typeof val === 'undefined') {
+        compileError("'" + funcName + "'" + " was given an undefined parameter");
+      } else if (typeof val !== 'number' && val.type !== 'float') {
         compileError("'" + funcName + "'" + " accepts only a scalar. Was given: '" + val.type + "'");
       }
     }
@@ -45064,15 +44844,32 @@
     } // Color/Lighting
 
 
+    function colorRGBA(col, green, blue, alpha) {}
+
     function color(col, green, blue) {
+      var alpha = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1.0;
+
       if (green !== undefined) {
+        if (blue === undefined) {
+          compileError("color must be vec3, or vec4, or receive rgb, or rgba");
+        }
+
         ensureScalar("color", col);
         ensureScalar("color", green);
         ensureScalar("color", blue);
+        ensureScalar("color", alpha);
         appendColorSource(getCurrentMaterial() + ".albedo = vec3(" + collapseToString(col) + ", " + collapseToString(green) + ", " + collapseToString(blue) + ");\n");
-      } else {
-        if (col.type !== 'vec3') compileError("albedo must be vec3");
-        appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+        appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+      } else {
+        if (col.type === 'vec3') {
+          appendColorSource(getCurrentMaterial() + ".albedo = " + collapseToString(col) + ";\n");
+          appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(alpha), ";\n"));
+        } else if (col.type === 'vec4') {
+          appendColorSource(getCurrentMaterial() + ".albedo = ".concat(collapseToString(col), ".rgb;\n"));
+          appendColorSource(getCurrentMaterial() + ".alpha = ".concat(collapseToString(col), ".a;\n"));
+        } else {
+          compileError("color must be vec3, or vec4");
+        }
       }
     }
 
@@ -45280,7 +45077,7 @@
   var minimalHeader = "#version 300 es\nprecision highp float;\nuniform mat4 projectionMatrix;\nin vec3 sculptureCenter;\nout vec4 pc_fragColor;\n#define cameraPosition vec3(0.0,0.0,-2.0)\n#define vUv vec2(0.0)\n#define worldPos vec4(vec2((gl_FragCoord.x/resolution.x-0.5)*(resolution.x/resolution.y),gl_FragCoord.y/resolution.y-0.5)*1.75,0.0,0.0)\n";
   var usePBRHeader = '#define USE_PBR\n';
   var useHemisphereLight = '#define HEMISPHERE_LIGHT\n';
-  var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
+  var sculptureStarterCode = "\nfloat surfaceDistance(vec3 p);\n\nconst float PI = 3.14159265;\nconst float TAU = PI*2.0;\nconst float TWO_PI = TAU;\n\nconst float max_dist = 100.0;\nconst float intersection_threshold = 0.00001;\n\nstruct Material {\n    vec3 albedo;\n    float alpha;\n    float metallic;\n    float roughness;\n    float ao;\n};\n\nMaterial blendMaterial(Material a, Material b, float amount) {\n    return Material(\n        mix(a.albedo, b.albedo, amount), \n        mix(a.alpha, b.alpha, amount),\n        mix(a.metallic, b.metallic, amount), \n        mix(a.roughness, b.roughness, amount), \n        mix(a.ao, b.ao, amount)\n    );\n}\n\n// Trig functions normalized to the range 0.0-1.0\nfloat nsin(float x) {\n    return sin(x)*0.5+0.5;\n}\n\nfloat ncos(float x) {\n    return cos(x)*0.5+0.5;\n}\n\nfloat softSquare(float x, int pw) {\n    return 1.0/(pow(tan(x),float(pw+1)*2.0)+1.0);\n}\n\n// Simple oscillators \n\nfloat osc(float freq, float amp, float base, float phase) {\n    return base+amp*sin(TWO_PI*(freq*time+phase));\n}\n\nfloat osc(float freq, float amp, float base) {\n    return osc(freq, amp, base, 0.0);\n}\n\nfloat osc(float freq, float amp) {\n    return osc(freq, amp, 1.0);\n}\n\nfloat osc(float freq) {\n    return osc(freq, 0.5);\n}\n\nfloat osc() {\n    return osc(1.0);\n}\n\n// Color Conversion\n// https://www.shadertoy.com/view/lsS3Wc\nvec3 hsv2rgb( vec3 c )\n{\n    vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );\n    return c.z * mix( vec3(1.0), rgb, c.y);\n}\n\nvec3 rgb2hsv( vec3 c)\n{\n    const float eps = 0.0000001;\n    vec4 k = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);\n    vec4 p = mix(vec4(c.zy, k.wz), vec4(c.yz, k.xy), (c.z<c.y) ? 1.0 : 0.0);\n    vec4 q = mix(vec4(p.xyw, c.x), vec4(c.x, p.yzx), (p.x<c.x) ? 1.0 : 0.0);\n    float d = q.x - min(q.w, q.y);\n    return vec3(abs(q.z + (q.w - q.y) / (6.0*d+eps)), d / (q.x+eps), q.x);\n}\n\n\n// Primitives\n\nfloat line(vec3 p, vec3 a, vec3 b) {\n\tvec3 pa = p-a;\n  \tvec3 ba = b-a;\n\tfloat t = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\n  \treturn length(pa - ba*t);\n}\n\n//line with radius\nfloat line( vec3 p, vec3 a, vec3 b, float radius ){\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - radius;\n}\n\nfloat sphere( vec3 p, float size ){\n  return length(p)-size;\n}\n\nfloat uBox( vec3 p, vec3 b ){\n  return length(max(abs(p)-b,0.0));\n}\n\nfloat uRoundBox( vec3 p, vec3 b, float r ){\n  return length(max(abs(p)-b,0.0))-r;\n}\n\nfloat box( vec3 p, vec3 box ){\n  vec3 d = abs(p) - box;\n  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat box( vec3 p, float bx, float by, float bz) {\n    vec3 box = vec3(bx,by,bz);\n    vec3 d = abs(p) - box;\n    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));\n}\n\nfloat roundedBox( vec3 p, vec3 box , float r){\n  return length(max(abs(p)-box,0.0))-r;\n}\n\nfloat torus( vec3 p, vec2 t ){\n  vec2 q = vec2(length(p.xz)-t.x,p.y);\n  return length(q)-t.y;\n}\n\nfloat torus( vec3 p, float tx, float ty ){\n    vec2 q = vec2(length(p.xz)-tx,p.y);\n    return length(q)-ty;\n}\n\nfloat infCylinder( vec3 p, vec3 c )\n{\n  return length(p.xz-c.xy)-c.z;\n}\n\nfloat cylinder( vec3 p, vec2 h )\n{\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\nfloat cylinder( vec3 p, float hx, float hy)\n{\n    return cylinder(p, vec2(hx,hy));\n}\n\nfloat cone( vec3 p, vec2 c )\n{\n    // c must be normalized\n    float q = length(p.xy);\n    return dot(c,vec2(q,p.z));\n}\n\nfloat plane( vec3 p, vec4 n )\n{\n  // n must be normalized\n  return dot(p,n.xyz) + n.w;\n}\n\nfloat plane( vec3 p, float nx, float ny, float nz, float nw)\n{\n  // n must be normalized\n  return dot(p,normalize(vec3(nx,ny,nz))) + nw;\n}\n\nfloat hexPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max((q.x*0.866025+q.y*0.5),q.y)-h.x);\n}\n\nfloat triPrism( vec3 p, vec2 h )\n{\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat capsule( vec3 p, vec3 a, vec3 b, float r )\n{\n    vec3 pa = p - a, ba = b - a;\n    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );\n    return length( pa - ba*h ) - r;\n}\n\nfloat triangularPrism( vec3 p, vec2 h ) {\n    vec3 q = abs(p);\n    return max(q.z-h.y,max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5);\n}\n\nfloat cappedCone( vec3 p, vec3 c )\n{\n    vec2 q = vec2( length(p.xz), p.y );\n    vec2 v = vec2( c.z*c.y/c.x, -c.z );\n    vec2 w = v - q;\n    vec2 vv = vec2( dot(v,v), v.x*v.x );\n    vec2 qv = vec2( dot(v,w), v.x*w.x );\n    vec2 d = max(qv,0.0)*qv/vv;\n    return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y));\n}\n\nfloat roundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)\n{\n    // sampling independent computations (only depend on shape)\n    vec3  ba = b - a;\n    float l2 = dot(ba,ba);\n    float rr = r1 - r2;\n    float a2 = l2 - rr*rr;\n    float il2 = 1.0/l2;\n    \n    // sampling dependant computations\n    vec3 pa = p - a;\n    float y = dot(pa,ba);\n    float z = y - l2;\n    vec3 rv = pa*l2 - ba*y;\n    float x2 = dot(rv,rv);\n    float y2 = y*y*l2;\n    float z2 = z*z*l2;\n\n    // single square root!\n    float k = sign(rr)*rr*rr*x2;\n    if( sign(z)*a2*z2 > k ) return  sqrt(x2 + z2)        *il2 - r2;\n    if( sign(y)*a2*y2 < k ) return  sqrt(x2 + y2)        *il2 - r1;\n                            return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n\nfloat ellipsoid( vec3 p, vec3 r )\n{\n    return (length( p/r ) - 1.0) * min(min(r.x,r.y),r.z);\n}\n\nvec3 toSpherical(vec3 p) {\n    float phi = atan(p.x,p.z);\n    float r = length(p);\n    float theta = acos(-p.y/r);\n    return vec3(r,theta,phi);\n}\n\nvec3 fromSpherical(vec3 p) {\n    return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));\n}\n\nfloat dot2( vec3 v ) { return dot(v,v); }\n\nfloat uTriangle( vec3 p, vec3 a, vec3 b, vec3 c )\n{\n    vec3 ba = b - a; vec3 pa = p - a;\n    vec3 cb = c - b; vec3 pb = p - b;\n    vec3 ac = a - c; vec3 pc = p - c;\n    vec3 nor = cross( ba, ac );\n    return sqrt(\n    (sign(dot(cross(ba,nor),pa)) +\n     sign(dot(cross(cb,nor),pb)) +\n     sign(dot(cross(ac,nor),pc))<2.0)\n     ?\n     min( min(\n     dot2(ba*clamp(dot(ba,pa)/dot2(ba),0.0,1.0)-pa),\n     dot2(cb*clamp(dot(cb,pb)/dot2(cb),0.0,1.0)-pb) ),\n     dot2(ac*clamp(dot(ac,pc)/dot2(ac),0.0,1.0)-pc) )\n     :\n     dot(nor,pa)*dot(nor,pa)/dot2(nor) );\n}\n\nfloat add( float d1, float d2 )\n{\n    return min(d1,d2);\n}\n\nfloat add(float d1, float d2, float d3) {\n   return min(d1, min(d2,d3));\n}\n\nfloat add(float d1, float d2, float d3, float d4) {\n    return min(min(d1,d2),min(d3,d4));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5) {\n    return min(min(min(d1,d2), min(d3,d4)),d5);\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6) {\n    return min(min(min(d1,d2),min(d3,d4)),min(d5,d6));\n}\n\nfloat add(float d1, float d2, float d3, float d4, float d5, float d6, float d7) {\n    return min(min(min(d1,d2),min(d3,d4)),min(min(d5,d6),d7));\n}\n\nfloat subtract( float d1, float d2 )\n{\n    return max(-d1,d2);\n}\n\nfloat intersect( float d1, float d2 )\n{\n    return max(d1,d2);\n}\n\nfloat shell(float d, float thickness) {\n    return abs(d)-thickness;\n}\n\nvec3 repeat3D(vec3 p, vec3 c )\n{\n    return mod(p,c)-0.5*c;\n}\n\nfloat repeat1D(float p, float size)\n{\n\tfloat halfSize = size * 0.5;\n\tfloat c = floor((p + halfSize) / size);\n  \tp = mod(p + halfSize, size)-halfSize;\n  \treturn c;\n}\n\nmat2 rot2(float a){\n    float c = cos(a); float s = sin(a);\n\treturn mat2(c, s, -s, c);\n}\n\n// polynomial smooth min (k = 0.1) (from IQ)\nfloat smoothAdd( float a, float b, float k )\n{\n    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );\n    return mix( b, a, h ) - k*h*(1.0-h);\n}\n\nfloat smoothSubtract(float a,float b, float k)\n{\n    return -smoothAdd(-a,-b,k);\n}\n\nvec2 _hash( vec2 p ) // replace this by something better\n{\n\tp = vec2( dot(p,vec2(127.1,311.7)),\n\t\t\t  dot(p,vec2(269.5,183.3)) );\n\treturn -1.0 + 2.0*fract(sin(p)*43758.5453123);\n}\n\nfloat noise( vec2 p )\n{\n    const float K1 = 0.366025404; // (sqrt(3)-1)/2;\n    const float K2 = 0.211324865; // (3-sqrt(3))/6;\n\tvec2 i = floor( p + (p.x+p.y)*K1 );\n\t\n    vec2 a = p - i + (i.x+i.y)*K2;\n    vec2 o = step(a.yx,a.xy);    \n    vec2 b = a - o + K2;\n\tvec2 c = a - 1.0 + 2.0*K2;\n    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );\n\tvec3 n = h*h*h*h*vec3( dot(a,_hash(i+0.0)), dot(b,_hash(i+o)), dot(c,_hash(i+1.0)));\n    return dot( n, vec3(70.0) );\n}\n\n// from https://www.shadertoy.com/view/4djSRW\nfloat _hash13(vec3 p3)\n{\n    p3  = fract(p3 * .1031);\n    p3 += dot(p3, p3.zyx + 31.32);\n    return fract((p3.x + p3.y) * p3.z);\n}\n\nvec3 _hash33(vec3 p3)\n{\n    p3 = fract(p3 * vec3(.1031,.11369,.13787));\n    p3 += dot(p3, p3.yxz+19.19);\n    return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));\n}\n\n// simplex noise from https://www.shadertoy.com/view/4sc3z2\nfloat noise(vec3 p)\n{\n    const float K1 = 0.333333333;\n    const float K2 = 0.166666667;\n    \n    vec3 i = floor(p + (p.x + p.y + p.z) * K1);\n    vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);\n    \n    // thx nikita: https://www.shadertoy.com/view/XsX3zB\n    vec3 e = step(vec3(0.0), d0 - d0.yzx);\n\tvec3 i1 = e * (1.0 - e.zxy);\n\tvec3 i2 = 1.0 - e.zxy * (1.0 - e);\n    \n    vec3 d1 = d0 - (i1 - 1.0 * K2);\n    vec3 d2 = d0 - (i2 - 2.0 * K2);\n    vec3 d3 = d0 - (1.0 - 3.0 * K2);\n    \n    vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);\n    vec4 n = h * h * h * h * vec4(dot(d0, _hash33(i)), dot(d1, _hash33(i + i1)), dot(d2, _hash33(i + i2)), dot(d3, _hash33(i + 1.0)));\n    \n    return dot(vec4(31.316), n);\n}\n\nfloat fractalNoise(vec3 p, float falloff, int iterations) {\n    float v = 0.0;\n    float amp = 1.0;\n    float invFalloff = 1.0/falloff;\n    for (int i=0; i<10; i++) {\n        v += noise(p)*amp;\n\tif (i>=iterations) break;\n        amp *= invFalloff;\n        p *= falloff;\n    }\n    return v;\n} \n\nfloat fractalNoise(vec3 p) {\n    return fractalNoise(p, 2.0, 5);\n}\n\n// Adapted from IQ's usage at https://www.shadertoy.com/view/lllXz4\n// Spherical Fibonnacci points, Benjamin Keinert, Matthias Innmann,\n// Michael Sanger and Marc Stamminger\n\nconst float PHI = 1.61803398875;\n\nvec4 sphericalDistribution( vec3 p, float n )\n{\n    p = normalize(p);\n    float m = 1.0 - 1.0/n;\n\n    float phi = min(atan(p.y, p.x), PI), cosTheta = p.z;\n\n    float k = max(2.0, floor( log(n * PI * sqrt(5.0) * (1.0 - cosTheta*cosTheta))/ log(PHI+1.0)));\n    float Fk = pow(PHI, k)/sqrt(5.0);\n    vec2 F = vec2( round(Fk), round(Fk * PHI) ); // k, k+1\n\n    vec2 ka = 2.0*F/n;\n    vec2 kb = 2.0*PI*( fract((F+1.0)*PHI) - (PHI-1.0) );\n\n    mat2 iB = mat2( ka.y, -ka.x,\n    kb.y, -kb.x ) / (ka.y*kb.x - ka.x*kb.y);\n\n    vec2 c = floor( iB * vec2(phi, cosTheta - m));\n    float d = 8.0;\n    float j = 0.0;\n    vec3 bestQ = vec3(0.0,0.0,8.0);\n    for( int s=0; s<4; s++ )\n    {\n        vec2 uv = vec2( float(s-2*(s/2)), float(s/2) );\n\n        float i = dot(F, uv + c); // all quantities are ingeters (can take a round() for extra safety)\n\n        float phi = 2.0*PI*fract(i*PHI);\n        float cosTheta = m - 2.0*i/n;\n        float sinTheta = sqrt(1.0 - cosTheta*cosTheta);\n\n        vec3 q = vec3( cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta );\n        float squaredDistance = dot(q-p, q-p);\n        if (squaredDistance < d)\n        {\n            d = squaredDistance;\n            j = i;\n            bestQ = q;\n        }\n    }\n    return vec4(bestQ,sqrt(d));\n}\n\n// Compute intersection of ray and SDF. You probably won't need to modify this.\nfloat intersect(vec3 ro, vec3 rd, float stepFraction) {\n    float t = 0.0;\n\tfor(int i = 0; i < MAX_ITERATIONS; ++i) {\n\t\tfloat h = surfaceDistance((ro+rd*t));\n\t\tif(h < intersection_threshold || t > max_dist) break;\n\t\tt += h*STEP_SIZE_CONSTANT;\n    }\n\treturn t;\n}\n\nvec3 getRayDirection() {\n\treturn normalize(worldPos.xyz-cameraPosition);\n}\n\nvec3 mouseIntersection() {\n    vec3 rayDirection = getRayDirection();\n    return mouse+rayDirection*intersect(mouse, rayDirection, 0.8);\n}\n\n// Calculate the normal of a SDF\nvec3 calcNormal( vec3 pos )\n{\n    vec2 e = vec2(1.0,-1.0)*0.0005;\n    return normalize( e.xyy*surfaceDistance( pos + e.xyy ) + \n\t\t      e.yyx*surfaceDistance( pos + e.yyx ) + \n\t\t      e.yxy*surfaceDistance( pos + e.yxy ) + \n\t\t      e.xxx*surfaceDistance( pos + e.xxx ) );\n}\n\n// from https://learnopengl.com/PBR/Lighting\nvec3 fresnelSchlick(float cosTheta, vec3 F0)\n{\n    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}  \n\nfloat DistributionGGX(vec3 N, vec3 H, float roughness)\n{\n    float a      = roughness*roughness;\n    float a2     = a*a;\n    float NdotH  = max(dot(N, H), 0.0);\n    float NdotH2 = NdotH*NdotH;\n\t\n    float num   = a2;\n    float denom = (NdotH2 * (a2 - 1.0) + 1.0);\n    denom = PI * denom * denom;\n\t\n    return num / denom;\n}\n\nfloat GeometrySchlickGGX(float NdotV, float roughness)\n{\n    float r = (roughness + 1.0);\n    float k = (r*r) / 8.0;\n\n    float num   = NdotV;\n    float denom = NdotV * (1.0 - k) + k;\n\t\n    return num / denom;\n}\n\nfloat GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)\n{\n    float NdotV = max(dot(N, V), 0.0);\n    float NdotL = max(dot(N, L), 0.0);\n    float ggx2  = GeometrySchlickGGX(NdotV, roughness);\n    float ggx1  = GeometrySchlickGGX(NdotL, roughness);\n\t\n    return ggx1 * ggx2;\n}\n\n// adapted from https://learnopengl.com/PBR/Lighting\nvec3 pbrLighting(vec3 WordPos, vec3 N, vec3 lightdir, Material mat, vec3 backgroundColor) {\n\n    vec3 V = -getRayDirection();\n    vec3 F0 = vec3(0.04); \n    F0 = mix(F0, mat.albedo, mat.metallic);\n\t\n    // reflectance equation\n    vec3 Lo = vec3(0.0);\n\n    // calculate per-light radiance\n    vec3 L = normalize(lightdir);\n    vec3 H = normalize(V + L);        \n    \n    // cook-torrance brdf\n    float NDF = DistributionGGX(N, H, mat.roughness);        \n    float G   = GeometrySmith(N, V, L, mat.roughness);      \n    vec3 F    = fresnelSchlick(max(dot(H, V), 0.0), F0);    \n\n    vec3 kS = F;\n    vec3 kD = vec3(1.0) - kS;\n    kD *= 1.0 - mat.metallic;\t  \n    \n    vec3 numerator    = NDF * G * F;\n    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n    vec3 specular     = numerator / max(denominator, 0.001);  \n    \n    // add to outgoing radiance Lo\n    float NdotL = max(dot(N, L), 0.0);                \n    Lo += (kD * mat.albedo / PI + specular) * NdotL;  \n  \n    float hemi = 1.0;\n    #ifdef HEMISPHERE_LIGHT\n    // ground is black, taken into account by ambient light\n    hemi = NdotL*1.25;\n    #endif\n\n    vec3 ambient = (vec3(1.2+hemi) * mat.albedo) * mat.ao;\n    vec3 color = ambient + Lo*1.7;\n    \n    /// this section adds edge glow as if there were a white env map ///\n    /// there should probably be a way to disable it //\n    float lt = 1.0-max(dot(N,V),0.0);\n    lt = pow(lt,6.0);\n    color += 16.0*lt*(0.2+mat.albedo)*mat.metallic*backgroundColor*(1.3-mat.roughness);\n    ///\n    \n    color = color / (color + vec3(1.0));\n    color = pow(color, vec3(1.0/2.2));\n   \n    return color;\n}\n\nfloat simpleLighting(vec3 p, vec3 normal, vec3 lightdir) {\n    // Simple phong-like shading\n    float value = clamp(dot(normal, normalize(lightdir)),0.0, 1.0);\n    return value * 0.3 + 0.7;\n}\n\nfloat specularLighting(vec3 p, vec3 normal, vec3 lightDirection, float shine) {\n    float lamb = clamp(dot(normal,normalize(lightDirection)),0.0,1.0);\n    float spec = pow(lamb, exp(10.0*shine));\n    lamb = 0.4*lamb + 0.4 + 0.2*spec;\n    return lamb;\n}\n\nfloat shadow(vec3 p, vec3 lightDirection, float amount) {\n    float t = intersect(p+0.001*lightDirection, lightDirection, stepSize);\n    return t < (max_dist - 0.1) ? 1.0-amount : 1.0;\n}\n\n// From https://www.shadertoy.com/view/XslSWl\nfloat occlusion(vec3 p,vec3 n) { \n    const int AO_SAMPLES = 8;\n    const float INV_AO_SAMPLES = 1.0/float(AO_SAMPLES);\n    const float R = 0.9;\n    const float D = 0.8;\n    float r = 0.0;\n    for(int i = 0; i < AO_SAMPLES; i++) {\n        float f = float(i)*INV_AO_SAMPLES;\n        float h = 0.05+f*R;\n        float d = surfaceDistance(p + n * h) - 0.003;\n        r += clamp(h*D-d,0.0,1.0) * (1.0-f);\n    }    \n    return clamp(1.0-r,0.0,1.0);\n}\n";
   var fragFooter = "\n// For advanced users //\nvoid main() {\n\n    vec3 rayOrigin = (cameraPosition - sculptureCenter) / max(intersection_threshold, _scale);\n    vec3 rayDirection = getRayDirection();\n    float t = intersect(rayOrigin, rayDirection, stepSize);\n    if(t < max_dist) {\n        vec3 p = (rayOrigin + rayDirection*t);\n        //vec4 sp = projectionMatrix*viewMatrix*vec4(p,1.0); //could be used to set FragDepth\n        vec3 normal = calcNormal(p);\n        // p *= _scale;\n        vec3 col = shade(p, normal);\n        pc_fragColor = vec4(col, opacity);\n        \n    } else {\n        discard;\n    }\n}\n";
 
   /**
@@ -96467,7 +96264,7 @@
     };
   }
 
-  console.log("using shader-park version: 0.1.10"); /// Generate code for various targets
+  console.log("using shader-park version: 0.1.12"); /// Generate code for various targets
 
   exports.baseUniforms = baseUniforms;
   exports.bindStaticData = bindStaticData;
@@ -96500,4 +96297,4 @@
 
   Object.defineProperty(exports, '__esModule', { value: true });
 
-}));
+})));
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 876e414..a5f21d3 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -10,7 +10,9 @@ import {
 
 import {convertFunctionToString} from './helpers.js'
 
-import { Texture, Vector2, Vector3, ShaderMaterial, Mesh, BoxBufferGeometry, BackSide, SphereBufferGeometry} from 'three';
+import { MultiPostFX } from 'multiPostFX.js';
+
+import { Texture, Vector2, Vector3, Vector4, ShaderMaterial, Mesh, BoxBufferGeometry, BackSide, SphereBufferGeometry} from 'three';
 
 /**
  *  Three targets are provided for both GLSL and Sculpt/JS api.
@@ -88,6 +90,57 @@ export function createSculptureWithGeometry(geometry, source, uniformCallback=()
     return createSculpture(source, uniformCallback, params);
 }
 
+export function createMultiPassSculptureWithGeometry(geometry, source, uniformCallback=() => {return {}}, params={}) {
+    geometry.computeBoundingSphere();
+    let radius = ('radius' in params)? params.radius: geometry.boundingSphere.radius;
+    params.radius = radius;
+    params.geometry = geometry;
+    return createSculpture(source, uniformCallback, params);
+}
+
+
+//
+{
+    buffera : `enable2D()`,
+    bufferb : `enable2D()`,
+    bufferc : `enable2D()`
+}
+export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
+    // source = convertFunctionToString(source);
+    let {bufferA, bufferB, bufferC, bufferD, finalImage} = source;
+
+    let buffers = [bufferA, bufferB, bufferC, bufferD]
+
+
+    let radius = ('radius' in params)? params.radius: 2;
+
+    let geometry;
+    if ('geometry' in params) {
+        geometry = params.geometry;
+    } else {
+        let segments = ('segments' in params)? params.segments: 10;
+        geometry = new SphereBufferGeometry( radius, segments, segments );   
+    }
+    let material = sculptToThreeJSMaterial(source);
+    
+    material.uniforms['opacity'].value = 1.0;
+    material.uniforms['mouse'].value = new Vector3();
+    material.uniforms['_scale'].value = radius;
+    let mesh = new Mesh(geometry, material);
+
+    mesh.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
+        let uniformsToUpdate = uniformCallback();
+        if (!(typeof uniformsToUpdate === "object")) {
+            throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update"
+        }
+
+        for (const [uniform, value] of Object.entries(uniformsToUpdate)) {
+            material.uniforms[uniform].value = value;
+        }
+        // material.uniforms['sculptureCenter'].value = geometry.position;
+    }
+}
+
 // uniformCallback 
 export function createSculpture(source, uniformCallback=() => {return {}}, params={}) {
     source = convertFunctionToString(source);
@@ -98,7 +151,7 @@ export function createSculpture(source, uniformCallback=() => {return {}}, param
     if ('geometry' in params) {
         geometry = params.geometry;
     } else {
-        let segments = ('segments' in params)? params.segments: 8;
+        let segments = ('segments' in params)? params.segments: 10;
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
     let material = sculptToThreeJSMaterial(source);

From 032c545f9bc09882bd31b30c1545f0e6ebac1457 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 20 Mar 2022 23:05:30 -0400
Subject: [PATCH 05/20] working single texture read

---
 dist/shader-park-core.cjs.js | 331 +++++++++++++++++++++++++++++++----
 dist/shader-park-core.esm.js | 331 +++++++++++++++++++++++++++++++----
 dist/shader-park-core.umd.js | 331 +++++++++++++++++++++++++++++++----
 generators/sculpt.js         |  31 +++-
 index.js                     |   7 +-
 targets/multiPostFX.js       |  24 ++-
 targets/threeJS.js           |  75 ++++++--
 7 files changed, 999 insertions(+), 131 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 40d9af9..4dca7a2 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -45002,8 +45002,44 @@ function sculptToGLSL(userProvidedSrc) {
       max: max
     });
     return new vec2(name, true);
+  } // let bufferA = inputTexture('bufferA');
+  // let samp = sampler(bufferA, vec2(.4));
+  // color(samp.x, samp.y, samp.z);
+
+
+  function inputTexture(name) {
+    uniforms.push({
+      name: name,
+      type: 'sampler2D'
+    });
+    return new makeVar(name, 'sampler2D', 0, true);
+  }
+
+  function sampleTexture(textureRef, uv) {
+    ensureDims("sampleTexture", 2, uv);
+    return new vec4("texture(".concat(collapseToString(textureRef), ", ").concat(uv, ")"), false);
   }
 
+  function _bindTextureRead(name) {
+    return function (coord) {
+      if (!uniforms.find(function (el) {
+        return el.name === name;
+      })) {
+        inputTexture(name);
+      }
+
+      return sampleTexture(name, coord);
+    };
+  }
+
+  var sampleBufferA = _bindTextureRead("bufferA");
+
+  var sampleBufferB = _bindTextureRead("bufferB");
+
+  var sampleBufferC = _bindTextureRead("bufferC");
+
+  var sampleBufferD = _bindTextureRead("bufferD");
+
   function getPixelCoord() {
     return makeVarWithDims('gl_FragCoord.xy', 2, true);
   }
@@ -47561,7 +47597,7 @@ Texture.DEFAULT_MAPPING = UVMapping;
 
 Texture.prototype.isTexture = true;
 
-class Vector4$1 {
+class Vector4 {
 
 	constructor( x = 0, y = 0, z = 0, w = 1 ) {
 
@@ -48222,7 +48258,7 @@ class Vector4$1 {
 
 }
 
-Vector4$1.prototype.isVector4 = true;
+Vector4.prototype.isVector4 = true;
 
 /*
  In options, we can specify:
@@ -48239,10 +48275,10 @@ class WebGLRenderTarget extends EventDispatcher {
 		this.height = height;
 		this.depth = 1;
 
-		this.scissor = new Vector4$1( 0, 0, width, height );
+		this.scissor = new Vector4( 0, 0, width, height );
 		this.scissorTest = false;
 
-		this.viewport = new Vector4$1( 0, 0, width, height );
+		this.viewport = new Vector4( 0, 0, width, height );
 
 		const image = { width: width, height: height, depth: 1 };
 
@@ -54390,7 +54426,7 @@ class BufferAttribute {
 			if ( vector === undefined ) {
 
 				console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
-				vector = new Vector4$1();
+				vector = new Vector4();
 
 			}
 
@@ -61690,7 +61726,7 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
 	const influencesList = {};
 	const morphInfluences = new Float32Array( 8 );
 	const morphTextures = new WeakMap();
-	const morph = new Vector4$1();
+	const morph = new Vector4();
 
 	const workInfluences = [];
 
@@ -65704,7 +65740,7 @@ function WebGLShadowMap( _renderer, _objects, _capabilities ) {
 	const _shadowMapSize = new Vector2(),
 		_viewportSize = new Vector2(),
 
-		_viewport = new Vector4$1(),
+		_viewport = new Vector4(),
 
 		_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
 		_distanceMaterial = new MeshDistanceMaterial(),
@@ -66070,9 +66106,9 @@ function WebGLState( gl, extensions, capabilities ) {
 
 		let locked = false;
 
-		const color = new Vector4$1();
+		const color = new Vector4();
 		let currentColorMask = null;
-		const currentColorClear = new Vector4$1( 0, 0, 0, 0 );
+		const currentColorClear = new Vector4( 0, 0, 0, 0 );
 
 		return {
 
@@ -66425,8 +66461,8 @@ function WebGLState( gl, extensions, capabilities ) {
 	const scissorParam = gl.getParameter( 3088 );
 	const viewportParam = gl.getParameter( 2978 );
 
-	const currentScissor = new Vector4$1().fromArray( scissorParam );
-	const currentViewport = new Vector4$1().fromArray( viewportParam );
+	const currentScissor = new Vector4().fromArray( scissorParam );
+	const currentViewport = new Vector4().fromArray( viewportParam );
 
 	function createTexture( type, target, count ) {
 
@@ -69734,11 +69770,11 @@ class WebXRManager extends EventDispatcher {
 
 		const cameraL = new PerspectiveCamera();
 		cameraL.layers.enable( 1 );
-		cameraL.viewport = new Vector4$1();
+		cameraL.viewport = new Vector4();
 
 		const cameraR = new PerspectiveCamera();
 		cameraR.layers.enable( 2 );
-		cameraR.viewport = new Vector4$1();
+		cameraR.viewport = new Vector4();
 
 		const cameras = [ cameraL, cameraR ];
 
@@ -71246,8 +71282,8 @@ function WebGLRenderer( parameters = {} ) {
 
 	let _currentCamera = null;
 
-	const _currentViewport = new Vector4$1();
-	const _currentScissor = new Vector4$1();
+	const _currentViewport = new Vector4();
+	const _currentScissor = new Vector4();
 	let _currentScissorTest = null;
 
 	//
@@ -71259,8 +71295,8 @@ function WebGLRenderer( parameters = {} ) {
 	let _opaqueSort = null;
 	let _transparentSort = null;
 
-	const _viewport = new Vector4$1( 0, 0, _width, _height );
-	const _scissor = new Vector4$1( 0, 0, _width, _height );
+	const _viewport = new Vector4( 0, 0, _width, _height );
+	const _scissor = new Vector4( 0, 0, _width, _height );
 	let _scissorTest = false;
 
 	// frustum
@@ -74252,8 +74288,8 @@ class LOD extends Object3D {
 
 const _basePosition = /*@__PURE__*/ new Vector3();
 
-const _skinIndex = /*@__PURE__*/ new Vector4$1();
-const _skinWeight = /*@__PURE__*/ new Vector4$1();
+const _skinIndex = /*@__PURE__*/ new Vector4();
+const _skinWeight = /*@__PURE__*/ new Vector4();
 
 const _vector$5 = /*@__PURE__*/ new Vector3();
 const _matrix = /*@__PURE__*/ new Matrix4();
@@ -74313,7 +74349,7 @@ class SkinnedMesh extends Mesh {
 
 	normalizeSkinWeights() {
 
-		const vector = new Vector4$1();
+		const vector = new Vector4();
 
 		const skinWeight = this.geometry.attributes.skinWeight;
 
@@ -85357,7 +85393,7 @@ class LightShadow {
 
 		this._viewports = [
 
-			new Vector4$1( 0, 0, 1, 1 )
+			new Vector4( 0, 0, 1, 1 )
 
 		];
 
@@ -85605,17 +85641,17 @@ class PointLightShadow extends LightShadow {
 			// z - Negative z direction
 
 			// positive X
-			new Vector4$1( 2, 1, 1, 1 ),
+			new Vector4( 2, 1, 1, 1 ),
 			// negative X
-			new Vector4$1( 0, 1, 1, 1 ),
+			new Vector4( 0, 1, 1, 1 ),
 			// positive Z
-			new Vector4$1( 3, 1, 1, 1 ),
+			new Vector4( 3, 1, 1, 1 ),
 			// negative Z
-			new Vector4$1( 1, 1, 1, 1 ),
+			new Vector4( 1, 1, 1, 1 ),
 			// positive Y
-			new Vector4$1( 3, 0, 1, 1 ),
+			new Vector4( 3, 0, 1, 1 ),
 			// negative Y
-			new Vector4$1( 1, 0, 1, 1 )
+			new Vector4( 1, 0, 1, 1 )
 		];
 
 		this._cubeDirections = [
@@ -86289,7 +86325,7 @@ class MaterialLoader extends Loader {
 						break;
 
 					case 'v4':
-						material.uniforms[ name ].value = new Vector4$1().fromArray( uniform.value );
+						material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
 						break;
 
 					case 'm3':
@@ -94581,14 +94617,14 @@ Vector3.prototype.lengthManhattan = function () {
 
 //
 
-Vector4$1.prototype.fromAttribute = function ( attribute, index, offset ) {
+Vector4.prototype.fromAttribute = function ( attribute, index, offset ) {
 
 	console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
 	return this.fromBufferAttribute( attribute, index, offset );
 
 };
 
-Vector4$1.prototype.lengthManhattan = function () {
+Vector4.prototype.lengthManhattan = function () {
 
 	console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
 	return this.manhattanLength();
@@ -95797,6 +95833,127 @@ if ( typeof window !== 'undefined' ) {
 
 }
 
+/**
+ *
+ * @params: (object)
+ * renderer: (THREE.WebGLRenderer) renderer used to render your original scene
+ * passes: (object) object describing the passes applied consecutively
+ *  - passName (object):
+ *      - format: (THREE texture constants format, optionnal) format to use for your pass texure (default to THREE.RGBAFormat)
+ *      - uniforms: (object, optionnal) additional uniforms to use (see THREE Uniform)
+ *      - vertexShader: (string, optionnal) vertexShader to use. Use one if you want to specify varyings to your fragment shader. Uses the default const vertexShader if none specified
+ *      - fragmentShader: (string optionnal) fragmentShader to use. Uses the default const fragmentShader (that just display your scene) if none specified.
+ *
+ */
+
+var MultiPostFX = /*#__PURE__*/function () {
+  function MultiPostFX(params) {
+    _classCallCheck(this, MultiPostFX);
+
+    this.renderer = params.renderer;
+    if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+
+    this.dummyCamera = new OrthographicCamera();
+    this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
+
+    var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
+    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+    this.resolution = new Vector2();
+    this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+
+    this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+
+    this.nbPasses = 0;
+    this.passes = {};
+    params.passes = params.passes || {};
+
+    for (var passName in params.passes) {
+      this.addPass(passName, params.passes[passName]);
+    }
+  }
+
+  _createClass(MultiPostFX, [{
+    key: "addPass",
+    value: function addPass(passName, passParams) {
+      // create a pass object that will contain a scene, a render target
+      // a material and its uniforms and finally a mesh
+      var pass = {
+        scene: new Scene(),
+        target: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+          format: passParams.format || RGBAFormat,
+          // allow transparency
+          stencilBuffer: false,
+          depthBuffer: true
+        })
+      };
+      var uniforms = {
+        uScene: {
+          value: pass.target.texture
+        },
+        uResolution: {
+          value: this.resolution
+        }
+      }; // merge default uniforms with params
+
+      if (passParams.uniforms) {
+        uniforms = Object.assign(uniforms, passParams.uniforms);
+      }
+
+      pass.material = new RawShaderMaterial({
+        fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
+        vertexShader: passParams.vertexShader || this.defaultVertexShader,
+        uniforms: uniforms
+      });
+      pass.mesh = new Mesh(this.geometry, pass.material);
+      pass.mesh.frustumCulled = false;
+      pass.scene.add(pass.mesh);
+      this.passes[passName] = pass;
+      this.nbPasses++;
+    }
+  }, {
+    key: "resize",
+    value: function resize() {
+      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+
+      var passes = Object.keys(this.passes);
+
+      for (var i = 0; i < this.nbPasses; i++) {
+        this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+        this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+      }
+    }
+  }, {
+    key: "render",
+    value: function render(scene, camera) {
+      if (this.nbPasses === 0) {
+        // no passes defined, just render the scene
+        this.renderer.render(scene, camera);
+      } else {
+        var passes = Object.keys(this.passes);
+        this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+        // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        // this.renderer.render(scene, camera);
+        // render next passes
+        // console.log(' numpasses', passes.length, passes)
+        // for(let i = 1; i < this.nbPasses; i++) {
+        //     console.log('rendering', this.nbPasses);
+        //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
+        //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
+        // }
+        // render the last pass back to the canvas
+        // TODO Check if we need this
+        // this.renderer.setRenderTarget(null);
+        // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+      }
+    }
+  }]);
+
+  return MultiPostFX;
+}();
+
 /**
  *  Three targets are provided for both GLSL and Sculpt/JS api.
  * 
@@ -95829,6 +95986,7 @@ function sculptToThreeJSShaderSource(source) {
   }
 
   var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
+  console.log(frg);
   return {
     uniforms: src.uniforms,
     frag: frg,
@@ -95858,31 +96016,86 @@ function createSculptureWithGeometry(geometry, source) {
   params.radius = radius;
   params.geometry = geometry;
   return createSculpture(source, uniformCallback, params);
-} // uniformCallback 
+}
+function createMultiPassSculptureWithGeometry(geometry, source) {
+  var uniformCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
+    return {};
+  };
+  var params = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+  geometry.computeBoundingSphere();
+  var radius = 'radius' in params ? params.radius : geometry.boundingSphere.radius;
+  params.radius = radius;
+  params.geometry = geometry;
+  return createMultiPassSculpture(source, uniformCallback, params);
+} // let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform sampler2D uScene;
+//             uniform vec2 uResolution;
+//             void main() {
+//                 vec2 uv = gl_FragCoord.xy / uResolution.xy;
+//                 vec4 color = texture2D(uScene, uv);
+//                 // invert colors                 
+//                 color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.x, 0.5));
+//                 //color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.y, 0.5));
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
 
-function createSculpture(source) {
+var passes = {
+  bufferA: {
+    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+  }
+};
+function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
     return {};
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-  source = convertFunctionToString(source);
+  // source = convertFunctionToString(source);
+  var common = source.common,
+      bufferA = source.bufferA,
+      bufferB = source.bufferB,
+      bufferC = source.bufferC,
+      bufferD = source.bufferD,
+      finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
+
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
   if ('geometry' in params) {
     geometry = params.geometry;
   } else {
-    var segments = 'segments' in params ? params.segments : 8;
+    var segments = 'segments' in params ? params.segments : 10;
     geometry = new SphereGeometry(radius, segments, segments);
   }
 
-  var material = sculptToThreeJSMaterial(source);
+  var material = sculptToThreeJSMaterial(finalImage);
   material.uniforms['opacity'].value = 1.0;
   material.uniforms['mouse'].value = new Vector3();
   material.uniforms['_scale'].value = radius;
   var mesh = new Mesh(geometry, material);
+  var multiPost;
 
   mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+    if (!multiPost) {
+      multiPost = new MultiPostFX({
+        renderer: renderer,
+        passes: passes
+      });
+      console.log(multiPost);
+    } else {
+      multiPost.render(scene, camera);
+
+      if ('bufferA' in material.uniforms) {
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+        console.log('setting buffA', material.uniforms['bufferA'].value);
+      }
+    }
+
     var uniformsToUpdate = uniformCallback();
 
     if (!(_typeof(uniformsToUpdate) === "object")) {
@@ -95899,6 +96112,48 @@ function createSculpture(source) {
 
   };
 
+  return mesh;
+} // uniformCallback 
+
+function createSculpture(source) {
+  var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
+    return {};
+  };
+  var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+  source = convertFunctionToString(source);
+  var radius = 'radius' in params ? params.radius : 2;
+  var geometry;
+
+  if ('geometry' in params) {
+    geometry = params.geometry;
+  } else {
+    var segments = 'segments' in params ? params.segments : 10;
+    geometry = new SphereGeometry(radius, segments, segments);
+  }
+
+  var material = sculptToThreeJSMaterial(source);
+  material.uniforms['opacity'].value = 1.0;
+  material.uniforms['mouse'].value = new Vector3();
+  material.uniforms['_scale'].value = radius;
+  var mesh = new Mesh(geometry, material);
+
+  mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+    var uniformsToUpdate = uniformCallback();
+
+    if (!(_typeof(uniformsToUpdate) === "object")) {
+      throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
+    }
+
+    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+          uniform = _Object$entries2$_i[0],
+          value = _Object$entries2$_i[1];
+
+      material.uniforms[uniform].value = value;
+    } // material.uniforms['sculptureCenter'].value = geometry.position;
+
+  };
+
   return mesh;
 }
 
@@ -95928,6 +96183,10 @@ function uniformDescriptionToThreeJSFormat(unifs, payload) {
       finalUniforms[uniform.name] = {
         value: new Vector4(uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w)
       };
+    } else if (uniform.type === 'sampler2D') {
+      finalUniforms[uniform.name] = {
+        value: new Texture()
+      };
     }
   });
   return finalUniforms;
@@ -96266,6 +96525,8 @@ console.log("using shader-park version: 0.1.12"); /// Generate code for various
 
 exports.baseUniforms = baseUniforms;
 exports.bindStaticData = bindStaticData;
+exports.createMultiPassSculpture = createMultiPassSculpture;
+exports.createMultiPassSculptureWithGeometry = createMultiPassSculptureWithGeometry;
 exports.createSculpture = createSculpture;
 exports.createSculptureWithGeometry = createSculptureWithGeometry;
 exports.defaultFragSourceGLSL = defaultFragSourceGLSL;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 91cb627..e2eacf0 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -44998,8 +44998,44 @@ function sculptToGLSL(userProvidedSrc) {
       max: max
     });
     return new vec2(name, true);
+  } // let bufferA = inputTexture('bufferA');
+  // let samp = sampler(bufferA, vec2(.4));
+  // color(samp.x, samp.y, samp.z);
+
+
+  function inputTexture(name) {
+    uniforms.push({
+      name: name,
+      type: 'sampler2D'
+    });
+    return new makeVar(name, 'sampler2D', 0, true);
+  }
+
+  function sampleTexture(textureRef, uv) {
+    ensureDims("sampleTexture", 2, uv);
+    return new vec4("texture(".concat(collapseToString(textureRef), ", ").concat(uv, ")"), false);
   }
 
+  function _bindTextureRead(name) {
+    return function (coord) {
+      if (!uniforms.find(function (el) {
+        return el.name === name;
+      })) {
+        inputTexture(name);
+      }
+
+      return sampleTexture(name, coord);
+    };
+  }
+
+  var sampleBufferA = _bindTextureRead("bufferA");
+
+  var sampleBufferB = _bindTextureRead("bufferB");
+
+  var sampleBufferC = _bindTextureRead("bufferC");
+
+  var sampleBufferD = _bindTextureRead("bufferD");
+
   function getPixelCoord() {
     return makeVarWithDims('gl_FragCoord.xy', 2, true);
   }
@@ -47557,7 +47593,7 @@ Texture.DEFAULT_MAPPING = UVMapping;
 
 Texture.prototype.isTexture = true;
 
-class Vector4$1 {
+class Vector4 {
 
 	constructor( x = 0, y = 0, z = 0, w = 1 ) {
 
@@ -48218,7 +48254,7 @@ class Vector4$1 {
 
 }
 
-Vector4$1.prototype.isVector4 = true;
+Vector4.prototype.isVector4 = true;
 
 /*
  In options, we can specify:
@@ -48235,10 +48271,10 @@ class WebGLRenderTarget extends EventDispatcher {
 		this.height = height;
 		this.depth = 1;
 
-		this.scissor = new Vector4$1( 0, 0, width, height );
+		this.scissor = new Vector4( 0, 0, width, height );
 		this.scissorTest = false;
 
-		this.viewport = new Vector4$1( 0, 0, width, height );
+		this.viewport = new Vector4( 0, 0, width, height );
 
 		const image = { width: width, height: height, depth: 1 };
 
@@ -54386,7 +54422,7 @@ class BufferAttribute {
 			if ( vector === undefined ) {
 
 				console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
-				vector = new Vector4$1();
+				vector = new Vector4();
 
 			}
 
@@ -61686,7 +61722,7 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
 	const influencesList = {};
 	const morphInfluences = new Float32Array( 8 );
 	const morphTextures = new WeakMap();
-	const morph = new Vector4$1();
+	const morph = new Vector4();
 
 	const workInfluences = [];
 
@@ -65700,7 +65736,7 @@ function WebGLShadowMap( _renderer, _objects, _capabilities ) {
 	const _shadowMapSize = new Vector2(),
 		_viewportSize = new Vector2(),
 
-		_viewport = new Vector4$1(),
+		_viewport = new Vector4(),
 
 		_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
 		_distanceMaterial = new MeshDistanceMaterial(),
@@ -66066,9 +66102,9 @@ function WebGLState( gl, extensions, capabilities ) {
 
 		let locked = false;
 
-		const color = new Vector4$1();
+		const color = new Vector4();
 		let currentColorMask = null;
-		const currentColorClear = new Vector4$1( 0, 0, 0, 0 );
+		const currentColorClear = new Vector4( 0, 0, 0, 0 );
 
 		return {
 
@@ -66421,8 +66457,8 @@ function WebGLState( gl, extensions, capabilities ) {
 	const scissorParam = gl.getParameter( 3088 );
 	const viewportParam = gl.getParameter( 2978 );
 
-	const currentScissor = new Vector4$1().fromArray( scissorParam );
-	const currentViewport = new Vector4$1().fromArray( viewportParam );
+	const currentScissor = new Vector4().fromArray( scissorParam );
+	const currentViewport = new Vector4().fromArray( viewportParam );
 
 	function createTexture( type, target, count ) {
 
@@ -69730,11 +69766,11 @@ class WebXRManager extends EventDispatcher {
 
 		const cameraL = new PerspectiveCamera();
 		cameraL.layers.enable( 1 );
-		cameraL.viewport = new Vector4$1();
+		cameraL.viewport = new Vector4();
 
 		const cameraR = new PerspectiveCamera();
 		cameraR.layers.enable( 2 );
-		cameraR.viewport = new Vector4$1();
+		cameraR.viewport = new Vector4();
 
 		const cameras = [ cameraL, cameraR ];
 
@@ -71242,8 +71278,8 @@ function WebGLRenderer( parameters = {} ) {
 
 	let _currentCamera = null;
 
-	const _currentViewport = new Vector4$1();
-	const _currentScissor = new Vector4$1();
+	const _currentViewport = new Vector4();
+	const _currentScissor = new Vector4();
 	let _currentScissorTest = null;
 
 	//
@@ -71255,8 +71291,8 @@ function WebGLRenderer( parameters = {} ) {
 	let _opaqueSort = null;
 	let _transparentSort = null;
 
-	const _viewport = new Vector4$1( 0, 0, _width, _height );
-	const _scissor = new Vector4$1( 0, 0, _width, _height );
+	const _viewport = new Vector4( 0, 0, _width, _height );
+	const _scissor = new Vector4( 0, 0, _width, _height );
 	let _scissorTest = false;
 
 	// frustum
@@ -74248,8 +74284,8 @@ class LOD extends Object3D {
 
 const _basePosition = /*@__PURE__*/ new Vector3();
 
-const _skinIndex = /*@__PURE__*/ new Vector4$1();
-const _skinWeight = /*@__PURE__*/ new Vector4$1();
+const _skinIndex = /*@__PURE__*/ new Vector4();
+const _skinWeight = /*@__PURE__*/ new Vector4();
 
 const _vector$5 = /*@__PURE__*/ new Vector3();
 const _matrix = /*@__PURE__*/ new Matrix4();
@@ -74309,7 +74345,7 @@ class SkinnedMesh extends Mesh {
 
 	normalizeSkinWeights() {
 
-		const vector = new Vector4$1();
+		const vector = new Vector4();
 
 		const skinWeight = this.geometry.attributes.skinWeight;
 
@@ -85353,7 +85389,7 @@ class LightShadow {
 
 		this._viewports = [
 
-			new Vector4$1( 0, 0, 1, 1 )
+			new Vector4( 0, 0, 1, 1 )
 
 		];
 
@@ -85601,17 +85637,17 @@ class PointLightShadow extends LightShadow {
 			// z - Negative z direction
 
 			// positive X
-			new Vector4$1( 2, 1, 1, 1 ),
+			new Vector4( 2, 1, 1, 1 ),
 			// negative X
-			new Vector4$1( 0, 1, 1, 1 ),
+			new Vector4( 0, 1, 1, 1 ),
 			// positive Z
-			new Vector4$1( 3, 1, 1, 1 ),
+			new Vector4( 3, 1, 1, 1 ),
 			// negative Z
-			new Vector4$1( 1, 1, 1, 1 ),
+			new Vector4( 1, 1, 1, 1 ),
 			// positive Y
-			new Vector4$1( 3, 0, 1, 1 ),
+			new Vector4( 3, 0, 1, 1 ),
 			// negative Y
-			new Vector4$1( 1, 0, 1, 1 )
+			new Vector4( 1, 0, 1, 1 )
 		];
 
 		this._cubeDirections = [
@@ -86285,7 +86321,7 @@ class MaterialLoader extends Loader {
 						break;
 
 					case 'v4':
-						material.uniforms[ name ].value = new Vector4$1().fromArray( uniform.value );
+						material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
 						break;
 
 					case 'm3':
@@ -94577,14 +94613,14 @@ Vector3.prototype.lengthManhattan = function () {
 
 //
 
-Vector4$1.prototype.fromAttribute = function ( attribute, index, offset ) {
+Vector4.prototype.fromAttribute = function ( attribute, index, offset ) {
 
 	console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
 	return this.fromBufferAttribute( attribute, index, offset );
 
 };
 
-Vector4$1.prototype.lengthManhattan = function () {
+Vector4.prototype.lengthManhattan = function () {
 
 	console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
 	return this.manhattanLength();
@@ -95793,6 +95829,127 @@ if ( typeof window !== 'undefined' ) {
 
 }
 
+/**
+ *
+ * @params: (object)
+ * renderer: (THREE.WebGLRenderer) renderer used to render your original scene
+ * passes: (object) object describing the passes applied consecutively
+ *  - passName (object):
+ *      - format: (THREE texture constants format, optionnal) format to use for your pass texure (default to THREE.RGBAFormat)
+ *      - uniforms: (object, optionnal) additional uniforms to use (see THREE Uniform)
+ *      - vertexShader: (string, optionnal) vertexShader to use. Use one if you want to specify varyings to your fragment shader. Uses the default const vertexShader if none specified
+ *      - fragmentShader: (string optionnal) fragmentShader to use. Uses the default const fragmentShader (that just display your scene) if none specified.
+ *
+ */
+
+var MultiPostFX = /*#__PURE__*/function () {
+  function MultiPostFX(params) {
+    _classCallCheck(this, MultiPostFX);
+
+    this.renderer = params.renderer;
+    if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+
+    this.dummyCamera = new OrthographicCamera();
+    this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
+
+    var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
+    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+    this.resolution = new Vector2();
+    this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+
+    this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+
+    this.nbPasses = 0;
+    this.passes = {};
+    params.passes = params.passes || {};
+
+    for (var passName in params.passes) {
+      this.addPass(passName, params.passes[passName]);
+    }
+  }
+
+  _createClass(MultiPostFX, [{
+    key: "addPass",
+    value: function addPass(passName, passParams) {
+      // create a pass object that will contain a scene, a render target
+      // a material and its uniforms and finally a mesh
+      var pass = {
+        scene: new Scene(),
+        target: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+          format: passParams.format || RGBAFormat,
+          // allow transparency
+          stencilBuffer: false,
+          depthBuffer: true
+        })
+      };
+      var uniforms = {
+        uScene: {
+          value: pass.target.texture
+        },
+        uResolution: {
+          value: this.resolution
+        }
+      }; // merge default uniforms with params
+
+      if (passParams.uniforms) {
+        uniforms = Object.assign(uniforms, passParams.uniforms);
+      }
+
+      pass.material = new RawShaderMaterial({
+        fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
+        vertexShader: passParams.vertexShader || this.defaultVertexShader,
+        uniforms: uniforms
+      });
+      pass.mesh = new Mesh(this.geometry, pass.material);
+      pass.mesh.frustumCulled = false;
+      pass.scene.add(pass.mesh);
+      this.passes[passName] = pass;
+      this.nbPasses++;
+    }
+  }, {
+    key: "resize",
+    value: function resize() {
+      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+
+      var passes = Object.keys(this.passes);
+
+      for (var i = 0; i < this.nbPasses; i++) {
+        this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+        this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+      }
+    }
+  }, {
+    key: "render",
+    value: function render(scene, camera) {
+      if (this.nbPasses === 0) {
+        // no passes defined, just render the scene
+        this.renderer.render(scene, camera);
+      } else {
+        var passes = Object.keys(this.passes);
+        this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+        // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        // this.renderer.render(scene, camera);
+        // render next passes
+        // console.log(' numpasses', passes.length, passes)
+        // for(let i = 1; i < this.nbPasses; i++) {
+        //     console.log('rendering', this.nbPasses);
+        //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
+        //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
+        // }
+        // render the last pass back to the canvas
+        // TODO Check if we need this
+        // this.renderer.setRenderTarget(null);
+        // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+      }
+    }
+  }]);
+
+  return MultiPostFX;
+}();
+
 /**
  *  Three targets are provided for both GLSL and Sculpt/JS api.
  * 
@@ -95825,6 +95982,7 @@ function sculptToThreeJSShaderSource(source) {
   }
 
   var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
+  console.log(frg);
   return {
     uniforms: src.uniforms,
     frag: frg,
@@ -95854,31 +96012,86 @@ function createSculptureWithGeometry(geometry, source) {
   params.radius = radius;
   params.geometry = geometry;
   return createSculpture(source, uniformCallback, params);
-} // uniformCallback 
+}
+function createMultiPassSculptureWithGeometry(geometry, source) {
+  var uniformCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
+    return {};
+  };
+  var params = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+  geometry.computeBoundingSphere();
+  var radius = 'radius' in params ? params.radius : geometry.boundingSphere.radius;
+  params.radius = radius;
+  params.geometry = geometry;
+  return createMultiPassSculpture(source, uniformCallback, params);
+} // let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform sampler2D uScene;
+//             uniform vec2 uResolution;
+//             void main() {
+//                 vec2 uv = gl_FragCoord.xy / uResolution.xy;
+//                 vec4 color = texture2D(uScene, uv);
+//                 // invert colors                 
+//                 color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.x, 0.5));
+//                 //color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.y, 0.5));
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
 
-function createSculpture(source) {
+var passes = {
+  bufferA: {
+    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+  }
+};
+function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
     return {};
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-  source = convertFunctionToString(source);
+  // source = convertFunctionToString(source);
+  var common = source.common,
+      bufferA = source.bufferA,
+      bufferB = source.bufferB,
+      bufferC = source.bufferC,
+      bufferD = source.bufferD,
+      finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
+
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
   if ('geometry' in params) {
     geometry = params.geometry;
   } else {
-    var segments = 'segments' in params ? params.segments : 8;
+    var segments = 'segments' in params ? params.segments : 10;
     geometry = new SphereGeometry(radius, segments, segments);
   }
 
-  var material = sculptToThreeJSMaterial(source);
+  var material = sculptToThreeJSMaterial(finalImage);
   material.uniforms['opacity'].value = 1.0;
   material.uniforms['mouse'].value = new Vector3();
   material.uniforms['_scale'].value = radius;
   var mesh = new Mesh(geometry, material);
+  var multiPost;
 
   mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+    if (!multiPost) {
+      multiPost = new MultiPostFX({
+        renderer: renderer,
+        passes: passes
+      });
+      console.log(multiPost);
+    } else {
+      multiPost.render(scene, camera);
+
+      if ('bufferA' in material.uniforms) {
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+        console.log('setting buffA', material.uniforms['bufferA'].value);
+      }
+    }
+
     var uniformsToUpdate = uniformCallback();
 
     if (!(_typeof(uniformsToUpdate) === "object")) {
@@ -95895,6 +96108,48 @@ function createSculpture(source) {
 
   };
 
+  return mesh;
+} // uniformCallback 
+
+function createSculpture(source) {
+  var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
+    return {};
+  };
+  var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+  source = convertFunctionToString(source);
+  var radius = 'radius' in params ? params.radius : 2;
+  var geometry;
+
+  if ('geometry' in params) {
+    geometry = params.geometry;
+  } else {
+    var segments = 'segments' in params ? params.segments : 10;
+    geometry = new SphereGeometry(radius, segments, segments);
+  }
+
+  var material = sculptToThreeJSMaterial(source);
+  material.uniforms['opacity'].value = 1.0;
+  material.uniforms['mouse'].value = new Vector3();
+  material.uniforms['_scale'].value = radius;
+  var mesh = new Mesh(geometry, material);
+
+  mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+    var uniformsToUpdate = uniformCallback();
+
+    if (!(_typeof(uniformsToUpdate) === "object")) {
+      throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
+    }
+
+    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+          uniform = _Object$entries2$_i[0],
+          value = _Object$entries2$_i[1];
+
+      material.uniforms[uniform].value = value;
+    } // material.uniforms['sculptureCenter'].value = geometry.position;
+
+  };
+
   return mesh;
 }
 
@@ -95924,6 +96179,10 @@ function uniformDescriptionToThreeJSFormat(unifs, payload) {
       finalUniforms[uniform.name] = {
         value: new Vector4(uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w)
       };
+    } else if (uniform.type === 'sampler2D') {
+      finalUniforms[uniform.name] = {
+        value: new Texture()
+      };
     }
   });
   return finalUniforms;
@@ -96260,4 +96519,4 @@ function sculptToTouchDesignerShaderSource(source) {
 
 console.log("using shader-park version: 0.1.12"); /// Generate code for various targets
 
-export { baseUniforms, bindStaticData, createSculpture, createSculptureWithGeometry, defaultFragSourceGLSL, fragFooter, glslToMinimalHTMLRenderer, glslToMinimalRenderer, glslToOfflineRenderer, glslToThreeJSMaterial, glslToThreeJSMesh, glslToThreeJSShaderSource, glslToTouchDesignerShaderSource, minimalHeader, minimalVertexSource, sculptToGLSL, sculptToMinimalHTMLRenderer, sculptToMinimalRenderer, sculptToOfflineRenderer, sculptToRawSDF4Meshing, sculptToThreeJSMaterial, sculptToThreeJSMesh, sculptToThreeJSShaderSource, sculptToTouchDesignerShaderSource, sculptureStarterCode, uniformsToGLSL, useHemisphereLight, usePBRHeader };
+export { baseUniforms, bindStaticData, createMultiPassSculpture, createMultiPassSculptureWithGeometry, createSculpture, createSculptureWithGeometry, defaultFragSourceGLSL, fragFooter, glslToMinimalHTMLRenderer, glslToMinimalRenderer, glslToOfflineRenderer, glslToThreeJSMaterial, glslToThreeJSMesh, glslToThreeJSShaderSource, glslToTouchDesignerShaderSource, minimalHeader, minimalVertexSource, sculptToGLSL, sculptToMinimalHTMLRenderer, sculptToMinimalRenderer, sculptToOfflineRenderer, sculptToRawSDF4Meshing, sculptToThreeJSMaterial, sculptToThreeJSMesh, sculptToThreeJSShaderSource, sculptToTouchDesignerShaderSource, sculptureStarterCode, uniformsToGLSL, useHemisphereLight, usePBRHeader };
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 61d9a50..9a66514 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -45004,8 +45004,44 @@
         max: max
       });
       return new vec2(name, true);
+    } // let bufferA = inputTexture('bufferA');
+    // let samp = sampler(bufferA, vec2(.4));
+    // color(samp.x, samp.y, samp.z);
+
+
+    function inputTexture(name) {
+      uniforms.push({
+        name: name,
+        type: 'sampler2D'
+      });
+      return new makeVar(name, 'sampler2D', 0, true);
+    }
+
+    function sampleTexture(textureRef, uv) {
+      ensureDims("sampleTexture", 2, uv);
+      return new vec4("texture(".concat(collapseToString(textureRef), ", ").concat(uv, ")"), false);
     }
 
+    function _bindTextureRead(name) {
+      return function (coord) {
+        if (!uniforms.find(function (el) {
+          return el.name === name;
+        })) {
+          inputTexture(name);
+        }
+
+        return sampleTexture(name, coord);
+      };
+    }
+
+    var sampleBufferA = _bindTextureRead("bufferA");
+
+    var sampleBufferB = _bindTextureRead("bufferB");
+
+    var sampleBufferC = _bindTextureRead("bufferC");
+
+    var sampleBufferD = _bindTextureRead("bufferD");
+
     function getPixelCoord() {
       return makeVarWithDims('gl_FragCoord.xy', 2, true);
     }
@@ -47563,7 +47599,7 @@
 
   Texture.prototype.isTexture = true;
 
-  class Vector4$1 {
+  class Vector4 {
 
   	constructor( x = 0, y = 0, z = 0, w = 1 ) {
 
@@ -48224,7 +48260,7 @@
 
   }
 
-  Vector4$1.prototype.isVector4 = true;
+  Vector4.prototype.isVector4 = true;
 
   /*
    In options, we can specify:
@@ -48241,10 +48277,10 @@
   		this.height = height;
   		this.depth = 1;
 
-  		this.scissor = new Vector4$1( 0, 0, width, height );
+  		this.scissor = new Vector4( 0, 0, width, height );
   		this.scissorTest = false;
 
-  		this.viewport = new Vector4$1( 0, 0, width, height );
+  		this.viewport = new Vector4( 0, 0, width, height );
 
   		const image = { width: width, height: height, depth: 1 };
 
@@ -54392,7 +54428,7 @@
   			if ( vector === undefined ) {
 
   				console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
-  				vector = new Vector4$1();
+  				vector = new Vector4();
 
   			}
 
@@ -61692,7 +61728,7 @@
   	const influencesList = {};
   	const morphInfluences = new Float32Array( 8 );
   	const morphTextures = new WeakMap();
-  	const morph = new Vector4$1();
+  	const morph = new Vector4();
 
   	const workInfluences = [];
 
@@ -65706,7 +65742,7 @@
   	const _shadowMapSize = new Vector2(),
   		_viewportSize = new Vector2(),
 
-  		_viewport = new Vector4$1(),
+  		_viewport = new Vector4(),
 
   		_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
   		_distanceMaterial = new MeshDistanceMaterial(),
@@ -66072,9 +66108,9 @@
 
   		let locked = false;
 
-  		const color = new Vector4$1();
+  		const color = new Vector4();
   		let currentColorMask = null;
-  		const currentColorClear = new Vector4$1( 0, 0, 0, 0 );
+  		const currentColorClear = new Vector4( 0, 0, 0, 0 );
 
   		return {
 
@@ -66427,8 +66463,8 @@
   	const scissorParam = gl.getParameter( 3088 );
   	const viewportParam = gl.getParameter( 2978 );
 
-  	const currentScissor = new Vector4$1().fromArray( scissorParam );
-  	const currentViewport = new Vector4$1().fromArray( viewportParam );
+  	const currentScissor = new Vector4().fromArray( scissorParam );
+  	const currentViewport = new Vector4().fromArray( viewportParam );
 
   	function createTexture( type, target, count ) {
 
@@ -69736,11 +69772,11 @@
 
   		const cameraL = new PerspectiveCamera();
   		cameraL.layers.enable( 1 );
-  		cameraL.viewport = new Vector4$1();
+  		cameraL.viewport = new Vector4();
 
   		const cameraR = new PerspectiveCamera();
   		cameraR.layers.enable( 2 );
-  		cameraR.viewport = new Vector4$1();
+  		cameraR.viewport = new Vector4();
 
   		const cameras = [ cameraL, cameraR ];
 
@@ -71248,8 +71284,8 @@
 
   	let _currentCamera = null;
 
-  	const _currentViewport = new Vector4$1();
-  	const _currentScissor = new Vector4$1();
+  	const _currentViewport = new Vector4();
+  	const _currentScissor = new Vector4();
   	let _currentScissorTest = null;
 
   	//
@@ -71261,8 +71297,8 @@
   	let _opaqueSort = null;
   	let _transparentSort = null;
 
-  	const _viewport = new Vector4$1( 0, 0, _width, _height );
-  	const _scissor = new Vector4$1( 0, 0, _width, _height );
+  	const _viewport = new Vector4( 0, 0, _width, _height );
+  	const _scissor = new Vector4( 0, 0, _width, _height );
   	let _scissorTest = false;
 
   	// frustum
@@ -74254,8 +74290,8 @@
 
   const _basePosition = /*@__PURE__*/ new Vector3();
 
-  const _skinIndex = /*@__PURE__*/ new Vector4$1();
-  const _skinWeight = /*@__PURE__*/ new Vector4$1();
+  const _skinIndex = /*@__PURE__*/ new Vector4();
+  const _skinWeight = /*@__PURE__*/ new Vector4();
 
   const _vector$5 = /*@__PURE__*/ new Vector3();
   const _matrix = /*@__PURE__*/ new Matrix4();
@@ -74315,7 +74351,7 @@
 
   	normalizeSkinWeights() {
 
-  		const vector = new Vector4$1();
+  		const vector = new Vector4();
 
   		const skinWeight = this.geometry.attributes.skinWeight;
 
@@ -85359,7 +85395,7 @@
 
   		this._viewports = [
 
-  			new Vector4$1( 0, 0, 1, 1 )
+  			new Vector4( 0, 0, 1, 1 )
 
   		];
 
@@ -85607,17 +85643,17 @@
   			// z - Negative z direction
 
   			// positive X
-  			new Vector4$1( 2, 1, 1, 1 ),
+  			new Vector4( 2, 1, 1, 1 ),
   			// negative X
-  			new Vector4$1( 0, 1, 1, 1 ),
+  			new Vector4( 0, 1, 1, 1 ),
   			// positive Z
-  			new Vector4$1( 3, 1, 1, 1 ),
+  			new Vector4( 3, 1, 1, 1 ),
   			// negative Z
-  			new Vector4$1( 1, 1, 1, 1 ),
+  			new Vector4( 1, 1, 1, 1 ),
   			// positive Y
-  			new Vector4$1( 3, 0, 1, 1 ),
+  			new Vector4( 3, 0, 1, 1 ),
   			// negative Y
-  			new Vector4$1( 1, 0, 1, 1 )
+  			new Vector4( 1, 0, 1, 1 )
   		];
 
   		this._cubeDirections = [
@@ -86291,7 +86327,7 @@
   						break;
 
   					case 'v4':
-  						material.uniforms[ name ].value = new Vector4$1().fromArray( uniform.value );
+  						material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
   						break;
 
   					case 'm3':
@@ -94583,14 +94619,14 @@
 
   //
 
-  Vector4$1.prototype.fromAttribute = function ( attribute, index, offset ) {
+  Vector4.prototype.fromAttribute = function ( attribute, index, offset ) {
 
   	console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
   	return this.fromBufferAttribute( attribute, index, offset );
 
   };
 
-  Vector4$1.prototype.lengthManhattan = function () {
+  Vector4.prototype.lengthManhattan = function () {
 
   	console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' );
   	return this.manhattanLength();
@@ -95799,6 +95835,127 @@
 
   }
 
+  /**
+   *
+   * @params: (object)
+   * renderer: (THREE.WebGLRenderer) renderer used to render your original scene
+   * passes: (object) object describing the passes applied consecutively
+   *  - passName (object):
+   *      - format: (THREE texture constants format, optionnal) format to use for your pass texure (default to THREE.RGBAFormat)
+   *      - uniforms: (object, optionnal) additional uniforms to use (see THREE Uniform)
+   *      - vertexShader: (string, optionnal) vertexShader to use. Use one if you want to specify varyings to your fragment shader. Uses the default const vertexShader if none specified
+   *      - fragmentShader: (string optionnal) fragmentShader to use. Uses the default const fragmentShader (that just display your scene) if none specified.
+   *
+   */
+
+  var MultiPostFX = /*#__PURE__*/function () {
+    function MultiPostFX(params) {
+      _classCallCheck(this, MultiPostFX);
+
+      this.renderer = params.renderer;
+      if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+
+      this.dummyCamera = new OrthographicCamera();
+      this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
+
+      var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
+      this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+      this.resolution = new Vector2();
+      this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+
+      this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+      this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+
+      this.nbPasses = 0;
+      this.passes = {};
+      params.passes = params.passes || {};
+
+      for (var passName in params.passes) {
+        this.addPass(passName, params.passes[passName]);
+      }
+    }
+
+    _createClass(MultiPostFX, [{
+      key: "addPass",
+      value: function addPass(passName, passParams) {
+        // create a pass object that will contain a scene, a render target
+        // a material and its uniforms and finally a mesh
+        var pass = {
+          scene: new Scene(),
+          target: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+            format: passParams.format || RGBAFormat,
+            // allow transparency
+            stencilBuffer: false,
+            depthBuffer: true
+          })
+        };
+        var uniforms = {
+          uScene: {
+            value: pass.target.texture
+          },
+          uResolution: {
+            value: this.resolution
+          }
+        }; // merge default uniforms with params
+
+        if (passParams.uniforms) {
+          uniforms = Object.assign(uniforms, passParams.uniforms);
+        }
+
+        pass.material = new RawShaderMaterial({
+          fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
+          vertexShader: passParams.vertexShader || this.defaultVertexShader,
+          uniforms: uniforms
+        });
+        pass.mesh = new Mesh(this.geometry, pass.material);
+        pass.mesh.frustumCulled = false;
+        pass.scene.add(pass.mesh);
+        this.passes[passName] = pass;
+        this.nbPasses++;
+      }
+    }, {
+      key: "resize",
+      value: function resize() {
+        this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+
+        var passes = Object.keys(this.passes);
+
+        for (var i = 0; i < this.nbPasses; i++) {
+          this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+          this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+        }
+      }
+    }, {
+      key: "render",
+      value: function render(scene, camera) {
+        if (this.nbPasses === 0) {
+          // no passes defined, just render the scene
+          this.renderer.render(scene, camera);
+        } else {
+          var passes = Object.keys(this.passes);
+          this.renderer.setRenderTarget(this.passes[passes[0]].target);
+          this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+          this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+          // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+          // this.renderer.render(scene, camera);
+          // render next passes
+          // console.log(' numpasses', passes.length, passes)
+          // for(let i = 1; i < this.nbPasses; i++) {
+          //     console.log('rendering', this.nbPasses);
+          //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
+          //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
+          // }
+          // render the last pass back to the canvas
+          // TODO Check if we need this
+          // this.renderer.setRenderTarget(null);
+          // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+        }
+      }
+    }]);
+
+    return MultiPostFX;
+  }();
+
   /**
    *  Three targets are provided for both GLSL and Sculpt/JS api.
    * 
@@ -95831,6 +95988,7 @@
     }
 
     var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
+    console.log(frg);
     return {
       uniforms: src.uniforms,
       frag: frg,
@@ -95860,31 +96018,86 @@
     params.radius = radius;
     params.geometry = geometry;
     return createSculpture(source, uniformCallback, params);
-  } // uniformCallback 
+  }
+  function createMultiPassSculptureWithGeometry(geometry, source) {
+    var uniformCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
+      return {};
+    };
+    var params = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+    geometry.computeBoundingSphere();
+    var radius = 'radius' in params ? params.radius : geometry.boundingSphere.radius;
+    params.radius = radius;
+    params.geometry = geometry;
+    return createMultiPassSculpture(source, uniformCallback, params);
+  } // let passes = {
+  //     bufferA: {
+  //         fragmentShader: `
+  //             precision highp float;
+  //             uniform sampler2D uScene;
+  //             uniform vec2 uResolution;
+  //             void main() {
+  //                 vec2 uv = gl_FragCoord.xy / uResolution.xy;
+  //                 vec4 color = texture2D(uScene, uv);
+  //                 // invert colors                 
+  //                 color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.x, 0.5));
+  //                 //color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.y, 0.5));
+  //                 gl_FragColor = color;
+  //             }
+  //         `,
+  //     }
+  // }
 
-  function createSculpture(source) {
+  var passes = {
+    bufferA: {
+      fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+    }
+  };
+  function createMultiPassSculpture(source) {
     var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
       return {};
     };
     var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-    source = convertFunctionToString(source);
+    // source = convertFunctionToString(source);
+    var common = source.common,
+        bufferA = source.bufferA,
+        bufferB = source.bufferB,
+        bufferC = source.bufferC,
+        bufferD = source.bufferD,
+        finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
+
     var radius = 'radius' in params ? params.radius : 2;
     var geometry;
 
     if ('geometry' in params) {
       geometry = params.geometry;
     } else {
-      var segments = 'segments' in params ? params.segments : 8;
+      var segments = 'segments' in params ? params.segments : 10;
       geometry = new SphereGeometry(radius, segments, segments);
     }
 
-    var material = sculptToThreeJSMaterial(source);
+    var material = sculptToThreeJSMaterial(finalImage);
     material.uniforms['opacity'].value = 1.0;
     material.uniforms['mouse'].value = new Vector3();
     material.uniforms['_scale'].value = radius;
     var mesh = new Mesh(geometry, material);
+    var multiPost;
 
     mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+      if (!multiPost) {
+        multiPost = new MultiPostFX({
+          renderer: renderer,
+          passes: passes
+        });
+        console.log(multiPost);
+      } else {
+        multiPost.render(scene, camera);
+
+        if ('bufferA' in material.uniforms) {
+          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+          console.log('setting buffA', material.uniforms['bufferA'].value);
+        }
+      }
+
       var uniformsToUpdate = uniformCallback();
 
       if (!(_typeof(uniformsToUpdate) === "object")) {
@@ -95901,6 +96114,48 @@
 
     };
 
+    return mesh;
+  } // uniformCallback 
+
+  function createSculpture(source) {
+    var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
+      return {};
+    };
+    var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+    source = convertFunctionToString(source);
+    var radius = 'radius' in params ? params.radius : 2;
+    var geometry;
+
+    if ('geometry' in params) {
+      geometry = params.geometry;
+    } else {
+      var segments = 'segments' in params ? params.segments : 10;
+      geometry = new SphereGeometry(radius, segments, segments);
+    }
+
+    var material = sculptToThreeJSMaterial(source);
+    material.uniforms['opacity'].value = 1.0;
+    material.uniforms['mouse'].value = new Vector3();
+    material.uniforms['_scale'].value = radius;
+    var mesh = new Mesh(geometry, material);
+
+    mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
+      var uniformsToUpdate = uniformCallback();
+
+      if (!(_typeof(uniformsToUpdate) === "object")) {
+        throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
+      }
+
+      for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+        var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+            uniform = _Object$entries2$_i[0],
+            value = _Object$entries2$_i[1];
+
+        material.uniforms[uniform].value = value;
+      } // material.uniforms['sculptureCenter'].value = geometry.position;
+
+    };
+
     return mesh;
   }
 
@@ -95930,6 +96185,10 @@
         finalUniforms[uniform.name] = {
           value: new Vector4(uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w)
         };
+      } else if (uniform.type === 'sampler2D') {
+        finalUniforms[uniform.name] = {
+          value: new Texture()
+        };
       }
     });
     return finalUniforms;
@@ -96268,6 +96527,8 @@
 
   exports.baseUniforms = baseUniforms;
   exports.bindStaticData = bindStaticData;
+  exports.createMultiPassSculpture = createMultiPassSculpture;
+  exports.createMultiPassSculptureWithGeometry = createMultiPassSculptureWithGeometry;
   exports.createSculpture = createSculpture;
   exports.createSculptureWithGeometry = createSculptureWithGeometry;
   exports.defaultFragSourceGLSL = defaultFragSourceGLSL;
diff --git a/generators/sculpt.js b/generators/sculpt.js
index cadddc8..1ace4a7 100644
--- a/generators/sculpt.js
+++ b/generators/sculpt.js
@@ -1120,8 +1120,6 @@ export function sculptToGLSL(userProvidedSrc) {
 		return new float(name, true);
 	}
 
-
-	
 	function input2D(name, value={x: 0.0, y: 0.0}, min = {x: 0.0, y: 0.0}, max = {x: 1.0, y: 1.0}) {
 		if(typeof value === 'number' && typeof min === 'number' && typeof max === 'object') {
 			// syntax input2D(.2, 1.2);
@@ -1142,6 +1140,35 @@ export function sculptToGLSL(userProvidedSrc) {
 		return new vec2(name, true);
 	}
 
+	// let bufferA = inputTexture('bufferA');
+	// let samp = sampler(bufferA, vec2(.4));
+	// color(samp.x, samp.y, samp.z);
+
+	function inputTexture(name) {
+		uniforms.push({name, type:'sampler2D'});
+		return new makeVar(name, 'sampler2D', 0, true);
+	}
+
+	function sampleTexture(textureRef, uv) {
+		ensureDims("sampleTexture", 2, uv);
+		return new vec4(`texture(${collapseToString(textureRef)}, ${uv})`, false);
+	}
+
+	function _bindTextureRead(name) {
+		return (coord) => {
+			if(!uniforms.find((el) => el.name === name)) {
+				inputTexture(name);
+			}
+			return sampleTexture(name, coord);
+		}
+	}
+
+	let sampleBufferA = _bindTextureRead("bufferA");
+	let sampleBufferB = _bindTextureRead("bufferB");
+	let sampleBufferC = _bindTextureRead("bufferC");
+	let sampleBufferD = _bindTextureRead("bufferD");
+
+
 	function getPixelCoord() {
 		return makeVarWithDims('gl_FragCoord.xy', 2, true);
 	}
diff --git a/index.js b/index.js
index d8e048a..250e321 100644
--- a/index.js
+++ b/index.js
@@ -6,7 +6,10 @@ import {
     sculptToThreeJSMaterial,
     sculptToThreeJSMesh,
     createSculpture,
-    createSculptureWithGeometry
+    createSculptureWithGeometry,
+    createMultiPassSculptureWithGeometry,
+    createMultiPassSculpture
+
 } from './targets/threeJS.js'
 
 import {
@@ -61,6 +64,8 @@ export {
     sculptToThreeJSShaderSource,
     sculptToThreeJSMaterial,
     sculptToThreeJSMesh,
+    createMultiPassSculptureWithGeometry,
+    createMultiPassSculpture,
     createSculptureWithGeometry,
     createSculpture,
     bindStaticData,
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index e38b9c2..435f388 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -49,7 +49,7 @@ import {
  *      - fragmentShader: (string optionnal) fragmentShader to use. Uses the default const fragmentShader (that just display your scene) if none specified.
  *
  */
-export default class MultiPostFX {
+export class MultiPostFX {
     constructor(params) {
         this.renderer = params.renderer;
 
@@ -156,19 +156,25 @@ export default class MultiPostFX {
         else {
             const passes = Object.keys(this.passes);
 
-            // render the original scene in our first pass render target
             this.renderer.setRenderTarget(this.passes[passes[0]].target);
-            this.renderer.render(scene, camera);
+            this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+            this.renderer.setRenderTarget(null);
+            // render the original scene in our first pass render target
+            // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+            // this.renderer.render(scene, camera);
 
             // render next passes
-            for(let i = 1; i < this.nbPasses; i++) {
-                this.renderer.setRenderTarget(this.passes[passes[i]].target);
-                this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
-            }
+            // console.log(' numpasses', passes.length, passes)
+            // for(let i = 1; i < this.nbPasses; i++) {
+            //     console.log('rendering', this.nbPasses);
+            //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
+            //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
+            // }
 
             // render the last pass back to the canvas
-            this.renderer.setRenderTarget(null);
-            this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+            // TODO Check if we need this
+            // this.renderer.setRenderTarget(null);
+            // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
         }
     }
 }
\ No newline at end of file
diff --git a/targets/threeJS.js b/targets/threeJS.js
index a5f21d3..ad97097 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -10,7 +10,7 @@ import {
 
 import {convertFunctionToString} from './helpers.js'
 
-import { MultiPostFX } from 'multiPostFX.js';
+import {MultiPostFX} from './multiPostFX.js';
 
 import { Texture, Vector2, Vector3, Vector4, ShaderMaterial, Mesh, BoxBufferGeometry, BackSide, SphereBufferGeometry} from 'three';
 
@@ -59,7 +59,7 @@ export function sculptToThreeJSShaderSource(source) {
         + src.colorGLSL 
         + '\n' 
         + fragFooter;
-
+    console.log(frg)
     return {
         uniforms: src.uniforms,
         frag: frg,
@@ -95,21 +95,51 @@ export function createMultiPassSculptureWithGeometry(geometry, source, uniformCa
     let radius = ('radius' in params)? params.radius: geometry.boundingSphere.radius;
     params.radius = radius;
     params.geometry = geometry;
-    return createSculpture(source, uniformCallback, params);
+    return createMultiPassSculpture(source, uniformCallback, params);
 }
 
+// let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform sampler2D uScene;
+//             uniform vec2 uResolution;
+            
+//             void main() {
+//                 vec2 uv = gl_FragCoord.xy / uResolution.xy;
+//                 vec4 color = texture2D(uScene, uv);
+//                 // invert colors                 
+//                 color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.x, 0.5));
+//                 //color = mix(color, vec4((1.0 - color.rgb) * color.a, color.a), step(uv.y, 0.5));
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
 
-//
-{
-    buffera : `enable2D()`,
-    bufferb : `enable2D()`,
-    bufferc : `enable2D()`
+let passes = {
+    bufferA: {
+        fragmentShader: `
+            precision highp float;
+            uniform sampler2D uScene;
+            uniform vec2 uResolution;
+            
+            void main() {
+                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);
+                gl_FragColor = color;
+            }
+        `,
+    }
 }
+
 export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
+    
     // source = convertFunctionToString(source);
-    let {bufferA, bufferB, bufferC, bufferD, finalImage} = source;
 
-    let buffers = [bufferA, bufferB, bufferC, bufferD]
+    
+    let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
+
+    // let buffers = [bufferA, bufferB, bufferC, bufferD]
 
 
     let radius = ('radius' in params)? params.radius: 2;
@@ -121,14 +151,30 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         let segments = ('segments' in params)? params.segments: 10;
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
-    let material = sculptToThreeJSMaterial(source);
-    
+    let material = sculptToThreeJSMaterial(finalImage);
+
     material.uniforms['opacity'].value = 1.0;
     material.uniforms['mouse'].value = new Vector3();
     material.uniforms['_scale'].value = radius;
+    
     let mesh = new Mesh(geometry, material);
-
+    let multiPost;
     mesh.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
+        if(!multiPost) {
+            multiPost = new MultiPostFX({
+                renderer,
+                passes
+            });
+            console.log(multiPost)
+        } else {
+            multiPost.render(scene, camera);
+            
+            if('bufferA' in material.uniforms) {
+                
+                material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+                console.log('setting buffA', material.uniforms['bufferA'].value)
+            }
+        }
         let uniformsToUpdate = uniformCallback();
         if (!(typeof uniformsToUpdate === "object")) {
             throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update"
@@ -139,6 +185,7 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         }
         // material.uniforms['sculptureCenter'].value = geometry.position;
     }
+    return mesh;
 }
 
 // uniformCallback 
@@ -192,6 +239,8 @@ function uniformDescriptionToThreeJSFormat(unifs, payload) {
             finalUniforms[uniform.name] = {value: new Vector3(uniform.value.x, uniform.value.y, uniform.value.z)};
         } else if (uniform.type === 'vec4') {
             finalUniforms[uniform.name] = {value: new Vector4(uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w)};
+        } else if(uniform.type === 'sampler2D') {
+            finalUniforms[uniform.name] = {value: new Texture()}
         }
     });
     return finalUniforms;

From 206a0273c649ff2f44d4ca3fff267ce4216615be Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 10:55:39 -0400
Subject: [PATCH 06/20] allow for multiple render targets

---
 targets/multiPostFX.js | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 435f388..2f64b86 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -156,24 +156,23 @@ export class MultiPostFX {
         else {
             const passes = Object.keys(this.passes);
 
-            this.renderer.setRenderTarget(this.passes[passes[0]].target);
-            this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-            this.renderer.setRenderTarget(null);
+            // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+            // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+            // this.renderer.setRenderTarget(null);
             // render the original scene in our first pass render target
             // this.renderer.setRenderTarget(this.passes[passes[0]].target);
             // this.renderer.render(scene, camera);
 
             // render next passes
             // console.log(' numpasses', passes.length, passes)
-            // for(let i = 1; i < this.nbPasses; i++) {
-            //     console.log('rendering', this.nbPasses);
-            //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
-            //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
-            // }
+            for(let i = 0; i < this.nbPasses; i++) {
+                this.renderer.setRenderTarget(this.passes[passes[i]].target);
+                this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+            }
 
             // render the last pass back to the canvas
             // TODO Check if we need this
-            // this.renderer.setRenderTarget(null);
+            this.renderer.setRenderTarget(null);
             // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
         }
     }

From 03ac9e0057ac37669e8e5d3a43960746d5e71a9a Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 10:56:13 -0400
Subject: [PATCH 07/20] prep spCodeToMultiPassGLSL

---
 dist/shader-park-core.cjs.js | 111 ++++++++++++++++++++++-------------
 dist/shader-park-core.esm.js | 111 ++++++++++++++++++++++-------------
 dist/shader-park-core.umd.js | 111 ++++++++++++++++++++++-------------
 generators/sculpt.js         |  13 ++--
 targets/threeJS.js           |  46 ++++++++++-----
 5 files changed, 248 insertions(+), 144 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 4dca7a2..ed834ea 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -43912,10 +43912,6 @@ function spCodeToMultiPassGLSL(passes) {
   }
 
   var common = passes.common,
-      bufferA = passes.bufferA,
-      bufferB = passes.bufferB,
-      bufferC = passes.bufferC,
-      bufferD = passes.bufferD,
       finalImage = passes.finalImage;
 
   if (!common) {
@@ -43926,11 +43922,19 @@ function spCodeToMultiPassGLSL(passes) {
     errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
   }
 
-  return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
-    if (pass) {
-      return sculptToGLSL(common + '\n' + pass);
+  var output = {};
+
+  for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+        key = _Object$entries$_i[0],
+        value = _Object$entries$_i[1];
+
+    if (key !== 'common') {
+      output[key] = sculptToGLSL(common + '\n' + value);
     }
-  });
+  }
+
+  return output;
 }
 function sculptToGLSL(userProvidedSrc) {
   var PI = Math.PI;
@@ -44089,10 +44093,10 @@ function sculptToGLSL(userProvidedSrc) {
 
   var boundSDFs = {};
 
-  for (var _i = 0, _Object$entries = Object.entries(sdfs); _i < _Object$entries.length; _i++) {
-    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-        key = _Object$entries$_i[0],
-        value = _Object$entries$_i[1];
+  for (var _i2 = 0, _Object$entries2 = Object.entries(sdfs); _i2 < _Object$entries2.length; _i2++) {
+    var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+        key = _Object$entries2$_i[0],
+        value = _Object$entries2$_i[1];
 
     boundSDFs[key] = glslSDF(value);
   }
@@ -44136,10 +44140,10 @@ function sculptToGLSL(userProvidedSrc) {
 
   var primitivesJS = "";
 
-  for (var _i2 = 0, _Object$entries2 = Object.entries(geometryFunctions); _i2 < _Object$entries2.length; _i2++) {
-    var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-        funcName = _Object$entries2$_i[0],
-        body = _Object$entries2$_i[1];
+  for (var _i3 = 0, _Object$entries3 = Object.entries(geometryFunctions); _i3 < _Object$entries3.length; _i3++) {
+    var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+        funcName = _Object$entries3$_i[0],
+        body = _Object$entries3$_i[1];
 
     var argList = body['args'];
     primitivesJS += "function " + funcName + "(";
@@ -44186,10 +44190,10 @@ function sculptToGLSL(userProvidedSrc) {
   function generateGLSLWrapper(funcJSON) {
     var wrapperSrc = "";
 
-    for (var _i3 = 0, _Object$entries3 = Object.entries(funcJSON); _i3 < _Object$entries3.length; _i3++) {
-      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-          _funcName = _Object$entries3$_i[0],
-          _body = _Object$entries3$_i[1];
+    for (var _i4 = 0, _Object$entries4 = Object.entries(funcJSON); _i4 < _Object$entries4.length; _i4++) {
+      var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+          _funcName = _Object$entries4$_i[0],
+          _body = _Object$entries4$_i[1];
 
       var _argList = _body['args'];
       var returnType = _body['ret'];
@@ -95930,23 +95934,23 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes);
-        this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-        this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+        var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        // this.renderer.setRenderTarget(null);
+        // render the original scene in our first pass render target
         // this.renderer.setRenderTarget(this.passes[passes[0]].target);
         // this.renderer.render(scene, camera);
         // render next passes
         // console.log(' numpasses', passes.length, passes)
-        // for(let i = 1; i < this.nbPasses; i++) {
-        //     console.log('rendering', this.nbPasses);
-        //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
-        //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
-        // }
-        // render the last pass back to the canvas
+
+        for (var i = 0; i < this.nbPasses; i++) {
+          this.renderer.setRenderTarget(this.passes[passes[i]].target);
+          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+        } // render the last pass back to the canvas
         // TODO Check if we need this
-        // this.renderer.setRenderTarget(null);
-        // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+
+
+        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -95980,7 +95984,10 @@ function glslToThreeJSMesh(source, payload) {
 }
 function sculptToThreeJSShaderSource(source) {
   var src = sculptToGLSL(source);
+  return generateThreeJSFrag(src);
+}
 
+function generateThreeJSFrag(src) {
   if (src.error) {
     console.log(src.error);
   }
@@ -95995,6 +96002,27 @@ function sculptToThreeJSShaderSource(source) {
     geoGLSL: src.geoGLSL,
     colorGLSL: src.colorGLSL
   };
+} // {buffera, bufferb, bufferc, finalImage}
+
+
+function multiPassSculpToThreeJSMaterial(passesSources) {
+  var passes = spCodeToMultiPassGLSL(passesSources);
+  var output = {};
+
+  for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+        key = _Object$entries$_i[0],
+        value = _Object$entries$_i[1];
+
+    var src = generateThreeJSFrag(value);
+
+    var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
+
+    _material.uniformDescriptions = src.uniforms;
+    output[key] = _material;
+  }
+
+  return material;
 }
 function sculptToThreeJSMaterial(source, payload) {
   var src = sculptToThreeJSShaderSource(source);
@@ -96049,7 +96077,8 @@ var passes = {
   bufferA: {
     fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
-};
+}; // TODO NEXT Replace sculptToThreeJSMaterial with 
+
 function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
     return {};
@@ -96102,10 +96131,10 @@ function createMultiPassSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i = 0, _Object$entries = Object.entries(uniformsToUpdate); _i < _Object$entries.length; _i++) {
-      var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-          uniform = _Object$entries$_i[0],
-          value = _Object$entries$_i[1];
+    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+          uniform = _Object$entries2$_i[0],
+          value = _Object$entries2$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
@@ -96144,10 +96173,10 @@ function createSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
-      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-          uniform = _Object$entries2$_i[0],
-          value = _Object$entries2$_i[1];
+    for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
+      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+          uniform = _Object$entries3$_i[0],
+          value = _Object$entries3$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index e2eacf0..1949d65 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -43908,10 +43908,6 @@ function spCodeToMultiPassGLSL(passes) {
   }
 
   var common = passes.common,
-      bufferA = passes.bufferA,
-      bufferB = passes.bufferB,
-      bufferC = passes.bufferC,
-      bufferD = passes.bufferD,
       finalImage = passes.finalImage;
 
   if (!common) {
@@ -43922,11 +43918,19 @@ function spCodeToMultiPassGLSL(passes) {
     errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
   }
 
-  return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
-    if (pass) {
-      return sculptToGLSL(common + '\n' + pass);
+  var output = {};
+
+  for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+        key = _Object$entries$_i[0],
+        value = _Object$entries$_i[1];
+
+    if (key !== 'common') {
+      output[key] = sculptToGLSL(common + '\n' + value);
     }
-  });
+  }
+
+  return output;
 }
 function sculptToGLSL(userProvidedSrc) {
   var PI = Math.PI;
@@ -44085,10 +44089,10 @@ function sculptToGLSL(userProvidedSrc) {
 
   var boundSDFs = {};
 
-  for (var _i = 0, _Object$entries = Object.entries(sdfs); _i < _Object$entries.length; _i++) {
-    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-        key = _Object$entries$_i[0],
-        value = _Object$entries$_i[1];
+  for (var _i2 = 0, _Object$entries2 = Object.entries(sdfs); _i2 < _Object$entries2.length; _i2++) {
+    var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+        key = _Object$entries2$_i[0],
+        value = _Object$entries2$_i[1];
 
     boundSDFs[key] = glslSDF(value);
   }
@@ -44132,10 +44136,10 @@ function sculptToGLSL(userProvidedSrc) {
 
   var primitivesJS = "";
 
-  for (var _i2 = 0, _Object$entries2 = Object.entries(geometryFunctions); _i2 < _Object$entries2.length; _i2++) {
-    var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-        funcName = _Object$entries2$_i[0],
-        body = _Object$entries2$_i[1];
+  for (var _i3 = 0, _Object$entries3 = Object.entries(geometryFunctions); _i3 < _Object$entries3.length; _i3++) {
+    var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+        funcName = _Object$entries3$_i[0],
+        body = _Object$entries3$_i[1];
 
     var argList = body['args'];
     primitivesJS += "function " + funcName + "(";
@@ -44182,10 +44186,10 @@ function sculptToGLSL(userProvidedSrc) {
   function generateGLSLWrapper(funcJSON) {
     var wrapperSrc = "";
 
-    for (var _i3 = 0, _Object$entries3 = Object.entries(funcJSON); _i3 < _Object$entries3.length; _i3++) {
-      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-          _funcName = _Object$entries3$_i[0],
-          _body = _Object$entries3$_i[1];
+    for (var _i4 = 0, _Object$entries4 = Object.entries(funcJSON); _i4 < _Object$entries4.length; _i4++) {
+      var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+          _funcName = _Object$entries4$_i[0],
+          _body = _Object$entries4$_i[1];
 
       var _argList = _body['args'];
       var returnType = _body['ret'];
@@ -95926,23 +95930,23 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes);
-        this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-        this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+        var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        // this.renderer.setRenderTarget(null);
+        // render the original scene in our first pass render target
         // this.renderer.setRenderTarget(this.passes[passes[0]].target);
         // this.renderer.render(scene, camera);
         // render next passes
         // console.log(' numpasses', passes.length, passes)
-        // for(let i = 1; i < this.nbPasses; i++) {
-        //     console.log('rendering', this.nbPasses);
-        //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
-        //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
-        // }
-        // render the last pass back to the canvas
+
+        for (var i = 0; i < this.nbPasses; i++) {
+          this.renderer.setRenderTarget(this.passes[passes[i]].target);
+          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+        } // render the last pass back to the canvas
         // TODO Check if we need this
-        // this.renderer.setRenderTarget(null);
-        // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+
+
+        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -95976,7 +95980,10 @@ function glslToThreeJSMesh(source, payload) {
 }
 function sculptToThreeJSShaderSource(source) {
   var src = sculptToGLSL(source);
+  return generateThreeJSFrag(src);
+}
 
+function generateThreeJSFrag(src) {
   if (src.error) {
     console.log(src.error);
   }
@@ -95991,6 +95998,27 @@ function sculptToThreeJSShaderSource(source) {
     geoGLSL: src.geoGLSL,
     colorGLSL: src.colorGLSL
   };
+} // {buffera, bufferb, bufferc, finalImage}
+
+
+function multiPassSculpToThreeJSMaterial(passesSources) {
+  var passes = spCodeToMultiPassGLSL(passesSources);
+  var output = {};
+
+  for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+    var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+        key = _Object$entries$_i[0],
+        value = _Object$entries$_i[1];
+
+    var src = generateThreeJSFrag(value);
+
+    var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
+
+    _material.uniformDescriptions = src.uniforms;
+    output[key] = _material;
+  }
+
+  return material;
 }
 function sculptToThreeJSMaterial(source, payload) {
   var src = sculptToThreeJSShaderSource(source);
@@ -96045,7 +96073,8 @@ var passes = {
   bufferA: {
     fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
-};
+}; // TODO NEXT Replace sculptToThreeJSMaterial with 
+
 function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
     return {};
@@ -96098,10 +96127,10 @@ function createMultiPassSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i = 0, _Object$entries = Object.entries(uniformsToUpdate); _i < _Object$entries.length; _i++) {
-      var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-          uniform = _Object$entries$_i[0],
-          value = _Object$entries$_i[1];
+    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+          uniform = _Object$entries2$_i[0],
+          value = _Object$entries2$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
@@ -96140,10 +96169,10 @@ function createSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
-      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-          uniform = _Object$entries2$_i[0],
-          value = _Object$entries2$_i[1];
+    for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
+      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+          uniform = _Object$entries3$_i[0],
+          value = _Object$entries3$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 9a66514..7da7080 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -43914,10 +43914,6 @@
     }
 
     var common = passes.common,
-        bufferA = passes.bufferA,
-        bufferB = passes.bufferB,
-        bufferC = passes.bufferC,
-        bufferD = passes.bufferD,
         finalImage = passes.finalImage;
 
     if (!common) {
@@ -43928,11 +43924,19 @@
       errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
     }
 
-    return [bufferA, bufferB, bufferC, bufferD, finalImage].map(function (pass) {
-      if (pass) {
-        return sculptToGLSL(common + '\n' + pass);
+    var output = {};
+
+    for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+      var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+          key = _Object$entries$_i[0],
+          value = _Object$entries$_i[1];
+
+      if (key !== 'common') {
+        output[key] = sculptToGLSL(common + '\n' + value);
       }
-    });
+    }
+
+    return output;
   }
   function sculptToGLSL(userProvidedSrc) {
     var PI = Math.PI;
@@ -44091,10 +44095,10 @@
 
     var boundSDFs = {};
 
-    for (var _i = 0, _Object$entries = Object.entries(sdfs); _i < _Object$entries.length; _i++) {
-      var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-          key = _Object$entries$_i[0],
-          value = _Object$entries$_i[1];
+    for (var _i2 = 0, _Object$entries2 = Object.entries(sdfs); _i2 < _Object$entries2.length; _i2++) {
+      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+          key = _Object$entries2$_i[0],
+          value = _Object$entries2$_i[1];
 
       boundSDFs[key] = glslSDF(value);
     }
@@ -44138,10 +44142,10 @@
 
     var primitivesJS = "";
 
-    for (var _i2 = 0, _Object$entries2 = Object.entries(geometryFunctions); _i2 < _Object$entries2.length; _i2++) {
-      var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-          funcName = _Object$entries2$_i[0],
-          body = _Object$entries2$_i[1];
+    for (var _i3 = 0, _Object$entries3 = Object.entries(geometryFunctions); _i3 < _Object$entries3.length; _i3++) {
+      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+          funcName = _Object$entries3$_i[0],
+          body = _Object$entries3$_i[1];
 
       var argList = body['args'];
       primitivesJS += "function " + funcName + "(";
@@ -44188,10 +44192,10 @@
     function generateGLSLWrapper(funcJSON) {
       var wrapperSrc = "";
 
-      for (var _i3 = 0, _Object$entries3 = Object.entries(funcJSON); _i3 < _Object$entries3.length; _i3++) {
-        var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-            _funcName = _Object$entries3$_i[0],
-            _body = _Object$entries3$_i[1];
+      for (var _i4 = 0, _Object$entries4 = Object.entries(funcJSON); _i4 < _Object$entries4.length; _i4++) {
+        var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+            _funcName = _Object$entries4$_i[0],
+            _body = _Object$entries4$_i[1];
 
         var _argList = _body['args'];
         var returnType = _body['ret'];
@@ -95932,23 +95936,23 @@
           // no passes defined, just render the scene
           this.renderer.render(scene, camera);
         } else {
-          var passes = Object.keys(this.passes);
-          this.renderer.setRenderTarget(this.passes[passes[0]].target);
-          this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-          this.renderer.setRenderTarget(null); // render the original scene in our first pass render target
+          var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
+          // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+          // this.renderer.setRenderTarget(null);
+          // render the original scene in our first pass render target
           // this.renderer.setRenderTarget(this.passes[passes[0]].target);
           // this.renderer.render(scene, camera);
           // render next passes
           // console.log(' numpasses', passes.length, passes)
-          // for(let i = 1; i < this.nbPasses; i++) {
-          //     console.log('rendering', this.nbPasses);
-          //     this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          //     this.renderer.render(this.passes[passes[i - 1]].scene, this.dummyCamera);
-          // }
-          // render the last pass back to the canvas
+
+          for (var i = 0; i < this.nbPasses; i++) {
+            this.renderer.setRenderTarget(this.passes[passes[i]].target);
+            this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+          } // render the last pass back to the canvas
           // TODO Check if we need this
-          // this.renderer.setRenderTarget(null);
-          // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+
+
+          this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
         }
       }
     }]);
@@ -95982,7 +95986,10 @@
   }
   function sculptToThreeJSShaderSource(source) {
     var src = sculptToGLSL(source);
+    return generateThreeJSFrag(src);
+  }
 
+  function generateThreeJSFrag(src) {
     if (src.error) {
       console.log(src.error);
     }
@@ -95997,6 +96004,27 @@
       geoGLSL: src.geoGLSL,
       colorGLSL: src.colorGLSL
     };
+  } // {buffera, bufferb, bufferc, finalImage}
+
+
+  function multiPassSculpToThreeJSMaterial(passesSources) {
+    var passes = spCodeToMultiPassGLSL(passesSources);
+    var output = {};
+
+    for (var _i = 0, _Object$entries = Object.entries(passes); _i < _Object$entries.length; _i++) {
+      var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
+          key = _Object$entries$_i[0],
+          value = _Object$entries$_i[1];
+
+      var src = generateThreeJSFrag(value);
+
+      var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
+
+      _material.uniformDescriptions = src.uniforms;
+      output[key] = _material;
+    }
+
+    return material;
   }
   function sculptToThreeJSMaterial(source, payload) {
     var src = sculptToThreeJSShaderSource(source);
@@ -96051,7 +96079,8 @@
     bufferA: {
       fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
     }
-  };
+  }; // TODO NEXT Replace sculptToThreeJSMaterial with 
+
   function createMultiPassSculpture(source) {
     var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
       return {};
@@ -96104,10 +96133,10 @@
         throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
       }
 
-      for (var _i = 0, _Object$entries = Object.entries(uniformsToUpdate); _i < _Object$entries.length; _i++) {
-        var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
-            uniform = _Object$entries$_i[0],
-            value = _Object$entries$_i[1];
+      for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
+        var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
+            uniform = _Object$entries2$_i[0],
+            value = _Object$entries2$_i[1];
 
         material.uniforms[uniform].value = value;
       } // material.uniforms['sculptureCenter'].value = geometry.position;
@@ -96146,10 +96175,10 @@
         throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
       }
 
-      for (var _i2 = 0, _Object$entries2 = Object.entries(uniformsToUpdate); _i2 < _Object$entries2.length; _i2++) {
-        var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
-            uniform = _Object$entries2$_i[0],
-            value = _Object$entries2$_i[1];
+      for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
+        var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+            uniform = _Object$entries3$_i[0],
+            value = _Object$entries3$_i[1];
 
         material.uniforms[uniform].value = value;
       } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/generators/sculpt.js b/generators/sculpt.js
index 1ace4a7..41ce3e1 100644
--- a/generators/sculpt.js
+++ b/generators/sculpt.js
@@ -197,19 +197,20 @@ export function spCodeToMultiPassGLSL(passes) {
 	if(typeof(passes) !== 'object') {
 		errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object')
 	}
-	let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = passes;
-
+	let {common, finalImage} = passes;
 	if (!common) {
 		common = '';
 	}
 	if (!finalImage) {
 		errorMsg('spCodeToMultiPassGLSL requires finalImage to be defined in the provided object');
 	}
-	return [bufferA, bufferB, bufferC, bufferD, finalImage].map(pass => {
-		if (pass) {
-			return sculptToGLSL(common + '\n' + pass)
+	let output = {};
+	for (const [key, value] of Object.entries(passes)) {
+		if(key !== 'common') {
+			output[key] = sculptToGLSL(common + '\n' + value);
 		}
-	})
+	}
+	return output;
 }
 
 export function sculptToGLSL(userProvidedSrc) {
diff --git a/targets/threeJS.js b/targets/threeJS.js
index ad97097..5ba2afa 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -1,4 +1,4 @@
-import {sculptToGLSL, baseUniforms, uniformsToGLSL} from '../generators/sculpt.js'
+import {sculptToGLSL, baseUniforms, uniformsToGLSL, spCodeToMultiPassGLSL} from '../generators/sculpt.js'
 import {
     threeJSVertexSource, 
     threeHeader,
@@ -43,22 +43,26 @@ export function glslToThreeJSMesh(source, payload) {
 
 export function sculptToThreeJSShaderSource(source) {
     const src = sculptToGLSL(source);
+    return generateThreeJSFrag(src);
+}
+
+function generateThreeJSFrag(src) {
     if (src.error) {
         console.log(src.error);
     }
     let frg = 
-          threeHeader
-        + usePBRHeader
-        + useHemisphereLight
-        + uniformsToGLSL(src.uniforms) 
-        + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n'
-        + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n'
-        + sculptureStarterCode 
-        + src.geoGLSL 
-        + '\n' 
-        + src.colorGLSL 
-        + '\n' 
-        + fragFooter;
+        threeHeader
+    + usePBRHeader
+    + useHemisphereLight
+    + uniformsToGLSL(src.uniforms) 
+    + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n'
+    + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n'
+    + sculptureStarterCode 
+    + src.geoGLSL 
+    + '\n' 
+    + src.colorGLSL 
+    + '\n' 
+    + fragFooter;
     console.log(frg)
     return {
         uniforms: src.uniforms,
@@ -69,6 +73,18 @@ export function sculptToThreeJSShaderSource(source) {
         colorGLSL: src.colorGLSL
     };
 }
+// {buffera, bufferb, bufferc, finalImage}
+export function multiPassSculpToThreeJSMaterial(passesSources) {
+    const passes = spCodeToMultiPassGLSL(passesSources);
+    let output = {};
+    for (const [key, value] of Object.entries(passes)) {
+        let src = generateThreeJSFrag(value);
+        let material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
+        material.uniformDescriptions = src.uniforms;
+        output[key] = material
+    }
+    return material;
+}
 
 export function sculptToThreeJSMaterial(source, payload) {
     let src = sculptToThreeJSShaderSource(source);
@@ -132,11 +148,10 @@ let passes = {
     }
 }
 
+// TODO NEXT Replace sculptToThreeJSMaterial with 
 export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
     
     // source = convertFunctionToString(source);
-
-    
     let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
 
     // let buffers = [bufferA, bufferB, bufferC, bufferD]
@@ -151,6 +166,7 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         let segments = ('segments' in params)? params.segments: 10;
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
+    
     let material = sculptToThreeJSMaterial(finalImage);
 
     material.uniforms['opacity'].value = 1.0;

From fb8039d90f44e04b034f0763f2f9c251f2b727b9 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 11:16:44 -0400
Subject: [PATCH 08/20] clean up

---
 targets/multiPostFX.js | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 2f64b86..5162b46 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -156,22 +156,12 @@ export class MultiPostFX {
         else {
             const passes = Object.keys(this.passes);
 
-            // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-            // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-            // this.renderer.setRenderTarget(null);
-            // render the original scene in our first pass render target
-            // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-            // this.renderer.render(scene, camera);
-
-            // render next passes
-            // console.log(' numpasses', passes.length, passes)
             for(let i = 0; i < this.nbPasses; i++) {
                 this.renderer.setRenderTarget(this.passes[passes[i]].target);
                 this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
             }
-
-            // render the last pass back to the canvas
-            // TODO Check if we need this
+            
+            // switch the renderer back to the main canvas
             this.renderer.setRenderTarget(null);
             // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
         }

From 0edec45560f434630ea1f97c73575462b10323d6 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 11:16:55 -0400
Subject: [PATCH 09/20] start using multiPassSculpToThreeJSMaterial

---
 dist/shader-park-core.cjs.js | 45 ++++++++++++++++--------------------
 dist/shader-park-core.esm.js | 45 ++++++++++++++++--------------------
 dist/shader-park-core.umd.js | 45 ++++++++++++++++--------------------
 targets/threeJS.js           | 19 ++++++++-------
 4 files changed, 69 insertions(+), 85 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index ed834ea..9c76f58 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95934,20 +95934,12 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-        // this.renderer.setRenderTarget(null);
-        // render the original scene in our first pass render target
-        // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        // this.renderer.render(scene, camera);
-        // render next passes
-        // console.log(' numpasses', passes.length, passes)
+        var passes = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
           this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
-        } // render the last pass back to the canvas
-        // TODO Check if we need this
+        } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
@@ -95992,8 +95984,8 @@ function generateThreeJSFrag(src) {
     console.log(src.error);
   }
 
-  var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
-  console.log(frg);
+  var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter; // console.log(frg)
+
   return {
     uniforms: src.uniforms,
     frag: frg,
@@ -96014,15 +96006,15 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
         key = _Object$entries$_i[0],
         value = _Object$entries$_i[1];
 
+    console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
+    var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
 
-    var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
-
-    _material.uniformDescriptions = src.uniforms;
-    output[key] = _material;
+    material.uniformDescriptions = src.uniforms;
+    output[key] = material;
   }
 
-  return material;
+  return output;
 }
 function sculptToThreeJSMaterial(source, payload) {
   var src = sculptToThreeJSShaderSource(source);
@@ -96085,13 +96077,7 @@ function createMultiPassSculpture(source) {
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
   // source = convertFunctionToString(source);
-  var common = source.common,
-      bufferA = source.bufferA,
-      bufferB = source.bufferB,
-      bufferC = source.bufferC,
-      bufferD = source.bufferD,
-      finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
-
+  // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
@@ -96102,7 +96088,16 @@ function createMultiPassSculpture(source) {
     geometry = new SphereGeometry(radius, segments, segments);
   }
 
-  var material = sculptToThreeJSMaterial(finalImage);
+  var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
+      common = _multiPassSculpToThre.common,
+      bufferA = _multiPassSculpToThre.bufferA,
+      bufferB = _multiPassSculpToThre.bufferB,
+      bufferC = _multiPassSculpToThre.bufferC,
+      bufferD = _multiPassSculpToThre.bufferD,
+      finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+
+
+  var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
   material.uniforms['mouse'].value = new Vector3();
   material.uniforms['_scale'].value = radius;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 1949d65..f1cf7d6 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95930,20 +95930,12 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-        // this.renderer.setRenderTarget(null);
-        // render the original scene in our first pass render target
-        // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-        // this.renderer.render(scene, camera);
-        // render next passes
-        // console.log(' numpasses', passes.length, passes)
+        var passes = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
           this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
-        } // render the last pass back to the canvas
-        // TODO Check if we need this
+        } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
@@ -95988,8 +95980,8 @@ function generateThreeJSFrag(src) {
     console.log(src.error);
   }
 
-  var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
-  console.log(frg);
+  var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter; // console.log(frg)
+
   return {
     uniforms: src.uniforms,
     frag: frg,
@@ -96010,15 +96002,15 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
         key = _Object$entries$_i[0],
         value = _Object$entries$_i[1];
 
+    console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
+    var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
 
-    var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
-
-    _material.uniformDescriptions = src.uniforms;
-    output[key] = _material;
+    material.uniformDescriptions = src.uniforms;
+    output[key] = material;
   }
 
-  return material;
+  return output;
 }
 function sculptToThreeJSMaterial(source, payload) {
   var src = sculptToThreeJSShaderSource(source);
@@ -96081,13 +96073,7 @@ function createMultiPassSculpture(source) {
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
   // source = convertFunctionToString(source);
-  var common = source.common,
-      bufferA = source.bufferA,
-      bufferB = source.bufferB,
-      bufferC = source.bufferC,
-      bufferD = source.bufferD,
-      finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
-
+  // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
@@ -96098,7 +96084,16 @@ function createMultiPassSculpture(source) {
     geometry = new SphereGeometry(radius, segments, segments);
   }
 
-  var material = sculptToThreeJSMaterial(finalImage);
+  var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
+      common = _multiPassSculpToThre.common,
+      bufferA = _multiPassSculpToThre.bufferA,
+      bufferB = _multiPassSculpToThre.bufferB,
+      bufferC = _multiPassSculpToThre.bufferC,
+      bufferD = _multiPassSculpToThre.bufferD,
+      finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+
+
+  var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
   material.uniforms['mouse'].value = new Vector3();
   material.uniforms['_scale'].value = radius;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 7da7080..981678b 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95936,20 +95936,12 @@
           // no passes defined, just render the scene
           this.renderer.render(scene, camera);
         } else {
-          var passes = Object.keys(this.passes); // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-          // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
-          // this.renderer.setRenderTarget(null);
-          // render the original scene in our first pass render target
-          // this.renderer.setRenderTarget(this.passes[passes[0]].target);
-          // this.renderer.render(scene, camera);
-          // render next passes
-          // console.log(' numpasses', passes.length, passes)
+          var passes = Object.keys(this.passes);
 
           for (var i = 0; i < this.nbPasses; i++) {
             this.renderer.setRenderTarget(this.passes[passes[i]].target);
             this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
-          } // render the last pass back to the canvas
-          // TODO Check if we need this
+          } // switch the renderer back to the main canvas
 
 
           this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
@@ -95994,8 +95986,8 @@
       console.log(src.error);
     }
 
-    var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter;
-    console.log(frg);
+    var frg = threeHeader + usePBRHeader + useHemisphereLight + uniformsToGLSL(src.uniforms) + 'const float STEP_SIZE_CONSTANT = ' + src.stepSizeConstant + ';\n' + 'const int MAX_ITERATIONS = ' + src.maxIterations + ';\n' + sculptureStarterCode + src.geoGLSL + '\n' + src.colorGLSL + '\n' + fragFooter; // console.log(frg)
+
     return {
       uniforms: src.uniforms,
       frag: frg,
@@ -96016,15 +96008,15 @@
           key = _Object$entries$_i[0],
           value = _Object$entries$_i[1];
 
+      console.log('keyval', key, value);
       var src = generateThreeJSFrag(value);
+      var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
 
-      var _material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
-
-      _material.uniformDescriptions = src.uniforms;
-      output[key] = _material;
+      material.uniformDescriptions = src.uniforms;
+      output[key] = material;
     }
 
-    return material;
+    return output;
   }
   function sculptToThreeJSMaterial(source, payload) {
     var src = sculptToThreeJSShaderSource(source);
@@ -96087,13 +96079,7 @@
     };
     var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
     // source = convertFunctionToString(source);
-    var common = source.common,
-        bufferA = source.bufferA,
-        bufferB = source.bufferB,
-        bufferC = source.bufferC,
-        bufferD = source.bufferD,
-        finalImage = source.finalImage; // let buffers = [bufferA, bufferB, bufferC, bufferD]
-
+    // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
     var radius = 'radius' in params ? params.radius : 2;
     var geometry;
 
@@ -96104,7 +96090,16 @@
       geometry = new SphereGeometry(radius, segments, segments);
     }
 
-    var material = sculptToThreeJSMaterial(finalImage);
+    var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
+        common = _multiPassSculpToThre.common,
+        bufferA = _multiPassSculpToThre.bufferA,
+        bufferB = _multiPassSculpToThre.bufferB,
+        bufferC = _multiPassSculpToThre.bufferC,
+        bufferD = _multiPassSculpToThre.bufferD,
+        finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+
+
+    var material = finalImage;
     material.uniforms['opacity'].value = 1.0;
     material.uniforms['mouse'].value = new Vector3();
     material.uniforms['_scale'].value = radius;
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 5ba2afa..3659c7a 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -63,7 +63,7 @@ function generateThreeJSFrag(src) {
     + src.colorGLSL 
     + '\n' 
     + fragFooter;
-    console.log(frg)
+    // console.log(frg)
     return {
         uniforms: src.uniforms,
         frag: frg,
@@ -78,12 +78,14 @@ export function multiPassSculpToThreeJSMaterial(passesSources) {
     const passes = spCodeToMultiPassGLSL(passesSources);
     let output = {};
     for (const [key, value] of Object.entries(passes)) {
+        console.log('keyval', key, value)
         let src = generateThreeJSFrag(value);
-        let material = makeMaterial(src.uniforms, src.vert, src.frag, payload);
+        let material = makeMaterial(src.uniforms, src.vert, src.frag);
+        // console.log(src, material);
         material.uniformDescriptions = src.uniforms;
         output[key] = material
     }
-    return material;
+    return output;
 }
 
 export function sculptToThreeJSMaterial(source, payload) {
@@ -152,10 +154,7 @@ let passes = {
 export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
     
     // source = convertFunctionToString(source);
-    let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
-
-    // let buffers = [bufferA, bufferB, bufferC, bufferD]
-
+    // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
 
     let radius = ('radius' in params)? params.radius: 2;
 
@@ -166,9 +165,9 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         let segments = ('segments' in params)? params.segments: 10;
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
-    
-    let material = sculptToThreeJSMaterial(finalImage);
-
+    let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
+    // let material = sculptToThreeJSMaterial(finalImage);
+    let material = finalImage;
     material.uniforms['opacity'].value = 1.0;
     material.uniforms['mouse'].value = new Vector3();
     material.uniforms['_scale'].value = radius;

From 508e0216647ee3ab2196c227da42d2c9c9176d81 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 22:20:41 -0400
Subject: [PATCH 10/20] prep for SP bufferA

---
 dist/shader-park-core.cjs.js | 55 +++++++++++++++++++++++++++---------
 dist/shader-park-core.esm.js | 55 +++++++++++++++++++++++++++---------
 dist/shader-park-core.umd.js | 55 +++++++++++++++++++++++++++---------
 targets/multiPostFX.js       | 22 ++++++++++++++-
 targets/threeJS.js           | 25 ++++++++++------
 5 files changed, 163 insertions(+), 49 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 9c76f58..2d692ee 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95865,7 +95865,8 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-    this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+    this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
+
     this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
@@ -95897,6 +95898,24 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         uResolution: {
           value: this.resolution
+        },
+        opacity: {
+          value: 1.0
+        },
+        mouse: {
+          value: new Vector3()
+        },
+        _scale: {
+          value: 2.0
+        },
+        time: {
+          value: 0.0
+        },
+        stepSize: {
+          value: 0.85
+        },
+        resolution: {
+          value: this.resolution
         }
       }; // merge default uniforms with params
 
@@ -95907,7 +95926,9 @@ var MultiPostFX = /*#__PURE__*/function () {
       pass.material = new RawShaderMaterial({
         fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
         vertexShader: passParams.vertexShader || this.defaultVertexShader,
-        uniforms: uniforms
+        uniforms: uniforms // transparent: true,
+        // side: BackSide
+
       });
       pass.mesh = new Mesh(this.geometry, pass.material);
       pass.mesh.frustumCulled = false;
@@ -95943,6 +95964,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96008,12 +96030,14 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
 
     console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
-    var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
-
-    material.uniformDescriptions = src.uniforms;
-    output[key] = material;
+    output[key] = src;
   }
 
+  console.log(output);
+  var finalImage = output['finalImage'];
+  var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
+  material.uniformDescriptions = finalImage.uniforms;
+  output['finalImage'] = material;
   return output;
 }
 function sculptToThreeJSMaterial(source, payload) {
@@ -96094,8 +96118,15 @@ function createMultiPassSculpture(source) {
       bufferB = _multiPassSculpToThre.bufferB,
       bufferC = _multiPassSculpToThre.bufferC,
       bufferD = _multiPassSculpToThre.bufferD,
-      finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+      finalImage = _multiPassSculpToThre.finalImage;
 
+  console.log('buffA', bufferA); // let passes = {
+  //     bufferA: {
+  //         // '#version 300 es\n' +'precision highp float;\n'+
+  //         fragmentShader: bufferA.frag,
+  //     }
+  // }
+  // let material = sculptToThreeJSMaterial(finalImage);
 
   var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
@@ -96109,14 +96140,12 @@ function createMultiPassSculpture(source) {
       multiPost = new MultiPostFX({
         renderer: renderer,
         passes: passes
-      });
-      console.log(multiPost);
+      }); // console.log(multiPost)
     } else {
       multiPost.render(scene, camera);
 
       if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-        console.log('setting buffA', material.uniforms['bufferA'].value);
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
       }
     }
 
@@ -96224,8 +96253,8 @@ function makeMaterial(unifs, vert, frag, payload) {
     fragmentShader: frag,
     transparent: true,
     side: BackSide
-  });
-  material.extensions.fragDepth = false;
+  }); // material.extensions.fragDepth = false;
+
   return material;
 } // There should be more options supported like size and shape
 
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index f1cf7d6..f5edf82 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95861,7 +95861,8 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-    this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+    this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
+
     this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
@@ -95893,6 +95894,24 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         uResolution: {
           value: this.resolution
+        },
+        opacity: {
+          value: 1.0
+        },
+        mouse: {
+          value: new Vector3()
+        },
+        _scale: {
+          value: 2.0
+        },
+        time: {
+          value: 0.0
+        },
+        stepSize: {
+          value: 0.85
+        },
+        resolution: {
+          value: this.resolution
         }
       }; // merge default uniforms with params
 
@@ -95903,7 +95922,9 @@ var MultiPostFX = /*#__PURE__*/function () {
       pass.material = new RawShaderMaterial({
         fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
         vertexShader: passParams.vertexShader || this.defaultVertexShader,
-        uniforms: uniforms
+        uniforms: uniforms // transparent: true,
+        // side: BackSide
+
       });
       pass.mesh = new Mesh(this.geometry, pass.material);
       pass.mesh.frustumCulled = false;
@@ -95939,6 +95960,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96004,12 +96026,14 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
 
     console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
-    var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
-
-    material.uniformDescriptions = src.uniforms;
-    output[key] = material;
+    output[key] = src;
   }
 
+  console.log(output);
+  var finalImage = output['finalImage'];
+  var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
+  material.uniformDescriptions = finalImage.uniforms;
+  output['finalImage'] = material;
   return output;
 }
 function sculptToThreeJSMaterial(source, payload) {
@@ -96090,8 +96114,15 @@ function createMultiPassSculpture(source) {
       bufferB = _multiPassSculpToThre.bufferB,
       bufferC = _multiPassSculpToThre.bufferC,
       bufferD = _multiPassSculpToThre.bufferD,
-      finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+      finalImage = _multiPassSculpToThre.finalImage;
 
+  console.log('buffA', bufferA); // let passes = {
+  //     bufferA: {
+  //         // '#version 300 es\n' +'precision highp float;\n'+
+  //         fragmentShader: bufferA.frag,
+  //     }
+  // }
+  // let material = sculptToThreeJSMaterial(finalImage);
 
   var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
@@ -96105,14 +96136,12 @@ function createMultiPassSculpture(source) {
       multiPost = new MultiPostFX({
         renderer: renderer,
         passes: passes
-      });
-      console.log(multiPost);
+      }); // console.log(multiPost)
     } else {
       multiPost.render(scene, camera);
 
       if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-        console.log('setting buffA', material.uniforms['bufferA'].value);
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
       }
     }
 
@@ -96220,8 +96249,8 @@ function makeMaterial(unifs, vert, frag, payload) {
     fragmentShader: frag,
     transparent: true,
     side: BackSide
-  });
-  material.extensions.fragDepth = false;
+  }); // material.extensions.fragDepth = false;
+
   return material;
 } // There should be more options supported like size and shape
 
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 981678b..50c0489 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95867,7 +95867,8 @@
       this.resolution = new Vector2();
       this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-      this.defaultVertexShader = "\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        ";
+      this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
+
       this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
       this.nbPasses = 0;
@@ -95899,6 +95900,24 @@
           },
           uResolution: {
             value: this.resolution
+          },
+          opacity: {
+            value: 1.0
+          },
+          mouse: {
+            value: new Vector3()
+          },
+          _scale: {
+            value: 2.0
+          },
+          time: {
+            value: 0.0
+          },
+          stepSize: {
+            value: 0.85
+          },
+          resolution: {
+            value: this.resolution
           }
         }; // merge default uniforms with params
 
@@ -95909,7 +95928,9 @@
         pass.material = new RawShaderMaterial({
           fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
           vertexShader: passParams.vertexShader || this.defaultVertexShader,
-          uniforms: uniforms
+          uniforms: uniforms // transparent: true,
+          // side: BackSide
+
         });
         pass.mesh = new Mesh(this.geometry, pass.material);
         pass.mesh.frustumCulled = false;
@@ -95945,6 +95966,7 @@
 
 
           this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+          // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
       }
     }]);
@@ -96010,12 +96032,14 @@
 
       console.log('keyval', key, value);
       var src = generateThreeJSFrag(value);
-      var material = makeMaterial(src.uniforms, src.vert, src.frag); // console.log(src, material);
-
-      material.uniformDescriptions = src.uniforms;
-      output[key] = material;
+      output[key] = src;
     }
 
+    console.log(output);
+    var finalImage = output['finalImage'];
+    var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
+    material.uniformDescriptions = finalImage.uniforms;
+    output['finalImage'] = material;
     return output;
   }
   function sculptToThreeJSMaterial(source, payload) {
@@ -96096,8 +96120,15 @@
         bufferB = _multiPassSculpToThre.bufferB,
         bufferC = _multiPassSculpToThre.bufferC,
         bufferD = _multiPassSculpToThre.bufferD,
-        finalImage = _multiPassSculpToThre.finalImage; // let material = sculptToThreeJSMaterial(finalImage);
+        finalImage = _multiPassSculpToThre.finalImage;
 
+    console.log('buffA', bufferA); // let passes = {
+    //     bufferA: {
+    //         // '#version 300 es\n' +'precision highp float;\n'+
+    //         fragmentShader: bufferA.frag,
+    //     }
+    // }
+    // let material = sculptToThreeJSMaterial(finalImage);
 
     var material = finalImage;
     material.uniforms['opacity'].value = 1.0;
@@ -96111,14 +96142,12 @@
         multiPost = new MultiPostFX({
           renderer: renderer,
           passes: passes
-        });
-        console.log(multiPost);
+        }); // console.log(multiPost)
       } else {
         multiPost.render(scene, camera);
 
         if ('bufferA' in material.uniforms) {
-          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-          console.log('setting buffA', material.uniforms['bufferA'].value);
+          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
         }
       }
 
@@ -96226,8 +96255,8 @@
       fragmentShader: frag,
       transparent: true,
       side: BackSide
-    });
-    material.extensions.fragDepth = false;
+    }); // material.extensions.fragDepth = false;
+
     return material;
   } // There should be more options supported like size and shape
 
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 5162b46..716d15c 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -25,6 +25,10 @@
  *
  */
 
+ import {
+    threeJSVertexSource, 
+} from '../glsl/glsl-lib.js'
+
 import {
     WebGLRenderTarget,
     OrthographicCamera,
@@ -33,8 +37,11 @@ import {
     BufferAttribute,
     Mesh,
     Scene,
+    ShaderMaterial,
     RawShaderMaterial,
     Vector2,
+    Vector3,
+    BackSide
 } from 'three';
 
 /**
@@ -73,12 +80,14 @@ export class MultiPostFX {
 
         // default shaders
         this.defaultVertexShader = `
+
             precision highp float;
             attribute vec2 position;
             void main() {
                 gl_Position = vec4(position, 1.0, 1.0);
             }
         `;
+        // this.defaultVertexShader = threeJSVertexSource;
 
         this.defaultFragmentShader = `
             precision highp float;
@@ -115,6 +124,13 @@ export class MultiPostFX {
         let uniforms = {
             uScene: { value: pass.target.texture },
             uResolution: { value: this.resolution },
+            opacity: { value:  1.0},
+            mouse: { value:  new Vector3()},
+            _scale: { value:  2.0},
+            time: {value: 0.0},
+            stepSize: {value: 0.85},
+            resolution: {value: this.resolution}
+
         };
 
         // merge default uniforms with params
@@ -125,8 +141,11 @@ export class MultiPostFX {
         pass.material = new RawShaderMaterial({
             fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
             vertexShader: passParams.vertexShader || this.defaultVertexShader,
-            uniforms: uniforms
+            uniforms: uniforms,
+            // transparent: true,
+            // side: BackSide
         });
+        
 
         pass.mesh = new Mesh(this.geometry, pass.material);
         pass.mesh.frustumCulled = false;
@@ -164,6 +183,7 @@ export class MultiPostFX {
             // switch the renderer back to the main canvas
             this.renderer.setRenderTarget(null);
             // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
+            // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
     }
 }
\ No newline at end of file
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 3659c7a..cadcf3f 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -80,11 +80,13 @@ export function multiPassSculpToThreeJSMaterial(passesSources) {
     for (const [key, value] of Object.entries(passes)) {
         console.log('keyval', key, value)
         let src = generateThreeJSFrag(value);
-        let material = makeMaterial(src.uniforms, src.vert, src.frag);
-        // console.log(src, material);
-        material.uniformDescriptions = src.uniforms;
-        output[key] = material
+        output[key] = src;
     }
+    console.log(output)
+    let finalImage = output['finalImage'];
+    let material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
+    material.uniformDescriptions = finalImage.uniforms;
+    output['finalImage'] = material;
     return output;
 }
 
@@ -166,6 +168,13 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
     let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
+    console.log('buffA', bufferA);
+    // let passes = {
+    //     bufferA: {
+    //         // '#version 300 es\n' +'precision highp float;\n'+
+    //         fragmentShader: bufferA.frag,
+    //     }
+    // }
     // let material = sculptToThreeJSMaterial(finalImage);
     let material = finalImage;
     material.uniforms['opacity'].value = 1.0;
@@ -180,14 +189,12 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
                 renderer,
                 passes
             });
-            console.log(multiPost)
+            // console.log(multiPost)
         } else {
             multiPost.render(scene, camera);
-            
             if('bufferA' in material.uniforms) {
-                
                 material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-                console.log('setting buffA', material.uniforms['bufferA'].value)
+                // console.log('setting buffA', material.uniforms['bufferA'].value)
             }
         }
         let uniformsToUpdate = uniformCallback();
@@ -270,7 +277,7 @@ function makeMaterial(unifs, vert, frag, payload) {
         transparent: true,
         side: BackSide
     });
-    material.extensions.fragDepth = false;
+    // material.extensions.fragDepth = false;
     return material;
 }
 

From 0989a24ed9f66b65b9bacc44f536da5da35231f0 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 22:31:11 -0400
Subject: [PATCH 11/20] switch from uresolution to resolution

---
 dist/shader-park-core.cjs.js | 11 ++++-------
 dist/shader-park-core.esm.js | 11 ++++-------
 dist/shader-park-core.umd.js | 11 ++++-------
 targets/multiPostFX.js       | 11 ++++-------
 targets/threeJS.js           |  4 ++--
 5 files changed, 18 insertions(+), 30 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 2d692ee..9e2d625 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95867,7 +95867,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
     this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
 
-    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
     this.passes = {};
@@ -95896,7 +95896,7 @@ var MultiPostFX = /*#__PURE__*/function () {
         uScene: {
           value: pass.target.texture
         },
-        uResolution: {
+        resolution: {
           value: this.resolution
         },
         opacity: {
@@ -95913,9 +95913,6 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         stepSize: {
           value: 0.85
-        },
-        resolution: {
-          value: this.resolution
         }
       }; // merge default uniforms with params
 
@@ -95945,7 +95942,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
       for (var i = 0; i < this.nbPasses; i++) {
         this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
-        this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+        this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
       }
     }
   }, {
@@ -96091,7 +96088,7 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 
 var passes = {
   bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
 }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index f5edf82..c061351 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95863,7 +95863,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
     this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
 
-    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
     this.passes = {};
@@ -95892,7 +95892,7 @@ var MultiPostFX = /*#__PURE__*/function () {
         uScene: {
           value: pass.target.texture
         },
-        uResolution: {
+        resolution: {
           value: this.resolution
         },
         opacity: {
@@ -95909,9 +95909,6 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         stepSize: {
           value: 0.85
-        },
-        resolution: {
-          value: this.resolution
         }
       }; // merge default uniforms with params
 
@@ -95941,7 +95938,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
       for (var i = 0; i < this.nbPasses; i++) {
         this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
-        this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+        this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
       }
     }
   }, {
@@ -96087,7 +96084,7 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 
 var passes = {
   bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
 }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 50c0489..07e9cc2 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95869,7 +95869,7 @@
 
       this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
 
-      this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / uResolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+      this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
 
       this.nbPasses = 0;
       this.passes = {};
@@ -95898,7 +95898,7 @@
           uScene: {
             value: pass.target.texture
           },
-          uResolution: {
+          resolution: {
             value: this.resolution
           },
           opacity: {
@@ -95915,9 +95915,6 @@
           },
           stepSize: {
             value: 0.85
-          },
-          resolution: {
-            value: this.resolution
           }
         }; // merge default uniforms with params
 
@@ -95947,7 +95944,7 @@
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
-          this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+          this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
         }
       }
     }, {
@@ -96093,7 +96090,7 @@
 
   var passes = {
     bufferA: {
-      fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 uResolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+      fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
     }
   }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 716d15c..3915a9c 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -92,9 +92,9 @@ export class MultiPostFX {
         this.defaultFragmentShader = `
             precision highp float;
             uniform sampler2D uScene;
-            uniform vec2 uResolution;
+            uniform vec2 resolution;
             void main() {
-                vec2 uv = gl_FragCoord.xy / uResolution.xy;
+                vec2 uv = gl_FragCoord.xy / resolution.xy;
                 gl_FragColor = texture2D(uScene, uv);
             }
         `;
@@ -123,14 +123,12 @@ export class MultiPostFX {
 
         let uniforms = {
             uScene: { value: pass.target.texture },
-            uResolution: { value: this.resolution },
+            resolution: { value: this.resolution },
             opacity: { value:  1.0},
             mouse: { value:  new Vector3()},
             _scale: { value:  2.0},
             time: {value: 0.0},
             stepSize: {value: 0.85},
-            resolution: {value: this.resolution}
-
         };
 
         // merge default uniforms with params
@@ -163,7 +161,7 @@ export class MultiPostFX {
         const passes = Object.keys(this.passes);
         for(let i = 0; i < this.nbPasses; i++) {
             this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
-            this.passes[passes[i]].material.uniforms.uResolution.value = this.resolution;
+            this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
         }
     }
 
@@ -174,7 +172,6 @@ export class MultiPostFX {
         }
         else {
             const passes = Object.keys(this.passes);
-
             for(let i = 0; i < this.nbPasses; i++) {
                 this.renderer.setRenderTarget(this.passes[passes[i]].target);
                 this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
diff --git a/targets/threeJS.js b/targets/threeJS.js
index cadcf3f..1df66a4 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -142,10 +142,10 @@ let passes = {
         fragmentShader: `
             precision highp float;
             uniform sampler2D uScene;
-            uniform vec2 uResolution;
+            uniform vec2 resolution;
             
             void main() {
-                vec4 color = vec4(gl_FragCoord.xy / uResolution.xy, 1., 1.);
+                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
                 gl_FragColor = color;
             }
         `,

From fe3b6cc746bd1a863793ae931e1a56be56347ba2 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Mon, 21 Mar 2022 23:01:38 -0400
Subject: [PATCH 12/20] start to convert default vertex towards three default
 shader + use ShaderMaterial

---
 dist/shader-park-core.cjs.js | 29 +++++++++++++++++++----------
 dist/shader-park-core.esm.js | 29 +++++++++++++++++++----------
 dist/shader-park-core.umd.js | 29 +++++++++++++++++++----------
 targets/multiPostFX.js       | 35 +++++++++++++++++++++++++----------
 targets/threeJS.js           |  1 -
 5 files changed, 82 insertions(+), 41 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 9e2d625..9856892 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95865,9 +95865,20 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-    this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
-
-    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+    // //varying vec2 vUv;
+    // varying vec3 sculptureCenter;
+    // void main()
+    // {
+    //     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+    //     worldPos = modelMatrix*vec4(position,1.0);
+    //     sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
+    //     //vUv = uv;
+    //     gl_Position = projectionMatrix * mvPosition;
+    // }        
+    // this.defaultVertexShader = threeJSVertexSource;
+
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
     this.passes = {};
@@ -95893,9 +95904,7 @@ var MultiPostFX = /*#__PURE__*/function () {
         })
       };
       var uniforms = {
-        uScene: {
-          value: pass.target.texture
-        },
+        // uScene: { value: pass.target.texture },
         resolution: {
           value: this.resolution
         },
@@ -95920,11 +95929,11 @@ var MultiPostFX = /*#__PURE__*/function () {
         uniforms = Object.assign(uniforms, passParams.uniforms);
       }
 
-      pass.material = new RawShaderMaterial({
+      pass.material = new ShaderMaterial({
         fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
         vertexShader: passParams.vertexShader || this.defaultVertexShader,
-        uniforms: uniforms // transparent: true,
-        // side: BackSide
+        uniforms: uniforms,
+        transparent: true // side: BackSide
 
       });
       pass.mesh = new Mesh(this.geometry, pass.material);
@@ -96088,7 +96097,7 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 
 var passes = {
   bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+    fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
 }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index c061351..82ffac1 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95861,9 +95861,20 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-    this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
-
-    this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+    // //varying vec2 vUv;
+    // varying vec3 sculptureCenter;
+    // void main()
+    // {
+    //     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+    //     worldPos = modelMatrix*vec4(position,1.0);
+    //     sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
+    //     //vUv = uv;
+    //     gl_Position = projectionMatrix * mvPosition;
+    // }        
+    // this.defaultVertexShader = threeJSVertexSource;
+
+    this.defaultFragmentShader = "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "; // add our passes
 
     this.nbPasses = 0;
     this.passes = {};
@@ -95889,9 +95900,7 @@ var MultiPostFX = /*#__PURE__*/function () {
         })
       };
       var uniforms = {
-        uScene: {
-          value: pass.target.texture
-        },
+        // uScene: { value: pass.target.texture },
         resolution: {
           value: this.resolution
         },
@@ -95916,11 +95925,11 @@ var MultiPostFX = /*#__PURE__*/function () {
         uniforms = Object.assign(uniforms, passParams.uniforms);
       }
 
-      pass.material = new RawShaderMaterial({
+      pass.material = new ShaderMaterial({
         fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
         vertexShader: passParams.vertexShader || this.defaultVertexShader,
-        uniforms: uniforms // transparent: true,
-        // side: BackSide
+        uniforms: uniforms,
+        transparent: true // side: BackSide
 
       });
       pass.mesh = new Mesh(this.geometry, pass.material);
@@ -96084,7 +96093,7 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 
 var passes = {
   bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+    fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
   }
 }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 07e9cc2..b8bdd79 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95867,9 +95867,20 @@
       this.resolution = new Vector2();
       this.renderer.getDrawingBufferSize(this.resolution); // default shaders
 
-      this.defaultVertexShader = "\n\n            precision highp float;\n            attribute vec2 position;\n            void main() {\n                gl_Position = vec4(position, 1.0, 1.0);\n            }\n        "; // this.defaultVertexShader = threeJSVertexSource;
-
-      this.defaultFragmentShader = "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            void main() {\n                vec2 uv = gl_FragCoord.xy / resolution.xy;\n                gl_FragColor = texture2D(uScene, uv);\n            }\n        "; // add our passes
+      this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+      // //varying vec2 vUv;
+      // varying vec3 sculptureCenter;
+      // void main()
+      // {
+      //     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+      //     worldPos = modelMatrix*vec4(position,1.0);
+      //     sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
+      //     //vUv = uv;
+      //     gl_Position = projectionMatrix * mvPosition;
+      // }        
+      // this.defaultVertexShader = threeJSVertexSource;
+
+      this.defaultFragmentShader = "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "; // add our passes
 
       this.nbPasses = 0;
       this.passes = {};
@@ -95895,9 +95906,7 @@
           })
         };
         var uniforms = {
-          uScene: {
-            value: pass.target.texture
-          },
+          // uScene: { value: pass.target.texture },
           resolution: {
             value: this.resolution
           },
@@ -95922,11 +95931,11 @@
           uniforms = Object.assign(uniforms, passParams.uniforms);
         }
 
-        pass.material = new RawShaderMaterial({
+        pass.material = new ShaderMaterial({
           fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
           vertexShader: passParams.vertexShader || this.defaultVertexShader,
-          uniforms: uniforms // transparent: true,
-          // side: BackSide
+          uniforms: uniforms,
+          transparent: true // side: BackSide
 
         });
         pass.mesh = new Mesh(this.geometry, pass.material);
@@ -96090,7 +96099,7 @@
 
   var passes = {
     bufferA: {
-      fragmentShader: "\n            precision highp float;\n            uniform sampler2D uScene;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
+      fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
     }
   }; // TODO NEXT Replace sculptToThreeJSMaterial with 
 
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 3915a9c..fd5fec3 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -80,22 +80,37 @@ export class MultiPostFX {
 
         // default shaders
         this.defaultVertexShader = `
-
-            precision highp float;
-            attribute vec2 position;
+            varying vec4 worldPos;
+            varying vec3 sculptureCenter;
+            // precision highp float;
+            // attribute vec2 position;
             void main() {
-                gl_Position = vec4(position, 1.0, 1.0);
+                worldPos = modelMatrix*vec4(position,1.0);
+                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
+                gl_Position = vec4(position, 1.0);
             }
         `;
+
+        // varying vec4 worldPos;
+        // //varying vec2 vUv;
+        // varying vec3 sculptureCenter;
+        // void main()
+        // {
+        //     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+        //     worldPos = modelMatrix*vec4(position,1.0);
+        //     sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
+        //     //vUv = uv;
+        //     gl_Position = projectionMatrix * mvPosition;
+        // }        
         // this.defaultVertexShader = threeJSVertexSource;
 
         this.defaultFragmentShader = `
             precision highp float;
-            uniform sampler2D uScene;
             uniform vec2 resolution;
+            
             void main() {
-                vec2 uv = gl_FragCoord.xy / resolution.xy;
-                gl_FragColor = texture2D(uScene, uv);
+                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+                gl_FragColor = color;
             }
         `;
 
@@ -122,7 +137,7 @@ export class MultiPostFX {
         };
 
         let uniforms = {
-            uScene: { value: pass.target.texture },
+            // uScene: { value: pass.target.texture },
             resolution: { value: this.resolution },
             opacity: { value:  1.0},
             mouse: { value:  new Vector3()},
@@ -136,11 +151,11 @@ export class MultiPostFX {
             uniforms = Object.assign(uniforms, passParams.uniforms);
         }
 
-        pass.material = new RawShaderMaterial({
+        pass.material = new ShaderMaterial({
             fragmentShader: passParams.fragmentShader || this.defaultFragmentShader,
             vertexShader: passParams.vertexShader || this.defaultVertexShader,
             uniforms: uniforms,
-            // transparent: true,
+            transparent: true,
             // side: BackSide
         });
         
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 1df66a4..6e0fb14 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -141,7 +141,6 @@ let passes = {
     bufferA: {
         fragmentShader: `
             precision highp float;
-            uniform sampler2D uScene;
             uniform vec2 resolution;
             
             void main() {

From 0bbbec18ea38791ec52b2b7ac7bd34b65c540f48 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Tue, 22 Mar 2022 00:35:29 -0400
Subject: [PATCH 13/20] working w/ 1 buffer

---
 dist/shader-park-core.cjs.js | 48 +++++++++++++++++++++++-------------
 dist/shader-park-core.esm.js | 48 +++++++++++++++++++++++-------------
 dist/shader-park-core.umd.js | 48 +++++++++++++++++++++++-------------
 targets/multiPostFX.js       |  8 +++---
 targets/threeJS.js           | 44 +++++++++++++++++++--------------
 5 files changed, 123 insertions(+), 73 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 9856892..76a9707 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95856,8 +95856,8 @@ var MultiPostFX = /*#__PURE__*/function () {
 
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+    // this.dummyCamera = new OrthographicCamera();
 
-    this.dummyCamera = new OrthographicCamera();
     this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
 
     var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
@@ -95965,12 +95965,12 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+          this.renderer.render(this.passes[passes[i]].scene, camera);
         } // switch the renderer back to the main canvas
 
 
-        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
-        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
+        // this.renderer.render(this.passes[passes[0]].scene, camera);
       }
     }
   }]);
@@ -96094,12 +96094,19 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 //         `,
 //     }
 // }
-
-var passes = {
-  bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
-  }
-}; // TODO NEXT Replace sculptToThreeJSMaterial with 
+// let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform vec2 resolution;
+//             void main() {
+//                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
+// TODO NEXT Replace sculptToThreeJSMaterial with 
 
 function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
@@ -96126,13 +96133,20 @@ function createMultiPassSculpture(source) {
       bufferD = _multiPassSculpToThre.bufferD,
       finalImage = _multiPassSculpToThre.finalImage;
 
-  console.log('buffA', bufferA); // let passes = {
-  //     bufferA: {
-  //         // '#version 300 es\n' +'precision highp float;\n'+
-  //         fragmentShader: bufferA.frag,
-  //     }
-  // }
-  // let material = sculptToThreeJSMaterial(finalImage);
+  console.log('buffA', bufferA);
+  var passes = {
+    bufferA: {
+      fragmentShader: bufferA.frag //             fragmentShader: `
+      //             precision highp float;
+      //             uniform vec2 resolution;
+      //             void main() {
+      //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+      //                 gl_FragColor = color;
+      //             }
+      //         `,
+
+    }
+  }; // let material = sculptToThreeJSMaterial(finalImage);
 
   var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 82ffac1..310be96 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95852,8 +95852,8 @@ var MultiPostFX = /*#__PURE__*/function () {
 
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+    // this.dummyCamera = new OrthographicCamera();
 
-    this.dummyCamera = new OrthographicCamera();
     this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
 
     var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
@@ -95961,12 +95961,12 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+          this.renderer.render(this.passes[passes[i]].scene, camera);
         } // switch the renderer back to the main canvas
 
 
-        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
-        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
+        // this.renderer.render(this.passes[passes[0]].scene, camera);
       }
     }
   }]);
@@ -96090,12 +96090,19 @@ function createMultiPassSculptureWithGeometry(geometry, source) {
 //         `,
 //     }
 // }
-
-var passes = {
-  bufferA: {
-    fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
-  }
-}; // TODO NEXT Replace sculptToThreeJSMaterial with 
+// let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform vec2 resolution;
+//             void main() {
+//                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
+// TODO NEXT Replace sculptToThreeJSMaterial with 
 
 function createMultiPassSculpture(source) {
   var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
@@ -96122,13 +96129,20 @@ function createMultiPassSculpture(source) {
       bufferD = _multiPassSculpToThre.bufferD,
       finalImage = _multiPassSculpToThre.finalImage;
 
-  console.log('buffA', bufferA); // let passes = {
-  //     bufferA: {
-  //         // '#version 300 es\n' +'precision highp float;\n'+
-  //         fragmentShader: bufferA.frag,
-  //     }
-  // }
-  // let material = sculptToThreeJSMaterial(finalImage);
+  console.log('buffA', bufferA);
+  var passes = {
+    bufferA: {
+      fragmentShader: bufferA.frag //             fragmentShader: `
+      //             precision highp float;
+      //             uniform vec2 resolution;
+      //             void main() {
+      //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+      //                 gl_FragColor = color;
+      //             }
+      //         `,
+
+    }
+  }; // let material = sculptToThreeJSMaterial(finalImage);
 
   var material = finalImage;
   material.uniforms['opacity'].value = 1.0;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index b8bdd79..521bb60 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95858,8 +95858,8 @@
 
       this.renderer = params.renderer;
       if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
+      // this.dummyCamera = new OrthographicCamera();
 
-      this.dummyCamera = new OrthographicCamera();
       this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
 
       var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
@@ -95967,12 +95967,12 @@
 
           for (var i = 0; i < this.nbPasses; i++) {
             this.renderer.setRenderTarget(this.passes[passes[i]].target);
-            this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+            this.renderer.render(this.passes[passes[i]].scene, camera);
           } // switch the renderer back to the main canvas
 
 
-          this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
-          // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+          this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
+          // this.renderer.render(this.passes[passes[0]].scene, camera);
         }
       }
     }]);
@@ -96096,12 +96096,19 @@
   //         `,
   //     }
   // }
-
-  var passes = {
-    bufferA: {
-      fragmentShader: "\n            precision highp float;\n            uniform vec2 resolution;\n            \n            void main() {\n                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);\n                gl_FragColor = color;\n            }\n        "
-    }
-  }; // TODO NEXT Replace sculptToThreeJSMaterial with 
+  // let passes = {
+  //     bufferA: {
+  //         fragmentShader: `
+  //             precision highp float;
+  //             uniform vec2 resolution;
+  //             void main() {
+  //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+  //                 gl_FragColor = color;
+  //             }
+  //         `,
+  //     }
+  // }
+  // TODO NEXT Replace sculptToThreeJSMaterial with 
 
   function createMultiPassSculpture(source) {
     var uniformCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
@@ -96128,13 +96135,20 @@
         bufferD = _multiPassSculpToThre.bufferD,
         finalImage = _multiPassSculpToThre.finalImage;
 
-    console.log('buffA', bufferA); // let passes = {
-    //     bufferA: {
-    //         // '#version 300 es\n' +'precision highp float;\n'+
-    //         fragmentShader: bufferA.frag,
-    //     }
-    // }
-    // let material = sculptToThreeJSMaterial(finalImage);
+    console.log('buffA', bufferA);
+    var passes = {
+      bufferA: {
+        fragmentShader: bufferA.frag //             fragmentShader: `
+        //             precision highp float;
+        //             uniform vec2 resolution;
+        //             void main() {
+        //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+        //                 gl_FragColor = color;
+        //             }
+        //         `,
+
+      }
+    }; // let material = sculptToThreeJSMaterial(finalImage);
 
     var material = finalImage;
     material.uniforms['opacity'].value = 1.0;
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index fd5fec3..e2a1a97 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -63,7 +63,7 @@ export class MultiPostFX {
         if(!this.renderer) return;
 
         // three.js for .render() wants a camera, even if we're not using it :(
-        this.dummyCamera = new OrthographicCamera();
+        // this.dummyCamera = new OrthographicCamera();
         this.geometry = new BufferGeometry();
 
         // Triangle expressed in clip space coordinates
@@ -189,13 +189,13 @@ export class MultiPostFX {
             const passes = Object.keys(this.passes);
             for(let i = 0; i < this.nbPasses; i++) {
                 this.renderer.setRenderTarget(this.passes[passes[i]].target);
-                this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+                this.renderer.render(this.passes[passes[i]].scene, camera);
             }
             
             // switch the renderer back to the main canvas
             this.renderer.setRenderTarget(null);
-            // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, this.dummyCamera);
-            // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+            // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
+            // this.renderer.render(this.passes[passes[0]].scene, camera);
         }
     }
 }
\ No newline at end of file
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 6e0fb14..8fec2c8 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -137,19 +137,19 @@ export function createMultiPassSculptureWithGeometry(geometry, source, uniformCa
 //     }
 // }
 
-let passes = {
-    bufferA: {
-        fragmentShader: `
-            precision highp float;
-            uniform vec2 resolution;
+// let passes = {
+//     bufferA: {
+//         fragmentShader: `
+//             precision highp float;
+//             uniform vec2 resolution;
             
-            void main() {
-                vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
-                gl_FragColor = color;
-            }
-        `,
-    }
-}
+//             void main() {
+//                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+//                 gl_FragColor = color;
+//             }
+//         `,
+//     }
+// }
 
 // TODO NEXT Replace sculptToThreeJSMaterial with 
 export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
@@ -168,12 +168,20 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
     }
     let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
     console.log('buffA', bufferA);
-    // let passes = {
-    //     bufferA: {
-    //         // '#version 300 es\n' +'precision highp float;\n'+
-    //         fragmentShader: bufferA.frag,
-    //     }
-    // }
+    let passes = {
+        bufferA: {
+            fragmentShader: bufferA.frag,
+//             fragmentShader: `
+//             precision highp float;
+//             uniform vec2 resolution;
+            
+//             void main() {
+//                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
+//                 gl_FragColor = color;
+//             }
+//         `,
+        }
+    }
     // let material = sculptToThreeJSMaterial(finalImage);
     let material = finalImage;
     material.uniforms['opacity'].value = 1.0;

From 7d4bc13fcad7f059c40cb24e16fa9b9e6d0b297b Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Tue, 22 Mar 2022 12:09:18 -0400
Subject: [PATCH 14/20] fix triangle size + camera

---
 dist/shader-park-core.cjs.js | 37 ++++++++++++++++++++++++------------
 dist/shader-park-core.esm.js | 37 ++++++++++++++++++++++++------------
 dist/shader-park-core.umd.js | 37 ++++++++++++++++++++++++------------
 targets/multiPostFX.js       | 37 +++++++++++++++++++++++-------------
 targets/threeJS.js           |  5 +++++
 5 files changed, 104 insertions(+), 49 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 76a9707..75b83c1 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95851,21 +95851,27 @@ if ( typeof window !== 'undefined' ) {
  */
 
 var MultiPostFX = /*#__PURE__*/function () {
-  function MultiPostFX(params) {
+  function MultiPostFX(params, camera) {
     _classCallCheck(this, MultiPostFX);
 
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
     // this.dummyCamera = new OrthographicCamera();
 
-    this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
-
-    var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
-    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+    this.dummyCamera = params.camera.clone();
+    this.geometry = new BufferGeometry();
     this.resolution = new Vector2();
-    this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+    this.renderer.getDrawingBufferSize(this.resolution);
+    var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
+    //  const vertices = new Float32Array([
+    //     -1.0, -1.0,
+    //     3.0, -1.0,
+    //     -1.0, 3.0
+    // ]);
+
+    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2)); // default shaders
 
-    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                // gl_Position = vec4(position, 1.0);\n                gl_Position = projectionMatrix * mvPosition;\n            }\n        "; // varying vec4 worldPos;
     // //varying vec2 vUv;
     // varying vec3 sculptureCenter;
     // void main()
@@ -95915,7 +95921,7 @@ var MultiPostFX = /*#__PURE__*/function () {
           value: new Vector3()
         },
         _scale: {
-          value: 2.0
+          value: 1.0
         },
         time: {
           value: 0.0
@@ -95945,7 +95951,8 @@ var MultiPostFX = /*#__PURE__*/function () {
   }, {
     key: "resize",
     value: function resize() {
-      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+      this.renderer.getDrawingBufferSize(this.resolution);
+      console.log(this.resolution); // resize all passes
 
       var passes = Object.keys(this.passes);
 
@@ -95965,12 +95972,13 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, camera);
+          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-        // this.renderer.render(this.passes[passes[0]].scene, camera);
+
+        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96159,8 +96167,13 @@ function createMultiPassSculpture(source) {
     if (!multiPost) {
       multiPost = new MultiPostFX({
         renderer: renderer,
+        camera: camera,
         passes: passes
-      }); // console.log(multiPost)
+      });
+      multiPost.resize();
+      window.addEventListener('resize', function () {
+        multiPost.resize();
+      }, false); // console.log(multiPost)
     } else {
       multiPost.render(scene, camera);
 
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 310be96..e43e356 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95847,21 +95847,27 @@ if ( typeof window !== 'undefined' ) {
  */
 
 var MultiPostFX = /*#__PURE__*/function () {
-  function MultiPostFX(params) {
+  function MultiPostFX(params, camera) {
     _classCallCheck(this, MultiPostFX);
 
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
     // this.dummyCamera = new OrthographicCamera();
 
-    this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
-
-    var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
-    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+    this.dummyCamera = params.camera.clone();
+    this.geometry = new BufferGeometry();
     this.resolution = new Vector2();
-    this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+    this.renderer.getDrawingBufferSize(this.resolution);
+    var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
+    //  const vertices = new Float32Array([
+    //     -1.0, -1.0,
+    //     3.0, -1.0,
+    //     -1.0, 3.0
+    // ]);
+
+    this.geometry.setAttribute('position', new BufferAttribute(vertices, 2)); // default shaders
 
-    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+    this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                // gl_Position = vec4(position, 1.0);\n                gl_Position = projectionMatrix * mvPosition;\n            }\n        "; // varying vec4 worldPos;
     // //varying vec2 vUv;
     // varying vec3 sculptureCenter;
     // void main()
@@ -95911,7 +95917,7 @@ var MultiPostFX = /*#__PURE__*/function () {
           value: new Vector3()
         },
         _scale: {
-          value: 2.0
+          value: 1.0
         },
         time: {
           value: 0.0
@@ -95941,7 +95947,8 @@ var MultiPostFX = /*#__PURE__*/function () {
   }, {
     key: "resize",
     value: function resize() {
-      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+      this.renderer.getDrawingBufferSize(this.resolution);
+      console.log(this.resolution); // resize all passes
 
       var passes = Object.keys(this.passes);
 
@@ -95961,12 +95968,13 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, camera);
+          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-        // this.renderer.render(this.passes[passes[0]].scene, camera);
+
+        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96155,8 +96163,13 @@ function createMultiPassSculpture(source) {
     if (!multiPost) {
       multiPost = new MultiPostFX({
         renderer: renderer,
+        camera: camera,
         passes: passes
-      }); // console.log(multiPost)
+      });
+      multiPost.resize();
+      window.addEventListener('resize', function () {
+        multiPost.resize();
+      }, false); // console.log(multiPost)
     } else {
       multiPost.render(scene, camera);
 
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 521bb60..58f80e7 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95853,21 +95853,27 @@
    */
 
   var MultiPostFX = /*#__PURE__*/function () {
-    function MultiPostFX(params) {
+    function MultiPostFX(params, camera) {
       _classCallCheck(this, MultiPostFX);
 
       this.renderer = params.renderer;
       if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
       // this.dummyCamera = new OrthographicCamera();
 
-      this.geometry = new BufferGeometry(); // Triangle expressed in clip space coordinates
-
-      var vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
-      this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
+      this.dummyCamera = params.camera.clone();
+      this.geometry = new BufferGeometry();
       this.resolution = new Vector2();
-      this.renderer.getDrawingBufferSize(this.resolution); // default shaders
+      this.renderer.getDrawingBufferSize(this.resolution);
+      var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
+      //  const vertices = new Float32Array([
+      //     -1.0, -1.0,
+      //     3.0, -1.0,
+      //     -1.0, 3.0
+      // ]);
+
+      this.geometry.setAttribute('position', new BufferAttribute(vertices, 2)); // default shaders
 
-      this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                gl_Position = vec4(position, 1.0);\n            }\n        "; // varying vec4 worldPos;
+      this.defaultVertexShader = "\n            varying vec4 worldPos;\n            varying vec3 sculptureCenter;\n            // precision highp float;\n            // attribute vec2 position;\n            void main() {\n                worldPos = modelMatrix*vec4(position,1.0);\n                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n                sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;\n                // gl_Position = vec4(position, 1.0);\n                gl_Position = projectionMatrix * mvPosition;\n            }\n        "; // varying vec4 worldPos;
       // //varying vec2 vUv;
       // varying vec3 sculptureCenter;
       // void main()
@@ -95917,7 +95923,7 @@
             value: new Vector3()
           },
           _scale: {
-            value: 2.0
+            value: 1.0
           },
           time: {
             value: 0.0
@@ -95947,7 +95953,8 @@
     }, {
       key: "resize",
       value: function resize() {
-        this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
+        this.renderer.getDrawingBufferSize(this.resolution);
+        console.log(this.resolution); // resize all passes
 
         var passes = Object.keys(this.passes);
 
@@ -95967,12 +95974,13 @@
 
           for (var i = 0; i < this.nbPasses; i++) {
             this.renderer.setRenderTarget(this.passes[passes[i]].target);
-            this.renderer.render(this.passes[passes[i]].scene, camera);
+            this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
           } // switch the renderer back to the main canvas
 
 
           this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-          // this.renderer.render(this.passes[passes[0]].scene, camera);
+
+          this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
       }
     }]);
@@ -96161,8 +96169,13 @@
       if (!multiPost) {
         multiPost = new MultiPostFX({
           renderer: renderer,
+          camera: camera,
           passes: passes
-        }); // console.log(multiPost)
+        });
+        multiPost.resize();
+        window.addEventListener('resize', function () {
+          multiPost.resize();
+        }, false); // console.log(multiPost)
       } else {
         multiPost.render(scene, camera);
 
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index e2a1a97..f154157 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -57,27 +57,36 @@ import {
  *
  */
 export class MultiPostFX {
-    constructor(params) {
+    constructor(params, camera) {
         this.renderer = params.renderer;
 
         if(!this.renderer) return;
 
         // three.js for .render() wants a camera, even if we're not using it :(
         // this.dummyCamera = new OrthographicCamera();
+        this.dummyCamera = params.camera.clone();
         this.geometry = new BufferGeometry();
 
-        // Triangle expressed in clip space coordinates
+       
+
+        this.resolution = new Vector2();
+        this.renderer.getDrawingBufferSize(this.resolution);
+
+
         const vertices = new Float32Array([
-            -1.0, -1.0,
-            3.0, -1.0,
-            -1.0, 3.0
+            0.0, -10.0,
+            10.0, 10.0,
+            -10.0, 10.0,
         ]);
+        //  // Triangle expressed in clip space coordinates
+        //  const vertices = new Float32Array([
+        //     -1.0, -1.0,
+        //     3.0, -1.0,
+        //     -1.0, 3.0
+        // ]);
 
         this.geometry.setAttribute('position', new BufferAttribute(vertices, 2));
 
-        this.resolution = new Vector2();
-        this.renderer.getDrawingBufferSize(this.resolution);
-
         // default shaders
         this.defaultVertexShader = `
             varying vec4 worldPos;
@@ -86,8 +95,10 @@ export class MultiPostFX {
             // attribute vec2 position;
             void main() {
                 worldPos = modelMatrix*vec4(position,1.0);
+                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
                 sculptureCenter = (modelMatrix * vec4(0., 0., 0., 1.)).xyz;
-                gl_Position = vec4(position, 1.0);
+                // gl_Position = vec4(position, 1.0);
+                gl_Position = projectionMatrix * mvPosition;
             }
         `;
 
@@ -141,7 +152,7 @@ export class MultiPostFX {
             resolution: { value: this.resolution },
             opacity: { value:  1.0},
             mouse: { value:  new Vector3()},
-            _scale: { value:  2.0},
+            _scale: { value:  1.0},
             time: {value: 0.0},
             stepSize: {value: 0.85},
         };
@@ -171,7 +182,7 @@ export class MultiPostFX {
 
     resize() {
         this.renderer.getDrawingBufferSize(this.resolution);
-
+        console.log(this.resolution)
         // resize all passes
         const passes = Object.keys(this.passes);
         for(let i = 0; i < this.nbPasses; i++) {
@@ -189,13 +200,13 @@ export class MultiPostFX {
             const passes = Object.keys(this.passes);
             for(let i = 0; i < this.nbPasses; i++) {
                 this.renderer.setRenderTarget(this.passes[passes[i]].target);
-                this.renderer.render(this.passes[passes[i]].scene, camera);
+                this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
             }
             
             // switch the renderer back to the main canvas
             this.renderer.setRenderTarget(null);
             // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-            // this.renderer.render(this.passes[passes[0]].scene, camera);
+            this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
     }
 }
\ No newline at end of file
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 8fec2c8..e6bf4e5 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -194,8 +194,13 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         if(!multiPost) {
             multiPost = new MultiPostFX({
                 renderer,
+                camera,
                 passes
             });
+            multiPost.resize();
+            window.addEventListener('resize', () => {
+                multiPost.resize();
+            }, false);
             // console.log(multiPost)
         } else {
             multiPost.render(scene, camera);

From cd8a0258e88175380122fbe2ca96d3976e86f10a Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Tue, 22 Mar 2022 13:26:41 -0400
Subject: [PATCH 15/20] working projection + camera update

---
 dist/shader-park-core.cjs.js | 24 +++++++++++++++++-------
 dist/shader-park-core.esm.js | 24 +++++++++++++++++-------
 dist/shader-park-core.umd.js | 24 +++++++++++++++++-------
 targets/multiPostFX.js       | 12 +++++++-----
 targets/threeJS.js           |  5 +++--
 5 files changed, 61 insertions(+), 28 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 75b83c1..ed712b6 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95857,11 +95857,13 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
     // this.dummyCamera = new OrthographicCamera();
+    // this.dummyCamera = params.camera.clone();
 
-    this.dummyCamera = params.camera.clone();
-    this.geometry = new BufferGeometry();
+    this.dummyCamera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+    this.dummyCamera.position.z = 2;
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution);
+    this.geometry = new BufferGeometry();
     var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
     //  const vertices = new Float32Array([
     //     -1.0, -1.0,
@@ -96178,7 +96180,7 @@ function createMultiPassSculpture(source) {
       multiPost.render(scene, camera);
 
       if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
       }
     }
 
@@ -96194,6 +96196,14 @@ function createMultiPassSculpture(source) {
           value = _Object$entries2$_i[1];
 
       material.uniforms[uniform].value = value;
+
+      for (var _i3 = 0, _Object$entries3 = Object.entries(multiPost.passes); _i3 < _Object$entries3.length; _i3++) {
+        var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+            passName = _Object$entries3$_i[0],
+            currPass = _Object$entries3$_i[1];
+
+        currPass.material.uniforms[uniform].value = value;
+      }
     } // material.uniforms['sculptureCenter'].value = geometry.position;
 
   };
@@ -96230,10 +96240,10 @@ function createSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
-      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-          uniform = _Object$entries3$_i[0],
-          value = _Object$entries3$_i[1];
+    for (var _i4 = 0, _Object$entries4 = Object.entries(uniformsToUpdate); _i4 < _Object$entries4.length; _i4++) {
+      var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+          uniform = _Object$entries4$_i[0],
+          value = _Object$entries4$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index e43e356..95ec417 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95853,11 +95853,13 @@ var MultiPostFX = /*#__PURE__*/function () {
     this.renderer = params.renderer;
     if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
     // this.dummyCamera = new OrthographicCamera();
+    // this.dummyCamera = params.camera.clone();
 
-    this.dummyCamera = params.camera.clone();
-    this.geometry = new BufferGeometry();
+    this.dummyCamera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+    this.dummyCamera.position.z = 2;
     this.resolution = new Vector2();
     this.renderer.getDrawingBufferSize(this.resolution);
+    this.geometry = new BufferGeometry();
     var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
     //  const vertices = new Float32Array([
     //     -1.0, -1.0,
@@ -96174,7 +96176,7 @@ function createMultiPassSculpture(source) {
       multiPost.render(scene, camera);
 
       if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
+        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
       }
     }
 
@@ -96190,6 +96192,14 @@ function createMultiPassSculpture(source) {
           value = _Object$entries2$_i[1];
 
       material.uniforms[uniform].value = value;
+
+      for (var _i3 = 0, _Object$entries3 = Object.entries(multiPost.passes); _i3 < _Object$entries3.length; _i3++) {
+        var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+            passName = _Object$entries3$_i[0],
+            currPass = _Object$entries3$_i[1];
+
+        currPass.material.uniforms[uniform].value = value;
+      }
     } // material.uniforms['sculptureCenter'].value = geometry.position;
 
   };
@@ -96226,10 +96236,10 @@ function createSculpture(source) {
       throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
     }
 
-    for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
-      var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-          uniform = _Object$entries3$_i[0],
-          value = _Object$entries3$_i[1];
+    for (var _i4 = 0, _Object$entries4 = Object.entries(uniformsToUpdate); _i4 < _Object$entries4.length; _i4++) {
+      var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+          uniform = _Object$entries4$_i[0],
+          value = _Object$entries4$_i[1];
 
       material.uniforms[uniform].value = value;
     } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 58f80e7..e124b9d 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95859,11 +95859,13 @@
       this.renderer = params.renderer;
       if (!this.renderer) return; // three.js for .render() wants a camera, even if we're not using it :(
       // this.dummyCamera = new OrthographicCamera();
+      // this.dummyCamera = params.camera.clone();
 
-      this.dummyCamera = params.camera.clone();
-      this.geometry = new BufferGeometry();
+      this.dummyCamera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+      this.dummyCamera.position.z = 2;
       this.resolution = new Vector2();
       this.renderer.getDrawingBufferSize(this.resolution);
+      this.geometry = new BufferGeometry();
       var vertices = new Float32Array([0.0, -10.0, 10.0, 10.0, -10.0, 10.0]); //  // Triangle expressed in clip space coordinates
       //  const vertices = new Float32Array([
       //     -1.0, -1.0,
@@ -96180,7 +96182,7 @@
         multiPost.render(scene, camera);
 
         if ('bufferA' in material.uniforms) {
-          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture; // console.log('setting buffA', material.uniforms['bufferA'].value)
+          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
         }
       }
 
@@ -96196,6 +96198,14 @@
             value = _Object$entries2$_i[1];
 
         material.uniforms[uniform].value = value;
+
+        for (var _i3 = 0, _Object$entries3 = Object.entries(multiPost.passes); _i3 < _Object$entries3.length; _i3++) {
+          var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
+              passName = _Object$entries3$_i[0],
+              currPass = _Object$entries3$_i[1];
+
+          currPass.material.uniforms[uniform].value = value;
+        }
       } // material.uniforms['sculptureCenter'].value = geometry.position;
 
     };
@@ -96232,10 +96242,10 @@
         throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update";
       }
 
-      for (var _i3 = 0, _Object$entries3 = Object.entries(uniformsToUpdate); _i3 < _Object$entries3.length; _i3++) {
-        var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
-            uniform = _Object$entries3$_i[0],
-            value = _Object$entries3$_i[1];
+      for (var _i4 = 0, _Object$entries4 = Object.entries(uniformsToUpdate); _i4 < _Object$entries4.length; _i4++) {
+        var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
+            uniform = _Object$entries4$_i[0],
+            value = _Object$entries4$_i[1];
 
         material.uniforms[uniform].value = value;
       } // material.uniforms['sculptureCenter'].value = geometry.position;
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index f154157..016366f 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -41,7 +41,8 @@ import {
     RawShaderMaterial,
     Vector2,
     Vector3,
-    BackSide
+    BackSide,
+    PerspectiveCamera
 } from 'three';
 
 /**
@@ -64,15 +65,16 @@ export class MultiPostFX {
 
         // three.js for .render() wants a camera, even if we're not using it :(
         // this.dummyCamera = new OrthographicCamera();
-        this.dummyCamera = params.camera.clone();
-        this.geometry = new BufferGeometry();
-
+        // this.dummyCamera = params.camera.clone();
+        
+        this.dummyCamera = new PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
+        this.dummyCamera.position.z = 2;
        
 
         this.resolution = new Vector2();
         this.renderer.getDrawingBufferSize(this.resolution);
 
-
+        this.geometry = new BufferGeometry();
         const vertices = new Float32Array([
             0.0, -10.0,
             10.0, 10.0,
diff --git a/targets/threeJS.js b/targets/threeJS.js
index e6bf4e5..4d8158e 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -206,16 +206,17 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
             multiPost.render(scene, camera);
             if('bufferA' in material.uniforms) {
                 material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-                // console.log('setting buffA', material.uniforms['bufferA'].value)
             }
         }
         let uniformsToUpdate = uniformCallback();
         if (!(typeof uniformsToUpdate === "object")) {
             throw "createSculpture takes, (source, uniformCallback, params) the uniformCallback must be a function that returns a dictionary of uniforms to update"
         }
-
         for (const [uniform, value] of Object.entries(uniformsToUpdate)) {
             material.uniforms[uniform].value = value;
+            for (const [passName, currPass] of Object.entries(multiPost.passes)) {
+                currPass.material.uniforms[uniform].value = value;
+            }
         }
         // material.uniforms['sculptureCenter'].value = geometry.position;
     }

From a77bd754e1ff2c75eea163056c71ec47b556499d Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Tue, 22 Mar 2022 13:36:39 -0400
Subject: [PATCH 16/20] test out reading bufferA

---
 dist/shader-park-core.cjs.js | 4 ++++
 dist/shader-park-core.esm.js | 4 ++++
 dist/shader-park-core.umd.js | 4 ++++
 targets/threeJS.js           | 4 ++++
 4 files changed, 16 insertions(+)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index ed712b6..9959491 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -96182,6 +96182,10 @@ function createMultiPassSculpture(source) {
       if ('bufferA' in material.uniforms) {
         material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
       }
+
+      if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+        multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+      }
     }
 
     var uniformsToUpdate = uniformCallback();
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 95ec417..df2971d 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -96178,6 +96178,10 @@ function createMultiPassSculpture(source) {
       if ('bufferA' in material.uniforms) {
         material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
       }
+
+      if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+        multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+      }
     }
 
     var uniformsToUpdate = uniformCallback();
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index e124b9d..d98796e 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -96184,6 +96184,10 @@
         if ('bufferA' in material.uniforms) {
           material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
         }
+
+        if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+          multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+        }
       }
 
       var uniformsToUpdate = uniformCallback();
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 4d8158e..7e02428 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -207,6 +207,10 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
             if('bufferA' in material.uniforms) {
                 material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
             }
+            if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+                multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+
+            }
         }
         let uniformsToUpdate = uniformCallback();
         if (!(typeof uniformsToUpdate === "object")) {

From 365c7892efff711ae30785dd309fe8eb2648b17c Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Wed, 23 Mar 2022 13:23:23 -0400
Subject: [PATCH 17/20] working feedback

---
 dist/shader-park-core.cjs.js | 19 ++++++++++++++++++-
 dist/shader-park-core.esm.js | 19 ++++++++++++++++++-
 dist/shader-park-core.umd.js | 19 ++++++++++++++++++-
 generators/sculpt.js         |  1 +
 targets/multiPostFX.js       | 18 +++++++++++++++++-
 5 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 9959491..8d80bc2 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -45044,6 +45044,8 @@ function sculptToGLSL(userProvidedSrc) {
 
   var sampleBufferD = _bindTextureRead("bufferD");
 
+  var sampleLastFrame = _bindTextureRead("lastFrame");
+
   function getPixelCoord() {
     return makeVarWithDims('gl_FragCoord.xy', 2, true);
   }
@@ -95909,6 +95911,12 @@ var MultiPostFX = /*#__PURE__*/function () {
           // allow transparency
           stencilBuffer: false,
           depthBuffer: true
+        }),
+        targetOld: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+          format: passParams.format || RGBAFormat,
+          // allow transparency
+          stencilBuffer: false,
+          depthBuffer: true
         })
       };
       var uniforms = {
@@ -95930,7 +95938,8 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         stepSize: {
           value: 0.85
-        }
+        },
+        lastFrame: new Texture()
       }; // merge default uniforms with params
 
       if (passParams.uniforms) {
@@ -95960,6 +95969,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
       for (var i = 0; i < this.nbPasses; i++) {
         this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+        this.passes[passes[i]].targetOld.setSize(this.resolution.x, this.resolution.y);
         this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
       }
     }
@@ -95973,6 +95983,13 @@ var MultiPostFX = /*#__PURE__*/function () {
         var passes = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
+          //PingPong texture
+          var temp = this.passes[passes[i]].targetOld;
+          this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
+          this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+
+          this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
           this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index df2971d..db2ffda 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -45040,6 +45040,8 @@ function sculptToGLSL(userProvidedSrc) {
 
   var sampleBufferD = _bindTextureRead("bufferD");
 
+  var sampleLastFrame = _bindTextureRead("lastFrame");
+
   function getPixelCoord() {
     return makeVarWithDims('gl_FragCoord.xy', 2, true);
   }
@@ -95905,6 +95907,12 @@ var MultiPostFX = /*#__PURE__*/function () {
           // allow transparency
           stencilBuffer: false,
           depthBuffer: true
+        }),
+        targetOld: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+          format: passParams.format || RGBAFormat,
+          // allow transparency
+          stencilBuffer: false,
+          depthBuffer: true
         })
       };
       var uniforms = {
@@ -95926,7 +95934,8 @@ var MultiPostFX = /*#__PURE__*/function () {
         },
         stepSize: {
           value: 0.85
-        }
+        },
+        lastFrame: new Texture()
       }; // merge default uniforms with params
 
       if (passParams.uniforms) {
@@ -95956,6 +95965,7 @@ var MultiPostFX = /*#__PURE__*/function () {
 
       for (var i = 0; i < this.nbPasses; i++) {
         this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+        this.passes[passes[i]].targetOld.setSize(this.resolution.x, this.resolution.y);
         this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
       }
     }
@@ -95969,6 +95979,13 @@ var MultiPostFX = /*#__PURE__*/function () {
         var passes = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
+          //PingPong texture
+          var temp = this.passes[passes[i]].targetOld;
+          this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
+          this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+
+          this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+
           this.renderer.setRenderTarget(this.passes[passes[i]].target);
           this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index d98796e..6ea3be6 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -45046,6 +45046,8 @@
 
     var sampleBufferD = _bindTextureRead("bufferD");
 
+    var sampleLastFrame = _bindTextureRead("lastFrame");
+
     function getPixelCoord() {
       return makeVarWithDims('gl_FragCoord.xy', 2, true);
     }
@@ -95911,6 +95913,12 @@
             // allow transparency
             stencilBuffer: false,
             depthBuffer: true
+          }),
+          targetOld: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+            format: passParams.format || RGBAFormat,
+            // allow transparency
+            stencilBuffer: false,
+            depthBuffer: true
           })
         };
         var uniforms = {
@@ -95932,7 +95940,8 @@
           },
           stepSize: {
             value: 0.85
-          }
+          },
+          lastFrame: new Texture()
         }; // merge default uniforms with params
 
         if (passParams.uniforms) {
@@ -95962,6 +95971,7 @@
 
         for (var i = 0; i < this.nbPasses; i++) {
           this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+          this.passes[passes[i]].targetOld.setSize(this.resolution.x, this.resolution.y);
           this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
         }
       }
@@ -95975,6 +95985,13 @@
           var passes = Object.keys(this.passes);
 
           for (var i = 0; i < this.nbPasses; i++) {
+            //PingPong texture
+            var temp = this.passes[passes[i]].targetOld;
+            this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
+            this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+
+            this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+
             this.renderer.setRenderTarget(this.passes[passes[i]].target);
             this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
           } // switch the renderer back to the main canvas
diff --git a/generators/sculpt.js b/generators/sculpt.js
index 41ce3e1..08aa5fd 100644
--- a/generators/sculpt.js
+++ b/generators/sculpt.js
@@ -1168,6 +1168,7 @@ export function sculptToGLSL(userProvidedSrc) {
 	let sampleBufferB = _bindTextureRead("bufferB");
 	let sampleBufferC = _bindTextureRead("bufferC");
 	let sampleBufferD = _bindTextureRead("bufferD");
+	let sampleLastFrame = _bindTextureRead("lastFrame");
 
 
 	function getPixelCoord() {
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 016366f..538cc50 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -42,7 +42,8 @@ import {
     Vector2,
     Vector3,
     BackSide,
-    PerspectiveCamera
+    PerspectiveCamera,
+    Texture
 } from 'three';
 
 /**
@@ -147,6 +148,11 @@ export class MultiPostFX {
                 stencilBuffer: false,
                 depthBuffer: true,
             }),
+            targetOld: new WebGLRenderTarget(this.resolution.x, this.resolution.y, {
+                format: passParams.format || RGBAFormat, // allow transparency
+                stencilBuffer: false,
+                depthBuffer: true,
+            }),
         };
 
         let uniforms = {
@@ -157,6 +163,7 @@ export class MultiPostFX {
             _scale: { value:  1.0},
             time: {value: 0.0},
             stepSize: {value: 0.85},
+            lastFrame: new Texture()
         };
 
         // merge default uniforms with params
@@ -189,6 +196,7 @@ export class MultiPostFX {
         const passes = Object.keys(this.passes);
         for(let i = 0; i < this.nbPasses; i++) {
             this.passes[passes[i]].target.setSize(this.resolution.x, this.resolution.y);
+            this.passes[passes[i]].targetOld.setSize(this.resolution.x, this.resolution.y);
             this.passes[passes[i]].material.uniforms.resolution.value = this.resolution;
         }
     }
@@ -201,6 +209,14 @@ export class MultiPostFX {
         else {
             const passes = Object.keys(this.passes);
             for(let i = 0; i < this.nbPasses; i++) {
+                
+                //PingPong texture
+                let temp = this.passes[passes[i]].targetOld;
+                this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
+                this.passes[passes[i]].target = temp;
+                //set uniform to correct target for feedback
+                this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+                // apply to render target
                 this.renderer.setRenderTarget(this.passes[passes[i]].target);
                 this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
             }

From a933aa16e3a90622558874b6948d04cf63c54ced Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 24 Apr 2022 22:49:32 -0400
Subject: [PATCH 18/20] backup working sampleLastFrame

---
 dist/shader-park-core.cjs.js | 68 ++++++++++++++++++++++--------------
 dist/shader-park-core.esm.js | 68 ++++++++++++++++++++++--------------
 dist/shader-park-core.umd.js | 68 ++++++++++++++++++++++--------------
 targets/multiPostFX.js       | 26 +++++++++-----
 targets/threeJS.js           | 48 ++++++++++++++++---------
 5 files changed, 172 insertions(+), 106 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 8d80bc2..5065757 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95939,7 +95939,11 @@ var MultiPostFX = /*#__PURE__*/function () {
         stepSize: {
           value: 0.85
         },
-        lastFrame: new Texture()
+        lastFrame: new Texture(),
+        bufferA: new Texture(),
+        bufferB: new Texture(),
+        bufferC: new Texture(),
+        bufferD: new Texture()
       }; // merge default uniforms with params
 
       if (passParams.uniforms) {
@@ -95984,20 +95988,22 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           //PingPong texture
-          var temp = this.passes[passes[i]].targetOld;
-          this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
-          this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+          var curPass = this.passes[passes[i]];
+          var temp = curPass.targetOld;
+          curPass.targetOld = curPass.target;
+          curPass.target = temp; //set uniform to correct target for feedback
+          // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
+          // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
 
-          this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+          curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
 
-          this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+          this.renderer.setRenderTarget(curPass.target);
+          this.renderer.render(curPass.scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-
-        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96160,18 +96166,18 @@ function createMultiPassSculpture(source) {
       bufferD = _multiPassSculpToThre.bufferD,
       finalImage = _multiPassSculpToThre.finalImage;
 
-  console.log('buffA', bufferA);
   var passes = {
     bufferA: {
-      fragmentShader: bufferA.frag //             fragmentShader: `
-      //             precision highp float;
-      //             uniform vec2 resolution;
-      //             void main() {
-      //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
-      //                 gl_FragColor = color;
-      //             }
-      //         `,
-
+      fragmentShader: bufferA.frag
+    },
+    bufferB: {
+      fragmentShader: bufferB.frag
+    },
+    bufferC: {
+      fragmentShader: bufferC.frag
+    },
+    bufferD: {
+      fragmentShader: bufferD.frag
     }
   }; // let material = sculptToThreeJSMaterial(finalImage);
 
@@ -96181,6 +96187,7 @@ function createMultiPassSculpture(source) {
   material.uniforms['_scale'].value = radius;
   var mesh = new Mesh(geometry, material);
   var multiPost;
+  var passNames = Object.keys(passes);
 
   mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
     if (!multiPost) {
@@ -96194,15 +96201,20 @@ function createMultiPassSculpture(source) {
         multiPost.resize();
       }, false); // console.log(multiPost)
     } else {
-      multiPost.render(scene, camera);
+      passNames.forEach(function (passName) {
+        if (passName in material.uniforms) {
+          // is passName our current Buffer?
+          material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+        } // if(passName in multiPost.passes[passName].material.uniforms) {
+        //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
+        // }
 
-      if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-      }
-
-      if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
-        multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
-      }
+      }); // if('bufferA' in material.uniforms) {
+      //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+      // }
+      // if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+      //     multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+      // }
     }
 
     var uniformsToUpdate = uniformCallback();
@@ -96227,6 +96239,8 @@ function createMultiPassSculpture(source) {
       }
     } // material.uniforms['sculptureCenter'].value = geometry.position;
 
+
+    multiPost.render(scene, camera);
   };
 
   return mesh;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index db2ffda..c14664b 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95935,7 +95935,11 @@ var MultiPostFX = /*#__PURE__*/function () {
         stepSize: {
           value: 0.85
         },
-        lastFrame: new Texture()
+        lastFrame: new Texture(),
+        bufferA: new Texture(),
+        bufferB: new Texture(),
+        bufferC: new Texture(),
+        bufferD: new Texture()
       }; // merge default uniforms with params
 
       if (passParams.uniforms) {
@@ -95980,20 +95984,22 @@ var MultiPostFX = /*#__PURE__*/function () {
 
         for (var i = 0; i < this.nbPasses; i++) {
           //PingPong texture
-          var temp = this.passes[passes[i]].targetOld;
-          this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
-          this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+          var curPass = this.passes[passes[i]];
+          var temp = curPass.targetOld;
+          curPass.targetOld = curPass.target;
+          curPass.target = temp; //set uniform to correct target for feedback
+          // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
+          // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
 
-          this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+          curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
 
-          this.renderer.setRenderTarget(this.passes[passes[i]].target);
-          this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+          this.renderer.setRenderTarget(curPass.target);
+          this.renderer.render(curPass.scene, this.dummyCamera);
         } // switch the renderer back to the main canvas
 
 
         this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-
-        this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+        // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
       }
     }
   }]);
@@ -96156,18 +96162,18 @@ function createMultiPassSculpture(source) {
       bufferD = _multiPassSculpToThre.bufferD,
       finalImage = _multiPassSculpToThre.finalImage;
 
-  console.log('buffA', bufferA);
   var passes = {
     bufferA: {
-      fragmentShader: bufferA.frag //             fragmentShader: `
-      //             precision highp float;
-      //             uniform vec2 resolution;
-      //             void main() {
-      //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
-      //                 gl_FragColor = color;
-      //             }
-      //         `,
-
+      fragmentShader: bufferA.frag
+    },
+    bufferB: {
+      fragmentShader: bufferB.frag
+    },
+    bufferC: {
+      fragmentShader: bufferC.frag
+    },
+    bufferD: {
+      fragmentShader: bufferD.frag
     }
   }; // let material = sculptToThreeJSMaterial(finalImage);
 
@@ -96177,6 +96183,7 @@ function createMultiPassSculpture(source) {
   material.uniforms['_scale'].value = radius;
   var mesh = new Mesh(geometry, material);
   var multiPost;
+  var passNames = Object.keys(passes);
 
   mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
     if (!multiPost) {
@@ -96190,15 +96197,20 @@ function createMultiPassSculpture(source) {
         multiPost.resize();
       }, false); // console.log(multiPost)
     } else {
-      multiPost.render(scene, camera);
+      passNames.forEach(function (passName) {
+        if (passName in material.uniforms) {
+          // is passName our current Buffer?
+          material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+        } // if(passName in multiPost.passes[passName].material.uniforms) {
+        //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
+        // }
 
-      if ('bufferA' in material.uniforms) {
-        material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-      }
-
-      if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
-        multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
-      }
+      }); // if('bufferA' in material.uniforms) {
+      //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+      // }
+      // if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+      //     multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+      // }
     }
 
     var uniformsToUpdate = uniformCallback();
@@ -96223,6 +96235,8 @@ function createMultiPassSculpture(source) {
       }
     } // material.uniforms['sculptureCenter'].value = geometry.position;
 
+
+    multiPost.render(scene, camera);
   };
 
   return mesh;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 6ea3be6..96e5121 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95941,7 +95941,11 @@
           stepSize: {
             value: 0.85
           },
-          lastFrame: new Texture()
+          lastFrame: new Texture(),
+          bufferA: new Texture(),
+          bufferB: new Texture(),
+          bufferC: new Texture(),
+          bufferD: new Texture()
         }; // merge default uniforms with params
 
         if (passParams.uniforms) {
@@ -95986,20 +95990,22 @@
 
           for (var i = 0; i < this.nbPasses; i++) {
             //PingPong texture
-            var temp = this.passes[passes[i]].targetOld;
-            this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
-            this.passes[passes[i]].target = temp; //set uniform to correct target for feedback
+            var curPass = this.passes[passes[i]];
+            var temp = curPass.targetOld;
+            curPass.targetOld = curPass.target;
+            curPass.target = temp; //set uniform to correct target for feedback
+            // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
+            // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
 
-            this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture; // apply to render target
+            curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
 
-            this.renderer.setRenderTarget(this.passes[passes[i]].target);
-            this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+            this.renderer.setRenderTarget(curPass.target);
+            this.renderer.render(curPass.scene, this.dummyCamera);
           } // switch the renderer back to the main canvas
 
 
           this.renderer.setRenderTarget(null); // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-
-          this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+          // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
       }
     }]);
@@ -96162,18 +96168,18 @@
         bufferD = _multiPassSculpToThre.bufferD,
         finalImage = _multiPassSculpToThre.finalImage;
 
-    console.log('buffA', bufferA);
     var passes = {
       bufferA: {
-        fragmentShader: bufferA.frag //             fragmentShader: `
-        //             precision highp float;
-        //             uniform vec2 resolution;
-        //             void main() {
-        //                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
-        //                 gl_FragColor = color;
-        //             }
-        //         `,
-
+        fragmentShader: bufferA.frag
+      },
+      bufferB: {
+        fragmentShader: bufferB.frag
+      },
+      bufferC: {
+        fragmentShader: bufferC.frag
+      },
+      bufferD: {
+        fragmentShader: bufferD.frag
       }
     }; // let material = sculptToThreeJSMaterial(finalImage);
 
@@ -96183,6 +96189,7 @@
     material.uniforms['_scale'].value = radius;
     var mesh = new Mesh(geometry, material);
     var multiPost;
+    var passNames = Object.keys(passes);
 
     mesh.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
       if (!multiPost) {
@@ -96196,15 +96203,20 @@
           multiPost.resize();
         }, false); // console.log(multiPost)
       } else {
-        multiPost.render(scene, camera);
+        passNames.forEach(function (passName) {
+          if (passName in material.uniforms) {
+            // is passName our current Buffer?
+            material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+          } // if(passName in multiPost.passes[passName].material.uniforms) {
+          //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
+          // }
 
-        if ('bufferA' in material.uniforms) {
-          material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-        }
-
-        if ('bufferA' in multiPost.passes.bufferA.material.uniforms) {
-          multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
-        }
+        }); // if('bufferA' in material.uniforms) {
+        //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+        // }
+        // if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+        //     multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+        // }
       }
 
       var uniformsToUpdate = uniformCallback();
@@ -96229,6 +96241,8 @@
         }
       } // material.uniforms['sculptureCenter'].value = geometry.position;
 
+
+      multiPost.render(scene, camera);
     };
 
     return mesh;
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 538cc50..5a5ea77 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -163,7 +163,11 @@ export class MultiPostFX {
             _scale: { value:  1.0},
             time: {value: 0.0},
             stepSize: {value: 0.85},
-            lastFrame: new Texture()
+            lastFrame: new Texture(),
+            bufferA: new Texture(),
+            bufferB: new Texture(),
+            bufferC: new Texture(),
+            bufferD: new Texture()
         };
 
         // merge default uniforms with params
@@ -211,20 +215,26 @@ export class MultiPostFX {
             for(let i = 0; i < this.nbPasses; i++) {
                 
                 //PingPong texture
-                let temp = this.passes[passes[i]].targetOld;
-                this.passes[passes[i]].targetOld = this.passes[passes[i]].target;
-                this.passes[passes[i]].target = temp;
+                let curPass = this.passes[passes[i]];
+                let temp = curPass.targetOld;
+                curPass.targetOld = curPass.target;
+                curPass.target = temp;
                 //set uniform to correct target for feedback
-                this.passes[passes[i]].material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+                
+                // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
+                // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
+                
+                curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+                
                 // apply to render target
-                this.renderer.setRenderTarget(this.passes[passes[i]].target);
-                this.renderer.render(this.passes[passes[i]].scene, this.dummyCamera);
+                this.renderer.setRenderTarget(curPass.target);
+                this.renderer.render(curPass.scene, this.dummyCamera);
             }
             
             // switch the renderer back to the main canvas
             this.renderer.setRenderTarget(null);
             // this.renderer.render(this.passes[passes[this.nbPasses - 1]].scene, camera);
-            this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
+            // this.renderer.render(this.passes[passes[0]].scene, this.dummyCamera);
         }
     }
 }
\ No newline at end of file
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 7e02428..caa9d6c 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -167,19 +167,18 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
     let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
-    console.log('buffA', bufferA);
     let passes = {
         bufferA: {
             fragmentShader: bufferA.frag,
-//             fragmentShader: `
-//             precision highp float;
-//             uniform vec2 resolution;
-            
-//             void main() {
-//                 vec4 color = vec4(gl_FragCoord.xy / resolution.xy, 1., 1.);
-//                 gl_FragColor = color;
-//             }
-//         `,
+        },
+        bufferB: {
+            fragmentShader: bufferB.frag,
+        },
+        bufferC: {
+            fragmentShader: bufferC.frag,
+        },
+        bufferD: {
+            fragmentShader: bufferD.frag,
         }
     }
     // let material = sculptToThreeJSMaterial(finalImage);
@@ -190,6 +189,7 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
     
     let mesh = new Mesh(geometry, material);
     let multiPost;
+    let passNames = Object.keys(passes);
     mesh.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
         if(!multiPost) {
             multiPost = new MultiPostFX({
@@ -203,14 +203,27 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
             }, false);
             // console.log(multiPost)
         } else {
-            multiPost.render(scene, camera);
-            if('bufferA' in material.uniforms) {
-                material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
-            }
-            if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
-                multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+            
+            passNames.forEach((passName) => {
 
-            }
+                if(passName in material.uniforms){
+                    // is passName our current Buffer?
+                    
+                    material.uniforms[passName].value = multiPost.passes[passName].target.texture;
+                   // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+                }
+                // if(passName in multiPost.passes[passName].material.uniforms) {
+                //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
+                // }
+            });
+            
+            // if('bufferA' in material.uniforms) {
+            //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
+            // }
+            // if('bufferA' in multiPost.passes.bufferA.material.uniforms) {
+            //     multiPost.passes['bufferA'].material.uniforms['bufferA'].value = multiPost.passes.bufferA.material.uniforms;
+
+            // }
         }
         let uniformsToUpdate = uniformCallback();
         if (!(typeof uniformsToUpdate === "object")) {
@@ -223,6 +236,7 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
             }
         }
         // material.uniforms['sculptureCenter'].value = geometry.position;
+        multiPost.render(scene, camera);
     }
     return mesh;
 }

From de6b5b6415a6f1518b36f9ce852df36374540f82 Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Sun, 24 Apr 2022 23:25:01 -0400
Subject: [PATCH 19/20] workinggggg multi pass

---
 dist/shader-park-core.cjs.js | 39 +++++++++++++++++++++++++++---------
 dist/shader-park-core.esm.js | 39 +++++++++++++++++++++++++++---------
 dist/shader-park-core.umd.js | 39 +++++++++++++++++++++++++++---------
 targets/multiPostFX.js       | 15 ++++++++++----
 targets/threeJS.js           | 12 +++++++----
 5 files changed, 106 insertions(+), 38 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 5065757..551c32f 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95853,7 +95853,7 @@ if ( typeof window !== 'undefined' ) {
  */
 
 var MultiPostFX = /*#__PURE__*/function () {
-  function MultiPostFX(params, camera) {
+  function MultiPostFX(params) {
     _classCallCheck(this, MultiPostFX);
 
     this.renderer = params.renderer;
@@ -95984,18 +95984,33 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes);
+        var passNames = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
-          //PingPong texture
-          var curPass = this.passes[passes[i]];
+          var curPass = this.passes[passNames[i]];
+
+          var _iterator = _createForOfIteratorHelper(passNames),
+              _step;
+
+          try {
+            for (_iterator.s(); !(_step = _iterator.n()).done;) {
+              var passName = _step.value;
+              curPass.material.uniforms[passName].value = this.passes[passName].target.texture;
+            } //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+            //PingPong texture
+
+          } catch (err) {
+            _iterator.e(err);
+          } finally {
+            _iterator.f();
+          }
+
           var temp = curPass.targetOld;
           curPass.targetOld = curPass.target;
           curPass.target = temp; //set uniform to correct target for feedback
           // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
           // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
-
-          curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
+          // apply to render target
 
           this.renderer.setRenderTarget(curPass.target);
           this.renderer.render(curPass.scene, this.dummyCamera);
@@ -96204,10 +96219,14 @@ function createMultiPassSculpture(source) {
       passNames.forEach(function (passName) {
         if (passName in material.uniforms) {
           // is passName our current Buffer?
-          material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
-        } // if(passName in multiPost.passes[passName].material.uniforms) {
-        //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
-        // }
+          material.uniforms[passName].value = multiPost.passes[passName].target.texture; //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+        }
+        /*
+        if (passName in multiPost.passes[passName].material.uniforms) {
+            console.log('setting passName', passName)
+            multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].target.texture;  
+        }
+        */
 
       }); // if('bufferA' in material.uniforms) {
       //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index c14664b..9863cfc 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95849,7 +95849,7 @@ if ( typeof window !== 'undefined' ) {
  */
 
 var MultiPostFX = /*#__PURE__*/function () {
-  function MultiPostFX(params, camera) {
+  function MultiPostFX(params) {
     _classCallCheck(this, MultiPostFX);
 
     this.renderer = params.renderer;
@@ -95980,18 +95980,33 @@ var MultiPostFX = /*#__PURE__*/function () {
         // no passes defined, just render the scene
         this.renderer.render(scene, camera);
       } else {
-        var passes = Object.keys(this.passes);
+        var passNames = Object.keys(this.passes);
 
         for (var i = 0; i < this.nbPasses; i++) {
-          //PingPong texture
-          var curPass = this.passes[passes[i]];
+          var curPass = this.passes[passNames[i]];
+
+          var _iterator = _createForOfIteratorHelper(passNames),
+              _step;
+
+          try {
+            for (_iterator.s(); !(_step = _iterator.n()).done;) {
+              var passName = _step.value;
+              curPass.material.uniforms[passName].value = this.passes[passName].target.texture;
+            } //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+            //PingPong texture
+
+          } catch (err) {
+            _iterator.e(err);
+          } finally {
+            _iterator.f();
+          }
+
           var temp = curPass.targetOld;
           curPass.targetOld = curPass.target;
           curPass.target = temp; //set uniform to correct target for feedback
           // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
           // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
-
-          curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
+          // apply to render target
 
           this.renderer.setRenderTarget(curPass.target);
           this.renderer.render(curPass.scene, this.dummyCamera);
@@ -96200,10 +96215,14 @@ function createMultiPassSculpture(source) {
       passNames.forEach(function (passName) {
         if (passName in material.uniforms) {
           // is passName our current Buffer?
-          material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
-        } // if(passName in multiPost.passes[passName].material.uniforms) {
-        //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
-        // }
+          material.uniforms[passName].value = multiPost.passes[passName].target.texture; //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+        }
+        /*
+        if (passName in multiPost.passes[passName].material.uniforms) {
+            console.log('setting passName', passName)
+            multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].target.texture;  
+        }
+        */
 
       }); // if('bufferA' in material.uniforms) {
       //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index 96e5121..acd764f 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95855,7 +95855,7 @@
    */
 
   var MultiPostFX = /*#__PURE__*/function () {
-    function MultiPostFX(params, camera) {
+    function MultiPostFX(params) {
       _classCallCheck(this, MultiPostFX);
 
       this.renderer = params.renderer;
@@ -95986,18 +95986,33 @@
           // no passes defined, just render the scene
           this.renderer.render(scene, camera);
         } else {
-          var passes = Object.keys(this.passes);
+          var passNames = Object.keys(this.passes);
 
           for (var i = 0; i < this.nbPasses; i++) {
-            //PingPong texture
-            var curPass = this.passes[passes[i]];
+            var curPass = this.passes[passNames[i]];
+
+            var _iterator = _createForOfIteratorHelper(passNames),
+                _step;
+
+            try {
+              for (_iterator.s(); !(_step = _iterator.n()).done;) {
+                var passName = _step.value;
+                curPass.material.uniforms[passName].value = this.passes[passName].target.texture;
+              } //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+              //PingPong texture
+
+            } catch (err) {
+              _iterator.e(err);
+            } finally {
+              _iterator.f();
+            }
+
             var temp = curPass.targetOld;
             curPass.targetOld = curPass.target;
             curPass.target = temp; //set uniform to correct target for feedback
             // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
             // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
-
-            curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture; // apply to render target
+            // apply to render target
 
             this.renderer.setRenderTarget(curPass.target);
             this.renderer.render(curPass.scene, this.dummyCamera);
@@ -96206,10 +96221,14 @@
         passNames.forEach(function (passName) {
           if (passName in material.uniforms) {
             // is passName our current Buffer?
-            material.uniforms[passName].value = multiPost.passes[passName].target.texture; // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
-          } // if(passName in multiPost.passes[passName].material.uniforms) {
-          //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
-          // }
+            material.uniforms[passName].value = multiPost.passes[passName].target.texture; //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+          }
+          /*
+          if (passName in multiPost.passes[passName].material.uniforms) {
+              console.log('setting passName', passName)
+              multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].target.texture;  
+          }
+          */
 
         }); // if('bufferA' in material.uniforms) {
         //     material.uniforms['bufferA'].value = multiPost.passes['bufferA'].target.texture;
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 5a5ea77..872baba 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -59,7 +59,7 @@ import {
  *
  */
 export class MultiPostFX {
-    constructor(params, camera) {
+    constructor(params) {
         this.renderer = params.renderer;
 
         if(!this.renderer) return;
@@ -211,11 +211,18 @@ export class MultiPostFX {
             this.renderer.render(scene, camera);
         }
         else {
-            const passes = Object.keys(this.passes);
+            const passNames = Object.keys(this.passes);
             for(let i = 0; i < this.nbPasses; i++) {
+
+                let curPass = this.passes[passNames[i]];
+                for (let passName of passNames) {
+                    curPass.material.uniforms[passName].value = this.passes[passName].target.texture;
+                }
+
+                //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
                 
                 //PingPong texture
-                let curPass = this.passes[passes[i]];
+                
                 let temp = curPass.targetOld;
                 curPass.targetOld = curPass.target;
                 curPass.target = temp;
@@ -224,7 +231,7 @@ export class MultiPostFX {
                 // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
                 // curPass.material.uniforms[passes[i]].value = curPass.targetOld.texture;
                 
-                curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+                
                 
                 // apply to render target
                 this.renderer.setRenderTarget(curPass.target);
diff --git a/targets/threeJS.js b/targets/threeJS.js
index caa9d6c..18a0b40 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -210,11 +210,15 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
                     // is passName our current Buffer?
                     
                     material.uniforms[passName].value = multiPost.passes[passName].target.texture;
-                   // material.uniforms.lastFrame.value = this.passes[passes[i]].targetOld.texture;
+                    //curPass.material.uniforms.lastFrame.value = curPass.targetOld.texture;
+                
                 }
-                // if(passName in multiPost.passes[passName].material.uniforms) {
-                //     multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].material.uniforms;
-                // }
+                /*
+                if (passName in multiPost.passes[passName].material.uniforms) {
+                    console.log('setting passName', passName)
+                    multiPost.passes[passName].material.uniforms[passName].value = multiPost.passes[passName].target.texture;  
+                }
+                */
             });
             
             // if('bufferA' in material.uniforms) {

From ca5042a9bfc33beb1fd2e762eac4f34da92796ba Mon Sep 17 00:00:00 2001
From: Torin Blankensmith <torin.blankensmith@gmail.com>
Date: Tue, 26 Apr 2022 14:47:07 -0400
Subject: [PATCH 20/20] remove extra console logs

---
 dist/shader-park-core.cjs.js | 8 +-------
 dist/shader-park-core.esm.js | 8 +-------
 dist/shader-park-core.umd.js | 8 +-------
 targets/multiPostFX.js       | 1 -
 targets/threeJS.js           | 8 +-------
 5 files changed, 4 insertions(+), 29 deletions(-)

diff --git a/dist/shader-park-core.cjs.js b/dist/shader-park-core.cjs.js
index 551c32f..5fe2ace 100644
--- a/dist/shader-park-core.cjs.js
+++ b/dist/shader-park-core.cjs.js
@@ -95966,8 +95966,7 @@ var MultiPostFX = /*#__PURE__*/function () {
   }, {
     key: "resize",
     value: function resize() {
-      this.renderer.getDrawingBufferSize(this.resolution);
-      console.log(this.resolution); // resize all passes
+      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
 
       var passes = Object.keys(this.passes);
 
@@ -96082,12 +96081,10 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
         key = _Object$entries$_i[0],
         value = _Object$entries$_i[1];
 
-    console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
     output[key] = src;
   }
 
-  console.log(output);
   var finalImage = output['finalImage'];
   var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
   material.uniformDescriptions = finalImage.uniforms;
@@ -96161,8 +96158,6 @@ function createMultiPassSculpture(source) {
     return {};
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-  // source = convertFunctionToString(source);
-  // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
@@ -96174,7 +96169,6 @@ function createMultiPassSculpture(source) {
   }
 
   var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
-      common = _multiPassSculpToThre.common,
       bufferA = _multiPassSculpToThre.bufferA,
       bufferB = _multiPassSculpToThre.bufferB,
       bufferC = _multiPassSculpToThre.bufferC,
diff --git a/dist/shader-park-core.esm.js b/dist/shader-park-core.esm.js
index 9863cfc..6d286d6 100644
--- a/dist/shader-park-core.esm.js
+++ b/dist/shader-park-core.esm.js
@@ -95962,8 +95962,7 @@ var MultiPostFX = /*#__PURE__*/function () {
   }, {
     key: "resize",
     value: function resize() {
-      this.renderer.getDrawingBufferSize(this.resolution);
-      console.log(this.resolution); // resize all passes
+      this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
 
       var passes = Object.keys(this.passes);
 
@@ -96078,12 +96077,10 @@ function multiPassSculpToThreeJSMaterial(passesSources) {
         key = _Object$entries$_i[0],
         value = _Object$entries$_i[1];
 
-    console.log('keyval', key, value);
     var src = generateThreeJSFrag(value);
     output[key] = src;
   }
 
-  console.log(output);
   var finalImage = output['finalImage'];
   var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
   material.uniformDescriptions = finalImage.uniforms;
@@ -96157,8 +96154,6 @@ function createMultiPassSculpture(source) {
     return {};
   };
   var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-  // source = convertFunctionToString(source);
-  // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
   var radius = 'radius' in params ? params.radius : 2;
   var geometry;
 
@@ -96170,7 +96165,6 @@ function createMultiPassSculpture(source) {
   }
 
   var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
-      common = _multiPassSculpToThre.common,
       bufferA = _multiPassSculpToThre.bufferA,
       bufferB = _multiPassSculpToThre.bufferB,
       bufferC = _multiPassSculpToThre.bufferC,
diff --git a/dist/shader-park-core.umd.js b/dist/shader-park-core.umd.js
index acd764f..83af8d6 100644
--- a/dist/shader-park-core.umd.js
+++ b/dist/shader-park-core.umd.js
@@ -95968,8 +95968,7 @@
     }, {
       key: "resize",
       value: function resize() {
-        this.renderer.getDrawingBufferSize(this.resolution);
-        console.log(this.resolution); // resize all passes
+        this.renderer.getDrawingBufferSize(this.resolution); // resize all passes
 
         var passes = Object.keys(this.passes);
 
@@ -96084,12 +96083,10 @@
           key = _Object$entries$_i[0],
           value = _Object$entries$_i[1];
 
-      console.log('keyval', key, value);
       var src = generateThreeJSFrag(value);
       output[key] = src;
     }
 
-    console.log(output);
     var finalImage = output['finalImage'];
     var material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
     material.uniformDescriptions = finalImage.uniforms;
@@ -96163,8 +96160,6 @@
       return {};
     };
     var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-    // source = convertFunctionToString(source);
-    // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
     var radius = 'radius' in params ? params.radius : 2;
     var geometry;
 
@@ -96176,7 +96171,6 @@
     }
 
     var _multiPassSculpToThre = multiPassSculpToThreeJSMaterial(source),
-        common = _multiPassSculpToThre.common,
         bufferA = _multiPassSculpToThre.bufferA,
         bufferB = _multiPassSculpToThre.bufferB,
         bufferC = _multiPassSculpToThre.bufferC,
diff --git a/targets/multiPostFX.js b/targets/multiPostFX.js
index 872baba..85fb981 100644
--- a/targets/multiPostFX.js
+++ b/targets/multiPostFX.js
@@ -195,7 +195,6 @@ export class MultiPostFX {
 
     resize() {
         this.renderer.getDrawingBufferSize(this.resolution);
-        console.log(this.resolution)
         // resize all passes
         const passes = Object.keys(this.passes);
         for(let i = 0; i < this.nbPasses; i++) {
diff --git a/targets/threeJS.js b/targets/threeJS.js
index 18a0b40..77f7263 100644
--- a/targets/threeJS.js
+++ b/targets/threeJS.js
@@ -78,11 +78,9 @@ export function multiPassSculpToThreeJSMaterial(passesSources) {
     const passes = spCodeToMultiPassGLSL(passesSources);
     let output = {};
     for (const [key, value] of Object.entries(passes)) {
-        console.log('keyval', key, value)
         let src = generateThreeJSFrag(value);
         output[key] = src;
     }
-    console.log(output)
     let finalImage = output['finalImage'];
     let material = makeMaterial(finalImage.uniforms, finalImage.vert, finalImage.frag);
     material.uniformDescriptions = finalImage.uniforms;
@@ -153,10 +151,6 @@ export function createMultiPassSculptureWithGeometry(geometry, source, uniformCa
 
 // TODO NEXT Replace sculptToThreeJSMaterial with 
 export function createMultiPassSculpture(source, uniformCallback=() => {return {}}, params={}) {
-    
-    // source = convertFunctionToString(source);
-    // let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = source;
-
     let radius = ('radius' in params)? params.radius: 2;
 
     let geometry;
@@ -166,7 +160,7 @@ export function createMultiPassSculpture(source, uniformCallback=() => {return {
         let segments = ('segments' in params)? params.segments: 10;
         geometry = new SphereBufferGeometry( radius, segments, segments );   
     }
-    let {common, bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
+    let {bufferA, bufferB, bufferC, bufferD, finalImage} = multiPassSculpToThreeJSMaterial(source);
     let passes = {
         bufferA: {
             fragmentShader: bufferA.frag,
