├── .gitignore
├── index.html
├── license.md
├── package-lock.json
├── package.json
├── readme.md
├── server.js
├── src
├── assets
│ ├── bottomlayer.jpg
│ └── toplayer.png
├── script.js
├── script.js.map
├── script.ts
└── style.css
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Image Editor Effects
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
4 |
5 | In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
9 | For more information, please refer to
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "image-editor-effects",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "version": "1.0.0",
9 | "license": "Unlicense",
10 | "dependencies": {
11 | "express": "^4.x.x"
12 | },
13 | "devDependencies": {
14 | "typescript": "^4.x.x"
15 | }
16 | },
17 | "node_modules/accepts": {
18 | "version": "1.3.7",
19 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
20 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
21 | "dependencies": {
22 | "mime-types": "~2.1.24",
23 | "negotiator": "0.6.2"
24 | },
25 | "engines": {
26 | "node": ">= 0.6"
27 | }
28 | },
29 | "node_modules/array-flatten": {
30 | "version": "1.1.1",
31 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
32 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
33 | },
34 | "node_modules/body-parser": {
35 | "version": "1.19.0",
36 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
37 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
38 | "dependencies": {
39 | "bytes": "3.1.0",
40 | "content-type": "~1.0.4",
41 | "debug": "2.6.9",
42 | "depd": "~1.1.2",
43 | "http-errors": "1.7.2",
44 | "iconv-lite": "0.4.24",
45 | "on-finished": "~2.3.0",
46 | "qs": "6.7.0",
47 | "raw-body": "2.4.0",
48 | "type-is": "~1.6.17"
49 | },
50 | "engines": {
51 | "node": ">= 0.8"
52 | }
53 | },
54 | "node_modules/body-parser/node_modules/debug": {
55 | "version": "2.6.9",
56 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
57 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
58 | "dependencies": {
59 | "ms": "2.0.0"
60 | }
61 | },
62 | "node_modules/body-parser/node_modules/http-errors": {
63 | "version": "1.7.2",
64 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
65 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
66 | "dependencies": {
67 | "depd": "~1.1.2",
68 | "inherits": "2.0.3",
69 | "setprototypeof": "1.1.1",
70 | "statuses": ">= 1.5.0 < 2",
71 | "toidentifier": "1.0.0"
72 | },
73 | "engines": {
74 | "node": ">= 0.6"
75 | }
76 | },
77 | "node_modules/body-parser/node_modules/inherits": {
78 | "version": "2.0.3",
79 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
80 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
81 | },
82 | "node_modules/body-parser/node_modules/qs": {
83 | "version": "6.7.0",
84 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
85 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
86 | "engines": {
87 | "node": ">=0.6"
88 | }
89 | },
90 | "node_modules/body-parser/node_modules/raw-body": {
91 | "version": "2.4.0",
92 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
93 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
94 | "dependencies": {
95 | "bytes": "3.1.0",
96 | "http-errors": "1.7.2",
97 | "iconv-lite": "0.4.24",
98 | "unpipe": "1.0.0"
99 | },
100 | "engines": {
101 | "node": ">= 0.8"
102 | }
103 | },
104 | "node_modules/body-parser/node_modules/statuses": {
105 | "version": "1.5.0",
106 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
107 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
108 | "engines": {
109 | "node": ">= 0.6"
110 | }
111 | },
112 | "node_modules/bytes": {
113 | "version": "3.1.0",
114 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
115 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
116 | "engines": {
117 | "node": ">= 0.8"
118 | }
119 | },
120 | "node_modules/content-disposition": {
121 | "version": "0.5.3",
122 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
123 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
124 | "dependencies": {
125 | "safe-buffer": "5.1.2"
126 | },
127 | "engines": {
128 | "node": ">= 0.6"
129 | }
130 | },
131 | "node_modules/content-type": {
132 | "version": "1.0.4",
133 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
134 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
135 | "engines": {
136 | "node": ">= 0.6"
137 | }
138 | },
139 | "node_modules/cookie-signature": {
140 | "version": "1.0.6",
141 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
142 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
143 | },
144 | "node_modules/depd": {
145 | "version": "1.1.2",
146 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
147 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
148 | "engines": {
149 | "node": ">= 0.6"
150 | }
151 | },
152 | "node_modules/destroy": {
153 | "version": "1.0.4",
154 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
155 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
156 | },
157 | "node_modules/ee-first": {
158 | "version": "1.1.1",
159 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
160 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
161 | },
162 | "node_modules/encodeurl": {
163 | "version": "1.0.2",
164 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
165 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
166 | "engines": {
167 | "node": ">= 0.8"
168 | }
169 | },
170 | "node_modules/escape-html": {
171 | "version": "1.0.3",
172 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
173 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
174 | },
175 | "node_modules/etag": {
176 | "version": "1.8.1",
177 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
178 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
179 | "engines": {
180 | "node": ">= 0.6"
181 | }
182 | },
183 | "node_modules/express": {
184 | "version": "4.17.1",
185 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
186 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
187 | "dependencies": {
188 | "accepts": "~1.3.7",
189 | "array-flatten": "1.1.1",
190 | "body-parser": "1.19.0",
191 | "content-disposition": "0.5.3",
192 | "content-type": "~1.0.4",
193 | "cookie": "0.4.0",
194 | "cookie-signature": "1.0.6",
195 | "debug": "2.6.9",
196 | "depd": "~1.1.2",
197 | "encodeurl": "~1.0.2",
198 | "escape-html": "~1.0.3",
199 | "etag": "~1.8.1",
200 | "finalhandler": "~1.1.2",
201 | "fresh": "0.5.2",
202 | "merge-descriptors": "1.0.1",
203 | "methods": "~1.1.2",
204 | "on-finished": "~2.3.0",
205 | "parseurl": "~1.3.3",
206 | "path-to-regexp": "0.1.7",
207 | "proxy-addr": "~2.0.5",
208 | "qs": "6.7.0",
209 | "range-parser": "~1.2.1",
210 | "safe-buffer": "5.1.2",
211 | "send": "0.17.1",
212 | "serve-static": "1.14.1",
213 | "setprototypeof": "1.1.1",
214 | "statuses": "~1.5.0",
215 | "type-is": "~1.6.18",
216 | "utils-merge": "1.0.1",
217 | "vary": "~1.1.2"
218 | },
219 | "engines": {
220 | "node": ">= 0.10.0"
221 | }
222 | },
223 | "node_modules/express/node_modules/cookie": {
224 | "version": "0.4.0",
225 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
226 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
227 | "engines": {
228 | "node": ">= 0.6"
229 | }
230 | },
231 | "node_modules/express/node_modules/debug": {
232 | "version": "2.6.9",
233 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
234 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
235 | "dependencies": {
236 | "ms": "2.0.0"
237 | }
238 | },
239 | "node_modules/express/node_modules/finalhandler": {
240 | "version": "1.1.2",
241 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
242 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
243 | "dependencies": {
244 | "debug": "2.6.9",
245 | "encodeurl": "~1.0.2",
246 | "escape-html": "~1.0.3",
247 | "on-finished": "~2.3.0",
248 | "parseurl": "~1.3.3",
249 | "statuses": "~1.5.0",
250 | "unpipe": "~1.0.0"
251 | },
252 | "engines": {
253 | "node": ">= 0.8"
254 | }
255 | },
256 | "node_modules/express/node_modules/mime": {
257 | "version": "1.6.0",
258 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
259 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
260 | "bin": {
261 | "mime": "cli.js"
262 | },
263 | "engines": {
264 | "node": ">=4"
265 | }
266 | },
267 | "node_modules/express/node_modules/qs": {
268 | "version": "6.7.0",
269 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
270 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
271 | "engines": {
272 | "node": ">=0.6"
273 | }
274 | },
275 | "node_modules/express/node_modules/send": {
276 | "version": "0.17.1",
277 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
278 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
279 | "dependencies": {
280 | "debug": "2.6.9",
281 | "depd": "~1.1.2",
282 | "destroy": "~1.0.4",
283 | "encodeurl": "~1.0.2",
284 | "escape-html": "~1.0.3",
285 | "etag": "~1.8.1",
286 | "fresh": "0.5.2",
287 | "http-errors": "~1.7.2",
288 | "mime": "1.6.0",
289 | "ms": "2.1.1",
290 | "on-finished": "~2.3.0",
291 | "range-parser": "~1.2.1",
292 | "statuses": "~1.5.0"
293 | },
294 | "engines": {
295 | "node": ">= 0.8.0"
296 | }
297 | },
298 | "node_modules/express/node_modules/send/node_modules/ms": {
299 | "version": "2.1.1",
300 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
301 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
302 | },
303 | "node_modules/express/node_modules/serve-static": {
304 | "version": "1.14.1",
305 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
306 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
307 | "dependencies": {
308 | "encodeurl": "~1.0.2",
309 | "escape-html": "~1.0.3",
310 | "parseurl": "~1.3.3",
311 | "send": "0.17.1"
312 | },
313 | "engines": {
314 | "node": ">= 0.8.0"
315 | }
316 | },
317 | "node_modules/express/node_modules/statuses": {
318 | "version": "1.5.0",
319 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
320 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
321 | "engines": {
322 | "node": ">= 0.6"
323 | }
324 | },
325 | "node_modules/forwarded": {
326 | "version": "0.1.2",
327 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
328 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
329 | "engines": {
330 | "node": ">= 0.6"
331 | }
332 | },
333 | "node_modules/fresh": {
334 | "version": "0.5.2",
335 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
336 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
337 | "engines": {
338 | "node": ">= 0.6"
339 | }
340 | },
341 | "node_modules/http-errors": {
342 | "version": "1.7.3",
343 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
344 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
345 | "dependencies": {
346 | "depd": "~1.1.2",
347 | "inherits": "2.0.4",
348 | "setprototypeof": "1.1.1",
349 | "statuses": ">= 1.5.0 < 2",
350 | "toidentifier": "1.0.0"
351 | },
352 | "engines": {
353 | "node": ">= 0.6"
354 | }
355 | },
356 | "node_modules/http-errors/node_modules/statuses": {
357 | "version": "1.5.0",
358 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
359 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
360 | "engines": {
361 | "node": ">= 0.6"
362 | }
363 | },
364 | "node_modules/iconv-lite": {
365 | "version": "0.4.24",
366 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
367 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
368 | "dependencies": {
369 | "safer-buffer": ">= 2.1.2 < 3"
370 | },
371 | "engines": {
372 | "node": ">=0.10.0"
373 | }
374 | },
375 | "node_modules/inherits": {
376 | "version": "2.0.4",
377 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
378 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
379 | },
380 | "node_modules/ipaddr.js": {
381 | "version": "1.9.0",
382 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
383 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==",
384 | "engines": {
385 | "node": ">= 0.10"
386 | }
387 | },
388 | "node_modules/media-typer": {
389 | "version": "0.3.0",
390 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
391 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
392 | "engines": {
393 | "node": ">= 0.6"
394 | }
395 | },
396 | "node_modules/merge-descriptors": {
397 | "version": "1.0.1",
398 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
399 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
400 | },
401 | "node_modules/methods": {
402 | "version": "1.1.2",
403 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
404 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
405 | "engines": {
406 | "node": ">= 0.6"
407 | }
408 | },
409 | "node_modules/mime-db": {
410 | "version": "1.40.0",
411 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
412 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
413 | "engines": {
414 | "node": ">= 0.6"
415 | }
416 | },
417 | "node_modules/mime-types": {
418 | "version": "2.1.24",
419 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
420 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
421 | "dependencies": {
422 | "mime-db": "1.40.0"
423 | },
424 | "engines": {
425 | "node": ">= 0.6"
426 | }
427 | },
428 | "node_modules/ms": {
429 | "version": "2.0.0",
430 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
431 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
432 | },
433 | "node_modules/negotiator": {
434 | "version": "0.6.2",
435 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
436 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
437 | "engines": {
438 | "node": ">= 0.6"
439 | }
440 | },
441 | "node_modules/on-finished": {
442 | "version": "2.3.0",
443 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
444 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
445 | "dependencies": {
446 | "ee-first": "1.1.1"
447 | },
448 | "engines": {
449 | "node": ">= 0.8"
450 | }
451 | },
452 | "node_modules/parseurl": {
453 | "version": "1.3.3",
454 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
455 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
456 | "engines": {
457 | "node": ">= 0.8"
458 | }
459 | },
460 | "node_modules/path-to-regexp": {
461 | "version": "0.1.7",
462 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
463 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
464 | },
465 | "node_modules/proxy-addr": {
466 | "version": "2.0.5",
467 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
468 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
469 | "dependencies": {
470 | "forwarded": "~0.1.2",
471 | "ipaddr.js": "1.9.0"
472 | },
473 | "engines": {
474 | "node": ">= 0.10"
475 | }
476 | },
477 | "node_modules/range-parser": {
478 | "version": "1.2.1",
479 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
480 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
481 | "engines": {
482 | "node": ">= 0.6"
483 | }
484 | },
485 | "node_modules/safe-buffer": {
486 | "version": "5.1.2",
487 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
488 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
489 | },
490 | "node_modules/safer-buffer": {
491 | "version": "2.1.2",
492 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
493 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
494 | },
495 | "node_modules/setprototypeof": {
496 | "version": "1.1.1",
497 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
498 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
499 | },
500 | "node_modules/toidentifier": {
501 | "version": "1.0.0",
502 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
503 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
504 | "engines": {
505 | "node": ">=0.6"
506 | }
507 | },
508 | "node_modules/type-is": {
509 | "version": "1.6.18",
510 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
511 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
512 | "dependencies": {
513 | "media-typer": "0.3.0",
514 | "mime-types": "~2.1.24"
515 | },
516 | "engines": {
517 | "node": ">= 0.6"
518 | }
519 | },
520 | "node_modules/typescript": {
521 | "version": "4.2.2",
522 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz",
523 | "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==",
524 | "dev": true,
525 | "bin": {
526 | "tsc": "bin/tsc",
527 | "tsserver": "bin/tsserver"
528 | },
529 | "engines": {
530 | "node": ">=4.2.0"
531 | }
532 | },
533 | "node_modules/unpipe": {
534 | "version": "1.0.0",
535 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
536 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
537 | "engines": {
538 | "node": ">= 0.8"
539 | }
540 | },
541 | "node_modules/utils-merge": {
542 | "version": "1.0.1",
543 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
544 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
545 | "engines": {
546 | "node": ">= 0.4.0"
547 | }
548 | },
549 | "node_modules/vary": {
550 | "version": "1.1.2",
551 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
552 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
553 | "engines": {
554 | "node": ">= 0.8"
555 | }
556 | }
557 | },
558 | "dependencies": {
559 | "accepts": {
560 | "version": "1.3.7",
561 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
562 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
563 | "requires": {
564 | "mime-types": "~2.1.24",
565 | "negotiator": "0.6.2"
566 | }
567 | },
568 | "array-flatten": {
569 | "version": "1.1.1",
570 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
571 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
572 | },
573 | "body-parser": {
574 | "version": "1.19.0",
575 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
576 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
577 | "requires": {
578 | "bytes": "3.1.0",
579 | "content-type": "~1.0.4",
580 | "debug": "2.6.9",
581 | "depd": "~1.1.2",
582 | "http-errors": "1.7.2",
583 | "iconv-lite": "0.4.24",
584 | "on-finished": "~2.3.0",
585 | "qs": "6.7.0",
586 | "raw-body": "2.4.0",
587 | "type-is": "~1.6.17"
588 | },
589 | "dependencies": {
590 | "debug": {
591 | "version": "2.6.9",
592 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
593 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
594 | "requires": {
595 | "ms": "2.0.0"
596 | }
597 | },
598 | "http-errors": {
599 | "version": "1.7.2",
600 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
601 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
602 | "requires": {
603 | "depd": "~1.1.2",
604 | "inherits": "2.0.3",
605 | "setprototypeof": "1.1.1",
606 | "statuses": ">= 1.5.0 < 2",
607 | "toidentifier": "1.0.0"
608 | }
609 | },
610 | "inherits": {
611 | "version": "2.0.3",
612 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
613 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
614 | },
615 | "qs": {
616 | "version": "6.7.0",
617 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
618 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
619 | },
620 | "raw-body": {
621 | "version": "2.4.0",
622 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
623 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
624 | "requires": {
625 | "bytes": "3.1.0",
626 | "http-errors": "1.7.2",
627 | "iconv-lite": "0.4.24",
628 | "unpipe": "1.0.0"
629 | }
630 | },
631 | "statuses": {
632 | "version": "1.5.0",
633 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
634 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
635 | }
636 | }
637 | },
638 | "bytes": {
639 | "version": "3.1.0",
640 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
641 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
642 | },
643 | "content-disposition": {
644 | "version": "0.5.3",
645 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
646 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
647 | "requires": {
648 | "safe-buffer": "5.1.2"
649 | }
650 | },
651 | "content-type": {
652 | "version": "1.0.4",
653 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
654 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
655 | },
656 | "cookie-signature": {
657 | "version": "1.0.6",
658 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
659 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
660 | },
661 | "depd": {
662 | "version": "1.1.2",
663 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
664 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
665 | },
666 | "destroy": {
667 | "version": "1.0.4",
668 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
669 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
670 | },
671 | "ee-first": {
672 | "version": "1.1.1",
673 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
674 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
675 | },
676 | "encodeurl": {
677 | "version": "1.0.2",
678 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
679 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
680 | },
681 | "escape-html": {
682 | "version": "1.0.3",
683 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
684 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
685 | },
686 | "etag": {
687 | "version": "1.8.1",
688 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
689 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
690 | },
691 | "express": {
692 | "version": "4.17.1",
693 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
694 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
695 | "requires": {
696 | "accepts": "~1.3.7",
697 | "array-flatten": "1.1.1",
698 | "body-parser": "1.19.0",
699 | "content-disposition": "0.5.3",
700 | "content-type": "~1.0.4",
701 | "cookie": "0.4.0",
702 | "cookie-signature": "1.0.6",
703 | "debug": "2.6.9",
704 | "depd": "~1.1.2",
705 | "encodeurl": "~1.0.2",
706 | "escape-html": "~1.0.3",
707 | "etag": "~1.8.1",
708 | "finalhandler": "~1.1.2",
709 | "fresh": "0.5.2",
710 | "merge-descriptors": "1.0.1",
711 | "methods": "~1.1.2",
712 | "on-finished": "~2.3.0",
713 | "parseurl": "~1.3.3",
714 | "path-to-regexp": "0.1.7",
715 | "proxy-addr": "~2.0.5",
716 | "qs": "6.7.0",
717 | "range-parser": "~1.2.1",
718 | "safe-buffer": "5.1.2",
719 | "send": "0.17.1",
720 | "serve-static": "1.14.1",
721 | "setprototypeof": "1.1.1",
722 | "statuses": "~1.5.0",
723 | "type-is": "~1.6.18",
724 | "utils-merge": "1.0.1",
725 | "vary": "~1.1.2"
726 | },
727 | "dependencies": {
728 | "cookie": {
729 | "version": "0.4.0",
730 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
731 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
732 | },
733 | "debug": {
734 | "version": "2.6.9",
735 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
736 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
737 | "requires": {
738 | "ms": "2.0.0"
739 | }
740 | },
741 | "finalhandler": {
742 | "version": "1.1.2",
743 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
744 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
745 | "requires": {
746 | "debug": "2.6.9",
747 | "encodeurl": "~1.0.2",
748 | "escape-html": "~1.0.3",
749 | "on-finished": "~2.3.0",
750 | "parseurl": "~1.3.3",
751 | "statuses": "~1.5.0",
752 | "unpipe": "~1.0.0"
753 | }
754 | },
755 | "mime": {
756 | "version": "1.6.0",
757 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
758 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
759 | },
760 | "qs": {
761 | "version": "6.7.0",
762 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
763 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
764 | },
765 | "send": {
766 | "version": "0.17.1",
767 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
768 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
769 | "requires": {
770 | "debug": "2.6.9",
771 | "depd": "~1.1.2",
772 | "destroy": "~1.0.4",
773 | "encodeurl": "~1.0.2",
774 | "escape-html": "~1.0.3",
775 | "etag": "~1.8.1",
776 | "fresh": "0.5.2",
777 | "http-errors": "~1.7.2",
778 | "mime": "1.6.0",
779 | "ms": "2.1.1",
780 | "on-finished": "~2.3.0",
781 | "range-parser": "~1.2.1",
782 | "statuses": "~1.5.0"
783 | },
784 | "dependencies": {
785 | "ms": {
786 | "version": "2.1.1",
787 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
788 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
789 | }
790 | }
791 | },
792 | "serve-static": {
793 | "version": "1.14.1",
794 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
795 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
796 | "requires": {
797 | "encodeurl": "~1.0.2",
798 | "escape-html": "~1.0.3",
799 | "parseurl": "~1.3.3",
800 | "send": "0.17.1"
801 | }
802 | },
803 | "statuses": {
804 | "version": "1.5.0",
805 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
806 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
807 | }
808 | }
809 | },
810 | "forwarded": {
811 | "version": "0.1.2",
812 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
813 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
814 | },
815 | "fresh": {
816 | "version": "0.5.2",
817 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
818 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
819 | },
820 | "http-errors": {
821 | "version": "1.7.3",
822 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
823 | "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
824 | "requires": {
825 | "depd": "~1.1.2",
826 | "inherits": "2.0.4",
827 | "setprototypeof": "1.1.1",
828 | "statuses": ">= 1.5.0 < 2",
829 | "toidentifier": "1.0.0"
830 | },
831 | "dependencies": {
832 | "statuses": {
833 | "version": "1.5.0",
834 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
835 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
836 | }
837 | }
838 | },
839 | "iconv-lite": {
840 | "version": "0.4.24",
841 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
842 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
843 | "requires": {
844 | "safer-buffer": ">= 2.1.2 < 3"
845 | }
846 | },
847 | "inherits": {
848 | "version": "2.0.4",
849 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
850 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
851 | },
852 | "ipaddr.js": {
853 | "version": "1.9.0",
854 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
855 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
856 | },
857 | "media-typer": {
858 | "version": "0.3.0",
859 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
860 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
861 | },
862 | "merge-descriptors": {
863 | "version": "1.0.1",
864 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
865 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
866 | },
867 | "methods": {
868 | "version": "1.1.2",
869 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
870 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
871 | },
872 | "mime-db": {
873 | "version": "1.40.0",
874 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
875 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
876 | },
877 | "mime-types": {
878 | "version": "2.1.24",
879 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
880 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
881 | "requires": {
882 | "mime-db": "1.40.0"
883 | }
884 | },
885 | "ms": {
886 | "version": "2.0.0",
887 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
888 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
889 | },
890 | "negotiator": {
891 | "version": "0.6.2",
892 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
893 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
894 | },
895 | "on-finished": {
896 | "version": "2.3.0",
897 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
898 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
899 | "requires": {
900 | "ee-first": "1.1.1"
901 | }
902 | },
903 | "parseurl": {
904 | "version": "1.3.3",
905 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
906 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
907 | },
908 | "path-to-regexp": {
909 | "version": "0.1.7",
910 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
911 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
912 | },
913 | "proxy-addr": {
914 | "version": "2.0.5",
915 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
916 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
917 | "requires": {
918 | "forwarded": "~0.1.2",
919 | "ipaddr.js": "1.9.0"
920 | }
921 | },
922 | "range-parser": {
923 | "version": "1.2.1",
924 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
925 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
926 | },
927 | "safe-buffer": {
928 | "version": "5.1.2",
929 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
930 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
931 | },
932 | "safer-buffer": {
933 | "version": "2.1.2",
934 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
935 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
936 | },
937 | "setprototypeof": {
938 | "version": "1.1.1",
939 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
940 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
941 | },
942 | "toidentifier": {
943 | "version": "1.0.0",
944 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
945 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
946 | },
947 | "type-is": {
948 | "version": "1.6.18",
949 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
950 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
951 | "requires": {
952 | "media-typer": "0.3.0",
953 | "mime-types": "~2.1.24"
954 | }
955 | },
956 | "typescript": {
957 | "version": "4.2.2",
958 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz",
959 | "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==",
960 | "dev": true
961 | },
962 | "unpipe": {
963 | "version": "1.0.0",
964 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
965 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
966 | },
967 | "utils-merge": {
968 | "version": "1.0.1",
969 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
970 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
971 | },
972 | "vary": {
973 | "version": "1.1.2",
974 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
975 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
976 | }
977 | }
978 | }
979 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "image-editor-effects",
3 | "version": "1.0.0",
4 | "description": "An example of image editor effects for layers and color correction found in apps like Photoshop or GIMP.",
5 | "main": "src/script.js",
6 | "scripts": {
7 | "build": "tsc",
8 | "start": "node server.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/alaingalvan/image-editor-effects.git"
13 | },
14 | "keywords": [
15 | "image",
16 | "editor",
17 | "effects"
18 | ],
19 | "author": "Alain Galvan",
20 | "license": "Unlicense",
21 | "bugs": {
22 | "url": "https://github.com/alaingalvan/image-editor-effects/issues"
23 | },
24 | "homepage": "https://github.com/alaingalvan/image-editor-effects#readme",
25 | "devDependencies": {
26 | "typescript": "^4.x.x"
27 | },
28 | "dependencies": {
29 | "express": "^4.x.x"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Image Editor Effects
4 |
5 | [![License][license-img]][license-url]
6 | [![Codepen][codepen-img]][codepen-url]
7 |
8 | Image processing effects used in image editors like **Adobe Photoshop** or **GIMP** are used to composite different layers and adjust the overall appearance of an image. These effects build upon research in areas such as signal processing, statistics, and mathematical analysis, and applies them to visual effects and postprocessing.
9 |
10 | This is an example of photoshop layer effects, describe in detail in this [blog post](https://alain.xyz/blog/image-editor-effects).
11 |
12 | ## Shader Snippets
13 |
14 | You'll find these GLSL snippets in `src/script.ts`, line 4.
15 |
16 | ## Running
17 |
18 | ```bash
19 | # 👶 Get Dependencies
20 | npm i
21 |
22 | # 🔨 Compile typescript files
23 | npm run build
24 |
25 | # 💻 Run a server at http://localhost:8080
26 | npm start
27 | ```
28 |
29 | ## License
30 |
31 | This project is unlicensed, feel free to use it however you would like.
32 |
33 |
34 | [license-img]: https://img.shields.io/:license-unlicense-blue.svg?style=flat-square
35 | [license-url]: https://unlicense.org/
36 | [codepen-img]: https://img.shields.io/:demo-codepen-1e1f26.svg?style=flat-square
37 | [codepen-url]: https://codepen.io/alaingalvan/pen/eQeqwE
38 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path')
3 |
4 | const app = express();
5 | app.use('/src', express.static(path.join(__dirname, 'src')));
6 | app.get('/', function(_, response) {
7 | response.sendFile(path.join(__dirname, 'index.html'));
8 | });
9 |
10 | const listener = app.listen(8080, function() {
11 | console.log('Your app running at http://localhost:' + listener.address().port);
12 | });
13 |
--------------------------------------------------------------------------------
/src/assets/bottomlayer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alaingalvan/image-editor-effects/de4a88a0ac96a9f077e8ef9f50e0a9c946e0bde5/src/assets/bottomlayer.jpg
--------------------------------------------------------------------------------
/src/assets/toplayer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alaingalvan/image-editor-effects/de4a88a0ac96a9f077e8ef9f50e0a9c946e0bde5/src/assets/toplayer.png
--------------------------------------------------------------------------------
/src/script.js:
--------------------------------------------------------------------------------
1 | var bottomImgDom = document.getElementById("bottomLayerImg");
2 | var topImgDom = document.getElementById('topLayerImg');
3 | var bottomLayerImg = bottomImgDom.src;
4 | var topLayerImg = topImgDom.src;
5 | var effects = {
6 | overlay: "\n// \uD83C\uDF26\uFE0F Overlay\nvec4 overlay(vec4 col, vec4 blend)\n{\n vec4 outColor = vec4(0., 0., 0., col.a);\n\n if (col.r > 0.5)\n {\n outColor.r = (1.0 - (1.0 - 2.0 * (col.r - 0.5)) * (1.0 - blend.r));\n }\n else\n {\n outColor.r = ((2.0 * col.r) * blend.r);\n }\n\n if (col.g > 0.5)\n {\n outColor.g = (1.0 - (1.0 - 2.0 * (col.g - 0.5)) * (1.0 - blend.g));\n }\n else\n {\n outColor.g = ((2.0 * col.g) * blend.g);\n }\n\n if (col.b > 0.5)\n {\n outColor.b = (1.0 - (1.0 - 2.0 * (col.b - 0.5)) * (1.0 - blend.b));\n }\n else\n {\n outColor.b = ((2.0 * col.b) * blend.b);\n }\n\n return mix(col, outColor, blend.a);\n}\n",
7 | multiply: "\n// \u2734\uFE0F Multiply\nvec4 multiply(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, col.rgb * blend.rgb, blend.a), col.a);\n}",
8 | dissolve: "\n//\uD83D\uDD00 iq's random functions:\nfloat rand(float seed)\n{\n return abs(fract(sin(seed) * 43758.5453123));\n}\n\nfloat rand(vec2 seed)\n{\n return rand(dot(seed, vec2(12.9898, 78.233)));\n}\n\n// \uD83E\uDD64 Dissolve\nvec4 dissolve(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, blend.rgb, blend.a > rand(vFragCoord) ? 1.0 : 0.0), col.a);\n}",
9 | darken: "\n// \uD83C\uDF18 Darken\nvec4 darken(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, min(col.rgb, blend.rgb), blend.a), col.a);\n}",
10 | lighten: "\n// \uD83C\uDF14 Lighten\nvec4 lighten(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, max(col.rgb, blend.rgb), blend.a), col.a);\n}",
11 | screen: "\n// \uD83D\uDD05 Screen\nvec4 screen(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, 1.0 - (1.0 - col.rgb) * (1.0 - blend.rgb), blend.a), col.a);\n}",
12 | divide: "\n// \uD83D\uDDC2\uFE0F Divide\nvec4 divide(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, sign(blend.rgb) * col.rgb / clamp(blend.rgb, 0.00001, 1.0), blend.a), col.a);\n}",
13 | 'color dodge': "\n// \uD83C\uDF05 Color Dodge\nvec4 colorDodge(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, col.rgb / clamp(1.0 - blend.rgb, 0.00001, 1.0), blend.a), col.a);\n}",
14 | 'linear dodge': "\n// \u2600\uFE0F Linear Dodge\nvec4 linearDodge(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, col.rgb + blend.rgb, blend.a), col.a);\n}",
15 | 'color burn': "\n// \uD83D\uDD6F\uFE0F Color Burn\nvec4 colorBurn(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, 1.0 - (1.0 - col.rgb) / clamp(blend.rgb, 0.00001, 1.0), blend.a), col.a);\n}",
16 | 'linear burn': "\n// \uD83D\uDD25 Linear Burn\nvec4 linearBurn(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, max(col.rgb - (1.0 - blend.rgb), 0.0), blend.a), col.a);\n}",
17 | 'exclusion': "\n// \uD83E\uDD51 Exclusion\nvec4 exclusion(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, 0.5 - 2.0 * (col.rgb - 0.5) * (blend.rgb - 0.5), blend.a), col.a);\n}",
18 | 'difference': "\n// \uD83D\uDC41\uFE0F Difference\nvec4 difference(vec4 col, vec4 blend)\n{\n return vec4(mix(col.rgb, abs(col.rgb - blend.rgb), blend.a), col.a);\n}"
19 | };
20 | var curEffect = effects.overlay;
21 | var canvas = document.getElementById('game');
22 | var compiled, gui;
23 | var gl = canvas.getContext('webgl');
24 | if (!gl) {
25 | throw new Error('Could not create WebGL Context!');
26 | }
27 | var ndcQuad = [1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0];
28 | var indices = [0, 1, 2, 1, 2, 3];
29 | var dataBuffer = gl.createBuffer();
30 | var indexBuffer = gl.createBuffer();
31 | gl.bindBuffer(gl.ARRAY_BUFFER, dataBuffer);
32 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(ndcQuad), gl.STATIC_DRAW);
33 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
34 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
35 | function createProgram(vsSource, fsSource) {
36 | var vs = gl.createShader(gl.VERTEX_SHADER);
37 | gl.shaderSource(vs, vsSource);
38 | gl.compileShader(vs);
39 | if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
40 | console.error('An error occurred compiling the shader: ' + gl.getShaderInfoLog(vs));
41 | }
42 | var fs = gl.createShader(gl.FRAGMENT_SHADER);
43 | gl.shaderSource(fs, fsSource);
44 | gl.compileShader(fs);
45 | if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
46 | console.error('An error occurred compiling the shader: ' + gl.getShaderInfoLog(fs));
47 | }
48 | var program = gl.createProgram();
49 | gl.attachShader(program, vs);
50 | gl.attachShader(program, fs);
51 | gl.linkProgram(program);
52 | if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
53 | console.error(gl.getProgramInfoLog(program));
54 | }
55 | return { vs: vs, fs: fs, program: program };
56 | }
57 | function deleteProgram(_a) {
58 | var vs = _a.vs, fs = _a.fs, program = _a.program;
59 | gl.deleteProgram(program);
60 | gl.deleteShader(vs);
61 | gl.deleteShader(fs);
62 | }
63 | var vs = "\nattribute vec2 aPosition;\nvarying vec2 vFragCoord;\n\nvoid main()\n{\n vFragCoord = (0.5 * aPosition) + vec2(0.5, 0.5);\n vFragCoord.y = 1.0 - vFragCoord.y;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n";
64 | var fs = "\nprecision mediump float;\n\nvarying vec2 vFragCoord;\n\nuniform sampler2D tBottomLayer;\nuniform sampler2D tTopLayer;\n\n" + curEffect + "\n#define effect overlay\n\nvoid main()\n{\n vec2 uv = vFragCoord;\n vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n\n vec4 bottomColor = texture2D(tBottomLayer, uv);\n vec4 topColor = texture2D(tTopLayer, uv);\n\n outColor = effect(bottomColor, topColor);\n\n gl_FragColor = outColor;\n}\n";
65 | compiled = createProgram(vs, fs);
66 | function loadTexture(url) {
67 | var tex = gl.createTexture();
68 | gl.bindTexture(gl.TEXTURE_2D, tex);
69 | var pixel = new Uint8Array([0, 0, 128, 255]);
70 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
71 | var img = new Image();
72 | img.src = url;
73 | img.onload = function () {
74 | gl.bindTexture(gl.TEXTURE_2D, tex);
75 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
76 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
77 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
78 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
79 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
80 | };
81 | return tex;
82 | }
83 | var topLayer = loadTexture(topLayerImg);
84 | var bottomLayer = loadTexture(bottomLayerImg);
85 | function draw() {
86 | gl.useProgram(compiled.program);
87 | var loc = gl.getAttribLocation(compiled.program, 'aPosition');
88 | gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 4 * 2, 0);
89 | gl.enableVertexAttribArray(loc);
90 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
91 | var shaderTexNumber = 0;
92 | var bottomLayerLoc = gl.getUniformLocation(compiled.program, 'tBottomLayer');
93 | gl.uniform1i(bottomLayerLoc, shaderTexNumber);
94 | gl.activeTexture(gl.TEXTURE0 + shaderTexNumber);
95 | gl.bindTexture(gl.TEXTURE_2D, bottomLayer);
96 | shaderTexNumber++;
97 | var topLayerLoc = gl.getUniformLocation(compiled.program, 'tTopLayer');
98 | gl.uniform1i(topLayerLoc, shaderTexNumber);
99 | gl.activeTexture(gl.TEXTURE0 + shaderTexNumber);
100 | gl.bindTexture(gl.TEXTURE_2D, topLayer);
101 | gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
102 | }
103 | var resizeHandler = function () {
104 | var size = innerWidth < innerHeight ? innerHeight : innerWidth;
105 | canvas.width = size;
106 | canvas.height = size * (9.0 / 16.0);
107 | gl.viewport(0, 0, size, size * (9.0 / 16.0));
108 | draw();
109 | };
110 | window.addEventListener('resize', resizeHandler);
111 | resizeHandler();
112 | function update() {
113 | draw();
114 | requestAnimationFrame(update);
115 | }
116 | requestAnimationFrame(update);
117 | function toCamelCase(s) {
118 | return s.replace(/^([A-Z])|\s(\w)/g, function (match, p1, p2, offset) {
119 | if (p2)
120 | return p2.toUpperCase();
121 | return p1.toLowerCase();
122 | });
123 | }
124 | ;
125 | gui = new dat.GUI({ autoPlace: false });
126 | var params = {
127 | Effect: 'Overlay'
128 | };
129 | var list = gui.add(params, 'Effect', [
130 | 'Dissolve',
131 | 'Darken',
132 | 'Lighten',
133 | 'Multiply',
134 | 'Divide',
135 | 'Screen',
136 | 'Overlay',
137 | 'Color Dodge',
138 | 'Linear Dodge',
139 | 'Color Burn',
140 | 'Linear Burn',
141 | 'Exclusion',
142 | 'Difference',
143 | ]);
144 | list.onChange(function (value) {
145 | console.log('Changing Effect!');
146 | value = value.toLowerCase();
147 | curEffect = effects[value];
148 | fs = "\nprecision mediump float;\n\nvarying vec2 vFragCoord;\n\nuniform sampler2D tBottomLayer;\nuniform sampler2D tTopLayer;\n\n" + curEffect + "\n#define effect " + toCamelCase(value) + "\n\nvoid main()\n{\n vec2 uv = vFragCoord;\n vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n\n vec4 bottomColor = texture2D(tBottomLayer, uv);\n vec4 topColor = texture2D(tTopLayer, uv);\n\n outColor = effect(bottomColor, topColor);\n\n gl_FragColor = outColor;\n}\n";
149 | deleteProgram(compiled);
150 | compiled = createProgram(vs, fs);
151 | console.log(fs);
152 | });
153 | gui.close();
154 | var debugContainer = document.getElementById('debug');
155 | gui.domElement.style.position = 'absolute';
156 | gui.domElement.style.top = '0px';
157 | gui.domElement.style.left = '0px';
158 | debugContainer.appendChild(gui.domElement);
159 | //# sourceMappingURL=script.js.map
--------------------------------------------------------------------------------
/src/script.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"script.js","sourceRoot":"","sources":["script.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/src/script.ts:
--------------------------------------------------------------------------------
1 | declare var dat;
2 |
3 | var bottomImgDom: HTMLImageElement = document.getElementById("bottomLayerImg") as HTMLImageElement;
4 | var topImgDom: HTMLImageElement = document.getElementById('topLayerImg') as HTMLImageElement;
5 |
6 | var bottomLayerImg = bottomImgDom.src;
7 | var topLayerImg = topImgDom.src;
8 |
9 | let effects = {
10 | overlay: `
11 | // 🌦️ Overlay
12 | vec4 overlay(vec4 col, vec4 blend)
13 | {
14 | vec4 outColor = vec4(0., 0., 0., col.a);
15 |
16 | if (col.r > 0.5)
17 | {
18 | outColor.r = (1.0 - (1.0 - 2.0 * (col.r - 0.5)) * (1.0 - blend.r));
19 | }
20 | else
21 | {
22 | outColor.r = ((2.0 * col.r) * blend.r);
23 | }
24 |
25 | if (col.g > 0.5)
26 | {
27 | outColor.g = (1.0 - (1.0 - 2.0 * (col.g - 0.5)) * (1.0 - blend.g));
28 | }
29 | else
30 | {
31 | outColor.g = ((2.0 * col.g) * blend.g);
32 | }
33 |
34 | if (col.b > 0.5)
35 | {
36 | outColor.b = (1.0 - (1.0 - 2.0 * (col.b - 0.5)) * (1.0 - blend.b));
37 | }
38 | else
39 | {
40 | outColor.b = ((2.0 * col.b) * blend.b);
41 | }
42 |
43 | return mix(col, outColor, blend.a);
44 | }
45 | `,
46 | multiply: `
47 | // ✴️ Multiply
48 | vec4 multiply(vec4 col, vec4 blend)
49 | {
50 | return vec4(mix(col.rgb, col.rgb * blend.rgb, blend.a), col.a);
51 | }`,
52 | dissolve: `
53 | //🔀 iq's random functions:
54 | float rand(float seed)
55 | {
56 | return abs(fract(sin(seed) * 43758.5453123));
57 | }
58 |
59 | float rand(vec2 seed)
60 | {
61 | return rand(dot(seed, vec2(12.9898, 78.233)));
62 | }
63 |
64 | // 🥤 Dissolve
65 | vec4 dissolve(vec4 col, vec4 blend)
66 | {
67 | return vec4(mix(col.rgb, blend.rgb, blend.a > rand(vFragCoord) ? 1.0 : 0.0), col.a);
68 | }`,
69 | darken: `
70 | // 🌘 Darken
71 | vec4 darken(vec4 col, vec4 blend)
72 | {
73 | return vec4(mix(col.rgb, min(col.rgb, blend.rgb), blend.a), col.a);
74 | }`,
75 | lighten:`
76 | // 🌔 Lighten
77 | vec4 lighten(vec4 col, vec4 blend)
78 | {
79 | return vec4(mix(col.rgb, max(col.rgb, blend.rgb), blend.a), col.a);
80 | }`,
81 | screen: `
82 | // 🔅 Screen
83 | vec4 screen(vec4 col, vec4 blend)
84 | {
85 | return vec4(mix(col.rgb, 1.0 - (1.0 - col.rgb) * (1.0 - blend.rgb), blend.a), col.a);
86 | }`,
87 | divide: `
88 | // 🗂️ Divide
89 | vec4 divide(vec4 col, vec4 blend)
90 | {
91 | return vec4(mix(col.rgb, sign(blend.rgb) * col.rgb / clamp(blend.rgb, 0.00001, 1.0), blend.a), col.a);
92 | }`,
93 | 'color dodge': `
94 | // 🌅 Color Dodge
95 | vec4 colorDodge(vec4 col, vec4 blend)
96 | {
97 | return vec4(mix(col.rgb, col.rgb / clamp(1.0 - blend.rgb, 0.00001, 1.0), blend.a), col.a);
98 | }`,
99 | 'linear dodge': `
100 | // ☀️ Linear Dodge
101 | vec4 linearDodge(vec4 col, vec4 blend)
102 | {
103 | return vec4(mix(col.rgb, col.rgb + blend.rgb, blend.a), col.a);
104 | }`,
105 | 'color burn': `
106 | // 🕯️ Color Burn
107 | vec4 colorBurn(vec4 col, vec4 blend)
108 | {
109 | return vec4(mix(col.rgb, 1.0 - (1.0 - col.rgb) / clamp(blend.rgb, 0.00001, 1.0), blend.a), col.a);
110 | }`,
111 | 'linear burn': `
112 | // 🔥 Linear Burn
113 | vec4 linearBurn(vec4 col, vec4 blend)
114 | {
115 | return vec4(mix(col.rgb, max(col.rgb - (1.0 - blend.rgb), 0.0), blend.a), col.a);
116 | }`,
117 | 'exclusion': `
118 | // 🥑 Exclusion
119 | vec4 exclusion(vec4 col, vec4 blend)
120 | {
121 | return vec4(mix(col.rgb, 0.5 - 2.0 * (col.rgb - 0.5) * (blend.rgb - 0.5), blend.a), col.a);
122 | }`,
123 | 'difference': `
124 | // 👁️ Difference
125 | vec4 difference(vec4 col, vec4 blend)
126 | {
127 | return vec4(mix(col.rgb, abs(col.rgb - blend.rgb), blend.a), col.a);
128 | }`
129 | };
130 |
131 | // Effects
132 | let curEffect = effects.overlay;
133 |
134 | // ⚪ Initialization
135 | let canvas = document.getElementById('game') as HTMLCanvasElement;
136 | let compiled, gui;
137 |
138 | var gl = canvas.getContext('webgl');
139 | if (!gl) {
140 | throw new Error('Could not create WebGL Context!');
141 | }
142 |
143 | // 🔲 Create NDC Space Quad (attribute vec2 position)
144 | let ndcQuad = [ 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ];
145 | let indices = [ 0, 1, 2, 1, 2, 3 ];
146 |
147 | // Create Buffers
148 | let dataBuffer = gl.createBuffer();
149 | let indexBuffer = gl.createBuffer();
150 |
151 | // Bind Data/Indices to Buffers
152 | gl.bindBuffer(gl.ARRAY_BUFFER, dataBuffer);
153 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(ndcQuad), gl.STATIC_DRAW);
154 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
155 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
156 |
157 | function createProgram(vsSource: string, fsSource: string) {
158 | let vs = gl.createShader(gl.VERTEX_SHADER);
159 | gl.shaderSource(vs, vsSource);
160 | gl.compileShader(vs);
161 | if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
162 | console.error('An error occurred compiling the shader: ' + gl.getShaderInfoLog(vs));
163 | }
164 |
165 | let fs = gl.createShader(gl.FRAGMENT_SHADER);
166 | gl.shaderSource(fs, fsSource);
167 | gl.compileShader(fs);
168 | if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
169 | console.error('An error occurred compiling the shader: ' + gl.getShaderInfoLog(fs));
170 | }
171 |
172 | let program = gl.createProgram();
173 | gl.attachShader(program, vs);
174 | gl.attachShader(program, fs);
175 | gl.linkProgram(program);
176 | if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
177 | console.error(gl.getProgramInfoLog(program));
178 | }
179 | return { vs, fs, program };
180 | }
181 |
182 | function deleteProgram({ vs, fs, program }) {
183 | gl.deleteProgram(program);
184 | gl.deleteShader(vs);
185 | gl.deleteShader(fs);
186 | }
187 |
188 | let vs = `
189 | attribute vec2 aPosition;
190 | varying vec2 vFragCoord;
191 |
192 | void main()
193 | {
194 | vFragCoord = (0.5 * aPosition) + vec2(0.5, 0.5);
195 | vFragCoord.y = 1.0 - vFragCoord.y;
196 | gl_Position = vec4(aPosition, 0.0, 1.0);
197 | }
198 | `;
199 |
200 | let fs = `
201 | precision mediump float;
202 |
203 | varying vec2 vFragCoord;
204 |
205 | uniform sampler2D tBottomLayer;
206 | uniform sampler2D tTopLayer;
207 |
208 | ${curEffect}
209 | #define effect overlay
210 |
211 | void main()
212 | {
213 | vec2 uv = vFragCoord;
214 | vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);
215 |
216 | vec4 bottomColor = texture2D(tBottomLayer, uv);
217 | vec4 topColor = texture2D(tTopLayer, uv);
218 |
219 | outColor = effect(bottomColor, topColor);
220 |
221 | gl_FragColor = outColor;
222 | }
223 | `;
224 |
225 | compiled = createProgram(vs, fs);
226 |
227 | // 🖼️ Load Textures
228 | function loadTexture(url: string) {
229 | let tex = gl.createTexture();
230 | gl.bindTexture(gl.TEXTURE_2D, tex);
231 | const pixel = new Uint8Array([ 0, 0, 128, 255 ]);
232 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
233 | let img = new Image();
234 | img.src = url;
235 | img.onload = () => {
236 | gl.bindTexture(gl.TEXTURE_2D, tex);
237 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
238 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
239 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
240 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
241 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
242 | };
243 | return tex;
244 | }
245 |
246 | let topLayer = loadTexture(topLayerImg);
247 | let bottomLayer = loadTexture(bottomLayerImg);
248 |
249 | // 📐 Draw
250 | function draw() {
251 | // Bind Shaders
252 | gl.useProgram(compiled.program);
253 | // Bind Vertex Layout
254 | let loc = gl.getAttribLocation(compiled.program, 'aPosition');
255 | gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 4 * 2, 0);
256 | gl.enableVertexAttribArray(loc);
257 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
258 |
259 | // Bind Uniforms
260 | var shaderTexNumber = 0;
261 | let bottomLayerLoc = gl.getUniformLocation(compiled.program, 'tBottomLayer');
262 | gl.uniform1i(bottomLayerLoc, shaderTexNumber);
263 | gl.activeTexture(gl.TEXTURE0 + shaderTexNumber);
264 | gl.bindTexture(gl.TEXTURE_2D, bottomLayer);
265 | shaderTexNumber++;
266 | let topLayerLoc = gl.getUniformLocation(compiled.program, 'tTopLayer');
267 | gl.uniform1i(topLayerLoc, shaderTexNumber);
268 | gl.activeTexture(gl.TEXTURE0 + shaderTexNumber);
269 | gl.bindTexture(gl.TEXTURE_2D, topLayer);
270 |
271 | gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
272 | }
273 | let resizeHandler = () => {
274 | var size = innerWidth < innerHeight ? innerHeight : innerWidth;
275 | canvas.width = size;
276 | canvas.height = size * (9.0 / 16.0);
277 | gl.viewport(0, 0, size, size * (9.0 / 16.0));
278 | draw();
279 | };
280 |
281 | window.addEventListener('resize', resizeHandler);
282 | resizeHandler();
283 |
284 | function update() {
285 | draw();
286 | requestAnimationFrame(update);
287 | }
288 |
289 | requestAnimationFrame(update);
290 |
291 | function toCamelCase(s) {
292 | return s.replace(/^([A-Z])|\s(\w)/g, function(match, p1, p2, offset) {
293 | if (p2) return p2.toUpperCase();
294 | return p1.toLowerCase();
295 | });
296 | };
297 |
298 | //DATGUI Controls
299 | gui = new dat.GUI({ autoPlace: false });
300 | var params = {
301 | Effect: 'Overlay'
302 | };
303 | var list = gui.add(params, 'Effect', [
304 | 'Dissolve',
305 | 'Darken',
306 | 'Lighten',
307 | 'Multiply',
308 | 'Divide',
309 | 'Screen',
310 | 'Overlay',
311 | 'Color Dodge',
312 | 'Linear Dodge',
313 | 'Color Burn',
314 | 'Linear Burn',
315 | 'Exclusion',
316 | 'Difference',
317 | //'Curves',
318 | //'Brightness Contrast',
319 | //'Gamma',
320 | //'Hue Saturation Lightness',
321 | //'Gradient',
322 | //'Gaussian Blur',
323 | //'Pixelate',
324 | //'Sobel',
325 | //'Sharpen'
326 | ]);
327 |
328 | list.onChange((value) => {
329 | console.log('Changing Effect!');
330 | value = value.toLowerCase();
331 | curEffect = effects[value];
332 |
333 | fs = `
334 | precision mediump float;
335 |
336 | varying vec2 vFragCoord;
337 |
338 | uniform sampler2D tBottomLayer;
339 | uniform sampler2D tTopLayer;
340 |
341 | ${curEffect}
342 | #define effect ${toCamelCase(value)}
343 |
344 | void main()
345 | {
346 | vec2 uv = vFragCoord;
347 | vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);
348 |
349 | vec4 bottomColor = texture2D(tBottomLayer, uv);
350 | vec4 topColor = texture2D(tTopLayer, uv);
351 |
352 | outColor = effect(bottomColor, topColor);
353 |
354 | gl_FragColor = outColor;
355 | }
356 | `;
357 |
358 | deleteProgram(compiled);
359 | compiled = createProgram(vs, fs);
360 | console.log(fs);
361 | });
362 |
363 | gui.close();
364 | var debugContainer = document.getElementById('debug');
365 | gui.domElement.style.position = 'absolute';
366 | gui.domElement.style.top = '0px';
367 | gui.domElement.style.left = '0px';
368 | debugContainer.appendChild(gui.domElement);
369 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | overflow: hidden;
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | width: 100vw;
7 | height: 100vh;
8 | background: #000;
9 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "es5",
7 | "es2015",
8 | "es2016",
9 | "es2017"
10 | ],
11 | "module": "commonjs",
12 | "declaration": false,
13 | "noImplicitAny": false,
14 | "suppressImplicitAnyIndexErrors": true,
15 | "removeComments": true,
16 | "emitDecoratorMetadata": true,
17 | "experimentalDecorators": true,
18 | "noEmitHelpers": false,
19 | "sourceMap": true,
20 | "strictNullChecks": false,
21 | "jsx": "react",
22 | "allowSyntheticDefaultImports": true
23 | }
24 | }
--------------------------------------------------------------------------------