├── .gitignore
├── CHANGELOG
├── LICENSE
├── README.md
├── backend
├── SulfurousOffline.zip
├── admintools
│ ├── admintools.js
│ └── logs.json
├── cloud.js
├── cloudSave
│ └── 237126447.json
├── package.js
├── package.json
├── sb2
│ ├── .gitkeep
│ ├── 168825763project.json
│ ├── 235462997project.json
│ └── 237126447project.json
├── sb3
│ └── .gitkeep
├── sb3converter.js
├── server.js
└── ssl
│ └── .gitkeep
├── docker-compose.yml
├── docker-composeSULFSER.yml
├── frontend
├── main.js
├── package.json
└── public
│ ├── admintools
│ └── index.html
│ ├── css
│ ├── app.css
│ ├── embed.css
│ ├── index.css
│ └── player.css
│ ├── fonts
│ ├── DSEG7Classic-Light.ttf
│ └── fonts.js
│ ├── html
│ ├── app.html
│ ├── embed.html
│ └── embedtest.html
│ ├── img
│ ├── favicon.ico
│ ├── icons.svg
│ └── sulfurouslogo.png
│ ├── index.html
│ ├── js
│ ├── app.js
│ ├── embed.js
│ ├── fonts.js
│ ├── gl-matrix-min.js
│ ├── gyronorm.complete.min.js
│ ├── index.js
│ ├── jquery.qrcode.js
│ ├── phosphorus.js
│ ├── player.js
│ ├── qrcode.min.js
│ ├── shaders.js
│ ├── socket.io.js
│ ├── socket.io.js.map
│ └── websocket.js
│ └── soundbank
│ ├── Instr.as
│ ├── drums
│ ├── BassDrum(1b)_22k.wav
│ ├── Bongo_22k.wav
│ ├── Cabasa(1)_22k.wav
│ ├── Clap(1)_22k.wav
│ ├── Claves(1)_22k.wav
│ ├── Conga(1)_22k.wav
│ ├── Cowbell(3)_22k.wav
│ ├── Crash(2)_22k.wav
│ ├── Cuica(2)_22k.wav
│ ├── GuiroLong(1)_22k.wav
│ ├── GuiroShort(1)_22k.wav
│ ├── HiHatClosed(1)_22k.wav
│ ├── HiHatOpen(2)_22k.wav
│ ├── HiHatPedal(1)_22k.wav
│ ├── Maracas(1)_22k.wav
│ ├── SideStick(1)_22k.wav
│ ├── SnareDrum(1)_22k.wav
│ ├── Tambourine(3)_22k.wav
│ ├── Tom(1)_22k.wav
│ ├── Triangle(1)_22k.wav
│ ├── Vibraslap(1)_22k.wav
│ └── WoodBlock(1)_22k.wav
│ └── instruments
│ ├── AcousticGuitar_F3_22k.wav
│ ├── AcousticPiano(5)_A%233_22k.wav
│ ├── AcousticPiano(5)_A3_22k.wav
│ ├── AcousticPiano(5)_C4_22k.wav
│ ├── AcousticPiano(5)_C6_22k.wav
│ ├── AcousticPiano(5)_D6_22k.wav
│ ├── AcousticPiano(5)_D7_22k.wav
│ ├── AcousticPiano(5)_F5_22k.wav
│ ├── AcousticPiano(5)_G4_22k.wav
│ ├── AltoSax(3)_C6_22k.wav
│ ├── AltoSax_A3_22K.wav
│ ├── BassTrombone_A2(2)_22k.wav
│ ├── BassTrombone_A2(3)_22k.wav
│ ├── Bassoon_C3_22k.wav
│ ├── Cello(3)_A2_22k.wav
│ ├── Cello(3b)_C2_22k.wav
│ ├── Choir(4)_F3_22k.wav
│ ├── Choir(4)_F4_22k.wav
│ ├── Choir(4)_F5_22k.wav
│ ├── Clarinet_C4_22k.wav
│ ├── ElectricBass(2)_G1_22k.wav
│ ├── ElectricGuitar(2)_F3(1)_22k.wav
│ ├── ElectricPiano_C2_22k.wav
│ ├── ElectricPiano_C4_22k.wav
│ ├── EnglishHorn(1)_D4_22k.wav
│ ├── EnglishHorn(1)_F3_22k.wav
│ ├── Flute(3)_B5(1)_22k.wav
│ ├── Flute(3)_B5(2)_22k.wav
│ ├── Marimba_C4_22k.wav
│ ├── MusicBox_C4_22k.wav
│ ├── Organ(2)_G2_22k.wav
│ ├── Pizz(2)_A3_22k.wav
│ ├── Pizz(2)_E4_22k.wav
│ ├── Pizz(2)_G2_22k.wav
│ ├── SteelDrum_D5_22k.wav
│ ├── SynthLead(6)_C4_22k.wav
│ ├── SynthLead(6)_C6_22k.wav
│ ├── SynthPad(2)_A3_22k.wav
│ ├── SynthPad(2)_C6_22k.wav
│ ├── TenorSax(1)_C3_22k.wav
│ ├── Trombone_B3_22k.wav
│ ├── Trumpet_E5_22k.wav
│ ├── Vibraphone_C3_22k.wav
│ ├── Violin(2)_D4_22K.wav
│ ├── Violin(3)_A4_22k.wav
│ ├── Violin(3b)_E5_22k.wav
│ └── WoodenFlute_C5_22k.wav
├── imgs
├── img0.png
├── img1.png
├── img10.png
├── img11.png
├── img2.png
├── img3.png
├── img4.png
├── img5.png
├── img6.png
├── img7.png
├── img8.png
└── img9.png
├── sb3tosb2
├── dockerfile
├── sb2
│ └── .gitkeep
├── sb3
│ ├── .gitkeep
│ └── converted
│ │ └── .gitkeep
└── src
│ ├── LICENSE
│ ├── README.md
│ ├── run.sh
│ └── sb3tosb2.py
└── start
├── startSulurousCloud.bat
├── startSulurousCloud.sh
├── startSulurousSB2.bat
├── startSulurousSB2.sh
├── startSulurousSB3.bat
└── startSulurousSB3.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | *.sb2
3 | *.sb3
4 | package-lock.json
5 | .vscode/
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | Sulfurous Changelog
2 |
3 |
4 | Bugfixes:
5 |
6 | * SVGs (vector sprites) now load. (canvg was dropped)
7 | * SVGs render correctly in most cases. (text still doesn't work).
8 | * All sound is supported, doesn't always work in Firefox. (Chrome works)
9 | * Support for touchscreen and mouse on hybrid devices.
10 | * Costume selection emulates Scratch more closely now.
11 | * Sprite does not draw while being dragged.
12 | * UI is visible in fullscreen in Firefox.
13 | * SVGs without content no longer cause problems.
14 | * Loaded SVGs are hidden from DOM.
15 | * Default pen color is set (blue).
16 |
17 | Improvements:
18 |
19 | * Bitmaps render without image smoothing.
20 | * Vector sprites are rendered according to screen resolution, so they never pixelate.
21 | * Bitmaps embedded in SVG also render without image smoothing.
22 |
23 | New Features:
24 |
25 | * Some graphic effects were added: Pixelate, Mosaic, Brightness.
26 | * Adjustable screen size: Package and Embed options allow setting a fixed screen size.
27 |
28 | Planned/Ideas:
29 |
30 | * Add all visual effects.
31 | * Cloud vars, possibly using cookies.
32 | * Networking between projects (like mesh).
33 | * Insertion of custom code in Scratch project.
34 | * Access to rendering options through Scratch project.
35 | * Import/export of local files into Scratch project.
36 | * Compiled Javascript code viewer.
37 | * WebGL rendering.
38 | * Different rendering of speech bubbles. (not in DOM).
39 | * Fix SVG text and font.
40 | * Render lists (show list/hide list).
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2014 Nathan Dinsmore
4 | Copyright (c) 2016 Mittagskogel
5 | Copyright (c) 2017-2020 FRALEX
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | this software and associated documentation files (the "Software"), to deal in
9 | the Software without restriction, including without limitation the rights to
10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | the Software, and to permit persons to whom the Software is furnished to do so,
12 | subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/backend/SulfurousOffline.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/backend/SulfurousOffline.zip
--------------------------------------------------------------------------------
/backend/admintools/admintools.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 |
3 | let logs;
4 |
5 | var setupAdminTools = function (io) {
6 |
7 | console.log(__dirname)
8 |
9 | logs = JSON.parse(fs.readFileSync(__dirname + "/logs.json"))
10 |
11 | io = io.of('/admintools')
12 | io.on('connection', function (socket) {
13 | console.log("client connected")
14 |
15 | socket.on("getLogs", function () {
16 |
17 | calculateLogs()
18 | socket.emit("logs", {
19 | "lastHour": logs.requests.lastHour,
20 | "last24Hours": logs.requests.last24Hours,
21 | "last30Days": logs.requests.last30Days,
22 | "currentConnections": logs.currentConnections,
23 | "SB2IDs": logs.lastSB2IDs,
24 | "SB3IDs": logs.lastSB3IDs,
25 | "landingPageLoad": logs.landingPageLoad,
26 | "SB3Load": logs.SB3Load,
27 | "SB2Load": logs.SB2Load
28 | })
29 | })
30 |
31 |
32 |
33 | });
34 |
35 |
36 |
37 | calculateLogs()
38 | console.log(logs)
39 |
40 | console.log("ADMINTOOLS SCRIPT")
41 | }
42 |
43 |
44 | function calculateLogs() {
45 | console.log({ "lastHour": logs.requests.lastHour, "last24Hours": logs.requests.last24Hours, "last30Days": logs.requests.last30Days, "currentConnections": logs.currentConnections })
46 | logs.requests.lastHour = 0;
47 | logs.requests.last24Hours = 0;
48 | logs.requests.last30Days = 0;
49 | logs.lastSB2IDs = {};
50 | logs.lastSB3IDs = {};
51 | logs.landingPageLoad = 0;
52 | logs.SB2Load = 0;
53 | logs.SB3Load = 0;
54 | logs.requests.all.forEach(element => {
55 | // console.log(element)
56 | //console.log(new Date(element.timestamp).getTime() + " " + (new Date().getTime() + (3600 * 1000)) + " " + (new Date() - new Date(element.timestamp).getTime()))
57 |
58 | if ((new Date() - new Date(element.timestamp).getTime()) < (3600 * 1000)) {
59 | logs.requests.lastHour++;
60 | }
61 | if ((new Date() - new Date(element.timestamp).getTime()) < (3600 * 1000 * 24)) {
62 | logs.requests.last24Hours++;
63 | }
64 | if ((new Date() - new Date(element.timestamp).getTime()) < (3600 * 1000 * 24 * 30)) {
65 | logs.requests.last30Days++;
66 | }
67 |
68 |
69 |
70 | if (element.data.id != "none" && element.data.id.length < 8 || element.data.id.length > 9) {
71 | console.log("WRONG ID WRONG")
72 | console.log(element.data.id)
73 | } else {
74 | if (element.data.version == 2) {
75 |
76 | if (logs.lastSB2IDs[element.data.id] == undefined) {
77 | logs.lastSB2IDs[element.data.id] = 1
78 | } else {
79 | logs.lastSB2IDs[element.data.id]++;
80 | }
81 | logs.SB2Load++;
82 | } else if (element.data.version == 3) {
83 |
84 | if (logs.lastSB3IDs[element.data.id] == undefined) {
85 | logs.lastSB3IDs[element.data.id] = 1
86 | } else {
87 | logs.lastSB3IDs[element.data.id]++;
88 | }
89 | logs.SB3Load++;
90 | } else {
91 | logs.landingPageLoad++;
92 | }
93 | }
94 |
95 | });
96 |
97 | }
98 |
99 |
100 | var setCurrentConnections = function (data) {
101 | logs.currentConnections = data;
102 | }
103 |
104 | var logRequest = function (data) {
105 | console.log("log ------")
106 | logs.requests.all.push({ "data": data, "timestamp": new Date() })
107 |
108 |
109 | calculateLogs();
110 |
111 | }
112 |
113 | setInterval(() => {
114 |
115 | fs.writeFileSync(__dirname + "/logs.json", JSON.stringify(logs))
116 | }, 10000);
117 |
118 | module.exports = { setupAdminTools, logRequest, setCurrentConnections }
--------------------------------------------------------------------------------
/backend/admintools/logs.json:
--------------------------------------------------------------------------------
1 | {"requests":{"lastHour":31,"last24Hours":69,"last30Days":102,"all":[{"data":{"id":"none","version":"-1"},"timestamp":"2022-10-23T09:38:43.619Z"},{"data":{"id":"none","version":"-1"},"timestamp":"2022-10-26T21:27:25.277Z"},{"data":{"id":"none","version":"-1"},"timestamp":"2022-11-26T09:47:59.716Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:02:58.494Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:05:18.439Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:11:59.477Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:19:15.394Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:19:36.393Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:20:28.725Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:22:12.665Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-22T18:31:37.044Z"},{"data":{"id":"none","version":"-1"},"timestamp":"2023-05-22T18:32:01.307Z"},{"data":{"id":"34791164","version":"2"},"timestamp":"2023-05-22T18:32:30.719Z"},{"data":{"id":"10128407","version":"2"},"timestamp":"2023-05-29T09:31:33.610Z"},{"data":{"id":"10128407","version":"2"},"timestamp":"2023-05-29T09:31:41.602Z"},{"data":{"id":"16205373","version":"2"},"timestamp":"2023-05-29T11:17:06.930Z"},{"data":{"id":"10128407","version":"2"},"timestamp":"2023-05-29T11:17:24.363Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-05-29T11:18:30.758Z"},{"data":{"id":"none","version":"-1"},"timestamp":"2023-06-02T08:47:30.703Z"},{"data":{"id":"15945630","version":"2"},"timestamp":"2023-06-02T08:47:53.515Z"},{"data":{"id":"16205373","version":"2"},"timestamp":"2023-06-02T08:48:14.001Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:49:08.998Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:53:10.290Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:53:59.443Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:54:27.389Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:57:09.838Z"},{"data":{"id":"802434827","version":"2"},"timestamp":"2023-06-02T08:58:16.507Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-06-02T08:58:25.113Z"},{"data":{"id":"16207935","version":"2"},"timestamp":"2023-06-02T09:00:02.132Z"},{"data":{"id":"802434827","version":"3"},"timestamp":"2023-06-02T09:04:34.499Z"},{"data":{"id":"802434827","version":"3"},"timestamp":"2023-06-02T09:04:51.858Z"},{"data":{"id":"802434827","version":"3"},"timestamp":"2023-06-02T09:06:37.102Z"},{"data":{"id":"802434827","version":"3"},"timestamp":"2023-06-02T09:07:57.897Z"},{"data":{"id":"802434827","version":"3"},"timestamp":"2023-06-02T09:12:13.708Z"},{"data":{"id":"400185398","version":"3"},"timestamp":"2023-06-02T09:13:16.981Z"},{"data":{"id":"278296619","version":"3"},"timestamp":"2023-06-02T09:14:32.901Z"},{"data":{"id":"none","version":"-1"},"timestamp":"2023-06-06T10:23:04.871Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:23:13.323Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:41:44.580Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:43:52.142Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:44:01.762Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:45:10.317Z"},{"data":{"id":"861888652","version":"3"},"timestamp":"2023-06-06T10:46:23.833Z"},{"data":{"id":"235462997","version":"3"},"timestamp":"2023-06-06T11:37:14.786Z"},{"data":{"id":"235462997","version":"3"},"timestamp":"2023-06-06T11:44:06.135Z"},{"data":{"id":"235462997","version":"3"},"timestamp":"2023-06-06T11:45:59.748Z"},{"data":{"id":"235462997","version":"3"},"timestamp":"2023-06-06T11:46:24.098Z"},{"data":{"id":"235462997","version":"3"},"timestamp":"2023-06-06T11:46:57.605Z"},{"data":{"id":"174772777","version":"2"},"timestamp":"2023-06-06T11:55:13.656Z"},{"data":{"id":"168825763","version":"3"},"timestamp":"2023-06-06T12:00:42.041Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:01:25.203Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:01:55.875Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:02:47.056Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:08:06.680Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:08:33.519Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:10:27.853Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:10:43.182Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:11:51.353Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:13:47.229Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:14:54.237Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:16:16.290Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:17:18.294Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:19:43.292Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:20:32.774Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:21:34.348Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:21:54.836Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:22:21.199Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:23:39.806Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:24:21.826Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:25:39.760Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:26:35.834Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:26:55.039Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:27:53.964Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T12:28:25.412Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:07:34.140Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:10:17.329Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:10:34.806Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:11:04.817Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:11:43.043Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:12:21.219Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:12:56.446Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:13:51.536Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:21:08.232Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:21:43.257Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:22:13.128Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:23:56.549Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:24:06.341Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:24:24.164Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:24:44.493Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:25:02.173Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:29:13.903Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:30:40.202Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:33:43.722Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:34:08.452Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:35:31.807Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:36:36.216Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:36:52.290Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:37:45.813Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:38:37.440Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:38:52.765Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:39:24.180Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:41:16.997Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:41:59.016Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:42:10.218Z"},{"data":{"id":"237126447","version":"3"},"timestamp":"2023-06-06T14:42:25.349Z"}]},"currentConnections":1,"lastSB2IDs":{"10128407":3,"15945630":1,"16205373":2,"16207935":11,"34791164":1,"174772777":1,"802434827":6},"lastSB3IDs":{"168825763":1,"235462997":5,"237126447":55,"278296619":1,"400185398":1,"802434827":5,"861888652":6},"landingPageLoad":6,"SB2Load":25,"SB3Load":74}
--------------------------------------------------------------------------------
/backend/cloud.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 | var autoSaveInterval = 100000
4 | var ttlInterval = 1000
5 |
6 | var CLOUDSAVE = {}
7 |
8 | var loadJSON = function (projectID) {
9 |
10 | console.log("[CLOUD] loading JSON for " + projectID);
11 |
12 | try {
13 | var content = fs.readFileSync('./cloudSave/' + projectID + '.json');
14 | CLOUDSAVE[projectID] = JSON.parse(content);
15 | console.log("[CLOUD] DONE loading JSON for " + projectID);
16 | } catch (err) {
17 |
18 | CLOUDSAVE[projectID] = { "vars": {} };
19 | createProjectJSON(projectID, CLOUDSAVE[projectID])
20 | console.log("[CLOUD] DONE loading JSON for " + projectID);
21 | }
22 |
23 | }
24 |
25 | var getReq = function (data) {
26 |
27 | data.sulfCloudVarsChanged = data.sulfCloudVars;
28 |
29 | delete data.sulfCloudVars
30 |
31 |
32 | if (typeof CLOUDSAVE[data.projectID] == 'undefined') {
33 |
34 | loadJSON(data.projectID);
35 |
36 | }
37 |
38 | if (data.sulfCloudVarsChanged == undefined) {
39 | return
40 | }
41 |
42 | if (typeof Object.keys(data.sulfCloudVarsChanged)[0] != 'undefined') {
43 |
44 | console.log("got request")
45 | console.log(data)
46 | for (var i = 0; i < Object.keys(data.sulfCloudVarsChanged).length; i++) {
47 | //console.log(Object.keys(data.sulfCloudVarsChanged)[i]);
48 |
49 | CLOUDSAVE[data.projectID].vars[Object.keys(data.sulfCloudVarsChanged)[i]] = data.sulfCloudVarsChanged[Object.keys(data.sulfCloudVarsChanged)[i]];
50 |
51 | }
52 |
53 | }
54 |
55 | CLOUDSAVE[data.projectID].ttl = 10;
56 | }
57 |
58 |
59 | setInterval(async function () {
60 | console.log("[CLOUD] Auto saving");
61 | Object.keys(CLOUDSAVE).forEach(element => {
62 | saveProjectJSON(element);
63 | });
64 |
65 | }, autoSaveInterval);
66 |
67 | setInterval(function () {
68 | Object.keys(CLOUDSAVE).forEach(element => {
69 | CLOUDSAVE[element].ttl -= 1;
70 | if (CLOUDSAVE[element].ttl == 0) {
71 |
72 | saveProjectJSON(element, true);
73 | console.log("[CLOUD] deleted project JSON from RAM for " + element);
74 | }
75 | });
76 | }, ttlInterval);
77 |
78 | function saveProjectJSON(projectID, delFlag) {
79 | var tempTTL = CLOUDSAVE[projectID].ttl;
80 | delete CLOUDSAVE[projectID].ttl;
81 | fs.writeFile('./cloudSave/' + projectID + '.json', JSON.stringify(CLOUDSAVE[projectID]), function (err) {
82 | if (err) {
83 | return console.log(err);
84 | }
85 | if (delFlag) {
86 | delete CLOUDSAVE[projectID];
87 | } else {
88 | CLOUDSAVE[projectID].ttl = tempTTL;
89 | }
90 | console.log("[CLOUD] project file saved for " + projectID);
91 | });
92 | }
93 |
94 |
95 | function createProjectJSON(projectID, data) {
96 |
97 | fs.writeFile('./cloudSave/' + projectID + '.json', JSON.stringify(data), function (err) {
98 | if (err) {
99 | return console.log(err);
100 | }
101 |
102 | console.log("[CLOUD] Created project file for " + projectID);
103 | });
104 |
105 | }
106 |
107 |
108 |
109 | module.exports = { CLOUDSAVE, getReq };
--------------------------------------------------------------------------------
/backend/cloudSave/237126447.json:
--------------------------------------------------------------------------------
1 | {"vars":{"sulf.c.liste":["sss","awdawdawdad","awdaw","adawd","awd "]}}
--------------------------------------------------------------------------------
/backend/package.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | var JSZip = require("jszip");
3 | var generatePackageFromZip = function (project, settings, callback) {
4 | var zip = new JSZip();
5 | fs.readFile("./SulfurousOffline.zip", function (err, data) {
6 | zip.loadAsync(data)
7 | .then(function (zip) {
8 | //console.log(zip)
9 | // you now have every files contained in the loaded zip
10 |
11 | zip.file("settings.json", JSON.stringify(settings))
12 | zip.file("project.sb2", project); // a promise of "Hello World\n"
13 |
14 | zip.generateAsync({ type: "arraybuffer" }).then(function (base64) {
15 |
16 | callback(base64);
17 | });
18 | });
19 | })
20 | }
21 |
22 | const fetch = require('node-fetch');
23 |
24 |
25 | var getProjectDATA = async function (projectID) {
26 | //console.log(projectJSONBaseURL + projectID)
27 | const req = await fetch('https://api.scratch.mit.edu/projects/' + projectID);
28 | return req.json()
29 | }
30 |
31 | var getProjectJSON = async function (projectID,token) {
32 | //console.log(projectJSONBaseURL + projectID)
33 | const req = await fetch("https://projects.scratch.mit.edu/" + projectID + "?token="+token);
34 | return req.json()
35 | }
36 |
37 | var getAsset = async function (md5) {
38 | //console.log(projectJSONBaseURL + projectID)
39 | const req = await fetch("https://cdn.assets.scratch.mit.edu/internalapi/asset/" + md5 + "/get");
40 | return req
41 | }
42 |
43 | var generatePackageFromID = function (id, settings, callback) {
44 | var zip = new JSZip();
45 | var project = new JSZip();
46 | fs.readFile("./SulfurousOffline.zip", function (err, data) {
47 |
48 | zip.loadAsync(data).then(async function (zip) {
49 | //console.log(zip)
50 | // you now have every files contained in the loaded zip
51 |
52 | let projectDATA = await getProjectDATA(id)
53 | console.log(projectDATA)
54 |
55 |
56 | getProjectJSON(id,projectDATA.project_token).then(async res => {
57 |
58 | // var filemap = parseMap(res.targets);
59 | console.log(id);
60 | let costumeId = 0;
61 | let soundId = 0;
62 | let totalAssets = 0;
63 | let assets = { sounds: [], costumes: [] }
64 |
65 |
66 | if (res.hasOwnProperty("costumes")) {
67 | for (let index = 0; index < res.costumes.length; index++) {
68 | var current = res.costumes[index];
69 |
70 | current.baseLayerID = costumeId;
71 | costumeId++;
72 | totalAssets++;
73 | assets.costumes.push(current);
74 |
75 | }
76 | }
77 | if (res.hasOwnProperty("sounds")) {
78 | for (let index = 0; index < res.sounds.length - 1; index++) {
79 | var current = res.sounds[index];
80 | current.soundID = soundId;
81 | soundId++;
82 | totalAssets++;
83 | assets.sounds.push(current);
84 | }
85 | }
86 |
87 | if (res.hasOwnProperty("children")) {
88 | res.children.forEach(element => {
89 | if (element.hasOwnProperty("costumes")) {
90 | for (var i = 0; i < element.costumes.length; i++) {
91 | var current = element.costumes[i];
92 | current.baseLayerID = costumeId;
93 | costumeId++;
94 | totalAssets++;
95 | assets.costumes.push(current);
96 | }
97 | }
98 | if (element.hasOwnProperty("sounds")) {
99 | for (var i = 0; i < element.sounds.length; i++) {
100 | var current = element.sounds[i];
101 | current.soundID = soundId;
102 | soundId++;
103 | totalAssets++;
104 | assets.sounds.push(current);
105 | }
106 | }
107 |
108 | });
109 |
110 | }
111 |
112 |
113 |
114 | for (let index = 0; index < assets.sounds.length; index++) {
115 | const element = assets.sounds[index];
116 | let data = await getAsset(element.md5)
117 | project.file(element.soundID + "." + element.md5.split(".")[1], data.buffer());
118 | }
119 | for (let index = 0; index < assets.costumes.length; index++) {
120 | const element = assets.costumes[index];
121 | let data = await getAsset(element.baseLayerMD5)
122 | project.file(element.baseLayerID + "." + element.baseLayerMD5.split(".")[1], data.buffer());
123 | }
124 |
125 |
126 |
127 | project.file("project.json", JSON.stringify(res));
128 |
129 |
130 | // fs.writeFileSync("./sb2/" + projectID + "project.json", outJSON)
131 | // newZip.addFile("project.json", Buffer.alloc(outJSON.length, outJSON));
132 |
133 | }).then(() => {
134 |
135 | project.generateAsync({ type: "arraybuffer" }).then(function (base64) {
136 |
137 | //console.log("-------------------------------------------")
138 | //console.log(base64)
139 |
140 | zip.file("settings.json", JSON.stringify(settings))
141 |
142 | zip.file("project.sb2", base64); // a promise of "Hello World\n"
143 | // console.log(project)
144 | zip.generateAsync({ type: "arraybuffer" }).then(function (base64) {
145 | callback(base64);
146 | });
147 | });
148 |
149 |
150 | })
151 |
152 | })
153 | })
154 | }
155 |
156 | module.exports = { generatePackageFromZip, generatePackageFromID }
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sulfurous-backend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "npm i && node server.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/Mittagskogel/Sulfurous.git"
12 | },
13 | "author": "Alexander Pichler",
14 | "license": "ISC",
15 | "bugs": {
16 | "url": "https://github.com/Mittagskogel/Sulfurous/issues"
17 | },
18 | "homepage": "https://github.com/Mittagskogel/Sulfurous#readme",
19 | "dependencies": {
20 | "adm-zip": "^0.4.16",
21 | "axios": "^1.4.0",
22 | "express": "^4.17.1",
23 | "jszip": "^3.5.0",
24 | "node-fetch": "^2.6.0",
25 | "socket.io": "^2.3.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/backend/sb2/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/backend/sb2/.gitkeep
--------------------------------------------------------------------------------
/backend/sb2/168825763project.json:
--------------------------------------------------------------------------------
1 | {"targets":[{"isStage":true,"name":"Stage","variables":{"{wQSVFJ;-}_(VQqvyvBw-x-":["x","-190"],"{wQSVFJ;-}_(VQqvyvBw-y-":["y",-225],"{wQSVFJ;-}_(VQqvyvBw-c-":["c",210],"{wQSVFJ;-}_(VQqvyvBw-i-":["i",0]},"lists":{},"broadcasts":{},"blocks":{},"comments":{},"currentCostume":0,"costumes":[{"assetId":"797b03bdb8cf6ccfc30c0692d533d998","name":"backdrop1","bitmapResolution":2,"md5ext":"797b03bdb8cf6ccfc30c0692d533d998.png","dataFormat":"png","rotationCenterX":480,"rotationCenterY":360}],"sounds":[{"assetId":"83a9787d4cb6f3b7632b4ddfebf74367","name":"pop","dataFormat":"wav","format":"","rate":48000,"sampleCount":1123,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"off","textToSpeechLanguage":null},{"isStage":false,"name":"Sprite1","variables":{},"lists":{},"broadcasts":{},"blocks":{"rG]J%Yds`O_.63h~+R0t":{"opcode":"control_start_as_clone","next":";x~K/LC^RPFJuh+Uhyh[","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":657,"y":246},";x~K/LC^RPFJuh+Uhyh[":{"opcode":"looks_setsizeto","next":"T57jyys]]#}5ZsCi@;-h","parent":"rG]J%Yds`O_.63h~+R0t","inputs":{"SIZE":[1,[4,"80"]]},"fields":{},"shadow":false,"topLevel":false},"T57jyys]]#}5ZsCi@;-h":{"opcode":"motion_gotoxy","next":"5|l+n*%LW*:%:z#/*/{3","parent":";x~K/LC^RPFJuh+Uhyh[","inputs":{"X":[3,[12,"x","{wQSVFJ;-}_(VQqvyvBw-x-"],[4,"10"]],"Y":[3,[12,"y","{wQSVFJ;-}_(VQqvyvBw-y-"],[4,"10"]]},"fields":{},"shadow":false,"topLevel":false},"5|l+n*%LW*:%:z#/*/{3":{"opcode":"looks_seteffectto","next":"yY?Q1JmUjMY*bjp_7[3G","parent":"T57jyys]]#}5ZsCi@;-h","inputs":{"VALUE":[3,[12,"c","{wQSVFJ;-}_(VQqvyvBw-c-"],[4,"10"]]},"fields":{"EFFECT":["color",null]},"shadow":false,"topLevel":false},"yY?Q1JmUjMY*bjp_7[3G":{"opcode":"data_changevariableby","next":"|}rPW*eFpYSSpWeAkyB,","parent":"5|l+n*%LW*:%:z#/*/{3","inputs":{"VALUE":[1,[4,"10"]]},"fields":{"VARIABLE":["c","{wQSVFJ;-}_(VQqvyvBw-c-"]},"shadow":false,"topLevel":false},"|}rPW*eFpYSSpWeAkyB,":{"opcode":"data_changevariableby","next":"ArD];;-IPj.3Kf7Gxrx}","parent":"yY?Q1JmUjMY*bjp_7[3G","inputs":{"VALUE":[1,[4,"80"]]},"fields":{"VARIABLE":["x","{wQSVFJ;-}_(VQqvyvBw-x-"]},"shadow":false,"topLevel":false},"ArD];;-IPj.3Kf7Gxrx}":{"opcode":"data_changevariableby","next":"lS~KCI#X#zUhbf(7A-Q;","parent":"|}rPW*eFpYSSpWeAkyB,","inputs":{"VALUE":[1,[4,"1"]]},"fields":{"VARIABLE":["i","{wQSVFJ;-}_(VQqvyvBw-i-"]},"shadow":false,"topLevel":false},"lS~KCI#X#zUhbf(7A-Q;":{"opcode":"control_if","next":null,"parent":"ArD];;-IPj.3Kf7Gxrx}","inputs":{"CONDITION":[2,"umpfA{L9e9-xxYcmutvm"],"SUBSTACK":[2,"or7!fqKC!jMRP`TLig,s"]},"fields":{},"shadow":false,"topLevel":false},"umpfA{L9e9-xxYcmutvm":{"opcode":"operator_equals","next":null,"parent":"lS~KCI#X#zUhbf(7A-Q;","inputs":{"OPERAND1":[3,[12,"i","{wQSVFJ;-}_(VQqvyvBw-i-"],[10,""]],"OPERAND2":[1,[10,"6"]]},"fields":{},"shadow":false,"topLevel":false},"or7!fqKC!jMRP`TLig,s":{"opcode":"data_setvariableto","next":"6cstwa9S!Z23%g|aG~wj","parent":"lS~KCI#X#zUhbf(7A-Q;","inputs":{"VALUE":[1,[10,"0"]]},"fields":{"VARIABLE":["i","{wQSVFJ;-}_(VQqvyvBw-i-"]},"shadow":false,"topLevel":false},"6cstwa9S!Z23%g|aG~wj":{"opcode":"data_setvariableto","next":".+|OC!8HU1voxb*2-]QB","parent":"or7!fqKC!jMRP`TLig,s","inputs":{"VALUE":[1,[10,"-190"]]},"fields":{"VARIABLE":["x","{wQSVFJ;-}_(VQqvyvBw-x-"]},"shadow":false,"topLevel":false},".+|OC!8HU1voxb*2-]QB":{"opcode":"data_setvariableto","next":null,"parent":"6cstwa9S!Z23%g|aG~wj","inputs":{"VALUE":[3,";%[D,O7zQL`s??7MuAp2",[10,""]]},"fields":{"VARIABLE":["y","{wQSVFJ;-}_(VQqvyvBw-y-"]},"shadow":false,"topLevel":false},";%[D,O7zQL`s??7MuAp2":{"opcode":"operator_subtract","next":null,"parent":".+|OC!8HU1voxb*2-]QB","inputs":{"NUM1":[3,[12,"y","{wQSVFJ;-}_(VQqvyvBw-y-"],[4,"10"]],"NUM2":[1,[4,"90"]]},"fields":{},"shadow":false,"topLevel":false},"rO@J5sCw8}duwcYUQlD2":{"opcode":"event_whenflagclicked","next":"`En:-Y|D@XlyFKTHiEx)","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":187,"y":290},"`En:-Y|D@XlyFKTHiEx)":{"opcode":"looks_setsizeto","next":"gym!UCxYOg_MhuF2Cp?q","parent":"rO@J5sCw8}duwcYUQlD2","inputs":{"SIZE":[1,[4,"80"]]},"fields":{},"shadow":false,"topLevel":false},"gym!UCxYOg_MhuF2Cp?q":{"opcode":"data_setvariableto","next":"I;ta2=fx?|@ZocAtLw)H","parent":"`En:-Y|D@XlyFKTHiEx)","inputs":{"VALUE":[1,[10,"-195"]]},"fields":{"VARIABLE":["x","{wQSVFJ;-}_(VQqvyvBw-x-"]},"shadow":false,"topLevel":false},"I;ta2=fx?|@ZocAtLw)H":{"opcode":"data_setvariableto","next":"x:T.dt,[?E^1~GLr4~Tl","parent":"gym!UCxYOg_MhuF2Cp?q","inputs":{"VALUE":[1,[10,"135"]]},"fields":{"VARIABLE":["y","{wQSVFJ;-}_(VQqvyvBw-y-"]},"shadow":false,"topLevel":false},"x:T.dt,[?E^1~GLr4~Tl":{"opcode":"motion_gotoxy","next":"TMScQo`|IGe{T@]IYa}P","parent":"I;ta2=fx?|@ZocAtLw)H","inputs":{"X":[3,[12,"x","{wQSVFJ;-}_(VQqvyvBw-x-"],[4,"10"]],"Y":[3,[12,"y","{wQSVFJ;-}_(VQqvyvBw-y-"],[4,"10"]]},"fields":{},"shadow":false,"topLevel":false},"TMScQo`|IGe{T@]IYa}P":{"opcode":"data_setvariableto","next":"Ua`2W!KVCsaVQzrYvO{8","parent":"x:T.dt,[?E^1~GLr4~Tl","inputs":{"VALUE":[1,[10,"-110"]]},"fields":{"VARIABLE":["x","{wQSVFJ;-}_(VQqvyvBw-x-"]},"shadow":false,"topLevel":false},"Ua`2W!KVCsaVQzrYvO{8":{"opcode":"data_setvariableto","next":"h0[Cyb2FIAVYQP~pQy;/","parent":"TMScQo`|IGe{T@]IYa}P","inputs":{"VALUE":[1,[10,"10"]]},"fields":{"VARIABLE":["c","{wQSVFJ;-}_(VQqvyvBw-c-"]},"shadow":false,"topLevel":false},"h0[Cyb2FIAVYQP~pQy;/":{"opcode":"control_repeat","next":null,"parent":"Ua`2W!KVCsaVQzrYvO{8","inputs":{"TIMES":[1,[6,"20"]],"SUBSTACK":[2,"(FZ7uW#!=qrLAy)n(:cX"]},"fields":{},"shadow":false,"topLevel":false},"(FZ7uW#!=qrLAy)n(:cX":{"opcode":"control_create_clone_of","next":null,"parent":"h0[Cyb2FIAVYQP~pQy;/","inputs":{"CLONE_OPTION":[1,"@RE`NUl1=A`ZE{s``V/2"]},"fields":{},"shadow":false,"topLevel":false},"@RE`NUl1=A`ZE{s``V/2":{"opcode":"control_create_clone_of_menu","next":null,"parent":"(FZ7uW#!=qrLAy)n(:cX","inputs":{},"fields":{"CLONE_OPTION":["_myself_",null]},"shadow":true,"topLevel":false},"^cz3L|Ol!+Q!sksfF#1q":{"opcode":"event_whenflagclicked","next":"{+2R[8Iy)A8Rt2!|nzzl","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":1481,"y":746},"{+2R[8Iy)A8Rt2!|nzzl":{"opcode":"looks_switchcostumeto","next":";4sqpeUiZWt;v:e)IKKA","parent":"^cz3L|Ol!+Q!sksfF#1q","inputs":{"COSTUME":[1,"VdVMlq@Z]8a1_ChBX?KW"]},"fields":{},"shadow":false,"topLevel":false},"VdVMlq@Z]8a1_ChBX?KW":{"opcode":"looks_costume","next":null,"parent":"{+2R[8Iy)A8Rt2!|nzzl","inputs":{},"fields":{"COSTUME":["costume1",null]},"shadow":true,"topLevel":false},";4sqpeUiZWt;v:e)IKKA":{"opcode":"control_wait","next":"EeE6pW%.k3a29D)y^YAe","parent":"{+2R[8Iy)A8Rt2!|nzzl","inputs":{"DURATION":[1,[5,"5"]]},"fields":{},"shadow":false,"topLevel":false},"EeE6pW%.k3a29D)y^YAe":{"opcode":"looks_switchcostumeto","next":null,"parent":";4sqpeUiZWt;v:e)IKKA","inputs":{"COSTUME":[1,"@iKzM%u7`b1aG6c;+9yH"]},"fields":{},"shadow":false,"topLevel":false},"@iKzM%u7`b1aG6c;+9yH":{"opcode":"looks_costume","next":null,"parent":"EeE6pW%.k3a29D)y^YAe","inputs":{},"fields":{"COSTUME":["costume2",null]},"shadow":true,"topLevel":false}},"comments":{},"currentCostume":1,"costumes":[{"assetId":"bcaaa8547a07cfe572c0967ba829e99d","name":"costume1","bitmapResolution":1,"md5ext":"bcaaa8547a07cfe572c0967ba829e99d.svg","dataFormat":"svg","rotationCenterX":47,"rotationCenterY":55},{"assetId":"11d6c5fbd91e433a1b85a00fd9dd43b6","name":"costume2","bitmapResolution":1,"md5ext":"11d6c5fbd91e433a1b85a00fd9dd43b6.svg","dataFormat":"svg","rotationCenterX":47,"rotationCenterY":55}],"sounds":[{"assetId":"83c36d806dc92327b9e7049a565c6bff","name":"meow","dataFormat":"wav","format":"","rate":48000,"sampleCount":40681,"md5ext":"83c36d806dc92327b9e7049a565c6bff.wav"}],"volume":100,"layerOrder":1,"visible":true,"x":-78,"y":-26,"size":80,"direction":90,"draggable":false,"rotationStyle":"all around"}],"monitors":[{"id":"{wQSVFJ;-}_(VQqvyvBw-x-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"x"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"{wQSVFJ;-}_(VQqvyvBw-y-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"y"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":32,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"{wQSVFJ;-}_(VQqvyvBw-c-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"c"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":59,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"{wQSVFJ;-}_(VQqvyvBw-i-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"i"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":86,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true}],"extensions":[],"meta":{"semver":"3.0.0","vm":"0.2.0-prerelease.20200622143012","agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"}}
--------------------------------------------------------------------------------
/backend/sb2/235462997project.json:
--------------------------------------------------------------------------------
1 | {"targets":[{"isStage":true,"name":"Stage","variables":{"Gi)RmvR(uaikyu({2_T.-sulf.time-":["sulf.time",0],"Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-":["sulf.resolutionX",0],"Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-":["sulf.resolutionY",0],"Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-":["sulf.hasTouchEvents",0],"Gi)RmvR(uaikyu({2_T.-sulf.version-":["sulf.version",0],"Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-":["sulf.p.username","fritz"],"Gi)RmvR(uaikyu({2_T.-test-":["test",""],"Gi)RmvR(uaikyu({2_T.-sulf.p.plackbeard-":["sulf.p.plackbeard",0],"Gi)RmvR(uaikyu({2_T.-Space-":["Space",0],"Gi)RmvR(uaikyu({2_T.-silf.p.-":["silf.p.",0]},"lists":{},"broadcasts":{},"blocks":{},"comments":{},"currentCostume":0,"costumes":[{"name":"backdrop1","bitmapResolution":2,"dataFormat":"png","assetId":"797b03bdb8cf6ccfc30c0692d533d998","md5ext":"797b03bdb8cf6ccfc30c0692d533d998.png","rotationCenterX":480,"rotationCenterY":360}],"sounds":[{"name":"pop","assetId":"83a9787d4cb6f3b7632b4ddfebf74367","dataFormat":"wav","format":"","rate":48000,"sampleCount":1123,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"off","textToSpeechLanguage":null},{"isStage":false,"name":"Sprite1","variables":{},"lists":{},"broadcasts":{},"blocks":{"?{RbpKF)P`+-uFJVD3E+":{"opcode":"event_whenkeypressed","next":"av=nwti+2clho:nUIQDD","parent":null,"inputs":{},"fields":{"KEY_OPTION":["space"]},"shadow":false,"topLevel":true,"x":15,"y":22},"av=nwti+2clho:nUIQDD":{"opcode":"data_showvariable","next":"4.q!tXy0O0BKkoHEJ?ed","parent":"?{RbpKF)P`+-uFJVD3E+","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"4.q!tXy0O0BKkoHEJ?ed":{"opcode":"data_hidevariable","next":"yElCIscy-P!rW/rnG1FD","parent":"av=nwti+2clho:nUIQDD","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"yElCIscy-P!rW/rnG1FD":{"opcode":"data_hidevariable","next":"|JGVIJl4j0:[tZCTIy?+","parent":"4.q!tXy0O0BKkoHEJ?ed","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"|JGVIJl4j0:[tZCTIy?+":{"opcode":"data_hidevariable","next":"r0IL/,4{V/JE2%n7-pTU","parent":"yElCIscy-P!rW/rnG1FD","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"r0IL/,4{V/JE2%n7-pTU":{"opcode":"data_hidevariable","next":"gb|3GS1_+1)_HBLPV.-2","parent":"|JGVIJl4j0:[tZCTIy?+","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"gb|3GS1_+1)_HBLPV.-2":{"opcode":"data_hidevariable","next":null,"parent":"r0IL/,4{V/JE2%n7-pTU","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"l/UC^,A)JbE4!OpbneOP":{"opcode":"event_whenkeypressed","next":"hLERj3WnvfLGnODX@:rx","parent":null,"inputs":{},"fields":{"KEY_OPTION":["right arrow"]},"shadow":false,"topLevel":true,"x":803,"y":550},"hLERj3WnvfLGnODX@:rx":{"opcode":"data_showvariable","next":"9!0,|ID]xUb6=|Q66@r^","parent":"l/UC^,A)JbE4!OpbneOP","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"9!0,|ID]xUb6=|Q66@r^":{"opcode":"data_hidevariable","next":"cV(dN?_521y*xZoP)Ixv","parent":"hLERj3WnvfLGnODX@:rx","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"cV(dN?_521y*xZoP)Ixv":{"opcode":"data_hidevariable","next":"c-kpnzp[7d(cAHl`b#Ia","parent":"9!0,|ID]xUb6=|Q66@r^","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"c-kpnzp[7d(cAHl`b#Ia":{"opcode":"data_hidevariable","next":"hm,K5uQf.j]|1L%#}A.X","parent":"cV(dN?_521y*xZoP)Ixv","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"hm,K5uQf.j]|1L%#}A.X":{"opcode":"data_hidevariable","next":"u![4^_!K)Xqsi9d-mCno","parent":"c-kpnzp[7d(cAHl`b#Ia","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"u![4^_!K)Xqsi9d-mCno":{"opcode":"data_hidevariable","next":null,"parent":"hm,K5uQf.j]|1L%#}A.X","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"nmIwW~4[m~55S-KBE1vy":{"opcode":"event_whenkeypressed","next":"!W._]wfh0q_4yRgD6^b=","parent":null,"inputs":{},"fields":{"KEY_OPTION":["down arrow"]},"shadow":false,"topLevel":true,"x":781,"y":1050},"!W._]wfh0q_4yRgD6^b=":{"opcode":"data_showvariable","next":"yMfNK:`~V{Pqfz5Pxp{v","parent":"nmIwW~4[m~55S-KBE1vy","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"yMfNK:`~V{Pqfz5Pxp{v":{"opcode":"data_hidevariable","next":"vhE5Td0VcDeAD+q5yvfG","parent":"!W._]wfh0q_4yRgD6^b=","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"vhE5Td0VcDeAD+q5yvfG":{"opcode":"data_hidevariable","next":":+%lyoDlY*yY@T49sF}j","parent":"yMfNK:`~V{Pqfz5Pxp{v","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},":+%lyoDlY*yY@T49sF}j":{"opcode":"data_hidevariable","next":"?XAeoJ[b.`x=kGC:cC(l","parent":"vhE5Td0VcDeAD+q5yvfG","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"?XAeoJ[b.`x=kGC:cC(l":{"opcode":"data_hidevariable","next":"=T~Y?(y#xUV;0?/*X%hm","parent":":+%lyoDlY*yY@T49sF}j","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"=T~Y?(y#xUV;0?/*X%hm":{"opcode":"data_hidevariable","next":null,"parent":"?XAeoJ[b.`x=kGC:cC(l","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"ZFv]sktSwFeN-@APDw9E":{"opcode":"event_whenkeypressed","next":"1Z,)#jocqq]1PE}#`w(4","parent":null,"inputs":{},"fields":{"KEY_OPTION":["up arrow"]},"shadow":false,"topLevel":true,"x":763,"y":23},"1Z,)#jocqq]1PE}#`w(4":{"opcode":"data_showvariable","next":"J[s%e}pbTQ~QP9.76v8I","parent":"ZFv]sktSwFeN-@APDw9E","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"J[s%e}pbTQ~QP9.76v8I":{"opcode":"data_hidevariable","next":"Z,N-y,3ule/lxS?cNB3h","parent":"1Z,)#jocqq]1PE}#`w(4","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"Z,N-y,3ule/lxS?cNB3h":{"opcode":"data_hidevariable","next":".-[E9(vH+~nS+ZN.Hj}d","parent":"J[s%e}pbTQ~QP9.76v8I","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},".-[E9(vH+~nS+ZN.Hj}d":{"opcode":"data_hidevariable","next":"OgMcH.!6Tb8x,DYb,PGw","parent":"Z,N-y,3ule/lxS?cNB3h","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"OgMcH.!6Tb8x,DYb,PGw":{"opcode":"data_hidevariable","next":"nLz:4IV7t1C-W68~9e~E","parent":".-[E9(vH+~nS+ZN.Hj}d","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"nLz:4IV7t1C-W68~9e~E":{"opcode":"data_hidevariable","next":null,"parent":"OgMcH.!6Tb8x,DYb,PGw","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"j9!GC:(40?XRT_0Qo^8+":{"opcode":"event_whenthisspriteclicked","next":"F0YsLE_H)yPrRs=DOy6%","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":34,"y":991},"F0YsLE_H)yPrRs=DOy6%":{"opcode":"data_showvariable","next":"%#Y~g=h~VNg]=dGIkPM{","parent":"j9!GC:(40?XRT_0Qo^8+","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"%#Y~g=h~VNg]=dGIkPM{":{"opcode":"data_hidevariable","next":"Ap[]7)tlL49{R3%Qh,Re","parent":"F0YsLE_H)yPrRs=DOy6%","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false,"comment":"[)MDr^+uyyFI7~O`KH4S"},"Ap[]7)tlL49{R3%Qh,Re":{"opcode":"data_hidevariable","next":"VUz9Z{@kV%`TSrDwMJ99","parent":"%#Y~g=h~VNg]=dGIkPM{","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"VUz9Z{@kV%`TSrDwMJ99":{"opcode":"data_hidevariable","next":"8e]llBQq=lq%34SaBMY}","parent":"Ap[]7)tlL49{R3%Qh,Re","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"8e]llBQq=lq%34SaBMY}":{"opcode":"data_hidevariable","next":"nZR=x%?~G)HT2Au3/#JJ","parent":"VUz9Z{@kV%`TSrDwMJ99","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"nZR=x%?~G)HT2Au3/#JJ":{"opcode":"data_hidevariable","next":null,"parent":"8e]llBQq=lq%34SaBMY}","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"9`!:Lppt,TXa;#XZ!^(#":{"opcode":"event_whenkeypressed","next":"4aLN~M@`do[}WVOnGN06","parent":null,"inputs":{},"fields":{"KEY_OPTION":["left arrow"]},"shadow":false,"topLevel":true,"x":7,"y":516},"4aLN~M@`do[}WVOnGN06":{"opcode":"data_showvariable","next":"gij1I3b~U5jMIzfGb;+N","parent":"9`!:Lppt,TXa;#XZ!^(#","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"gij1I3b~U5jMIzfGb;+N":{"opcode":"data_hidevariable","next":"l*w(8l5/HLx#k(3n5hrc","parent":"4aLN~M@`do[}WVOnGN06","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"l*w(8l5/HLx#k(3n5hrc":{"opcode":"data_hidevariable","next":"]So4Dtwo*|@ON2w+_e4t","parent":"gij1I3b~U5jMIzfGb;+N","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"]So4Dtwo*|@ON2w+_e4t":{"opcode":"data_hidevariable","next":"RNf.X]pX.AgLw3RR]5P!","parent":"l*w(8l5/HLx#k(3n5hrc","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false,"comment":"0s-Itw3Yl57zvEolVsFe"},"RNf.X]pX.AgLw3RR]5P!":{"opcode":"data_hidevariable","next":"o^uw|4LcINE^7lDOPlE5","parent":"]So4Dtwo*|@ON2w+_e4t","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"o^uw|4LcINE^7lDOPlE5":{"opcode":"data_hidevariable","next":null,"parent":"RNf.X]pX.AgLw3RR]5P!","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"T_5cEK(+7gty:[K`l8,.":{"opcode":"event_whenflagclicked","next":"#w.JNhW^;2JN(ly.}]A.","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":1454,"y":25},"#w.JNhW^;2JN(ly.}]A.":{"opcode":"data_hidevariable","next":"?#,knBqwsgna-8z((3Ht","parent":"T_5cEK(+7gty:[K`l8,.","inputs":{},"fields":{"VARIABLE":["sulf.time","Gi)RmvR(uaikyu({2_T.-sulf.time-"]},"shadow":false,"topLevel":false},"?#,knBqwsgna-8z((3Ht":{"opcode":"data_hidevariable","next":"TUa;T`=]`}F?#CZ|krMT","parent":"#w.JNhW^;2JN(ly.}]A.","inputs":{},"fields":{"VARIABLE":["sulf.resolutionX","Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-"]},"shadow":false,"topLevel":false},"TUa;T`=]`}F?#CZ|krMT":{"opcode":"data_hidevariable","next":"QrG/k;Cl+BEp%MPFzwZx","parent":"?#,knBqwsgna-8z((3Ht","inputs":{},"fields":{"VARIABLE":["sulf.resolutionY","Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-"]},"shadow":false,"topLevel":false},"QrG/k;Cl+BEp%MPFzwZx":{"opcode":"data_hidevariable","next":"R(!@@0^EvLe;h[}K6/T3","parent":"TUa;T`=]`}F?#CZ|krMT","inputs":{},"fields":{"VARIABLE":["sulf.hasTouchEvents","Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-"]},"shadow":false,"topLevel":false},"R(!@@0^EvLe;h[}K6/T3":{"opcode":"data_hidevariable","next":"ren#]:Hv^dS]y%AOyFst","parent":"QrG/k;Cl+BEp%MPFzwZx","inputs":{},"fields":{"VARIABLE":["sulf.version","Gi)RmvR(uaikyu({2_T.-sulf.version-"]},"shadow":false,"topLevel":false},"ren#]:Hv^dS]y%AOyFst":{"opcode":"data_hidevariable","next":null,"parent":"R(!@@0^EvLe;h[}K6/T3","inputs":{},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":false},"5un-)1#y5`r.KzVJY8}[":{"opcode":"data_setvariableto","next":null,"parent":null,"inputs":{"VALUE":[1,[10,"fritz"]]},"fields":{"VARIABLE":["sulf.p.username","Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-"]},"shadow":false,"topLevel":true,"x":510,"y":586}},"comments":{"[)MDr^+uyyFI7~O`KH4S":{"blockId":"%#Y~g=h~VNg]=dGIkPM{","x":428.03703703703707,"y":1176.4814814814813,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn die Leertaste gedrückt wird wird die Variable sulf.p.peterpan angezeigt.\r\rENGLISH: If Space is pressed the sulf.p.peterpan variable is shown."},"6g.kZ?pls85v`BLPe8nh":{"blockId":null,"x":1168.8000000000002,"y":29.92,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn Pfeil nach oben gedrückt wird wird die Variable sulf.time angezeigt.\r\rENGLISH: If the Arrow up key is pressed the sulf.time variable is shown."},"fl_+KeK^5+vY!2^6N3z2":{"blockId":null,"x":1185.6750000000002,"y":544.72,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn Pfeil nach rechts Taste gedrückt wird wird die Variable sulf.resolutionY angezeigt.\r\rENGLISH: If the arrow right key is pressed the sulf.resolutionY is shown."},"X=s+^E|(GsS^1Dnf9iqn":{"blockId":null,"x":1186.35,"y":1063.3700000000001,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn die Pfeil nach unten Taste gedrückt wird, wird die sulf.hasTouchEvents angezeigt.\r\rENGLISH: If the arrow down key is pressed, the sulf.hasTouchEvents variable is shown."},"GKhrbmAi,zH,.f{dGCpy":{"blockId":null,"x":451.57500000000005,"y":41.800000000000004,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn die Pfeil nach links Taste gedrückt wird wird die Variable sulf.resolutionX angezeigt.\r\rENGLISH: If the arrow left key is pressed the sulf.resolutionX variable is shown."},"0s-Itw3Yl57zvEolVsFe":{"blockId":"]So4Dtwo*|@ON2w+_e4t","x":378.33333333333337,"y":671.5555555555555,"width":229.5,"height":446.6,"minimized":false,"text":"DEUTSCH: Wenn die Figur angeklickt wird, wird ide sulf.version Variable angezeigt.\r\rENGLISH: When the figure is clicked, the sulf.version variable is shown."}},"currentCostume":1,"costumes":[{"name":"costume1","bitmapResolution":1,"dataFormat":"svg","assetId":"bcaaa8547a07cfe572c0967ba829e99d","md5ext":"bcaaa8547a07cfe572c0967ba829e99d.svg","rotationCenterX":47,"rotationCenterY":55},{"name":"costume2","bitmapResolution":1,"dataFormat":"svg","assetId":"11d6c5fbd91e433a1b85a00fd9dd43b6","md5ext":"11d6c5fbd91e433a1b85a00fd9dd43b6.svg","rotationCenterX":47,"rotationCenterY":55}],"sounds":[{"name":"meow","assetId":"83c36d806dc92327b9e7049a565c6bff","dataFormat":"wav","format":"","rate":48000,"sampleCount":40681,"md5ext":"83c36d806dc92327b9e7049a565c6bff.wav"}],"volume":100,"layerOrder":1,"visible":true,"x":4,"y":-22,"size":100,"direction":90,"draggable":false,"rotationStyle":"all around"}],"monitors":[{"id":"Gi)RmvR(uaikyu({2_T.-test-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"test"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":5,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.time-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.time"},"spriteName":null,"value":"","width":0,"height":0,"x":165.3,"y":51.45,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.hasTouchEvents-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.hasTouchEvents"},"spriteName":null,"value":"","width":0,"height":0,"x":130.95,"y":48.85,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.resolutionX-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.resolutionX"},"spriteName":null,"value":0,"width":0,"height":0,"x":141.7,"y":46.45,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.version-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.version"},"spriteName":null,"value":"","width":0,"height":0,"x":152,"y":51.4,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.resolutionY-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.resolutionY"},"spriteName":null,"value":"","width":0,"height":0,"x":145.1,"y":50.4,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.p.plackbeard-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.p.plackbeard"},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":75,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-sulf.p.peterpan-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"sulf.p.username"},"spriteName":null,"value":"fritz","width":0,"height":0,"x":141.9,"y":46.9,"visible":true,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-Space-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"Space"},"spriteName":null,"value":0,"width":0,"height":0,"x":5,"y":32,"visible":true,"sliderMin":0,"sliderMax":100,"isDiscrete":true},{"id":"Gi)RmvR(uaikyu({2_T.-silf.p.-","mode":"default","opcode":"data_variable","params":{"VARIABLE":"silf.p."},"spriteName":null,"value":"","width":0,"height":0,"x":5,"y":102,"visible":false,"sliderMin":0,"sliderMax":100,"isDiscrete":true}],"extensions":[],"meta":{"semver":"3.0.0","vm":"1.5.68","agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"}}
--------------------------------------------------------------------------------
/backend/sb2/237126447project.json:
--------------------------------------------------------------------------------
1 | {"targets":[{"isStage":true,"name":"Stage","variables":{},"lists":{".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list":["sulf.c.liste",["sss"]],".:u*s9D5|y9-7h1rjuQk-test.liste-list":["test.liste",["hi",""]]},"broadcasts":{},"blocks":{},"comments":{},"currentCostume":0,"costumes":[{"assetId":"797b03bdb8cf6ccfc30c0692d533d998","name":"backdrop1","bitmapResolution":2,"md5ext":"797b03bdb8cf6ccfc30c0692d533d998.png","dataFormat":"png","rotationCenterX":480,"rotationCenterY":360}],"sounds":[{"assetId":"83a9787d4cb6f3b7632b4ddfebf74367","name":"pop","dataFormat":"wav","format":"","rate":48000,"sampleCount":1123,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"off","textToSpeechLanguage":null},{"isStage":false,"name":"Sprite1","variables":{},"lists":{},"broadcasts":{},"blocks":{"{nVu}t(WHB.IMp_W5bFN":{"opcode":"event_whenflagclicked","next":"w7Bg1iTyeN@b+11UOU1T","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":495,"y":407},"w7Bg1iTyeN@b+11UOU1T":{"opcode":"data_showlist","next":"lD**(23E|u9A};|I65-o","parent":"{nVu}t(WHB.IMp_W5bFN","inputs":{},"fields":{"LIST":["sulf.c.liste",".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list"]},"shadow":false,"topLevel":false},"lD**(23E|u9A};|I65-o":{"opcode":"data_showlist","next":null,"parent":"w7Bg1iTyeN@b+11UOU1T","inputs":{},"fields":{"LIST":["test.liste",".:u*s9D5|y9-7h1rjuQk-test.liste-list"]},"shadow":false,"topLevel":false},"A~(U`Kw}754h3jf_3Ot4":{"opcode":"event_whenkeypressed","next":"sm:64.u~E(a-KF]6^oBR","parent":null,"inputs":{},"fields":{"KEY_OPTION":["space"]},"shadow":false,"topLevel":true,"x":820,"y":556},"sm:64.u~E(a-KF]6^oBR":{"opcode":"sensing_askandwait","next":"PWGN/{q/9I!xu4![g34K","parent":"A~(U`Kw}754h3jf_3Ot4","inputs":{"QUESTION":[1,[10,"next item in list"]]},"fields":{},"shadow":false,"topLevel":false},"PWGN/{q/9I!xu4![g34K":{"opcode":"data_addtolist","next":"5=Za`E@(T%j|P(Ze2[Wv","parent":"sm:64.u~E(a-KF]6^oBR","inputs":{"ITEM":[3,",8bt;8=CA]ovX:h~):wF",[10,""]]},"fields":{"LIST":["sulf.c.liste",".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list"]},"shadow":false,"topLevel":false},",8bt;8=CA]ovX:h~):wF":{"opcode":"sensing_answer","next":null,"parent":"PWGN/{q/9I!xu4![g34K","inputs":{},"fields":{},"shadow":false,"topLevel":false},"5=Za`E@(T%j|P(Ze2[Wv":{"opcode":"looks_sayforsecs","next":"WT9MpU{X.`Sc/j:y^|Sf","parent":"PWGN/{q/9I!xu4![g34K","inputs":{"MESSAGE":[3,"z_ie%^H8T?oN9)MwZiHD",[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"z_ie%^H8T?oN9)MwZiHD":{"opcode":"data_itemoflist","next":null,"parent":"5=Za`E@(T%j|P(Ze2[Wv","inputs":{"INDEX":[1,[7,1]]},"fields":{"LIST":["sulf.c.liste",".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list"]},"shadow":false,"topLevel":false},"WT9MpU{X.`Sc/j:y^|Sf":{"opcode":"control_wait","next":"t.IZ?QA1-c?UOw:G6bxr","parent":"5=Za`E@(T%j|P(Ze2[Wv","inputs":{"DURATION":[1,[5,2]]},"fields":{},"shadow":false,"topLevel":false},"t.IZ?QA1-c?UOw:G6bxr":{"opcode":"looks_sayforsecs","next":"T((!CtV_+6Nbp?cW)CAO","parent":"WT9MpU{X.`Sc/j:y^|Sf","inputs":{"MESSAGE":[3,[13,"sulf.c.liste",".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list"],[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"T((!CtV_+6Nbp?cW)CAO":{"opcode":"control_wait","next":"tl[blZDBgS6Dl_g{E[?U","parent":"t.IZ?QA1-c?UOw:G6bxr","inputs":{"DURATION":[1,[5,2]]},"fields":{},"shadow":false,"topLevel":false},"tl[blZDBgS6Dl_g{E[?U":{"opcode":"looks_sayforsecs","next":null,"parent":"T((!CtV_+6Nbp?cW)CAO","inputs":{"MESSAGE":[3,"H3hS=MuP9e@sws+}6m^x",[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"H3hS=MuP9e@sws+}6m^x":{"opcode":"data_lengthoflist","next":null,"parent":"tl[blZDBgS6Dl_g{E[?U","inputs":{},"fields":{"LIST":["sulf.c.liste",".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list"]},"shadow":false,"topLevel":false},"8lTYe)F?`,Goza.neDi,":{"opcode":"event_whenkeypressed","next":"|@he/W_ocP^X{vnXlye~","parent":null,"inputs":{},"fields":{"KEY_OPTION":["up arrow"]},"shadow":false,"topLevel":true,"x":289,"y":662},"|@he/W_ocP^X{vnXlye~":{"opcode":"sensing_askandwait","next":"uE)=Q6)/HB`|kDV)KtW}","parent":"8lTYe)F?`,Goza.neDi,","inputs":{"QUESTION":[1,[10,"next item in list"]]},"fields":{},"shadow":false,"topLevel":false},"uE)=Q6)/HB`|kDV)KtW}":{"opcode":"data_addtolist","next":"]ZFsHjH@q~SrsR6;Qg=[","parent":"|@he/W_ocP^X{vnXlye~","inputs":{"ITEM":[3,"o/A=ybvy`Mhc/k{(-O;|",[10,""]]},"fields":{"LIST":["test.liste",".:u*s9D5|y9-7h1rjuQk-test.liste-list"]},"shadow":false,"topLevel":false},"o/A=ybvy`Mhc/k{(-O;|":{"opcode":"sensing_answer","next":null,"parent":"uE)=Q6)/HB`|kDV)KtW}","inputs":{},"fields":{},"shadow":false,"topLevel":false},"]ZFsHjH@q~SrsR6;Qg=[":{"opcode":"looks_sayforsecs","next":"r0j3`EeRa)_=`Jr{0CmY","parent":"uE)=Q6)/HB`|kDV)KtW}","inputs":{"MESSAGE":[3,"iPz2hjc{?-2Ge;:(pC.G",[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"iPz2hjc{?-2Ge;:(pC.G":{"opcode":"data_itemoflist","next":null,"parent":"]ZFsHjH@q~SrsR6;Qg=[","inputs":{"INDEX":[1,[7,1]]},"fields":{"LIST":["test.liste",".:u*s9D5|y9-7h1rjuQk-test.liste-list"]},"shadow":false,"topLevel":false},"r0j3`EeRa)_=`Jr{0CmY":{"opcode":"control_wait","next":"arXe.oz,/WiTUuuGf/?Z","parent":"]ZFsHjH@q~SrsR6;Qg=[","inputs":{"DURATION":[1,[5,2]]},"fields":{},"shadow":false,"topLevel":false},"arXe.oz,/WiTUuuGf/?Z":{"opcode":"looks_sayforsecs","next":"i,:KK;,vC{BX4PtsHTI/","parent":"r0j3`EeRa)_=`Jr{0CmY","inputs":{"MESSAGE":[3,[13,"test.liste",".:u*s9D5|y9-7h1rjuQk-test.liste-list"],[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"i,:KK;,vC{BX4PtsHTI/":{"opcode":"control_wait","next":",l}5H),^Bj0x3+N}oaj`","parent":"arXe.oz,/WiTUuuGf/?Z","inputs":{"DURATION":[1,[5,2]]},"fields":{},"shadow":false,"topLevel":false},",l}5H),^Bj0x3+N}oaj`":{"opcode":"looks_sayforsecs","next":null,"parent":"i,:KK;,vC{BX4PtsHTI/","inputs":{"MESSAGE":[3,"aG=4(3K2I-J=[x3U1}p|",[10,""]],"SECS":[1,[4,2]]},"fields":{},"shadow":false,"topLevel":false},"aG=4(3K2I-J=[x3U1}p|":{"opcode":"data_lengthoflist","next":null,"parent":",l}5H),^Bj0x3+N}oaj`","inputs":{},"fields":{"LIST":["test.liste",".:u*s9D5|y9-7h1rjuQk-test.liste-list"]},"shadow":false,"topLevel":false}},"comments":{},"currentCostume":0,"costumes":[{"assetId":"bcaaa8547a07cfe572c0967ba829e99d","name":"costume1","bitmapResolution":1,"md5ext":"bcaaa8547a07cfe572c0967ba829e99d.svg","dataFormat":"svg","rotationCenterX":47,"rotationCenterY":55},{"assetId":"11d6c5fbd91e433a1b85a00fd9dd43b6","name":"costume2","bitmapResolution":1,"md5ext":"11d6c5fbd91e433a1b85a00fd9dd43b6.svg","dataFormat":"svg","rotationCenterX":47,"rotationCenterY":55}],"sounds":[{"assetId":"83c36d806dc92327b9e7049a565c6bff","name":"meow","dataFormat":"wav","format":"","rate":48000,"sampleCount":40681,"md5ext":"83c36d806dc92327b9e7049a565c6bff.wav"}],"volume":100,"layerOrder":1,"visible":true,"x":2,"y":0,"size":100,"direction":90,"draggable":false,"rotationStyle":"all around"}],"monitors":[{"id":".:u*s9D5|y9-7h1rjuQk-test.liste-list","mode":"list","opcode":"data_listcontents","params":{"LIST":"test.liste"},"spriteName":null,"value":["hi",""],"width":102,"height":202,"x":352,"y":69,"visible":true},{"id":".:u*s9D5|y9-7h1rjuQk-sulf.c.liste-list","mode":"list","opcode":"data_listcontents","params":{"LIST":"sulf.c.liste"},"spriteName":null,"value":["sss"],"width":106,"height":206,"x":35,"y":72,"visible":true}],"extensions":[],"meta":{"semver":"3.0.0","vm":"0.2.0-prerelease.20190619042313","agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}}
--------------------------------------------------------------------------------
/backend/sb3/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/backend/sb3/.gitkeep
--------------------------------------------------------------------------------
/backend/sb3converter.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require("fs");
3 | const fetch = require('node-fetch');
4 | var JSZip = require("jszip");
5 | const axios = require("axios")
6 |
7 | const projectJSONBaseURL = "https://projects.scratch.mit.edu/"
8 | const assetsBaseURL = "https://cdn.assets.scratch.mit.edu/internalapi/asset/"
9 |
10 | var getProjectJSON = async function (projectID) {
11 | //console.log(projectJSONBaseURL + projectID)
12 | let resp = await axios.get('https://api.scratch.mit.edu/projects/' + projectID)
13 | console.log(resp.data.project_token)
14 | const req = await fetch(projectJSONBaseURL + projectID+"?token="+resp.data.project_token);
15 | return req.json()
16 | }
17 |
18 | var getAssets = async function (sb3Name) {
19 |
20 | //console.log(assetsBaseURL + sb3Name+"/get/")
21 | const req = await fetch(assetsBaseURL + sb3Name + "/get/");
22 | return req.buffer()
23 |
24 | }
25 |
26 |
27 |
28 | var convertFromFile = function (file) {
29 | console.log(file)
30 | return new Promise((resolve, reject) => {
31 | //console.log("[CONVERTER] started converting " + projectID + " from FILE")
32 | newZip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
33 | .pipe(fs.createWriteStream("./sb3/" + projectID + ".sb3"))
34 | .on('finish', function () {
35 | // JSZip generates a readable stream with a "end" event,
36 | // but is piped here in a writable stream which emits a "finish" event.
37 | console.log("out.zip written.");
38 | });
39 |
40 | let findsb2 = setInterval(() => {
41 | var files = fs.readdirSync('./sb2/');
42 | // console.log(files)
43 | files.forEach(element => {
44 | if (element == projectID + ".sb2") {
45 | // console.log(projectID + ".sb2")
46 | fs.readFile('./sb2/' + projectID + ".sb2", function (err, data) {
47 | if (err) throw err;
48 | // console.log(data.buffer);
49 | resolve(data.buffer);
50 | });
51 | clearInterval(findsb2);
52 | }
53 | });
54 | }, 1000);
55 |
56 |
57 |
58 | });
59 | }
60 |
61 | var convertFromID = function (projectID) {
62 | return new Promise((resolve, reject) => {
63 | console.log("[CONVERTER] started converting " + projectID + " from ID")
64 |
65 |
66 |
67 |
68 | fs.readFile('./sb2/' + projectID + ".sb2", function (err, data) {
69 | if (err) {
70 | // throw err;
71 | var newZip = new JSZip();
72 |
73 | getProjectJSON(projectID).then(res => {
74 |
75 | var filemap = parseMap(res.targets);
76 |
77 |
78 | let outJSON = JSON.stringify(res).replace("â˜", "\u2601")
79 |
80 |
81 | fs.writeFileSync("./sb2/" + projectID + "project.json", outJSON)
82 |
83 |
84 |
85 | newZip.file("project.json", outJSON);
86 |
87 |
88 |
89 |
90 |
91 | Object.keys(filemap).forEach(sb3Name => {
92 |
93 | getAssets(sb3Name).then(asset => {
94 | newZip.file(sb3Name, asset);
95 |
96 | }).then(function () {
97 | if (Object.keys(filemap).length == Object.keys(newZip.files).length - 1) {
98 | // console.log(newZip)
99 | newZip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
100 | .pipe(fs.createWriteStream("./sb3/" + projectID + ".sb3"))
101 | .on('finish', function () {
102 | // JSZip generates a readable stream with a "end" event,
103 | // but is piped here in a writable stream which emits a "finish" event.
104 | console.log("out.zip written.");
105 | });
106 |
107 | let findsb2 = setInterval(() => {
108 | var files = fs.readdirSync('./sb2/');
109 | // console.log(files)
110 | files.forEach(element => {
111 | if (element == projectID + ".sb2") {
112 | // console.log(projectID + ".sb2")
113 | fs.readFile('./sb2/' + projectID + ".sb2", function (err, data) {
114 | if (err) throw err;
115 | // console.log(data.buffer);
116 | resolve(data.buffer);
117 | });
118 | clearInterval(findsb2);
119 | }
120 | });
121 | }, 1000);
122 |
123 |
124 | console.log("[CONVERTER] finished converting " + projectID + " from ID")
125 | }
126 | })
127 | })
128 | })
129 | return
130 | }
131 | console.log("[CONVERTER] found converted project " + projectID)
132 | resolve(data.buffer);
133 | });
134 |
135 |
136 |
137 |
138 |
139 | });
140 | }
141 |
142 | function parseMap(targets) {
143 | var out = {};
144 | var costumeList = {};
145 | var soundList = {};
146 | targets.forEach(target => {
147 | target.costumes.forEach(costume => {
148 | if (costumeList[costume.assetId] == null)
149 | costumeList[costume.assetId] = Object.keys(costumeList).length;
150 |
151 | if (costume.md5ext == undefined) {
152 | out[costume.assetId + "." + costume.dataFormat] = costumeList[costume.assetId] + "." + costume.dataFormat;
153 | } else {
154 | out[costume.md5ext] = costumeList[costume.assetId] + "." + costume.dataFormat;
155 | }
156 |
157 | });
158 |
159 | target.sounds.forEach(sound => {
160 | if (soundList[sound.assetId] == null)
161 | soundList[sound.assetId] = Object.keys(soundList).length;
162 |
163 | out[sound.md5ext] = soundList[sound.assetId] + "." + sound.dataFormat;
164 | });
165 | });
166 | return out;
167 | }
168 |
169 | module.exports = { convertFromFile, convertFromID, getProjectJSON, getAssets, parseMap };
--------------------------------------------------------------------------------
/backend/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 | var https = require('https');
4 | var http = require('http');
5 | var fs = require('fs');
6 | const axios = require('axios');
7 |
8 | var cloudSave = require("./cloud.js")
9 | var sb3converter = require("./sb3converter.js")
10 | var packager = require("./package.js")
11 | var admintools = require("./admintools/admintools.js")
12 |
13 |
14 | process.env.ADMINTOOLS = "true"
15 |
16 | console.log(process.env.ADMINTOOLS)
17 |
18 |
19 |
20 |
21 | if (process.env.ISSULFSERVER == "true") {
22 | var files = fs.readdirSync('./ssl/');
23 | console.log(files)
24 |
25 | var server = https.createServer({
26 | key: fs.readFileSync('./ssl/privkey.pem'), cert: fs.readFileSync('./ssl/cert.pem'),
27 | requestCert: false,
28 | rejectUnauthorized: false
29 | }, app).listen(8082);
30 | console.log("RUNNING ON SULF SERVER")
31 | } else {
32 | var server = http.createServer(app).listen(8082);
33 | }
34 |
35 | var io = require('socket.io').listen(server);
36 |
37 | io.on('connection', function (socket) {
38 |
39 |
40 | admintools.setCurrentConnections(Object.keys(io.sockets.sockets).length)
41 | socket.on('sendSB3file', function (data) {
42 | var file = sb3converter.convertFromFile(data).then(function (file) {
43 | socket.emit("sendSB2file", file);
44 | });
45 | });
46 | socket.on('sendSB3ID', function (data) {
47 | var file = sb3converter.convertFromID(data).then(function (file) {
48 | socket.emit("sendSB2file", file);
49 | })
50 | });
51 | socket.on('getReq', function (data) {
52 | // console.log("DATA FROM PLAYER: ",data)
53 | cloudSave.getReq(data);
54 | console.log(cloudSave.CLOUDSAVE[data.projectID])
55 | socket.emit('getRes', cloudSave.CLOUDSAVE[data.projectID].vars);
56 | });
57 | socket.on('getPackage', function (data) {
58 | console.log("packager")
59 | //console.log(data)
60 | if (data.zip != undefined) {
61 | console.log("package from file")
62 | var b64string = data.zip;
63 | var buf = Buffer.from(b64string, 'base64');
64 | packager.generatePackageFromZip(buf, data.settings, function (output) {
65 | console.log("done Converting")
66 | socket.emit('sendPackage', output);
67 | });
68 | }
69 | if (data.id != undefined) {
70 | console.log("package from id")
71 | packager.generatePackageFromID(data.id, data.settings, function (output) {
72 | console.log("done Converting")
73 | socket.emit('sendPackage', output);
74 | });
75 | }
76 | });
77 | socket.on('getProjectData', async function (data,cb) {
78 | let resp = await axios.get('https://api.scratch.mit.edu/projects/' + data)
79 | .then(function (response) {
80 | // handle success
81 | // console.log(response);
82 | socket.emit('getProjectDataReturn', response.data);
83 | cb(response.data)
84 | })
85 | .catch(function (error) {
86 | // handle error
87 | console.log(error);
88 | })
89 | .finally(function () {
90 | // always executed
91 | });
92 | })
93 | socket.on('logRequest', function (data) {
94 | admintools.logRequest(data);
95 | })
96 | socket.on('disconnect', function () {
97 | admintools.setCurrentConnections(Object.keys(io.sockets.sockets).length)
98 | })
99 | });
100 |
101 |
102 | if (process.env.ADMINTOOLS == "true") {
103 | console.log("LOADING ADMINTOOLS!")
104 | admintools.setupAdminTools(io);
105 | } else {
106 | console.log("NO ADMINTOOLS")
107 | }
--------------------------------------------------------------------------------
/backend/ssl/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/backend/ssl/.gitkeep
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | sulfurous-sb3tosb2:
4 | build: ./sb3tosb2
5 | volumes:
6 | - ./sb3tosb2/src:/work/src
7 | - ./backend/sb2:/work/sb2
8 | - ./backend/sb3:/work/sb3
9 | container_name: sulfurous-sb3tosb2
10 | sulfurous-frontend:
11 | image: "node:10-alpine"
12 | user: "root"
13 | working_dir: /home/node/app
14 | environment:
15 | - NODE_ENV=production
16 | ports:
17 | - "3000:3000"
18 | volumes:
19 | - ./frontend:/home/node/app
20 | command: "npm start"
21 | container_name: sulfurous-frontend
22 | restart: unless-stopped
23 | sulfurous-backend:
24 | image: "node:10-alpine"
25 | user: "root"
26 | working_dir: /home/node/app
27 | environment:
28 | - NODE_ENV=production
29 | ports:
30 | - "8082:8082"
31 | volumes:
32 | - ./backend:/home/node/app
33 | - ./sb3tosb2/sb3:/home/node/app/sb3
34 | - ./sb3tosb2/sb2:/home/node/app/sb2
35 | command: "npm start"
36 | container_name: sulfurous-backend
37 | restart: unless-stopped
38 |
--------------------------------------------------------------------------------
/docker-composeSULFSER.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | sulfurous-sb3tosb2:
4 | build: ./sb3tosb2
5 | volumes:
6 | - ./sb3tosb2/src:/work/src
7 | - ./sb3tosb2/sb2:/work/sb2
8 | - ./sb3tosb2/sb3:/work/sb3
9 | container_name: sulfurous-sb3tosb2
10 | sulfurous-backend:
11 | image: "node:14-alpine"
12 | user: "root"
13 | working_dir: /home/node/app
14 | environment:
15 | - NODE_ENV=production
16 | - ISSULFSERVER=true
17 | ports:
18 | - "8082:8082"
19 | volumes:
20 | - ./backend:/home/node/app
21 | - ./sb3tosb2/sb3:/home/node/app/sb3
22 | - ./sb3tosb2/sb2:/home/node/app/sb2
23 | - ./backend/ssl:/home/node/app/ssl
24 | command: "npm start"
25 | container_name: sulfurous-backend
26 | restart: unless-stopped
27 |
--------------------------------------------------------------------------------
/frontend/main.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var app = express();
3 |
4 | app.listen(3000, () => console.log('listening at 3000'));
5 | app.use(express.static('./public'));
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sulfurous-frontend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "npm i && node main"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/Mittagskogel/Sulfurous.git"
12 | },
13 | "author": "Alexander Pichler",
14 | "license": "ISC",
15 | "bugs": {
16 | "url": "https://github.com/Mittagskogel/Sulfurous/issues"
17 | },
18 | "homepage": "https://github.com/Mittagskogel/Sulfurous#readme",
19 | "dependencies": {
20 | "express": "^4.17.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/public/admintools/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sulfurous-Admintools
8 |
9 |
118 |
119 |
120 |
121 |
122 |
Current Connections
123 |
00000
124 |
125 |
126 |
127 |
128 |
129 | Last Hour
130 | Last 24h
131 | Last 30Days
132 |
133 |
134 | 000000
135 | 000000
136 | 000000
137 |
138 |
139 |
140 |
141 |
142 |
143 |
SB2 IDs Log
144 |
145 |
146 |
147 |
148 |
149 |
SB3 IDs Log
150 |
151 |
152 |
153 |
154 |
155 | This is a test where am I
156 |
157 |
158 |
159 |
160 |
161 |
208 |
209 |
--------------------------------------------------------------------------------
/frontend/public/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #000;
3 | margin: 0;
4 | overflow: hidden;
5 | }
6 | .player {
7 | position: absolute;
8 | }
9 | .splash,
10 | .error {
11 | position: absolute;
12 | top: 0;
13 | left: 0;
14 | width: 100%;
15 | height: 100%;
16 | background: #000;
17 | display: table;
18 | color: #fff;
19 | }
20 | .error {
21 | display: none;
22 | }
23 | .webgl-error {
24 | position: absolute;
25 | top: 0;
26 | left: 0;
27 | width: 100%;
28 | height: 100%;
29 | background: #000;
30 | display: table;
31 | color: #fff;
32 | display: none;
33 | }
34 | .splash > div,
35 | .error > div {
36 | display: table-cell;
37 | height: 100%;
38 | text-align: center;
39 | vertical-align: middle;
40 | }
41 | .webgl-error > div {
42 | display: table-cell;
43 | height: 100%;
44 | text-align: center;
45 | vertical-align: middle;
46 | }
47 | .progress {
48 | width: 80%;
49 | height: 16px;
50 | border: 1px solid #fff;
51 | margin: 0 auto;
52 | }
53 | .progress-bar {
54 | background: #fff;
55 | width: 10%;
56 | height: 100%;
57 | }
58 | h1 {
59 | font: 300 72px Helvetica Neue, Helvetica, Arial, sans-serif;
60 | margin: 0 0 16px;
61 | }
62 | p {
63 | font: 300 24px/1.5 Helvetica Neue, Helvetica, Arial, sans-serif;
64 | margin: 0;
65 | color: rgba(255, 255, 255, .6);
66 | }
67 | .error a {
68 | color: #fff;
69 | }
70 |
--------------------------------------------------------------------------------
/frontend/public/css/embed.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 480px;
3 | margin: 0 auto;
4 | }
5 |
6 | .progress-bar {
7 | padding: 0;
8 | }
9 |
10 | .internal-error {
11 | position: absolute;
12 | left: 1px;
13 | bottom: 1px;
14 | right: 1px;
15 | background: #fff;
16 | box-shadow: 0 -1px rgba(0, 0, 0, .4);
17 | }
18 |
19 | .controls {
20 | display: none;
21 | }
22 |
23 | .has-ui .controls {
24 | display: block;
25 | }
26 |
27 | .hide-ui .controls {
28 | position: absolute;
29 | width: 100%;
30 | }
31 | .hide-ui .controls span {
32 | display: none;
33 | }
34 | .hide-ui .player {
35 | box-shadow: none;
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/public/css/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100vw;
3 | height: 98vh;
4 | margin: 0px;
5 | margin-top: 1vh;
6 | background-color: #424242;
7 |
8 | color: black;
9 | /*image-rendering: -moz-crisp-edges;*/
10 | /*image-rendering: pixelated;*/
11 | overflow-x: hidden; /* Hide scrollbars */
12 | }
13 |
14 | ::-webkit-scrollbar {
15 | display: none;
16 | }
17 |
18 | .featured-image {
19 | display: none;
20 | }
21 |
22 | .version {
23 | position: absolute;
24 | top: 80%;
25 | left: 80%;
26 | transform: translate(-80%, -80%);
27 | font-size: 80%;
28 | /* use same color as url */
29 | color: rgba(0, 0, 0, .4);
30 | }
31 |
32 | .logocontainer{
33 | position: relative;
34 | text-align: center;
35 | color: white;
36 | }
37 |
38 | .url {
39 |
40 | background: 0;
41 | border: 0;
42 | margin: 0;
43 | padding: 0 0 0 32px;
44 | outline: 0;
45 | font: 300 23px/32px Helvetica Neue, Helvetica, Arial, sans-serif;
46 | display: block;
47 | width: 100%;
48 | -moz-box-sizing: border-box;
49 | box-sizing: border-box;
50 | color: #000;
51 | position: absolute;
52 | top: 50%;
53 | -ms-transform: translateY(-50%);
54 | transform: translateY(-50%);
55 | }
56 |
57 | .project-link {
58 | position: absolute;
59 | top: 50%;
60 | -ms-transform: translateY(-50%);
61 | transform: translateY(-50%);
62 |
63 | background-position: -160px 0;
64 | }
65 |
66 | a {
67 | color: #25d;
68 | text-decoration: underline;
69 | }
70 |
71 | a:visited {
72 | color: #73c;
73 | }
74 |
75 | a:active {
76 | color: #03a;
77 | }
78 |
79 | .dropdown {
80 | display: inline-block;
81 | position: relative;
82 | }
83 |
84 | .dropdown>select {
85 | -webkit-appearance: none;
86 | font: inherit;
87 | position: absolute;
88 | opacity: 0;
89 | cursor: pointer;
90 | top: 0;
91 | left: 0;
92 | width: 100%;
93 | height: 100%;
94 | }
95 |
96 | .area {
97 | overflow: hidden;
98 | margin: 0 -24px;
99 | padding: 0 24px;
100 | margin: 0 auto 0;
101 | width: 60%;
102 | max-width: 880px;
103 | min-width: 480px;
104 | border-radius: 20px;
105 | background-color: #bcbcbc;
106 | }
107 |
108 | #title {
109 | height: 4vh;
110 | position: relative;
111 | }
112 |
113 | #playercontainer{
114 | float: left;
115 | }
116 |
117 | #qrdiv{
118 | float: right;
119 |
120 | text-align: center;
121 | }
122 | #qrcode{
123 | margin: 0 auto 0;
124 | width: 256px;
125 | }
126 |
127 |
128 | #project-area {
129 | display: none;
130 |
131 | margin-top: 1vh;
132 | }
133 |
134 | #title-area {
135 | margin-bottom: 1vh;
136 | }
137 |
138 | #credits-area {
139 | margin-top: 1vh;
140 | border-radius: 20px;
141 | padding-bottom: 2px;
142 | }
143 |
144 | a,a:visited{
145 | color: #1f63ff;
146 |
147 | text-decoration:none
148 | }
149 |
150 | .privlink{
151 | text-align: right;
152 | }
153 |
154 | .progress-bar{
155 | background-color: #ff9900;
156 | }
157 |
158 |
159 | .fs #player-area {
160 | overflow: visible;
161 | }
162 |
163 |
164 | .package{
165 |
166 | float: left;
167 | }
168 | .embed{
169 |
170 | float: right;
171 | }
172 |
173 |
174 | h1,
175 | p {
176 | font: 300 16px/1.5 Helvetica Neue, Helvetica, Arial, sans-serif;
177 | margin: 0 0 16px;
178 | }
179 |
180 | h1 {
181 | font: 300 24px/32px Helvetica Neue, Helvetica, Arial, sans-serif;
182 | margin: 16px 0 0;
183 | }
184 |
185 | h1.title {
186 | font: 300 54px/72px Helvetica Neue, Helvetica, Arial, sans-serif;
187 | margin: 0;
188 | }
189 |
190 | code {
191 | font: 12px Menlo, Monaco, Consolas, Courier New, monospace;
192 | background: #f5f5f5;
193 | border-radius: 3px;
194 | padding: 3px;
195 | }
196 |
197 | .package a {
198 | padding: 2px 8px;
199 | background: linear-gradient(#fafafa, #e8e8e8);
200 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .35), 0 1px 4px rgba(0, 0, 0, .2);
201 | border-radius: 3px;
202 | cursor: pointer;
203 | color: #000;
204 | text-decoration: none;
205 | -webkit-tap-highlight-color: transparent;
206 | }
207 |
208 | .package a:hover {
209 | background: linear-gradient(#fff, #eaeaea);
210 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .4), 0 1px 4px rgba(0, 0, 0, .3);
211 | }
212 |
213 | .package a:active {
214 | background: linear-gradient(#ddd, #eaeaea);
215 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .5), inset 0 2px 5px rgba(0, 0, 0, .15);
216 | }
217 |
218 | .package label,
219 | .package input,
220 | .package a,
221 | .package span {
222 | display: inline-block;
223 | vertical-align: middle;
224 | }
225 |
226 | .package input[type=checkbox] {
227 | margin: 0 0 0 16px;
228 | }
229 |
230 | .xyinput {
231 | width: 8ch;
232 | }
233 |
234 | #embed-code {
235 | background: 0;
236 | border: 1px solid rgba(0, 0, 0, .4);
237 | margin: 0;
238 | padding: 4px;
239 | outline: 0;
240 | width: 80px;
241 | font: 12px/16px Menlo, Monaco, Consolas, Courier New, monospace;
242 | -moz-box-sizing: border-box;
243 | box-sizing: border-box;
244 | color: rgba(0, 0, 0, .7);
245 | }
--------------------------------------------------------------------------------
/frontend/public/css/player.css:
--------------------------------------------------------------------------------
1 | .progress-bar {
2 | position: absolute;
3 | top: 0;
4 | left: 0;
5 | bottom: 0;
6 | width: 0;
7 | background: #cde;
8 | -webkit-transition: .3s;
9 | -moz-transition: .3s;
10 | -o-transition: .3s;
11 | transition: .3s;
12 | }
13 | .light-content .progress-bar {
14 | background: #468;
15 | }
16 | .progress-bar.error {
17 | background: #ecc;
18 | }
19 | .light-content .progress-bar.error {
20 | background: #844;
21 | }
22 | .controls {
23 | position: relative;
24 | height: 32px;
25 | }
26 | .controls span,
27 | .project-link {
28 | width: 32px;
29 | height: 32px;
30 | float: right;
31 | cursor: pointer;
32 | text-align: center;
33 | opacity: .4;
34 | background-image: url(../img/icons.svg);
35 | text-decoration: none;
36 | }
37 | .controls .flag {
38 | background-position: 0 0;
39 | }
40 | .controls .stop {
41 | background-position: -96px 0;
42 | }
43 | .controls .pause {
44 | background-position: -32px 0;
45 | }
46 | .controls .play {
47 | background-position: -64px 0;
48 | }
49 | .controls .full-screen {
50 | float: left;
51 | background-position: -128px 0;
52 | }
53 | .controls span:active,
54 | .project-link:active {
55 | opacity: 1 !important;
56 | }
57 | .controls .turbo {
58 | float: right;
59 | display: none;
60 | cursor: default;
61 | color: rgba(0, 0, 0, .4);
62 | font: 500 12px/32px Helvetica Neue, Helvetica, Arial, sans-serif;
63 | padding: 0 8px;
64 | }
65 | .player {
66 | box-shadow: 0 0 0 1px rgba(0, 0, 0, .4);
67 | width: 480px;
68 | height: 360px;
69 | position: relative;
70 | -webkit-transform-origin: 0 0;
71 | -moz-transform-origin: 0 0;
72 | -ms-transform-origin: 0 0;
73 | -o-transform-origin: 0 0;
74 | transform-origin: 0 0;
75 | }
76 | .light-content .player {
77 | box-shadow: 0 0 0 1px rgba(255, 255, 255, .4);
78 | }
79 |
80 | .internal-error {
81 | color: rgba(128, 0, 0, .6);
82 | font: 500 12px Helvetica Neue, Helvetica, Arial, sans-serif;
83 | padding: 8px;
84 | display: none;
85 | }
86 | .internal-error a {
87 | color: rgba(128, 0, 0, .8);
88 | }
89 |
90 | .webgl-error {
91 | color: rgba(128, 0, 0, .6);
92 | font: 500 12px Helvetica Neue, Helvetica, Arial, sans-serif;
93 | padding: 8px;
94 | display: none;
95 | }
96 | .webgl-error a {
97 | color: rgba(128, 0, 0, .8);
98 | }
99 |
100 | .fs {
101 | background: #000;
102 | width: 100%;
103 | height: 100%;
104 | }
105 | .fs body {
106 | margin: 0;
107 | padding: 0;
108 | overflow: hidden;
109 | }
110 | .fs .title,
111 | .fs section {
112 | display: none;
113 | }
114 | .fs .controls span,
115 | .light-content .controls span {
116 | background-position-y: -32px;
117 | opacity: .6;
118 | }
119 | /*
120 | .fs .controls .flag,
121 | .light-content .controls .flag{
122 | background-position: 0 -32px;
123 | }
124 | .fs .controls .stop,
125 | .light-content .controls .stop{
126 | background-position: -96px -32px;
127 | }
128 | .fs .controls .pause,
129 | .light-content .controls .pause{
130 | background-position: -32px -32px;
131 | }
132 | .fs .controls .play,
133 | .light-content .controls .play{
134 | background-position: -64px -32px;
135 | }
136 | .fs .controls .full-screen,
137 | .light-content .controls .full-screen{
138 | float: left;
139 | background-position: -128px -32px;
140 | }*/
141 | .light-content .controls .full-screen {
142 | background-position-y: -64px;
143 | }
144 | .fs .light-content .controls .full-screen {
145 | background-position-y: -32px;
146 | }
147 | .fs .controls .turbo,
148 | .light-content .controls .turbo {
149 | color: rgba(255, 255, 255, .6);
150 | }
151 | .fs .player {
152 | box-shadow: none;
153 | }
154 |
--------------------------------------------------------------------------------
/frontend/public/fonts/DSEG7Classic-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/fonts/DSEG7Classic-Light.ttf
--------------------------------------------------------------------------------
/frontend/public/html/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | sulfurous
7 |
8 |
9 |
10 |
11 |
12 |
sulfurous
13 |
16 |
17 |
18 |
19 |
20 |
21 |
sulfurous
22 |
An error has occurred. Click here to
23 | file a bug report on GitHub.
24 |
25 |
26 |
27 |
28 |
sulfurous
29 |
It looks like your device doesn't support WebGL. You can try viewing this project in the legacy player here .
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/frontend/public/html/embed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | phosphorus
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Turbo Mode
13 |
14 |
15 |
16 |
17 | An internal error occurred.
Click here to file a bug report.
18 |
19 |
20 | It looks like your device doesn't support WebGL. You can try viewing this project in the legacy player
here .
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/frontend/public/html/embedtest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | If embed works, you should see a project below:
7 |
8 |
9 |
--------------------------------------------------------------------------------
/frontend/public/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/img/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/img/icons.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
20 |
39 |
46 |
57 |
58 |
60 |
61 |
63 | image/svg+xml
64 |
66 |
67 |
68 |
69 |
70 |
75 |
81 |
87 |
93 |
99 |
105 |
111 |
116 |
122 |
128 |
134 |
140 |
146 |
152 |
158 |
164 |
170 |
176 |
182 |
188 |
194 |
200 |
206 |
216 |
222 |
228 |
234 |
240 |
246 |
256 |
266 |
276 |
286 |
296 |
306 |
312 |
318 |
324 |
330 |
331 |
332 |
--------------------------------------------------------------------------------
/frontend/public/img/sulfurouslogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/img/sulfurouslogo.png
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sulfurous
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
Turbo Mode
48 |
49 |
50 |
51 |
52 | An internal error occurred.
Click here to file a bug report.
54 |
55 | It looks like your device doesn't support WebGL. You can try viewing this project in the legacy player
here .
57 |
58 |
59 |
60 |
QR-Code
61 | with Link to your Project
62 |
63 |
64 |
65 |
66 |
72 |
75 |
129 |
132 |
133 |
Credits
134 |
Sulfurous was created by Mittagskogel and further developed by
135 | FRALEX as part of their work at the Alpen-Adria-University Klagenfurt . Sulfurous is based off Phosphorus, which
137 | was created by Nathan Dinsmore . Its CPS-style compilation and overall
138 | design was inspired by Rhys Simpson 's sb2.js . It would have more bugs if not for Truman Kilen . It uses the JSZip
141 | library, created by Stuart Knightley , David Duponchel , Franz Buchinger, and António Afonso , to read .sb2
files and compressed projects,
144 | and the canvg library, created by Gabe Lerner, to render SVGs in
146 | <canvas>
elements.
147 |
Code
148 |
Sulfurous is released under the MIT license, the source code for Sulfurous is available on GitHub . See Phosphorus for the original version.
151 |
Report a problem
152 |
Sulfurous is still in development. Click here to report a problem with this
154 | project. If you are the creator of this Project please publish your project on scratch that we can see the
155 | code and debug it.
156 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/frontend/public/js/app.js:
--------------------------------------------------------------------------------
1 | var splash = document.querySelector('.splash');
2 | var progressBar = document.querySelector('.progress-bar');
3 | var error = document.querySelector('.error');
4 | var bugLink = document.querySelector('#bug-link');
5 | var webGLError = document.querySelector('.webgl-error');
6 | var legacyLink = document.querySelector('#legacy-link');
7 | var player = document.querySelector('.player');
8 |
9 | var stage;
10 |
11 | var projectId = 17088932;
12 | var projectTitle = '';
13 | var turbo = false;
14 | var fullScreen = true;
15 | var aspectX = 4;
16 | var aspectY = 3;
17 | var resolutionX = 480;
18 | var resolutionY = 360;
19 | let isPackage = false;
20 |
21 | (function () {
22 | 'use strict';
23 |
24 |
25 | setupWebsocket("app")
26 |
27 |
28 |
29 |
30 |
31 |
32 | /*
33 | if (location.protocol === 'https:') {
34 | location.replace(('' + location).replace(/^https:/, 'https:'));
35 | }
36 | */
37 |
38 |
39 |
40 | var params = location.search.substr(1).split('&');
41 | params.forEach(function (p) {
42 | var parts = p.split('=');
43 | if (parts.length > 1) {
44 | switch (parts[0]) {
45 | case 'id':
46 | if (parts[1] == "zip") {
47 | isPackage = true;
48 | }
49 | projectId = Number(parts[1]);
50 | break;
51 | case 'turbo':
52 | turbo = parts[1] !== 'false';
53 | break;
54 | case 'full-screen':
55 | fullScreen = parts[1] !== 'false';
56 | break;
57 | case 'aspect-x':
58 | aspectX = Number(parts[1]);
59 | break;
60 | case 'aspect-y':
61 | aspectY = Number(parts[1]);
62 | break;
63 | case 'resolution-x':
64 | resolutionX = Number(parts[1]);
65 | break;
66 | case 'resolution-y':
67 | resolutionY = Number(parts[1]);
68 | break;
69 | default:
70 | console.log('Skipping unknown option: ' + parts[0] + '=' + parts[1]);
71 | }
72 | }
73 | });
74 |
75 | P.resolution = resolutionX;
76 |
77 |
78 |
79 |
80 |
81 | function mobileFullScreen(e) {
82 | if (e) e.preventDefault();
83 | document.documentElement.classList.toggle('fs');
84 |
85 | if (!e) {
86 | var el = document.documentElement;
87 | if (el.requestFullScreenWithKeys) {
88 | el.requestFullScreenWithKeys();
89 | } else if (el.webkitRequestFullScreen) {
90 | el.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
91 | } else if (el.mozRequestFullScreen) {
92 | el.mozRequestFullScreen();
93 | } else {
94 | console.warn('No full screen available.');
95 | }
96 | }
97 | updateFullScreen();
98 | }
99 |
100 | function updateFullScreen() {
101 | if (!stage) return;
102 |
103 | resolutionX = !resolutionX ? 480 : resolutionX;
104 | resolutionY = !resolutionY ? 360 : resolutionY;
105 |
106 | window.scrollTo(0, 0);
107 | var padding = 8;
108 | var w = window.innerWidth - padding * 2;
109 | var h = window.innerHeight - padding;
110 | w = Math.min(w, h * resolutionX / resolutionY);
111 | h = w * resolutionY / resolutionX;
112 | document.body.style.width = w + 'px';
113 | document.body.style.height = h + 'px';
114 | document.body.style.marginLeft = (window.innerWidth - w) / 2 + 'px';
115 | document.body.style.marginTop = (window.innerHeight - h + padding) / 2 + 'px';
116 | stage.setZoom(w / 480, w * resolutionY / resolutionX / 360);
117 | }
118 |
119 |
120 | if (P.hasTouchEvents) {
121 | window.addEventListener('load', function () {
122 | document.getElementById('fullscreenWarning').textContent = 'On mobile browsers, use two finger tap in portrait orientation and turn to landscape orientation for full screen.';
123 | });
124 |
125 | document.addEventListener('touchstart', function (e) {
126 | if (e.targetTouches.length >= 2)
127 | mobileFullScreen(e);
128 | });
129 | }
130 |
131 |
132 |
133 | window.addEventListener('resize', layout);
134 |
135 | if (P.hasTouchEvents) {
136 | document.addEventListener('touchmove', function (e) {
137 | e.preventDefault();
138 | });
139 | }
140 |
141 |
142 |
143 |
144 |
145 | load(projectId)
146 | }());
147 |
148 | function layout() {
149 | if (!stage) return;
150 | var w = Math.min(window.innerWidth, window.innerHeight * aspectX / aspectY);
151 | if (!fullScreen) w = resolutionX;
152 | var h = w * aspectY / aspectX;
153 | if (!fullScreen) h = resolutionY;
154 | player.style.left = (window.innerWidth - w) / 2 + 'px';
155 | player.style.top = (window.innerHeight - h) / 2 + 'px';
156 | stage.setZoom(w / 480, h / 360);
157 | stage.draw();
158 | }
159 |
160 | function showError(e) {
161 | error.style.display = 'table';
162 | bugLink.href = 'https://github.com/mittagskogel/sulfurous/issues/new?title=' + encodeURIComponent(projectTitle || '') + '&body=' + encodeURIComponent('\n\n\nhttps://scratch.mit.edu/projects/' + projectId + '\nhttps://newton.nes.aau.at/~sulfurous/#' + projectId + (e.stack ? '\n\n```\n' + e.stack + '\n```' : ''));
163 | console.error(e.stack);
164 | }
165 |
166 | function showWebGLError(e) {
167 | webGLError.style.display = 'table';
168 | legacyLink.href = location;
169 | legacyLink.href = legacyLink.href.replace('html', 'legacy/html');
170 | console.error(e);
171 | }
172 |
173 | function isSB2(id) {
174 |
175 | return true
176 |
177 | return new Promise(function (resolve, reject) {
178 | fetch('https://api.scratch.mit.edu/projects/' + id)
179 | .then(function (response) {
180 | console.log(response.data)
181 | if (response.status == 200) {
182 |
183 | resolve(true);
184 | } else if (response.status == 404) {
185 |
186 | resolve(false);
187 | }
188 | })
189 | })
190 |
191 |
192 | }
193 |
194 | async function load(id) {
195 |
196 | if (isPackage) {
197 |
198 | fetch("../project.sb2").then(async (res) => {
199 |
200 | var request = P.IO.loadSB2File(await res.blob());
201 |
202 | request.onload = function (s) {
203 | splash.style.display = 'none';
204 |
205 | stage = s;
206 | layout();
207 |
208 | stage.isTurbo = turbo;
209 | stage.start();
210 | stage.triggerGreenFlag();
211 |
212 | player.appendChild(stage.root);
213 | stage.focus();
214 | stage.handleError = showError;
215 | };
216 | request.onerror = showError;
217 | request.onprogress = function (e) {
218 | progressBar.style.width = (10 + e.loaded / e.total * 90) + '%';
219 | };
220 |
221 |
222 |
223 |
224 | })
225 |
226 |
227 | } else if (await isSB2(id)) {
228 | console.log("SB2")
229 |
230 | socket.emit('getProjectData', id, async function (projectData) {
231 |
232 | var request = P.IO.loadScratchr2Project(id, projectData.project_token);
233 |
234 | request.onload = function (s) {
235 | splash.style.display = 'none';
236 |
237 | stage = s;
238 | layout();
239 |
240 | stage.isTurbo = turbo;
241 | stage.start();
242 | stage.triggerGreenFlag();
243 |
244 | player.appendChild(stage.root);
245 | stage.focus();
246 | stage.handleError = showError;
247 | };
248 | request.onerror = showError;
249 | request.onprogress = function (e) {
250 | progressBar.style.width = (10 + e.loaded / e.total * 90) + '%';
251 | };
252 | })
253 | } else {
254 | console.log("SB3")
255 | socket.emit("sendSB3ID", id);
256 | }
257 | }
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 | function loadFromSocket(data) {
266 |
267 | console.log(data)
268 |
269 | var blob = new Blob([data]);
270 |
271 | var request = P.IO.loadSB2File(blob);
272 |
273 | request.onload = function (s) {
274 | splash.style.display = 'none';
275 |
276 | stage = s;
277 | layout();
278 |
279 | stage.isTurbo = turbo;
280 | stage.start();
281 | stage.triggerGreenFlag();
282 |
283 | player.appendChild(stage.root);
284 | stage.focus();
285 | stage.handleError = showError;
286 | };
287 | request.onerror = showError;
288 | request.onprogress = function (e) {
289 | progressBar.style.width = (10 + e.loaded / e.total * 90) + '%';
290 | };
291 | }
--------------------------------------------------------------------------------
/frontend/public/js/embed.js:
--------------------------------------------------------------------------------
1 | (function(global) {
2 | 'use strict';
3 |
4 | var script = document.currentScript || (function(scripts) {
5 | return scripts[scripts.length - 1];
6 | })(document.getElementsByTagName('script'));
7 |
8 | var hasUI = true;
9 | var resolutionX = 480;
10 | var resolutionY = 360;
11 | var params = script.src.split('?')[1].split('&');
12 | params.forEach(function(p) {
13 | var parts = p.split('=');
14 | if (parts.length > 1 && parts[0] === 'ui') {
15 | hasUI = parts[1] !== 'false';
16 | }
17 | if (parts.length > 1 && parts[0] === 'resolution-x'){
18 | resolutionX = Number(parts[1]);
19 | }
20 | if (parts.length > 1 && parts[0] === 'resolution-y'){
21 | resolutionY = Number(parts[1]);
22 | }
23 | });
24 |
25 | var iframe = document.createElement('iframe');
26 | iframe.setAttribute('allowfullscreen', true);
27 | iframe.setAttribute('allowtransparency', true);
28 | iframe.src = script.src.replace(/^https:/, 'https:').replace(/js\/embed\.js/, 'html/embed.html');
29 | //width: 482, height: 393
30 | iframe.width = hasUI ? resolutionX + 2 : resolutionX;
31 | iframe.height = hasUI ? resolutionY + 33 : resolutionY;
32 | iframe.style.border = '0';
33 | iframe.className = 'phosphorus';
34 |
35 | script.parentNode.replaceChild(iframe, script);
36 |
37 | }(this));
--------------------------------------------------------------------------------
/frontend/public/js/fonts.js:
--------------------------------------------------------------------------------
1 | WebFontConfig = {
2 | google: { families: [ 'Donegal+One::latin', 'Gloria+Hallelujah::latin', 'Permanent+Marker::latin', 'Mystery+Quest::latin' ] }
3 | };
4 | (function() {
5 | var wf = document.createElement('script');
6 | wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
7 | '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
8 | wf.type = 'text/javascript';
9 | wf.async = 'true';
10 | var s = document.getElementsByTagName('script')[0];
11 | s.parentNode.insertBefore(wf, s);
12 | })();
13 |
--------------------------------------------------------------------------------
/frontend/public/js/gyronorm.complete.min.js:
--------------------------------------------------------------------------------
1 | /*! Full Tilt v0.5.3 / http://github.com/richtr/Full-Tilt */
2 | !function(a){function b(a){return a=+a,0===a||isNaN(a)?a:a>0?1:-1}function c(a){var b=new Promise(function(b,c){var d=function(e){setTimeout(function(){a&&a.data?b():e>=20?c():d(++e)},50)};d(0)});return b}function d(){o=n?(a.screen.orientation.angle||0)*j:(a.orientation||0)*j}function e(a){l.orientation.data=a;for(var b in l.orientation.callbacks)l.orientation.callbacks[b].call(this)}function f(a){l.motion.data=a;for(var b in l.motion.callbacks)l.motion.callbacks[b].call(this)}if(void 0===a.FULLTILT||null===a.FULLTILT){var g=Math.PI,h=g/2,i=2*g,j=g/180,k=180/g,l={orientation:{active:!1,callbacks:[],data:void 0},motion:{active:!1,callbacks:[],data:void 0}},m=!1,n=a.screen&&a.screen.orientation&&void 0!==a.screen.orientation.angle&&null!==a.screen.orientation.angle?!0:!1,o=(n?a.screen.orientation.angle:a.orientation||0)*j,p=h,q=g,r=i/3,s=-h,t={};t.version="0.5.3",t.getDeviceOrientation=function(a){var b=new Promise(function(b,d){var e=new t.DeviceOrientation(a);e.start();var f=new c(l.orientation);f.then(function(){e._alphaAvailable=l.orientation.data.alpha&&null!==l.orientation.data.alpha,e._betaAvailable=l.orientation.data.beta&&null!==l.orientation.data.beta,e._gammaAvailable=l.orientation.data.gamma&&null!==l.orientation.data.gamma,b(e)})["catch"](function(){e.stop(),d("DeviceOrientation is not supported")})});return b},t.getDeviceMotion=function(a){var b=new Promise(function(b,d){var e=new t.DeviceMotion(a);e.start();var f=new c(l.motion);f.then(function(){e._accelerationXAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.x,e._accelerationYAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.y,e._accelerationZAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.z,e._accelerationIncludingGravityXAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.x,e._accelerationIncludingGravityYAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.y,e._accelerationIncludingGravityZAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.z,e._rotationRateAlphaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.alpha,e._rotationRateBetaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.beta,e._rotationRateGammaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.gamma,b(e)})["catch"](function(){e.stop(),d("DeviceMotion is not supported")})});return b},t.Quaternion=function(a,c,d,e){var f;this.set=function(a,b,c,d){this.x=a||0,this.y=b||0,this.z=c||0,this.w=d||1},this.copy=function(a){this.x=a.x,this.y=a.y,this.z=a.z,this.w=a.w},this.setFromEuler=function(){var a,b,c,d,e,f,g,h,i,k,l,m;return function(n){return n=n||{},c=(n.alpha||0)*j,a=(n.beta||0)*j,b=(n.gamma||0)*j,f=c/2,d=a/2,e=b/2,g=Math.cos(d),h=Math.cos(e),i=Math.cos(f),k=Math.sin(d),l=Math.sin(e),m=Math.sin(f),this.set(k*h*i-g*l*m,g*l*i+k*h*m,g*h*m+k*l*i,g*h*i-k*l*m),this.normalize(),this}}(),this.setFromRotationMatrix=function(){var a;return function(c){return a=c.elements,this.set(.5*Math.sqrt(1+a[0]-a[4]-a[8])*b(a[7]-a[5]),.5*Math.sqrt(1-a[0]+a[4]-a[8])*b(a[2]-a[6]),.5*Math.sqrt(1-a[0]-a[4]+a[8])*b(a[3]-a[1]),.5*Math.sqrt(1+a[0]+a[4]+a[8])),this}}(),this.multiply=function(a){return f=t.Quaternion.prototype.multiplyQuaternions(this,a),this.copy(f),this},this.rotateX=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[1,0,0],a),this.copy(f),this},this.rotateY=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[0,1,0],a),this.copy(f),this},this.rotateZ=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[0,0,1],a),this.copy(f),this},this.normalize=function(){return t.Quaternion.prototype.normalize(this)},this.set(a,c,d,e)},t.Quaternion.prototype={constructor:t.Quaternion,multiplyQuaternions:function(){var a=new t.Quaternion;return function(b,c){var d=b.x,e=b.y,f=b.z,g=b.w,h=c.x,i=c.y,j=c.z,k=c.w;return a.set(d*k+g*h+e*j-f*i,e*k+g*i+f*h-d*j,f*k+g*j+d*i-e*h,g*k-d*h-e*i-f*j),a}}(),normalize:function(a){var b=Math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z+a.w*a.w);return 0===b?(a.x=0,a.y=0,a.z=0,a.w=1):(b=1/b,a.x*=b,a.y*=b,a.z*=b,a.w*=b),a},rotateByAxisAngle:function(){var a,b,c=new t.Quaternion,d=new t.Quaternion;return function(e,f,g){return a=(g||0)/2,b=Math.sin(a),d.set((f[0]||0)*b,(f[1]||0)*b,(f[2]||0)*b,Math.cos(a)),c=t.Quaternion.prototype.multiplyQuaternions(e,d),t.Quaternion.prototype.normalize(c)}}()},t.RotationMatrix=function(a,b,c,d,e,f,g,h,i){var k;this.elements=new Float32Array(9),this.identity=function(){return this.set(1,0,0,0,1,0,0,0,1),this},this.set=function(a,b,c,d,e,f,g,h,i){this.elements[0]=a||1,this.elements[1]=b||0,this.elements[2]=c||0,this.elements[3]=d||0,this.elements[4]=e||1,this.elements[5]=f||0,this.elements[6]=g||0,this.elements[7]=h||0,this.elements[8]=i||1},this.copy=function(a){this.elements[0]=a.elements[0],this.elements[1]=a.elements[1],this.elements[2]=a.elements[2],this.elements[3]=a.elements[3],this.elements[4]=a.elements[4],this.elements[5]=a.elements[5],this.elements[6]=a.elements[6],this.elements[7]=a.elements[7],this.elements[8]=a.elements[8]},this.setFromEuler=function(){var a,b,c,d,e,f,g,h,i;return function(k){return k=k||{},c=(k.alpha||0)*j,a=(k.beta||0)*j,b=(k.gamma||0)*j,d=Math.cos(a),e=Math.cos(b),f=Math.cos(c),g=Math.sin(a),h=Math.sin(b),i=Math.sin(c),this.set(f*e-i*g*h,-d*i,e*i*g+f*h,e*i+f*g*h,f*d,i*h-f*e*g,-d*h,g,d*e),this.normalize(),this}}(),this.setFromQuaternion=function(){var a,b,c,d;return function(e){return a=e.w*e.w,b=e.x*e.x,c=e.y*e.y,d=e.z*e.z,this.set(a+b-c-d,2*(e.x*e.y-e.w*e.z),2*(e.x*e.z+e.w*e.y),2*(e.x*e.y+e.w*e.z),a-b+c-d,2*(e.y*e.z-e.w*e.x),2*(e.x*e.z-e.w*e.y),2*(e.y*e.z+e.w*e.x),a-b-c+d),this}}(),this.multiply=function(a){return k=t.RotationMatrix.prototype.multiplyMatrices(this,a),this.copy(k),this},this.rotateX=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[1,0,0],a),this.copy(k),this},this.rotateY=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[0,1,0],a),this.copy(k),this},this.rotateZ=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[0,0,1],a),this.copy(k),this},this.normalize=function(){return t.RotationMatrix.prototype.normalize(this)},this.set(a,b,c,d,e,f,g,h,i)},t.RotationMatrix.prototype={constructor:t.RotationMatrix,multiplyMatrices:function(){var a,b,c=new t.RotationMatrix;return function(d,e){return a=d.elements,b=e.elements,c.set(a[0]*b[0]+a[1]*b[3]+a[2]*b[6],a[0]*b[1]+a[1]*b[4]+a[2]*b[7],a[0]*b[2]+a[1]*b[5]+a[2]*b[8],a[3]*b[0]+a[4]*b[3]+a[5]*b[6],a[3]*b[1]+a[4]*b[4]+a[5]*b[7],a[3]*b[2]+a[4]*b[5]+a[5]*b[8],a[6]*b[0]+a[7]*b[3]+a[8]*b[6],a[6]*b[1]+a[7]*b[4]+a[8]*b[7],a[6]*b[2]+a[7]*b[5]+a[8]*b[8]),c}}(),normalize:function(a){var b=a.elements,c=b[0]*b[4]*b[8]-b[0]*b[5]*b[7]-b[1]*b[3]*b[8]+b[1]*b[5]*b[6]+b[2]*b[3]*b[7]-b[2]*b[4]*b[6];return b[0]/=c,b[1]/=c,b[2]/=c,b[3]/=c,b[4]/=c,b[5]/=c,b[6]/=c,b[7]/=c,b[8]/=c,a.elements=b,a},rotateByAxisAngle:function(){var a,b,c=new t.RotationMatrix,d=new t.RotationMatrix,e=!1;return function(f,g,h){return d.identity(),e=!1,a=Math.sin(h),b=Math.cos(h),1===g[0]&&0===g[1]&&0===g[2]?(e=!0,d.elements[4]=b,d.elements[5]=-a,d.elements[7]=a,d.elements[8]=b):1===g[1]&&0===g[0]&&0===g[2]?(e=!0,d.elements[0]=b,d.elements[2]=a,d.elements[6]=-a,d.elements[8]=b):1===g[2]&&0===g[0]&&0===g[1]&&(e=!0,d.elements[0]=b,d.elements[1]=-a,d.elements[3]=a,d.elements[4]=b),e?(c=t.RotationMatrix.prototype.multiplyMatrices(f,d),c=t.RotationMatrix.prototype.normalize(c)):c=f,c}}()},t.Euler=function(a,b,c){this.set=function(a,b,c){this.alpha=a||0,this.beta=b||0,this.gamma=c||0},this.copy=function(a){this.alpha=a.alpha,this.beta=a.beta,this.gamma=a.gamma},this.setFromRotationMatrix=function(){var a,b,c,d;return function(e){a=e.elements,a[8]>0?(b=Math.atan2(-a[1],a[4]),c=Math.asin(a[7]),d=Math.atan2(-a[6],a[8])):a[8]<0?(b=Math.atan2(a[1],-a[4]),c=-Math.asin(a[7]),c+=c>=0?-g:g,d=Math.atan2(a[6],-a[8])):a[6]>0?(b=Math.atan2(-a[1],a[4]),c=Math.asin(a[7]),d=-h):a[6]<0?(b=Math.atan2(a[1],-a[4]),c=-Math.asin(a[7]),c+=c>=0?-g:g,d=-h):(b=Math.atan2(a[3],a[0]),c=a[7]>0?h:-h,d=0),0>b&&(b+=i),b*=k,c*=k,d*=k,this.set(b,c,d)}}(),this.setFromQuaternion=function(){var a,b,c;return function(d){var e=d.w*d.w,f=d.x*d.x,j=d.y*d.y,l=d.z*d.z,m=e+f+j+l,n=d.w*d.x+d.y*d.z,o=1e-6;if(n>(.5-o)*m)a=2*Math.atan2(d.y,d.w),b=h,c=0;else if((-.5+o)*m>n)a=-2*Math.atan2(d.y,d.w),b=-h,c=0;else{var p=e-f+j-l,q=2*(d.w*d.z-d.x*d.y),r=e-f-j+l,s=2*(d.w*d.y-d.x*d.z);r>0?(a=Math.atan2(q,p),b=Math.asin(2*n/m),c=Math.atan2(s,r)):(a=Math.atan2(-q,-p),b=-Math.asin(2*n/m),b+=0>b?g:-g,c=Math.atan2(-s,-r))}0>a&&(a+=i),a*=k,b*=k,c*=k,this.set(a,b,c)}}(),this.rotateX=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[1,0,0],a),this},this.rotateY=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[0,1,0],a),this},this.rotateZ=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[0,0,1],a),this},this.set(a,b,c)},t.Euler.prototype={constructor:t.Euler,rotateByAxisAngle:function(){var a=new t.RotationMatrix;return function(b,c,d){return a.setFromEuler(b),a=t.RotationMatrix.prototype.rotateByAxisAngle(a,c,d),b.setFromRotationMatrix(a),b}}()},t.DeviceOrientation=function(b){this.options=b||{};var c=0,d=200,e=0,f=10;if(this.alphaOffsetScreen=0,this.alphaOffsetDevice=void 0,"game"===this.options.type){var g=function(b){return null!==b.alpha&&(this.alphaOffsetDevice=new t.Euler(b.alpha,0,0),this.alphaOffsetDevice.rotateZ(-o),++e>=f)?void a.removeEventListener("deviceorientation",g,!1):void(++c>=d&&a.removeEventListener("deviceorientation",g,!1))}.bind(this);a.addEventListener("deviceorientation",g,!1)}else if("world"===this.options.type){var h=function(b){return b.absolute!==!0&&void 0!==b.webkitCompassAccuracy&&null!==b.webkitCompassAccuracy&&+b.webkitCompassAccuracy>=0&&+b.webkitCompassAccuracy<50&&(this.alphaOffsetDevice=new t.Euler(b.webkitCompassHeading,0,0),this.alphaOffsetDevice.rotateZ(o),this.alphaOffsetScreen=o,++e>=f)?void a.removeEventListener("deviceorientation",h,!1):void(++c>=d&&a.removeEventListener("deviceorientation",h,!1))}.bind(this);a.addEventListener("deviceorientation",h,!1)}},t.DeviceOrientation.prototype={constructor:t.DeviceOrientation,start:function(b){b&&"[object Function]"==Object.prototype.toString.call(b)&&l.orientation.callbacks.push(b),m||(n?a.screen.orientation.addEventListener("change",d,!1):a.addEventListener("orientationchange",d,!1)),l.orientation.active||(a.addEventListener("deviceorientation",e,!1),l.orientation.active=!0)},stop:function(){l.orientation.active&&(a.removeEventListener("deviceorientation",e,!1),l.orientation.active=!1)},listen:function(a){this.start(a)},getFixedFrameQuaternion:function(){var a=new t.Euler,b=new t.RotationMatrix,c=new t.Quaternion;return function(){var d=l.orientation.data||{alpha:0,beta:0,gamma:0},e=d.alpha;return this.alphaOffsetDevice&&(b.setFromEuler(this.alphaOffsetDevice),b.rotateZ(-this.alphaOffsetScreen),a.setFromRotationMatrix(b),a.alpha<0&&(a.alpha+=360),a.alpha%=360,e-=a.alpha),a.set(e,d.beta,d.gamma),c.setFromEuler(a),c}}(),getScreenAdjustedQuaternion:function(){var a;return function(){return a=this.getFixedFrameQuaternion(),a.rotateZ(-o),a}}(),getFixedFrameMatrix:function(){var a=new t.Euler,b=new t.RotationMatrix;return function(){var c=l.orientation.data||{alpha:0,beta:0,gamma:0},d=c.alpha;return this.alphaOffsetDevice&&(b.setFromEuler(this.alphaOffsetDevice),b.rotateZ(-this.alphaOffsetScreen),a.setFromRotationMatrix(b),a.alpha<0&&(a.alpha+=360),a.alpha%=360,d-=a.alpha),a.set(d,c.beta,c.gamma),b.setFromEuler(a),b}}(),getScreenAdjustedMatrix:function(){var a;return function(){return a=this.getFixedFrameMatrix(),a.rotateZ(-o),a}}(),getFixedFrameEuler:function(){var a,b=new t.Euler;return function(){return a=this.getFixedFrameMatrix(),b.setFromRotationMatrix(a),b}}(),getScreenAdjustedEuler:function(){var a,b=new t.Euler;return function(){return a=this.getScreenAdjustedMatrix(),b.setFromRotationMatrix(a),b}}(),isAbsolute:function(){return l.orientation.data&&l.orientation.data.absolute===!0?!0:!1},getLastRawEventData:function(){return l.orientation.data||{}},_alphaAvailable:!1,_betaAvailable:!1,_gammaAvailable:!1,isAvailable:function(a){switch(a){case this.ALPHA:return this._alphaAvailable;case this.BETA:return this._betaAvailable;case this.GAMMA:return this._gammaAvailable}},ALPHA:"alpha",BETA:"beta",GAMMA:"gamma"},t.DeviceMotion=function(a){this.options=a||{}},t.DeviceMotion.prototype={constructor:t.DeviceMotion,start:function(b){b&&"[object Function]"==Object.prototype.toString.call(b)&&l.motion.callbacks.push(b),m||(n?a.screen.orientation.addEventListener("change",d,!1):a.addEventListener("orientationchange",d,!1)),l.motion.active||(a.addEventListener("devicemotion",f,!1),l.motion.active=!0)},stop:function(){l.motion.active&&(a.removeEventListener("devicemotion",f,!1),l.motion.active=!1)},listen:function(a){this.start(a)},getScreenAdjustedAcceleration:function(){var a=l.motion.data&&l.motion.data.acceleration?l.motion.data.acceleration:{x:0,y:0,z:0},b={};switch(o){case p:b.x=-a.y,b.y=a.x;break;case q:b.x=-a.x,b.y=-a.y;break;case r:case s:b.x=a.y,b.y=-a.x;break;default:b.x=a.x,b.y=a.y}return b.z=a.z,b},getScreenAdjustedAccelerationIncludingGravity:function(){var a=l.motion.data&&l.motion.data.accelerationIncludingGravity?l.motion.data.accelerationIncludingGravity:{x:0,y:0,z:0},b={};switch(o){case p:b.x=-a.y,b.y=a.x;break;case q:b.x=-a.x,b.y=-a.y;break;case r:case s:b.x=a.y,b.y=-a.x;break;default:b.x=a.x,b.y=a.y}return b.z=a.z,b},getScreenAdjustedRotationRate:function(){var a=l.motion.data&&l.motion.data.rotationRate?l.motion.data.rotationRate:{alpha:0,beta:0,gamma:0},b={};switch(o){case p:b.beta=-a.gamma,b.gamma=a.beta;break;case q:b.beta=-a.beta,b.gamma=-a.gamma;break;case r:case s:b.beta=a.gamma,b.gamma=-a.beta;break;default:b.beta=a.beta,b.gamma=a.gamma}return b.alpha=a.alpha,b},getLastRawEventData:function(){return l.motion.data||{}},_accelerationXAvailable:!1,_accelerationYAvailable:!1,_accelerationZAvailable:!1,_accelerationIncludingGravityXAvailable:!1,_accelerationIncludingGravityYAvailable:!1,_accelerationIncludingGravityZAvailable:!1,_rotationRateAlphaAvailable:!1,_rotationRateBetaAvailable:!1,_rotationRateGammaAvailable:!1,isAvailable:function(a){switch(a){case this.ACCELERATION_X:return this._accelerationXAvailable;case this.ACCELERATION_Y:return this._accelerationYAvailable;case this.ACCELERATION_Z:return this._accelerationZAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_X:return this._accelerationIncludingGravityXAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_Y:return this._accelerationIncludingGravityYAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_Z:return this._accelerationIncludingGravityZAvailable;case this.ROTATION_RATE_ALPHA:return this._rotationRateAlphaAvailable;case this.ROTATION_RATE_BETA:return this._rotationRateBetaAvailable;case this.ROTATION_RATE_GAMMA:return this._rotationRateGammaAvailable}},ACCELERATION_X:"accelerationX",ACCELERATION_Y:"accelerationY",ACCELERATION_Z:"accelerationZ",ACCELERATION_INCLUDING_GRAVITY_X:"accelerationIncludingGravityX",ACCELERATION_INCLUDING_GRAVITY_Y:"accelerationIncludingGravityY",ACCELERATION_INCLUDING_GRAVITY_Z:"accelerationIncludingGravityZ",ROTATION_RATE_ALPHA:"rotationRateAlpha",ROTATION_RATE_BETA:"rotationRateBeta",ROTATION_RATE_GAMMA:"rotationRateGamma"},a.FULLTILT=t}}(window);
3 |
4 | /* gyronorm.js v2.0.6 - https://github.com/dorukeker/gyronorm.git*/
5 | !function(a,b){var c={GyroNorm:b()};"function"==typeof define&&define.amd?define(function(){return c}):"object"==typeof module&&module.exports?module.exports=c:a.GyroNorm=c.GyroNorm}(this,function(){function a(a){return Math.round(a*Math.pow(10,t))/Math.pow(10,t)}function b(){var b={};b=v?o.getScreenAdjustedEuler():o.getFixedFrameEuler();var c=p.getScreenAdjustedAcceleration(),e=p.getScreenAdjustedAccelerationIncludingGravity(),f=p.getScreenAdjustedRotationRate(),g=0;s===d?(g=b.alpha-k,g=0>g?360-Math.abs(g):g):g=b.alpha;var h={"do":{alpha:a(g),beta:a(b.beta),gamma:a(b.gamma),absolute:o.isAbsolute()},dm:{x:a(c.x),y:a(c.y),z:a(c.z),gx:a(e.x),gy:a(e.y),gz:a(e.z),alpha:a(f.alpha),beta:a(f.beta),gamma:a(f.gamma)}};return r&&(h.dm.gx*=l,h.dm.gy*=l,h.dm.gz*=l),h}function c(a){u&&("string"==typeof a&&(a={message:a,code:0}),u(a))}var d="game",e="world",f="deviceorientation",g="acceleration",h="accelerationinludinggravity",i="rotationrate",j=null,k=0,l=0,m=!1,n=!1,o=null,p=null,q=50,r=!0,s=d,t=2,u=null,v=!1,w=function(a){};return w.GAME=d,w.WORLD=e,w.DEVICE_ORIENTATION=f,w.ACCELERATION=g,w.ACCELERATION_INCLUDING_GRAVITY=h,w.ROTATION_RATE=i,w.prototype.init=function(a){a&&a.frequency&&(q=a.frequency),a&&a.gravityNormalized&&(r=a.gravityNormalized),a&&a.orientationBase&&(s=a.orientationBase),a&&"number"==typeof a.decimalCount&&a.decimalCount>=0&&(t=parseInt(a.decimalCount)),a&&a.logger&&(u=a.logger),a&&a.screenAdjusted&&(v=a.screenAdjusted);var b=new FULLTILT.getDeviceOrientation({type:s}).then(function(a){o=a}),c=(new FULLTILT.getDeviceMotion).then(function(a){p=a,l=p.getScreenAdjustedAccelerationIncludingGravity().z>0?-1:1});return Promise.all([b,c]).then(function(){n=!0})},w.prototype.end=function(){try{n=!1,this.stop(),p.stop(),o.stop()}catch(a){c(a)}},w.prototype.start=function(a){return n?(j=setInterval(function(){a(b())},q),void(m=!0)):void c({message:'GyroNorm is not initialized yet. First call the "init()" function.',code:1})},w.prototype.stop=function(){j&&(clearInterval(j),m=!1)},w.prototype.normalizeGravity=function(a){r=a?!0:!1},w.prototype.setHeadDirection=function(){return v||s===e?!1:(k=o.getFixedFrameEuler().alpha,!0)},w.prototype.startLogging=function(a){a&&(u=a)},w.prototype.stopLogging=function(){u=null},w.prototype.isAvailable=function(a){var b=o.getScreenAdjustedEuler(),c=p.getScreenAdjustedAcceleration(),d=p.getScreenAdjustedAccelerationIncludingGravity(),e=p.getScreenAdjustedRotationRate();switch(a){case f:return b.alpha&&null!==b.alpha&&b.beta&&null!==b.beta&&b.gamma&&null!==b.gamma;case g:return c&&c.x&&c.y&&c.z;case h:return d&&d.x&&d.y&&d.z;case i:return e&&e.alpha&&e.beta&&e.gamma;default:return{deviceOrientationAvailable:b.alpha&&null!==b.alpha&&b.beta&&null!==b.beta&&b.gamma&&null!==b.gamma,accelerationAvailable:c&&c.x&&c.y&&c.z,accelerationIncludingGravityAvailable:d&&d.x&&d.y&&d.z,rotationRateAvailable:e&&e.alpha&&e.beta&&e.gamma}}},w.prototype.isRunning=function(){return m},w});
--------------------------------------------------------------------------------
/frontend/public/js/jquery.qrcode.js:
--------------------------------------------------------------------------------
1 | (function( $ ){
2 | $.fn.qrcode = function(options) {
3 | // if options is string,
4 | if( typeof options === 'string' ){
5 | options = { text: options };
6 | }
7 |
8 | // set default values
9 | // typeNumber < 1 for automatic calculation
10 | options = $.extend( {}, {
11 | render : "canvas",
12 | width : 256,
13 | height : 256,
14 | typeNumber : -1,
15 | correctLevel : QRErrorCorrectLevel.H,
16 | background : "#ffffff",
17 | foreground : "#000000"
18 | }, options);
19 |
20 | var createCanvas = function(){
21 | // create the qrcode itself
22 | var qrcode = new QRCode(options.typeNumber, options.correctLevel);
23 | qrcode.addData(options.text);
24 | qrcode.make();
25 |
26 | // create canvas element
27 | var canvas = document.createElement('canvas');
28 | canvas.width = options.width;
29 | canvas.height = options.height;
30 | var ctx = canvas.getContext('2d');
31 |
32 | // compute tileW/tileH based on options.width/options.height
33 | var tileW = options.width / qrcode.getModuleCount();
34 | var tileH = options.height / qrcode.getModuleCount();
35 |
36 | // draw in the canvas
37 | for( var row = 0; row < qrcode.getModuleCount(); row++ ){
38 | for( var col = 0; col < qrcode.getModuleCount(); col++ ){
39 | ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
40 | var w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW));
41 | var h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW));
42 | ctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h);
43 | }
44 | }
45 | // return just built canvas
46 | return canvas;
47 | }
48 |
49 | // from Jon-Carlos Rivera (https://github.com/imbcmdth)
50 | var createTable = function(){
51 | // create the qrcode itself
52 | var qrcode = new QRCode(options.typeNumber, options.correctLevel);
53 | qrcode.addData(options.text);
54 | qrcode.make();
55 |
56 | // create table element
57 | var $table = $('')
58 | .css("width", options.width+"px")
59 | .css("height", options.height+"px")
60 | .css("border", "0px")
61 | .css("border-collapse", "collapse")
62 | .css('background-color', options.background);
63 |
64 | // compute tileS percentage
65 | var tileW = options.width / qrcode.getModuleCount();
66 | var tileH = options.height / qrcode.getModuleCount();
67 |
68 | // draw in the table
69 | for(var row = 0; row < qrcode.getModuleCount(); row++ ){
70 | var $row = $(' ').css('height', tileH+"px").appendTo($table);
71 |
72 | for(var col = 0; col < qrcode.getModuleCount(); col++ ){
73 | $(' ')
74 | .css('width', tileW+"px")
75 | .css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background)
76 | .appendTo($row);
77 | }
78 | }
79 | // return just built canvas
80 | return $table;
81 | }
82 |
83 |
84 | return this.each(function(){
85 | var element = options.render == "canvas" ? createCanvas() : createTable();
86 | jQuery(element).appendTo(this);
87 | });
88 | };
89 | })( jQuery );
90 |
--------------------------------------------------------------------------------
/frontend/public/js/player.js:
--------------------------------------------------------------------------------
1 | P.player = (function () {
2 | 'use strict';
3 |
4 | var aspectX;
5 | var aspectY;
6 | var resolutionX = 480;
7 | var resolutionY = 360;
8 |
9 | var stage;
10 | var frameId = null;
11 | var isFullScreen = false;
12 |
13 | var progressBar = document.querySelector('.progress-bar');
14 | var player = document.querySelector('.player');
15 | var projectLink = document.querySelector('.project-link');
16 | var bugLink = document.querySelector('#bug-link');
17 |
18 | var controls = document.querySelector('.controls');
19 | var flag = document.querySelector('.flag');
20 | var turbo = document.querySelector('.turbo');
21 | var pause = document.querySelector('.pause');
22 | var stop = document.querySelector('.stop');
23 | var fullScreen = document.querySelector('.full-screen');
24 |
25 | var error = document.querySelector('.internal-error');
26 | var errorBugLink = document.querySelector('#error-bug-link');
27 |
28 | var webGLError = document.querySelector('.webgl-error');
29 | var legacyLink = document.querySelector('#legacy-link');
30 |
31 | var flagTouchTimeout;
32 |
33 | function setResolution(resX, resY) {
34 | resolutionX = resX;
35 | resolutionY = resY;
36 | player.style.width = resolutionX + 'px';
37 | player.style.height = resolutionY + 'px'
38 | }
39 |
40 | function flagTouchStart() {
41 | flagTouchTimeout = setTimeout(function () {
42 | turboClick();
43 | flagTouchTimeout = true;
44 | }, 500);
45 | }
46 | function turboClick() {
47 | stage.isTurbo = !stage.isTurbo;
48 | flag.title = stage.isTurbo ? 'Turbo mode enabled. Shift+click to disable.' : 'Shift+click to enable turbo mode.';
49 | turbo.style.display = stage.isTurbo ? 'block' : 'none';
50 | }
51 | function flagClick(e) {
52 | if (!stage) return;
53 | if (flagTouchTimeout === true) return;
54 | if (flagTouchTimeout) {
55 | clearTimeout(flagTouchTimeout);
56 | }
57 | if (e.shiftKey) {
58 | turboClick();
59 | } else {
60 | stage.start();
61 | pause.className = 'pause';
62 | stage.stopAll();
63 | stage.triggerGreenFlag();
64 | }
65 | stage.focus();
66 | e.preventDefault();
67 | }
68 |
69 | function pauseClick(e) {
70 | if (!stage) return;
71 | if (stage.isRunning) {
72 | stage.pause();
73 | pause.className = 'play';
74 | } else {
75 | stage.start();
76 | pause.className = 'pause';
77 | }
78 | stage.focus();
79 | e.preventDefault();
80 | }
81 |
82 | function stopClick(e) {
83 |
84 | console.log('stop');
85 |
86 | if (!stage) return;
87 | stage.start();
88 | pause.className = 'pause';
89 | stage.stopAll();
90 | stage.focus();
91 | e.preventDefault();
92 | }
93 |
94 | function fullScreenClick(e) {
95 | if (e) e.preventDefault();
96 | if (!stage) return;
97 | document.documentElement.classList.toggle('fs');
98 | isFullScreen = !isFullScreen;
99 | if (!e || !e.shiftKey) {
100 | if (isFullScreen) {
101 | var el = document.documentElement;
102 | if (el.requestFullScreenWithKeys) {
103 | el.requestFullScreenWithKeys();
104 | } else if (el.webkitRequestFullScreen) {
105 | el.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
106 | }
107 | else if (el.mozRequestFullScreen) {
108 | el.mozRequestFullScreen();
109 | }
110 | else {
111 | console.warn("No full screen available.");
112 | }
113 | } else {
114 | if (document.exitFullscreen) {
115 | document.exitFullscreen();
116 | } else if (document.mozCancelFullScreen) {
117 | document.mozCancelFullScreen();
118 | } else if (document.webkitCancelFullScreen) {
119 | document.webkitCancelFullScreen();
120 | }
121 | }
122 | }
123 | if (!isFullScreen) {
124 | document.body.style.width = resolutionX + 'px';
125 | document.body.style.height =
126 | document.body.style.marginLeft =
127 | document.body.style.marginTop = '';
128 | }
129 | updateFullScreen();
130 | if (!stage.isRunning) {
131 | stage.draw();
132 | }
133 | stage.focus();
134 | }
135 |
136 | function exitFullScreen(e) {
137 | if (isFullScreen && e.keyCode === 27) {
138 | fullScreenClick(e);
139 | }
140 | }
141 |
142 | function updateFullScreen() {
143 | if (!stage) return;
144 | if (isFullScreen) {
145 | window.scrollTo(0, 0);
146 | var padding = 8;
147 | var w = window.innerWidth - padding * 2;
148 | var h = window.innerHeight - padding - controls.offsetHeight;
149 | w = Math.min(w, h * resolutionX / resolutionY);
150 | h = w * resolutionY / resolutionX + controls.offsetHeight;
151 | document.body.style.width = w + 'px';
152 | document.body.style.height = h + 'px';
153 | document.body.style.marginLeft = (window.innerWidth - w) / 2 + 'px';
154 | document.body.style.marginTop = (window.innerHeight - h + padding) / 2 + 'px';
155 | stage.setZoom(w / 480, w * resolutionY / resolutionX / 360);
156 | } else {
157 | stage.setZoom(resolutionX ? resolutionX / 480 : 1, resolutionY ? resolutionY / 360 : 1);
158 | }
159 | }
160 |
161 | function preventDefault(e) {
162 | e.preventDefault();
163 | }
164 |
165 | window.addEventListener('resize', updateFullScreen);
166 | if (P.hasTouchEvents) {
167 | flag.addEventListener('touchstart', flagTouchStart);
168 | flag.addEventListener('touchend', flagClick);
169 | pause.addEventListener('touchend', pauseClick);
170 | stop.addEventListener('touchend', stopClick);
171 | fullScreen.addEventListener('touchend', fullScreenClick);
172 |
173 | flag.addEventListener('touchstart', preventDefault);
174 | pause.addEventListener('touchstart', preventDefault);
175 | stop.addEventListener('touchstart', preventDefault);
176 | fullScreen.addEventListener('touchstart', preventDefault);
177 |
178 | document.addEventListener('touchmove', function (e) {
179 | if (isFullScreen) e.preventDefault();
180 | });
181 | }
182 |
183 | flag.addEventListener('click', flagClick);
184 | pause.addEventListener('click', pauseClick);
185 | stop.addEventListener('click', stopClick);
186 | fullScreen.addEventListener('click', fullScreenClick);
187 |
188 |
189 | document.addEventListener("fullscreenchange", function () {
190 | if (isFullScreen !== document.fullscreen) fullScreenClick();
191 | });
192 | document.addEventListener("mozfullscreenchange", function () {
193 | if (isFullScreen !== document.mozFullScreen) fullScreenClick();
194 | });
195 | document.addEventListener("webkitfullscreenchange", function () {
196 | if (isFullScreen !== document.webkitIsFullScreen) fullScreenClick();
197 | });
198 |
199 | async function load(id, cb, titleCallback) {
200 |
201 |
202 | socket.emit('getProjectData', id, async function (projectData) {
203 |
204 |
205 |
206 | // console.log(projectData)
207 |
208 |
209 | P.player.projectId = id;
210 | P.player.projectURL = id ? 'https://scratch.mit.edu/projects/' + id + '?token=' + projectData.project_token : '';
211 |
212 | if (stage) {
213 | stage.stopAll();
214 | stage.pause();
215 | }
216 | while (player.firstChild) player.removeChild(player.lastChild);
217 | turbo.style.display = 'none';
218 | error.style.display = 'none';
219 | webGLError.style.display = 'none';
220 | pause.className = 'pause';
221 | progressBar.style.display = 'none';
222 |
223 |
224 |
225 |
226 | if (await isSB2(projectData)) {
227 | socket.emit("logRequest", { "id": id, "version": "2" })
228 |
229 | showProgress(P.IO.loadScratchr2Project(id, projectData.project_token), cb);
230 | P.IO.loadScratchr2ProjectTitle(id, function (title) {
231 | if (titleCallback) titleCallback(P.player.projectTitle = title);
232 | });
233 | } else {
234 | socket.emit("logRequest", { "id": id, "version": "3" })
235 | socket.emit("sendSB3ID", id);
236 | document.getElementById("sb3loading").innerHTML = "loading...."
237 | if (titleCallback) setTimeout(function () {
238 | titleCallback('');
239 | });
240 | }
241 | });
242 | }
243 |
244 | function showError(e) {
245 | error.style.display = 'block';
246 | errorBugLink.href = 'https://github.com/nathan/phosphorus/issues/new?title=' + encodeURIComponent(P.player.projectTitle || P.player.projectURL) + '&body=' + encodeURIComponent('\n\n\n' + P.player.projectURL + '\nhttps://phosphorus.github.io/#' + P.player.projectId + '\n' + navigator.userAgent + (e.stack ? '\n\n```\n' + e.stack + '\n```' : ''));
247 | console.error(e);
248 | }
249 |
250 | function showWebGLError(e) {
251 | webGLError.style.display = 'block';
252 | if (document.querySelector('#player-area'))
253 | document.querySelector('#player-area').style.height = 'auto';
254 | legacyLink.href = 'https://sulfurous.aau.at/legacy/#' + P.player.projectId;
255 | console.error(e);
256 | }
257 |
258 | function showProgress(request, loadCallback) {
259 | progressBar.style.display = 'none';
260 | setTimeout(function () {
261 | progressBar.style.width = '10%';
262 | progressBar.className = 'progress-bar';
263 | progressBar.style.opacity = 1;
264 | progressBar.style.display = 'block';
265 | });
266 | request.onload = function (s) {
267 | progressBar.style.width = '100%';
268 | setTimeout(function () {
269 | progressBar.style.opacity = 0;
270 | setTimeout(function () {
271 | progressBar.style.display = 'none';
272 | }, 300);
273 | }, 100);
274 |
275 | var zoomX = stage ? stage.zoomX : 1;
276 | var zoomY = stage ? stage.zoomY : 1;
277 | zoomX = resolutionX ? resolutionX / 480 : zoomX;
278 | zoomY = resolutionY ? resolutionY / 360 : zoomY;
279 |
280 | window.stage = stage = s;
281 | stage.start();
282 | stage.setZoom(zoomX, zoomY);
283 |
284 | stage.root.addEventListener('keydown', exitFullScreen);
285 | stage.handleError = showError;
286 |
287 | player.appendChild(stage.root);
288 | stage.focus();
289 | if (loadCallback) {
290 | loadCallback(stage);
291 | loadCallback = null;
292 | }
293 | };
294 | request.onerror = function (e) {
295 | progressBar.style.width = '100%';
296 | progressBar.className = 'progress-bar error';
297 | console.error(e.stack);
298 | };
299 | request.onprogress = function (e) {
300 | progressBar.style.width = (10 + e.loaded / e.total * 90) + '%';
301 | };
302 | }
303 |
304 | P.showWebGLError = showWebGLError;
305 |
306 | return {
307 | load: load,
308 | showProgress: showProgress,
309 | setResolution: setResolution,
310 | };
311 |
312 |
313 | async function isSB2(projectData) {
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 | return new Promise(async function (resolve, reject) {
322 | // console.log(projectData)
323 |
324 |
325 | const response = await fetch("https://projects.scratch.mit.edu/" + projectData.id + "?token=" + projectData.project_token);
326 | const jsonData = await response.json();
327 |
328 | if(jsonData.targets == undefined){
329 | resolve(true)
330 | }else{
331 | resolve(false)
332 | }
333 |
334 | })
335 |
336 |
337 | }
338 |
339 | }());
--------------------------------------------------------------------------------
/frontend/public/js/shaders.js:
--------------------------------------------------------------------------------
1 | Shader = {};
2 |
3 | // Pen
4 |
5 | Shader.penVert = `
6 | precision mediump float;
7 |
8 | attribute vec4 vertexData;
9 | attribute vec2 lineData;
10 | attribute vec4 colorData;
11 |
12 | varying vec4 fragColor;
13 |
14 |
15 | //vertexData:
16 | //[0] = x1
17 | //[1] = y1
18 | //[2] = x2
19 | //[3] = y2
20 |
21 | //lineData:
22 | //[0] = thickened vertex direction
23 | //[1] = thickened vertex distance
24 |
25 | //colorData:
26 | //[0] = red
27 | //[1] = green
28 | //[2] = blue
29 | //[3] = alpha
30 |
31 |
32 |
33 | void main(){
34 |
35 | vec2 lineDir = normalize(vertexData.zw - vertexData.xy);
36 |
37 | mat2 rot;
38 | rot[0] = vec2(cos(lineData.x), sin(lineData.x));
39 | rot[1] = vec2(-sin(lineData.x), cos(lineData.x));
40 |
41 | lineDir *= rot * lineData.y;
42 |
43 | vec2 p = (vertexData.xy + lineDir);
44 | p.x /= 240.0;
45 | p.y /= 180.0;
46 |
47 | gl_Position = vec4(p, 0.0, 1.0);
48 | fragColor = colorData;
49 | }
50 | `;
51 |
52 |
53 | Shader.penFrag = `
54 | precision mediump float;
55 |
56 | varying vec4 fragColor;
57 |
58 | void main(){
59 |
60 | gl_FragColor = vec4(fragColor.xyz / 255.0, fragColor.w);
61 | }
62 | `;
63 |
64 |
65 | // DrawImage
66 |
67 | Shader.imgVert = `
68 | attribute vec2 position;
69 | attribute vec2 texcoord;
70 |
71 | uniform mat4 u_matrix;
72 |
73 | varying vec2 fragTexcoord;
74 |
75 | void main(){
76 | gl_Position = u_matrix * vec4(position, 0, 1);
77 | fragTexcoord = texcoord;
78 | }
79 | `;
80 |
81 | Shader.imgFrag = `
82 | precision mediump float;
83 |
84 | varying vec2 fragTexcoord;
85 |
86 | uniform sampler2D u_texture;
87 |
88 | uniform vec2 texSize;
89 |
90 | uniform vec2 colorEffect;
91 | uniform mat4 colorMatrix;
92 | // colorEffect[0] = brightness
93 | // colorEffect[1] = ghost
94 |
95 | uniform vec4 texEffect;
96 | // texEffect[0] = fisheye
97 | // texEffect[1] = whirl
98 | // texEffect[2] = pixelate
99 | // texEffect[3] = mosaic
100 |
101 | void main(){
102 |
103 | vec2 texCoord = fragTexcoord;
104 |
105 | vec2 m = vec2(0.5, 0.5);
106 | float d = distance(texCoord, m);
107 |
108 |
109 | //fisheye
110 | if(texEffect[0] != 0.0){
111 | texCoord = m + normalize(texCoord - m) * pow(0.5 / d, texEffect[0]) / 2.0;
112 | }
113 |
114 | //whirl
115 | if(texEffect[1] != 0.0){
116 | float d2 = max(0.5 - d, 0.0);
117 | float phi = atan(0.5 - texCoord.x, 0.5 - texCoord.y);
118 | texCoord = vec2(0.5 - sin(phi + texEffect[1] * d2) * d,
119 | 0.5 - cos(phi + texEffect[1] * d2) * d);
120 | }
121 |
122 | //pixelate
123 | if(texEffect[2] != 1.0){
124 | texCoord = vec2(floor(texCoord.x * texSize.x / texEffect[2]) / texSize.x * texEffect[2],
125 | floor(texCoord.y * texSize.y / texEffect[2]) / texSize.y * texEffect[2]);
126 | }
127 |
128 | //mosaic
129 | if(texEffect[3] != 1.0){
130 | texCoord = vec2(mod(texCoord.x * texEffect[3], 1.0),
131 | mod(texCoord.y * texEffect[3], 1.0));
132 | }
133 |
134 | vec4 c = texture2D(u_texture, texCoord);
135 |
136 | gl_FragColor = vec4(c.xyz + colorEffect.x, c.w) * colorEffect.y * colorMatrix;
137 | }
138 | `;
139 |
140 | /*
141 | Shader.imgVert = `
142 | attribute vec2 position;
143 | attribute vec2 texcoord;
144 |
145 | uniform mat4 u_matrix;
146 |
147 | varying vec2 fragTexcoord;
148 |
149 | void main(){
150 | gl_Position = u_matrix * vec4(position, 0, 1);
151 | fragTexcoord = texcoord;
152 | }
153 | `;
154 |
155 | Shader.imgFrag = `
156 | precision mediump float;
157 |
158 | varying vec2 fragTexcoord;
159 |
160 | uniform sampler2D u_texture;
161 |
162 | void main(){
163 | gl_FragColor = texture2D(u_texture, fragTexcoord);
164 | //gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
165 | }
166 | `;
167 | */
168 |
169 | Shader.touchingVert = `
170 | attribute vec2 position;
171 | attribute vec2 texcoord;
172 |
173 | uniform mat4 u_matrix;
174 |
175 | varying vec2 fragTexcoord;
176 |
177 | void main(){
178 | gl_Position = u_matrix * vec4(position, 0, 1);
179 | fragTexcoord = texcoord;
180 | }
181 | `;
182 |
183 | Shader.touchingFrag = `
184 | precision mediump float;
185 |
186 | varying vec2 fragTexcoord;
187 |
188 | uniform sampler2D u_texture;
189 |
190 | uniform vec4 tColor;
191 |
192 | uniform vec2 texSize;
193 |
194 | uniform vec2 colorEffect;
195 | uniform mat4 colorMatrix;
196 | // colorEffect[0] = brightness
197 | // colorEffect[1] = ghost
198 |
199 | uniform vec4 texEffect;
200 | // texEffect[0] = fisheye
201 | // texEffect[1] = whirl
202 | // texEffect[2] = pixelate
203 | // texEffect[3] = mosaic
204 |
205 | void main(){
206 | vec2 texCoord = fragTexcoord;
207 |
208 | vec2 m = vec2(0.5, 0.5);
209 | float d = distance(texCoord, m);
210 |
211 | //fisheye
212 | if(texEffect[0] != 0.0){
213 | texCoord = m + normalize(texCoord - m) * pow(0.5 / d, texEffect[0]) / 2.0;
214 | }
215 |
216 | //whirl
217 | if(texEffect[1] != 0.0){
218 | float d2 = max(0.5 - d, 0.0);
219 | float phi = atan(0.5 - texCoord.x, 0.5 - texCoord.y);
220 | texCoord = vec2(0.5 - sin(phi + texEffect[1] * d2) * d,
221 | 0.5 - cos(phi + texEffect[1] * d2) * d);
222 | }
223 |
224 | //pixelate
225 | if(texEffect[2] != 1.0){
226 | texCoord = vec2(floor(texCoord.x * texSize.x / texEffect[2]) / texSize.x * texEffect[2],
227 | floor(texCoord.y * texSize.y / texEffect[2]) / texSize.y * texEffect[2]);
228 | }
229 |
230 | //mosaic
231 | if(texEffect[3] != 1.0){
232 | texCoord = vec2(mod(texCoord.x * texEffect[3], 1.0),
233 | mod(texCoord.y * texEffect[3], 1.0));
234 | }
235 |
236 | vec4 c = texture2D(u_texture, texCoord);
237 |
238 | if(tColor.w == 1.0 && c.xyz == tColor.xyz && c.w != 0.0){
239 | c = vec4(1.0, 1.0, 1.0, 1.0);
240 | }
241 | else if(tColor.w == 0.0 && c.w > 0.0){
242 | c = vec4(1.0, 1.0, 1.0, 1.0);
243 | }
244 | else{
245 | c = vec4(0.0, 0.0, 0.0, 0.0);
246 | }
247 |
248 | gl_FragColor = c;
249 | }
250 | `;
--------------------------------------------------------------------------------
/frontend/public/js/websocket.js:
--------------------------------------------------------------------------------
1 | var socket;
2 |
3 | var projectData = undefined
4 |
5 | function setupWebsocket(type) {
6 |
7 | if (type == "extern") {
8 | socket = io.connect("https://sulfurous.aau.at" + ':8082');
9 | } else if (type == "intern" || type == "app") {
10 | socket = io.connect(window.location.hostname + ':8082');
11 | }
12 |
13 | socket.on("getProjectDataReturn", function (data) {
14 | projectData = data.project_token
15 | // console.log(data)
16 | });
17 |
18 | socket.on("sendSB2file", function (data) {
19 |
20 | if (type != "app") {
21 | loadSP2FileFromSocket(data);
22 | } else {
23 | loadFromSocket(data);
24 | }
25 | });
26 |
27 | socket.on("sendPackage", function (data) {
28 | console.log("tset")
29 | console.log(data)
30 | var zip = new JSZip(data);
31 | console.log(zip)
32 | var content = zip.generate({ type: "blob" });
33 | saveData(content, "OUTPUT.zip")
34 | })
35 | }
--------------------------------------------------------------------------------
/frontend/public/soundbank/Instr.as:
--------------------------------------------------------------------------------
1 | /*
2 | * Scratch Project Editor and Player
3 | * Copyright (C) 2014 Massachusetts Institute of Technology
4 | *
5 | * This program is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU General Public License
7 | * as published by the Free Software Foundation; either version 2
8 | * of the License, or (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 | */
19 |
20 | // Instr.as
21 | // John Maloney, April 2012
22 | //
23 | // This class embeds the sound data for Scratch instruments and drums.
24 | // The static variable 'samples' is a dictionary of named sound buffers.
25 | // Call initSamples() to initialize 'samples' before using.
26 | //
27 | // All instrument and drum samples were created for Scratch by:
28 | //
29 | // Paul Madden, paulmatthewmadden@yahoo.com
30 | //
31 | // Paul is an excellent sound designer and we appreciate all the effort
32 | // he put into this project.
33 |
34 | package soundbank {
35 | import flash.utils.*;
36 | import sound.WAVFile;
37 |
38 | public class Instr {
39 |
40 | public static var samples:Object;
41 |
42 | public static function initSamples():void {
43 | // Initialize the dictionary of named sound buffers.
44 | // Details: Build the dictionary by enumerating all the embedded sounds in this file
45 | // (i.e. constants with a value of type 'class'), extracting the sound data from the
46 | // WAV file, and adding an entry for it to the 'samples' object.
47 |
48 | if (samples) return; // already initialized
49 |
50 | samples = {};
51 | var classDescription:XML = describeType(Instr);
52 | for each (var k:XML in classDescription.elements('constant')) {
53 | if (k.attribute('type') == 'Class') {
54 | var instrName:String = k.attribute('name');
55 | samples[instrName] = getWAVSamples(new Instr[instrName]);
56 | }
57 | }
58 | }
59 |
60 | private static function getWAVSamples(wavData:ByteArray):ByteArray {
61 | // Extract a sound buffer from a WAV file. Assume the WAV file contains 16-bit, uncompressed sound data.
62 | var info:Object = WAVFile.decode(wavData);
63 | var soundBuffer:ByteArray = new ByteArray();
64 | soundBuffer.endian = Endian.LITTLE_ENDIAN;
65 | wavData.position = info.sampleDataStart;
66 | wavData.readBytes(soundBuffer, 0, 2 * info.sampleCount);
67 | return soundBuffer;
68 | }
69 |
70 | /* Instruments */
71 |
72 | [Embed(source='instruments/AcousticGuitar_F3_22k.wav', mimeType='application/octet-stream')]
73 | public static const AcousticGuitar_F3:Class;
74 |
75 | [Embed(source='instruments/AcousticPiano(5)_A#3_22k.wav', mimeType='application/octet-stream')]
76 | public static const AcousticPiano_As3:Class;
77 |
78 | [Embed(source='instruments/AcousticPiano(5)_C4_22k.wav', mimeType='application/octet-stream')]
79 | public static const AcousticPiano_C4:Class;
80 |
81 | [Embed(source='instruments/AcousticPiano(5)_G4_22k.wav', mimeType='application/octet-stream')]
82 | public static const AcousticPiano_G4:Class;
83 |
84 | [Embed(source='instruments/AcousticPiano(5)_F5_22k.wav', mimeType='application/octet-stream')]
85 | public static const AcousticPiano_F5:Class;
86 |
87 | [Embed(source='instruments/AcousticPiano(5)_C6_22k.wav', mimeType='application/octet-stream')]
88 | public static const AcousticPiano_C6:Class;
89 |
90 | [Embed(source='instruments/AcousticPiano(5)_D#6_22k.wav', mimeType='application/octet-stream')]
91 | public static const AcousticPiano_Ds6:Class;
92 |
93 | [Embed(source='instruments/AcousticPiano(5)_D7_22k.wav', mimeType='application/octet-stream')]
94 | public static const AcousticPiano_D7:Class;
95 |
96 | [Embed(source='instruments/AltoSax_A3_22K.wav', mimeType='application/octet-stream')]
97 | public static const AltoSax_A3:Class;
98 |
99 | [Embed(source='instruments/AltoSax(3)_C6_22k.wav', mimeType='application/octet-stream')]
100 | public static const AltoSax_C6:Class;
101 |
102 | [Embed(source='instruments/Bassoon_C3_22k.wav', mimeType='application/octet-stream')]
103 | public static const Bassoon_C3:Class;
104 |
105 | [Embed(source='instruments/BassTrombone_A2(2)_22k.wav', mimeType='application/octet-stream')]
106 | public static const BassTrombone_A2_2:Class;
107 |
108 | [Embed(source='instruments/BassTrombone_A2(3)_22k.wav', mimeType='application/octet-stream')]
109 | public static const BassTrombone_A2_3:Class;
110 |
111 | [Embed(source='instruments/Cello(3b)_C2_22k.wav', mimeType='application/octet-stream')]
112 | public static const Cello_C2:Class;
113 |
114 | [Embed(source='instruments/Cello(3)_A#2_22k.wav', mimeType='application/octet-stream')]
115 | public static const Cello_As2:Class;
116 |
117 | [Embed(source='instruments/Choir(4)_F3_22k.wav', mimeType='application/octet-stream')]
118 | public static const Choir_F3:Class;
119 |
120 | [Embed(source='instruments/Choir(4)_F4_22k.wav', mimeType='application/octet-stream')]
121 | public static const Choir_F4:Class;
122 |
123 | [Embed(source='instruments/Choir(4)_F5_22k.wav', mimeType='application/octet-stream')]
124 | public static const Choir_F5:Class;
125 |
126 | [Embed(source='instruments/Clarinet_C4_22k.wav', mimeType='application/octet-stream')]
127 | public static const Clarinet_C4:Class;
128 |
129 | [Embed(source='instruments/ElectricBass(2)_G1_22k.wav', mimeType='application/octet-stream')]
130 | public static const ElectricBass_G1:Class;
131 |
132 | [Embed(source='instruments/ElectricGuitar(2)_F3(1)_22k.wav', mimeType='application/octet-stream')]
133 | public static const ElectricGuitar_F3:Class;
134 |
135 | [Embed(source='instruments/ElectricPiano_C2_22k.wav', mimeType='application/octet-stream')]
136 | public static const ElectricPiano_C2:Class;
137 |
138 | [Embed(source='instruments/ElectricPiano_C4_22k.wav', mimeType='application/octet-stream')]
139 | public static const ElectricPiano_C4:Class;
140 |
141 | [Embed(source='instruments/EnglishHorn(1)_D4_22k.wav', mimeType='application/octet-stream')]
142 | public static const EnglishHorn_D4:Class;
143 |
144 | [Embed(source='instruments/EnglishHorn(1)_F3_22k.wav', mimeType='application/octet-stream')]
145 | public static const EnglishHorn_F3:Class;
146 |
147 | [Embed(source='instruments/Flute(3)_B5(1)_22k.wav', mimeType='application/octet-stream')]
148 | public static const Flute_B5_1:Class;
149 |
150 | [Embed(source='instruments/Flute(3)_B5(2)_22k.wav', mimeType='application/octet-stream')]
151 | public static const Flute_B5_2:Class;
152 |
153 | [Embed(source='instruments/Marimba_C4_22k.wav', mimeType='application/octet-stream')]
154 | public static const Marimba_C4:Class;
155 |
156 | [Embed(source='instruments/MusicBox_C4_22k.wav', mimeType='application/octet-stream')]
157 | public static const MusicBox_C4:Class;
158 |
159 | [Embed(source='instruments/Organ(2)_G2_22k.wav', mimeType='application/octet-stream')]
160 | public static const Organ_G2:Class;
161 |
162 | [Embed(source='instruments/Pizz(2)_A3_22k.wav', mimeType='application/octet-stream')]
163 | public static const Pizz_A3:Class;
164 |
165 | [Embed(source='instruments/Pizz(2)_E4_22k.wav', mimeType='application/octet-stream')]
166 | public static const Pizz_E4:Class;
167 |
168 | [Embed(source='instruments/Pizz(2)_G2_22k.wav', mimeType='application/octet-stream')]
169 | public static const Pizz_G2:Class;
170 |
171 | [Embed(source='instruments/SteelDrum_D5_22k.wav', mimeType='application/octet-stream')]
172 | public static const SteelDrum_D5:Class;
173 |
174 | [Embed(source='instruments/SynthLead(6)_C4_22k.wav', mimeType='application/octet-stream')]
175 | public static const SynthLead_C4:Class;
176 |
177 | [Embed(source='instruments/SynthLead(6)_C6_22k.wav', mimeType='application/octet-stream')]
178 | public static const SynthLead_C6:Class;
179 |
180 | [Embed(source='instruments/SynthPad(2)_A3_22k.wav', mimeType='application/octet-stream')]
181 | public static const SynthPad_A3:Class;
182 |
183 | [Embed(source='instruments/SynthPad(2)_C6_22k.wav', mimeType='application/octet-stream')]
184 | public static const SynthPad_C6:Class;
185 |
186 | [Embed(source='instruments/TenorSax(1)_C3_22k.wav', mimeType='application/octet-stream')]
187 | public static const TenorSax_C3:Class;
188 |
189 | [Embed(source='instruments/Trombone_B3_22k.wav', mimeType='application/octet-stream')]
190 | public static const Trombone_B3:Class;
191 |
192 | [Embed(source='instruments/Trumpet_E5_22k.wav', mimeType='application/octet-stream')]
193 | public static const Trumpet_E5:Class;
194 |
195 | [Embed(source='instruments/Vibraphone_C3_22k.wav', mimeType='application/octet-stream')]
196 | public static const Vibraphone_C3:Class;
197 |
198 | [Embed(source='instruments/Violin(2)_D4_22K.wav', mimeType='application/octet-stream')]
199 | public static const Violin_D4:Class;
200 |
201 | [Embed(source='instruments/Violin(3)_A4_22k.wav', mimeType='application/octet-stream')]
202 | public static const Violin_A4:Class;
203 |
204 | [Embed(source='instruments/Violin(3b)_E5_22k.wav', mimeType='application/octet-stream')]
205 | public static const Violin_E5:Class;
206 |
207 | [Embed(source='instruments/WoodenFlute_C5_22k.wav', mimeType='application/octet-stream')]
208 | public static const WoodenFlute_C5:Class;
209 |
210 | /* Drums */
211 |
212 | [Embed(source='drums/BassDrum(1b)_22k.wav', mimeType='application/octet-stream')]
213 | public static const BassDrum:Class;
214 |
215 | [Embed(source='drums/Bongo_22k.wav', mimeType='application/octet-stream')]
216 | public static const Bongo:Class;
217 |
218 | [Embed(source='drums/Cabasa(1)_22k.wav', mimeType='application/octet-stream')]
219 | public static const Cabasa:Class;
220 |
221 | [Embed(source='drums/Clap(1)_22k.wav', mimeType='application/octet-stream')]
222 | public static const Clap:Class;
223 |
224 | [Embed(source='drums/Claves(1)_22k.wav', mimeType='application/octet-stream')]
225 | public static const Claves:Class;
226 |
227 | [Embed(source='drums/Conga(1)_22k.wav', mimeType='application/octet-stream')]
228 | public static const Conga:Class;
229 |
230 | [Embed(source='drums/Cowbell(3)_22k.wav', mimeType='application/octet-stream')]
231 | public static const Cowbell:Class;
232 |
233 | [Embed(source='drums/Crash(2)_22k.wav', mimeType='application/octet-stream')]
234 | public static const Crash:Class;
235 |
236 | [Embed(source='drums/Cuica(2)_22k.wav', mimeType='application/octet-stream')]
237 | public static const Cuica:Class;
238 |
239 | [Embed(source='drums/GuiroLong(1)_22k.wav', mimeType='application/octet-stream')]
240 | public static const GuiroLong:Class;
241 |
242 | [Embed(source='drums/GuiroShort(1)_22k.wav', mimeType='application/octet-stream')]
243 | public static const GuiroShort:Class;
244 |
245 | [Embed(source='drums/HiHatClosed(1)_22k.wav', mimeType='application/octet-stream')]
246 | public static const HiHatClosed:Class;
247 |
248 | [Embed(source='drums/HiHatOpen(2)_22k.wav', mimeType='application/octet-stream')]
249 | public static const HiHatOpen:Class;
250 |
251 | [Embed(source='drums/HiHatPedal(1)_22k.wav', mimeType='application/octet-stream')]
252 | public static const HiHatPedal:Class;
253 |
254 | [Embed(source='drums/Maracas(1)_22k.wav', mimeType='application/octet-stream')]
255 | public static const Maracas:Class;
256 |
257 | [Embed(source='drums/SideStick(1)_22k.wav', mimeType='application/octet-stream')]
258 | public static const SideStick:Class;
259 |
260 | [Embed(source='drums/SnareDrum(1)_22k.wav', mimeType='application/octet-stream')]
261 | public static const SnareDrum:Class;
262 |
263 | [Embed(source='drums/Tambourine(3)_22k.wav', mimeType='application/octet-stream')]
264 | public static const Tambourine:Class;
265 |
266 | [Embed(source='drums/Tom(1)_22k.wav', mimeType='application/octet-stream')]
267 | public static const Tom:Class;
268 |
269 | [Embed(source='drums/Triangle(1)_22k.wav', mimeType='application/octet-stream')]
270 | public static const Triangle:Class;
271 |
272 | [Embed(source='drums/Vibraslap(1)_22k.wav', mimeType='application/octet-stream')]
273 | public static const Vibraslap:Class;
274 |
275 | [Embed(source='drums/WoodBlock(1)_22k.wav', mimeType='application/octet-stream')]
276 | public static const WoodBlock:Class;
277 |
278 | }}
279 |
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/BassDrum(1b)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/BassDrum(1b)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Bongo_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Bongo_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Cabasa(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Cabasa(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Clap(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Clap(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Claves(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Claves(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Conga(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Conga(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Cowbell(3)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Cowbell(3)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Crash(2)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Crash(2)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Cuica(2)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Cuica(2)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/GuiroLong(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/GuiroLong(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/GuiroShort(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/GuiroShort(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/HiHatClosed(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/HiHatClosed(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/HiHatOpen(2)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/HiHatOpen(2)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/HiHatPedal(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/HiHatPedal(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Maracas(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Maracas(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/SideStick(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/SideStick(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/SnareDrum(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/SnareDrum(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Tambourine(3)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Tambourine(3)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Tom(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Tom(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Triangle(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Triangle(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/Vibraslap(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/Vibraslap(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/drums/WoodBlock(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/drums/WoodBlock(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticGuitar_F3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticGuitar_F3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_A%233_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_A%233_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_A3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_A3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_C6_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_C6_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_D6_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_D6_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_D7_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_D7_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_F5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_F5_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AcousticPiano(5)_G4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AcousticPiano(5)_G4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AltoSax(3)_C6_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AltoSax(3)_C6_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/AltoSax_A3_22K.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/AltoSax_A3_22K.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/BassTrombone_A2(2)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/BassTrombone_A2(2)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/BassTrombone_A2(3)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/BassTrombone_A2(3)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Bassoon_C3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Bassoon_C3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Cello(3)_A2_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Cello(3)_A2_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Cello(3b)_C2_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Cello(3b)_C2_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Choir(4)_F3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Choir(4)_F3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Choir(4)_F4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Choir(4)_F4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Choir(4)_F5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Choir(4)_F5_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Clarinet_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Clarinet_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/ElectricBass(2)_G1_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/ElectricBass(2)_G1_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/ElectricGuitar(2)_F3(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/ElectricGuitar(2)_F3(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/ElectricPiano_C2_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/ElectricPiano_C2_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/ElectricPiano_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/ElectricPiano_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/EnglishHorn(1)_D4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/EnglishHorn(1)_D4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/EnglishHorn(1)_F3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/EnglishHorn(1)_F3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Flute(3)_B5(1)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Flute(3)_B5(1)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Flute(3)_B5(2)_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Flute(3)_B5(2)_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Marimba_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Marimba_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/MusicBox_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/MusicBox_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Organ(2)_G2_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Organ(2)_G2_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Pizz(2)_A3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Pizz(2)_A3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Pizz(2)_E4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Pizz(2)_E4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Pizz(2)_G2_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Pizz(2)_G2_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/SteelDrum_D5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/SteelDrum_D5_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/SynthLead(6)_C4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/SynthLead(6)_C4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/SynthLead(6)_C6_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/SynthLead(6)_C6_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/SynthPad(2)_A3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/SynthPad(2)_A3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/SynthPad(2)_C6_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/SynthPad(2)_C6_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/TenorSax(1)_C3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/TenorSax(1)_C3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Trombone_B3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Trombone_B3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Trumpet_E5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Trumpet_E5_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Vibraphone_C3_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Vibraphone_C3_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Violin(2)_D4_22K.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Violin(2)_D4_22K.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Violin(3)_A4_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Violin(3)_A4_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/Violin(3b)_E5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/Violin(3b)_E5_22k.wav
--------------------------------------------------------------------------------
/frontend/public/soundbank/instruments/WoodenFlute_C5_22k.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/frontend/public/soundbank/instruments/WoodenFlute_C5_22k.wav
--------------------------------------------------------------------------------
/imgs/img0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img0.png
--------------------------------------------------------------------------------
/imgs/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img1.png
--------------------------------------------------------------------------------
/imgs/img10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img10.png
--------------------------------------------------------------------------------
/imgs/img11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img11.png
--------------------------------------------------------------------------------
/imgs/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img2.png
--------------------------------------------------------------------------------
/imgs/img3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img3.png
--------------------------------------------------------------------------------
/imgs/img4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img4.png
--------------------------------------------------------------------------------
/imgs/img5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img5.png
--------------------------------------------------------------------------------
/imgs/img6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img6.png
--------------------------------------------------------------------------------
/imgs/img7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img7.png
--------------------------------------------------------------------------------
/imgs/img8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img8.png
--------------------------------------------------------------------------------
/imgs/img9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/imgs/img9.png
--------------------------------------------------------------------------------
/sb3tosb2/dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:18.04
2 |
3 | RUN apt-get update
4 | RUN apt-get install -y python3
5 |
6 | WORKDIR /work
7 |
8 | #./src/run.sh
9 | CMD [ "bash","./src/run.sh" ]
--------------------------------------------------------------------------------
/sb3tosb2/sb2/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/sb3tosb2/sb2/.gitkeep
--------------------------------------------------------------------------------
/sb3tosb2/sb3/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/sb3tosb2/sb3/.gitkeep
--------------------------------------------------------------------------------
/sb3tosb2/sb3/converted/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mittagskogel/Sulfurous/213e7d930affff87943f2e0f4fa2dac0310b25cc/sb3tosb2/sb3/converted/.gitkeep
--------------------------------------------------------------------------------
/sb3tosb2/src/README.md:
--------------------------------------------------------------------------------
1 | SB3 to SB2 Converter
2 | ==============
3 |
4 | A simple Python 3 program that converts .sb3 files to .sb2 files
5 |
6 | Requirements
7 | --------------
8 | - Python 3 (preferably 3.6.2 or later)
9 |
10 | Installation
11 | --------------
12 | Download and extract the ZIP file and move the sb3tosb2.py file to wherever you want.
13 |
14 | Usage
15 | --------------
16 | 1. Run sb3tosb2.py with Python
17 | 2. Select the SB3 file to open
18 | 3. Either select the SB2 file to save to or type in a new file name
19 | 4. Click OK to exit
20 |
21 | Usage (command line)
22 | --------------
23 | 1. Open the terminal or command prompt and navigate to the directory of the sb3tosb2.py file.
24 | 2. Enter the following command: `python sb3tosb2.py [unordered options] sb3path [sb2path]` Options and sb2path are not necessary.
25 | 3. If an error is given, make sure you entered a valid sb3 file.
26 |
27 | Arguments
28 | --------------
29 | Options may or may not be separated by a space.
30 | List of options:
31 | - `-h`: Displays the program arguments and list of options
32 | - `-c`: This enables compatibility mode. Workarounds for the following blocks will be added to sprites:
33 | - glide to [ v]
34 | - costume [number v]
35 | - set drag mode [ v]
36 | - <[] contains []?> (may result in performance loss)
37 | - (item # of [] in [ v]) (may result in performance loss)
38 | - pen color blocks (including HSV and shade blocks)
39 | - timer blocks
40 | - `-j`: Automatically enables compatibility mode and adds an unlimited join workaround (may result in significant performance loss)
41 | - `-l`: Automatically enables compatibility mode and adds custom blocks to automatically limit list length to 200,000 (may result in performance loss)
42 | - `-p`: Tries to insert blocks to fill the screen when the pen size is set to a value greater than 255
43 |
44 | Known Issues
45 | --------------
46 | - MP3 audio files cannot be converted
47 | - Compatibility mode changes variable monitor labels
48 | - Compatibility mode allows ([ v] of [ v]) to access only variables (not attributes like x position, backdrop #, etc.)
49 | - Dragging in projects converted with compatibility mode does not have the same pen behavior as in 3.0
50 | - Unlimited join does not check case when checking string equality
--------------------------------------------------------------------------------
/sb3tosb2/src/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | while true
3 | do
4 | #echo "CHECKING FOR WORK..."
5 | for entry in ./sb3/*.sb3; do
6 | if [ "$entry" != "./sb3/*.sb3" ]
7 | then
8 | sb3name="$(cut -d'/' -f3 <<<"$entry")"
9 | sb2name="./sb2/$(cut -d'.' -f1 <<<"$sb3name").sb2"
10 | echo "WORK: $sb3name"
11 | echo "$sb2name"
12 | python3 ./src/sb3tosb2.py "$entry" "$sb2name"
13 | mv "$entry" "./sb3/converted/$sb3name"
14 | fi
15 | #echo "NO WORK"
16 | done
17 | sleep 1
18 | done
--------------------------------------------------------------------------------
/start/startSulurousCloud.bat:
--------------------------------------------------------------------------------
1 | docker-compose -f ../docker-compose.yml start sulfurous-frontend sulfurous-backend
--------------------------------------------------------------------------------
/start/startSulurousCloud.sh:
--------------------------------------------------------------------------------
1 | sudo docker-compose -f ../docker-compose.yml start sulfurous-frontend sulfurous-backend
--------------------------------------------------------------------------------
/start/startSulurousSB2.bat:
--------------------------------------------------------------------------------
1 | docker-compose -f ../docker-compose.yml start sulfurous-frontend
--------------------------------------------------------------------------------
/start/startSulurousSB2.sh:
--------------------------------------------------------------------------------
1 | sudo docker-compose -f ../docker-compose.yml start sulfurous-frontend
--------------------------------------------------------------------------------
/start/startSulurousSB3.bat:
--------------------------------------------------------------------------------
1 | docker-compose -f ../docker-compose.yml start sulfurous-frontend sulfurous-backend sulfurous-sb3tosb2
--------------------------------------------------------------------------------
/start/startSulurousSB3.sh:
--------------------------------------------------------------------------------
1 | sudo docker-compose -f ../docker-compose.yml start sulfurous-frontend sulfurous-backend sulfurous-sb3tosb2
--------------------------------------------------------------------------------