diff --git a/README.md b/README.md
index 3a081da..6613832 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Ronin is a procedural graphics tool designed to automate simple graphical
The library updates is constantly revealing new applications to Ronin, you can see the list of available functions here . Most of our iconography and designs were created with both Ronin and Dotgrid .
-Learn more by reading the manual , or have a look at some experiments on twitter . If you need help , visit the Community , follow the [workshop](https://github.com/hundredrabbits/Ronin/blob/master/WORKSHOP.md) or watch the [video tutorial](https://www.youtube.com/watch?v=SgAWGh1s9zg).
+Learn more by reading the manual , or have a look at some experiments on twitter . If you need help , visit the Community , follow the [workshop](https://github.com/hundredrabbits/Ronin/blob/master/resources/WORKSHOP.md) or watch the [video tutorial](https://www.youtube.com/watch?v=SgAWGh1s9zg).
```lisp
; clear screen
@@ -29,7 +29,7 @@ npm install
npm start
```
-
+
## Helpers
@@ -152,9 +152,9 @@ To save an image in memory, open an image file with Ronin, or drag an image file
- `(test name a b)`
- `(benchmark fn)` Logs time taken to execute a function.
-
+
-
+
## Extras
diff --git a/desktop/icon.svg b/desktop/icon.svg
index 6c60788..ae2f668 100644
--- a/desktop/icon.svg
+++ b/desktop/icon.svg
@@ -1,4 +1,6 @@
-
+
-
+
+
+
\ No newline at end of file
diff --git a/desktop/package-lock.json b/desktop/package-lock.json
index ce75acb..5c622fd 100644
--- a/desktop/package-lock.json
+++ b/desktop/package-lock.json
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@electron/get": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.6.0.tgz",
- "integrity": "sha512-xuvAzbN9iBApfAMvW0hKUpxHR5wPVbG9RaoSTbpu/WaHISDu0MVfMWYhfeU0X730CpBV0G2RkLgwAs9WDan3GA==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.2.tgz",
+ "integrity": "sha512-LSE4LZGMjGS9TloDx0yO44D2UTbaeKRk+QjlhWLiQlikV6J4spgDCjb6z4YIcqmPAwNzlNCnWF4dubytwI+ATA==",
"dev": true,
"requires": {
"debug": "^4.1.1",
@@ -17,7 +17,7 @@
"global-tunnel-ng": "^2.7.1",
"got": "^9.6.0",
"sanitize-filename": "^1.6.2",
- "sumchecker": "^3.0.0"
+ "sumchecker": "^3.0.1"
}
},
"@sindresorhus/is": {
@@ -36,15 +36,15 @@
}
},
"@types/node": {
- "version": "12.12.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.5.tgz",
- "integrity": "sha512-KEjODidV4XYUlJBF3XdjSH5FWoMCtO0utnhtdLf1AgeuZLOrRbvmU/gaRCVg7ZaQDjVf3l84egiY0mRNe5xE4A==",
+ "version": "12.12.26",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.26.tgz",
+ "integrity": "sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==",
"dev": true
},
"asar": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/asar/-/asar-2.0.1.tgz",
- "integrity": "sha512-Vo9yTuUtyFahkVMFaI6uMuX6N7k5DWa6a/8+7ov0/f8Lq9TVR0tUjzSzxQSxT1Y+RJIZgnP7BVb6Uhi+9cjxqA==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/asar/-/asar-2.0.3.tgz",
+ "integrity": "sha512-QdHKO+HOYVtE4B/M3up3i4LSJeJgsa2CTVBrjBf9GgLUPGGUFZowcdJ5yE4gOJuRAHNdqB9JFeRfFfaOu5x8Rw==",
"dev": true,
"requires": {
"chromium-pickle-js": "^0.2.0",
@@ -75,15 +75,15 @@
"dev": true
},
"bluebird": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
- "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"boolean": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/boolean/-/boolean-2.0.3.tgz",
- "integrity": "sha512-iHzXeFCXWrpjYE7DToXGCBPGZf0eVISqzL+4sgrOSYEKXnb59WHPFvGTTyCj6zJ/MuuLAxEn8zPkrTHHzlt3IA==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz",
+ "integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ==",
"dev": true,
"optional": true
},
@@ -220,9 +220,9 @@
}
},
"core-js": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.6.tgz",
- "integrity": "sha512-u4oM8SHwmDuh5mWZdDg9UwNVq5s1uqq6ZDLLIs07VY+VJU91i3h4f3K/pgFvtUQPGdeStrZ+odKyfyt4EnKHfA==",
+ "version": "3.6.4",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
+ "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
"dev": true,
"optional": true
},
@@ -233,18 +233,18 @@
"dev": true
},
"cross-zip": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-2.1.6.tgz",
- "integrity": "sha512-xLIETNkzRcU6jGRzenJyRFxahbtP4628xEKMTI/Ql0Vu8m4h8M7uRLVi7E5OYHuJ6VQPsG4icJumKAFUvfm0+A==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-3.0.0.tgz",
+ "integrity": "sha512-cm+l8PJ6WiSQmKZ/x8DGvUm2u/3FX2JFs1AFd18gdHaVhP5Lf4oE6Jrj2Jd05JYSioz5x+nIRVp0zBQuzuCRcQ==",
"dev": true,
"requires": {
"rimraf": "^3.0.0"
},
"dependencies": {
"rimraf": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
- "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
+ "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"
@@ -283,9 +283,9 @@
}
},
"defer-to-connect": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.0.tgz",
- "integrity": "sha512-WE2sZoctWm/v4smfCAdjYbrfS55JiMRdlY9ZubFhsYbteCK9+BvAx4YV7nPjYM6ZnX5BcoVKwfmyx9sIFTgQMQ==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
"dev": true
},
"define-properties": {
@@ -312,9 +312,9 @@
"dev": true
},
"electron": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/electron/-/electron-7.0.1.tgz",
- "integrity": "sha512-eMFoZIO0+eOAE9FyNC/f0Vp8l/sJziTMK+axEt2XIpGCagom1IZgUKPGwmHUcftZCX5lNKh+Tv53T0GcNnNTKQ==",
+ "version": "7.1.11",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-7.1.11.tgz",
+ "integrity": "sha512-YDXfnovKY+8iZ5ISQh1kRqYIRKbpOSxGXCx2WVxPFPutEQ7Q/Xzr3h4GePEY25/NXMytMfhKaAZAYjtWUm3r9Q==",
"dev": true,
"requires": {
"@electron/get": "^1.0.1",
@@ -323,19 +323,19 @@
}
},
"electron-notarize": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-0.1.1.tgz",
- "integrity": "sha512-TpKfJcz4LXl5jiGvZTs5fbEx+wUFXV5u8voeG5WCHWfY/cdgdD8lDZIZRqLVOtR3VO+drgJ9aiSHIO9TYn/fKg==",
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-0.2.1.tgz",
+ "integrity": "sha512-oZ6/NhKeXmEKNROiFmRNfytqu3cxqC95sjooG7kBXQVEUSQkZnbiAhxVh5jXngL881G197pbwpeVPJyM7Ikmxw==",
"dev": true,
"requires": {
"debug": "^4.1.1",
- "fs-extra": "^8.0.1"
+ "fs-extra": "^8.1.0"
}
},
"electron-osx-sign": {
- "version": "0.4.14",
- "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.14.tgz",
- "integrity": "sha512-72vtrz9I3dOeFDaNvO5thwIjrimDiXMmYEbN0hEBqnvcSSMOWugjim2wiY9ox3dhuBFUhxp3owmuZCoH3Ij08A==",
+ "version": "0.4.15",
+ "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.15.tgz",
+ "integrity": "sha512-1QtPNpjIji9bGZ0VRFwtJUyU1uHi7q3XUAOG0qFsvAUfs5H0T8hbgUfyg3xvPzmF1ruV8T8pQmQ86vNfLrcRiA==",
"dev": true,
"requires": {
"bluebird": "^3.5.0",
@@ -370,16 +370,16 @@
}
},
"electron-packager": {
- "version": "14.1.0",
- "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-14.1.0.tgz",
- "integrity": "sha512-4oGtQYYjSA/M4BGOwG0NBqEtThBf7aCV76C2AZsD71eGocYqZNvtvfzeeMnKkc3EW1nPq7iJ4Wge+GXma0kwIA==",
+ "version": "14.2.1",
+ "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-14.2.1.tgz",
+ "integrity": "sha512-g6y3BVrAOz/iavKD+VMFbehrQcwCWuA3CZvVbmmbQuCfegGA1ytwWn0BNIDDrEdbuz31Fti7mnNHhb5L+3Wq9A==",
"dev": true,
"requires": {
"@electron/get": "^1.6.0",
"asar": "^2.0.1",
- "cross-zip": "^2.1.5",
+ "cross-zip": "^3.0.0",
"debug": "^4.0.1",
- "electron-notarize": "^0.1.1",
+ "electron-notarize": "^0.2.0",
"electron-osx-sign": "^0.4.11",
"fs-extra": "^8.1.0",
"galactus": "^0.2.1",
@@ -392,6 +392,14 @@
"sanitize-filename": "^1.6.0",
"semver": "^6.0.0",
"yargs-parser": "^16.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
}
},
"encodeurl": {
@@ -526,13 +534,6 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": 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,
- "optional": true
- },
"galactus": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/galactus/-/galactus-0.2.1.tgz",
@@ -605,9 +606,9 @@
}
},
"glob": {
- "version": "7.1.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
- "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
+ "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",
@@ -619,18 +620,18 @@
}
},
"global-agent": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.5.tgz",
- "integrity": "sha512-pYJjCxxNBzYxo6iNO62JZn8iCFVbvpiM0zE4w/G5hBNIvLjnvzIeCVQPMKc3aK8ju5L7Q8NNI/oBSosU0eeSYw==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz",
+ "integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==",
"dev": true,
"optional": true,
"requires": {
- "boolean": "^2.0.2",
- "core-js": "^3.3.3",
+ "boolean": "^3.0.0",
+ "core-js": "^3.6.4",
"es6-error": "^4.1.1",
- "matcher": "^2.0.0",
- "roarr": "^2.14.2",
- "semver": "^6.3.0",
+ "matcher": "^2.1.0",
+ "roarr": "^2.15.2",
+ "semver": "^7.1.2",
"serialize-error": "^5.0.0"
}
},
@@ -648,15 +649,13 @@
}
},
"globalthis": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.0.tgz",
- "integrity": "sha512-vcCAZTJ3r5Qcu5l8/2oyVdoFwxKgfYnMTR2vwWeux/NAVZK3PwcMaWkdUIn4GJbmKuRK7xcvDsLuK+CKcXyodg==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz",
+ "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==",
"dev": true,
"optional": true,
"requires": {
- "define-properties": "^1.1.2",
- "function-bind": "^1.1.1",
- "object-keys": "^1.0.12"
+ "define-properties": "^1.1.3"
}
},
"got": {
@@ -827,9 +826,9 @@
"dev": true
},
"matcher": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.0.0.tgz",
- "integrity": "sha512-nlmfSlgHBFx36j/Pl/KQPbIaqE8Zf0TqmSMjsuddHDg6PMSVgmyW9HpkLs0o0M1n2GIZ/S2BZBLIww/xjhiGng==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz",
+ "integrity": "sha512-o+nZr+vtJtgPNklyeUKkkH42OsK8WAfdgaJE2FNxcjLPg+5QbeEoT6vRj8Xq/iv18JlQ9cmKsEu0b94ixWf1YQ==",
"dev": true,
"optional": true,
"requires": {
@@ -1089,9 +1088,9 @@
}
},
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -1104,9 +1103,9 @@
}
},
"resolve": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
- "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
+ "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
@@ -1131,15 +1130,15 @@
}
},
"roarr": {
- "version": "2.14.3",
- "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.14.3.tgz",
- "integrity": "sha512-D4BpKVruUDCJ9DJWcC7T+fx4o10IUYJ7MdmjM4Skx1aqc42CE7LGzPDUAfczibhavNGcnY1IHqJdq16NmiG4rQ==",
+ "version": "2.15.2",
+ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.2.tgz",
+ "integrity": "sha512-jmaDhK9CO4YbQAV8zzCnq9vjAqeO489MS5ehZ+rXmFiPFFE6B+S9KYO6prjmLJ5A0zY3QxVlQdrIya7E/azz/Q==",
"dev": true,
"optional": true,
"requires": {
- "boolean": "^2.0.2",
+ "boolean": "^3.0.0",
"detect-node": "^2.0.4",
- "globalthis": "^1.0.0",
+ "globalthis": "^1.0.1",
"json-stringify-safe": "^5.0.1",
"semver-compare": "^1.0.0",
"sprintf-js": "^1.1.2"
@@ -1161,10 +1160,11 @@
}
},
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.2.tgz",
+ "integrity": "sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ==",
+ "dev": true,
+ "optional": true
},
"semver-compare": {
"version": "1.0.0",
@@ -1238,9 +1238,9 @@
"dev": true
},
"sumchecker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.0.tgz",
- "integrity": "sha512-yreseuC/z4iaodVoq07XULEOO9p4jnQazO7mbrnDSvWAU/y2cbyIKs+gWJptfcGu9R+1l27K8Rkj0bfvqnBpgQ==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
+ "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
"dev": true,
"requires": {
"debug": "^4.1.0"
@@ -1350,9 +1350,9 @@
"dev": true
},
"xmldom": {
- "version": "0.1.27",
- "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
- "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=",
+ "version": "0.1.31",
+ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
+ "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
"dev": true
},
"yargs-parser": {
diff --git a/desktop/package.json b/desktop/package.json
index 9d8f23a..d223733 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -3,13 +3,14 @@
"version": "0.1.0",
"main": "main.js",
"scripts": {
- "start": "electron .",
+ "start": "electron . --disable-gpu",
"fix": "standard --fix",
"clean": "rm -r ~/Documents/Ronin-darwin-x64/ ; rm -r ~/Documents/Ronin-linux-x64/ ; rm -r ~/Documents/Ronin-win32-x64/ ; echo 'cleaned build location'",
"build_osx": "electron-packager . Ronin --platform=darwin --arch=x64 --out ~/Documents/ --overwrite --icon=icon.icns ; echo 'Built for OSX'",
"build_linux": "electron-packager . Ronin --platform=linux --arch=x64 --out ~/Documents/ --overwrite --icon=icon.ico ; echo 'Built for LINUX'",
"build_win": "electron-packager . Ronin --platform=win32 --arch=x64 --out ~/Documents/ --overwrite --icon=icon.ico ; echo 'Built for WIN'",
- "build": "npm run clean ; npm run build_osx ; npm run build_linux ; npm run build_win",
+ "build": "npm run clean ; npm run build_osx ; npm run build_linux ; npm run build_win ; npm run add_manual",
+ "add_manual": "cp ../resources/MANUAL.txt ~/Documents/Ronin-darwin-x64/MANUAL.txt ; cp ../resources/MANUAL.txt ~/Documents/Ronin-linux-x64/MANUAL.txt ; cp ../resources/MANUAL.txt ~/Documents/Ronin-win32-x64/MANUAL.txt",
"push_osx": "~/Applications/butler push ~/Documents/Ronin-darwin-x64/ hundredrabbits/ronin:osx-64",
"push_linux": "~/Applications/butler push ~/Documents/Ronin-linux-x64/ hundredrabbits/ronin:linux-64",
"push_win": "~/Applications/butler push ~/Documents/Ronin-win32-x64/ hundredrabbits/ronin:windows-64",
@@ -17,8 +18,8 @@
"push": "npm run build ; npm run push_osx ; npm run push_linux ; npm run push_win ; npm run clean ; npm run status"
},
"devDependencies": {
- "electron": "^7.1.5",
- "electron-packager": "^14.1.1"
+ "electron": "^7.1.11",
+ "electron-packager": "^14.2.1"
},
"standard": {
"globals": [
diff --git a/desktop/sources/scripts/client.js b/desktop/sources/scripts/client.js
index 3da2acd..0975bf2 100644
--- a/desktop/sources/scripts/client.js
+++ b/desktop/sources/scripts/client.js
@@ -39,8 +39,8 @@ function Client () {
window.addEventListener('drop', this.onDrop)
this.acels.set('File', 'New', 'CmdOrCtrl+N', () => { this.source.new(); this.surface.clear(); this.commander.clear() })
- this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.download('ronin', 'lisp', this.commander._input.value, 'text/plain') })
- this.acels.set('File', 'Export Image', 'CmdOrCtrl+E', () => { this.source.download('ronin', 'png', this.surface.el.toDataURL('image/png', 1.0), 'image/png') })
+ this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.write('ronin', 'lisp', this.commander._input.value, 'text/plain') })
+ this.acels.set('File', 'Export Image', 'CmdOrCtrl+E', () => { this.source.write('ronin', 'png', this.surface.el.toDataURL('image/png', 1.0), 'image/png') })
this.acels.set('File', 'Open', 'CmdOrCtrl+O', () => { this.source.open('lisp', this.whenOpen) })
this.acels.add('Edit', 'undo')
diff --git a/desktop/sources/scripts/lib/acels.js b/desktop/sources/scripts/lib/acels.js
index 40320bc..62f630c 100644
--- a/desktop/sources/scripts/lib/acels.js
+++ b/desktop/sources/scripts/lib/acels.js
@@ -37,10 +37,10 @@ function Acels (client) {
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
return `CmdOrCtrl+Shift+${accelerator}`
}
- if (event.shiftKey) {
+ if (event.shiftKey && event.key.toUpperCase() !== event.key) {
return `Shift+${accelerator}`
}
- if (event.altKey) {
+ if (event.altKey && event.key.length !== 1) {
return `Alt+${accelerator}`
}
if (event.ctrlKey || event.metaKey) {
@@ -73,7 +73,7 @@ function Acels (client) {
for (const cat in cats) {
text += `\n### ${cat}\n\n`
for (const item of cats[cat]) {
- text += item.accelerator ? `- \`${item.accelerator}\`: ${item.info}\n` : ''
+ text += item.accelerator ? `- \`${item.accelerator.replace('`', 'tilde')}\`: ${item.name}\n` : ''
}
}
return text.trim()
@@ -83,8 +83,9 @@ function Acels (client) {
const cats = this.sort()
let text = ''
for (const cat in cats) {
+ text += `\n${cat}\n\n`
for (const item of cats[cat]) {
- text += item.accelerator ? `${cat}: ${item.name} | ${item.accelerator}\n` : ''
+ text += item.accelerator ? `${item.name.padEnd(25, '.')} ${item.accelerator}\n` : ''
}
}
return text.trim()
@@ -105,13 +106,13 @@ function Acels (client) {
submenu: [
{ label: 'Download Themes', click: () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Themes') } },
{ label: 'Open Theme', click: () => { client.theme.open() } },
- { label: 'Reset Theme', click: () => { client.theme.reset() } }
+ { label: 'Reset Theme', accelerator: 'CmdOrCtrl+Escape', click: () => { client.theme.reset() } }
]
},
{ label: 'Fullscreen', accelerator: 'CmdOrCtrl+Enter', click: () => { app.toggleFullscreen() } },
{ label: 'Hide', accelerator: 'CmdOrCtrl+H', click: () => { app.toggleVisible() } },
{ label: 'Toggle Menubar', accelerator: 'Alt+H', click: () => { app.toggleMenubar() } },
- { label: 'Inspect', accelerator: 'CmdOrCtrl+.', click: () => { app.inspect() } },
+ { label: 'Inspect', accelerator: 'CmdOrCtrl+Tab', click: () => { app.inspect() } },
{ role: 'quit' }
]
})
diff --git a/desktop/sources/scripts/lib/source.js b/desktop/sources/scripts/lib/source.js
index f651b2e..ba2554c 100644
--- a/desktop/sources/scripts/lib/source.js
+++ b/desktop/sources/scripts/lib/source.js
@@ -18,14 +18,14 @@ function Source (client) {
this.cache = {}
}
- this.open = (ext, callback) => {
+ this.open = (ext, callback, store = false) => {
console.log('Source', 'Open file..')
const input = document.createElement('input')
input.type = 'file'
input.onchange = (e) => {
const file = e.target.files[0]
if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return }
- this.read(file, callback)
+ this.read(file, callback, store)
}
input.click()
}
@@ -37,7 +37,7 @@ function Source (client) {
input.setAttribute('multiple', 'multiple')
input.onchange = (e) => {
for (const file of e.target.files) {
- if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return }
+ if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); continue }
this.read(file, this.store)
}
}
@@ -60,11 +60,12 @@ function Source (client) {
// I/O
- this.read = (file, callback) => {
+ this.read = (file, callback, store = false) => {
const reader = new FileReader()
reader.onload = (event) => {
const res = event.target.result
if (callback) { callback(file, res) }
+ if (store) { this.store(file, res) }
}
reader.readAsText(file, 'UTF-8')
}
diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js
index 187ca84..d7f412b 100644
--- a/desktop/sources/scripts/library.js
+++ b/desktop/sources/scripts/library.js
@@ -1,5 +1,6 @@
'use strict'
+/* global Image */
/* global Image */
function Library (client) {
@@ -11,12 +12,9 @@ function Library (client) {
return shape || this.rect(0, 0, img.width, img.height)
}
- this.export = async (name = 'export', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
- const base64 = client.surface.el.toDataURL(type, quality)
- const link = document.createElement('a')
- link.setAttribute('href', base64)
- link.setAttribute('download', type === 'image/png' ? name + '.png' : name + '.jpg')
- link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))
+ this.export = async (name = 'ronin', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
+ const ext = type === 'image/png' ? name + '.png' : name + '.jpg'
+ client.source.write(name, ext, client.surface.el.toDataURL(type, 1.0), type)
}
// Shapes
diff --git a/resources/MANUAL.txt b/resources/MANUAL.txt
new file mode 100644
index 0000000..f763f1a
--- /dev/null
+++ b/resources/MANUAL.txt
@@ -0,0 +1,22 @@
+File
+
+New...................... CmdOrCtrl+N
+Save..................... CmdOrCtrl+S
+Export Image............. CmdOrCtrl+E
+Open..................... CmdOrCtrl+O
+
+Edit
+
+
+View
+
+Toggle Guides............ CmdOrCtrl+Shift+H
+Toggle Commander......... CmdOrCtrl+K
+Expand Commander......... CmdOrCtrl+Shift+K
+
+Project
+
+Run...................... CmdOrCtrl+R
+Reload Run............... CmdOrCtrl+Shift+R
+Re-Indent................ CmdOrCtrl+Shift+I
+Clean.................... Escape
\ No newline at end of file
diff --git a/resources/PRELUDE.md b/resources/PRELUDE.md
new file mode 100644
index 0000000..55fc238
--- /dev/null
+++ b/resources/PRELUDE.md
@@ -0,0 +1,46 @@
+# Prelude
+
+## Colors
+
+### Compare two Colors
+
+Use: `(if (color-eq (255 200 0) (200 255 0)) "yes" "no")`.
+
+```
+(defn color-eq
+ (a b)
+ (and
+ (eq a:0 b:0)
+ (eq a:1 b:1)
+ (eq a:2 b:2)))
+```
+
+## Pixels
+
+### Erase all pixels of a specific color
+
+Use: `(pixels erase-color (255 0 0))`.
+
+```
+(defn erase-color
+ (a b)
+ (a:0 a:1 a:2
+ (if
+ (and
+ (eq a:0 b:0)
+ (eq a:1 b:1)
+ (eq a:2 b:2)) 0 255)))
+```
+
+### Posterize
+
+Use: `(pixels posterize 40)`.
+
+```
+(defn posterize
+ (a q)
+ (
+ (step a:0 q)
+ (step a:1 q)
+ (step a:2 q) a:3))
+```
\ No newline at end of file
diff --git a/resources/PREVIEW.jpg b/resources/PREVIEW.jpg
new file mode 100644
index 0000000..3878100
Binary files /dev/null and b/resources/PREVIEW.jpg differ
diff --git a/resources/PREVIEW2.jpg b/resources/PREVIEW2.jpg
new file mode 100644
index 0000000..61e3447
Binary files /dev/null and b/resources/PREVIEW2.jpg differ
diff --git a/resources/PREVIEW3.jpg b/resources/PREVIEW3.jpg
new file mode 100644
index 0000000..9d87853
Binary files /dev/null and b/resources/PREVIEW3.jpg differ
diff --git a/resources/WORKSHOP.md b/resources/WORKSHOP.md
new file mode 100644
index 0000000..2f7a5e4
--- /dev/null
+++ b/resources/WORKSHOP.md
@@ -0,0 +1,261 @@
+# Workshop
+
+
+
+This workshop is designed to go over the **most commonly used functions** with [Ronin](https://github.com/hundredrabbits/Ronin). The list of all available functions and their usage is located [here](https://github.com/hundredrabbits/Ronin/#library). You can also follow along our [video tutorial](https://youtu.be/SgAWGh1s9zg).
+
+- **Part 1**: [Images](#Images) `(import)`, `(crop)`, `(export)`
+- **Part 2**: [Draw](#Draw) `(stroke)`, `(fill)`, `(gradient)`, `(clear)`
+- **Part 3**: [Filters](#Filters) `(pixels)`, `(saturation)`, `(convolve)`, `(sharpen)`
+- **Part 4**: [Events](#Events) `(echo)`, `(on "mouse-down")`, `(on "animate")`, `(on "/a")`
+
+## Images
+
+This section will teach the basics of opening, cropping and saving an image file. You can use the `$path` helper to quickly get an image's path into Ronin, by writing `$path` and dragging a file onto the Ronin window.
+
+### Import
+
+To import an image onto the current canvas, type the following text, drag an image file onto the Ronin window, trace a shape in the canvas and press `cmd+r`:
+
+```lisp
+(import $path
+ (guide $rect))
+```
+
+The previous code will import an image, and preserve its ratio. Alternatively, you could use a `$line` to stretch the image, or a `$pos` to simply draw the image at its original size.
+
+```lisp
+(import $path
+ (guide $line))
+```
+
+### Crop
+
+To crop the canvas, type the following text, drag an image file onto the Ronin window press `cmd+r`:
+
+```lisp
+(import $path
+ (pos 0 0))
+(crop
+ (rect 50 50 300 300))
+```
+
+### Export
+
+To export the resulting image, type the following text, drag an image file onto the Ronin window, then drag a folder and add the new file's name, and press `cmd+r`:
+
+```lisp
+(import $path)
+(export $path)
+```
+
+For example, a version of that same code with file paths, might look something like the following:
+
+```lisp
+(import "~/Desktop/photo.jpg")
+(export "~/Desktop/export.png")
+```
+
+You could also **generate the export path from the import path**. To import `~/Desktop/photo.jpg`, and automatically generate the export path `~/Desktop/photo-export.jpg`, use this:
+
+```lisp
+(def import-path $path)
+(def export-path
+ (concat
+ (dirpath import-path) "/"
+ (filename import-path) "-export.jpg"))
+(import import-path)
+(export export-path)
+```
+
+## Draw
+
+This section will teach you how to draw some basic shapes and colorize them.
+
+### Stroke
+
+In Ronin, a shape is either a `(rect)`, a `(line)`, a `(circle)` or a `(pos)`. To draw the outline of any shape, wrap the shape inside of a `(stroke shape width color)` function, like:
+
+```lisp
+(stroke
+ (rect 100 100 300 200) "red" 10)
+```
+
+Or, if you would like to trace the shape with your mouse:
+
+```lisp
+(stroke
+ $rect "red" 10)
+```
+
+### Fill
+
+To fill the inside of any shape, wrap it inside of a `(fill shape color)` function, like:
+
+```lisp
+(fill
+ (rect 100 100 300 200) "orange")
+```
+
+### Gradient
+
+To colorize a stroke or a fill, with a gradient, use the `(gradient line colors)` where the colors is a list of colors like `("blue" "red" "yellow")`:
+
+```lisp
+(clear)
+(fill
+ (circle 300 300 200)
+ (gradient
+ (line 0 0 500 500)
+ ("white" "black")))
+```
+
+To better understand how the `(line)` affects the coloring of the circle, wrap the `$line` inside a `(guide)`, as follows to preserve the guide interface:
+
+```lisp
+(clear)
+(fill
+ (circle 300 300 200)
+ (gradient
+ (guide $line)
+ ("white" "black")))
+```
+
+### Clear
+
+In the previous example, we used the `(clear)` function, which clears the canvas, but it can also be used to clear only a part of the canvas:
+
+```lisp
+(clear)
+(fill
+ frame "red")
+(clear
+ (rect 100 100 300 300))
+```
+
+## Filters
+
+This section will cover how to manipulate the pixels of an image.
+
+### Pixels
+
+First let's open an image, ideally one in color, and change every pixel of a selected area at `(rect 100 100 200 200)`:
+
+```lisp
+(import $path)
+(pixels saturation 10
+ (rect 100 100 200 200))
+```
+
+The `(pixels)` function expects a function that returns 4 values(r,g,b,a), and so you can define a custom filter like:
+
+```
+(defn invert
+ (pixel)
+ (
+ (sub 255 pixel:0)
+ (sub 255 pixel:1)
+ (sub 255 pixel:2) pixel:3))
+(pixels invert)
+```
+
+### saturation
+
+In the previous example, we increased the saturation of a region of the image, to desaturate an entire image, you can simply omit the `(rect)` which will select the entire canvas, and set the pixel filter to `saturation` and the value to `0.5`(50% saturation):
+
+```lisp
+(import $path)
+(pixels saturation 0.5)
+```
+
+### convolve
+
+Effects which use the surrounding pixels, or convolution matrix, are used with the `(convolve)` function, you can learn more about this family of filters [here](https://en.wikipedia.org/wiki/Kernel_(image_processing)).
+
+### sharpen
+
+```lisp
+(import $path)
+(convolve (sharpen) $rect)
+```
+
+Custom convolve kernels can also be created like this:
+
+```lisp
+(import $path)
+(def (blur)
+ (
+ (-1 -1 -1)
+ (-1 5 -1)
+ (-1 -1 -1)))
+(convolve (blur))
+```
+
+
+
+## Events
+
+This section will demonstrate how to use events in Ronin to create interactive scripts.
+
+### Echo
+
+You can print some content to the screen in Ronin, by using the `(echo)` function, for example, the following script will write the word `hello` at the bottom left of the interface:
+
+```lisp
+(echo "hello")
+```
+
+### MouseDown
+
+Let's use the `(debug)` function to display the position of the mouse cursor in the interface.
+
+```lisp
+(on "mouse-down" echo)
+```
+
+We can define a function that triggers when the `mouse-down` event is detected, or when you click on the canvas:
+
+```lisp
+; define the function
+(defn draw-rect
+ (e)
+ (fill e:circle "red"))
+; use the function
+(on "mouse-move" draw-rect)
+```
+
+For more examples of functions, see the [examples](https://github.com/hundredrabbits/Ronin/tree/master/examples).
+
+You can find a more elaborate version of this example [here](https://github.com/hundredrabbits/Ronin/blob/master/examples/events/on-mouse.lisp).
+
+### Animate
+
+The `animate` event fires around 30 times per second, and is a perfect tool to create animations. Following the previous example, and the pattern of creating a function and binding it to the event, let's make a function that will use the `(time)` to animate a box:
+
+```lisp
+; define the function
+(defn wob-rect
+ ()
+ (
+ (clear)
+ (def rect-x 300)
+ (def rect-y (add (mul (sin (time 0.005)) 50) 300))
+ (fill
+ (rect rect-x rect-y 100 100) "red")))
+; use the function
+(on "animate" wob-rect)
+```
+
+You can find a more elaborate version of this example [here](https://github.com/hundredrabbits/Ronin/blob/master/examples/events/on-animate.lisp).
+
+### OSC
+
+Other programs can communicate with Ronin via OSC with the previous pattern. For example, if you send OSC data to the port `49162`, at the path `/a`, the event can be used in Ronin to trigger a function:
+
+```lisp
+(on "/a" echo)
+```
+
+You can find a more elaborate version of this example [here](https://github.com/hundredrabbits/Ronin/blob/master/examples/events/on-osc.lisp).
+
+I hope this workshop has been enlightening, if you have questions or suggestions, please visit the [community](https://hundredrabbits.itch.io/ronin/community). Enjoy!