File size: 13,409 Bytes
7aec436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# Scaffolding API

## Scaffolding's API is in an ALPHA state. It WILL change in ways that are backwards incompatible. Please pin to exact versions to avoid pain later!

## This documentation is very work in progress. Report any errors you find or any issues you encounter.

Scaffolding is the project player used by the packager.

Here's what Scaffolding does for you:

 - Loads the entire Scratch VM and connects everything together
 - Forwards user input to Scratch and implements things like sprite dragging
 - Removes unnecessary parts of Scratch that you don't need just for running projects
 - Implements the "ask and wait" block
 - Implements highly optimized (much faster than scratch-gui) variable and list monitors with context menus and file dropping
 - Implements cloud variables using a Scratch-compatible WebSocket server or local storage
 - Implements video sensing

Here's what Scaffolding doesn't do for you:

 - Green flag screen
 - Controls
 - A progress bar

## Versions

There are two versions of Scaffolding:

 - scaffolding-full (4.6MB) - contains every part of Scratch
 - scaffolding-min (2.5MB) - contains all of Scratch EXCEPT sound files used by the music extension. Significantly smaller than scaffolding-full.

Scratch is a large application so either script is very large. If you don't need the music extension to function, use scaffolding-min.

## Supported environments

Scaffolding strives to support any web browser released in 2018 or later.

Scaffolding only runs in web browsers. It will not run in Node.js.

## Content-Security-Policy

Meaningfully sandboxing Scaffolding with a Content-Security-Policy is hard. It needs to be able to fetch things from `data:` and `blob:` URLs, and the compiler (enabled by default) requires `unsafe-eval`.

This section will be updated later with more guidance.

## Installing

Scaffolding is distributed as one big JavaScript file. Any supplemental CSS etc. is stored inside the JS file.

We make no promise of having a stable API between even minor releases as Scaffolding is effectively just an implementation detail of the packager, which is why it's very important to lock your application to specific versions.

You can only load one version of Scaffolding on a page, but you can create as many Scaffolding project players as you'd like.

### From a CDN

```html

<!-- for scaffolding-min: -->

<script src="https://cdn.jsdelivr.net/npm/@turbowarp/packager@0.0.0/dist/scaffolding/scaffolding-min.js"></script>



<!-- for scaffolding-full -->

<script src="https://cdn.jsdelivr.net/npm/@turbowarp/packager@0.0.0/dist/scaffolding/scaffolding-full.js"></script>

```

Replace `0.0.0` with the latest release from https://github.com/TurboWarp/packager/releases, for example `1.0.0`.

DO NOT use versions like `@1` or `@latest` -- your website will break if (when) Scaffolding's API changes!

If you don't want to use a CDN, you can download the JS file linked by the script tag to a server you control and simply load that script instead.

### From npm

```bash

npm install --save-exact @turbowarp/packager

```

```js

// for scaffolding-min:

require('@turbowarp/packager/dist/scaffolding/scaffolding-min.js');

// for scaffolding-full:

require('@turbowarp/packager/dist/scaffolding/scaffolding-full.js');



// or, if you prefer ES6 imports,

// for scaffolding-min:

import '@turbowarp/packager/dist/scaffolding/scaffolding-min.js';

// for scaffolding-full:

import '@turbowarp/packager/dist/scaffolding/scaffolding-full.js';

```

Note that regardless of how you import Scaffolding, it is exported on `window.Scaffolding`, not on the module. This is strange and weird; it may change in the future.

## Usage

For an example, see [../static/example.html](../static/example.html). You can also examine the output of files generated by the packager.

At this point you should have Scaffolding installed on `window.Scaffolding`.

### Setup

Create an instance of Scaffolding:

```js

const scaffolding = new Scaffolding.Scaffolding();

```

You should be able to have multiple of these on one page if you want.

### Configuration

Certain Scaffolding options must be configured before you can finish setting up the Scratch environment. These are optional. The options that must be configured at this point are listed below along with their defaults.

```js

scaffolding.width = 480; // Custom stage width

scaffolding.height = 360; // Custom stage height

scaffolding.resizeMode = 'preserve-ratio'; // or 'dynamic-resize' or 'stretch'

scaffolding.editableLists = false; // Affects list monitors

```

### Finalize setup

This will actually create the Scratch VM, Renderer, Audio Engine, etc. and link them all together.

```js

scaffolding.setup();

```

### Put it in the DOM somewhere

You are responsible for making a location in the DOM for Scaffolding and using CSS to appropriately size it.

If your HTML looks like this:

```html

<style>

  #project {

    width: 480px;

    height: 360px;

  }

</style>

<div id="project"></div>

```

You would append Scaffolding to the DOM like this:

```js

scaffolding.appendTo(document.getElementById('project'));

```

Scaffolding will automatically resize the project player to fit inside the space you gave it. It listens for the window 'resize' event to do this. If you are resizing the element in a way that doesn't involve a window resize, you can manually call `scaffolding.relayout()` to force a resize. This can be slow, so don't do it when you don't need to.

### Tell it where to fetch projects and assets from

You have to manually configure scratch-storage to know where to fetch files from. If you want to load projects from scratch.mit.edu, you would do:

```js

const storage = scaffolding.storage;

storage.addWebStore(

  [storage.AssetType.ImageVector, storage.AssetType.ImageBitmap, storage.AssetType.Sound],

  (asset) => `https://assets.scratch.mit.edu/internalapi/asset/${asset.assetId}.${asset.dataFormat}/get/`

);

```

Downloading shared Scratch projects can be done manually with something like this:

```js

const id = '437419376';

const projectMetadata = await (await fetch(`https://trampoline.turbowarp.org/api/projects/${id}`)).json();

const token = projectMetadata.project_token;

const projectData = await (await fetch(`https://projects.scratch.mit.edu/${id}?token=${token}`)).arrayBuffer();

```

### Configure cloud variables

By default cloud variables are just normal variables. You must reconfigure this manually if you don't want that.

To synchronize cloud variables globally:

```js

const cloudVariableProvider = scaffolding.addCloudProvider(new Scaffolding.Cloud.WebSocketProvider('wss://clouddata.example.com', 'PROJECT ID HERE'));

```

To store cloud variables locally:

```js

const localStorageProvider = scaffolding.addCloudProvider(new Scaffolding.Cloud.LocalStorageProvider('UNIQUE STORAGE KEY (such as project ID) HERE'));

```

To use a different provider for different variables, there is an override system.

```js

scaffolding.addCloudProviderOverride("☁ my variable", cloudVariableProvider);

scaffolding.addCloudProviderOverride("☁ other variable", localStorageProvider);

```

### Set username

To change the value of the username block from the default empty string:

```js

scaffolding.setUsername("ExampleUser");

```

### Set accent color

To change the accent color used in prompts, context menus, etc.:

```js

scaffolding.setAccentColor("#abcdef");

```

The color MUST be a hex color code with 6 characters. 3 character codes will not work. The leading # is required. Color names will also not work.

### Load a project

At this point you can load a project. Scaffolding accepts an ArrayBuffer, Uint8Array, or string containing a full compressed project or a project.json.

Full compressed projects are full sb/sb2/sb3 files including assets.

project.json is just the JSON part of an sb2/sb3 file. In this case assets will be fetched separately.

```js

scaffolding.loadProject(projectData)

  .then(() => {

    // ...

  })

  .catch((error) => {

    // ...

  });

```

This returns a Promise that resolves when the project has finished loading or rejects if the project could not be loaded.

The project is not automatically started when loadProject completes.

If you configured scratch-storage to load projects from scratch.mit.edu, you can use:

```js

scaffolding.storage.load(Scaffolding.Storage.AssetType.Project, "PROJECT ID HERE eg. 104")

  .then((projectDataAsset) => scaffolding.load(projectDataAsset.data))

  .then(() => {

    // ...

  })

  .catch((error) => {

    // ...

  });

```

### Start the project

This will start the project *and* start scripts that are supposed to run when you press the green flag.

If you want to automatically start the project, you can do:

```js

scaffolding.loadProject(/* ... */) // see previous step

  .then(() => {

    scaffolding.start();

  });

```

If you want to display something like Scratch's green flag screen, you can create the screen yourself and call scaffolding.start() when the user clicks on it.

### Advanced topics

Scaffolding gives you direct access to various internal classes.

|Package|Instance|Constructor|
|:-:|:-:|:-:|
|scratch-vm|`scaffolding.vm`|`Scaffolding.VM`|
|scratch-render|`scaffolding.renderer`|`Scaffolding.Renderer`|
|scratch-storage|`scaffolding.storage`|`Scaffolding.Storage`|
|scratch-audio|`scaffolding.audioEngine`|`Scaffolding.AudioEngine`|
|JSZip|N/A|`Scaffolding.JSZip`|

Constructors are immediately available when scaffolding-[full|min].js is loaded. Instances are available after scaffolding.setup() is called.

The scratch-audio instance might be null if the browser doesn't support the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API). This is pretty rare to not be supported, but a few people do turn it off for one reason or another.

The scratch-storage constructor is actually a wrapper used for implementing progress monitoring.

### VM Settings

```js

// Press the green flag (like Scratch's green flag button)

scaffolding.greenFlag();



// Stop all (like Scratch's stop sign button)

scaffolding.stopAll();



// Turbo Mode

scaffolding.vm.setTurboMode(true);



// Framerate

scaffolding.vm.setFramerate(60);



// Interpolation

scaffolding.vm.setInterpolation(true);



// High quality pen

scaffolding.renderer.setUseHighQualityRender(true);



// Turn off the compiler

scaffolding.vm.setRuntimeOptions({enabled: false});



// Infinite clones, Remove miscellaneous limits, Remove fencing

scaffolding.vm.setRuntimeOptions({fencing: false, miscLimits: false, maxClones: Infinity});



// Load custom extension

// Do this before calling loadProject() for best results.

scaffolding.vm.extensionManager.loadExtensionURL('https://extensions.turbowarp.org/fetch.js');



// Do something when the project stops

vm.runtime.on('PROJECT_RUN_STOP', () => {

  // ...

});

```

### Get or set variables and lists

```js

scaffolding.getVariable("global variable name"); // -> "Hello, world!"

scaffolding.getList("global list name"); // -> [1, 2, 3]



scaffolding.setVariable("global variable name", "New value");

scaffolding.setList("global list name", [4, 5, 6]);

```

Variables must be a number, string, or boolean, and lists can only contain numbers, strings, and booleans. The VM was not designed to handle these invalid values and will not behave properly. Invalid values will throw an error.

Lists returned by getList are returned by reference, so any changes you make to them will be reflected in the project. However, changes might not display on the any visible monitors unless you use setList.

### Progress monitoring

Scaffolding can't help you monitor the progress of the data you feed into loadProject() -- you have to do that on your own. That might mean using an XMLHttpRequest to fetch the data so you can listen to the progress event.

Scaffolding can help you monitor asset download progress.

```js

scaffolding.storage.onprogress = (totalAssets, loadedAssets) => {

  // ...

};

```

Again, you are responsible for displaying a progress bar on your own.

### Fullscreen

Scaffolding doesn't have an API for fullscreen. Instead, just use the DOM fullscreen API on an element that contains scaffolding.

```js

document.getElementById('project').requestFullScreen();

```

### Advanced styling

You are free to override the styles for any class starting with `sc-`.

### Addons

In the same place as scaffolding-[full|min].js, there is a file called addons.js that contains some extra features. You can load it the same way you load the normal scaffolding script. It exports on window.ScaffoldingAddons instead.

```js

ScaffoldingAddons.run(scaffolding, {

  // Enable what you want.

  gamepad: false,

  pointerlock: false,

  specialCloudBehaviors: false,

  unsafeCloudBehaviors: false,

  pause: false, // Adds API: scaffolding.vm.setPaused(true)

});

```

### Exporting sb3

Here's something to get you started:

```js

Object.assign(document.createElement("a"), {

  href: URL.createObjectURL(await scaffolding.vm.saveProjectSb3()),

  download: 'project.sb3'

}).click();

```