moonscratch 0.1.0 → 0.1.2

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.
Files changed (150) hide show
  1. package/dist/chunk-DQk6qfdC.mjs +18 -0
  2. package/dist/index.d.mts +1173 -0
  3. package/dist/index.mjs +27135 -0
  4. package/package.json +6 -1
  5. package/.agents/skills/moonbit-agent-guide/LICENSE +0 -202
  6. package/.agents/skills/moonbit-agent-guide/SKILL.mbt.md +0 -1126
  7. package/.agents/skills/moonbit-agent-guide/SKILL.md +0 -1126
  8. package/.agents/skills/moonbit-agent-guide/ide.md +0 -116
  9. package/.agents/skills/moonbit-agent-guide/references/advanced-moonbit-build.md +0 -106
  10. package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.mbt.md +0 -422
  11. package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.md +0 -422
  12. package/.agents/skills/moonbit-practice/SKILL.md +0 -258
  13. package/.agents/skills/moonbit-practice/assets/ci.yaml +0 -25
  14. package/.agents/skills/moonbit-practice/reference/agents.md +0 -1469
  15. package/.agents/skills/moonbit-practice/reference/configuration.md +0 -228
  16. package/.agents/skills/moonbit-practice/reference/ffi.md +0 -229
  17. package/.agents/skills/moonbit-practice/reference/ide.md +0 -189
  18. package/.agents/skills/moonbit-practice/reference/performance.md +0 -217
  19. package/.agents/skills/moonbit-practice/reference/refactor.md +0 -154
  20. package/.agents/skills/moonbit-practice/reference/stdlib.md +0 -351
  21. package/.agents/skills/moonbit-practice/reference/testing.md +0 -228
  22. package/.agents/skills/moonbit-refactoring/LICENSE +0 -21
  23. package/.agents/skills/moonbit-refactoring/SKILL.md +0 -323
  24. package/.githooks/README.md +0 -23
  25. package/.githooks/pre-commit +0 -3
  26. package/.github/workflows/copilot-setup-steps.yml +0 -40
  27. package/.turbo/turbo-typecheck.log +0 -2
  28. package/AGENTS.md +0 -91
  29. package/PLAN.md +0 -64
  30. package/TODO.md +0 -120
  31. package/benchmarks/calc.bench.ts +0 -144
  32. package/benchmarks/draw.bench.ts +0 -215
  33. package/benchmarks/load.bench.ts +0 -28
  34. package/benchmarks/render.bench.ts +0 -53
  35. package/benchmarks/run.bench.ts +0 -8
  36. package/benchmarks/types.d.ts +0 -15
  37. package/docs/scratch-vm-specs/eventloop.md +0 -103
  38. package/docs/scratch-vm-specs/moonscratch-time-separation.md +0 -50
  39. package/index.html +0 -91
  40. package/js/AGENTS.md +0 -5
  41. package/js/a.ts +0 -52
  42. package/js/assets/AGENTS.md +0 -5
  43. package/js/assets/base64.test.ts +0 -14
  44. package/js/assets/base64.ts +0 -21
  45. package/js/assets/build-asset.test.ts +0 -26
  46. package/js/assets/build-asset.ts +0 -28
  47. package/js/assets/create.test.ts +0 -142
  48. package/js/assets/create.ts +0 -122
  49. package/js/assets/index.test.ts +0 -15
  50. package/js/assets/index.ts +0 -2
  51. package/js/assets/types.ts +0 -26
  52. package/js/assets/validation.test.ts +0 -34
  53. package/js/assets/validation.ts +0 -25
  54. package/js/assets.test.ts +0 -14
  55. package/js/assets.ts +0 -1
  56. package/js/index.test.ts +0 -26
  57. package/js/index.ts +0 -3
  58. package/js/render/index.test.ts +0 -65
  59. package/js/render/index.ts +0 -13
  60. package/js/render/sharp.ts +0 -87
  61. package/js/render/svg.ts +0 -68
  62. package/js/render/types.ts +0 -35
  63. package/js/render/utils.ts +0 -108
  64. package/js/render/webgl.ts +0 -274
  65. package/js/sharp-optional.d.ts +0 -16
  66. package/js/test/helpers.ts +0 -116
  67. package/js/test/hikkaku-sample.test.ts +0 -37
  68. package/js/test/rubik-components.input-motion.test.ts +0 -60
  69. package/js/test/rubik-components.lists.test.ts +0 -49
  70. package/js/test/rubik-components.operators.test.ts +0 -104
  71. package/js/test/rubik-components.pen.test.ts +0 -112
  72. package/js/test/rubik-components.procedures-loops.test.ts +0 -72
  73. package/js/test/rubik-components.variables-branches.test.ts +0 -57
  74. package/js/test/rubik-components.visibility-entry.test.ts +0 -31
  75. package/js/test/test-projects.ts +0 -598
  76. package/js/test/variable.ts +0 -200
  77. package/js/test/warp.test.ts +0 -59
  78. package/js/vm/AGENTS.md +0 -6
  79. package/js/vm/README.md +0 -183
  80. package/js/vm/bindings.test.ts +0 -13
  81. package/js/vm/bindings.ts +0 -5
  82. package/js/vm/compare-operators.test.ts +0 -145
  83. package/js/vm/constants.test.ts +0 -11
  84. package/js/vm/constants.ts +0 -4
  85. package/js/vm/effect-guards.test.ts +0 -68
  86. package/js/vm/effect-guards.ts +0 -44
  87. package/js/vm/factory.test.ts +0 -486
  88. package/js/vm/factory.ts +0 -615
  89. package/js/vm/headless-vm.test.ts +0 -131
  90. package/js/vm/headless-vm.ts +0 -342
  91. package/js/vm/index.test.ts +0 -28
  92. package/js/vm/index.ts +0 -5
  93. package/js/vm/internal-types.ts +0 -32
  94. package/js/vm/json.test.ts +0 -40
  95. package/js/vm/json.ts +0 -273
  96. package/js/vm/normalize.test.ts +0 -48
  97. package/js/vm/normalize.ts +0 -65
  98. package/js/vm/options.test.ts +0 -30
  99. package/js/vm/options.ts +0 -55
  100. package/js/vm/pen-transparency.test.ts +0 -115
  101. package/js/vm/program-wasm.ts +0 -322
  102. package/js/vm/scheduler-render.test.ts +0 -401
  103. package/js/vm/scratch-assets.test.ts +0 -136
  104. package/js/vm/scratch-assets.ts +0 -202
  105. package/js/vm/types.ts +0 -358
  106. package/js/vm/value-guards.test.ts +0 -25
  107. package/js/vm/value-guards.ts +0 -18
  108. package/moon.mod.json +0 -10
  109. package/scripts/preinstall.ts +0 -4
  110. package/src/AGENTS.md +0 -6
  111. package/src/api.mbt +0 -161
  112. package/src/api_aot_commands.mbt +0 -184
  113. package/src/api_effects_json.mbt +0 -72
  114. package/src/api_options.mbt +0 -60
  115. package/src/api_program_wasm.mbt +0 -1647
  116. package/src/api_program_wat.mbt +0 -2206
  117. package/src/api_snapshot_json.mbt +0 -44
  118. package/src/cmd/AGENTS.md +0 -5
  119. package/src/cmd/main/AGENTS.md +0 -5
  120. package/src/cmd/main/main.mbt +0 -29
  121. package/src/cmd/main/moon.pkg +0 -7
  122. package/src/cmd/main/pkg.generated.mbti +0 -13
  123. package/src/json_helpers.mbt +0 -176
  124. package/src/moon.pkg +0 -65
  125. package/src/moonscratch.mbt +0 -3
  126. package/src/moonscratch_wbtest.mbt +0 -40
  127. package/src/parser_sb3.mbt +0 -890
  128. package/src/pkg.generated.mbti +0 -479
  129. package/src/runtime_eval.mbt +0 -2844
  130. package/src/runtime_exec.mbt +0 -3850
  131. package/src/runtime_render.mbt +0 -2550
  132. package/src/runtime_state.mbt +0 -870
  133. package/src/test/AGENTS.md +0 -3
  134. package/src/test/projects/AGENTS.md +0 -6
  135. package/src/test/projects/moon.pkg +0 -4
  136. package/src/test/projects/moonscratch_compat_test.mbt +0 -642
  137. package/src/test/projects/moonscratch_core_test.mbt +0 -1332
  138. package/src/test/projects/moonscratch_runtime_test.mbt +0 -1087
  139. package/src/test/projects/pkg.generated.mbti +0 -13
  140. package/src/test/projects/test_support.mbt +0 -35
  141. package/src/types_effects.mbt +0 -20
  142. package/src/types_error.mbt +0 -4
  143. package/src/types_options.mbt +0 -31
  144. package/src/types_runtime_structs.mbt +0 -254
  145. package/src/types_vm.mbt +0 -109
  146. package/tsconfig.json +0 -29
  147. package/viewer/index.ts +0 -399
  148. package/viewer/vite.d.ts +0 -1
  149. package/viewer/worker.ts +0 -161
  150. package/vite.config.ts +0 -11
@@ -1,131 +0,0 @@
1
- import { describe, expect, test, vi } from 'vite-plus/test'
2
- import { renderWithSVG } from '../render/index.ts'
3
- import {
4
- EXAMPLE_PROJECT,
5
- getStageVariables,
6
- INPUT_EVENT_PROJECT,
7
- stepMany,
8
- TEXT_TO_SPEECH_TRANSLATE_PROJECT,
9
- } from '../test/test-projects.ts'
10
- import { createHeadlessVM, createProgramModuleFromProject } from './factory.ts'
11
- import type { CreateHeadlessVMOptions, ProjectJson } from './types.ts'
12
-
13
- describe('moonscratch/js/vm/headless-vm.ts', () => {
14
- const createVm = (
15
- projectJson: ProjectJson,
16
- overrides: Omit<CreateHeadlessVMOptions, 'program'> = {},
17
- ) => {
18
- const program = createProgramModuleFromProject({ projectJson })
19
- return createHeadlessVM({
20
- program,
21
- ...overrides,
22
- })
23
- }
24
-
25
- test('runs project and normalizes frame values', () => {
26
- const vm = createVm(EXAMPLE_PROJECT, {
27
- initialNowMs: 0,
28
- })
29
- vm.greenFlag()
30
- expect(getStageVariables(vm).var_score).toBe(42)
31
- vm.setTime(17)
32
-
33
- const first = vm.stepFrame()
34
- const second = vm.stepFrame()
35
-
36
- expect(first).toEqual({
37
- activeThreads: 0,
38
- ticks: 0,
39
- ops: 0,
40
- emittedEffects: 0,
41
- stopReason: 'finished',
42
- shouldRender: true,
43
- isInWarp: false,
44
- })
45
- expect(second.stopReason).toBe('finished')
46
- expect(getStageVariables(vm).var_score).toBe(42)
47
- })
48
-
49
- test('renders current scene with renderFrame and renderWithSVG', () => {
50
- const vm = createVm(EXAMPLE_PROJECT)
51
- const frame = vm.renderFrame()
52
- const svg = renderWithSVG(frame)
53
-
54
- expect(frame.width).toBeGreaterThan(0)
55
- expect(frame.height).toBeGreaterThan(0)
56
- expect(frame.pixels.length).toBe(frame.width * frame.height * 4)
57
- expect(svg).toContain('<svg')
58
- expect(svg).toContain('shape-rendering="crispEdges"')
59
- expect(svg).toContain('fill="rgb(255,255,255)"')
60
- expect(svg).toContain('</svg>')
61
- })
62
-
63
- test('detects click and key hats from input state', () => {
64
- const vm = createVm(INPUT_EVENT_PROJECT, {
65
- initialNowMs: 0,
66
- })
67
- vm.greenFlag()
68
- vm.setMouseState({
69
- x: 0,
70
- y: 0,
71
- isDown: true,
72
- })
73
- vm.setMouseTargets({
74
- stage: true,
75
- targets: ['Sprite1'],
76
- })
77
- vm.setKeysDown(['space'])
78
- stepMany(vm, 12)
79
-
80
- expect(getStageVariables(vm).var_stage_click).toBe(1)
81
- expect(getStageVariables(vm).var_sprite_click).toBe(1)
82
- expect(getStageVariables(vm).var_key).toBe(1)
83
- })
84
-
85
- test('handleEffects dispatches handlers and caches translated text for next run', async () => {
86
- const vm = createVm(TEXT_TO_SPEECH_TRANSLATE_PROJECT, {
87
- viewerLanguage: 'ja',
88
- })
89
- const translate = vi.fn(async () => 'こんにちは')
90
- const textToSpeech = vi.fn(async () => undefined)
91
- const effect = vi.fn(async () => undefined)
92
-
93
- vm.greenFlag()
94
- stepMany(vm, 6)
95
-
96
- const handled = await vm.handleEffects({ translate, textToSpeech, effect })
97
- expect(handled.map((item) => item.type)).toEqual([
98
- 'translate_request',
99
- 'text_to_speech',
100
- ])
101
- expect(translate).toHaveBeenCalledTimes(1)
102
- expect(textToSpeech).toHaveBeenCalledTimes(1)
103
- expect(effect).toHaveBeenCalledTimes(2)
104
-
105
- stepMany(vm, 10)
106
- expect(getStageVariables(vm).var_done).toBe(1)
107
- expect(getStageVariables(vm).var_trans).toBe('hello')
108
-
109
- vm.greenFlag()
110
- stepMany(vm, 6)
111
-
112
- const secondRunEffects = vm.takeEffects()
113
- expect(
114
- secondRunEffects.some((item) => item.type === 'translate_request'),
115
- ).toBe(false)
116
- const secondRunTts = secondRunEffects.find(
117
- (item): item is { type: 'text_to_speech'; waitKey: string } =>
118
- item.type === 'text_to_speech' &&
119
- typeof (item as { waitKey?: unknown }).waitKey === 'string',
120
- )
121
- expect(secondRunTts).toBeDefined()
122
- if (!secondRunTts) {
123
- throw new Error('text_to_speech effect was not found in second run')
124
- }
125
- vm.ackTextToSpeech(secondRunTts.waitKey)
126
- stepMany(vm, 10)
127
-
128
- expect(getStageVariables(vm).var_done).toBe(1)
129
- expect(getStageVariables(vm).var_trans).toBe('こんにちは')
130
- })
131
- })
@@ -1,342 +0,0 @@
1
- import { moonscratch } from './bindings.ts'
2
- import { DEFAULT_MAX_FRAMES } from './constants.ts'
3
- import {
4
- isMusicPlayDrumEffect,
5
- isMusicPlayNoteEffect,
6
- isTextToSpeechEffect,
7
- isTranslateRequestEffect,
8
- } from './effect-guards.ts'
9
- import { parseJson } from './json.ts'
10
- import {
11
- cloneTranslateCache,
12
- normalizeLanguage,
13
- normalizeMaxFrames,
14
- normalizeNowMs,
15
- toFrameReport,
16
- } from './normalize.ts'
17
- import type {
18
- EffectHandlers,
19
- FrameReport,
20
- JsonValue,
21
- RenderFrame,
22
- RunReport,
23
- RunUntilIdleOptions,
24
- TranslateCache,
25
- VMEffect,
26
- VMInputEvent,
27
- VMSnapshot,
28
- } from './types.ts'
29
-
30
- type BoundWasmVmHandle = unknown
31
- type BoundMoonscratch = {
32
- vm_set_time?: (vmHandle: BoundWasmVmHandle, nowMs: number) => void
33
- vm_render_frame?: (vmHandle: BoundWasmVmHandle) => unknown
34
- }
35
-
36
- interface HeadlessVMHooks {
37
- afterGreenFlag?: () => void
38
- beforeStepFrame?: () => void
39
- }
40
-
41
- export class HeadlessVM {
42
- private readonly vmHandle: unknown
43
- private readonly hooks: HeadlessVMHooks
44
- private translateCache: TranslateCache = {}
45
-
46
- constructor(vmHandle: unknown, hooks: HeadlessVMHooks = {}) {
47
- this.vmHandle = vmHandle
48
- this.hooks = hooks
49
- }
50
-
51
- get raw(): unknown {
52
- return this.vmHandle
53
- }
54
-
55
- start(): void {
56
- moonscratch.vm_start(this.vmHandle)
57
- }
58
-
59
- greenFlag(): void {
60
- moonscratch.vm_green_flag(this.vmHandle)
61
- this.hooks.afterGreenFlag?.()
62
- }
63
-
64
- stepFrame(): FrameReport {
65
- this.hooks.beforeStepFrame?.()
66
- const raw = moonscratch.vm_step_frame(this.vmHandle)
67
- return toFrameReport(raw)
68
- }
69
-
70
- runFrames(frameCount: number): RunReport {
71
- const normalizedFrameCount = normalizeMaxFrames(frameCount)
72
- let frames = 0
73
- let ticks = 0
74
- let ops = 0
75
- let activeThreads = this.snapshot().activeThreads
76
- while (activeThreads > 0 && frames < normalizedFrameCount) {
77
- const frame = this.stepFrame()
78
- frames += 1
79
- ticks += frame.ticks
80
- ops += frame.ops
81
- activeThreads = frame.activeThreads
82
- }
83
- return {
84
- frames,
85
- ticks,
86
- ops,
87
- activeThreads,
88
- endedBy: 'frame_limit',
89
- }
90
- }
91
-
92
- runUntilIdle(options: RunUntilIdleOptions = {}): RunReport {
93
- const normalizedMaxFrames = normalizeMaxFrames(
94
- options.maxFrames ?? DEFAULT_MAX_FRAMES,
95
- )
96
- let frames = 0
97
- let ticks = 0
98
- let ops = 0
99
- let activeThreads = this.snapshot().activeThreads
100
- while (activeThreads > 0 && frames < normalizedMaxFrames) {
101
- const frame = this.stepFrame()
102
- frames += 1
103
- ticks += frame.ticks
104
- ops += frame.ops
105
- activeThreads = frame.activeThreads
106
- }
107
- return {
108
- frames,
109
- ticks,
110
- ops,
111
- activeThreads,
112
- endedBy: activeThreads === 0 ? 'idle' : 'frame_limit',
113
- }
114
- }
115
-
116
- postIO(device: string, payload: JsonValue): void {
117
- moonscratch.vm_post_io_json(this.vmHandle, device, JSON.stringify(payload))
118
- }
119
-
120
- postIORawJson(device: string, payloadJson: string): void {
121
- moonscratch.vm_post_io_json(this.vmHandle, device, payloadJson)
122
- }
123
-
124
- setAnswer(answer: string): void {
125
- this.dispatchInputEvent({
126
- type: 'answer',
127
- answer,
128
- })
129
- }
130
-
131
- setMouseState(input: { x: number; y: number; isDown?: boolean }): void {
132
- this.dispatchInputEvent({
133
- type: 'mouse',
134
- x: input.x,
135
- y: input.y,
136
- isDown: input.isDown ?? false,
137
- })
138
- }
139
-
140
- setKeysDown(keys: string[]): void {
141
- this.dispatchInputEvent({
142
- type: 'keys_down',
143
- keys,
144
- })
145
- }
146
-
147
- setTouching(touching: Record<string, string[]>): void {
148
- this.dispatchInputEvent({
149
- type: 'touching',
150
- touching,
151
- })
152
- }
153
-
154
- setMouseTargets(input: {
155
- stage?: boolean
156
- target?: string
157
- targets?: string[]
158
- }): void {
159
- this.dispatchInputEvent({
160
- type: 'mouse_targets',
161
- stage: input.stage,
162
- target: input.target,
163
- targets: input.targets,
164
- })
165
- }
166
-
167
- setBackdrop(backdrop: string | string[]): void {
168
- this.dispatchInputEvent({
169
- type: 'backdrop',
170
- backdrop,
171
- })
172
- }
173
-
174
- dispatchInputEvents(events: VMInputEvent[]): void {
175
- for (const event of events) {
176
- this.dispatchInputEvent(event)
177
- }
178
- }
179
-
180
- dispatchInputEvent(event: VMInputEvent): void {
181
- switch (event.type) {
182
- case 'answer':
183
- this.postIO('answer', event.answer)
184
- return
185
- case 'mouse':
186
- this.postIO('mouse', {
187
- x: event.x,
188
- y: event.y,
189
- isDown: event.isDown ?? false,
190
- })
191
- return
192
- case 'keys_down':
193
- this.postIO('keys_down', event.keys)
194
- return
195
- case 'touching':
196
- this.postIO('touching', event.touching)
197
- return
198
- case 'mouse_targets':
199
- this.postIO('mouse_targets', {
200
- stage: event.stage ?? false,
201
- target: event.target ?? '',
202
- targets: event.targets ?? [],
203
- })
204
- return
205
- case 'backdrop':
206
- if (Array.isArray(event.backdrop)) {
207
- this.postIO('backdrop', {
208
- backdrops: event.backdrop,
209
- })
210
- return
211
- }
212
- this.postIO('backdrop', {
213
- backdrop: event.backdrop,
214
- })
215
- return
216
- default: {
217
- const unreachable: never = event
218
- throw new Error(`Unknown input event: ${String(unreachable)}`)
219
- }
220
- }
221
- }
222
-
223
- broadcast(message: string): void {
224
- moonscratch.vm_broadcast(this.vmHandle, message)
225
- }
226
-
227
- stopAll(): void {
228
- moonscratch.vm_stop_all(this.vmHandle)
229
- }
230
-
231
- setTime(nowMs: number): void {
232
- const binding = moonscratch as unknown as BoundMoonscratch
233
- if (typeof binding.vm_set_time === 'function') {
234
- binding.vm_set_time(this.vmHandle, normalizeNowMs(nowMs))
235
- return
236
- }
237
- throw new Error(
238
- 'vm_set_time is unavailable in this build. Please rebuild moonscratch JS bindings.',
239
- )
240
- }
241
-
242
- takeEffects(): VMEffect[] {
243
- const effects = parseJson<unknown>(
244
- moonscratch.vm_take_effects_json(this.vmHandle),
245
- 'vm_take_effects_json',
246
- )
247
- if (!Array.isArray(effects)) {
248
- throw new Error('vm_take_effects_json: expected JSON array')
249
- }
250
- return effects as VMEffect[]
251
- }
252
-
253
- snapshot(): VMSnapshot {
254
- const snapshot = parseJson<unknown>(
255
- moonscratch.vm_snapshot_json(this.vmHandle),
256
- 'vm_snapshot_json',
257
- )
258
- if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) {
259
- throw new Error('vm_snapshot_json: expected JSON object')
260
- }
261
- return snapshot as VMSnapshot
262
- }
263
-
264
- snapshotJson(): string {
265
- return moonscratch.vm_snapshot_json(this.vmHandle)
266
- }
267
-
268
- renderFrame(): RenderFrame {
269
- const binding = moonscratch as unknown as BoundMoonscratch
270
- if (typeof binding.vm_render_frame !== 'function') {
271
- throw new Error(
272
- 'vm_render_frame is unavailable in this build. Please rebuild moonscratch JS bindings.',
273
- )
274
- }
275
- return binding.vm_render_frame(this.vmHandle) as RenderFrame
276
- }
277
-
278
- setViewerLanguage(language: string): void {
279
- this.postIO('viewer_language', normalizeLanguage(language))
280
- }
281
-
282
- setTranslateResult(
283
- words: string,
284
- language: string,
285
- translated: string,
286
- ): string {
287
- const normalizedLanguage = normalizeLanguage(language)
288
- if (!this.translateCache[normalizedLanguage]) {
289
- this.translateCache[normalizedLanguage] = {}
290
- }
291
- this.translateCache[normalizedLanguage][String(words)] = String(translated)
292
- this.syncTranslateCache()
293
- return translated
294
- }
295
-
296
- setTranslateCache(cache: TranslateCache): void {
297
- this.translateCache = cloneTranslateCache(cache)
298
- this.syncTranslateCache()
299
- }
300
-
301
- clearTranslateCache(): void {
302
- this.translateCache = {}
303
- this.syncTranslateCache()
304
- }
305
-
306
- ackTextToSpeech(waitKey: string | null | undefined): void {
307
- if (typeof waitKey !== 'string' || waitKey.length === 0) {
308
- return
309
- }
310
- this.postIO(waitKey, true)
311
- }
312
-
313
- async handleEffects(handlers: EffectHandlers = {}): Promise<VMEffect[]> {
314
- const effects = this.takeEffects()
315
- for (const effect of effects) {
316
- if (isTranslateRequestEffect(effect) && handlers.translate) {
317
- const translated = await handlers.translate(effect)
318
- if (typeof translated === 'string') {
319
- this.setTranslateResult(effect.words, effect.language, translated)
320
- }
321
- } else if (isTextToSpeechEffect(effect)) {
322
- if (handlers.textToSpeech) {
323
- await handlers.textToSpeech(effect)
324
- }
325
- this.ackTextToSpeech(effect.waitKey)
326
- } else if (isMusicPlayNoteEffect(effect) && handlers.musicNote) {
327
- await handlers.musicNote(effect)
328
- } else if (isMusicPlayDrumEffect(effect) && handlers.musicDrum) {
329
- await handlers.musicDrum(effect)
330
- }
331
-
332
- if (handlers.effect) {
333
- await handlers.effect(effect)
334
- }
335
- }
336
- return effects
337
- }
338
-
339
- private syncTranslateCache(): void {
340
- this.postIO('translate_cache', this.translateCache)
341
- }
342
- }
@@ -1,28 +0,0 @@
1
- import { describe, expect, test } from 'vite-plus/test'
2
-
3
- import * as factory from './factory.ts'
4
- import * as headless from './headless-vm.ts'
5
- import * as index from './index.ts'
6
- import * as scratchAssets from './scratch-assets.ts'
7
-
8
- describe('moonscratch/js/vm/index.ts', () => {
9
- test('re-exports vm runtime APIs', () => {
10
- expect(index.createHeadlessVM).toBe(factory.createHeadlessVM)
11
- expect(index.createHeadlessVMFromProject).toBe(
12
- factory.createHeadlessVMFromProject,
13
- )
14
- expect(index.createHeadlessVMWithScratchAssets).toBe(
15
- factory.createHeadlessVMWithScratchAssets,
16
- )
17
- expect(index.createVM).toBe(factory.createVM)
18
- expect(index.createVMFromProject).toBe(factory.createVMFromProject)
19
- expect(index.createVMWithScratchAssets).toBe(
20
- factory.createVMWithScratchAssets,
21
- )
22
- expect(index.HeadlessVM).toBe(headless.HeadlessVM)
23
- expect(index.resolveMissingScratchAssets).toBe(
24
- scratchAssets.resolveMissingScratchAssets,
25
- )
26
- expect(index.moonscratch).toBe(factory.moonscratch)
27
- })
28
- })
package/js/vm/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from './factory.ts'
2
- export * from './headless-vm.ts'
3
- export * from './program-wasm.ts'
4
- export * from './scratch-assets.ts'
5
- export * from './types.ts'
@@ -1,32 +0,0 @@
1
- export interface RawVMOptions {
2
- turbo?: boolean
3
- compatibility_30tps?: boolean
4
- max_clones?: number
5
- deterministic?: boolean
6
- seed?: number
7
- pen_width?: number
8
- pen_height?: number
9
- step_timeout_ticks?: number
10
- }
11
-
12
- export interface RawFrameReport {
13
- active_threads: number
14
- tick_count: number
15
- op_count: number
16
- emitted_effects: number
17
- stop_reason: string
18
- should_render: boolean
19
- is_in_warp: boolean
20
- }
21
-
22
- interface MoonOk<T> {
23
- $tag: 1
24
- _0: T
25
- }
26
-
27
- interface MoonErr<E> {
28
- $tag: 0
29
- _0: E
30
- }
31
-
32
- export type MoonResult<T, E> = MoonOk<T> | MoonErr<E>
@@ -1,40 +0,0 @@
1
- import { describe, expect, test } from 'vite-plus/test'
2
-
3
- import {
4
- parseJson,
5
- toJsonString,
6
- toOptionalJsonString,
7
- unwrapResult,
8
- } from './json.ts'
9
-
10
- describe('moonscratch/js/vm/json.ts', () => {
11
- test('serializes JSON object inputs', () => {
12
- expect(toJsonString({ answer: 42 }, 'projectJson', true)).toBe(
13
- '{"answer":42}',
14
- )
15
- })
16
-
17
- test('rejects empty required JSON strings', () => {
18
- expect(() => toJsonString(' ', 'projectJson', true)).toThrow(
19
- 'projectJson must be a non-empty JSON string or object',
20
- )
21
- })
22
-
23
- test('keeps optional JSON undefined', () => {
24
- expect(toOptionalJsonString(undefined, 'assets')).toBeUndefined()
25
- })
26
-
27
- test('unwraps moon results', () => {
28
- expect(unwrapResult({ $tag: 1, _0: 123 }, 'context')).toBe(123)
29
- expect(() =>
30
- unwrapResult({ $tag: 0, _0: { _0: 'boom' } }, 'context'),
31
- ).toThrow('context: boom')
32
- })
33
-
34
- test('parses json and reports context on parse error', () => {
35
- expect(parseJson<{ value: number }>(' {"value": 1}', 'ctx').value).toBe(1)
36
- expect(() => parseJson('not-json', 'ctx')).toThrow(
37
- 'ctx: failed to parse JSON',
38
- )
39
- })
40
- })