Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ddc7ff3
:wrench: chore(vm): convret util to be ts
SimonShiki May 10, 2026
9c129b1
:wrench: chore(vm): migrate some engine stuffs to typescript
SimonShiki May 10, 2026
b9655b8
:bug: fix(vm): correct reference
SimonShiki May 10, 2026
f2151c1
:wrench: chore(vm): migrate engine/variable
SimonShiki May 10, 2026
1c6cdcd
:wrench: chore(vm): migrate engine/adapter
SimonShiki May 10, 2026
e456e21
:fire: chore(vm): remove mutation adapter
SimonShiki May 10, 2026
30accb3
:wrench: chore(vm): migrate profiler
SimonShiki May 10, 2026
0d5b4a1
:rewind: revert: ":fire: chore(vm): remove mutation adapter"
SimonShiki May 10, 2026
a50ef86
:wrench: chore(vm): migrate mutation adapter
SimonShiki May 10, 2026
6381752
:bug: fix(vm): dts generation strategy
SimonShiki May 10, 2026
8e9c619
:wrench: chore(vm): migrate some io adapters
SimonShiki May 10, 2026
13c08d1
:wrench: chore(vm): migrate dispatchers
SimonShiki May 10, 2026
4686765
:bug: fix(vm): tests except worker-related issues
SimonShiki May 10, 2026
287d983
:art: chore(vm): fix lint
SimonShiki May 10, 2026
d3e5f90
:art: chore(vm): fix lint
SimonShiki May 10, 2026
00508b1
:bug: fix(vm): run ts worker in same process
SimonShiki May 10, 2026
37f73ca
:wrench: chore(vm): migrate scratch3_control category
SimonShiki May 11, 2026
b5a85fb
:wrench: chore(vm): migrate some categories
SimonShiki May 11, 2026
1032c03
:wrench: chore(vm): migrate left categories
SimonShiki May 11, 2026
331a33a
:wrench: chore(vm): migrate sprite.js
SimonShiki May 11, 2026
016e831
:wrench: chore(vm): migrate thread.js
SimonShiki May 11, 2026
b799478
:wrench: chore(block): migrate block-utility
SimonShiki May 11, 2026
80c5bf3
:art: chore(vm): lint fix
SimonShiki May 11, 2026
e19802d
:bug: fix: build and tests
SimonShiki May 11, 2026
e7c2ff9
:bug: fix(vm): missing util mock
SimonShiki May 11, 2026
c6050e7
:wrench: chore(vm): migrate sequencer
SimonShiki May 11, 2026
f8f34a1
:beers: fix(vm): accidentally change clone logic
SimonShiki May 11, 2026
61d5dd0
:bug: fix(vm): inconsistent behavior
SimonShiki May 11, 2026
47baeb8
:wrench: chore(vm): export schema
SimonShiki May 11, 2026
c57f136
:wrench: chore(vm): fix build
SimonShiki May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/block/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,11 @@ export * as callbackRegistry from './callback_registry';
export * as constants from './constants';
export * as scratchBlocksUtils from './utils';
export type * as proceduresSerializer from './serialization/procedures';
export type * as variableModel from './variable_model';

export {reportValue} from './report_value';
export {Colours} from './theme';
export {BlockDragEnd} from './events/block_drag_end';
export * as Theme from './theme';
export {glowStack} from './glow';

Expand Down
5 changes: 5 additions & 0 deletions packages/gui/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,8 @@ declare module 'react-tabs' {
export const Tab: React.ComponentType<TabProps>;
export const TabPanel: React.ComponentType<CommonProps>;
}

/**
* Compile-time injected clipcc global metadata
*/
declare const clipcc: { VERSION?: string };
2 changes: 1 addition & 1 deletion packages/render/src/RenderWebGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,7 @@ class RenderWebGL extends EventEmitter {
* Return drawable pixel data and color at a given scratch position
* @param {int} scratchX The scratch x coordinate of the picking location.
* @param {int} scratchY The scratch y coordinate of the picking location.
* @returns {?ColorExtraction} Data about the picked color
* @returns Data about the picked color
*/
extractColorInScratchCoordinate (scratchX, scratchY) {
this._doExitDrawRegion();
Expand Down
6 changes: 4 additions & 2 deletions packages/vm/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
const clipccConfig = require('eslint-config-clipcc');
const clipccNode = require('eslint-config-clipcc/node');
const clipccES6 = require('eslint-config-clipcc/es6');
const clipccTS = require('eslint-config-clipcc/ts');
const globals = require('globals');

module.exports = [
...clipccConfig,
...clipccNode,
...clipccES6,
...clipccTS,
{
files: ['src/**/*.js'],
files: ['src/**/*.{js,ts}'],
languageOptions: {
globals: {
...globals.browser
Expand All @@ -28,7 +30,7 @@ module.exports = [
}
},
{
files: ['test/**/*.js'],
files: ['test/**/*.{js,ts}'],
languageOptions: {
globals: {
...globals.browser,
Expand Down
9 changes: 6 additions & 3 deletions packages/vm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
},
"exports": {
"types": "./dist/types/index.d.ts",
"webpack": "./src/index.js",
"webpack": "./src/index.ts",
"node": "./dist/node/scratch-vm.js",
"browser": "./dist/web/scratch-vm.min.js",
"default": "./src/index.js"
"default": "./src/index.ts"
},
"scripts": {
"build:types": "tsc --project ./tsconfig.dts.json",
"build:types": "tsc",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test types should also get resolved if they use ts.

"build": "pnpm run build:types && webpack --progress --color --bail",
"coverage": "jest --silent --coverage",
"i18n:src": "mkdirp translations/core && format-message extract --out-file translations/core/en.json src/extensions/**/index.js",
Expand Down Expand Up @@ -57,6 +57,8 @@
"@babel/eslint-parser": "7.28.6",
"@babel/preset-env": "7.29.2",
"@babel/preset-typescript": "^7.28.5",
"@types/atob": "^2.1.4",
"@types/btoa": "^1.2.5",
"@types/fastestsmallesttextencoderdecoder": "^1.0.2",
"@types/node": "^25.5.2",
"adm-zip": "0.4.11",
Expand All @@ -73,6 +75,7 @@
"clipcc-svg-renderer": "workspace:~",
"codingclip-worker-loader": "^3.0.10",
"copy-webpack-plugin": "^14.0.0",
"domhandler": "^5.0.3",
"eslint": "^9.39.2",
"eslint-config-clipcc": "workspace:*",
"format-message-cli": "6.2.4",
Expand Down
21 changes: 21 additions & 0 deletions packages/vm/src/blocks/category_prototype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type BlockUtility from '../engine/block-utility';
import type {HatMetadata, MonitorBlockInfo} from '../engine/runtime';

export type BlockArgs = {
[argName: string]: any;
mutation?: Record<string, any>;
}

export type BlockFunction = (args: BlockArgs, util: BlockUtility) => any;

export interface CategoryPrototype {
/**
* Retrieve the block primitives implemented by this package.
* @returns Mapping of opcode to Function.
*/
getPrimitives(): Record<string, BlockFunction>;
getHats?(): Record<string, HatMetadata>;
getMonitored?(): Record<string, MonitorBlockInfo>;
getOrders?(): Record<string, (string | {execute: string})[]>;
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import Cast from '../util/cast.js';
import Cast from '../util/cast';
import type {BlockArgs, CategoryPrototype} from './category_prototype';
import type Runtime from '../engine/runtime';
import type RenderedTarget from '../sprites/rendered-target';
import type BlockUtility from '../engine/block-utility';
import type {BaseExecutionContext} from '../engine/block-utility';

interface ControlExecutionContext extends BaseExecutionContext {
loopCounter?: number;
index?: number;
}

class Scratch3ControlBlocks {
constructor (runtime) {
class Scratch3ControlBlocks implements CategoryPrototype {
/**
* The "counter" block value. For compatibility with 2.0.
*/
private _counter = 0;
constructor (
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;

/**
* The "counter" block value. For compatibility with 2.0.
* @type {number}
*/
this._counter = 0;

public runtime: Runtime
) {
this.runtime.on('RUNTIME_DISPOSED', this.clearCounter.bind(this));
}

/**
* Retrieve the block primitives implemented by this package.
* @returns {Record<string, Function>} Mapping of opcode to Function.
* @returns Mapping of opcode to Function.
*/
getPrimitives () {
return {
Expand Down Expand Up @@ -50,7 +57,7 @@ class Scratch3ControlBlocks {
};
}

repeat (args, util) {
repeat (args: BlockArgs, util: BlockUtility) {
const times = Math.round(Cast.toNumber(args.TIMES));
// Initialize loop
if (typeof util.stackFrame.loopCounter === 'undefined') {
Expand All @@ -60,56 +67,56 @@ class Scratch3ControlBlocks {
// When the branch finishes, `repeat` will be executed again and
// the second branch will be taken, yielding for the rest of the frame.
// Decrease counter
util.stackFrame.loopCounter--;
(util.stackFrame as ControlExecutionContext).loopCounter!--;
// If we still have some left, start the branch.
if (util.stackFrame.loopCounter >= 0) {
if ((util.stackFrame as ControlExecutionContext).loopCounter! >= 0) {
util.startBranch(1, true);
}
}

repeatUntil (args, util) {
repeatUntil (args: BlockArgs, util: BlockUtility) {
const condition = Cast.toBoolean(args.CONDITION);
// If the condition is false (repeat UNTIL), start the branch.
if (!condition) {
util.startBranch(1, true);
}
}

repeatWhile (args, util) {
repeatWhile (args: BlockArgs, util: BlockUtility) {
const condition = Cast.toBoolean(args.CONDITION);
// If the condition is true (repeat WHILE), start the branch.
if (condition) {
util.startBranch(1, true);
}
}

forEach (args, util) {
forEach (args: BlockArgs, util: BlockUtility) {
const variable = util.target.lookupOrCreateVariable(
args.VARIABLE.id, args.VARIABLE.name);

if (typeof util.stackFrame.index === 'undefined') {
util.stackFrame.index = 0;
}

if (util.stackFrame.index < Number(args.VALUE)) {
util.stackFrame.index++;
variable.value = util.stackFrame.index;
if ((util.stackFrame as ControlExecutionContext).index! < Number(args.VALUE)) {
(util.stackFrame as ControlExecutionContext).index!++;
variable.value = (util.stackFrame as ControlExecutionContext).index;
util.startBranch(1, true);
}
}

waitUntil (args, util) {
waitUntil (args: BlockArgs, util: BlockUtility) {
const condition = Cast.toBoolean(args.CONDITION);
if (!condition) {
util.yield();
}
}

forever (args, util) {
forever (args: BlockArgs, util: BlockUtility) {
util.startBranch(1, true);
}

wait (args, util) {
wait (args: BlockArgs, util: BlockUtility) {
if (util.stackTimerNeedsInit()) {
const duration = Math.max(0, 1000 * Cast.toNumber(args.DURATION));

Expand All @@ -121,14 +128,14 @@ class Scratch3ControlBlocks {
}
}

if (args, util) {
if (args: BlockArgs, util: BlockUtility) {
const condition = Cast.toBoolean(args.CONDITION);
if (condition) {
util.startBranch(1, false);
}
}

ifElse (args, util) {
ifElse (args: BlockArgs, util: BlockUtility) {
const condition = Cast.toBoolean(args.CONDITION);
if (condition) {
util.startBranch(1, false);
Expand All @@ -137,7 +144,7 @@ class Scratch3ControlBlocks {
}
}

stop (args, util) {
stop (args: BlockArgs, util: BlockUtility) {
const option = args.STOP_OPTION;
if (option === 'all') {
util.stopAll();
Expand All @@ -149,12 +156,12 @@ class Scratch3ControlBlocks {
}
}

createClone (args, util) {
createClone (args: BlockArgs, util: BlockUtility) {
// Cast argument to string
args.CLONE_OPTION = Cast.toString(args.CLONE_OPTION);

// Set clone target
let cloneTarget;
let cloneTarget: RenderedTarget | undefined;
if (args.CLONE_OPTION === '_myself_') {
cloneTarget = util.target;
} else {
Expand All @@ -174,7 +181,7 @@ class Scratch3ControlBlocks {
}
}

deleteClone (args, util) {
deleteClone (args: BlockArgs, util: BlockUtility) {
if (util.target.isOriginal) return;
this.runtime.disposeTarget(util.target);
this.runtime.stopForTarget(util.target);
Expand All @@ -192,7 +199,7 @@ class Scratch3ControlBlocks {
this._counter++;
}

allAtOnce (args, util) {
allAtOnce (args: BlockArgs, util: BlockUtility) {
// Since the "all at once" block is implemented for compatiblity with
// Scratch 2.0 projects, it behaves the same way it did in 2.0, which
// is to simply run the contained script (like "if 1 = 1").
Expand Down
Loading
Loading