From 3260f0126f63680e2fb8743e3474ffcdc89a2c5b Mon Sep 17 00:00:00 2001
From: BenPaoDeXiaoZhi <121215648+BenPaoDeXiaoZhi@users.noreply.github.com>
Date: Fri, 17 Oct 2025 07:26:23 +0800
Subject: [PATCH 1/4] Fix typo in comment for startHatsWithParams
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
改了一个错误的拼写(whit)…
---
src/engine/runtime.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/engine/runtime.js b/src/engine/runtime.js
index 959a6781..2858da87 100644
--- a/src/engine/runtime.js
+++ b/src/engine/runtime.js
@@ -2714,7 +2714,7 @@ class Runtime extends EventEmitter {
/**
* CCW
startHatsWithParams is only used in block utility for extension,
- WhitExtraMsg means skip field check when start a hat block.
+ WithExtraMsg means skip field check when start a hat block.
define here is only for debug
* @param {!string} requestedHatOpcode Opcode of hats to start.
* @param {object} data Optionally, contains fields to match on the hat and parameters to ccw_hat_parameter.
From e3ba8eaac40068eea88452b44c97f9476783e2fa Mon Sep 17 00:00:00 2001
From: BenPaoDeXiaoZhi
Date: Sat, 16 May 2026 12:12:04 +0800
Subject: [PATCH 2/4] fix: Remove duplicated method remove a duplicated
"_convertLabelForScratchBlocks" method in "runtime.js"
---
src/engine/runtime.js | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/src/engine/runtime.js b/src/engine/runtime.js
index 2858da87..a552ac26 100644
--- a/src/engine/runtime.js
+++ b/src/engine/runtime.js
@@ -602,6 +602,11 @@ class Runtime extends EventEmitter {
* Total number of finished or errored scratch-storage load() requests since the runtime was created or cleared.
*/
this.finishedAssetRequests = 0;
+
+ /**
+ * @type {ScratchStorage}
+ */
+ this.storage = {};
}
/**
@@ -1895,19 +1900,6 @@ class Runtime extends EventEmitter {
};
}
- /**
- * Generate a label between blocks categories or sub-categories.
- * @param {ExtensionBlockMetadata} blockInfo - the block to convert
- * @returns {ConvertedBlockInfo} - the converted & original block information
- * @private
- */
- _convertLabelForScratchBlocks (blockInfo) {
- return {
- info: blockInfo,
- xml: ``
- };
- }
-
/**
* Convert a button for scratch-blocks. A button has no opcode but specifies a callback name in the `func` field.
* @param {ExtensionBlockMetadata} buttonInfo - the button to convert
From c8c868fccd49bb81da98d2c2a35edd3a551dac01 Mon Sep 17 00:00:00 2001
From: BenPaoDeXiaoZhi
Date: Sat, 16 May 2026 12:49:20 +0800
Subject: [PATCH 3/4] feat: use sb3 file instead of project id use file to
solve the ccw server-side encryption
---
src/playground/benchmark.js | 66 ++++++++++++++++++++++---------------
src/playground/index.html | 2 +-
2 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/src/playground/benchmark.js b/src/playground/benchmark.js
index 85da6b49..e9c37356 100644
--- a/src/playground/benchmark.js
+++ b/src/playground/benchmark.js
@@ -58,10 +58,10 @@ const PROJECT_SERVER = 'https://cdn.projects.scratch.mit.edu/';
const SLOW = .1;
-const projectInput = document.querySelector('#project-id');
-if (location.hash) {
- projectInput.value = location.hash.substring(1);
-}
+/**
+ * @type {HTMLInputElement}
+ */
+const projectInput = document.querySelector('#project');
const enableCompiler = new URLSearchParams(location.search).get('compiler') === 'true';
const compilerInput = document.querySelector('#enable-compiler');
@@ -69,9 +69,10 @@ compilerInput.checked = enableCompiler;
document.querySelector('.run')
.addEventListener('click', () => {
- const params = new URLSearchParams(location.search);
- params.set('compiler', compilerInput.checked);
- location.href = `${location.pathname}?${params}#${projectInput.value}`;
+ window.profiler.run();
+ // const params = new URLSearchParams(location.search);
+ // params.set('compiler', compilerInput.checked);
+ // location.href = `${location.pathname}?${params}#${projectInput.value}`;
}, false);
const setShareLink = function (json) {
@@ -81,7 +82,7 @@ const setShareLink = function (json) {
.href = `suite.html`;
};
-const getProjectMetadata = async projectId => {
+const _getProjectMetadata = async projectId => {
const response = await fetch(`https://trampoline.turbowarp.org/api/projects/${projectId}`);
if (response.status === 404) {
throw new Error('The project is unshared or does not exist');
@@ -93,10 +94,15 @@ const getProjectMetadata = async projectId => {
return json;
};
-const getProjectData = async projectId => {
- const metadata = await getProjectMetadata(projectId);
- const token = metadata.project_token;
- const response = await fetch(`https://projects.scratch.mit.edu/${projectId}?token=${token}`);
+const _getProjectData = async () => {
+ // const metadata = await getProjectMetadata(projectId);
+ // const token = metadata.project_token;
+ // const response = await fetch(`https://projects.scratch.mit.edu/${projectId}?token=${token}`);
+ // if (!response.ok) {
+ // throw new Error(`HTTP error ${response.status} fetching project data`);
+ // }
+ // eslint-disable-next-line no-alert, quotes
+ const response = await fetch(prompt("输入m.ccw.site sb3") ?? "");
if (!response.ok) {
throw new Error(`HTTP error ${response.status} fetching project data`);
}
@@ -104,13 +110,18 @@ const getProjectData = async projectId => {
return data;
};
-const loadProject = function () {
- let id = location.hash.substring(1).split(',')[0];
- if (id.length < 1 || !isFinite(id)) {
- id = projectInput.value;
- }
- getProjectData(id).then(data => Scratch.vm.loadProject(data));
- return id;
+const loadProject = function (vm) {
+ // let id = location.hash.substring(1).split(',')[0];
+ // if (id.length < 1 || !isFinite(id)) {
+ // id = projectInput.value;
+ // }
+ // getProjectData(id)
+ new Promise(resolve => {
+ if (projectInput.files[0]){
+ projectInput.files[0].arrayBuffer().then(dat => resolve(dat));
+ }
+ }).then(data => vm.loadProject(data));
+ return '';
};
/**
@@ -539,7 +550,7 @@ class ProfilerRun {
}
run () {
- this.projectId = loadProject();
+ this.projectId = loadProject(this.vm);
window.parent.postMessage({
type: 'BENCH_MESSAGE_LOADING'
@@ -671,11 +682,12 @@ const runBenchmark = function () {
maxRecordedTime = Number(split[2] || '0') || 6000;
}
- new ProfilerRun({
+ window.profiler = new ProfilerRun({
vm,
warmUpTime,
maxRecordedTime
- }).run();
+ });
+ window.profiler.run();
// Instantiate the renderer and connect it to the VM.
const canvas = document.getElementById('scratch-stage');
@@ -695,7 +707,7 @@ const runBenchmark = function () {
canvasWidth: rect.width,
canvasHeight: rect.height
};
- Scratch.vm.postIOData('mouse', coordinates);
+ vm.postIOData('mouse', coordinates);
});
canvas.addEventListener('mousedown', e => {
const rect = canvas.getBoundingClientRect();
@@ -706,7 +718,7 @@ const runBenchmark = function () {
canvasWidth: rect.width,
canvasHeight: rect.height
};
- Scratch.vm.postIOData('mouse', data);
+ vm.postIOData('mouse', data);
e.preventDefault();
});
canvas.addEventListener('mouseup', e => {
@@ -718,7 +730,7 @@ const runBenchmark = function () {
canvasWidth: rect.width,
canvasHeight: rect.height
};
- Scratch.vm.postIOData('mouse', data);
+ vm.postIOData('mouse', data);
e.preventDefault();
});
@@ -728,7 +740,7 @@ const runBenchmark = function () {
if (e.target !== document && e.target !== document.body) {
return;
}
- Scratch.vm.postIOData('keyboard', {
+ vm.postIOData('keyboard', {
keyCode: e.keyCode,
isDown: true
});
@@ -737,7 +749,7 @@ const runBenchmark = function () {
document.addEventListener('keyup', e => {
// Always capture up events,
// even those that have switched to other targets.
- Scratch.vm.postIOData('keyboard', {
+ vm.postIOData('keyboard', {
keyCode: e.keyCode,
isDown: false
});
diff --git a/src/playground/index.html b/src/playground/index.html
index 43b3d423..69b84d13 100644
--- a/src/playground/index.html
+++ b/src/playground/index.html
@@ -34,7 +34,7 @@ Scratch VM Benchmark
The benchmark is not very useful when the compiler is enabled.
-
+