diff --git a/src/js/main.js b/src/js/main.js
index 5988708d..0d0af4a7 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -68,7 +68,7 @@ define([
"use strict";
-
+ const compressor = new LZMA( 'lzma_worker.js' );
// There's really no good way to tell which browsers fail.
// Right now Safari doesn't expose AudioContext (it's still webkitAudioContext)
@@ -79,6 +79,8 @@ define([
var $ = document.querySelector.bind(document);
var gl;
var m4 = twgl.m4;
+ const { base64 } = misc;
+ let s_firstCompile = true;
var q = misc.parseUrlQuery();
var s = {
screenshotCanvas: document.createElement("canvas"),
@@ -1264,6 +1266,21 @@ define([
settings.shader = e.userData;
setShaderSuccessStatus(true);
clearLineErrors();
+ if (s_firstCompile) {
+ s_firstCompile = false;
+ return;
+ }
+ const art = {
+ settings,
+ };
+ const data = JSON.stringify(art);
+ compressor.compress(data, 1, function(bytes) {
+ const hex = base64.encode(bytes);
+ const params = new URLSearchParams({
+ s: hex
+ });
+ parent.history.replaceState({}, '', `/src/#${params.toString()}`);
+ });
});
s.programManager.on('failure', function(errors) {
setShaderSuccessStatus(false);
@@ -2188,6 +2205,22 @@ define([
}
}
+ if (window.location.hash.includes("s=")) {
+ try {
+ const p = new URLSearchParams(window.location.hash.substring(1));
+ const bytes = base64.decode(p.get('s'));
+ await new Promise((resolve, reject) => {
+ compressor.decompress(bytes, function(text) {
+ const art = JSON.parse(text);
+ settings = art.settings;
+ resolve();
+ }, () => {}, reject);
+ });
+ } catch {
+ settings = s.sets.default;
+ }
+ }
+
document.querySelectorAll('.parentLink').forEach(elem => {
elem.addEventListener('click', function(event) {
if (parent) {
diff --git a/src/js/misc.js b/src/js/misc.js
index b23207ee..e2384b76 100644
--- a/src/js/misc.js
+++ b/src/js/misc.js
@@ -534,10 +534,18 @@ define(function() {
return a === b;
}
+ const base64 = {
+ decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
+ encode: b => btoa(String.fromCharCode(...new Uint8Array(b))),
+ decodeToString: s => new TextDecoder().decode(base64.decode(s)),
+ encodeString: s => base64.encode(new TextEncoder().encode(s)),
+ };
+
return {
applyObject: applyObject,
applyUrlSettings: applyUrlSettings,
applyListeners: applyListeners,
+ base64,
clamp: clamp,
clampPlusMinus: clampPlusMinus,
copyProperties: copyProperties,
diff --git a/src/lzma.js b/src/lzma.js
new file mode 100644
index 00000000..7aec536f
--- /dev/null
+++ b/src/lzma.js
@@ -0,0 +1,126 @@
+/// This code is licensed under the MIT License. See LICENSE for more details.
+
+/// Does the environment support web workers? If not, let's fake it.
+if (!Worker) {
+ ///NOTE: IE8 needs onmessage to be created first, IE9 cannot, IE7- do not care.
+ /*@cc_on
+ /// Is this IE8-?
+ @if (@_jscript_version < 9)
+ var onmessage = function () {};
+ @end
+ @*/
+
+ /// If this were a regular function statement, IE9 would run it first and therefore make the Worker variable truthy because of hoisting.
+ var Worker = function(script) {
+ var global_var,
+ return_object = {};
+
+ /// Determine the global variable (it's called "window" in browsers, "global" in Node.js).
+ if (typeof window !== "undefined") {
+ global_var = window;
+ } else if (global) {
+ global_var = global;
+ }
+
+ /// Is the environment is browser?
+ /// If not, create a require() function, if it doesn't have one.
+ if (global_var.document && !global_var.require) {
+ global_var.require = function (path) {
+ var script_tag = document.createElement("script");
+ script_tag.type ="text/javascript";
+ script_tag.src = path;
+ document.getElementsByTagName('head')[0].appendChild(script_tag);
+ };
+ }
+
+ /// Dummy onmessage() function.
+ return_object.onmessage = function () {};
+
+ /// This is the function that the main script calls to post a message to the "worker."
+ return_object.postMessage = function (message) {
+ /// Delay the call just in case the "worker" script has not had time to load.
+ setTimeout(function () {
+ /// Call the global onmessage() created by the "worker."
+ ///NOTE: Wrap the message in an object.
+ global_var.onmessage({data: message});
+ }, 10);
+ };
+
+ /// Create a global postMessage() function for the "worker" to call.
+ global_var.postMessage = function (e) {
+ ///NOTE: Wrap the message in an object.
+ ///TODO: Add more properties.
+ return_object.onmessage({data: e, type: "message"});
+ };
+
+ require(script);
+
+ return return_object;
+ };
+}
+
+
+///NOTE: The "this" keyword is the global context ("window" variable) if loaded via a