hikkaku 0.2.1 → 0.3.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 +31 -4
- package/assets/index.d.mts +1143 -783
- package/assets/index.mjs +1612 -2
- package/blocks/index.d.mts +20 -3
- package/blocks/index.mjs +20 -3
- package/chunk-DQk6qfdC.mjs +18 -0
- package/client/index.mjs +8 -1
- package/index.d.mts +2 -2
- package/index.mjs +31 -5
- package/package.json +5 -1
- package/{project-Ca9rsVT3.d.mts → project-djJPtrq7.d.mts} +21 -5
- package/types.d.mts +21 -0
- package/vite/index.mjs +112 -5
- /package/{composer-BudVTTBs.mjs → composer-DpyUR2R3.mjs} +0 -0
package/blocks/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as SoundSource, M as VariableReference, g as CostumeSource, w as PrimitiveSource, x as ListReference, y as HikkakuBlock } from "../project-djJPtrq7.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/blocks/control.d.ts
|
|
4
4
|
type StopOption = 'all' | 'this script' | 'other scripts in sprite' | 'other scripts in stage';
|
|
@@ -2570,9 +2570,18 @@ type SoundEffect = 'pitch' | 'pan';
|
|
|
2570
2570
|
* @returns Scratch statement block definition that is appended to the current script stack.
|
|
2571
2571
|
* @example
|
|
2572
2572
|
* ```ts
|
|
2573
|
+
* import { Project } from 'hikkaku'
|
|
2574
|
+
* import { SOUNDS } from 'hikkaku/assets'
|
|
2573
2575
|
* import { playSound } from 'hikkaku/blocks'
|
|
2574
2576
|
*
|
|
2575
|
-
*
|
|
2577
|
+
* const project = new Project()
|
|
2578
|
+
* const sprite = project.createSprite('Sprite')
|
|
2579
|
+
* const sound = sprite.addSound({
|
|
2580
|
+
* ...SOUNDS.COMPUTER_BEEP,
|
|
2581
|
+
* name: 'beep',
|
|
2582
|
+
* })
|
|
2583
|
+
*
|
|
2584
|
+
* playSound(sound)
|
|
2576
2585
|
* ```
|
|
2577
2586
|
*/
|
|
2578
2587
|
declare const playSound: (sound: SoundSource) => HikkakuBlock;
|
|
@@ -2586,9 +2595,17 @@ declare const playSound: (sound: SoundSource) => HikkakuBlock;
|
|
|
2586
2595
|
* @returns Scratch statement block definition that is appended to the current script stack.
|
|
2587
2596
|
* @example
|
|
2588
2597
|
* ```ts
|
|
2598
|
+
* import { Project } from 'hikkaku'
|
|
2599
|
+
* import { SOUNDS } from 'hikkaku/assets'
|
|
2589
2600
|
* import { playSoundUntilDone } from 'hikkaku/blocks'
|
|
2590
2601
|
*
|
|
2591
|
-
*
|
|
2602
|
+
* const project = new Project()
|
|
2603
|
+
* const sound = project.addSound({
|
|
2604
|
+
* ...SOUNDS.COMPUTER_BEEP,
|
|
2605
|
+
* name: 'beep',
|
|
2606
|
+
* })
|
|
2607
|
+
*
|
|
2608
|
+
* playSoundUntilDone(sound)
|
|
2592
2609
|
* ```
|
|
2593
2610
|
*/
|
|
2594
2611
|
declare const playSoundUntilDone: (sound: SoundSource) => HikkakuBlock;
|
package/blocks/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as valueBlock, c as fromSoundSource, i as substack, l as InputType, n as block, o as fromCostumeSource, s as fromPrimitiveSource, t as attachStack, u as Shadow } from "../composer-
|
|
1
|
+
import { a as valueBlock, c as fromSoundSource, i as substack, l as InputType, n as block, o as fromCostumeSource, s as fromPrimitiveSource, t as attachStack, u as Shadow } from "../composer-DpyUR2R3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/blocks/control.ts
|
|
4
4
|
/**
|
|
@@ -3136,9 +3136,18 @@ const getUsername = () => {
|
|
|
3136
3136
|
* @returns Scratch statement block definition that is appended to the current script stack.
|
|
3137
3137
|
* @example
|
|
3138
3138
|
* ```ts
|
|
3139
|
+
* import { Project } from 'hikkaku'
|
|
3140
|
+
* import { SOUNDS } from 'hikkaku/assets'
|
|
3139
3141
|
* import { playSound } from 'hikkaku/blocks'
|
|
3140
3142
|
*
|
|
3141
|
-
*
|
|
3143
|
+
* const project = new Project()
|
|
3144
|
+
* const sprite = project.createSprite('Sprite')
|
|
3145
|
+
* const sound = sprite.addSound({
|
|
3146
|
+
* ...SOUNDS.COMPUTER_BEEP,
|
|
3147
|
+
* name: 'beep',
|
|
3148
|
+
* })
|
|
3149
|
+
*
|
|
3150
|
+
* playSound(sound)
|
|
3142
3151
|
* ```
|
|
3143
3152
|
*/
|
|
3144
3153
|
const playSound = (sound) => {
|
|
@@ -3154,9 +3163,17 @@ const playSound = (sound) => {
|
|
|
3154
3163
|
* @returns Scratch statement block definition that is appended to the current script stack.
|
|
3155
3164
|
* @example
|
|
3156
3165
|
* ```ts
|
|
3166
|
+
* import { Project } from 'hikkaku'
|
|
3167
|
+
* import { SOUNDS } from 'hikkaku/assets'
|
|
3157
3168
|
* import { playSoundUntilDone } from 'hikkaku/blocks'
|
|
3158
3169
|
*
|
|
3159
|
-
*
|
|
3170
|
+
* const project = new Project()
|
|
3171
|
+
* const sound = project.addSound({
|
|
3172
|
+
* ...SOUNDS.COMPUTER_BEEP,
|
|
3173
|
+
* name: 'beep',
|
|
3174
|
+
* })
|
|
3175
|
+
*
|
|
3176
|
+
* playSoundUntilDone(sound)
|
|
3160
3177
|
* ```
|
|
3161
3178
|
*/
|
|
3162
3179
|
const playSoundUntilDone = (sound) => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) {
|
|
6
|
+
__defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (!no_symbols) {
|
|
12
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
}
|
|
14
|
+
return target;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { __exportAll as t };
|
package/client/index.mjs
CHANGED
|
@@ -35,7 +35,14 @@ const getScratchInternalStates = (root) => {
|
|
|
35
35
|
}
|
|
36
36
|
return false;
|
|
37
37
|
});
|
|
38
|
-
vm.runtime.storage
|
|
38
|
+
const storage = vm.runtime.storage;
|
|
39
|
+
storage.webHelper.assetTool.tools.splice(0, 1);
|
|
40
|
+
storage.webHelper.stores.splice(0, storage.webHelper.stores.length);
|
|
41
|
+
storage.addWebStore([
|
|
42
|
+
storage.AssetType.ImageVector,
|
|
43
|
+
storage.AssetType.ImageBitmap,
|
|
44
|
+
storage.AssetType.Sound
|
|
45
|
+
], (asset) => `/hikkaku-assets/${asset.assetId}.${asset.dataFormat}`, null, null);
|
|
39
46
|
return {
|
|
40
47
|
reduxState,
|
|
41
48
|
vm,
|
package/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
export { BlockInit, CostumeReference, CostumeSource, CreateListOptions, CreateVariableOptions, Handler, HikkakuBlock, ListMonitorOptions, ListReference, MonitorPosition, PrimitiveAvailableOnScratch, PrimitiveSource, Project, SoundReference, SoundSource, Target, VariableBase, VariableDefinition, VariableMonitorMode, VariableMonitorOptions, VariableReference, attachStack, block, createBlocks, fromCostumeSource, fromPrimitiveSource, fromSoundSource, substack, valueBlock };
|
|
1
|
+
import { A as VariableMonitorMode, C as PrimitiveAvailableOnScratch, D as SoundSource, E as SoundReference, M as VariableReference, O as VariableBase, S as MonitorPosition, T as SoundData, _ as CreateListOptions, a as Handler, b as ListMonitorOptions, c as createBlocks, d as fromCostumeSource, f as fromPrimitiveSource, g as CostumeSource, h as CostumeReference, i as BlockInit, j as VariableMonitorOptions, k as VariableDefinition, l as substack, m as CostumeData, n as SpriteOptions, o as attachStack, p as fromSoundSource, r as Target, s as block, t as Project, u as valueBlock, v as CreateVariableOptions, w as PrimitiveSource, x as ListReference, y as HikkakuBlock } from "./project-djJPtrq7.mjs";
|
|
2
|
+
export { BlockInit, CostumeData, CostumeReference, CostumeSource, CreateListOptions, CreateVariableOptions, Handler, HikkakuBlock, ListMonitorOptions, ListReference, MonitorPosition, PrimitiveAvailableOnScratch, PrimitiveSource, Project, SoundData, SoundReference, SoundSource, SpriteOptions, Target, VariableBase, VariableDefinition, VariableMonitorMode, VariableMonitorOptions, VariableReference, attachStack, block, createBlocks, fromCostumeSource, fromPrimitiveSource, fromSoundSource, substack, valueBlock };
|
package/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as valueBlock, c as fromSoundSource, i as substack, n as block, o as fromCostumeSource, r as createBlocks, s as fromPrimitiveSource, t as attachStack } from "./composer-
|
|
1
|
+
import { a as valueBlock, c as fromSoundSource, i as substack, n as block, o as fromCostumeSource, r as createBlocks, s as fromPrimitiveSource, t as attachStack } from "./composer-DpyUR2R3.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/core/monitors.ts
|
|
4
4
|
const createVariableMonitor = (id, name, defaultValue, spriteName, options) => {
|
|
@@ -86,9 +86,15 @@ var Target = class {
|
|
|
86
86
|
#monitors = [];
|
|
87
87
|
#costumes = [];
|
|
88
88
|
#sounds = [];
|
|
89
|
-
|
|
89
|
+
#size;
|
|
90
|
+
#x;
|
|
91
|
+
#y;
|
|
92
|
+
constructor(isStage, name, options) {
|
|
90
93
|
this.isStage = isStage;
|
|
91
94
|
this.name = name;
|
|
95
|
+
this.#size = options?.size;
|
|
96
|
+
this.#x = options?.x;
|
|
97
|
+
this.#y = options?.y;
|
|
92
98
|
}
|
|
93
99
|
run(handler) {
|
|
94
100
|
const blocks = createBlocks(() => {
|
|
@@ -171,9 +177,18 @@ var Target = class {
|
|
|
171
177
|
...target,
|
|
172
178
|
isStage: false,
|
|
173
179
|
name: this.name,
|
|
174
|
-
visible: true
|
|
180
|
+
visible: true,
|
|
181
|
+
size: this.#size,
|
|
182
|
+
x: this.#x,
|
|
183
|
+
y: this.#y
|
|
175
184
|
};
|
|
176
185
|
}
|
|
186
|
+
getAdditionalAssets() {
|
|
187
|
+
const assets = /* @__PURE__ */ new Map();
|
|
188
|
+
for (const costume of this.#costumes) if (costume._data) assets.set(`${costume.assetId}.${costume.dataFormat}`, costume._data);
|
|
189
|
+
for (const sound of this.#sounds) if (sound._data) assets.set(`${sound.assetId}.${sound.dataFormat}`, sound._data);
|
|
190
|
+
return assets;
|
|
191
|
+
}
|
|
177
192
|
};
|
|
178
193
|
var Project = class {
|
|
179
194
|
stage;
|
|
@@ -183,11 +198,17 @@ var Project = class {
|
|
|
183
198
|
this.stage = target;
|
|
184
199
|
this.#targets.push(target);
|
|
185
200
|
}
|
|
186
|
-
createSprite(name) {
|
|
187
|
-
const sprite = new Target(false, name);
|
|
201
|
+
createSprite(name, options) {
|
|
202
|
+
const sprite = new Target(false, name, options);
|
|
188
203
|
this.#targets.push(sprite);
|
|
189
204
|
return sprite;
|
|
190
205
|
}
|
|
206
|
+
addCostume(costume) {
|
|
207
|
+
return this.stage.addCostume(costume);
|
|
208
|
+
}
|
|
209
|
+
addSound(sound) {
|
|
210
|
+
return this.stage.addSound(sound);
|
|
211
|
+
}
|
|
191
212
|
toScratch() {
|
|
192
213
|
const targets = this.#targets.map((target) => target.toScratch());
|
|
193
214
|
return {
|
|
@@ -200,6 +221,11 @@ var Project = class {
|
|
|
200
221
|
}
|
|
201
222
|
};
|
|
202
223
|
}
|
|
224
|
+
getAdditionalAssets() {
|
|
225
|
+
const assets = /* @__PURE__ */ new Map();
|
|
226
|
+
for (const target of this.#targets) for (const [key, value] of target.getAdditionalAssets()) assets.set(key, value);
|
|
227
|
+
return assets;
|
|
228
|
+
}
|
|
203
229
|
};
|
|
204
230
|
|
|
205
231
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hikkaku",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"exports": {
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"./vite": {
|
|
24
24
|
"import": "./vite/index.mjs",
|
|
25
25
|
"types": "./vite/index.d.mts"
|
|
26
|
+
},
|
|
27
|
+
"./types": {
|
|
28
|
+
"import": "./types.d.mjs",
|
|
29
|
+
"types": "./types.d.mts"
|
|
26
30
|
}
|
|
27
31
|
},
|
|
28
32
|
"scripts": {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as sb3 from "sb3-types";
|
|
2
|
+
import { Costume, Sound } from "sb3-types";
|
|
2
3
|
|
|
3
4
|
//#region src/core/types.d.ts
|
|
4
5
|
type PrimitiveAvailableOnScratch = number | boolean | string;
|
|
@@ -55,6 +56,12 @@ interface HikkakuBlock {
|
|
|
55
56
|
isBlock: true;
|
|
56
57
|
id: string;
|
|
57
58
|
}
|
|
59
|
+
type CostumeData = Costume & {
|
|
60
|
+
_data?: Uint8Array;
|
|
61
|
+
};
|
|
62
|
+
type SoundData = Sound & {
|
|
63
|
+
_data?: Uint8Array;
|
|
64
|
+
};
|
|
58
65
|
//#endregion
|
|
59
66
|
//#region src/core/block-helper.d.ts
|
|
60
67
|
declare const fromPrimitiveSource: <T extends PrimitiveAvailableOnScratch>(source: PrimitiveSource<T>) => sb3.Input;
|
|
@@ -114,26 +121,35 @@ interface ListMonitor {
|
|
|
114
121
|
type Monitor = VariableMonitor | ListMonitor;
|
|
115
122
|
//#endregion
|
|
116
123
|
//#region src/core/project.d.ts
|
|
124
|
+
interface SpriteOptions {
|
|
125
|
+
size?: number;
|
|
126
|
+
x?: number;
|
|
127
|
+
y?: number;
|
|
128
|
+
}
|
|
117
129
|
declare class Target<IsStage extends boolean = boolean> {
|
|
118
130
|
#private;
|
|
119
131
|
readonly isStage: IsStage;
|
|
120
132
|
readonly name: IsStage extends true ? 'Stage' : string;
|
|
121
133
|
currentCostume: number;
|
|
122
|
-
constructor(isStage: IsStage, name: IsStage extends true ? 'Stage' : string);
|
|
134
|
+
constructor(isStage: IsStage, name: IsStage extends true ? 'Stage' : string, options?: IsStage extends false ? SpriteOptions : undefined);
|
|
123
135
|
run(handler: (target: Target<IsStage>) => void): void;
|
|
124
136
|
createVariable(name: string, defaultValue?: sb3.ScalarVal, isCloudVariableOrOptions?: boolean | CreateVariableOptions): VariableDefinition;
|
|
125
137
|
createList(name: string, defaultValue?: sb3.ScalarVal[], options?: CreateListOptions): ListReference;
|
|
126
|
-
addCostume(costume:
|
|
127
|
-
addSound(sound:
|
|
138
|
+
addCostume(costume: CostumeData): CostumeReference;
|
|
139
|
+
addSound(sound: SoundData): SoundReference;
|
|
128
140
|
get monitors(): readonly Monitor[];
|
|
129
141
|
toScratch(): IsStage extends true ? sb3.Stage : sb3.Sprite;
|
|
142
|
+
getAdditionalAssets(): Map<string, Uint8Array>;
|
|
130
143
|
}
|
|
131
144
|
declare class Project {
|
|
132
145
|
#private;
|
|
133
146
|
readonly stage: Target<true>;
|
|
134
147
|
constructor();
|
|
135
|
-
createSprite(name: string): Target<false>;
|
|
148
|
+
createSprite(name: string, options?: SpriteOptions): Target<false>;
|
|
149
|
+
addCostume(costume: CostumeData): CostumeReference;
|
|
150
|
+
addSound(sound: SoundData): SoundReference;
|
|
136
151
|
toScratch(): sb3.ScratchProject;
|
|
152
|
+
getAdditionalAssets(): Map<string, Uint8Array>;
|
|
137
153
|
}
|
|
138
154
|
//#endregion
|
|
139
|
-
export {
|
|
155
|
+
export { VariableMonitorMode as A, PrimitiveAvailableOnScratch as C, SoundSource as D, SoundReference as E, VariableReference as M, VariableBase as O, MonitorPosition as S, SoundData as T, CreateListOptions as _, Handler as a, ListMonitorOptions as b, createBlocks as c, fromCostumeSource as d, fromPrimitiveSource as f, CostumeSource as g, CostumeReference as h, BlockInit as i, VariableMonitorOptions as j, VariableDefinition as k, substack as l, CostumeData as m, SpriteOptions as n, attachStack as o, fromSoundSource as p, Target as r, block as s, Project as t, valueBlock as u, CreateVariableOptions as v, PrimitiveSource as w, ListReference as x, HikkakuBlock as y };
|
package/types.d.mts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
declare module '*.svg?scratch' {
|
|
3
|
+
import * as sb3 from 'sb3-types';
|
|
4
|
+
const content: sb3.Costume;
|
|
5
|
+
export default content;
|
|
6
|
+
}
|
|
7
|
+
declare module '*.png?scratch' {
|
|
8
|
+
import * as sb3 from 'sb3-types';
|
|
9
|
+
const content: sb3.Costume;
|
|
10
|
+
export default content;
|
|
11
|
+
}
|
|
12
|
+
declare module '*.wav?scratch' {
|
|
13
|
+
import * as sb3 from 'sb3-types';
|
|
14
|
+
const content: sb3.Sound;
|
|
15
|
+
export default content;
|
|
16
|
+
}
|
|
17
|
+
declare module '*.mp3?scratch' {
|
|
18
|
+
import * as sb3 from 'sb3-types';
|
|
19
|
+
const content: sb3.Sound;
|
|
20
|
+
export default content;
|
|
21
|
+
}
|
package/vite/index.mjs
CHANGED
|
@@ -1,15 +1,66 @@
|
|
|
1
1
|
import { zip } from "fflate";
|
|
2
|
-
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { createServerModuleRunner } from "vite";
|
|
6
|
+
import crypto from "node:crypto";
|
|
6
7
|
|
|
8
|
+
//#region src/vite/plugin-scratch-import.ts
|
|
9
|
+
const pluginScratchImport = () => ({
|
|
10
|
+
name: "vite-plugin-hikkaku:scratch-import",
|
|
11
|
+
enforce: "pre",
|
|
12
|
+
resolveId(source, importer, _options) {
|
|
13
|
+
if (source.endsWith("?scratch")) {
|
|
14
|
+
if (source.endsWith(".svg?scratch") || source.endsWith(".png?scratch") || source.endsWith(".wav?scratch") || source.endsWith(".mp3?scratch")) {
|
|
15
|
+
const importerPath = pathToFileURL(importer ?? "");
|
|
16
|
+
return { id: `\0scratch:${new URL(source, importerPath)}` };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
async load(id, _options) {
|
|
21
|
+
if (id.startsWith("\0scratch:")) {
|
|
22
|
+
const url = new URL(id.slice(9, -8));
|
|
23
|
+
const ext = url.pathname.split(".").pop();
|
|
24
|
+
if (!ext) throw new Error(`Unsupported scratch asset type: ${url.pathname}`);
|
|
25
|
+
const file = await readFile(fileURLToPath(url));
|
|
26
|
+
const hash = crypto.createHash("md5");
|
|
27
|
+
hash.update(file);
|
|
28
|
+
const md5 = hash.digest("hex");
|
|
29
|
+
const data = {
|
|
30
|
+
name: path.basename(url.pathname),
|
|
31
|
+
_data: Buffer.from(file).toString("base64"),
|
|
32
|
+
assetId: md5,
|
|
33
|
+
dataFormat: ext,
|
|
34
|
+
md5ext: `${md5}.${ext}`
|
|
35
|
+
};
|
|
36
|
+
return `
|
|
37
|
+
const data = ${JSON.stringify(data)}
|
|
38
|
+
// to Uint8Array
|
|
39
|
+
data._data = Uint8Array.from(atob(data._data), c => c.charCodeAt(0));
|
|
40
|
+
|
|
41
|
+
export default data
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
7
48
|
//#region src/vite/index.ts
|
|
8
49
|
const BASE_URL = "https://scratchfoundation.github.io/scratch-gui/";
|
|
9
50
|
const VIRTUAL_MODULE_IDS = { project: "/@virtual/hikkaku-project" };
|
|
10
51
|
function hikkaku(init) {
|
|
11
52
|
let runner = null;
|
|
12
|
-
|
|
53
|
+
let additionalAssets = /* @__PURE__ */ new Map();
|
|
54
|
+
const assetCache = /* @__PURE__ */ new Map();
|
|
55
|
+
const setContentType = (res, assetId) => {
|
|
56
|
+
const assetExt = path.extname(assetId).toLowerCase();
|
|
57
|
+
if (assetExt === ".png") res.setHeader("Content-Type", "image/png");
|
|
58
|
+
else if (assetExt === ".jpg" || assetExt === ".jpeg") res.setHeader("Content-Type", "image/jpeg");
|
|
59
|
+
else if (assetExt === ".wav") res.setHeader("Content-Type", "audio/wav");
|
|
60
|
+
else if (assetExt === ".mp3") res.setHeader("Content-Type", "audio/mpeg");
|
|
61
|
+
else res.setHeader("Content-Type", "application/octet-stream");
|
|
62
|
+
};
|
|
63
|
+
return [{
|
|
13
64
|
name: "vite-plugin-hikkaku",
|
|
14
65
|
config(config, env) {
|
|
15
66
|
if (env.command === "build") (config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "vite-plugin-turbowarp-packager"))?.api.setEntry(path.join(process.cwd(), "dist", "project.sb3"));
|
|
@@ -38,8 +89,12 @@ function hikkaku(init) {
|
|
|
38
89
|
}
|
|
39
90
|
const { default: project } = await import(pathToFileURL(path.join(process.cwd(), "dist/.tmp", "project.mjs")).href);
|
|
40
91
|
const projectJSON = project.toScratch();
|
|
92
|
+
const assets = project.getAdditionalAssets();
|
|
41
93
|
const zipData = await new Promise((resolve, reject) => {
|
|
42
|
-
zip({
|
|
94
|
+
zip({
|
|
95
|
+
"project.json": new TextEncoder().encode(JSON.stringify(projectJSON)),
|
|
96
|
+
...Object.fromEntries(assets.entries())
|
|
97
|
+
}, (err, data) => {
|
|
43
98
|
if (err) reject(err);
|
|
44
99
|
else resolve(data);
|
|
45
100
|
});
|
|
@@ -56,6 +111,12 @@ function hikkaku(init) {
|
|
|
56
111
|
name: "project.json",
|
|
57
112
|
source: JSON.stringify(projectJSON, null, 2)
|
|
58
113
|
});
|
|
114
|
+
for (const [assetId, data] of assets.entries()) this.emitFile({
|
|
115
|
+
type: "asset",
|
|
116
|
+
fileName: `assets/${assetId}`,
|
|
117
|
+
name: `assets/${assetId}`,
|
|
118
|
+
source: data
|
|
119
|
+
});
|
|
59
120
|
await rm(tmpDir, {
|
|
60
121
|
recursive: true,
|
|
61
122
|
force: true
|
|
@@ -88,6 +149,7 @@ function hikkaku(init) {
|
|
|
88
149
|
if (this.environment.name !== "hikkaku") return;
|
|
89
150
|
if (!runner) throw new Error("Module runner is not initialized.");
|
|
90
151
|
const project = (await runner.import(init.entry)).default;
|
|
152
|
+
additionalAssets = project.getAdditionalAssets();
|
|
91
153
|
options.server.environments.client.hot.send("hikkaku:project", project.toScratch());
|
|
92
154
|
},
|
|
93
155
|
async configureServer(server) {
|
|
@@ -98,9 +160,54 @@ function hikkaku(init) {
|
|
|
98
160
|
server.environments.client.hot.on("vite:client:connect", async () => {
|
|
99
161
|
if (!runner) throw new Error("Module runner is not initialized.");
|
|
100
162
|
const project = (await runner.import(init.entry)).default;
|
|
163
|
+
additionalAssets = project.getAdditionalAssets();
|
|
101
164
|
server.environments.client.hot.send("hikkaku:project", project.toScratch());
|
|
102
165
|
});
|
|
103
166
|
server.middlewares.use(async (req, res, next) => {
|
|
167
|
+
if (req.url?.startsWith("/hikkaku-assets/")) {
|
|
168
|
+
const segments = req.url.split("/");
|
|
169
|
+
const assetId = segments[segments.indexOf("hikkaku-assets") + 1];
|
|
170
|
+
if (!assetId) {
|
|
171
|
+
res.statusCode = 400;
|
|
172
|
+
res.end("Asset ID is required");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const assetData = additionalAssets.get(assetId);
|
|
176
|
+
if (!assetData) {
|
|
177
|
+
if (assetCache.has(assetId)) {
|
|
178
|
+
const cached = assetCache.get(assetId);
|
|
179
|
+
if (cached === false) {
|
|
180
|
+
res.statusCode = 404;
|
|
181
|
+
res.end("Asset not found");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
setContentType(res, assetId);
|
|
185
|
+
res.end(cached);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const assetData = await fetch(`https://assets.scratch.mit.edu/internalapi/asset/${assetId}/get/`).then((r) => {
|
|
189
|
+
if (!r.ok) return null;
|
|
190
|
+
return r.arrayBuffer();
|
|
191
|
+
}).catch((e) => {
|
|
192
|
+
console.warn("Failed to fetch asset from network:", e);
|
|
193
|
+
return null;
|
|
194
|
+
});
|
|
195
|
+
if (assetData) {
|
|
196
|
+
const uint8array = new Uint8Array(assetData);
|
|
197
|
+
assetCache.set(assetId, uint8array);
|
|
198
|
+
setContentType(res, assetId);
|
|
199
|
+
res.end(uint8array);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
assetCache.set(assetId, false);
|
|
203
|
+
res.statusCode = 404;
|
|
204
|
+
res.end("Asset not found");
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
setContentType(res, assetId);
|
|
208
|
+
res.end(assetData);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
104
211
|
if (req.url === "/") {
|
|
105
212
|
const html = (await fetch(BASE_URL).then((res) => res.text())).replace("gui.js", "https://scratchfoundation.github.io/scratch-gui/gui.js").replace("</head>", "<script src=\"/@vite/client\" type=\"module\"><\/script><script type=\"module\" src=\"/@virtual/hikkaku-client\"><\/script></head>");
|
|
106
213
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -122,7 +229,7 @@ function hikkaku(init) {
|
|
|
122
229
|
next();
|
|
123
230
|
});
|
|
124
231
|
}
|
|
125
|
-
};
|
|
232
|
+
}, pluginScratchImport()];
|
|
126
233
|
}
|
|
127
234
|
|
|
128
235
|
//#endregion
|
|
File without changes
|