soiz1 commited on
Commit
63b4dc2
·
verified ·
1 Parent(s): 8f5ea4b

Update src/lib/libraries/extensions/index.jsx

Browse files
Files changed (1) hide show
  1. src/lib/libraries/extensions/index.jsx +1531 -557
src/lib/libraries/extensions/index.jsx CHANGED
@@ -1,565 +1,1539 @@
1
- import LazyScratchBlocks from './tw-lazy-scratch-blocks';
2
-
3
- /**
4
- * Connect scratch blocks with the vm
5
- * @param {VirtualMachine} vm - The scratch vm
6
- * @return {ScratchBlocks} ScratchBlocks connected with the vm
7
- */
8
- export default function (vm) {
9
- const ScratchBlocks = LazyScratchBlocks.get();
10
-
11
- const jsonForMenuBlock = function (name, menuOptionsFn, colors, start) {
12
- return {
13
- message0: '%1',
14
- args0: [
15
- {
16
- type: 'field_dropdown',
17
- name: name,
18
- options: function () {
19
- return start.concat(menuOptionsFn());
20
- }
21
- }
22
- ],
23
- inputsInline: true,
24
- output: 'String',
25
- colour: colors.secondary,
26
- colourSecondary: colors.secondary,
27
- colourTertiary: colors.tertiary,
28
- outputShape: ScratchBlocks.OUTPUT_SHAPE_ROUND
29
- };
30
- };
31
-
32
- const jsonForHatBlockMenu = function (hatName, name, menuOptionsFn, colors, start) {
33
- return {
34
- message0: hatName,
35
- args0: [
36
- {
37
- type: 'field_dropdown',
38
- name: name,
39
- options: function () {
40
- return start.concat(menuOptionsFn());
41
- }
42
- }
43
- ],
44
- colour: colors.primary,
45
- colourSecondary: colors.secondary,
46
- colourTertiary: colors.tertiary,
47
- extensions: ['shape_hat']
48
- };
49
- };
50
-
51
-
52
- const jsonForSensingMenus = function (menuOptionsFn) {
53
- return {
54
- message0: ScratchBlocks.Msg.SENSING_OF,
55
- args0: [
56
- {
57
- type: 'field_dropdown',
58
- name: 'PROPERTY',
59
- options: function () {
60
- return menuOptionsFn();
61
- }
62
 
63
- },
64
- {
65
- type: 'input_value',
66
- name: 'OBJECT'
67
- }
68
- ],
69
- output: true,
70
- colour: ScratchBlocks.Colours.sensing.primary,
71
- colourSecondary: ScratchBlocks.Colours.sensing.secondary,
72
- colourTertiary: ScratchBlocks.Colours.sensing.tertiary,
73
- outputShape: ScratchBlocks.OUTPUT_SHAPE_ROUND
74
- };
75
- };
76
-
77
- const jsonForSensingSetMenus = function (menuOptionsFn) {
78
- return {
79
- message0: 'set %1 of %2 to %3',
80
- args0: [
81
- {
82
- type: 'field_dropdown',
83
- name: 'PROPERTY',
84
- options: function () {
85
- return menuOptionsFn();
86
- }
87
 
88
- },
89
- {
90
- type: 'input_value',
91
- name: 'OBJECT'
92
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  {
94
- type: 'input_value',
95
- name: 'VALUE'
96
  }
97
  ],
98
- colour: ScratchBlocks.Colours.sensing.primary,
99
- colourSecondary: ScratchBlocks.Colours.sensing.secondary,
100
- colourTertiary: ScratchBlocks.Colours.sensing.tertiary,
101
- extensions: ['shape_statement']
102
- };
103
- };
104
-
105
- const soundsMenu = function () {
106
- let menu = [['', '']];
107
- if (vm.editingTarget && vm.editingTarget.sprite.sounds.length > 0) {
108
- menu = vm.editingTarget.sprite.sounds.map(sound => [sound.name, sound.name]);
109
  }
110
- menu.push([
111
- ScratchBlocks.ScratchMsgs.translate('SOUND_RECORD', 'record...'),
112
- ScratchBlocks.recordSoundCallback
113
- ]);
114
- return menu;
115
- };
116
-
117
- const costumesMenu = function () {
118
- const next = ScratchBlocks.ScratchMsgs.translate('LOOKS_NEXTCOSTUME', 'next costume');
119
- const previous = "previous costume" //ScratchBlocks.ScratchMsgs.translate('LOOKS_PREVIOUSCOSTUME', 'previous costume');
120
- // TODO: Add translation index into ScratchBlocks for this.
121
-
122
- const random = "random costume"//ScratchBlocks.ScratchMsgs.translate('LOOKS_RANDOMBACKDROP', 'random costume');
123
- // TODO: Add translation entry
124
- if (vm.editingTarget && vm.editingTarget.getCostumes().length > 0) {
125
- return vm.editingTarget.getCostumes().map(costume => [costume.name, costume.name])
126
- .concat([
127
- [next, "next costume"],
128
- [previous, "previous costume"],
129
- [random, "random costume"]
130
- ])
131
- ;
132
- }
133
- return [['', '']];
134
- };
135
-
136
- const backdropsMenu = function () {
137
- const next = ScratchBlocks.ScratchMsgs.translate('LOOKS_NEXTBACKDROP', 'next backdrop');
138
- const previous = ScratchBlocks.ScratchMsgs.translate('LOOKS_PREVIOUSBACKDROP', 'previous backdrop');
139
- const random = ScratchBlocks.ScratchMsgs.translate('LOOKS_RANDOMBACKDROP', 'random backdrop');
140
- if (vm.runtime.targets[0] && vm.runtime.targets[0].getCostumes().length > 0) {
141
- return vm.runtime.targets[0].getCostumes().map(costume => [costume.name, costume.name])
142
- .concat([[next, 'next backdrop'],
143
- [previous, 'previous backdrop'],
144
- [random, 'random backdrop']]);
145
- }
146
- return [['', '']];
147
- };
148
-
149
- const backdropNamesMenu = function () {
150
- const stage = vm.runtime.getTargetForStage();
151
- if (stage && stage.getCostumes().length > 0) {
152
- return stage.getCostumes().map(costume => [costume.name, costume.name]);
153
- }
154
- return [['', '']];
155
- };
156
-
157
- const spriteMenu = function () {
158
- const sprites = [];
159
- for (const targetId in vm.runtime.targets) {
160
- if (!vm.runtime.targets.hasOwnProperty(targetId)) continue;
161
- if (vm.runtime.targets[targetId].isOriginal) {
162
- if (!vm.runtime.targets[targetId].isStage) {
163
- if (vm.runtime.targets[targetId] === vm.editingTarget) {
164
- continue;
165
- }
166
- sprites.push([vm.runtime.targets[targetId].sprite.name, vm.runtime.targets[targetId].sprite.name]);
167
- }
168
- }
169
- }
170
- return sprites;
171
- };
172
-
173
- const cloneMenu = function () {
174
- if (vm.editingTarget && vm.editingTarget.isStage) {
175
- const menu = spriteMenu();
176
- if (menu.length === 0) {
177
- return [['', '']]; // Empty menu matches Scratch 2 behavior
178
- }
179
- return menu;
180
- }
181
- const myself = ScratchBlocks.ScratchMsgs.translate('CONTROL_CREATECLONEOF_MYSELF', 'myself');
182
- return [[myself, '_myself_']].concat(spriteMenu());
183
- };
184
-
185
- const soundColors = ScratchBlocks.Colours.sounds;
186
-
187
- const looksColors = ScratchBlocks.Colours.looks;
188
-
189
- const motionColors = ScratchBlocks.Colours.motion;
190
-
191
- const sensingColors = ScratchBlocks.Colours.sensing;
192
-
193
- const controlColors = ScratchBlocks.Colours.control;
194
-
195
- const eventColors = ScratchBlocks.Colours.event;
196
-
197
- ScratchBlocks.Blocks.sound_sounds_menu.init = function () {
198
- const json = jsonForMenuBlock('SOUND_MENU', soundsMenu, soundColors, []);
199
- this.jsonInit(json);
200
- };
201
-
202
- ScratchBlocks.Blocks.looks_costume.init = function () {
203
- const json = jsonForMenuBlock('COSTUME', costumesMenu, looksColors, []);
204
- this.jsonInit(json);
205
- };
206
-
207
- ScratchBlocks.Blocks.looks_backdrops.init = function () {
208
- const json = jsonForMenuBlock('BACKDROP', backdropsMenu, looksColors, []);
209
- this.jsonInit(json);
210
- };
211
-
212
- ScratchBlocks.Blocks.event_whenbackdropswitchesto.init = function () {
213
- const json = jsonForHatBlockMenu(
214
- ScratchBlocks.Msg.EVENT_WHENBACKDROPSWITCHESTO,
215
- 'BACKDROP', backdropNamesMenu, eventColors, []);
216
- this.jsonInit(json);
217
- };
218
-
219
- ScratchBlocks.Blocks.motion_pointtowards_menu.init = function () {
220
- const random = ScratchBlocks.ScratchMsgs.translate('MOTION_POINTTOWARDS_RANDOM', 'random direction');
221
- const mouse = ScratchBlocks.ScratchMsgs.translate('MOTION_POINTTOWARDS_POINTER', 'mouse-pointer');
222
- const json = jsonForMenuBlock('TOWARDS', spriteMenu, motionColors, [
223
- [mouse, '_mouse_'],
224
- [random, '_random_']
225
- ]);
226
- this.jsonInit(json);
227
- };
228
-
229
- ScratchBlocks.Blocks.motion_goto_menu.init = function () {
230
- const random = ScratchBlocks.ScratchMsgs.translate('MOTION_GOTO_RANDOM', 'random position');
231
- const mouse = ScratchBlocks.ScratchMsgs.translate('MOTION_GOTO_POINTER', 'mouse-pointer');
232
- const json = jsonForMenuBlock('TO', spriteMenu, motionColors, [
233
- [random, '_random_'],
234
- [mouse, '_mouse_']
235
- ]);
236
- this.jsonInit(json);
237
- };
238
-
239
- ScratchBlocks.Blocks.motion_glideto_menu.init = function () {
240
- const random = ScratchBlocks.ScratchMsgs.translate('MOTION_GLIDETO_RANDOM', 'random position');
241
- const mouse = ScratchBlocks.ScratchMsgs.translate('MOTION_GLIDETO_POINTER', 'mouse-pointer');
242
- const json = jsonForMenuBlock('TO', spriteMenu, motionColors, [
243
- [random, '_random_'],
244
- [mouse, '_mouse_']
245
- ]);
246
- this.jsonInit(json);
247
- };
248
-
249
- ScratchBlocks.Blocks.sensing_of_object_menu.init = function () {
250
- const stage = ScratchBlocks.ScratchMsgs.translate('SENSING_OF_STAGE', 'Stage');
251
- const json = jsonForMenuBlock('OBJECT', spriteMenu, sensingColors, [
252
- [stage, '_stage_']
253
- ]);
254
- this.jsonInit(json);
255
- };
256
-
257
- ScratchBlocks.Blocks.sensing_of.init = function () {
258
- const blockId = this.id;
259
- const blockType = this.type;
260
-
261
- // Get the sensing_of block from vm.
262
- let defaultSensingOfBlock;
263
- const blocks = vm.runtime.flyoutBlocks._blocks;
264
- Object.keys(blocks).forEach(id => {
265
- const block = blocks[id];
266
- if (id === blockType || (block && block.opcode === blockType)) {
267
- defaultSensingOfBlock = block;
268
- }
269
- });
270
-
271
- // Function that fills in menu for the first input in the sensing block.
272
- // Called every time it opens since it depends on the values in the other block input.
273
- const menuFn = function () {
274
- const stageOptions = [
275
- [ScratchBlocks.Msg.SENSING_OF_BACKDROPNUMBER, 'backdrop #'],
276
- [ScratchBlocks.Msg.SENSING_OF_BACKDROPNAME, 'backdrop name'],
277
- [ScratchBlocks.Msg.SENSING_OF_VOLUME, 'volume']
278
- ];
279
- const spriteOptions = [
280
- [ScratchBlocks.Msg.SENSING_OF_XPOSITION, 'x position'],
281
- [ScratchBlocks.Msg.SENSING_OF_YPOSITION, 'y position'],
282
- [ScratchBlocks.Msg.SENSING_OF_DIRECTION, 'direction'],
283
- [ScratchBlocks.Msg.SENSING_OF_COSTUMENUMBER, 'costume #'],
284
- [ScratchBlocks.Msg.SENSING_OF_COSTUMENAME, 'costume name'],
285
- ['layer', 'layer'],
286
- [ScratchBlocks.Msg.SENSING_OF_SIZE, 'size'],
287
- [ScratchBlocks.Msg.SENSING_OF_VOLUME, 'volume']
288
- ];
289
- if (vm.editingTarget) {
290
- let lookupBlocks = vm.editingTarget.blocks;
291
- let sensingOfBlock = lookupBlocks.getBlock(blockId);
292
-
293
- // The block doesn't exist, but should be in the flyout. Look there.
294
- if (!sensingOfBlock) {
295
- sensingOfBlock = vm.runtime.flyoutBlocks.getBlock(blockId) || defaultSensingOfBlock;
296
- // If we still don't have a block, just return an empty list . This happens during
297
- // scratch blocks construction.
298
- if (!sensingOfBlock) {
299
- return [['', '']];
300
- }
301
- // The block was in the flyout so look up future block info there.
302
- lookupBlocks = vm.runtime.flyoutBlocks;
303
- }
304
- const sort = function (options) {
305
- options.sort(ScratchBlocks.scratchBlocksUtils.compareStrings);
306
- };
307
- // Get all the stage variables (no lists) so we can add them to menu when the stage is selected.
308
- const stageVariableOptions = vm.runtime.getTargetForStage().getAllVariableNamesInScopeByType('');
309
- sort(stageVariableOptions);
310
- const stageVariableMenuItems = stageVariableOptions.map(variable => [variable, variable]);
311
- if (sensingOfBlock.inputs.OBJECT.shadow !== sensingOfBlock.inputs.OBJECT.block) {
312
- // There's a block dropped on top of the menu. It'd be nice to evaluate it and
313
- // return the correct list, but that is tricky. Scratch2 just returns stage options
314
- // so just do that here too.
315
- return stageOptions.concat(stageVariableMenuItems);
316
- }
317
- const menuBlock = lookupBlocks.getBlock(sensingOfBlock.inputs.OBJECT.shadow);
318
- const selectedItem = menuBlock.fields.OBJECT.value;
319
- if (selectedItem === '_stage_') {
320
- return stageOptions.concat(stageVariableMenuItems);
321
- }
322
- // Get all the local variables (no lists) and add them to the menu.
323
- const target = vm.runtime.getSpriteTargetByName(selectedItem);
324
- let spriteVariableOptions = [];
325
- // The target should exist, but there are ways for it not to (e.g. #4203).
326
- if (target) {
327
- spriteVariableOptions = target.getAllVariableNamesInScopeByType('', true);
328
- sort(spriteVariableOptions);
329
- }
330
- const spriteVariableMenuItems = spriteVariableOptions.map(variable => [variable, variable]);
331
- return spriteOptions.concat(spriteVariableMenuItems);
332
- }
333
- return [['', '']];
334
- };
335
-
336
- const json = jsonForSensingMenus(menuFn);
337
- this.jsonInit(json);
338
- };
339
-
340
- ScratchBlocks.Blocks.sensing_set_of.init = function () {
341
- const blockId = this.id;
342
- const blockType = this.type;
343
-
344
- // Get the sensing_of block from vm.
345
- let defaultSensingOfBlock;
346
- const blocks = vm.runtime.flyoutBlocks._blocks;
347
- Object.keys(blocks).forEach(id => {
348
- const block = blocks[id];
349
- if (id === blockType || (block && block.opcode === blockType)) {
350
- defaultSensingOfBlock = block;
351
- }
352
- });
353
-
354
- // Function that fills in menu for the first input in the sensing block.
355
- // Called every time it opens since it depends on the values in the other block input.
356
- const menuFn = function () {
357
- const stageOptions = [
358
- ['backdrop', 'backdrop'],
359
- [ScratchBlocks.Msg.SENSING_OF_VOLUME, 'volume']
360
- ];
361
- const spriteOptions = [
362
- [ScratchBlocks.Msg.SENSING_OF_XPOSITION, 'x position'],
363
- [ScratchBlocks.Msg.SENSING_OF_YPOSITION, 'y position'],
364
- [ScratchBlocks.Msg.SENSING_OF_DIRECTION, 'direction'],
365
- ['costume', 'costume'],
366
- [ScratchBlocks.Msg.SENSING_OF_SIZE, 'size'],
367
- [ScratchBlocks.Msg.SENSING_OF_VOLUME, 'volume']
368
- ];
369
- if (vm.editingTarget) {
370
- let lookupBlocks = vm.editingTarget.blocks;
371
- let sensingOfBlock = lookupBlocks.getBlock(blockId);
372
-
373
- // The block doesn't exist, but should be in the flyout. Look there.
374
- if (!sensingOfBlock) {
375
- sensingOfBlock = vm.runtime.flyoutBlocks.getBlock(blockId) || defaultSensingOfBlock;
376
- // If we still don't have a block, just return an empty list . This happens during
377
- // scratch blocks construction.
378
- if (!sensingOfBlock) {
379
- return [['', '']];
380
- }
381
- // The block was in the flyout so look up future block info there.
382
- lookupBlocks = vm.runtime.flyoutBlocks;
383
- }
384
- const sort = function (options) {
385
- options.sort(ScratchBlocks.scratchBlocksUtils.compareStrings);
386
- };
387
- // Get all the stage variables (no lists) so we can add them to menu when the stage is selected.
388
- const stageVariableOptions = vm.runtime.getTargetForStage().getAllVariableNamesInScopeByType('');
389
- sort(stageVariableOptions);
390
- const stageVariableMenuItems = stageVariableOptions.map(variable => [variable, variable]);
391
- if (sensingOfBlock.inputs.OBJECT.shadow !== sensingOfBlock.inputs.OBJECT.block) {
392
- // There's a block dropped on top of the menu. It'd be nice to evaluate it and
393
- // return the correct list, but that is tricky. Scratch2 just returns stage options
394
- // so just do that here too.
395
- return stageOptions.concat(stageVariableMenuItems);
396
- }
397
- const menuBlock = lookupBlocks.getBlock(sensingOfBlock.inputs.OBJECT.shadow);
398
- const selectedItem = menuBlock.fields.OBJECT.value;
399
- if (selectedItem === '_stage_') {
400
- return stageOptions.concat(stageVariableMenuItems);
401
- }
402
- // Get all the local variables (no lists) and add them to the menu.
403
- const target = vm.runtime.getSpriteTargetByName(selectedItem);
404
- let spriteVariableOptions = [];
405
- // The target should exist, but there are ways for it not to (e.g. #4203).
406
- if (target) {
407
- spriteVariableOptions = target.getAllVariableNamesInScopeByType('', true);
408
- sort(spriteVariableOptions);
409
- }
410
- const spriteVariableMenuItems = spriteVariableOptions.map(variable => [variable, variable]);
411
- return spriteOptions.concat(spriteVariableMenuItems);
412
- }
413
- return [['', '']];
414
- };
415
-
416
- const json = jsonForSensingSetMenus(menuFn);
417
- this.jsonInit(json);
418
- };
419
-
420
- ScratchBlocks.Blocks.sensing_distancetomenu.init = function () {
421
- const mouse = ScratchBlocks.ScratchMsgs.translate('SENSING_DISTANCETO_POINTER', 'mouse-pointer');
422
- const json = jsonForMenuBlock('DISTANCETOMENU', spriteMenu, sensingColors, [
423
- [mouse, '_mouse_']
424
- ]);
425
- this.jsonInit(json);
426
- };
427
-
428
- ScratchBlocks.Blocks.sensing_touchingobjectmenu.init = function () {
429
- const mouse = ScratchBlocks.ScratchMsgs.translate('SENSING_TOUCHINGOBJECT_POINTER', 'mouse-pointer');
430
- const edge = ScratchBlocks.ScratchMsgs.translate('SENSING_TOUCHINGOBJECT_EDGE', 'edge');
431
- const json = jsonForMenuBlock('TOUCHINGOBJECTMENU', spriteMenu, sensingColors, [
432
- [mouse, '_mouse_'],
433
- [edge, '_edge_']
434
- ]);
435
- this.jsonInit(json);
436
- };
437
-
438
- ScratchBlocks.Blocks.sensing_fulltouchingobjectmenu.init = function () {
439
- const mouse = ScratchBlocks.ScratchMsgs.translate('SENSING_TOUCHINGOBJECT_POINTER', 'mouse-pointer');
440
- const edge = ScratchBlocks.ScratchMsgs.translate('SENSING_TOUCHINGOBJECT_EDGE', 'edge');
441
- const json = jsonForMenuBlock('FULLTOUCHINGOBJECTMENU', spriteMenu, sensingColors, [
442
- [mouse, '_mouse_'],
443
- [edge, '_edge_'],
444
- ['this sprite', '_myself_']
445
- ]);
446
- this.jsonInit(json);
447
- };
448
-
449
- ScratchBlocks.Blocks.sensing_touchingobjectmenusprites.init = function () {
450
- const json = jsonForMenuBlock('SPRITETOUCHINGOBJECTMENU', spriteMenu, sensingColors, [
451
- ['this sprite', '_myself_']
452
- ]);
453
- this.jsonInit(json);
454
- };
455
-
456
- ScratchBlocks.Blocks.control_create_clone_of_menu.init = function () {
457
- const json = jsonForMenuBlock('CLONE_OPTION', cloneMenu, controlColors, []);
458
- this.jsonInit(json);
459
- };
460
-
461
- ScratchBlocks.Blocks.control_run_as_sprite_menu.init = function () {
462
- const json = jsonForMenuBlock('RUN_AS_OPTION', spriteMenu, controlColors, [
463
- ['Stage', '_stage_']
464
- ]);
465
- this.jsonInit(json);
466
- };
467
-
468
- ScratchBlocks.Blocks.control_stop_sprite_menu.init = function () {
469
- const json = jsonForMenuBlock('STOP_OPTION', spriteMenu, controlColors, [
470
- ['Stage', '_stage_']
471
- ]);
472
- this.jsonInit(json);
473
- };
474
-
475
- ScratchBlocks.Blocks.looks_getOtherSpriteVisible_menu.init = function () {
476
- const json = jsonForMenuBlock('VISIBLE_OPTION', spriteMenu, looksColors, [
477
- ['this sprite', '_myself_']
478
- ]);
479
- this.jsonInit(json);
480
- };
481
-
482
- ScratchBlocks.Blocks.looks_changeVisibilityOfSprite_menu.init = function () {
483
- const json = jsonForMenuBlock('VISIBLE_OPTION', spriteMenu, looksColors, [
484
- ['this sprite', '_myself_']
485
- ]);
486
- this.jsonInit(json);
487
- };
488
-
489
- ScratchBlocks.VerticalFlyout.getCheckboxState = function (blockId, inputList) {
490
- const monitoredBlock = vm.runtime.monitorBlocks._blocks[blockId];
491
- if (!monitoredBlock)
492
- return false;
493
-
494
- const { opcode, fields } = monitoredBlock;
495
-
496
- if (opcode == "data_variable" || opcode == "data_listcontents")
497
- return monitoredBlock ? monitoredBlock.isMonitored : false;
498
-
499
- const parsedFields = inputList[0].fieldRow
500
- .filter(({ name }) => name in fields)
501
- .map(field => {
502
- if (field.variable_) return field.variable_.name;
503
- return field.name === "CURRENTMENU" ? field.value_.toLowerCase() : field.value_;
504
- }).join("_");
505
-
506
- const newBlockId = blockId + (parsedFields.length ? "_" : "") + parsedFields;
507
-
508
- const newMonitoredBlock = vm.runtime.monitorBlocks._blocks[newBlockId];
509
-
510
- return newMonitoredBlock ? newMonitoredBlock.isMonitored : false;
511
- };
512
-
513
- ScratchBlocks.FlyoutExtensionCategoryHeader.getExtensionState = function (extensionId) {
514
- if (vm.getPeripheralIsConnected(extensionId)) {
515
- return ScratchBlocks.StatusButtonState.READY;
516
- }
517
- return ScratchBlocks.StatusButtonState.NOT_READY;
518
- };
519
-
520
- ScratchBlocks.FieldNote.playNote_ = function (noteNum, extensionId) {
521
- vm.runtime.emit('PLAY_NOTE', noteNum, extensionId);
522
- };
523
-
524
- // Use a collator's compare instead of localeCompare which internally
525
- // creates a collator. Using this is a lot faster in browsers that create a
526
- // collator for every localeCompare call.
527
- const collator = new Intl.Collator([], {
528
- sensitivity: 'base',
529
- numeric: true
530
- });
531
- ScratchBlocks.scratchBlocksUtils.compareStrings = function (str1, str2) {
532
- return collator.compare(str1, str2);
533
- };
534
-
535
- // Blocks wants to know if 3D CSS transforms are supported. The cross
536
- // section of browsers Scratch supports and browsers that support 3D CSS
537
- // transforms will make the return always true.
538
- //
539
- // Shortcutting to true lets us skip an expensive style recalculation when
540
- // first loading the Scratch editor.
541
- ScratchBlocks.utils.is3dSupported = function () {
542
- return true;
543
- };
544
-
545
- // brute force a toolbox update if there are no extensions loaded
546
- // Someone made a commit that broke initial toolbox populate calls back in the day
547
- // and no one can find it, this brute fixes the problem...
548
- vm.runtime.on("PROJECT_LOADED", () => {
549
- if (vm.extensionManager._loadedExtensions.size > 0) return;
550
-
551
- const workspace = ScratchBlocks.getMainWorkspace();
552
- const toolbox = workspace.getToolbox();
553
- if (!toolbox) return;
554
- const categoryMenu = toolbox.categoryMenu_;
555
- if (!categoryMenu) return;
556
- if (categoryMenu.secondTable) return;
557
-
558
- categoryMenu.dispose();
559
- categoryMenu.createDom();
560
- toolbox.populate_(workspace.options.languageTree);
561
- toolbox.position();
562
  });
 
563
 
564
- return ScratchBlocks;
565
- }
 
1
+ /* eslint-disable max-len */
2
+ import React from 'react';
3
+ import {FormattedMessage} from 'react-intl';
4
+ import {APP_NAME} from '../../brand';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ import musicIconURL from './music/music.png';
7
+ import musicInsetIconURL from './music/music-small.svg';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ import penIconURL from './pen/pen.png';
10
+ import penInsetIconURL from './pen/pen-small.svg';
11
+
12
+ import videoSensingIconURL from './videoSensing/video-sensing.png';
13
+ import videoSensingInsetIconURL from './videoSensing/video-sensing-small.svg';
14
+
15
+ import text2speechIconURL from './text2speech/text2speech.png';
16
+ import text2speechInsetIconURL from './text2speech/text2speech-small.svg';
17
+
18
+ import translateIconURL from './translate/translate.png';
19
+ import translateInsetIconURL from './translate/translate-small.png';
20
+
21
+ import makeymakeyIconURL from './makeymakey/makeymakey.png';
22
+ import makeymakeyInsetIconURL from './makeymakey/makeymakey-small.svg';
23
+
24
+ import animatedTextIconURL from './penguinmod/extensions/text extension.png';
25
+ import animatedTextInsetIconURL from './penguinmod/extensions/text extension small.svg';
26
+
27
+ import microbitIconURL from './microbit/microbit.png';
28
+ import microbitInsetIconURL from './microbit/microbit-small.svg';
29
+ import microbitConnectionIconURL from './microbit/microbit-illustration.svg';
30
+ import microbitConnectionSmallIconURL from './microbit/microbit-small.svg';
31
+
32
+ import ev3IconURL from './ev3/ev3.png';
33
+ import ev3InsetIconURL from './ev3/ev3-small.svg';
34
+ import ev3ConnectionIconURL from './ev3/ev3-hub-illustration.svg';
35
+ import ev3ConnectionSmallIconURL from './ev3/ev3-small.svg';
36
+
37
+ import wedo2IconURL from './wedo2/wedo.png'; // TODO: Rename file names to match variable/prop names?
38
+ import wedo2InsetIconURL from './wedo2/wedo-small.svg';
39
+ import wedo2ConnectionIconURL from './wedo2/wedo-illustration.svg';
40
+ import wedo2ConnectionSmallIconURL from './wedo2/wedo-small.svg';
41
+ import wedo2ConnectionTipIconURL from './wedo2/wedo-button-illustration.svg';
42
+
43
+ import boostIconURL from './boost/boost.png';
44
+ import boostInsetIconURL from './boost/boost-small.svg';
45
+ import boostConnectionIconURL from './boost/boost-illustration.svg';
46
+ import boostConnectionSmallIconURL from './boost/boost-small.svg';
47
+ import boostConnectionTipIconURL from './boost/boost-button-illustration.svg';
48
+
49
+ import gdxforIconURL from './gdxfor/gdxfor.png';
50
+ import gdxforInsetIconURL from './gdxfor/gdxfor-small.svg';
51
+ import gdxforConnectionIconURL from './gdxfor/gdxfor-illustration.svg';
52
+ import gdxforConnectionSmallIconURL from './gdxfor/gdxfor-small.svg';
53
+
54
+ // turbowarp & gallery icons
55
+ import twIcon from './tw/tw.svg';
56
+ import galleryIcon from './gallery/gallery.svg';
57
+ import customExtensionIcon from './custom/custom.svg';
58
+ import turbowarpIcon from './penguinmod/extensions/turbowarp_icon.svg';
59
+ import penguinmodLibraryExtensionIcon from './penguinmod/library.svg';
60
+ import sharkpoolGalleryIcon from './penguinmod/sharkpool-library.svg';
61
+
62
+ import ExtForgeIcon from './penguinmod/extforge.svg';
63
+ import turboBuilderIcon from './penguinmod/turbobuilder.png';
64
+ import turboBuilderDevIcon from './penguinmod/turbobuilder-dev.png';
65
+
66
+ import filesExtensionIcon from './penguinmod/extensions/files.svg';
67
+ import jgJSONExtensionIcon from './penguinmod/extensions/json.png';
68
+ import jgTailgatingExtensionIcon from './penguinmod/extensions/tailgating.png';
69
+ import jgRuntimeExtensionIcon from './penguinmod/extensions/runtime.svg';
70
+ import jgPrismExtensionIcon from './penguinmod/extensions/prism.png';
71
+ import jgDebuggingIcon from './penguinmod/extensions/debugging.svg';
72
+
73
+ import jwProtoExtensionIcon from './penguinmod/extensions/proto.svg';
74
+ import jwUniteExtensionIcon from './penguinmod/extensions/Unite.png';
75
+ import jwXmlExtensionIcon from './penguinmod/extensions/xml.png';
76
+
77
+ import jwStructsExtensionIcon from './penguinmod/extensions/ooplogo.png';
78
+
79
+ import jwArrayExtensionThumb from './penguinmod/extensions/jwArray.svg';
80
+ import jwTargetsExtensionThumb from './penguinmod/extensions/jwTargets.svg';
81
+ import jwNumExtensionThumb from './penguinmod/extensions/jwNum.svg';
82
+ import jwColorExtensionThumb from './penguinmod/extensions/jwColor.svg';
83
+ import jwVectorExtensionThumb from './penguinmod/extensions/jwVector.svg';
84
+
85
+ import iygPerlinNoiseExtensionIcon from './penguinmod/extensions/perlinnoisebanner.png';
86
+
87
+ // thank yo godslayerakp for makin pmCamera :good:
88
+ import pmCameraExtensionIcon from './penguinmod/extensions/pmcamera_thumbnail.png';
89
+
90
+ // cl waw
91
+ // import cloudlinkThumb from './penguinmod/extensions/cloudlinkThumb.png';
92
+ import cloudlinkIcon from './penguinmod/extensions/cloudlinkIcon.svg';
93
+
94
+ // thx jeremey
95
+ import canvasExtensionBanner from './penguinmod/extensions/CanvasExtensionMenu.png';
96
+ import canvasExtensionIcon from './penguinmod/extensions/CanvasSmall.png';
97
+
98
+ // griffpatch stuff that hopefully we can keep pls plsplspl !!S!
99
+ import griffpatchPhysicsThumb from './penguinmod/extensions/griffpatch_physics.png';
100
+ import griffpatchPhysicsIcon from './penguinmod/extensions/griffpatch_physicsIcon.svg';
101
+
102
+ import gp from './penguinmod/extensions/gamepad.svg';
103
+ import clippingblending from './penguinmod/extensions/clippingblending.svg';
104
+
105
+ import pointerlockThumb from './penguinmod/extensions/pointerlock.png';
106
+ import cursorThumb from './penguinmod/extensions/cursor.svg';
107
+
108
+ // LilyMakesThings 🙏
109
+ // import lmsMcUtilsIcon from './penguinmod/extensions/mcutils.png';
110
+ import lilyTempVariablesExtensionIcon from './penguinmod/orgtw/TempVariables2.svg';
111
+
112
+ // more icons so they arent just red when the extension color is not red
113
+ import gsaTempVariablesExtensionIcon from './penguinmod/extensions/tempvariables.svg';
114
+ import gsaColorUtilExtensionIcon from './penguinmod/extensions/colorutil.png';
115
+ import jgIframeExtensionIcon from './penguinmod/extensions/iframe.png';
116
+ import jgExtendedAudioExtensionIcon from './penguinmod/extensions/extendedaudio.png';
117
+ import jgScratchAuthExtensionIcon from './penguinmod/extensions/scratchauth2.svg';
118
+ import jgPermissionExtensionIcon from './penguinmod/extensions/permissions.png';
119
+ import silvxrcatOddMessagesExtensionIcon from './penguinmod/extensions/oddmessages.svg';
120
+ import jgCloneManagerExtensionIcon from './penguinmod/extensions/clonemanager.png';
121
+ import pmInlineBlocksExtensionIcon from './penguinmod/extensions/inlineblocks.png';
122
+ import jgPackagerApplicationsExtensionIcon from './penguinmod/extensions/packagedApplications.png';
123
+ import jgPackagerApplicationsInsetExtensionIcon from './penguinmod/extensions/packagedApplications_inset.png';
124
+ import spJSONExtensionIcon from './penguinmod/extensions/sp_json.svg';
125
+
126
+ // import jgTweeningExtensionIcon from './penguinmod/extensions/tween.png';
127
+ import jgsilvxrcatInterfacesExtensionIcon from './penguinmod/extensions/interfaces2.png';
128
+
129
+ // 3D MAN WTF
130
+ import jg3dExtensionIcon from './penguinmod/extensions/3d.png';
131
+ import jg3dInsetExtensionIcon from './penguinmod/extensions/3dicon.png';
132
+ import jg3dVrExtensionIcon from './penguinmod/extensions/3dVr.png';
133
+ import jg3dVrInsetExtensionIcon from './penguinmod/extensions/3dVr_Inset.png';
134
+ import fr3dPhysicsExtensionIcon from './penguinmod/extensions/3d_physics.png';
135
+ import fr3dPhysicsInsetExtensionIcon from './penguinmod/extensions/3d_physics_icon_sized.png';
136
+
137
+ // virtal realty
138
+ import jgVrExtensionIcon from './penguinmod/extensions/vr_extension.png';
139
+
140
+ import theshovelCustomStylesIcon from './penguinmod/orgtw/CustomStyles.svg';
141
+ import theshovelCanvasEffectsIcon from './penguinmod/extensions/canvas_effects.svg';
142
+ import theshovelLzCompressIcon from './penguinmod/orgtw/lz-compress2.svg';
143
+ import theshovelColorPickerIcon from './penguinmod/orgtw/ColorPicker.svg';
144
+
145
+ // sharkpool
146
+ import sharkpoolPrintingIcon from './penguinmod/extensions/printing.svg';
147
+ import sharkpoolTuneIcon from './penguinmod/extensions/tuneShark.svg';
148
+ import sharkpoolMBPIcon from './penguinmod/extensions/myBlocksPlus.svg';
149
+ import sharkpoolBCIcon from './penguinmod/extensions/BetterComments.svg';
150
+ import sharkpoolPEIcon from './penguinmod/extensions/particleEngine.svg';
151
+ import jgScriptsExtensionIcon from './penguinmod/extensions/scripts.svg';
152
+ import sharkpoolLooksExpandedIcon from './penguinmod/extensions/looksExpanded.svg';
153
+
154
+ // events
155
+ import jgStorageExtensionIcon from './penguinmod/extensions/storage.png';
156
+ import jgTimersExtensionIcon from './penguinmod/extensions/multipletimers.png';
157
+ import jgAdvancedTextExtensionIcon from './penguinmod/extensions/advancedtext.png';
158
+
159
+ import jgJavascriptExtensionIcon from './penguinmod/extensions/javascript.png';
160
+ import jgPathfindingExtensionIcon from './penguinmod/extensions/pathfinding.png';
161
+ import jgAnimationExtensionIcon from './penguinmod/extensions/animation.png';
162
+
163
+ // category expansions
164
+ import pmMotionExpansionExtensionIcon from './penguinmod/extensions/motion_expanded.png';
165
+ import pmEventsExpansionExtensionIcon from './penguinmod/extensions/events_expanded.png';
166
+ import pmControlsExpansionExtensionIcon from './penguinmod/extensions/controls_expanded.png';
167
+ import pmSensingExpansionExtensionIcon from './penguinmod/extensions/sensing_expanded.png';
168
+ import pmOperatorsExpansionExtensionIcon from './penguinmod/extensions/operators_expanded.png';
169
+
170
+ // jg: default icon if you are too lazy to make one and you want me to make one instead lololololololol
171
+ // gsa: ololololololo
172
+ import defaultExtensionIcon from './penguinmod/extensions/placeholder.png';
173
+
174
+ const urlParams = new URLSearchParams(location.search);
175
+
176
+ const IsLocal = String(window.location.href).startsWith(`http://localhost:`);
177
+ const IsLiveTests = urlParams.has('livetests');
178
+
179
+ const menuItems = [
180
+ {
181
+ name: (
182
+ <FormattedMessage
183
+ defaultMessage="Music"
184
+ description="Name for the 'Music' extension"
185
+ id="gui.extension.music.name"
186
+ />
187
+ ),
188
+ extensionId: 'music',
189
+ iconURL: musicIconURL,
190
+ insetIconURL: musicInsetIconURL,
191
+ customInsetColor: '#CF63CF',
192
+ tags: ['scratch', 'noisemaker'],
193
+ description: (
194
+ <FormattedMessage
195
+ defaultMessage="Play instruments and drums."
196
+ description="Description for the 'Music' extension"
197
+ id="gui.extension.music.description"
198
+ />
199
+ ),
200
+ featured: true
201
+ },
202
+ {
203
+ name: (
204
+ <FormattedMessage
205
+ defaultMessage="Pen"
206
+ description="Name for the 'Pen' extension"
207
+ id="gui.extension.pen.name"
208
+ />
209
+ ),
210
+ extensionId: 'pen',
211
+ iconURL: penIconURL,
212
+ insetIconURL: penInsetIconURL,
213
+ tags: ['scratch', 'graphics'],
214
+ description: (
215
+ <FormattedMessage
216
+ defaultMessage="Draw with your sprites."
217
+ description="Description for the 'Pen' extension"
218
+ id="gui.extension.pen.description"
219
+ />
220
+ ),
221
+ featured: true
222
+ },
223
+ {
224
+ name: 'Animated Text',
225
+ extensionId: 'text',
226
+ iconURL: animatedTextIconURL,
227
+ insetIconURL: animatedTextInsetIconURL,
228
+ customInsetColor: '#9A66FF',
229
+ tags: ['scratch'],
230
+ description: 'Bring words to life.',
231
+ featured: true
232
+ },
233
+ {
234
+ name: (
235
+ <FormattedMessage
236
+ defaultMessage="Video Sensing"
237
+ description="Name for the 'Video Sensing' extension"
238
+ id="gui.extension.videosensing.name"
239
+ />
240
+ ),
241
+ extensionId: 'videoSensing',
242
+ iconURL: videoSensingIconURL,
243
+ insetIconURL: videoSensingInsetIconURL,
244
+ customInsetColor: '#74BDDC',
245
+ tags: ['scratch', 'hardware'],
246
+ description: (
247
+ <FormattedMessage
248
+ defaultMessage="Sense motion with the camera."
249
+ description="Description for the 'Video Sensing' extension"
250
+ id="gui.extension.videosensing.description"
251
+ />
252
+ ),
253
+ featured: true
254
+ },
255
+ {
256
+ name: (
257
+ <FormattedMessage
258
+ defaultMessage="Text to Speech"
259
+ description="Name for the Text to Speech extension"
260
+ id="gui.extension.text2speech.name"
261
+ />
262
+ ),
263
+ extensionId: 'text2speech',
264
+ collaborator: 'Amazon Web Services',
265
+ credits: 'Google TTS',
266
+ iconURL: text2speechIconURL,
267
+ insetIconURL: text2speechInsetIconURL,
268
+ customInsetColor: '#9966FF',
269
+ tags: ['scratch', 'noisemaker'],
270
+ description: (
271
+ <FormattedMessage
272
+ defaultMessage="Make your projects talk."
273
+ description="Description for the Text to speech extension"
274
+ id="gui.extension.text2speech.description"
275
+ />
276
+ ),
277
+ featured: true,
278
+ internetConnectionRequired: true
279
+ },
280
+ {
281
+ name: (
282
+ <FormattedMessage
283
+ defaultMessage="Translate"
284
+ description="Name for the Translate extension"
285
+ id="gui.extension.translate.name"
286
+ />
287
+ ),
288
+ extensionId: 'translate',
289
+ collaborator: 'Google',
290
+ iconURL: translateIconURL,
291
+ insetIconURL: translateInsetIconURL,
292
+ customInsetColor: '#5CB1D6',
293
+ tags: ['scratch'],
294
+ description: (
295
+ <FormattedMessage
296
+ defaultMessage="Translate text into many languages."
297
+ description="Description for the Translate extension"
298
+ id="gui.extension.translate.description"
299
+ />
300
+ ),
301
+ featured: true,
302
+ internetConnectionRequired: true
303
+ },
304
+ {
305
+ name: 'Makey Makey',
306
+ extensionId: 'makeymakey',
307
+ collaborator: 'JoyLabz',
308
+ iconURL: makeymakeyIconURL,
309
+ insetIconURL: makeymakeyInsetIconURL,
310
+ customInsetColor: '#E64D00',
311
+ tags: ['scratch', 'hardware'],
312
+ description: (
313
+ <FormattedMessage
314
+ defaultMessage="Make anything into a key."
315
+ description="Description for the 'Makey Makey' extension"
316
+ id="gui.extension.makeymakey.description"
317
+ />
318
+ ),
319
+ featured: true
320
+ },
321
+ {
322
+ name: 'Stage Camera',
323
+ extensionId: 'pmCamera',
324
+ iconURL: pmCameraExtensionIcon,
325
+ tags: ['penguinmod'],
326
+ description: (
327
+ <FormattedMessage
328
+ defaultMessage="Allows the camera to move around anywhere on the stage."
329
+ description="The description for the PenguinMod Camera extension."
330
+ id="pm.extension.camera.description"
331
+ />
332
+ ),
333
+ credits: 'Inspired by⠀⠀⠀⠀⠀⠀ DT-is-not-available',
334
+ featured: true
335
+ },
336
+ {
337
+ name: 'Files',
338
+ extensionId: 'twFiles',
339
+ twDeveloper: 'GarboMuffin',
340
+ iconURL: filesExtensionIcon,
341
+ insetIconURL: turbowarpIcon,
342
+ tags: ['turbowarp', 'datamgmt'],
343
+ description: 'Blocks for reading and creating files.',
344
+ featured: true
345
+ },
346
+ {
347
+ name: 'Zip',
348
+ extensionId: 'https://extensions.turbowarp.org/CST1229/zip.js',
349
+ iconURL: 'https://extensions.turbowarp.org/images/CST1229/zip.svg',
350
+ insetIconURL: turbowarpIcon,
351
+ tags: ['turbowarp', 'datamgmt'],
352
+ description: 'Create and edit .zip format files, including .sb3 files.',
353
+ twDeveloper: 'CST1229',
354
+ featured: true
355
+ },
356
+ {
357
+ name: 'Pen+',
358
+ extensionId: 'https://extensions.penguinmod.com/extensions/ObviousAlexC/PenPlus.js',
359
+ tags: ['categoryexpansion', 'graphics'],
360
+ iconURL: 'https://extensions.penguinmod.com/images/ObviousAlexC/PenPlus.svg',
361
+ description: 'An extension to the Pen category! Adds blocks for drawing triangles using textures and tints, drawing images and editing their pixels, etc.',
362
+ featured: true,
363
+ extDeveloper: 'pinksheep2917'
364
+ },
365
+ {
366
+ name: 'Sound Systems',
367
+ extensionId: 'jgExtendedAudio',
368
+ iconURL: jgExtendedAudioExtensionIcon,
369
+ tags: ['penguinmod', 'categoryexpansion', 'noisemaker'],
370
+ description: 'An audio grouping system for more intensive audio work.',
371
+ featured: true
372
+ },
373
+ {
374
+ name: 'Tune Shark V3',
375
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/Tune-Shark-V3.js',
376
+ iconURL: sharkpoolTuneIcon,
377
+ tags: ['penguinmod', 'categoryexpansion', 'noisemaker'],
378
+ description: 'Advanced audio engine with complex sound control, multiple audio effects and more!',
379
+ extDeveloper: 'SharkPool',
380
+ featured: true
381
+ },
382
+ {
383
+ name: 'Sound Waves',
384
+ extensionId: 'https://extensions.penguinmod.com/extensions/SharkPool/Sound-Waves.js',
385
+ iconURL: 'https://extensions.penguinmod.com/images/SharkPool/Sound-Waves.svg',
386
+ tags: ['penguinmod', 'noisemaker'],
387
+ description: 'Make sounds with oscillators!',
388
+ extDeveloper: 'SharkPool',
389
+ featured: true
390
+ },
391
+ {
392
+ name: 'Looks Expanded',
393
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/Looks-Expanded.js',
394
+ iconURL: sharkpoolLooksExpandedIcon,
395
+ tags: ['penguinmod', 'categoryexpansion', 'graphics'],
396
+ description: 'Expansion of the Looks Category.',
397
+ extDeveloper: 'SharkPool, CST1229',
398
+ featured: true
399
+ },
400
+ {
401
+ name: 'Motion Expansion',
402
+ extensionId: 'pmMotionExpansion',
403
+ iconURL: pmMotionExpansionExtensionIcon,
404
+ tags: ['penguinmod', 'categoryexpansion'],
405
+ description: 'More small motion blocks for movement or collision.',
406
+ featured: true,
407
+ credits: 'Some blocks from NexusKitten'
408
+ },
409
+ {
410
+ name: 'Events Expansion',
411
+ extensionId: 'pmEventsExpansion',
412
+ iconURL: pmEventsExpansionExtensionIcon,
413
+ tags: ['penguinmod', 'categoryexpansion'],
414
+ description: 'More events for sending & receiving information, notifing specific sprites or better control when things should happen.',
415
+ featured: true,
416
+ credits: 'Some blocks from LilyMakesThings'
417
+ },
418
+ {
419
+ name: 'Controls Expansion',
420
+ extensionId: 'pmControlsExpansion',
421
+ iconURL: pmControlsExpansionExtensionIcon,
422
+ tags: ['penguinmod', 'categoryexpansion'],
423
+ description: 'More control blocks for animations, complex systems or cleaner one-time use blocks.',
424
+ featured: true,
425
+ credits: '"new thread" by CubesterYT, CST1229, SharkPool'
426
+ },
427
+ {
428
+ name: 'Sensing Expansion',
429
+ extensionId: 'pmSensingExpansion',
430
+ iconURL: pmSensingExpansionExtensionIcon,
431
+ tags: ['penguinmod', 'categoryexpansion'],
432
+ description: "More sensing blocks for specific use cases or interacting with the user's device.",
433
+ credits: 'Some blocks from SharkPool-SP',
434
+ featured: true
435
+ },
436
+ {
437
+ name: 'Operators Expansion',
438
+ extensionId: 'pmOperatorsExpansion',
439
+ iconURL: pmOperatorsExpansionExtensionIcon,
440
+ tags: ['penguinmod', 'categoryexpansion', 'math'],
441
+ description: 'More operators like nand, nor, character code to character, reading multiple lined text line by line, etc.',
442
+ featured: true
443
+ },
444
+ {
445
+ name: 'My Blocks+',
446
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/My-Blocks-Plus.js',
447
+ iconURL: sharkpoolMBPIcon,
448
+ tags: ['penguinmod', 'categoryexpansion'],
449
+ description: 'Create private or global custom blocks with custom inputs, colors, and more!',
450
+ extDeveloper: 'SharkPool, CST1229, 0znzw',
451
+ featured: true
452
+ },
453
+ {
454
+ name: 'Better Comments',
455
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/Better-Comments.js',
456
+ iconURL: sharkpoolBCIcon,
457
+ tags: ['penguinmod', 'categoryexpansion'],
458
+ description: 'Better Comments with Customization and Markdown support',
459
+ extDeveloper: 'SharkPool',
460
+ featured: true
461
+ },
462
+ {
463
+ name: 'JSON',
464
+ extensionId: 'jgJSON',
465
+ iconURL: jgJSONExtensionIcon,
466
+ tags: ['penguinmod', 'datamgmt'],
467
+ description: 'Blocks for handling JSON objects and Arrays.',
468
+ featured: true
469
+ },
470
+ {
471
+ name: 'Swift JSON',
472
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/JSON-Array.js',
473
+ iconURL: spJSONExtensionIcon,
474
+ tags: ['penguinmod', 'datamgmt'],
475
+ extDeveloper: 'SharkPool',
476
+ description: 'POTENTIALLY DANGEROUS, but faster extension for handling JSON objects and arrays. Recommended if you are heavily using JSON several times in a project.',
477
+ featured: true
478
+ },
479
+ {
480
+ name: 'Particle Engine',
481
+ extensionId: 'https://sharkpools-extensions.vercel.app/extension-code/Particle-Engine.js',
482
+ iconURL: sharkpoolPEIcon,
483
+ tags: ['penguinmod', 'graphics'],
484
+ description: 'Create powerful Particle Engines without Clones',
485
+ extDeveloper: 'SharkPool',
486
+ featured: true
487
+ },
488
+ {
489
+ name: 'Custom Styles',
490
+ extensionId: 'shovelcss',
491
+ iconURL: theshovelCustomStylesIcon,
492
+ tags: ['penguinmod', 'graphics'],
493
+ description: 'Customize the appearance of variable monitors and prompts in your project.',
494
+ extDeveloper: 'TheShovel',
495
+ featured: true
496
+ },
497
+ {
498
+ name: 'Physics',
499
+ extensionId: 'https://extensions.turbowarp.org/box2d.js',
500
+ tags: ['turbowarp'],
501
+ extDeveloper: 'griffpatch',
502
+ iconURL: griffpatchPhysicsThumb,
503
+ insetIconURL: griffpatchPhysicsIcon,
504
+ description: 'Box2D Physics extension created by Griffpatch.',
505
+ customInsetColor: '#D9F0FF',
506
+ featured: true
507
+ },
508
+ {
509
+ name: 'Tweening',
510
+ extensionId: 'jgTween',
511
+ credits: 'easings.net, Arrow & GarboMuffin',
512
+ description: 'Smoothly animating values using different easing functions and directions.',
513
+ iconURL: 'https://extensions.turbowarp.org/images/JeremyGamer13/tween.svg',
514
+ tags: ['penguinmod'],
515
+ featured: true
516
+ },
517
+ {
518
+ name: 'Tailgating',
519
+ extensionId: 'jgTailgating',
520
+ description: 'Have sprites & clones follow behind other sprites & clones by an offset, like RPG party members.',
521
+ iconURL: jgTailgatingExtensionIcon,
522
+ tags: ['penguinmod'],
523
+ featured: true
524
+ },
525
+ {
526
+ name: 'Tile Grids',
527
+ extensionId: 'https://extensions.penguinmod.com/extensions/SharkPool/Tile-Grids.js',
528
+ iconURL: 'https://extensions.penguinmod.com/images/SharkPool/Tile-Grids.svg',
529
+ tags: ['penguinmod'],
530
+ description: 'Place sprites on grids.',
531
+ extDeveloper: 'SharkPool-SP',
532
+ featured: true
533
+ },
534
+ {
535
+ name: 'Canvas Effects',
536
+ extensionId: 'theshovelcanvaseffects',
537
+ iconURL: theshovelCanvasEffectsIcon,
538
+ tags: ['penguinmod', 'graphics'],
539
+ description: 'Apply visual effects to the entire stage.',
540
+ extDeveloper: 'TheShovel',
541
+ credits: 'SharkPool',
542
+ featured: true
543
+ },
544
+ {
545
+ name: 'Clones+',
546
+ extensionId: 'https://extensions.turbowarp.org/Lily/ClonesPlus.js',
547
+ tags: ['turbowarp', 'categoryexpansion'],
548
+ iconURL: 'https://extensions.turbowarp.org/images/Lily/ClonesPlus.svg',
549
+ insetIconURL: turbowarpIcon,
550
+ description: "Expansion of Scratch's clone features.",
551
+ featured: true,
552
+ twDeveloper: 'LilyMakesThings'
553
+ },
554
+ {
555
+ name: 'Skins',
556
+ extensionId: 'https://extensions.turbowarp.org/Lily/Skins.js',
557
+ tags: ['turbowarp', 'graphics'],
558
+ iconURL: 'https://extensions.turbowarp.org/images/Lily/Skins.svg',
559
+ insetIconURL: turbowarpIcon,
560
+ description: 'Have your sprites show themselves as other images or costumes.',
561
+ featured: true,
562
+ twDeveloper: 'LilyMakesThings'
563
+ },
564
+ {
565
+ name: 'Multiple Timers',
566
+ extensionId: 'jgTimers',
567
+ iconURL: jgTimersExtensionIcon,
568
+ tags: ['penguinmod'],
569
+ description: 'Create different timers you can control seperately.',
570
+ eventSubmittor: 'Arrow',
571
+ featured: true
572
+ },
573
+ {
574
+ name: 'Temporary Variables',
575
+ extensionId: 'tempVars',
576
+ iconURL: gsaTempVariablesExtensionIcon,
577
+ tags: ['penguinmod'],
578
+ description: 'Create variables for use in one block stack. Useful to not clutter the variable list with variables you only use once.',
579
+ credits: 'LilyMakesThings',
580
+ featured: true
581
+ },
582
+ {
583
+ name: 'TurboWarp Temporary Variables',
584
+ extensionId: 'lmsTempVars2',
585
+ iconURL: lilyTempVariablesExtensionIcon,
586
+ tags: ['turbowarp'],
587
+ description: 'Create disposable runtime or thread variables.',
588
+ insetIconURL: turbowarpIcon,
589
+ credits: 'LilyMakesThings',
590
+ featured: true
591
+ },
592
+ {
593
+ name: 'Runtime Modifications',
594
+ extensionId: 'jgRuntime',
595
+ tags: ['penguinmod'],
596
+ iconURL: jgRuntimeExtensionIcon,
597
+ description: 'Blocks for updating Scratch objects like the stage and sprites.',
598
+ credits: 'TheShovel, showierdata9978, SharkPool',
599
+ featured: true
600
+ },
601
+ {
602
+ name: 'Font Manager',
603
+ extensionId: 'https://extensions.penguinmod.com/extensions/SharkPool/Font-Manager.js',
604
+ iconURL: 'https://extensions.penguinmod.com/images/SharkPool/Font-Manager.svg',
605
+ tags: ['penguinmod', 'graphics'],
606
+ description: 'Manage, create, and delete fonts.',
607
+ credits: 'SharkPool, Ashimee',
608
+ featured: true
609
+ },
610
+ {
611
+ name: 'Storage',
612
+ extensionId: 'jgStorage',
613
+ iconURL: jgStorageExtensionIcon,
614
+ tags: ['penguinmod', 'datamgmt'],
615
+ description: 'Store data after PenguinMod has already been closed out. Basic Server Storage is also included.',
616
+ eventSubmittor: 'Fir & silvxrcat',
617
+ featured: true
618
+ },
619
+ {
620
+ name: 'HTTP',
621
+ extensionId: 'https://extensions.turbowarp.org/godslayerakp/http.js',
622
+ iconURL: 'https://extensions.turbowarp.org/images/godslayerakp/http.svg',
623
+ insetIconURL: turbowarpIcon,
624
+ tags: ['turbowarp'],
625
+ description: 'Comprehensive extension for interacting with external websites.',
626
+ featured: true,
627
+ internetConnectionRequired: true,
628
+ customInsetColor: '#ff4d4d'
629
+ },
630
+ {
631
+ name: 'CloudLink',
632
+ extensionId: 'https://extensions.penguinmod.com/extensions/MikeDev101/cloudlink.js',
633
+ tags: ['turbowarp', 'penguinmod'],
634
+ insetIconURL: cloudlinkIcon,
635
+ iconURL: 'https://extensions.penguinmod.com/images/MikeDev101/cloudlink.svg',
636
+ description: 'A powerful WebSocket extension for Scratch.',
637
+ featured: true,
638
+ extDeveloper: 'MikeDev',
639
+ internetConnectionRequired: true
640
+ },
641
+ {
642
+ name: 'Scripts',
643
+ extensionId: 'jgScripts',
644
+ iconURL: jgScriptsExtensionIcon,
645
+ tags: ['penguinmod', 'datamgmt'],
646
+ description: 'Create compiled scripts with blocks while the project is running.',
647
+ featured: true
648
+ },
649
+ {
650
+ name: 'Pang API',
651
+ extensionId: 'https://extensions.penguinmod.com/extensions/SammerLOL/pangapi.js',
652
+ iconURL: 'https://extensions.penguinmod.com/images/SammerLOL/pangapi.png',
653
+ tags: ['penguinmod'],
654
+ description: 'Fetch information from the PenguinMod API.',
655
+ extDeveloper: 'oc9x97, Ianyourgod',
656
+ featured: true
657
+ },
658
+ {
659
+ name: '3D Math',
660
+ extensionId: 'https://extensions.penguinmod.com/extensions/ObviousAlexC/3DMath.js',
661
+ iconURL: 'https://extensions.penguinmod.com/images/ObviousAlexC/3DMath.svg',
662
+ tags: ['penguinmod', '3d', 'graphics', 'math'],
663
+ description: 'A handful of utilities for making your own sprite-based 3D engine.',
664
+ extDeveloper: 'pinksheep2917',
665
+ featured: true
666
+ },
667
+ /*{ i dont like this extension anymore it kinda sucks
668
+ name: 'Extra Mathematics',
669
+ extensionId: 'https://extensions.penguinmod.com/extensions/jwklong/mathematics.js',
670
+ iconURL: 'https://extensions.penguinmod.com/images/jwklong/mathematics.png',
671
+ tags: ['penguinmod', 'categoryexpansion', 'math'],
672
+ description: 'Complicated maths extension for nerds.',
673
+ extDeveloper: 'jwklong',
674
+ featured: false
675
+ },*/
676
+ {
677
+ name: 'Random Utilities',
678
+ extensionId: 'https://extensions.penguinmod.com/extensions/Gen1x/random_utils.js',
679
+ iconURL: 'https://extensions.penguinmod.com/images/Gen1x/randomutils.png',
680
+ tags: ['penguinmod'],
681
+ description: 'Many blocks related to generating random values, including seed-based number generation, true number generation, UUID\'s, random strings, etc.',
682
+ extDeveloper: 'G1nX',
683
+ featured: true
684
+ },
685
+ {
686
+ name: 'LZ Compress',
687
+ extensionId: 'shovellzcompresss',
688
+ iconURL: theshovelLzCompressIcon,
689
+ tags: ['penguinmod', 'datamgmt'],
690
+ description: 'Compress and decompress text using lz-string.',
691
+ extDeveloper: 'TheShovel',
692
+ featured: true
693
+ },
694
+ {
695
+ name: 'Prism',
696
+ extensionId: 'jgPrism',
697
+ tags: ['penguinmod', 'datamgmt'],
698
+ iconURL: jgPrismExtensionIcon,
699
+ description: 'Blocks for specific use-cases or major convenience.',
700
+ featured: true
701
+ },
702
+ {
703
+ name: 'Odd Messages',
704
+ extensionId: 'oddMessage',
705
+ tags: ['penguinmod'],
706
+ iconURL: silvxrcatOddMessagesExtensionIcon,
707
+ description: 'For logging and variable utilization.',
708
+ featured: true,
709
+ extDeveloper: 'silvxrcat'
710
+ },
711
+ {
712
+ name: 'HTML iframe Elements',
713
+ extensionId: 'jgIframe',
714
+ iconURL: jgIframeExtensionIcon,
715
+ tags: ['penguinmod'],
716
+ description: 'Blocks to place and move around frames that contain HTML content or websites.',
717
+ featured: true,
718
+ internetConnectionRequired: true
719
+ },
720
+ {
721
+ name: 'Color Picker',
722
+ extensionId: 'shovelColorPicker',
723
+ iconURL: theshovelColorPickerIcon,
724
+ tags: ['penguinmod'],
725
+ description: 'Allow the user to choose a color using the built-in color picker, so you don\'t need to make your own.',
726
+ extDeveloper: 'TheShovel',
727
+ featured: true
728
+ },
729
+ {
730
+ name: 'Color Utility Blocks',
731
+ extensionId: 'colors',
732
+ iconURL: gsaColorUtilExtensionIcon,
733
+ tags: ['penguinmod'],
734
+ description: 'Converters for Hex, RGB, HSV and Decimal colors and other color related things.',
735
+ featured: true
736
+ },
737
+ {
738
+ name: 'All Menus',
739
+ extensionId: 'https://extensions.penguinmod.com/extensions/Lily/AllMenus.js',
740
+ iconURL: 'https://extensions.penguinmod.com/images/Lily/AllMenus.svg',
741
+ tags: ['penguinmod'],
742
+ description: 'Every dropdown menu for each block, in one extension.',
743
+ extDeveloper: 'LilyMakesThings',
744
+ featured: true
745
+ },
746
+ {
747
+ name: (
748
+ <FormattedMessage
749
+ defaultMessage="Labels"
750
+ description="Name of Proto extension"
751
+ id="jwProto.jwProtoExtension.name"
752
+ />
753
+ ),
754
+ extensionId: 'jwProto',
755
+ iconURL: jwProtoExtensionIcon,
756
+ tags: ['penguinmod'],
757
+ description: (
758
+ <FormattedMessage
759
+ // change this back if you update the extension to have more things
760
+ defaultMessage="Labelling and Placeholders."
761
+ description="Description of Proto extension"
762
+ id="jwProto.jwProtoExtension.description"
763
+ />
764
+ ),
765
+ featured: true
766
+ },
767
+ {
768
+ name: (
769
+ <FormattedMessage
770
+ defaultMessage="Perlin Noise"
771
+ description="Name of perlin noise extension"
772
+ id="iygPerlin.iygPerlinExtension.name"
773
+ />
774
+ ),
775
+ extensionId: 'iygPerlin',
776
+ tags: ['penguinmod'],
777
+ iconURL: iygPerlinNoiseExtensionIcon,
778
+ description: (
779
+ <FormattedMessage
780
+ defaultMessage="Blocks for generating and using Perlin noise. Good for generating terrain, clouds, and other things."
781
+ description="Description of perlin noise extension"
782
+ id="iygPerlin.iygPerlinExtension.description"
783
+ />
784
+ ),
785
+ featured: true
786
+ },
787
+ {
788
+ name: 'GamePad',
789
+ extensionId: 'Gamepad',
790
+ tags: ['turbowarp', 'hardware'],
791
+ insetIconURL: turbowarpIcon,
792
+ twDeveloper: 'GarboMuffin',
793
+ iconURL: gp,
794
+ description: (
795
+ <FormattedMessage
796
+ defaultMessage="Directly access gamepads instead of just mapping buttons to keys."
797
+ description="Description for the 'GamePad' extension"
798
+ id="GamepadExtension.GamepadExtension.description"
799
+ />
800
+ ),
801
+ featured: true
802
+ },
803
+ {
804
+ name: 'Printing',
805
+ tags: ['penguinmod', 'hardware'],
806
+ extensionId: 'sharkpoolPrinting',
807
+ iconURL: sharkpoolPrintingIcon,
808
+ description: 'Allows you to show a dialog for printing text, images, and custom HTML to a printer.',
809
+ featured: true
810
+ },
811
+ {
812
+ name: 'Clipping and Blending',
813
+ extensionId: 'https://extensions.turbowarp.org/Xeltalliv/clippingblending.js',
814
+ iconURL: clippingblending,
815
+ tags: ['turbowarp', 'graphics'],
816
+ insetIconURL: turbowarpIcon,
817
+ description: 'Clipping outside of a specified rectangular area and additive color blending.',
818
+ featured: true,
819
+ twDeveloper: 'Vadik1'
820
+ },
821
+ {
822
+ name: 'Pointer Lock',
823
+ extensionId: 'https://extensions.turbowarp.org/pointerlock.js',
824
+ tags: ['turbowarp'],
825
+ insetIconURL: turbowarpIcon,
826
+ iconURL: pointerlockThumb,
827
+ description: (
828
+ <FormattedMessage
829
+ defaultMessage="A extension to lock the mouse cursor in the stage."
830
+ description="Scratch utilities"
831
+ id="gui.extension.pointerlock.description"
832
+ />
833
+ ),
834
+ featured: true,
835
+ internetConnectionRequired: false,
836
+ twDeveloper: 'GarboMuffin'
837
+ },
838
+ {
839
+ name: 'Mouse Cursor',
840
+ extensionId: 'https://extensions.turbowarp.org/cursor.js',
841
+ tags: ['turbowarp'],
842
+ insetIconURL: turbowarpIcon,
843
+ iconURL: 'https://extensions.turbowarp.org/images/cursor.png',
844
+ description: (
845
+ <FormattedMessage
846
+ defaultMessage="A extension to change what the mouse cursor looks like on the stage."
847
+ description="Scratch utilities"
848
+ id="gui.extension.MouseCursor.description"
849
+ />
850
+ ),
851
+ featured: true,
852
+ internetConnectionRequired: false,
853
+ twDeveloper: 'GarboMuffin'
854
+ },
855
+ {
856
+ name: 'Scratch Authentication',
857
+ extensionId: 'jgScratchAuthenticate',
858
+ iconURL: jgScratchAuthExtensionIcon,
859
+ tags: ['penguinmod'],
860
+ description: "Interact with Scratch Authentication to prove the player is a real scratch user.",
861
+ featured: true
862
+ },
863
+ {
864
+ name: 'JavaScript',
865
+ extensionId: 'jgJavascript',
866
+ iconURL: jgJavascriptExtensionIcon,
867
+ tags: ['penguinmod', 'programminglanguage'],
868
+ description: 'Run your own custom code written in JavaScript!',
869
+ featured: true
870
+ },
871
+ {
872
+ name: 'Arrays',
873
+ extensionId: 'jwArray',
874
+ iconURL: jwArrayExtensionThumb,
875
+ tags: ['penguinmod', 'datamgmt'],
876
+ description: 'Store data efficiently in multi-purpose arrays.',
877
+ extDeveloper: 'jwklong',
878
+ featured: true
879
+ },
880
+ {
881
+ name: 'Targets',
882
+ extensionId: 'jwTargets',
883
+ iconURL: jwTargetsExtensionThumb,
884
+ tags: ['penguinmod'],
885
+ description: 'Direct access to sprites and their clones.',
886
+ extDeveloper: 'jwklong',
887
+ featured: true
888
+ },
889
+ {
890
+ name: 'Infinity',
891
+ extensionId: 'jwNum',
892
+ iconURL: jwNumExtensionThumb,
893
+ tags: ['penguinmod', 'math'],
894
+ description: 'Advanced number type capable of really big numbers.',
895
+ extDeveloper: 'jwklong',
896
+ credits: 'Naruyoko for ExpantaNum.js',
897
+ featured: true
898
+ },
899
+ {
900
+ name: 'Color',
901
+ extensionId: 'jwColor',
902
+ iconURL: jwColorExtensionThumb,
903
+ tags: ['penguinmod', 'graphics'],
904
+ description: 'Utilities for anything involving colors.',
905
+ extDeveloper: 'jwklong',
906
+ featured: true
907
+ },
908
+ {
909
+ name: 'Vector',
910
+ extensionId: 'jwVector',
911
+ iconURL: jwVectorExtensionThumb,
912
+ tags: ['penguinmod', 'math'],
913
+ description: 'Vector type for calculating with X and Y coordinates.',
914
+ extDeveloper: 'jwklong',
915
+ featured: true
916
+ },
917
+ {
918
+ name: 'micro:bit',
919
+ extensionId: 'microbit',
920
+ collaborator: 'micro:bit',
921
+ iconURL: microbitIconURL,
922
+ insetIconURL: microbitInsetIconURL,
923
+ tags: ['scratch', 'hardware'],
924
+ description: (
925
+ <FormattedMessage
926
+ defaultMessage="Connect your projects with the world."
927
+ description="Description for the 'micro:bit' extension"
928
+ id="gui.extension.microbit.description"
929
+ />
930
+ ),
931
+ featured: true,
932
+ disabled: false,
933
+ bluetoothRequired: true,
934
+ internetConnectionRequired: true,
935
+ launchPeripheralConnectionFlow: true,
936
+ useAutoScan: false,
937
+ connectionIconURL: microbitConnectionIconURL,
938
+ connectionSmallIconURL: microbitConnectionSmallIconURL,
939
+ connectingMessage: (
940
+ <FormattedMessage
941
+ defaultMessage="Connecting"
942
+ description="Message to help people connect to their micro:bit."
943
+ id="gui.extension.microbit.connectingMessage"
944
+ />
945
+ ),
946
+ helpLink: 'https://scratch.mit.edu/microbit'
947
+ },
948
+ {
949
+ name: 'LEGO MINDSTORMS EV3',
950
+ extensionId: 'ev3',
951
+ collaborator: 'LEGO',
952
+ iconURL: ev3IconURL,
953
+ insetIconURL: ev3InsetIconURL,
954
+ tags: ['scratch', 'hardware'],
955
+ description: (
956
+ <FormattedMessage
957
+ defaultMessage="Build interactive robots and more."
958
+ description="Description for the 'LEGO MINDSTORMS EV3' extension"
959
+ id="gui.extension.ev3.description"
960
+ />
961
+ ),
962
+ featured: true,
963
+ disabled: false,
964
+ bluetoothRequired: true,
965
+ internetConnectionRequired: true,
966
+ launchPeripheralConnectionFlow: true,
967
+ useAutoScan: false,
968
+ connectionIconURL: ev3ConnectionIconURL,
969
+ connectionSmallIconURL: ev3ConnectionSmallIconURL,
970
+ customInsetColor: '#FFBF00',
971
+ connectingMessage: (
972
+ <FormattedMessage
973
+ defaultMessage="Connecting. Make sure the pin on your EV3 is set to 1234."
974
+ description="Message to help people connect to their EV3. Must note the PIN should be 1234."
975
+ id="gui.extension.ev3.connectingMessage"
976
+ />
977
+ ),
978
+ helpLink: 'https://scratch.mit.edu/ev3'
979
+ },
980
+ {
981
+ name: 'LEGO BOOST',
982
+ extensionId: 'boost',
983
+ collaborator: 'LEGO',
984
+ iconURL: boostIconURL,
985
+ insetIconURL: boostInsetIconURL,
986
+ tags: ['scratch', 'hardware'],
987
+ description: (
988
+ <FormattedMessage
989
+ defaultMessage="Bring robotic creations to life."
990
+ description="Description for the 'LEGO BOOST' extension"
991
+ id="gui.extension.boost.description"
992
+ />
993
+ ),
994
+ featured: true,
995
+ disabled: false,
996
+ bluetoothRequired: true,
997
+ internetConnectionRequired: true,
998
+ launchPeripheralConnectionFlow: true,
999
+ useAutoScan: true,
1000
+ connectionIconURL: boostConnectionIconURL,
1001
+ connectionSmallIconURL: boostConnectionSmallIconURL,
1002
+ connectionTipIconURL: boostConnectionTipIconURL,
1003
+ customInsetColor: '#FFAB19',
1004
+ connectingMessage: (
1005
+ <FormattedMessage
1006
+ defaultMessage="Connecting"
1007
+ description="Message to help people connect to their BOOST."
1008
+ id="gui.extension.boost.connectingMessage"
1009
+ />
1010
+ ),
1011
+ helpLink: 'https://scratch.mit.edu/boost'
1012
+ },
1013
+ {
1014
+ name: 'LEGO Education WeDo 2.0',
1015
+ extensionId: 'wedo2',
1016
+ collaborator: 'LEGO',
1017
+ iconURL: wedo2IconURL,
1018
+ insetIconURL: wedo2InsetIconURL,
1019
+ description: (
1020
+ <FormattedMessage
1021
+ defaultMessage="Build with motors and sensors."
1022
+ description="Description for the 'LEGO WeDo 2.0' extension"
1023
+ id="gui.extension.wedo2.description"
1024
+ />
1025
+ ),
1026
+ featured: true,
1027
+ disabled: false,
1028
+ tags: ['scratch', 'hardware'],
1029
+ bluetoothRequired: true,
1030
+ internetConnectionRequired: true,
1031
+ launchPeripheralConnectionFlow: true,
1032
+ useAutoScan: true,
1033
+ connectionIconURL: wedo2ConnectionIconURL,
1034
+ connectionSmallIconURL: wedo2ConnectionSmallIconURL,
1035
+ connectionTipIconURL: wedo2ConnectionTipIconURL,
1036
+ customInsetColor: '#FF6680',
1037
+ connectingMessage: (
1038
+ <FormattedMessage
1039
+ defaultMessage="Connecting"
1040
+ description="Message to help people connect to their WeDo."
1041
+ id="gui.extension.wedo2.connectingMessage"
1042
+ />
1043
+ ),
1044
+ helpLink: 'https://scratch.mit.edu/wedo'
1045
+ },
1046
+ {
1047
+ name: 'Go Direct Force & Acceleration',
1048
+ extensionId: 'gdxfor',
1049
+ collaborator: 'Vernier',
1050
+ iconURL: gdxforIconURL,
1051
+ insetIconURL: gdxforInsetIconURL,
1052
+ customInsetColor: '#4C97FF',
1053
+ tags: ['scratch', 'hardware'],
1054
+ description: (
1055
+ <FormattedMessage
1056
+ defaultMessage="Sense push, pull, motion, and spin."
1057
+ description="Description for the Vernier Go Direct Force and Acceleration sensor extension"
1058
+ id="gui.extension.gdxfor.description"
1059
+ />
1060
+ ),
1061
+ featured: true,
1062
+ disabled: false,
1063
+ bluetoothRequired: true,
1064
+ internetConnectionRequired: true,
1065
+ launchPeripheralConnectionFlow: true,
1066
+ useAutoScan: false,
1067
+ connectionIconURL: gdxforConnectionIconURL,
1068
+ connectionSmallIconURL: gdxforConnectionSmallIconURL,
1069
+ connectingMessage: (
1070
+ <FormattedMessage
1071
+ defaultMessage="Connecting"
1072
+ description="Message to help people connect to their force and acceleration sensor."
1073
+ id="gui.extension.gdxfor.connectingMessage"
1074
+ />
1075
+ ),
1076
+ helpLink: 'https://scratch.mit.edu/vernier'
1077
+ },
1078
+ {
1079
+ name: (
1080
+ <FormattedMessage
1081
+ defaultMessage="PenguinMod Extra Extensions"
1082
+ description="Name of library item to open the Extra Extensions gallery"
1083
+ id="pm.extraLibraryExtensions.name"
1084
+ />
1085
+ ),
1086
+ href: 'https://extensions.penguinmod.com/',
1087
+ extensionId: 'special_penguinmodExtensionLibrary',
1088
+ iconURL: penguinmodLibraryExtensionIcon,
1089
+ description: (
1090
+ <FormattedMessage
1091
+ defaultMessage="See some user-submitted extensions. Opens in a new tab."
1092
+ description="Description of library item to open the Extra Extensions gallery"
1093
+ id="pm.extraLibraryExtensions.description"
1094
+ />
1095
+ ),
1096
+ tags: ['penguinmod', 'library'],
1097
+ featured: true
1098
+ },
1099
+ {
1100
+ name: (
1101
+ <FormattedMessage
1102
+ defaultMessage="TurboWarp Extension Gallery"
1103
+ description="Name of extensions.turbowarp.org in extension library"
1104
+ id="tw.extensionGallery.name"
1105
+ values={{
1106
+ APP_NAME: "TurboWarp"
1107
+ }}
1108
+ />
1109
+ ),
1110
+ href: 'https://extensions.turbowarp.org/',
1111
+ extensionId: 'special_turbowarpExtensionLibrary',
1112
+ iconURL: galleryIcon,
1113
+ description: (
1114
+ <FormattedMessage
1115
+ // eslint-disable-next-line max-len
1116
+ defaultMessage="We list many TurboWarp extensions here for convenience, but you can find even more on extensions.turbowarp.org."
1117
+ description="Description of extensions.turbowarp.org in extension library"
1118
+ id="tw.extensionGallery.description"
1119
+ />
1120
+ ),
1121
+ tags: ['tw', 'turbowarp', 'library'],
1122
+ featured: true
1123
+ },
1124
+ {
1125
+ name: 'SharkPool\'s Extension Collection',
1126
+ href: 'https://sharkpools-extensions.vercel.app/?originPM=true',
1127
+ extensionId: 'special_sharkpoolExtensionLibrary',
1128
+ iconURL: sharkpoolGalleryIcon,
1129
+ description: 'Tons of extensions created by SharkPool.\n\nClick on an extension while this menu is open to add it to your project.',
1130
+ credits: 'Listed in the site',
1131
+ tags: ['library'],
1132
+ featured: true
1133
+ },{
1134
+ // not really an extension, but it's easiest to present it as one
1135
+ name: 'ExtForge',
1136
+ href: 'https://jwklong.github.io/extforge',
1137
+ extensionId: 'special_extforge',
1138
+ iconURL: ExtForgeIcon,
1139
+ description: 'Create extensions with a block-based UI.',
1140
+ extDeveloper: 'jwklong',
1141
+ isNew: true,
1142
+ tags: ['extcreate'],
1143
+ featured: true
1144
+ },
1145
+ /*{
1146
+ // not really an extension, but it's easiest to present it as one
1147
+ name: 'TurboBuilder',
1148
+ href: 'https://turbobuilder.vercel.app/',
1149
+ extensionId: 'special_turboBuilder',
1150
+ iconURL: turboBuilderIcon,
1151
+ description: 'Create your own amazing extensions using a scratch-based UI!',
1152
+ credits: 'Started by JeremyGamer13, continued by jwklong',
1153
+ tags: ['extcreate'],
1154
+ featured: true,
1155
+ disabled: !(IsLocal || IsLiveTests)
1156
+ },
1157
+ {
1158
+ // not really an extension, but it's easiest to present it as one
1159
+ name: 'TurboBuilder - Dev Branch',
1160
+ href: 'https://turbobuilder-dev.vercel.app/',
1161
+ extensionId: 'special_turboBuilderDev',
1162
+ iconURL: turboBuilderDevIcon,
1163
+ description: 'Publicly available developer branch, with the latest features.',
1164
+ credits: 'Started by JeremyGamer13, continued by jwklong',
1165
+ tags: ['extcreate'],
1166
+ featured: true
1167
+ },*/
1168
+ {
1169
+ // not really an extension, but it's easiest to present it as one
1170
+ name: (
1171
+ <FormattedMessage
1172
+ defaultMessage="Custom Extension"
1173
+ description="Name of library item to load a custom extension from a remote source"
1174
+ id="tw.customExtension.name"
1175
+ />
1176
+ ),
1177
+ extensionId: '',
1178
+ iconURL: customExtensionIcon,
1179
+ description: (
1180
+ <FormattedMessage
1181
+ defaultMessage="Load custom extensions from URLs, files, or JavaScript source code."
1182
+ description="Description of library item to load a custom extension from a custom source"
1183
+ id="tw.customExtension.description"
1184
+ />
1185
+ ),
1186
+ featured: true
1187
+ }
1188
+ ];
1189
+
1190
+ /*
1191
+ ----------------------------------------------
1192
+ ### NOTE TO PENGUINMOD FORKS: ###
1193
+ Please DO NOT make the extensions below accessible in the editor without livetests!
1194
+ They are NOT fully developed for people to use and create full projects with!
1195
+
1196
+ These extensions could have missing features, cause random errors, broken projects, or even crash the editor!
1197
+ Moving these into the main extension list will cause people who use your fork to assume they are ready for them to use!
1198
+
1199
+ Please keep these in livetests to reduce bug reports on your fork! :)
1200
+ ----------------------------------------------
1201
+ */
1202
+ if (IsLocal || IsLiveTests) {
1203
+ const extras = [
1204
+ {
1205
+ name: (
1206
+ <FormattedMessage
1207
+ defaultMessage="HTML Canvas"
1208
+ description="Name of Text extension"
1209
+ id="canvas.name"
1210
+ />
1211
+ ),
1212
+ extensionId: 'newCanvas',
1213
+ iconURL: canvasExtensionBanner,
1214
+ tags: ['penguinmod'],
1215
+ insetIconURL: canvasExtensionIcon,
1216
+ customInsetColor: '#0094FF',
1217
+ description: (
1218
+ <FormattedMessage
1219
+ defaultMessage="Extra drawing tools using an HTML Canvas. Works well when used with other extensions."
1220
+ description="Description of Text extension"
1221
+ id="text.description"
1222
+ />
1223
+ ),
1224
+ featured: true
1225
+ },
1226
+ {
1227
+ name: 'OLD Canvas',
1228
+ extensionId: 'canvas',
1229
+ iconURL: canvasExtensionBanner,
1230
+ tags: ['penguinmod'],
1231
+ insetIconURL: canvasExtensionIcon,
1232
+ customInsetColor: '#0094FF',
1233
+ description: 'depracated version of HTML Canvas.',
1234
+ featured: true
1235
+ },
1236
+ {
1237
+ name: 'Legacy Files',
1238
+ extensionId: 'jgFiles',
1239
+ iconURL: defaultExtensionIcon,
1240
+ tags: ['penguinmod', 'datamgmt'],
1241
+ description: 'Basic blocks for files. This has been replaced by the TurboWarp files extension.',
1242
+ featured: true
1243
+ },
1244
+ {
1245
+ name: 'Clone Communication',
1246
+ extensionId: 'jgClones',
1247
+ iconURL: jgCloneManagerExtensionIcon,
1248
+ tags: ['penguinmod'],
1249
+ description: 'Mainly sharing data between clones and the main sprite, but also some other small features. This has been replaced by the TurboWarp Clones+ extension.',
1250
+ featured: true
1251
+ },
1252
+ {
1253
+ name: 'Easy Save',
1254
+ extensionId: 'jgEasySave',
1255
+ iconURL: defaultExtensionIcon,
1256
+ tags: ['penguinmod', 'datamgmt'],
1257
+ description: 'Save variables, lists and extra info to a file, then load those things back in.',
1258
+ featured: true
1259
+ },
1260
+ {
1261
+ name: (
1262
+ <FormattedMessage
1263
+ defaultMessage="TurboWarp Blocks"
1264
+ description="Name of TW extension"
1265
+ id="tw.twExtension.name"
1266
+ values={{
1267
+ APP_NAME: "TurboWarp"
1268
+ }}
1269
+ />
1270
+ ),
1271
+ extensionId: 'tw',
1272
+ twDeveloper: 'GarboMuffin',
1273
+ tags: ['turbowarp'],
1274
+ insetIconURL: turbowarpIcon,
1275
+ iconURL: twIcon,
1276
+ description: 'Weird new blocks. Replaced by Sensing Expansion.',
1277
+ featured: true
1278
+ },
1279
+ {
1280
+ name: 'the doo doo extension',
1281
+ extensionId: 'jgDooDoo',
1282
+ iconURL: defaultExtensionIcon,
1283
+ tags: ['penguinmod', 'joke'],
1284
+ description: 'dr bob eae',
1285
+ featured: true
1286
+ },
1287
+ {
1288
+ name: 'Christmas',
1289
+ extensionId: 'jgChristmas',
1290
+ iconURL: 'https://extensions.penguinmod.com/images/JeremyGamer13/christmas.png',
1291
+ tags: ['penguinmod', 'joke'],
1292
+ description: 'hooraye',
1293
+ featured: true
1294
+ },
1295
+ {
1296
+ name: 'an amazing extension',
1297
+ extensionId: 'jgBestExtension',
1298
+ iconURL: 'https://extensions.penguinmod.com/images/JeremyGamer13/epic.png',
1299
+ internetConnectionRequired: true,
1300
+ tags: ['penguinmod', 'joke'],
1301
+ description: 'this is SUCH A GOOD EXTENSION USE IT NOW',
1302
+ featured: true
1303
+ },
1304
+ {
1305
+ name: 'Epic utilities',
1306
+ extensionId: 'https://extensions.penguinmod.com/extensions/SharkPool/AprilFools.js',
1307
+ iconURL: 'https://extensions.penguinmod.com/images/JeremyGamer13/epicutils.png',
1308
+ tags: ['penguinmod', 'joke'],
1309
+ description: 'the super good utilities brought to you by todays sponsor sharkpool (the epic utilities)',
1310
+ featured: true
1311
+ },
1312
+ {
1313
+ name: 'CATS',
1314
+ extensionId: 'https://extensions.penguinmod.com/extensions/Gen1x/CATS.js',
1315
+ iconURL: 'https://extensions.penguinmod.com/images/Gen1x/cats.png',
1316
+ tags: ['penguinmod', 'joke'],
1317
+ description: 'Blocks related to cats.',
1318
+ extDeveloper: 'G1nX',
1319
+ featured: true
1320
+ },
1321
+ {
1322
+ name: 'McUtils',
1323
+ extensionId: 'https://extensions.turbowarp.org/Lily/McUtils.js',
1324
+ tags: ['turbowarp', 'joke'],
1325
+ iconURL: 'https://extensions.turbowarp.org/images/Lily/McUtils.png',
1326
+ insetIconURL: turbowarpIcon,
1327
+ description: 'Basic utilities for any fast food employee',
1328
+ featured: true,
1329
+ twDeveloper: 'LilyMakesThings'
1330
+ },
1331
+ {
1332
+ name: 'image blocks',
1333
+ extensionId: 'https://extensions.penguinmod.com/extensions/Ashime/funneimageblocks.js',
1334
+ iconURL: 'https://extensions.penguinmod.com/images/JeremyGamer13/screenshot1.png',
1335
+ tags: ['penguinmod', 'joke'],
1336
+ internetConnectionRequired: true,
1337
+ description: 'who needs cat blocks when you have penguin block',
1338
+ extDeveloper: 'Ashimee, 0znzw, CST1229',
1339
+ featured: true
1340
+ },
1341
+ {
1342
+ name: 'fire in the hole',
1343
+ extensionId: 'https://extensions.penguinmod.com/extensions/JeremyGamer13/FireInTheHole.js',
1344
+ iconURL: 'https://library.penguinmod.com/files/emojis/cluelesssmile.png',
1345
+ tags: ['penguinmod', 'joke'],
1346
+ internetConnectionRequired: true,
1347
+ description: 'april fools took too long man this joke is not funny anymore',
1348
+ featured: true
1349
+ },
1350
+ {
1351
+ name: 'Unite',
1352
+ extensionId: 'jwUnite',
1353
+ iconURL: jwUniteExtensionIcon,
1354
+ tags: ['penguinmod'],
1355
+ description: 'Legacy extension that was eventually merged into the default toolbox.',
1356
+ featured: true
1357
+ },
1358
+ {
1359
+ name: 'XML',
1360
+ extensionId: 'jwXml',
1361
+ iconURL: jwXmlExtensionIcon,
1362
+ tags: ['penguinmod', 'datamgmt'],
1363
+ description: 'Enables the creation and getting of XML data. Not yet able to modify data.',
1364
+ extDeveloper: 'jwklong',
1365
+ featured: true
1366
+ },
1367
+ {
1368
+ name: 'Debugging',
1369
+ extensionId: 'jgDebugging',
1370
+ iconURL: jgDebuggingIcon,
1371
+ tags: ['penguinmod'],
1372
+ description: 'Log information and run commands. Good for debugging packaged projects or just easily changing things.',
1373
+ featured: true
1374
+ },
1375
+ {
1376
+ name: 'Test Extension Loader',
1377
+ href: 'https://studio.penguinmod.com/loadExt.html',
1378
+ extensionId: 'special_testExtensionLibrary',
1379
+ iconURL: defaultExtensionIcon,
1380
+ description: 'Test loading extensions from a library. For developers.',
1381
+ featured: true
1382
+ },
1383
+ {
1384
+ name: 'Editor',
1385
+ href: 'https://studio.penguinmod.com/editor.html',
1386
+ extensionId: 'special_editorExtensionLibrary',
1387
+ iconURL: penguinmodLibraryExtensionIcon,
1388
+ description: 'Opens the editor with this tab as the parent, still with the library opened. For developers.',
1389
+ featured: true
1390
+ },
1391
+ {
1392
+ name: (
1393
+ <FormattedMessage
1394
+ defaultMessage="OOP"
1395
+ description="Name of OOP extension"
1396
+ id="jwStructs.jwStructsExtension.name"
1397
+ />
1398
+ ),
1399
+ extensionId: 'jwStructs',
1400
+ tags: ['penguinmod'],
1401
+ iconURL: jwStructsExtensionIcon,
1402
+ description: (
1403
+ <FormattedMessage
1404
+ defaultMessage="Removed from list. OOP blocks. OOp is a programming paradigm that uses objects and their interactions to design applications and computer programs."
1405
+ description="Description of OOP extension"
1406
+ id="jwStructs.jwStructsExtension.description"
1407
+ />
1408
+ ),
1409
+ featured: true
1410
+ },
1411
+ {
1412
+ name: 'PenguinMod Permissions',
1413
+ extensionId: 'JgPermissionBlocks',
1414
+ iconURL: jgPermissionExtensionIcon,
1415
+ tags: ['penguinmod'],
1416
+ description: 'Legacy extension, old blocks no longer serve a real purpose. Direct blocks to manage permissions that PenguinMod requires you have to do certain tasks.',
1417
+ featured: true
1418
+ },
1419
+ {
1420
+ name: 'Jeremys Dev Tools',
1421
+ extensionId: 'jgDev',
1422
+ iconURL: defaultExtensionIcon,
1423
+ tags: ['penguinmod'],
1424
+ description: 'Test extension to see if things are possible.\nDO NOT USE THIS IN PRODUCTION as blocks are subject to change and may corrupt your projects.',
1425
+ credits: 'Some features added from LilyMakesThings, CubesterYT, TheShovel',
1426
+ featured: true
1427
+ },
1428
+ {
1429
+ name: '3D',
1430
+ extensionId: 'jg3d',
1431
+ iconURL: defaultExtensionIcon,
1432
+ tags: ['penguinmod', '3d'],
1433
+ customInsetColor: '#B200FF',
1434
+ insetIconURL: jg3dInsetExtensionIcon,
1435
+ description: 'Do not use for real projects. Not recommended, unstable, and will be rewritten/remade entirely at a later date. In development.',
1436
+ featured: true,
1437
+ extensionWarningOnImport: true
1438
+ },
1439
+ {
1440
+ name: '3D Physics',
1441
+ extensionId: 'fr3d',
1442
+ iconURL: fr3dPhysicsExtensionIcon,
1443
+ tags: ['penguinmod', '3d'],
1444
+ customInsetColor: '#D066FE',
1445
+ insetIconURL: fr3dPhysicsInsetExtensionIcon,
1446
+ description: 'Physics for the 3D extension.',
1447
+ featured: true
1448
+ },
1449
+ {
1450
+ name: '3D Virtual Reality',
1451
+ extensionId: 'jg3dVr',
1452
+ iconURL: jg3dVrExtensionIcon,
1453
+ tags: ['penguinmod', 'hardware', '3d'],
1454
+ customInsetColor: '#B200FF',
1455
+ insetIconURL: jg3dVrInsetExtensionIcon,
1456
+ description: 'Do not use for real projects. Not recommended, unstable, and will be rewritten/remade entirely at a later date. In development. May break compatibility. Allow players to really jump into your world!',
1457
+ featured: true,
1458
+ extensionWarningOnImport: true
1459
+ },
1460
+ {
1461
+ name: 'Interfaces',
1462
+ extensionId: 'jgInterfaces',
1463
+ iconURL: jgsilvxrcatInterfacesExtensionIcon,
1464
+ credits: 'silvxrcat',
1465
+ tags: ['penguinmod'],
1466
+ description: 'In development.',
1467
+ featured: true
1468
+ },
1469
+ {
1470
+ name: 'Packager Applications',
1471
+ extensionId: 'jgPackagerApplications',
1472
+ iconURL: jgPackagerApplicationsExtensionIcon,
1473
+ insetIconURL: jgPackagerApplicationsInsetExtensionIcon,
1474
+ twDeveloper: 'CubesterYT',
1475
+ customInsetColor: '#66B8FF',
1476
+ tags: ['penguinmod', 'packager'],
1477
+ description: 'In development. Do extra things in packaged applications that you can\'t do in the website!',
1478
+ featured: true
1479
+ },
1480
+
1481
+ {
1482
+ name: 'Inline Blocks',
1483
+ extensionId: 'pmInlineBlocks',
1484
+ iconURL: pmInlineBlocksExtensionIcon,
1485
+ tags: ['penguinmod'],
1486
+ description: 'Create quick blocks for simple tasks. Insert them into any circle spot and have them return any value you want.',
1487
+ featured: true
1488
+ },
1489
+ {
1490
+ name: (
1491
+ <FormattedMessage
1492
+ defaultMessage="Pathfinding"
1493
+ description="Name of Pathfinding extension"
1494
+ id="jgPathfinding.Pathfinding.name"
1495
+ />
1496
+ ),
1497
+ extensionId: 'jgPathfinding',
1498
+ tags: ['penguinmod'],
1499
+ iconURL: jgPathfindingExtensionIcon,
1500
+ description: (
1501
+ <FormattedMessage
1502
+ defaultMessage="(Unstable and or laggy; Needs further work) Have sprites navigate around obstacles in your game instead of clipping into them."
1503
+ description="Description of Pathfinding extension"
1504
+ id="jgPathfinding.Pathfinding.description"
1505
+ />
1506
+ ),
1507
+ featured: true
1508
+ },
1509
+ {
1510
+ name: 'Animation',
1511
+ extensionId: 'jgAnimation',
1512
+ iconURL: jgAnimationExtensionIcon,
1513
+ tags: ['penguinmod'],
1514
+ description: 'In development. Currently buggy and missing features.',
1515
+ featured: true
1516
+ },
1517
+ {
1518
+ name: 'Virtual Reality',
1519
+ extensionId: 'jgVr',
1520
+ iconURL: jgVrExtensionIcon,
1521
+ tags: ['penguinmod', 'hardware'],
1522
+ description: 'In development.',
1523
+ extDeveloper: "JeremyGamer13",
1524
+ extraLabels: [
1525
  {
1526
+ name: "Uses code from",
1527
+ value: "\"Augmented Reality\" by Vadik1"
1528
  }
1529
  ],
1530
+ featured: true,
1531
+ extensionWarningOnImport: true
 
 
 
 
 
 
 
 
 
1532
  }
1533
+ ];
1534
+ extras.forEach(ext => {
1535
+ menuItems.push(ext);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1536
  });
1537
+ }
1538
 
1539
+ export default menuItems;