1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-05-30 06:41:33 +00:00

removed script platform

This commit is contained in:
Steven Hugg 2023-11-05 12:16:39 -06:00
parent fbd9089a8d
commit a2d818c3e5
15 changed files with 28 additions and 2086 deletions

134
package-lock.json generated
View File

@ -9,27 +9,20 @@
"version": "3.11.0",
"license": "GPL-3.0",
"dependencies": {
"@types/chroma-js": "^2.1.3",
"@types/dompurify": "^2.3.4",
"@types/emscripten": "^1.39.5",
"@types/js-yaml": "^4.0.5",
"atob": "^2.1.x",
"binaryen": "^101.0.0",
"btoa": "^1.2.x",
"chroma-js": "^2.1.2",
"clipboard": "^2.0.6",
"dompurify": "^2.4.0",
"error-stack-parser": "^2.0.6",
"fast-png": "^5.0.4",
"file-saver": "^2.0.5",
"jquery": "^3.6.3",
"jszip": "^3.7.0",
"localforage": "^1.9.0",
"mousetrap": "^1.6.5",
"octokat": "^0.10.0",
"preact": "^10.5.14",
"split.js": "^1.6.2",
"yufka": "^2.0.1"
"split.js": "^1.6.2"
},
"devDependencies": {
"@types/bootbox": "^5.1.3",
@ -45,6 +38,7 @@
"cors": "^2.8.5",
"esbuild": "^0.12.29",
"express": "^4.18.2",
"fast-png": "^5.0.4",
"jsdom": "^21.1.0",
"lzg": "^1.0.x",
"mocha": "^9.2.0",
@ -865,11 +859,6 @@
"integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
"optional": true
},
"node_modules/@types/chroma-js": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.5.tgz",
"integrity": "sha512-LnJmElng1zoH7GOYqIo/EuL7L0/vEh5rc+fKaF4rsylJyjwOkX0pXeBemH25FQAWHifKJWqaRwR0EhC+yDod9A=="
},
"node_modules/@types/dompurify": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz",
@ -962,11 +951,6 @@
"@types/sizzle": "*"
}
},
"node_modules/@types/js-yaml": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz",
"integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA=="
},
"node_modules/@types/lodash": {
"version": "4.14.200",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz",
@ -988,7 +972,8 @@
"node_modules/@types/pako": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.4.tgz",
"integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA=="
"integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==",
"dev": true
},
"node_modules/@types/selenium-webdriver": {
"version": "4.1.15",
@ -1084,6 +1069,7 @@
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"devOptional": true,
"bin": {
"acorn": "bin/acorn"
},
@ -1735,11 +1721,6 @@
"fsevents": "~2.3.2"
}
},
"node_modules/chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
},
"node_modules/chromedriver": {
"version": "119.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-119.0.0.tgz",
@ -2624,6 +2605,7 @@
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
"optional": true,
"dependencies": {
"stackframe": "^1.3.4"
}
@ -2851,6 +2833,7 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-5.0.4.tgz",
"integrity": "sha512-vTNj6yixRnclW6sTlCeH6sNRLBOhM5ITmlo1LSU5ojKEc2e9kZkqXPo2xzBxKb61MBCXRXBcr8qJztOHr2O6WQ==",
"dev": true,
"dependencies": {
"@types/pako": "^1.0.1",
"iobuffer": "^5.0.2",
@ -2860,7 +2843,8 @@
"node_modules/fast-png/node_modules/pako": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
"dev": true
},
"node_modules/fd-slicer": {
"version": "1.1.0",
@ -3617,7 +3601,8 @@
"node_modules/iobuffer": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.3.2.tgz",
"integrity": "sha512-kO3CjNfLZ9t+tHxAMd+Xk4v3D/31E91rMs1dHrm7ikEQrlZ8mLDbQ4z3tZfDM48zOkReas2jx8MWSAmN9+c8Fw=="
"integrity": "sha512-kO3CjNfLZ9t+tHxAMd+Xk4v3D/31E91rMs1dHrm7ikEQrlZ8mLDbQ4z3tZfDM48zOkReas2jx8MWSAmN9+c8Fw==",
"dev": true
},
"node_modules/ip-regex": {
"version": "4.3.0",
@ -4668,14 +4653,6 @@
"node": ">=0.8.0"
}
},
"node_modules/magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
"dependencies": {
"sourcemap-codec": "^1.4.8"
}
},
"node_modules/make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -6174,15 +6151,6 @@
"node": ">= 0.4.0"
}
},
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -6903,12 +6871,6 @@
"source-map": "^0.6.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"deprecated": "Please use @jridgewell/sourcemap-codec instead"
},
"node_modules/spawn-wrap": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz",
@ -7002,7 +6964,8 @@
"node_modules/stackframe": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
"optional": true
},
"node_modules/stacktrace-parser": {
"version": "0.1.10",
@ -7983,18 +7946,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yufka": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yufka/-/yufka-2.1.1.tgz",
"integrity": "sha512-/8gX42mxcoJ21pdGbEg2w/6l0xlL7XFkFarcLmq2upxt6PTf7ehHsPnQQibGd6yLP1odMh0F04eZMh/gZhQHIQ==",
"dependencies": {
"acorn": "^8.3.0",
"magic-string": "^0.25.2"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/yup": {
"version": "0.32.11",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
@ -8692,11 +8643,6 @@
"integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
"optional": true
},
"@types/chroma-js": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.5.tgz",
"integrity": "sha512-LnJmElng1zoH7GOYqIo/EuL7L0/vEh5rc+fKaF4rsylJyjwOkX0pXeBemH25FQAWHifKJWqaRwR0EhC+yDod9A=="
},
"@types/dompurify": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz",
@ -8788,11 +8734,6 @@
"@types/sizzle": "*"
}
},
"@types/js-yaml": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz",
"integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA=="
},
"@types/lodash": {
"version": "4.14.200",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz",
@ -8814,7 +8755,8 @@
"@types/pako": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.4.tgz",
"integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA=="
"integrity": "sha512-Z+5bJSm28EXBSUJEgx29ioWeEEHUh6TiMkZHDhLwjc9wVFH+ressbkmX6waUZc5R3Gobn4Qu5llGxaoflZ+yhA==",
"dev": true
},
"@types/selenium-webdriver": {
"version": "4.1.15",
@ -8906,7 +8848,8 @@
"acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw=="
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"devOptional": true
},
"acorn-globals": {
"version": "7.0.1",
@ -9400,11 +9343,6 @@
"readdirp": "~3.6.0"
}
},
"chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
},
"chromedriver": {
"version": "119.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-119.0.0.tgz",
@ -10096,6 +10034,7 @@
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
"optional": true,
"requires": {
"stackframe": "^1.3.4"
}
@ -10270,6 +10209,7 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-5.0.4.tgz",
"integrity": "sha512-vTNj6yixRnclW6sTlCeH6sNRLBOhM5ITmlo1LSU5ojKEc2e9kZkqXPo2xzBxKb61MBCXRXBcr8qJztOHr2O6WQ==",
"dev": true,
"requires": {
"@types/pako": "^1.0.1",
"iobuffer": "^5.0.2",
@ -10279,7 +10219,8 @@
"pako": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
"dev": true
}
}
},
@ -10859,7 +10800,8 @@
"iobuffer": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.3.2.tgz",
"integrity": "sha512-kO3CjNfLZ9t+tHxAMd+Xk4v3D/31E91rMs1dHrm7ikEQrlZ8mLDbQ4z3tZfDM48zOkReas2jx8MWSAmN9+c8Fw=="
"integrity": "sha512-kO3CjNfLZ9t+tHxAMd+Xk4v3D/31E91rMs1dHrm7ikEQrlZ8mLDbQ4z3tZfDM48zOkReas2jx8MWSAmN9+c8Fw==",
"dev": true
},
"ip-regex": {
"version": "4.3.0",
@ -11707,14 +11649,6 @@
}
}
},
"magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
"requires": {
"sourcemap-codec": "^1.4.8"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -12871,11 +12805,6 @@
"integrity": "sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==",
"dev": true
},
"preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg=="
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -13463,11 +13392,6 @@
"source-map": "^0.6.0"
}
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"spawn-wrap": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz",
@ -13556,7 +13480,8 @@
"stackframe": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
"optional": true
},
"stacktrace-parser": {
"version": "0.1.10",
@ -14309,15 +14234,6 @@
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"devOptional": true
},
"yufka": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yufka/-/yufka-2.1.1.tgz",
"integrity": "sha512-/8gX42mxcoJ21pdGbEg2w/6l0xlL7XFkFarcLmq2upxt6PTf7ehHsPnQQibGd6yLP1odMh0F04eZMh/gZhQHIQ==",
"requires": {
"acorn": "^8.3.0",
"magic-string": "^0.25.2"
}
},
"yup": {
"version": "0.32.11",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",

View File

@ -10,27 +10,20 @@
},
"license": "GPL-3.0",
"dependencies": {
"@types/chroma-js": "^2.1.3",
"@types/dompurify": "^2.3.4",
"@types/emscripten": "^1.39.5",
"@types/js-yaml": "^4.0.5",
"atob": "^2.1.x",
"binaryen": "^101.0.0",
"btoa": "^1.2.x",
"chroma-js": "^2.1.2",
"clipboard": "^2.0.6",
"dompurify": "^2.4.0",
"error-stack-parser": "^2.0.6",
"fast-png": "^5.0.4",
"file-saver": "^2.0.5",
"jquery": "^3.6.3",
"jszip": "^3.7.0",
"localforage": "^1.9.0",
"mousetrap": "^1.6.5",
"octokat": "^0.10.0",
"preact": "^10.5.14",
"split.js": "^1.6.2",
"yufka": "^2.0.1"
"split.js": "^1.6.2"
},
"devDependencies": {
"@types/bootbox": "^5.1.3",
@ -46,6 +39,7 @@
"cors": "^2.8.5",
"esbuild": "^0.12.29",
"express": "^4.18.2",
"fast-png": "^5.0.4",
"jsdom": "^21.1.0",
"lzg": "^1.0.x",
"mocha": "^9.2.0",

View File

@ -1,294 +0,0 @@
import { WorkerError } from "../workertypes";
import ErrorStackParser = require("error-stack-parser");
import yufka from 'yufka';
import * as bitmap from "./lib/bitmap";
import * as io from "./lib/io";
import * as output from "./lib/output";
import * as color from "./lib/color";
import * as scriptui from "./lib/scriptui";
export const PROP_CONSTRUCTOR_NAME = "$$consname";
export interface Cell {
id: string;
object?: any;
}
export interface RunResult {
cells: Cell[];
state: {};
}
const IMPORTS = {
'bitmap': bitmap,
'io': io,
'output': output,
'color': color,
'ui': scriptui,
}
const LINE_NUMBER_OFFSET = 3; // TODO: shouldnt need?
const GLOBAL_BADLIST = [
'eval'
]
const GLOBAL_GOODLIST = [
'eval', // 'eval' can't be defined or assigned to in strict mode code
'Math', 'JSON',
'parseFloat', 'parseInt', 'isFinite', 'isNaN',
'String', 'Symbol', 'Number', 'Object', 'Boolean', 'NaN', 'Infinity', 'Date', 'BigInt',
'Set', 'Map', 'RegExp', 'Array', 'ArrayBuffer', 'DataView',
'Float32Array', 'Float64Array',
'Int8Array', 'Int16Array', 'Int32Array',
'Uint8Array', 'Uint16Array', 'Uint32Array', 'Uint8ClampedArray',
]
class RuntimeError extends Error {
constructor(public loc: acorn.SourceLocation, msg: string) {
super(msg);
}
}
function setConstructorName(o: object) : void {
let name = Object.getPrototypeOf(o)?.constructor?.name;
if (name != null && name != 'Object') {
o[PROP_CONSTRUCTOR_NAME] = name;
}
}
export class Environment {
preamble: string;
postamble: string;
obj: {};
seq: number;
declvars : {[name : string] : acorn.Node};
builtins : {}
constructor(
public readonly globalenv: any,
public readonly path: string
) {
var badlst = Object.getOwnPropertyNames(this.globalenv).filter(name => GLOBAL_GOODLIST.indexOf(name) < 0);
this.builtins = {
print: (...args) => this.print(args),
...IMPORTS
}
this.preamble = `'use strict';var ${badlst.join(',')};`;
for (var impname in this.builtins) {
this.preamble += `var ${impname}=$$.${impname};`
}
this.preamble += '{\n';
this.postamble = '\n}';
}
error(varname: string, msg: string) {
let obj = this.declvars && this.declvars[varname];
console.log('ERROR', varname, obj, this);
throw new RuntimeError(obj && obj.loc, msg);
}
print(args: any[]) {
if (args && args.length > 0 && args[0] != null) {
this.obj[`$print__${this.seq++}`] = args.length == 1 ? args[0] : args;
}
}
preprocess(code: string): string {
this.declvars = {};
this.seq = 0;
let options = {
// https://www.npmjs.com/package/magic-string#sgeneratemap-options-
sourceMap: {
file: this.path,
source: this.path,
hires: false,
includeContent: false
},
// https://github.com/acornjs/acorn/blob/master/acorn/README.md
acorn: {
ecmaVersion: 6 as any,
locations: true,
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowReserved: true,
}
};
const result = yufka(code, options, (node, { update, source, parent }) => {
const isTopLevel = () => {
return parent() && parent().type === 'ExpressionStatement' && parent(2) && parent(2).type === 'Program';
}
const convertTopToPrint = () => {
if (isTopLevel()) {
let printkey = `$print__${this.seq++}`;
update(`this.${printkey} = io.data.load(${source()}, ${JSON.stringify(printkey)})`);
//update(`print(${source()});`)
}
}
const left = node['left'];
switch (node.type) {
// add preamble, postamble
case 'Program':
update(`${this.preamble}${source()}${this.postamble}`)
break;
// error on forbidden keywords
case 'Identifier':
if (GLOBAL_BADLIST.indexOf(source()) >= 0) {
update(`__FORBIDDEN__KEYWORD__${source()}__`) // TODO? how to preserve line number?
} else {
convertTopToPrint();
}
break;
// x = expr --> var x = expr (first use)
case 'AssignmentExpression':
if (isTopLevel()) {
if (left && left.type === 'Identifier') {
if (!this.declvars[left.name]) {
update(`var ${left.name}=io.data.load(this.${source()}, ${JSON.stringify(left.name)})`)
this.declvars[left.name] = left;
} else {
update(`${left.name}=this.${source()}`)
}
}
}
break;
// convert lone expressions to print()
case 'UnaryExpression':
case 'BinaryExpression':
case 'CallExpression':
case 'MemberExpression':
convertTopToPrint();
break;
// literal comments
case 'Literal':
if (typeof node['value'] === 'string' && isTopLevel()) {
update(`this.$doc__${this.seq++} = { literaltext: ${source()} };`);
} else {
convertTopToPrint();
}
break;
}
});
return result.toString();
}
async run(code: string): Promise<void> {
// TODO: split into cells based on "--" linebreaks?
code = this.preprocess(code);
this.obj = {};
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
const fn = new AsyncFunction('$$', code).bind(this.obj, this.builtins);
await fn.call(this);
this.checkResult(this.obj, new Set(), []);
}
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
// TODO: return initial location of thingie
checkResult(o, checked: Set<object>, fullkey: string[]) {
if (o == null) return;
if (checked.has(o)) return;
if (typeof o === 'object') {
setConstructorName(o);
delete o.$$callback; // clear callbacks (TODO? put somewhere else?)
if (o.length > 100) return; // big array, don't bother
if (o.BYTES_PER_ELEMENT > 0) return; // typed array, don't bother
checked.add(o); // so we don't recurse if cycle
function prkey() { return fullkey.join('.') }
// go through all object properties recursively
for (var [key, value] of Object.entries(o)) {
if (value == null && fullkey.length == 0 && !key.startsWith("$")) {
this.error(key, `"${key}" has no value.`)
}
fullkey.push(key);
if (typeof value === 'function') {
if (fullkey.length == 1)
this.error(fullkey[0], `"${prkey()}" is a function. Did you forget to pass parameters?`); // TODO? did you mean (needs to see entire expr)
else
this.error(fullkey[0], `This expression may be incomplete, or it contains a function object: ${prkey()}`); // TODO? did you mean (needs to see entire expr)
}
if (typeof value === 'symbol') {
this.error(fullkey[0], `"${prkey()}" is a Symbol, and can't be used.`) // TODO?
}
if (value instanceof Promise) {
this.error(fullkey[0], `"${prkey()}" is unresolved. Use "await" before expression.`) // TODO?
}
this.checkResult(value, checked, fullkey);
fullkey.pop();
}
}
}
render(): Cell[] {
var cells = [];
for (var [key, value] of Object.entries(this.obj)) {
if (typeof value === 'function') {
// TODO: find other values, functions embedded in objects?
} else {
var cell: Cell = { id: key, object: value };
cells.push(cell);
}
}
return cells;
}
extractErrors(e: Error): WorkerError[] {
let loc = e['loc'];
if (loc && loc.start && loc.end) {
return [{
path: this.path,
msg: e.message,
line: loc.start.line,
start: loc.start.column,
end: loc.end.line,
}]
}
if (loc && loc.line != null) {
return [{
path: this.path,
msg: e.message,
line: loc.line,
start: loc.column,
}]
}
// TODO: Cannot parse given Error object?
let frames = ErrorStackParser.parse(e);
let frame = frames.findIndex(f => f.functionName === 'anonymous');
let errors = [];
// if ErrorStackParser fails, resort to regex
if (frame < 0 && e.stack != null) {
let m = /.anonymous.:(\d+):(\d+)/g.exec(e.stack);
if (m != null) {
errors.push( {
path: this.path,
msg: e.message,
line: parseInt(m[1]) - LINE_NUMBER_OFFSET,
});
}
}
// otherwise iterate thru all the frames
while (frame >= 0) {
console.log(frames[frame]);
if (frames[frame].fileName.endsWith('Function')) {
// TODO: use source map
errors.push( {
path: this.path,
msg: e.message,
line: frames[frame].lineNumber - LINE_NUMBER_OFFSET,
//start: frames[frame].columnNumber,
} );
}
--frame;
}
// if no stack frames parsed, last resort error msg
if (errors.length == 0) {
errors.push( {
path: this.path,
msg: e.message,
line: 0
} );
}
return errors;
}
commitLoadableState() {
// TODO: visit children?
for (let [key, value] of Object.entries(this.obj)) {
let loadable = <any>value as io.Loadable;
io.data.save(loadable, key);
}
return io.$$getData();
}
}

View File

@ -1,474 +0,0 @@
// TODO: dynamic import
import * as fastpng from 'fast-png';
import { Palette } from './color';
import * as io from './io'
import * as color from './color'
import { coerceToArray, findIntegerFactors, RGBA } from '../../util';
export type PixelMapFunction = (x: number, y: number) => number;
export abstract class AbstractBitmap<T> {
aspect? : number; // aspect ratio, null == default == 1:1
style? : {} = {}; // CSS styles (TODO: other elements?)
constructor(
public readonly width: number,
public readonly height: number,
) {
}
abstract blank(width: number, height: number) : AbstractBitmap<T>;
abstract setarray(arr: ArrayLike<number>) : void;
abstract set(x: number, y: number, val: number) : void;
abstract get(x: number, y: number): number;
abstract getrgba(x: number, y: number): number;
inbounds(x: number, y: number): boolean {
return (x >= 0 && x < this.width && y >= 0 && y < this.height);
}
assign(fn: ArrayLike<number> | PixelMapFunction) : void {
if (typeof fn === 'function') {
for (let y=0; y<this.height; y++) {
for (let x=0; x<this.width; x++) {
this.set(x, y, fn(x, y));
}
}
} else if (fn && fn['length'] != null) {
this.setarray(fn);
} else {
throw new Error(`Illegal argument to assign(): ${fn}`)
}
}
clone() : AbstractBitmap<T> {
let bmp = this.blank(this.width, this.height);
bmp.assign((x,y) => this.get(x,y));
return bmp;
}
crop(srcx: number, srcy: number, width: number, height: number) {
let dest = this.blank(width, height);
dest.assign((x, y) => this.get(x + srcx, y + srcy));
return dest;
}
blit(src: BitmapType,
destx: number, desty: number,
srcx: number, srcy: number)
{
destx |= 0;
desty |= 0;
srcx |= 0;
srcy |= 0;
for (var y=0; y<src.height; y++) {
for (var x=0; x<src.width; x++) {
let rgba = src.getrgba(x+srcx, y+srcy);
this.set(x+destx, y+desty, rgba);
}
}
}
fill(destx: number, desty: number, width:number, height:number, value:number) {
for (var y=0; y<height; y++) {
for (var x=0; x<width; x++) {
this.set(x+destx, y+desty, value);
}
}
}
}
export class RGBABitmap extends AbstractBitmap<RGBABitmap> {
public readonly rgba: Uint32Array
constructor(
width: number,
height: number,
initial?: Uint32Array | PixelMapFunction
) {
super(width, height);
this.rgba = new Uint32Array(this.width * this.height);
if (initial) this.assign(initial);
}
setarray(arr: ArrayLike<number>) {
this.rgba.set(arr);
}
set(x: number, y: number, rgba: number) {
if (this.inbounds(x,y)) this.rgba[y * this.width + x] = rgba;
}
get(x: number, y: number): number {
return this.inbounds(x,y) ? this.rgba[y * this.width + x] : 0;
}
getrgba(x: number, y: number): number {
return this.get(x, y);
}
blank(width?: number, height?: number) : RGBABitmap {
return new RGBABitmap(width || this.width, height || this.height);
}
clone() : RGBABitmap {
let bitmap = this.blank(this.width, this.height);
bitmap.rgba.set(this.rgba);
return bitmap;
}
}
export abstract class MappedBitmap extends AbstractBitmap<MappedBitmap> {
public readonly pixels: Uint8Array
constructor(
width: number,
height: number,
public readonly bpp: number,
initial?: Uint8Array | PixelMapFunction
) {
super(width, height);
if (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8)
throw new Error(`Invalid bits per pixel: ${bpp}`);
this.pixels = new Uint8Array(this.width * this.height);
if (initial) this.assign(initial);
}
setarray(arr: ArrayLike<number>) {
this.pixels.set(arr);
}
set(x: number, y: number, index: number) {
if (this.inbounds(x,y)) this.pixels[y * this.width + x] = index;
}
get(x: number, y: number): number {
return this.inbounds(x,y) ? this.pixels[y * this.width + x] : 0;
}
}
function getbpp(x : number | Palette) : number {
if (typeof x === 'number') return x;
if (x instanceof Palette) {
if (x.colors.length <= 2) return 1;
else if (x.colors.length <= 4) return 2;
else if (x.colors.length <= 16) return 4;
}
return 8;
}
export class IndexedBitmap extends MappedBitmap {
public palette: Palette;
constructor(
width: number,
height: number,
bppOrPalette: number | Palette,
initial?: Uint8Array | PixelMapFunction
) {
super(width, height, getbpp(bppOrPalette), initial);
this.palette = bppOrPalette instanceof Palette
? bppOrPalette
: color.palette.colors(1 << this.bpp);
}
getrgba(x: number, y: number): number {
return this.palette && this.palette.colors[this.get(x, y)];
}
blank(width?: number, height?: number, newPalette?: Palette) : IndexedBitmap {
let bitmap = new IndexedBitmap(width || this.width, height || this.height, newPalette || this.palette);
return bitmap;
}
clone() : IndexedBitmap {
let bitmap = this.blank(this.width, this.height);
bitmap.pixels.set(this.pixels);
return bitmap;
}
}
export function rgba(width: number, height: number, initial?: Uint32Array | PixelMapFunction) {
return new RGBABitmap(width, height, initial);
}
export function indexed(width: number, height: number, bpp: number, initial?: Uint8Array | PixelMapFunction) {
return new IndexedBitmap(width, height, bpp, initial);
}
export type BitmapType = RGBABitmap | IndexedBitmap;
// TODO: check arguments
export function decode(arr: Uint8Array, fmt: PixelEditorImageFormat) {
var pixels = convertWordsToImages(arr, fmt);
// TODO: guess if missing w/h/count?
// TODO: reverse mapping
// TODO: maybe better composable functions
let bpp = (fmt.bpp||1) * (fmt.np||1);
return pixels.map(data => new IndexedBitmap(fmt.w, fmt.h, bpp, data));
}
export interface BitmapAnalysis {
min: {w: number, h: number};
max: {w: number, h: number};
}
export function analyze(bitmaps: BitmapType[]) {
bitmaps = coerceToArray(bitmaps);
let r = {min:{w:0,h:0}, max:{w:0,h:0}};
for (let bmp of bitmaps) {
if (!(bmp instanceof AbstractBitmap)) return null;
r.min.w = Math.min(bmp.width);
r.max.w = Math.max(bmp.width);
r.min.h = Math.min(bmp.height);
r.max.h = Math.max(bmp.height);
}
return r;
}
export interface MontageOptions {
analysis?: BitmapAnalysis;
gap?: number;
aspect?: number;
}
export function montage(bitmaps: BitmapType[], options?: MontageOptions) {
bitmaps = coerceToArray(bitmaps);
let minmax = (options && options.analysis) || analyze(bitmaps);
if (minmax == null) throw new Error(`Expected an array of bitmaps`);
let hitrects = [];
let aspect = (options && options.aspect) || 1;
let gap = (options && options.gap) || 0;
if (minmax.min.w == minmax.max.w && minmax.min.h == minmax.max.h) {
let totalPixels = minmax.min.w * minmax.min.h * bitmaps.length;
let factors = findIntegerFactors(totalPixels, minmax.max.w, minmax.max.h, aspect);
let columns = Math.ceil(factors.a / minmax.min.w); // TODO: rounding?
let rows = Math.ceil(factors.b / minmax.min.h);
let result = new RGBABitmap(factors.a + gap * (columns-1), factors.b + gap * (rows-1));
let x = 0;
let y = 0;
bitmaps.forEach((bmp) => {
result.blit(bmp, x, y, 0, 0);
hitrects.push({x, y, w: bmp.width, h: bmp.height })
x += bmp.width + gap;
if (x >= result.width) {
x = 0;
y += bmp.height + gap;
}
})
return result;
} else {
throw new Error(`combine() only supports uniformly-sized images right now`); // TODO
}
}
/////
export namespace png {
export function read(url: string): BitmapType {
return decode(io.readbin(url));
}
export function decode(data: Uint8Array): BitmapType {
let png = fastpng.decode(data);
return convertToBitmap(png);
}
function convertToBitmap(png: fastpng.IDecodedPNG): BitmapType {
if (png.palette && png.depth <= 8) {
return convertIndexedToBitmap(png);
} else {
return convertRGBAToBitmap(png);
}
}
function convertIndexedToBitmap(png: fastpng.IDecodedPNG): IndexedBitmap {
var palarr = <any>png.palette as [number, number, number, number][];
var palette = new Palette(palarr);
let bitmap = new IndexedBitmap(png.width, png.height, png.depth);
if (png.depth == 8) {
bitmap.pixels.set(png.data);
} else {
let pixperbyte = Math.floor(8 / png.depth);
let mask = (1 << png.depth) - 1;
for (let i = 0; i < bitmap.pixels.length; i++) {
var bofs = (i % pixperbyte) * png.depth;
let val = png.data[Math.floor(i / pixperbyte)];
bitmap.pixels[i] = (val >> bofs) & mask;
}
}
bitmap.palette = palette;
// TODO: aspect etc
return bitmap;
}
function convertRGBAToBitmap(png: fastpng.IDecodedPNG): RGBABitmap {
const bitmap = new RGBABitmap(png.width, png.height);
const rgba : [number,number,number,number] = [0, 0, 0, 0];
for (let i = 0; i < bitmap.rgba.length; i++) {
for (let j = 0; j < 4; j++)
rgba[j] = png.data[i * 4 + j];
bitmap.rgba[i] = color.rgba(rgba);
}
// TODO: aspect etc
return bitmap;
}
}
export namespace font {
interface Font {
maxheight: number;
glyphs: { [code: number]: Glyph };
properties: {};
}
class Glyph extends IndexedBitmap {
constructor(width: number, height: number, bpp: number,
public readonly code: number,
public readonly yoffset: number) {
super(width, height, bpp);
}
}
export function read(url: string) {
if (url.endsWith('.yaff')) return decodeyafflines(io.readlines(url));
if (url.endsWith('.draw')) return decodedrawlines(io.readlines(url));
throw new Error(`Can't figure out font format for "${url}"`);
}
export function decodeglyph(glines: string[], curcode: number, yoffset: number): Glyph {
let width = 0;
for (var gline of glines) width = Math.max(width, gline.length);
let g = new Glyph(width, glines.length, 1, curcode, yoffset);
for (var y = 0; y < glines.length; y++) {
let gline = glines[y];
for (var x = 0; x < gline.length; x++) {
let ch = gline[x];
g.set(x, y, ch==='@' || ch==='#' ? 1 : 0); // TODO: provide mapping
}
}
return g;
}
// https://github.com/robhagemans/monobit
export function decodeyafflines(lines: string[]): Font {
let maxheight = 0;
let properties = {};
let glyphs = {};
let yoffset = 0;
let curcode = -1;
let curglyph: string[] = [];
const re_prop = /^([\w-]+):\s+(.+)/i;
const re_label = /^0x([0-9a-f]+):|u[+]([0-9a-f]+):|(\w+):/i;
const re_gline = /^\s+([.@]+)/
function addfont() {
if (curcode >= 0 && curglyph.length) {
glyphs[curcode] = decodeglyph(curglyph, curcode, yoffset);
curcode = -1;
curglyph = [];
}
}
for (let line of lines) {
let m: RegExpExecArray;
if (m = re_prop.exec(line)) {
properties[m[1]] = m[2];
if (m[1] === 'bottom') yoffset = parseInt(m[2]);
if (m[1] === 'size') maxheight = parseInt(m[2]);
} else if (m = re_label.exec(line)) {
addfont();
if (m[1] != null) curcode = parseInt(m[1], 16);
else if (m[2] != null) curcode = parseInt(m[2], 16);
else if (m[3] != null) curcode = null; // text labels not supported
} else if (m = re_gline.exec(line)) {
curglyph.push(m[1]);
}
if (isNaN(curcode + yoffset + maxheight))
throw new Error(`couldn't decode .yaff: ${JSON.stringify(line)}`)
}
addfont();
return { maxheight, properties, glyphs };
}
// https://github.com/robhagemans/monobit
export function decodedrawlines(lines: string[]): Font {
let maxheight = 0;
let properties = {};
let glyphs = {};
let curcode = -1;
let curglyph: string[] = [];
const re_gline = /^([0-9a-f]+)?[:]?\s*([-#]+)/i;
function addfont() {
if (curcode >= 0 && curglyph.length) {
glyphs[curcode] = decodeglyph(curglyph, curcode, 0);
maxheight = Math.max(maxheight, curglyph.length);
curcode = -1;
curglyph = [];
}
}
for (let line of lines) {
let m: RegExpExecArray;
if (m = re_gline.exec(line)) {
if (m[1] != null) {
addfont();
curcode = parseInt(m[1], 16);
if (isNaN(curcode))
throw new Error(`couldn't decode .draw: ${JSON.stringify(line)}`)
}
curglyph.push(m[2]);
}
}
addfont();
return { maxheight, properties, glyphs };
}
}
// TODO: merge w/ pixeleditor
export type PixelEditorImageFormat = {
w:number
h:number
count?:number
bpp?:number
np?:number
bpw?:number
sl?:number
pofs?:number
remap?:number[]
reindex?:number[]
brev?:boolean
flip?:boolean
destfmt?:PixelEditorImageFormat
xform?:string
skip?:number
aspect?:number
};
function remapBits(x:number, arr:number[]) : number {
if (!arr) return x;
var y = 0;
for (var i=0; i<arr.length; i++) {
var s = arr[i];
if (s < 0) {
s = -s-1;
y ^= 1 << s;
}
if (x & (1 << i)) {
y ^= 1 << s;
}
}
return y;
}
export function convertWordsToImages(words:ArrayLike<number>, fmt:PixelEditorImageFormat) : Uint8Array[] {
var width = fmt.w;
var height = fmt.h;
var count = fmt.count || 1;
var bpp = fmt.bpp || 1;
var nplanes = fmt.np || 1;
var bitsperword = fmt.bpw || 8;
var wordsperline = fmt.sl || Math.ceil(width * bpp / bitsperword);
var mask = (1 << bpp)-1;
var pofs = fmt.pofs || wordsperline*height*count;
var skip = fmt.skip || 0;
var images = [];
for (var n=0; n<count; n++) {
var imgdata = [];
for (var y=0; y<height; y++) {
var yp = fmt.flip ? height-1-y : y;
var ofs0 = n*wordsperline*height + yp*wordsperline;
var shift = 0;
for (var x=0; x<width; x++) {
var color = 0;
var ofs = remapBits(ofs0, fmt.remap);
// TODO: if (fmt.reindex) { [ofs, shift] = reindexMask(x, fmt.reindex); ofs += ofs0; }
for (var p=0; p<nplanes; p++) {
var byte = words[ofs + p*pofs + skip];
color |= ((fmt.brev ? byte>>(bitsperword-shift-bpp) : byte>>shift) & mask) << (p*bpp);
}
imgdata.push(color);
shift += bpp;
if (shift >= bitsperword && !fmt.reindex) {
ofs0 += 1;
shift = 0;
}
}
}
images.push(new Uint8Array(imgdata));
}
return images;
}

View File

@ -1,163 +0,0 @@
import _chroma from 'chroma-js'
import { isArray, rgb2bgr } from '../../util';
export type Chroma = { _rgb: [number,number,number,number] };
export type ColorSource = number | [number,number,number] | [number,number,number,number] | string | Chroma;
function checkCount(count) {
if (count < 0 || count > 65536) {
throw new Error("Palettes cannot have more than 2^16 (65536) colors.");
}
}
export function isPalette(object): object is Palette {
return object['colors'] instanceof Uint32Array;
}
export function isChroma(object): object is Chroma {
return object['_rgb'] instanceof Array;
}
export class Palette {
readonly colors: Uint32Array;
constructor(arg: number | any[] | Uint32Array) {
// TODO: more array types
if (typeof arg === 'number') {
checkCount(arg);
this.colors = new Uint32Array(arg);
} else if (arg instanceof Uint32Array) {
this.colors = new Uint32Array(arg);
} else if (isArray(arg)) {
this.colors = new Uint32Array(arg.map(rgb));
} else
throw new Error(`Invalid Palette constructor`)
}
get(index: number) {
return this.colors[index];
}
chromas() {
return Array.from(this.colors).map((rgba) => from(rgba & 0xffffff));
}
}
export const chroma = _chroma;
export function from(obj: ColorSource) {
if (typeof obj === 'number')
return _chroma(rgb2bgr(obj & 0xffffff));
else
return _chroma(obj as any);
}
export function rgb(obj: ColorSource) : number;
export function rgb(r: number, g: number, b: number) : number;
export function rgb(obj: any, g?: number, b?: number) : number {
return rgba(obj, g, b, 0xff) | 0xff000000;
}
export function rgba(obj: ColorSource) : number;
export function rgba(r: number, g: number, b: number, a: number) : number;
export function rgba(obj: ColorSource, g?: number, b?: number, a?: number) : number {
if (isChroma(obj)) {
return rgba(obj._rgb[0], obj._rgb[1], obj._rgb[2], obj._rgb[3]);
}
if (typeof obj === 'number') {
let r = obj;
if (typeof g === 'number' && typeof b === 'number')
return ((r & 0xff) << 0) | ((g & 0xff) << 8) | ((b & 0xff) << 16) | ((a & 0xff) << 24);
else
return obj;
}
if (typeof obj !== 'string' && isArray(obj) && typeof obj[0] === 'number') {
let arr = obj;
let v = 0;
v |= (arr[0] & 0xff) << 0;
v |= (arr[1] & 0xff) << 8;
v |= (arr[2] & 0xff) << 16;
v |= (arr[3] & 0xff) << 24;
return v;
}
return rgba(from(obj).rgb());
}
export function rgba2arr(v: number): number[] {
return [
(v >> 0) & 0xff,
(v >> 8) & 0xff,
(v >> 16) & 0xff,
(v >> 24) & 0xff,
]
}
export function rgb2arr(v: number): number[] {
return rgba2arr(v).slice(0,3);
}
type ColorGenFunc = (index: number) => number;
export namespace palette {
export function from(obj: number | any[] | Uint32Array | ColorGenFunc, count?: number) {
checkCount(count);
if (typeof obj === 'function') {
if (!count) throw new Error(`You must also pass the number of colors to generate.`)
var pal = new Palette(count);
for (var i = 0; i < pal.colors.length; i++) {
pal.colors[i] = rgba(obj(i));
}
return pal;
} else {
return new Palette(obj);
}
}
export function mono() {
return greys(2);
}
function rgb2() {
return new Palette([
rgb(0, 0, 0),
rgb(0, 0, 255),
rgb(255, 0, 0),
rgb(0, 255, 0),
]);
}
function rgb3() {
return new Palette([
rgb(0, 0, 0),
rgb(0, 0, 255),
rgb(255, 0, 0),
rgb(255, 0, 255),
rgb(0, 255, 0),
rgb(0, 255, 255),
rgb(255, 255, 0),
rgb(255, 255, 255),
]);
}
export function greys(count: number) {
return from((i) => {
let v = 255 * i / (count - 1);
return rgb(v,v,v);
}, count);
}
export function colors(count: number) {
switch (count) {
case 2: return mono();
case 4: return rgb2();
case 8: return rgb3();
default: return factors(count); // TODO
}
}
export function helix(count: number) {
checkCount(count);
return new Palette(chroma.cubehelix().scale().colors(count));
}
export function factors(count: number, mult?: number) {
mult = mult || 0x031f0f;
return from((i) => rgb(i * mult), count);
}
// TODO: https://www.iquilezles.org/www/articles/palettes/palettes.htm
}

View File

@ -1,178 +0,0 @@
import { FileDataCache } from "../../util";
import { FileData, WorkingStore } from "../../workertypes";
// remote resource cache
var $$cache = new FileDataCache(); // TODO: better cache?
// file read/write interface
var $$store: WorkingStore;
// backing store for data
var $$data: {} = {};
// module cache
var $$modules: Map<string,{}> = new Map();
export function $$setupFS(store: WorkingStore) {
$$store = store;
}
export function $$getData() {
return $$data;
}
export function $$loadData(data: {}) {
Object.assign($$data, data);
}
// object that can load state from backing store