让 Scratch真正成为生产力工具
面板任意停靠,几个角色的工作区同时打开,积木在角色之间直接拖;一个作品好几个世界,两万块积木照样丝滑。
Scratch 的界面是给「一个小作品」设计的
一张舞台、一列角色、一个工作区,够用而且好懂。但当作品长到几十个角色、几万块积木、要分好几关的时候,这套界面会开始拦着你。
可以同时打开好几个角色的工作区、造型区、声音区,并且能把积木从一个角色的工作区直接拖到另一个角色的工作区里。积木栏全局只有一个,独立成面板。
面板即窗口
整个界面是一套完整的停靠系统,不是固定三栏。任意面板都能拖成标签、拖进任何一格、拖出来变成浮动窗口。点下面的布局切一切。
每个人都可以有不同的编辑器
配色、圆角、字体、背景图,连积木的凸起和圆角都能改。在主题工作室里拖一下,整个编辑器立刻跟着变、自动保存;导出成一个 JSON 文件,朋友装上就是同一套。
#2D8CFF1.02 格无改一处,全跟着
八个核心色推出整套配色;圆角、阴影、毛玻璃、动效各一个滑杆,即时生效。改内置主题会自动另存一套。
积木也是主题的一部分
类别色、凸起、圆角、帽子、输入槽、文字大小都能调,工作区里的积木原地换形,不重建。
一个文件就能分享
导出的 JSON 连背景图一起带走,导入即用。最多存三十套,右键卡片改名、导出、删除。
角色栏是个文件管理器
角色可以分文件夹,每个角色下面挂着它自己的积木页、造型、声音三棵树。右键新建,拖着走,顶上有搜索,像整理项目一样整理作品。
- 1右键就能建:文件夹、子文件夹、积木页、模块。改名、创建副本、移进移出文件夹都在同一个菜单里。
- 2什么都能拖:角色拖进文件夹,积木页拖去另一个角色,造型和声音也各自能分文件夹。
- 3模块是只有代码、不上舞台的角色,放全局积木和公共逻辑。
- 4存出来还是 .sb3,文件夹和页只是作品里多记了几行,别的编辑器照常打开。
一个角色,很多页积木
脚本不用全堆在一个工作区里。按功能分页:跳跃一页、攻击一页、受伤一页,工作区标题跟着页走,更像在游戏引擎里改一个对象的几个脚本文件。页能拖去别的角色,也能分文件夹,和造型、声音一个待遇。
并排打开
右键「在新面板打开」,同一个角色的两页并排,脚本在页之间直接拖,拖的时候另一边显示影子。
Ctrl + P 快速打开
所有角色的所有页一张表,打几个字就跳过去,最近打开的排前面。
页只是视图
脚本始终属于这个角色,运行时和原来完全一样;存出来还是普通的 .sb3,原版打开只是看不到分页。删一页会连里面的脚本一起删,先问再删。
Ctrl+F,整个作品里找一块积木
搜积木上的字、角色、积木页、造型、声音、变量、注释,所有场景所有角色一起翻,拼音、首字母也认。结果就是真的积木,命中的字标在积木上,回车直接跳过去。
一个键,从哪儿都能开
Ctrl+F 或顶栏的放大镜。搜所有场景、所有角色的积木、角色、积木页、造型、声音、变量、注释。
拼音也行
yidong、yd、混着数字都找得到,多音字按词认(重复是 chongfu,角色是 juese)。
结果就是积木
真积木渲染,命中的字标在积木上;同一角色里一样的积木折成一条,回车跳过去,黄框闪三下。
按一下中键,把一句话变成一串积木
在工作区空白处按鼠标中键,输入框就落在指针上。打积木上的字、拼音、只打开头都认得;一句话能拼出一整串,肚子里的、「否则」那一支都填好。回车放到按下的位置,或者按住结果直接拖进工作区。
打字就行,拼音也认
yidong 10 bu 是移动 10 步,「重复」是重复执行,「左转」是向左旋转。变量、列表、自制积木、装了的扩展积木,打名字一样出得来。
一句话,一整串
口语数字认得(五十是 50、半是 0.5);「如果碰到鼠标指针那么说你好否则说再见」两个肚子都填好,「等于」会变成 = 积木,变量是真的变量积木。
候选是真积木
点结果里的哪一块,下面就是它的候选,按数字换。回车放到按中键的位置,或者按住结果直接拖 —— 从抓住的那一点接管,不会跳。
几个角色的工作区同时打开,积木直接拖过去
同一页可以开好几个积木工作区,它们靠事件互相重放保持一致。从 A 角色的工作区把积木拖进 B 角色的工作区,拖动时另一边显示跟随指针的影子。
- 1积木栏全局只有一个,是能拖到屏幕任何地方的独立面板,不再假设它贴着工作区左边。
- 2造型区、声音区也能开多个,对照着改两个角色的造型。
- 3悬停铺开:鼠标放上去,长积木完整铺出来,不会被面板边缘截断。
一个作品,好几个世界
原来菜单、第一关、Boss 战、结算全挤在一张舞台里,每个角色都得自己判断「我这一关该不该出现」。场景把这件事拆开:每个场景是一个完整的小作品,自己的舞台、角色、脚本、造型、声音、变量。
卸载
不在内存里。纹理和解码后的音频都放掉了,存盘一个字节都不丢。
休眠
装着但没在跑。送给它的广播不会丢,排队等它下次开始。
在场 / 后台
在跑。可以在画面上,也可以在后台先把下一关算着,前台放过场动画。
全作品的造型和声音,一张表
它不是新的存储层,而是给已经按 md5 存着的素材一个作品级身份。树 / 网格 / 详情三栏,一个条目,多个用法。
角色1、Pico、小兵 都在用它。改动要影响哪些?
共用与分叉的规则是明确的
复制角色、复制场景、把造型拖给别的角色,共用同一份;复制造型、「改为独立副本」,独立一份。
改之前问一次
在画板里改一个被多处共用的造型,会问:全部更新,还是只改这个角色。
未被引用的也保存
「未使用」筛选能看到并清理,造型条、声音条、角色列表上有角标,一眼看出共用了 N 处。
积木栏是平台能力,不是扩展的许可
折叠、可扩展参数、自制积木的形状,这些都是编辑器给的,第三方扩展一句声明不写也一样能用。下面三个都能点。这里的每一块积木都是 gandi-blocks 渲染出来的。
可扩展参数 expandable
积木上那对 ➕➖。一块积木带几个参数由用户说了算,扩展在 getInfo() 里写一段 expandable 就有了,不用碰 Blockly。
命令块、报告块、布尔块、C 型积木、带参 hat 都支持。
可折叠分组 fold
分类 → 组 → 组里的小节,三级。任何一条标题都能点、能收;扩展写的 |fold-closed 只决定初始状态。
折叠是用户的权利,不是扩展的许可。
自制积木 procedures
三种形状:指令 / 报告 / 布尔。参数可以是下拉菜单,不只是输入框。改形状会自动重建所有调用块,并把用户插进去的积木搬过去。
表单是纯 React 的对话框,不是在对话框里再开一个 Blockly 工作区。
积木栏是你自己的
分类顺序自己排,用不上的藏起来,最常用的几块星标收进「常用」。靠左、靠右、网格三种摆法,改了立刻生效,跟着你的账号走。
不是 SVG DOM,是 Canvas 2D
旧编辑器撞的墙和积木编辑器是同一堵:几千个 <text> 一动就要重排。所以这里场景图是不可变的、命中测试自己在文档坐标里做、视口就是一个矩阵。无限画布,平移缩放是矩阵乘法。
造型就是帧
时间轴上每一格是一个造型。洋葱皮把前后帧淡色叠上来,按旋转中心对齐;补间在帧与帧之间自动插值。画出来的曲线和播放实际用的曲线逐点相同。
不是「剪一段波形」,是一套完整的音频工作台
四种形态:波形 / 频谱 / 编谱 / 音色。多轨编排、钢琴卷帘、混音台、合成器与 SoundFont;编好的谱子能变成积木,积木也能读回谱子。
按它真正被显示的尺寸测量和绘制
4:3、16:9 或自定义尺寸;三种动态尺寸模式:固定 / 宽度跟面板长 / 高度跟面板长。做宽银幕或竖屏不用改积木。
- 1页内全屏:在页面内部铺满窗口,不问浏览器要全屏,所以舞台不会被拉糊。
- 2切换场景时交叉淡入淡出,按缓冲尺寸抓帧。
- 3变量监视器、提问框层级固定,扩展加的覆盖层不会压住它们。
代码挂在作品上,跟着 .sb3 一起走
JavaScript / Python / JSON / GLSL,Monaco 编辑器。终端接管 runtime.logSystem 六个口子,扩展的 console.log 在这里看得到,出错会自己弹出来。
- ⌘Quick Open,按名字跳文件。
- >_xterm 终端,扩展日志不再散落在浏览器控制台里。
贴一个集市页面地址就能装
背后走 CCW 的公开接口取真实 js 地址;另有 ScratchX 兼容层。装进 VM 之后,再出现在积木栏里。
Scratch.gandi:给扩展的宿主接口
想在舞台上放 <iframe> 的扩展,过去只能满页面遍历去认哪个 canvas 是舞台,再猜它的父节点插进去;每换一次布局这套猜法就断一次。现在直接要一层:画布不动、监视器不动,你也不用知道编辑器的 DOM 长什么样。
| 选项 | 默认 | 含义 |
|---|---|---|
| scale | false | 内部坐标系固定成舞台原生尺寸,缩放交给编辑器 |
| interactive | false | 接收鼠标事件(会挡住那块舞台,所以默认穿透) |
| name | 无 | 写到 data-overlay 上,方便排查 |
编辑器没提供舞台服务时(无头播放器、单测、别家编辑器),这几个方法返回 null 并且只抱怨一次,不抛异常。
// 问功能本身,能力探测不会随版本失效 if (typeof Scratch.gandi?.stage?.addOverlay === 'function') { const layer = Scratch.gandi.stage.addOverlay({ scale: true, interactive: true, name: 'my-hud' }); layer.appendChild(myIframe); } // 折叠 + 可扩展参数,在 getInfo() 里声明就有 blocks: [ '---基础', { opcode: 'foo', /* … */ }, '---高级用法|fold-closed', { opcode: 'switchToWithParams', text: '切换到场景 [SCENE],参数 [EXPAND]', expandable: { slot: [ { name: 'KEY', type: ArgumentType.STRING, defaultValue: '关卡' }, { text: '=' }, { name: 'VALUE', type: ArgumentType.STRING, defaultValue: '1' } ], between: ',', min: 1, max: 10 } } ]
两种插件,同一套契约 {id, name, setup}。内置插件跟编辑器一起构建发版,设置里一个开关;外部插件填一个网址装进来。Patcher 提供 before / after 钩子并支持 unpatch,多个扩展 patch 同一个方法不再层层套娃。
编辑几万块积木不卡,运行一万个克隆体不掉帧
这是投入最大的一块。所有数字都是同一台机器、同一套脚本、前后两棵源码树背靠背测出来的,方法和复现步骤在仓库里的两份报告里。
几万块积木的工作区
真实项目,单个角色 19899 个积木 · 帧时间中位数一万个克隆体,各有各的线程
全部绘制 · scratch-vm 编译器 + scratch-render 批量绘制积木编辑器 gandi-blocks
- 视口裁剪:看不见的脚本从文档里移走,不是 display:none,Blink 对隐藏的 SVG 子树照样跑文字排版
- 文字层:字段的文字画在工作区共享的一层上,不再是每个字段一个 <text>
- 平移缩放跑在合成层上,手势期间不重排;文字测量用 canvas,不触发布局刷新
- 连接点数据库早退:没动的连接点不再做两次 O(n) splice
运行时 scratch-vm · scratch-render
- 数值变量槽:只写过数字的变量挪进 V8 会拆箱的小对象
- 自制积木内联、常量参数特化、常量折叠,语义是 Scratch 的不是 JS 的
- startHats 按 key 直接找线程,线程表增量维护
- 批量绘制:一万个同造型克隆体变成一次 draw call
打开 47 MB 的作品
- 5 个角色、1941 个 SVG 造型、73 段音频共 47 分钟、25600 个积木
- 从选文件到能干活:50 秒以上 → 4.7 ~ 5.6 秒
- 关键是造型等到有人要看它再变成图片:一个角色同时只穿一件造型,另外 1935 件从头到尾没人看
诚实的一处退步
- 三千个克隆体的生成从 89 ms 变成 111 ms:变量提升成槽要定义访问器
- 一次性成本,之后每帧省 0.68 ms,二十帧就回本
- 到一万个克隆体时生成反而快 2.2 倍,因为原来那个二次方的 hat 扫描在主导
作品卡在哪,录几秒就知道
顶栏「更多」里的「调试」,默认以悬浮窗打开。点「录制」让作品跑几秒,概览页直接给结论:哪块积木最费时、谁在广播风暴、克隆体是不是爆了。每条都是人话加建议,能一键跳到积木。
{分数} > 100启用断点,直接设在积木上
- Shift + 点击积木,或右键「设断点」
- 条件断点写法就是
{分数} > 100;还有每 N 次停、日志点(只打印不停) - 变量被改时停、广播时停、克隆时停
- 暂停 / 继续 / 单步 / 跳过 / 跳出,F8 F9 F10;暂停时看调用栈,变量直接改
帧 · 线程 · 积木 · 事件
- 帧柱状图,点一根看那一帧里发生了什么
- 线程表把克隆体合并起来,按泳道排,谁在跑一目了然
- 积木按占比排;工作区里也按耗时描边发光,颜色和强度可调
- 事件表记广播、克隆的次数和来源
监视 · 渲染 · 内存
- 变量和列表是活的,能直接改;二十万项的列表虚拟滚动不卡,能搜索、跳到第 N 项、置顶
- 渲染页:超大位图造型标红、在用的特效、克隆体数
- 内存页:JS 堆内存走势、素材大小、最大的列表
录下来,改完再比
- .gtrace 录制文件能导出、导入
- 「记为基线」,改完作品再录一段,直接比快慢
- 舞台角上的帧率仪表:帧率、每帧毫秒、线程数、120 帧小柱图
- 正在运行的积木整块蓝光加小箭头,停下的那块黄边
自动限流,作品照常能停;日志里指出是哪段脚本。
打开浏览器就能用
不用装任何东西。打开下面的地址,拖一个 .sb3 进去,或者从零开始。源码整理好之后会开源,敬请期待。