scratch4js 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -0
- package/dist/LICENSE +373 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/assets.d.ts +61 -0
- package/dist/esm/format.d.ts +7 -0
- package/dist/esm/ids.d.ts +6 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/md5.d.ts +7 -0
- package/dist/esm/project.d.ts +123 -0
- package/dist/esm/target.d.ts +217 -0
- package/dist/umd/index.js +3 -0
- package/dist/umd/index.js.LICENSE.txt +11 -0
- package/dist/umd/index.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# scratch4js
|
|
2
|
+
|
|
3
|
+
Read and edit Scratch **`.sb3`** projects with a small, declarative API.
|
|
4
|
+
|
|
5
|
+
An `.sb3` file is just a zip containing a `project.json` (the stage, the
|
|
6
|
+
sprites, their scripts) plus the costume and sound files it references.
|
|
7
|
+
scratch4js wraps that with plain objects you can read and mutate, then zip back
|
|
8
|
+
up. It uses [`@turbowarp/jszip`](https://github.com/TurboWarp/jszip) for fast
|
|
9
|
+
(de)compression and pure JSON for everything else — no Scratch VM, no DOM.
|
|
10
|
+
|
|
11
|
+
Works in Node and the browser. Written in plain JS with JSDoc types.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add scratch4js
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { Project } from 'scratch4js';
|
|
23
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
24
|
+
|
|
25
|
+
// Load an .sb3 from its bytes.
|
|
26
|
+
const project = await Project.load(await readFile('game.sb3'));
|
|
27
|
+
|
|
28
|
+
// Edit sprites declaratively.
|
|
29
|
+
const cat = project.sprite('Sprite1');
|
|
30
|
+
cat.x = 0;
|
|
31
|
+
cat.y = -20;
|
|
32
|
+
cat.size = 150;
|
|
33
|
+
cat.visible = true;
|
|
34
|
+
|
|
35
|
+
// Variables, lists and broadcasts.
|
|
36
|
+
project.stage.setVariable('score', 0);
|
|
37
|
+
project.stage.setList('inventory', ['sword', 'shield']);
|
|
38
|
+
project.stage.addBroadcast('game over');
|
|
39
|
+
|
|
40
|
+
// Save back to .sb3 bytes.
|
|
41
|
+
await writeFile('game.edited.sb3', await project.save());
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
In the browser, `Project.load` accepts an `ArrayBuffer`/`Uint8Array` (e.g. from a
|
|
45
|
+
file input) and `save()` returns a `Uint8Array` you can wrap in a `Blob`.
|
|
46
|
+
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
### `Project`
|
|
50
|
+
|
|
51
|
+
| Member | Description |
|
|
52
|
+
| ----------------------------------------------- | ------------------------------------------------------ |
|
|
53
|
+
| `await Project.load(bytes)` | Parse an `.sb3` (`Uint8Array`/`ArrayBuffer`/`Buffer`). |
|
|
54
|
+
| `Project.create()` | A new, empty project with a bare stage. |
|
|
55
|
+
| `project.stage` | The `Stage` target. |
|
|
56
|
+
| `project.sprites` | Array of `Sprite` targets. |
|
|
57
|
+
| `project.targets` | Every target, stage included. |
|
|
58
|
+
| `project.sprite(name)` / `project.target(name)` | Look up by name. |
|
|
59
|
+
| `project.addSprite(name, props?)` | Add a sprite (give it a costume before use). |
|
|
60
|
+
| `project.removeSprite(name)` | Remove a sprite; drops assets it solely owned. |
|
|
61
|
+
| `project.meta` / `monitors` / `extensions` | Raw project-level fields. |
|
|
62
|
+
| `await project.save({ compressionLevel })` | Serialize to `.sb3` bytes. |
|
|
63
|
+
|
|
64
|
+
### `Sprite` / `Stage` (extend `Target`)
|
|
65
|
+
|
|
66
|
+
Shared `Target` accessors: `name`, `volume`, `costumes`, `currentCostume`,
|
|
67
|
+
`sounds`, and the raw `blocks` object.
|
|
68
|
+
|
|
69
|
+
- **Costumes & sounds:** `getCostume(name)`, `addCostume(name, bytes, opts?)`,
|
|
70
|
+
`removeCostume(nameOrIndex)`, and the matching `getSound` / `addSound` /
|
|
71
|
+
`removeSound`. Asset bytes are stored under their MD5 automatically, and the
|
|
72
|
+
file type is sniffed from the bytes (override with `opts.dataFormat`).
|
|
73
|
+
- **Variables & lists:** `getVariable(name)`, `setVariable(name, value)`,
|
|
74
|
+
`deleteVariable(name)`, `variableNames`, plus `getList` / `setList` /
|
|
75
|
+
`deleteList` / `listNames`.
|
|
76
|
+
|
|
77
|
+
`Sprite` adds: `x`, `y`, `size`, `direction`, `visible`, `draggable`,
|
|
78
|
+
`rotationStyle`, `layerOrder`.
|
|
79
|
+
|
|
80
|
+
`Stage` adds: `tempo`, `videoState`, `videoTransparency`, `broadcastNames`, and
|
|
81
|
+
`addBroadcast(name)`.
|
|
82
|
+
|
|
83
|
+
### `Costume` / `Sound`
|
|
84
|
+
|
|
85
|
+
`name`, `dataFormat`, `md5ext`, and `data` (the raw bytes). Assigning to `data`
|
|
86
|
+
re-hashes and rewrites `assetId`/`md5ext`. Costumes also expose
|
|
87
|
+
`rotationCenterX/Y` and `bitmapResolution`; sounds expose `rate` and
|
|
88
|
+
`sampleCount`.
|
|
89
|
+
|
|
90
|
+
### Utilities
|
|
91
|
+
|
|
92
|
+
`md5(bytes)`, `uid()` (Scratch-style id), and `sniffFormat(bytes)` are exported
|
|
93
|
+
for convenience.
|
|
94
|
+
|
|
95
|
+
## Example: swap a costume's image
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import { Project } from 'scratch4js';
|
|
99
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
100
|
+
|
|
101
|
+
const project = await Project.load(await readFile('game.sb3'));
|
|
102
|
+
|
|
103
|
+
const cat = project.sprite('Sprite1');
|
|
104
|
+
cat.getCostume('costume1').data = await readFile('new-cat.png');
|
|
105
|
+
cat.addSound('boop', await readFile('boop.wav'));
|
|
106
|
+
|
|
107
|
+
await writeFile('game.edited.sb3', await project.save());
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Develop
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pnpm install
|
|
114
|
+
pnpm run build # bundle to dist/ (esm, cjs, umd)
|
|
115
|
+
pnpm run dev # watch mode
|
|
116
|
+
pnpm run lint
|
|
117
|
+
pnpm run format
|
|
118
|
+
```
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
Mozilla Public License Version 2.0
|
|
2
|
+
==================================
|
|
3
|
+
|
|
4
|
+
1. Definitions
|
|
5
|
+
--------------
|
|
6
|
+
|
|
7
|
+
1.1. "Contributor"
|
|
8
|
+
means each individual or legal entity that creates, contributes to
|
|
9
|
+
the creation of, or owns Covered Software.
|
|
10
|
+
|
|
11
|
+
1.2. "Contributor Version"
|
|
12
|
+
means the combination of the Contributions of others (if any) used
|
|
13
|
+
by a Contributor and that particular Contributor's Contribution.
|
|
14
|
+
|
|
15
|
+
1.3. "Contribution"
|
|
16
|
+
means Covered Software of a particular Contributor.
|
|
17
|
+
|
|
18
|
+
1.4. "Covered Software"
|
|
19
|
+
means Source Code Form to which the initial Contributor has attached
|
|
20
|
+
the notice in Exhibit A, the Executable Form of such Source Code
|
|
21
|
+
Form, and Modifications of such Source Code Form, in each case
|
|
22
|
+
including portions thereof.
|
|
23
|
+
|
|
24
|
+
1.5. "Incompatible With Secondary Licenses"
|
|
25
|
+
means
|
|
26
|
+
|
|
27
|
+
(a) that the initial Contributor has attached the notice described
|
|
28
|
+
in Exhibit B to the Covered Software; or
|
|
29
|
+
|
|
30
|
+
(b) that the Covered Software was made available under the terms of
|
|
31
|
+
version 1.1 or earlier of the License, but not also under the
|
|
32
|
+
terms of a Secondary License.
|
|
33
|
+
|
|
34
|
+
1.6. "Executable Form"
|
|
35
|
+
means any form of the work other than Source Code Form.
|
|
36
|
+
|
|
37
|
+
1.7. "Larger Work"
|
|
38
|
+
means a work that combines Covered Software with other material, in
|
|
39
|
+
a separate file or files, that is not Covered Software.
|
|
40
|
+
|
|
41
|
+
1.8. "License"
|
|
42
|
+
means this document.
|
|
43
|
+
|
|
44
|
+
1.9. "Licensable"
|
|
45
|
+
means having the right to grant, to the maximum extent possible,
|
|
46
|
+
whether at the time of the initial grant or subsequently, any and
|
|
47
|
+
all of the rights conveyed by this License.
|
|
48
|
+
|
|
49
|
+
1.10. "Modifications"
|
|
50
|
+
means any of the following:
|
|
51
|
+
|
|
52
|
+
(a) any file in Source Code Form that results from an addition to,
|
|
53
|
+
deletion from, or modification of the contents of Covered
|
|
54
|
+
Software; or
|
|
55
|
+
|
|
56
|
+
(b) any new file in Source Code Form that contains any Covered
|
|
57
|
+
Software.
|
|
58
|
+
|
|
59
|
+
1.11. "Patent Claims" of a Contributor
|
|
60
|
+
means any patent claim(s), including without limitation, method,
|
|
61
|
+
process, and apparatus claims, in any patent Licensable by such
|
|
62
|
+
Contributor that would be infringed, but for the grant of the
|
|
63
|
+
License, by the making, using, selling, offering for sale, having
|
|
64
|
+
made, import, or transfer of either its Contributions or its
|
|
65
|
+
Contributor Version.
|
|
66
|
+
|
|
67
|
+
1.12. "Secondary License"
|
|
68
|
+
means either the GNU General Public License, Version 2.0, the GNU
|
|
69
|
+
Lesser General Public License, Version 2.1, the GNU Affero General
|
|
70
|
+
Public License, Version 3.0, or any later versions of those
|
|
71
|
+
licenses.
|
|
72
|
+
|
|
73
|
+
1.13. "Source Code Form"
|
|
74
|
+
means the form of the work preferred for making modifications.
|
|
75
|
+
|
|
76
|
+
1.14. "You" (or "Your")
|
|
77
|
+
means an individual or a legal entity exercising rights under this
|
|
78
|
+
License. For legal entities, "You" includes any entity that
|
|
79
|
+
controls, is controlled by, or is under common control with You. For
|
|
80
|
+
purposes of this definition, "control" means (a) the power, direct
|
|
81
|
+
or indirect, to cause the direction or management of such entity,
|
|
82
|
+
whether by contract or otherwise, or (b) ownership of more than
|
|
83
|
+
fifty percent (50%) of the outstanding shares or beneficial
|
|
84
|
+
ownership of such entity.
|
|
85
|
+
|
|
86
|
+
2. License Grants and Conditions
|
|
87
|
+
--------------------------------
|
|
88
|
+
|
|
89
|
+
2.1. Grants
|
|
90
|
+
|
|
91
|
+
Each Contributor hereby grants You a world-wide, royalty-free,
|
|
92
|
+
non-exclusive license:
|
|
93
|
+
|
|
94
|
+
(a) under intellectual property rights (other than patent or trademark)
|
|
95
|
+
Licensable by such Contributor to use, reproduce, make available,
|
|
96
|
+
modify, display, perform, distribute, and otherwise exploit its
|
|
97
|
+
Contributions, either on an unmodified basis, with Modifications, or
|
|
98
|
+
as part of a Larger Work; and
|
|
99
|
+
|
|
100
|
+
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
|
101
|
+
for sale, have made, import, and otherwise transfer either its
|
|
102
|
+
Contributions or its Contributor Version.
|
|
103
|
+
|
|
104
|
+
2.2. Effective Date
|
|
105
|
+
|
|
106
|
+
The licenses granted in Section 2.1 with respect to any Contribution
|
|
107
|
+
become effective for each Contribution on the date the Contributor first
|
|
108
|
+
distributes such Contribution.
|
|
109
|
+
|
|
110
|
+
2.3. Limitations on Grant Scope
|
|
111
|
+
|
|
112
|
+
The licenses granted in this Section 2 are the only rights granted under
|
|
113
|
+
this License. No additional rights or licenses will be implied from the
|
|
114
|
+
distribution or licensing of Covered Software under this License.
|
|
115
|
+
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
|
116
|
+
Contributor:
|
|
117
|
+
|
|
118
|
+
(a) for any code that a Contributor has removed from Covered Software;
|
|
119
|
+
or
|
|
120
|
+
|
|
121
|
+
(b) for infringements caused by: (i) Your and any other third party's
|
|
122
|
+
modifications of Covered Software, or (ii) the combination of its
|
|
123
|
+
Contributions with other software (except as part of its Contributor
|
|
124
|
+
Version); or
|
|
125
|
+
|
|
126
|
+
(c) under Patent Claims infringed by Covered Software in the absence of
|
|
127
|
+
its Contributions.
|
|
128
|
+
|
|
129
|
+
This License does not grant any rights in the trademarks, service marks,
|
|
130
|
+
or logos of any Contributor (except as may be necessary to comply with
|
|
131
|
+
the notice requirements in Section 3.4).
|
|
132
|
+
|
|
133
|
+
2.4. Subsequent Licenses
|
|
134
|
+
|
|
135
|
+
No Contributor makes additional grants as a result of Your choice to
|
|
136
|
+
distribute the Covered Software under a subsequent version of this
|
|
137
|
+
License (see Section 10.2) or under the terms of a Secondary License (if
|
|
138
|
+
permitted under the terms of Section 3.3).
|
|
139
|
+
|
|
140
|
+
2.5. Representation
|
|
141
|
+
|
|
142
|
+
Each Contributor represents that the Contributor believes its
|
|
143
|
+
Contributions are its original creation(s) or it has sufficient rights
|
|
144
|
+
to grant the rights to its Contributions conveyed by this License.
|
|
145
|
+
|
|
146
|
+
2.6. Fair Use
|
|
147
|
+
|
|
148
|
+
This License is not intended to limit any rights You have under
|
|
149
|
+
applicable copyright doctrines of fair use, fair dealing, or other
|
|
150
|
+
equivalents.
|
|
151
|
+
|
|
152
|
+
2.7. Conditions
|
|
153
|
+
|
|
154
|
+
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
|
155
|
+
in Section 2.1.
|
|
156
|
+
|
|
157
|
+
3. Responsibilities
|
|
158
|
+
-------------------
|
|
159
|
+
|
|
160
|
+
3.1. Distribution of Source Form
|
|
161
|
+
|
|
162
|
+
All distribution of Covered Software in Source Code Form, including any
|
|
163
|
+
Modifications that You create or to which You contribute, must be under
|
|
164
|
+
the terms of this License. You must inform recipients that the Source
|
|
165
|
+
Code Form of the Covered Software is governed by the terms of this
|
|
166
|
+
License, and how they can obtain a copy of this License. You may not
|
|
167
|
+
attempt to alter or restrict the recipients' rights in the Source Code
|
|
168
|
+
Form.
|
|
169
|
+
|
|
170
|
+
3.2. Distribution of Executable Form
|
|
171
|
+
|
|
172
|
+
If You distribute Covered Software in Executable Form then:
|
|
173
|
+
|
|
174
|
+
(a) such Covered Software must also be made available in Source Code
|
|
175
|
+
Form, as described in Section 3.1, and You must inform recipients of
|
|
176
|
+
the Executable Form how they can obtain a copy of such Source Code
|
|
177
|
+
Form by reasonable means in a timely manner, at a charge no more
|
|
178
|
+
than the cost of distribution to the recipient; and
|
|
179
|
+
|
|
180
|
+
(b) You may distribute such Executable Form under the terms of this
|
|
181
|
+
License, or sublicense it under different terms, provided that the
|
|
182
|
+
license for the Executable Form does not attempt to limit or alter
|
|
183
|
+
the recipients' rights in the Source Code Form under this License.
|
|
184
|
+
|
|
185
|
+
3.3. Distribution of a Larger Work
|
|
186
|
+
|
|
187
|
+
You may create and distribute a Larger Work under terms of Your choice,
|
|
188
|
+
provided that You also comply with the requirements of this License for
|
|
189
|
+
the Covered Software. If the Larger Work is a combination of Covered
|
|
190
|
+
Software with a work governed by one or more Secondary Licenses, and the
|
|
191
|
+
Covered Software is not Incompatible With Secondary Licenses, this
|
|
192
|
+
License permits You to additionally distribute such Covered Software
|
|
193
|
+
under the terms of such Secondary License(s), so that the recipient of
|
|
194
|
+
the Larger Work may, at their option, further distribute the Covered
|
|
195
|
+
Software under the terms of either this License or such Secondary
|
|
196
|
+
License(s).
|
|
197
|
+
|
|
198
|
+
3.4. Notices
|
|
199
|
+
|
|
200
|
+
You may not remove or alter the substance of any license notices
|
|
201
|
+
(including copyright notices, patent notices, disclaimers of warranty,
|
|
202
|
+
or limitations of liability) contained within the Source Code Form of
|
|
203
|
+
the Covered Software, except that You may alter any license notices to
|
|
204
|
+
the extent required to remedy known factual inaccuracies.
|
|
205
|
+
|
|
206
|
+
3.5. Application of Additional Terms
|
|
207
|
+
|
|
208
|
+
You may choose to offer, and to charge a fee for, warranty, support,
|
|
209
|
+
indemnity or liability obligations to one or more recipients of Covered
|
|
210
|
+
Software. However, You may do so only on Your own behalf, and not on
|
|
211
|
+
behalf of any Contributor. You must make it absolutely clear that any
|
|
212
|
+
such warranty, support, indemnity, or liability obligation is offered by
|
|
213
|
+
You alone, and You hereby agree to indemnify every Contributor for any
|
|
214
|
+
liability incurred by such Contributor as a result of warranty, support,
|
|
215
|
+
indemnity or liability terms You offer. You may include additional
|
|
216
|
+
disclaimers of warranty and limitations of liability specific to any
|
|
217
|
+
jurisdiction.
|
|
218
|
+
|
|
219
|
+
4. Inability to Comply Due to Statute or Regulation
|
|
220
|
+
---------------------------------------------------
|
|
221
|
+
|
|
222
|
+
If it is impossible for You to comply with any of the terms of this
|
|
223
|
+
License with respect to some or all of the Covered Software due to
|
|
224
|
+
statute, judicial order, or regulation then You must: (a) comply with
|
|
225
|
+
the terms of this License to the maximum extent possible; and (b)
|
|
226
|
+
describe the limitations and the code they affect. Such description must
|
|
227
|
+
be placed in a text file included with all distributions of the Covered
|
|
228
|
+
Software under this License. Except to the extent prohibited by statute
|
|
229
|
+
or regulation, such description must be sufficiently detailed for a
|
|
230
|
+
recipient of ordinary skill to be able to understand it.
|
|
231
|
+
|
|
232
|
+
5. Termination
|
|
233
|
+
--------------
|
|
234
|
+
|
|
235
|
+
5.1. The rights granted under this License will terminate automatically
|
|
236
|
+
if You fail to comply with any of its terms. However, if You become
|
|
237
|
+
compliant, then the rights granted under this License from a particular
|
|
238
|
+
Contributor are reinstated (a) provisionally, unless and until such
|
|
239
|
+
Contributor explicitly and finally terminates Your grants, and (b) on an
|
|
240
|
+
ongoing basis, if such Contributor fails to notify You of the
|
|
241
|
+
non-compliance by some reasonable means prior to 60 days after You have
|
|
242
|
+
come back into compliance. Moreover, Your grants from a particular
|
|
243
|
+
Contributor are reinstated on an ongoing basis if such Contributor
|
|
244
|
+
notifies You of the non-compliance by some reasonable means, this is the
|
|
245
|
+
first time You have received notice of non-compliance with this License
|
|
246
|
+
from such Contributor, and You become compliant prior to 30 days after
|
|
247
|
+
Your receipt of the notice.
|
|
248
|
+
|
|
249
|
+
5.2. If You initiate litigation against any entity by asserting a patent
|
|
250
|
+
infringement claim (excluding declaratory judgment actions,
|
|
251
|
+
counter-claims, and cross-claims) alleging that a Contributor Version
|
|
252
|
+
directly or indirectly infringes any patent, then the rights granted to
|
|
253
|
+
You by any and all Contributors for the Covered Software under Section
|
|
254
|
+
2.1 of this License shall terminate.
|
|
255
|
+
|
|
256
|
+
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
|
257
|
+
end user license agreements (excluding distributors and resellers) which
|
|
258
|
+
have been validly granted by You or Your distributors under this License
|
|
259
|
+
prior to termination shall survive termination.
|
|
260
|
+
|
|
261
|
+
************************************************************************
|
|
262
|
+
* *
|
|
263
|
+
* 6. Disclaimer of Warranty *
|
|
264
|
+
* ------------------------- *
|
|
265
|
+
* *
|
|
266
|
+
* Covered Software is provided under this License on an "as is" *
|
|
267
|
+
* basis, without warranty of any kind, either expressed, implied, or *
|
|
268
|
+
* statutory, including, without limitation, warranties that the *
|
|
269
|
+
* Covered Software is free of defects, merchantable, fit for a *
|
|
270
|
+
* particular purpose or non-infringing. The entire risk as to the *
|
|
271
|
+
* quality and performance of the Covered Software is with You. *
|
|
272
|
+
* Should any Covered Software prove defective in any respect, You *
|
|
273
|
+
* (not any Contributor) assume the cost of any necessary servicing, *
|
|
274
|
+
* repair, or correction. This disclaimer of warranty constitutes an *
|
|
275
|
+
* essential part of this License. No use of any Covered Software is *
|
|
276
|
+
* authorized under this License except under this disclaimer. *
|
|
277
|
+
* *
|
|
278
|
+
************************************************************************
|
|
279
|
+
|
|
280
|
+
************************************************************************
|
|
281
|
+
* *
|
|
282
|
+
* 7. Limitation of Liability *
|
|
283
|
+
* -------------------------- *
|
|
284
|
+
* *
|
|
285
|
+
* Under no circumstances and under no legal theory, whether tort *
|
|
286
|
+
* (including negligence), contract, or otherwise, shall any *
|
|
287
|
+
* Contributor, or anyone who distributes Covered Software as *
|
|
288
|
+
* permitted above, be liable to You for any direct, indirect, *
|
|
289
|
+
* special, incidental, or consequential damages of any character *
|
|
290
|
+
* including, without limitation, damages for lost profits, loss of *
|
|
291
|
+
* goodwill, work stoppage, computer failure or malfunction, or any *
|
|
292
|
+
* and all other commercial damages or losses, even if such party *
|
|
293
|
+
* shall have been informed of the possibility of such damages. This *
|
|
294
|
+
* limitation of liability shall not apply to liability for death or *
|
|
295
|
+
* personal injury resulting from such party's negligence to the *
|
|
296
|
+
* extent applicable law prohibits such limitation. Some *
|
|
297
|
+
* jurisdictions do not allow the exclusion or limitation of *
|
|
298
|
+
* incidental or consequential damages, so this exclusion and *
|
|
299
|
+
* limitation may not apply to You. *
|
|
300
|
+
* *
|
|
301
|
+
************************************************************************
|
|
302
|
+
|
|
303
|
+
8. Litigation
|
|
304
|
+
-------------
|
|
305
|
+
|
|
306
|
+
Any litigation relating to this License may be brought only in the
|
|
307
|
+
courts of a jurisdiction where the defendant maintains its principal
|
|
308
|
+
place of business and such litigation shall be governed by laws of that
|
|
309
|
+
jurisdiction, without reference to its conflict-of-law provisions.
|
|
310
|
+
Nothing in this Section shall prevent a party's ability to bring
|
|
311
|
+
cross-claims or counter-claims.
|
|
312
|
+
|
|
313
|
+
9. Miscellaneous
|
|
314
|
+
----------------
|
|
315
|
+
|
|
316
|
+
This License represents the complete agreement concerning the subject
|
|
317
|
+
matter hereof. If any provision of this License is held to be
|
|
318
|
+
unenforceable, such provision shall be reformed only to the extent
|
|
319
|
+
necessary to make it enforceable. Any law or regulation which provides
|
|
320
|
+
that the language of a contract shall be construed against the drafter
|
|
321
|
+
shall not be used to construe this License against a Contributor.
|
|
322
|
+
|
|
323
|
+
10. Versions of the License
|
|
324
|
+
---------------------------
|
|
325
|
+
|
|
326
|
+
10.1. New Versions
|
|
327
|
+
|
|
328
|
+
Mozilla Foundation is the license steward. Except as provided in Section
|
|
329
|
+
10.3, no one other than the license steward has the right to modify or
|
|
330
|
+
publish new versions of this License. Each version will be given a
|
|
331
|
+
distinguishing version number.
|
|
332
|
+
|
|
333
|
+
10.2. Effect of New Versions
|
|
334
|
+
|
|
335
|
+
You may distribute the Covered Software under the terms of the version
|
|
336
|
+
of the License under which You originally received the Covered Software,
|
|
337
|
+
or under the terms of any subsequent version published by the license
|
|
338
|
+
steward.
|
|
339
|
+
|
|
340
|
+
10.3. Modified Versions
|
|
341
|
+
|
|
342
|
+
If you create software not governed by this License, and you want to
|
|
343
|
+
create a new license for such software, you may create and use a
|
|
344
|
+
modified version of this License if you rename the license and remove
|
|
345
|
+
any references to the name of the license steward (except to note that
|
|
346
|
+
such modified license differs from this License).
|
|
347
|
+
|
|
348
|
+
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
|
349
|
+
Licenses
|
|
350
|
+
|
|
351
|
+
If You choose to distribute Source Code Form that is Incompatible With
|
|
352
|
+
Secondary Licenses under the terms of this version of the License, the
|
|
353
|
+
notice described in Exhibit B of this License must be attached.
|
|
354
|
+
|
|
355
|
+
Exhibit A - Source Code Form License Notice
|
|
356
|
+
-------------------------------------------
|
|
357
|
+
|
|
358
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
359
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
360
|
+
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
361
|
+
|
|
362
|
+
If it is not possible or desirable to put the notice in a particular
|
|
363
|
+
file, then You may include the notice in a location (such as a LICENSE
|
|
364
|
+
file in a relevant directory) where a recipient would be likely to look
|
|
365
|
+
for such a notice.
|
|
366
|
+
|
|
367
|
+
You may add additional accurate notices of copyright ownership.
|
|
368
|
+
|
|
369
|
+
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
|
370
|
+
---------------------------------------------------------
|
|
371
|
+
|
|
372
|
+
This Source Code Form is "Incompatible With Secondary Licenses", as
|
|
373
|
+
defined by the Mozilla Public License, v. 2.0.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,t,s)=>{var r=(t,s)=>{for(var r in t)__webpack_require__.o(t,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,[s]:t[r]})};r(t,"get"),r(s,"value")},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{Costume:()=>Costume,Project:()=>Project,Sound:()=>Sound,Sprite:()=>Sprite,Stage:()=>Stage,Target:()=>Target,md5:()=>md5,sniffFormat:()=>sniffFormat,uid:()=>uid});const jszip_namespaceObject=require("@turbowarp/jszip"),K=new Int32Array([0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x2441453,0xd8a1e681,0xe7d3fbc8,0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x4881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391]),S=[7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21],rotl=(e,t)=>e<<t|e>>>32-t,HEX=[];for(let i=0;i<256;i++)HEX[i]=(i<16?"0":"")+i.toString(16);const hexLE=e=>HEX[255&e]+HEX[e>>>8&255]+HEX[e>>>16&255]+HEX[e>>>24&255];function md5(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),s=t.length,r=s+1,n=r+(r%64<=56?56-r%64:120-r%64)+8,o=new Uint8Array(n);o.set(t),o[s]=128;let a=s<<3>>>0,u=s>>>29>>>0;o[n-8]=255&a,o[n-7]=a>>>8&255,o[n-6]=a>>>16&255,o[n-5]=a>>>24&255,o[n-4]=255&u,o[n-3]=u>>>8&255,o[n-2]=u>>>16&255,o[n-1]=u>>>24&255;let c=0x67452301,d=0xefcdab89,m=0x98badcfe,l=0x10325476,p=new Int32Array(16);for(let e=0;e<n;e+=64){for(let t=0;t<16;t++){let s=e+4*t;p[t]=o[s]|o[s+1]<<8|o[s+2]<<16|o[s+3]<<24}let t=c,s=d,r=m,n=l;for(let e=0;e<64;e++){let o,a;e<16?(o=s&r|~s&n,a=e):e<32?(o=n&s|~n&r,a=(5*e+1)%16):e<48?(o=s^r^n,a=(3*e+5)%16):(o=r^(s|~n),a=7*e%16),o=o+t+K[e]+p[a]|0,t=n,n=r,r=s,s=s+rotl(o,S[e])|0}c=c+t|0,d=d+s|0,m=m+r|0,l=l+n|0}return hexLE(c)+hexLE(d)+hexLE(m)+hexLE(l)}class Asset{constructor(e,t){this.json=e,this.project=t}get name(){return this.json.name}set name(e){this.json.name=String(e)}get dataFormat(){return this.json.dataFormat}get md5ext(){return this.json.md5ext}get data(){return this.project.assets.get(this.json.md5ext)}set data(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),s=this.json.md5ext,r=md5(t);this.json.assetId=r,this.json.md5ext=`${r}.${this.json.dataFormat}`,this.project.assets.set(this.json.md5ext,t),s&&s!==this.json.md5ext&&this.project._maybeDropAsset(s)}}class Costume extends Asset{get bitmapResolution(){return this.json.bitmapResolution??1}set bitmapResolution(e){this.json.bitmapResolution=Number(e)}get rotationCenterX(){return this.json.rotationCenterX??0}set rotationCenterX(e){this.json.rotationCenterX=Number(e)}get rotationCenterY(){return this.json.rotationCenterY??0}set rotationCenterY(e){this.json.rotationCenterY=Number(e)}}class Sound extends Asset{get rate(){return this.json.rate}set rate(e){this.json.rate=Number(e)}get sampleCount(){return this.json.sampleCount}set sampleCount(e){this.json.sampleCount=Number(e)}}const startsWith=(e,t)=>t.every((t,s)=>e[s]===t),ascii=e=>[...e].map(e=>e.charCodeAt(0));function sniffFormat(e){if(!e||e.length<4)return;if(startsWith(e,[137,80,78,71]))return"png";if(startsWith(e,[255,216,255]))return"jpg";if(startsWith(e,ascii("GIF")))return"gif";if(startsWith(e,ascii("RIFF")))return"wav";if(startsWith(e,ascii("ID3"))||255===e[0]&&(224&e[1])==224)return"mp3";let t=String.fromCharCode(...e.slice(0,256)).trimStart();if(t.startsWith("<?xml")||t.startsWith("<svg")||t.includes("<svg"))return"svg"}const SOUP="!#%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function uid(){let e="";for(let t=0;t<20;t++)e+=SOUP[Math.floor(Math.random()*SOUP.length)];return e}class Target{constructor(e,t){this.json=e,this.project=t}get isStage(){return!!this.json.isStage}get name(){return this.json.name}set name(e){this.json.name=String(e)}get volume(){return this.json.volume??100}set volume(e){this.json.volume=Number(e)}get costumes(){return this.json.costumes.map(e=>new Costume(e,this.project))}get currentCostume(){return this.json.currentCostume??0}set currentCostume(e){this.json.currentCostume=Number(e)}getCostume(e){let t=this.json.costumes.find(t=>t.name===e);return t?new Costume(t,this.project):void 0}addCostume(e,t,s={}){let r=t instanceof Uint8Array?t:new Uint8Array(t),n=s.dataFormat??sniffFormat(r)??"png",o=md5(r),a={name:String(e),bitmapResolution:s.bitmapResolution??("svg"===n?1:2),dataFormat:n,assetId:o,md5ext:`${o}.${n}`,rotationCenterX:s.rotationCenterX??0,rotationCenterY:s.rotationCenterY??0};return this.project.assets.set(a.md5ext,r),this.json.costumes.push(a),new Costume(a,this.project)}removeCostume(e){return this._removeMedia("costumes",e)}get sounds(){return this.json.sounds.map(e=>new Sound(e,this.project))}getSound(e){let t=this.json.sounds.find(t=>t.name===e);return t?new Sound(t,this.project):void 0}addSound(e,t,s={}){let r=t instanceof Uint8Array?t:new Uint8Array(t),n=s.dataFormat??sniffFormat(r)??"wav",o=md5(r),a={name:String(e),assetId:o,dataFormat:n,format:"",rate:s.rate??48e3,sampleCount:s.sampleCount??0,md5ext:`${o}.${n}`};return this.project.assets.set(a.md5ext,r),this.json.sounds.push(a),new Sound(a,this.project)}removeSound(e){return this._removeMedia("sounds",e)}_removeMedia(e,t){let s=this.json[e],r="number"==typeof t?t:s.findIndex(e=>e.name===t);if(r<0||r>=s.length)return!1;let[n]=s.splice(r,1);return"costumes"===e&&this.json.currentCostume>=s.length&&(this.json.currentCostume=Math.max(0,s.length-1)),this.project._maybeDropAsset(n.md5ext),!0}get variableNames(){return Object.values(this.json.variables).map(([e])=>e)}getVariable(e){let t=Object.values(this.json.variables).find(([t])=>t===e);return t?t[1]:void 0}setVariable(e,t){for(let[s,r]of Object.entries(this.json.variables))if(r[0]===e)return r[1]=t,s;let s=uid();return this.json.variables[s]=[e,t],s}deleteVariable(e){for(let[t,s]of Object.entries(this.json.variables))if(s[0]===e)return delete this.json.variables[t],!0;return!1}get listNames(){return Object.values(this.json.lists).map(([e])=>e)}getList(e){let t=Object.values(this.json.lists).find(([t])=>t===e);return t?t[1]:void 0}setList(e,t=[]){for(let[s,r]of Object.entries(this.json.lists))if(r[0]===e)return r[1]=t,s;let s=uid();return this.json.lists[s]=[e,t],s}deleteList(e){for(let[t,s]of Object.entries(this.json.lists))if(s[0]===e)return delete this.json.lists[t],!0;return!1}get blocks(){return this.json.blocks}}class Stage extends Target{get isStage(){return!0}get tempo(){return this.json.tempo??60}set tempo(e){this.json.tempo=Number(e)}get videoState(){return this.json.videoState??"off"}set videoState(e){this.json.videoState=String(e)}get videoTransparency(){return this.json.videoTransparency??50}set videoTransparency(e){this.json.videoTransparency=Number(e)}get broadcastNames(){return Object.values(this.json.broadcasts)}addBroadcast(e){for(let[t,s]of Object.entries(this.json.broadcasts))if(s===e)return t;let t=`broadcastMsgId-${e}`;return this.json.broadcasts[t]=e,t}}class Sprite extends Target{get isStage(){return!1}get x(){return this.json.x??0}set x(e){this.json.x=Number(e)}get y(){return this.json.y??0}set y(e){this.json.y=Number(e)}get size(){return this.json.size??100}set size(e){this.json.size=Number(e)}get direction(){return this.json.direction??90}set direction(e){this.json.direction=Number(e)}get visible(){return this.json.visible??!0}set visible(e){this.json.visible=!!e}get draggable(){return this.json.draggable??!1}set draggable(e){this.json.draggable=!!e}get rotationStyle(){return this.json.rotationStyle??"all around"}set rotationStyle(e){this.json.rotationStyle=String(e)}get layerOrder(){return this.json.layerOrder??0}set layerOrder(e){this.json.layerOrder=Number(e)}}const DEFAULT_META={semver:"3.0.0",vm:"14.0.0",agent:""};class Project{constructor(e,t=new Map){this.json=e,this.assets=t}static async load(e){let t=await jszip_namespaceObject.loadAsync(e),s=t.file("project.json");if(!s)throw Error("Not a valid sb3: project.json is missing.");let r=JSON.parse(await s.async("string")),n=new Map,o=[];return t.forEach((e,t)=>{t.dir||"project.json"===e||o.push(t.async("uint8array").then(t=>n.set(e,t)))}),await Promise.all(o),new Project(r,n)}static create(){return new Project({targets:[{isStage:!0,name:"Stage",variables:{},lists:{},broadcasts:{},blocks:{},comments:{},currentCostume:0,costumes:[],sounds:[],volume:100,layerOrder:0,tempo:60,videoTransparency:50,videoState:"on",textToSpeechLanguage:null}],monitors:[],extensions:[],meta:{...DEFAULT_META}})}get stage(){return new Stage(this.json.targets.find(e=>e.isStage),this)}get sprites(){return this.json.targets.filter(e=>!e.isStage).map(e=>new Sprite(e,this))}get targets(){return this.json.targets.map(e=>e.isStage?new Stage(e,this):new Sprite(e,this))}get meta(){return this.json.meta}get monitors(){return this.json.monitors}get extensions(){return this.json.extensions}sprite(e){let t=this.json.targets.find(t=>!t.isStage&&t.name===e);return t?new Sprite(t,this):void 0}target(e){let t=this.json.targets.find(t=>t.name===e);if(t)return t.isStage?new Stage(t,this):new Sprite(t,this)}addSprite(e,t={}){if(this.sprite(e))throw Error(`A sprite named "${e}" already exists.`);let s=Math.max(0,...this.json.targets.map(e=>e.layerOrder??0)),r={isStage:!1,name:String(e),variables:{},lists:{},broadcasts:{},blocks:{},comments:{},currentCostume:0,costumes:[],sounds:[],volume:100,layerOrder:s+1,visible:!0,x:0,y:0,size:100,direction:90,draggable:!1,rotationStyle:"all around",...t};return this.json.targets.push(r),new Sprite(r,this)}removeSprite(e){let t="string"==typeof e?e:e.name,s=this.json.targets.findIndex(e=>!e.isStage&&e.name===t);if(s<0)return!1;let[r]=this.json.targets.splice(s,1);for(let e of[...r.costumes,...r.sounds])this._maybeDropAsset(e.md5ext);return!0}_maybeDropAsset(e){!e||this.json.targets.some(t=>t.costumes.some(t=>t.md5ext===e)||t.sounds.some(t=>t.md5ext===e))||this.assets.delete(e)}async save({compressionLevel:e=6}={}){let t=new jszip_namespaceObject;for(let[e,s]of(t.file("project.json",JSON.stringify(this.json)),this.assets))t.file(e,s);return t.generateAsync({type:"uint8array",compression:"DEFLATE",compressionOptions:{level:e}})}}for(var __rspack_i in exports.Costume=__webpack_exports__.Costume,exports.Project=__webpack_exports__.Project,exports.Sound=__webpack_exports__.Sound,exports.Sprite=__webpack_exports__.Sprite,exports.Stage=__webpack_exports__.Stage,exports.Target=__webpack_exports__.Target,exports.md5=__webpack_exports__.md5,exports.sniffFormat=__webpack_exports__.sniffFormat,exports.uid=__webpack_exports__.uid,__webpack_exports__)-1===["Costume","Project","Sound","Sprite","Stage","Target","md5","sniffFormat","uid"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["webpack://webpack/runtime/define_property_getters","webpack://webpack/runtime/has_own_property","webpack://webpack/runtime/make_namespace_object","../../src/md5.js","../../src/assets.js","../../src/format.js","../../src/ids.js","../../src/target.js","../../src/project.js"],"sourcesContent":["__webpack_require__.d = (exports, getters, values) => {\n\tvar define = (defs, kind) => {\n\t\tfor(var key in defs) {\n\t\t\tif(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] });\n\t\t\t}\n\t\t}\n\t};\n\tdefine(getters, \"get\");\n\tdefine(values, \"value\");\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// Pure-JS MD5 (RFC 1321). Scratch names asset files by the MD5 hash of their\n// bytes, so we need a hash that runs in both Node and the browser without\n// pulling in a dependency.\n\n// prettier-ignore\nconst K = new Int32Array([\n 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,\n 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,\n 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,\n 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,\n 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,\n 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,\n 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,\n 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,\n 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,\n 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,\n 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,\n]);\n\n// prettier-ignore\nconst S = [\n 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,\n 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,\n 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,\n 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,\n];\n\nconst rotl = (x, c) => (x << c) | (x >>> (32 - c));\n\nconst HEX = [];\nfor (let i = 0; i < 256; i++) HEX[i] = (i < 16 ? '0' : '') + i.toString(16);\nconst hexLE = (x) =>\n HEX[x & 0xff] +\n HEX[(x >>> 8) & 0xff] +\n HEX[(x >>> 16) & 0xff] +\n HEX[(x >>> 24) & 0xff];\n\n/**\n * Compute the lowercase hex MD5 digest of some bytes.\n *\n * @param {Uint8Array | ArrayBuffer} input - Bytes to hash.\n * @returns {string} 32-character lowercase hex digest.\n */\nexport function md5(input) {\n const msg = input instanceof Uint8Array ? input : new Uint8Array(input);\n const n = msg.length;\n\n // Pad: 0x80, zeros, then the original bit length as a 64-bit little-endian int.\n const withOne = n + 1;\n const padZeros =\n withOne % 64 <= 56 ? 56 - (withOne % 64) : 120 - (withOne % 64);\n const total = withOne + padZeros + 8;\n const buf = new Uint8Array(total);\n buf.set(msg);\n buf[n] = 0x80;\n const bitsLo = (n << 3) >>> 0;\n const bitsHi = (n >>> 29) >>> 0;\n buf[total - 8] = bitsLo & 0xff;\n buf[total - 7] = (bitsLo >>> 8) & 0xff;\n buf[total - 6] = (bitsLo >>> 16) & 0xff;\n buf[total - 5] = (bitsLo >>> 24) & 0xff;\n buf[total - 4] = bitsHi & 0xff;\n buf[total - 3] = (bitsHi >>> 8) & 0xff;\n buf[total - 2] = (bitsHi >>> 16) & 0xff;\n buf[total - 1] = (bitsHi >>> 24) & 0xff;\n\n let a0 = 0x67452301;\n let b0 = 0xefcdab89;\n let c0 = 0x98badcfe;\n let d0 = 0x10325476;\n\n const M = new Int32Array(16);\n for (let off = 0; off < total; off += 64) {\n for (let i = 0; i < 16; i++) {\n const j = off + i * 4;\n M[i] =\n buf[j] | (buf[j + 1] << 8) | (buf[j + 2] << 16) | (buf[j + 3] << 24);\n }\n\n let A = a0;\n let B = b0;\n let C = c0;\n let D = d0;\n\n for (let i = 0; i < 64; i++) {\n let F;\n let g;\n if (i < 16) {\n F = (B & C) | (~B & D);\n g = i;\n } else if (i < 32) {\n F = (D & B) | (~D & C);\n g = (5 * i + 1) % 16;\n } else if (i < 48) {\n F = B ^ C ^ D;\n g = (3 * i + 5) % 16;\n } else {\n F = C ^ (B | ~D);\n g = (7 * i) % 16;\n }\n F = (F + A + K[i] + M[g]) | 0;\n A = D;\n D = C;\n C = B;\n B = (B + rotl(F, S[i])) | 0;\n }\n\n a0 = (a0 + A) | 0;\n b0 = (b0 + B) | 0;\n c0 = (c0 + C) | 0;\n d0 = (d0 + D) | 0;\n }\n\n return hexLE(a0) + hexLE(b0) + hexLE(c0) + hexLE(d0);\n}\n","import { md5 } from './md5.js';\n\n/**\n * Base class for the two kinds of media a target can own: costumes and sounds.\n * Each asset wraps its raw entry in `project.json` plus the bytes stored in the\n * surrounding zip, keyed by `md5ext` (e.g. `b7f1cf69….wav`).\n *\n * @abstract\n */\nclass Asset {\n /**\n * @param {object} json - The raw costume/sound entry from project.json.\n * @param {import('./project.js').Project} project - Owning project (holds the bytes).\n */\n constructor(json, project) {\n /** @type {object} The underlying JSON; mutate via the accessors below. */\n this.json = json;\n /** @type {import('./project.js').Project} */\n this.project = project;\n }\n\n /** @returns {string} Display name shown in the editor. */\n get name() {\n return this.json.name;\n }\n set name(value) {\n this.json.name = String(value);\n }\n\n /** @returns {string} File extension/type, e.g. `png`, `svg`, `wav`, `mp3`. */\n get dataFormat() {\n return this.json.dataFormat;\n }\n\n /** @returns {string} The `<md5>.<ext>` filename of this asset inside the zip. */\n get md5ext() {\n return this.json.md5ext;\n }\n\n /**\n * The raw bytes of this asset, read from / written to the project's zip.\n *\n * Assigning new bytes recomputes the MD5 and rewrites `assetId`/`md5ext`, so\n * the file is always addressed by the hash of its current contents.\n *\n * @returns {Uint8Array | undefined}\n */\n get data() {\n return this.project.assets.get(this.json.md5ext);\n }\n set data(bytes) {\n const buf = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n const old = this.json.md5ext;\n const hash = md5(buf);\n this.json.assetId = hash;\n this.json.md5ext = `${hash}.${this.json.dataFormat}`;\n this.project.assets.set(this.json.md5ext, buf);\n if (old && old !== this.json.md5ext) this.project._maybeDropAsset(old);\n }\n}\n\n/**\n * A costume: an image (bitmap or SVG) a target can display.\n */\nexport class Costume extends Asset {\n /** @returns {number} Pixels per unit for bitmaps (1 for SVG, 2 for HD bitmaps). */\n get bitmapResolution() {\n return this.json.bitmapResolution ?? 1;\n }\n set bitmapResolution(value) {\n this.json.bitmapResolution = Number(value);\n }\n\n /** @returns {number} X of the rotation/anchor center, in costume pixels. */\n get rotationCenterX() {\n return this.json.rotationCenterX ?? 0;\n }\n set rotationCenterX(value) {\n this.json.rotationCenterX = Number(value);\n }\n\n /** @returns {number} Y of the rotation/anchor center, in costume pixels. */\n get rotationCenterY() {\n return this.json.rotationCenterY ?? 0;\n }\n set rotationCenterY(value) {\n this.json.rotationCenterY = Number(value);\n }\n}\n\n/**\n * A sound a target can play.\n */\nexport class Sound extends Asset {\n /** @returns {number} Sample rate in Hz. */\n get rate() {\n return this.json.rate;\n }\n set rate(value) {\n this.json.rate = Number(value);\n }\n\n /** @returns {number} Number of samples in the clip. */\n get sampleCount() {\n return this.json.sampleCount;\n }\n set sampleCount(value) {\n this.json.sampleCount = Number(value);\n }\n}\n","// Best-effort detection of an asset's type from its leading bytes, so callers\n// can drop in a buffer without spelling out `dataFormat` every time.\n\nconst startsWith = (bytes, sig) => sig.every((b, i) => bytes[i] === b);\nconst ascii = (s) => [...s].map((c) => c.charCodeAt(0));\n\n/**\n * Guess a Scratch `dataFormat` (file extension) from raw asset bytes.\n *\n * @param {Uint8Array} bytes - The asset contents.\n * @returns {string | undefined} The detected format, or undefined if unknown.\n */\nexport function sniffFormat(bytes) {\n if (!bytes || bytes.length < 4) return undefined;\n if (startsWith(bytes, [0x89, 0x50, 0x4e, 0x47])) return 'png';\n if (startsWith(bytes, [0xff, 0xd8, 0xff])) return 'jpg';\n if (startsWith(bytes, ascii('GIF'))) return 'gif';\n if (startsWith(bytes, ascii('RIFF'))) return 'wav';\n if (\n startsWith(bytes, ascii('ID3')) ||\n (bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0)\n )\n return 'mp3';\n // Text-based: SVG documents start with an XML prolog or the root tag.\n const head = String.fromCharCode(...bytes.slice(0, 256)).trimStart();\n if (\n head.startsWith('<?xml') ||\n head.startsWith('<svg') ||\n head.includes('<svg')\n )\n return 'svg';\n return undefined;\n}\n","// Scratch generates the keys used for blocks, variables, lists and broadcasts\n// from a fixed \"soup\" of characters. We mirror that here so generated IDs look\n// native and stay clear of JSON-unsafe characters.\nconst SOUP =\n '!#%()*+,-./:;=?@[]^_`{|}~' +\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +\n 'abcdefghijklmnopqrstuvwxyz' +\n '0123456789';\n\n/**\n * Generate a fresh 20-character Scratch-style unique id.\n *\n * @returns {string} A new id.\n */\nexport function uid() {\n let id = '';\n for (let i = 0; i < 20; i++) {\n id += SOUP[Math.floor(Math.random() * SOUP.length)];\n }\n return id;\n}\n","import { Costume, Sound } from './assets.js';\nimport { sniffFormat } from './format.js';\nimport { md5 } from './md5.js';\nimport { uid } from './ids.js';\n\n/**\n * A target is anything that lives in the project's `targets` array: either the\n * single {@link Stage} or a {@link Sprite}. This base class covers everything\n * the two share — name, costumes, sounds, variables, lists and raw blocks.\n *\n * @abstract\n */\nexport class Target {\n /**\n * @param {object} json - The raw target entry from project.json.\n * @param {import('./project.js').Project} project - Owning project.\n */\n constructor(json, project) {\n /** @type {object} The underlying JSON; the accessors below keep it in sync. */\n this.json = json;\n /** @type {import('./project.js').Project} */\n this.project = project;\n }\n\n /** @returns {boolean} True for the stage, false for sprites. */\n get isStage() {\n return Boolean(this.json.isStage);\n }\n\n /** @returns {string} The target's name. */\n get name() {\n return this.json.name;\n }\n set name(value) {\n this.json.name = String(value);\n }\n\n /** @returns {number} Output volume, 0–100. */\n get volume() {\n return this.json.volume ?? 100;\n }\n set volume(value) {\n this.json.volume = Number(value);\n }\n\n // --- Costumes -------------------------------------------------------------\n\n /** @returns {Costume[]} The target's costumes, in order. */\n get costumes() {\n return this.json.costumes.map((c) => new Costume(c, this.project));\n }\n\n /** @returns {number} Index of the currently selected costume. */\n get currentCostume() {\n return this.json.currentCostume ?? 0;\n }\n set currentCostume(value) {\n this.json.currentCostume = Number(value);\n }\n\n /**\n * Find a costume by name.\n *\n * @param {string} name\n * @returns {Costume | undefined}\n */\n getCostume(name) {\n const entry = this.json.costumes.find((c) => c.name === name);\n return entry ? new Costume(entry, this.project) : undefined;\n }\n\n /**\n * Add a costume from raw image bytes. The asset is stored in the zip keyed by\n * its MD5, and a costume entry pointing at it is appended.\n *\n * @param {string} name - Costume name.\n * @param {Uint8Array | ArrayBuffer} data - Image bytes (PNG/SVG/JPG/…).\n * @param {object} [options]\n * @param {string} [options.dataFormat] - Override the detected file type.\n * @param {number} [options.rotationCenterX] - Anchor X (defaults to 0).\n * @param {number} [options.rotationCenterY] - Anchor Y (defaults to 0).\n * @param {number} [options.bitmapResolution] - 1 for SVG, 2 for HD bitmaps.\n * @returns {Costume} The newly added costume.\n */\n addCostume(name, data, options = {}) {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\n const dataFormat = options.dataFormat ?? sniffFormat(bytes) ?? 'png';\n const hash = md5(bytes);\n const entry = {\n name: String(name),\n bitmapResolution:\n options.bitmapResolution ?? (dataFormat === 'svg' ? 1 : 2),\n dataFormat,\n assetId: hash,\n md5ext: `${hash}.${dataFormat}`,\n rotationCenterX: options.rotationCenterX ?? 0,\n rotationCenterY: options.rotationCenterY ?? 0,\n };\n this.project.assets.set(entry.md5ext, bytes);\n this.json.costumes.push(entry);\n return new Costume(entry, this.project);\n }\n\n /**\n * Remove a costume by name or index.\n *\n * @param {string | number} nameOrIndex\n * @returns {boolean} True if a costume was removed.\n */\n removeCostume(nameOrIndex) {\n return this._removeMedia('costumes', nameOrIndex);\n }\n\n // --- Sounds ---------------------------------------------------------------\n\n /** @returns {Sound[]} The target's sounds, in order. */\n get sounds() {\n return this.json.sounds.map((s) => new Sound(s, this.project));\n }\n\n /**\n * Find a sound by name.\n *\n * @param {string} name\n * @returns {Sound | undefined}\n */\n getSound(name) {\n const entry = this.json.sounds.find((s) => s.name === name);\n return entry ? new Sound(entry, this.project) : undefined;\n }\n\n /**\n * Add a sound from raw audio bytes.\n *\n * @param {string} name - Sound name.\n * @param {Uint8Array | ArrayBuffer} data - Audio bytes (WAV/MP3).\n * @param {object} [options]\n * @param {string} [options.dataFormat] - Override the detected file type.\n * @param {number} [options.rate] - Sample rate in Hz (default 48000).\n * @param {number} [options.sampleCount] - Number of samples (default 0).\n * @returns {Sound} The newly added sound.\n */\n addSound(name, data, options = {}) {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\n const dataFormat = options.dataFormat ?? sniffFormat(bytes) ?? 'wav';\n const hash = md5(bytes);\n const entry = {\n name: String(name),\n assetId: hash,\n dataFormat,\n format: '',\n rate: options.rate ?? 48000,\n sampleCount: options.sampleCount ?? 0,\n md5ext: `${hash}.${dataFormat}`,\n };\n this.project.assets.set(entry.md5ext, bytes);\n this.json.sounds.push(entry);\n return new Sound(entry, this.project);\n }\n\n /**\n * Remove a sound by name or index.\n *\n * @param {string | number} nameOrIndex\n * @returns {boolean} True if a sound was removed.\n */\n removeSound(nameOrIndex) {\n return this._removeMedia('sounds', nameOrIndex);\n }\n\n /**\n * @param {'costumes' | 'sounds'} kind\n * @param {string | number} nameOrIndex\n * @returns {boolean}\n * @private\n */\n _removeMedia(kind, nameOrIndex) {\n const list = this.json[kind];\n const index =\n typeof nameOrIndex === 'number'\n ? nameOrIndex\n : list.findIndex((m) => m.name === nameOrIndex);\n if (index < 0 || index >= list.length) return false;\n const [removed] = list.splice(index, 1);\n if (kind === 'costumes' && this.json.currentCostume >= list.length) {\n this.json.currentCostume = Math.max(0, list.length - 1);\n }\n this.project._maybeDropAsset(removed.md5ext);\n return true;\n }\n\n // --- Variables & lists ----------------------------------------------------\n\n /** @returns {string[]} Names of this target's variables. */\n get variableNames() {\n return Object.values(this.json.variables).map(([name]) => name);\n }\n\n /**\n * Read a variable's value by name.\n *\n * @param {string} name\n * @returns {string | number | boolean | undefined}\n */\n getVariable(name) {\n const found = Object.values(this.json.variables).find(([n]) => n === name);\n return found ? found[1] : undefined;\n }\n\n /**\n * Create or update a variable by name.\n *\n * @param {string} name\n * @param {string | number | boolean} value\n * @returns {string} The variable's id.\n */\n setVariable(name, value) {\n for (const [id, entry] of Object.entries(this.json.variables)) {\n if (entry[0] === name) {\n entry[1] = value;\n return id;\n }\n }\n const id = uid();\n this.json.variables[id] = [name, value];\n return id;\n }\n\n /**\n * Delete a variable by name.\n *\n * @param {string} name\n * @returns {boolean} True if a variable was deleted.\n */\n deleteVariable(name) {\n for (const [id, entry] of Object.entries(this.json.variables)) {\n if (entry[0] === name) {\n delete this.json.variables[id];\n return true;\n }\n }\n return false;\n }\n\n /** @returns {string[]} Names of this target's lists. */\n get listNames() {\n return Object.values(this.json.lists).map(([name]) => name);\n }\n\n /**\n * Read a list's contents by name.\n *\n * @param {string} name\n * @returns {Array<string | number> | undefined}\n */\n getList(name) {\n const found = Object.values(this.json.lists).find(([n]) => n === name);\n return found ? found[1] : undefined;\n }\n\n /**\n * Create or replace a list by name.\n *\n * @param {string} name\n * @param {Array<string | number>} items\n * @returns {string} The list's id.\n */\n setList(name, items = []) {\n for (const [id, entry] of Object.entries(this.json.lists)) {\n if (entry[0] === name) {\n entry[1] = items;\n return id;\n }\n }\n const id = uid();\n this.json.lists[id] = [name, items];\n return id;\n }\n\n /**\n * Delete a list by name.\n *\n * @param {string} name\n * @returns {boolean} True if a list was deleted.\n */\n deleteList(name) {\n for (const [id, entry] of Object.entries(this.json.lists)) {\n if (entry[0] === name) {\n delete this.json.lists[id];\n return true;\n }\n }\n return false;\n }\n\n /**\n * The raw `blocks` object for advanced scripting edits. Keys are block ids;\n * values are the block definitions. Mutate directly for low-level changes.\n *\n * @returns {object}\n */\n get blocks() {\n return this.json.blocks;\n }\n}\n\n/**\n * The stage: the single backdrop-bearing target that also owns the project's\n * broadcasts.\n */\nexport class Stage extends Target {\n /** @returns {true} Always the stage. Discriminates {@link Stage} from {@link Sprite}. */\n get isStage() {\n return true;\n }\n\n /** @returns {number} Tempo for music blocks, in BPM. */\n get tempo() {\n return this.json.tempo ?? 60;\n }\n set tempo(value) {\n this.json.tempo = Number(value);\n }\n\n /** @returns {string} Video input state: `on`, `off`, or `on-flipped`. */\n get videoState() {\n return this.json.videoState ?? 'off';\n }\n set videoState(value) {\n this.json.videoState = String(value);\n }\n\n /** @returns {number} Video transparency, 0–100. */\n get videoTransparency() {\n return this.json.videoTransparency ?? 50;\n }\n set videoTransparency(value) {\n this.json.videoTransparency = Number(value);\n }\n\n /** @returns {string[]} Names of all broadcast messages in the project. */\n get broadcastNames() {\n return Object.values(this.json.broadcasts);\n }\n\n /**\n * Add a broadcast message if it does not already exist.\n *\n * @param {string} name\n * @returns {string} The broadcast's id.\n */\n addBroadcast(name) {\n for (const [id, n] of Object.entries(this.json.broadcasts)) {\n if (n === name) return id;\n }\n const id = `broadcastMsgId-${name}`;\n this.json.broadcasts[id] = name;\n return id;\n }\n}\n\n/**\n * A sprite: a movable target with a position, size and orientation.\n */\nexport class Sprite extends Target {\n /** @returns {false} Never the stage. Discriminates {@link Sprite} from {@link Stage}. */\n get isStage() {\n return false;\n }\n\n /** @returns {number} X position on the stage (−240…240). */\n get x() {\n return this.json.x ?? 0;\n }\n set x(value) {\n this.json.x = Number(value);\n }\n\n /** @returns {number} Y position on the stage (−180…180). */\n get y() {\n return this.json.y ?? 0;\n }\n set y(value) {\n this.json.y = Number(value);\n }\n\n /** @returns {number} Size as a percentage (100 = original). */\n get size() {\n return this.json.size ?? 100;\n }\n set size(value) {\n this.json.size = Number(value);\n }\n\n /** @returns {number} Direction in degrees (90 = pointing right). */\n get direction() {\n return this.json.direction ?? 90;\n }\n set direction(value) {\n this.json.direction = Number(value);\n }\n\n /** @returns {boolean} Whether the sprite is shown. */\n get visible() {\n return this.json.visible ?? true;\n }\n set visible(value) {\n this.json.visible = Boolean(value);\n }\n\n /** @returns {boolean} Whether the sprite can be dragged in the player. */\n get draggable() {\n return this.json.draggable ?? false;\n }\n set draggable(value) {\n this.json.draggable = Boolean(value);\n }\n\n /** @returns {string} Rotation style: `all around`, `left-right`, `don't rotate`. */\n get rotationStyle() {\n return this.json.rotationStyle ?? 'all around';\n }\n set rotationStyle(value) {\n this.json.rotationStyle = String(value);\n }\n\n /** @returns {number} Stacking order; higher draws on top. */\n get layerOrder() {\n return this.json.layerOrder ?? 0;\n }\n set layerOrder(value) {\n this.json.layerOrder = Number(value);\n }\n}\n","import JSZip from '@turbowarp/jszip';\nimport { Sprite, Stage } from './target.js';\n\n/**\n * The project's `meta` block.\n *\n * @typedef {object} ProjectMeta\n * @property {string} semver - Scratch project schema version (e.g. `3.0.0`).\n * @property {string} vm - VM version that wrote the project.\n * @property {string} agent - User-agent string of the editor, if any.\n */\n\nconst DEFAULT_META = {\n semver: '3.0.0',\n vm: '14.0.0',\n agent: '',\n};\n\n/**\n * A loaded Scratch project (`.sb3`). An sb3 is a zip holding a `project.json`\n * description plus the costume/sound asset files it references. This class is\n * the entry point: load bytes, edit declaratively through {@link Stage} and\n * {@link Sprite}, then save back to bytes.\n *\n * @example\n * import { Project } from 'scratch4js';\n * import { readFile, writeFile } from 'node:fs/promises';\n *\n * const project = await Project.load(await readFile('game.sb3'));\n * const cat = project.sprite('Sprite1');\n * cat.x = 0;\n * cat.size = 150;\n * project.stage.setVariable('score', 0);\n * await writeFile('game.edited.sb3', await project.save());\n */\nexport class Project {\n /**\n * Prefer {@link Project.load}. Construct directly only when you already hold a\n * parsed `project.json` and its asset bytes.\n *\n * @param {object} json - Parsed project.json.\n * @param {Map<string, Uint8Array>} [assets] - Asset bytes keyed by `md5ext`.\n */\n constructor(json, assets = new Map()) {\n /** @type {object} The parsed project.json. */\n this.json = json;\n /** @type {Map<string, Uint8Array>} Asset bytes keyed by `<md5>.<ext>`. */\n this.assets = assets;\n }\n\n /**\n * Load a project from the raw bytes of an `.sb3` file.\n *\n * @param {Uint8Array | ArrayBuffer | Buffer} data - The sb3 zip bytes.\n * @returns {Promise<Project>}\n */\n static async load(data) {\n const zip = await JSZip.loadAsync(data);\n const projectFile = zip.file('project.json');\n if (!projectFile)\n throw new Error('Not a valid sb3: project.json is missing.');\n const json = JSON.parse(await projectFile.async('string'));\n\n const assets = new Map();\n const reads = [];\n zip.forEach((path, file) => {\n if (file.dir || path === 'project.json') return;\n reads.push(\n file.async('uint8array').then((bytes) => assets.set(path, bytes)),\n );\n });\n await Promise.all(reads);\n\n return new Project(json, assets);\n }\n\n /**\n * Create a new, empty project containing just a bare stage.\n *\n * @returns {Project}\n */\n static create() {\n const json = {\n targets: [\n {\n isStage: true,\n name: 'Stage',\n variables: {},\n lists: {},\n broadcasts: {},\n blocks: {},\n comments: {},\n currentCostume: 0,\n costumes: [],\n sounds: [],\n volume: 100,\n layerOrder: 0,\n tempo: 60,\n videoTransparency: 50,\n videoState: 'on',\n textToSpeechLanguage: null,\n },\n ],\n monitors: [],\n extensions: [],\n meta: { ...DEFAULT_META },\n };\n return new Project(json);\n }\n\n /** @returns {Stage} The project's single stage. */\n get stage() {\n const json = this.json.targets.find((t) => t.isStage);\n return new Stage(json, this);\n }\n\n /** @returns {Sprite[]} All non-stage targets, in array order. */\n get sprites() {\n return this.json.targets\n .filter((t) => !t.isStage)\n .map((t) => new Sprite(t, this));\n }\n\n /** @returns {Array<Stage | Sprite>} Every target, stage included. */\n get targets() {\n return this.json.targets.map((t) =>\n t.isStage ? new Stage(t, this) : new Sprite(t, this),\n );\n }\n\n /** @returns {ProjectMeta} The project's `meta` block (semver, vm, agent). */\n get meta() {\n return this.json.meta;\n }\n\n /** @returns {object[]} The raw `monitors` (variable/list watchers) array. */\n get monitors() {\n return this.json.monitors;\n }\n\n /** @returns {string[]} Ids of enabled extensions (e.g. `pen`, `music`). */\n get extensions() {\n return this.json.extensions;\n }\n\n /**\n * Find a sprite by name.\n *\n * @param {string} name\n * @returns {Sprite | undefined}\n */\n sprite(name) {\n const json = this.json.targets.find((t) => !t.isStage && t.name === name);\n return json ? new Sprite(json, this) : undefined;\n }\n\n /**\n * Find any target (sprite or stage) by name.\n *\n * @param {string} name\n * @returns {Stage | Sprite | undefined}\n */\n target(name) {\n const json = this.json.targets.find((t) => t.name === name);\n if (!json) return undefined;\n return json.isStage ? new Stage(json, this) : new Sprite(json, this);\n }\n\n /**\n * Add a new, empty sprite. It starts with no costumes, so add at least one\n * with {@link Sprite#addCostume} before opening the project in the editor.\n *\n * @param {string} name - Sprite name (must be unique among sprites).\n * @param {object} [props] - Initial property overrides (`x`, `y`, `size`, …).\n * @returns {Sprite} The new sprite.\n */\n addSprite(name, props = {}) {\n if (this.sprite(name))\n throw new Error(`A sprite named \"${name}\" already exists.`);\n const maxLayer = Math.max(\n 0,\n ...this.json.targets.map((t) => t.layerOrder ?? 0),\n );\n const json = {\n isStage: false,\n name: String(name),\n variables: {},\n lists: {},\n broadcasts: {},\n blocks: {},\n comments: {},\n currentCostume: 0,\n costumes: [],\n sounds: [],\n volume: 100,\n layerOrder: maxLayer + 1,\n visible: true,\n x: 0,\n y: 0,\n size: 100,\n direction: 90,\n draggable: false,\n rotationStyle: 'all around',\n ...props,\n };\n this.json.targets.push(json);\n return new Sprite(json, this);\n }\n\n /**\n * Remove a sprite by name or instance. Assets it solely owned are dropped.\n *\n * @param {string | Sprite} nameOrSprite\n * @returns {boolean} True if a sprite was removed.\n */\n removeSprite(nameOrSprite) {\n const name =\n typeof nameOrSprite === 'string' ? nameOrSprite : nameOrSprite.name;\n const index = this.json.targets.findIndex(\n (t) => !t.isStage && t.name === name,\n );\n if (index < 0) return false;\n const [removed] = this.json.targets.splice(index, 1);\n for (const media of [...removed.costumes, ...removed.sounds]) {\n this._maybeDropAsset(media.md5ext);\n }\n return true;\n }\n\n /**\n * Drop an asset's bytes if no costume or sound anywhere still references it.\n * Called automatically when media is removed or its bytes are replaced.\n *\n * @param {string} md5ext\n * @private\n */\n _maybeDropAsset(md5ext) {\n if (!md5ext) return;\n const stillUsed = this.json.targets.some(\n (t) =>\n t.costumes.some((c) => c.md5ext === md5ext) ||\n t.sounds.some((s) => s.md5ext === md5ext),\n );\n if (!stillUsed) this.assets.delete(md5ext);\n }\n\n /**\n * Serialize the project back into `.sb3` bytes.\n *\n * @param {object} [options]\n * @param {number} [options.compressionLevel=6] - DEFLATE level, 1–9.\n * @returns {Promise<Uint8Array>} The sb3 zip bytes.\n */\n async save({ compressionLevel = 6 } = {}) {\n const zip = new JSZip();\n zip.file('project.json', JSON.stringify(this.json));\n for (const [path, bytes] of this.assets) {\n zip.file(path, bytes);\n }\n return zip.generateAsync({\n type: 'uint8array',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n}\n"],"names":["__webpack_require__","e","Object","Symbol","K","Int32Array","S","rotl","x","c","HEX","i","hexLE","md5","input","msg","Uint8Array","n","withOne","total","buf","bitsLo","bitsHi","a0","b0","c0","d0","M","off","j","A","B","C","D","F","g","Asset","json","project","value","String","bytes","old","hash","Costume","Number","Sound","startsWith","sig","b","ascii","s","sniffFormat","head","SOUP","uid","id","Math","Target","Boolean","name","entry","undefined","data","options","dataFormat","nameOrIndex","kind","list","index","m","removed","found","items","Stage","Sprite","DEFAULT_META","Project","assets","Map","zip","JSZip","projectFile","Error","JSON","reads","path","file","Promise","t","props","maxLayer","nameOrSprite","media","md5ext","compressionLevel"],"mappings":"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"}
|