{"id":13583627,"url":"https://github.com/Steve-xmh/scratch-script","last_synced_at":"2025-04-06T21:32:41.266Z","repository":{"id":39050946,"uuid":"260463293","full_name":"Steve-xmh/scratch-script","owner":"Steve-xmh","description":"A toolchain to make scratch project using a special coding language without drag any thing.","archived":false,"fork":false,"pushed_at":"2024-05-18T08:46:13.000Z","size":815,"stargazers_count":34,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-01T19:11:08.171Z","etag":null,"topics":["nodejs","scratch","scratch3","toolchain"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Steve-xmh.png","metadata":{"files":{"readme":"README-CN.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-01T13:16:37.000Z","updated_at":"2024-09-20T18:35:30.000Z","dependencies_parsed_at":"2024-05-18T09:34:34.380Z","dependency_job_id":null,"html_url":"https://github.com/Steve-xmh/scratch-script","commit_stats":{"total_commits":43,"total_committers":4,"mean_commits":10.75,"dds":0.5348837209302326,"last_synced_commit":"29b5ffc48b2706afee57c269822344a152281ec3"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Steve-xmh%2Fscratch-script","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Steve-xmh%2Fscratch-script/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Steve-xmh%2Fscratch-script/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Steve-xmh%2Fscratch-script/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Steve-xmh","download_url":"https://codeload.github.com/Steve-xmh/scratch-script/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223264887,"owners_count":17116230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nodejs","scratch","scratch3","toolchain"],"created_at":"2024-08-01T15:03:39.400Z","updated_at":"2024-11-06T00:30:31.234Z","avatar_url":"https://github.com/Steve-xmh.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# ScratchScriptKit\n\n一个简约的玩具脚本语言工具包，用于将 Scratch 工程规模化和代码化。\n\nChinese 中文 [English](./README.md)\n\nScratchScript 示例：\n```lua\nvar direction = 0;\nwhen events.flagClicked() {\n    looks.sayFor('Hello ScratchScript!', 3);\n    forever {\n        direction = 1;\n        repeat (10) {\n            motion.changeY(5 * direction);\n        }\n        if (direction == 1) {\n            direction = -1;\n        } else {\n            direction = 1;\n        }\n    }\n}\n```\n\n## 项目描述文件\n\n项目描述文件用于定义各个角色和舞台的初始属性，统一命名 `project.yaml` 或者 `project.json` ，支持 YAML 和 JSON 语法进行描述。\n基本格式如下，JSON 则大同小异：\n\n```yaml\n# 井号开头为注释\n# YAML 使用缩进表达层级关系，详情请搜索 YAML 查询文档\n\n# 作品描述对象，如无提供则会生成一个干净的空作品文件（只有纯白色无代码舞台）\ninfo:\n    # 舞台对象，如无提供则会默认添加纯白色无代码舞台\n    stage:\n        # 代码属性\n        code:\n            # 相对于项目描述文件所在文件夹的代码文件位置，如无提供则无代码\n            file: ./src/stage.ss\n        # 当前舞台背景编号，如无提供则默认为 0\n        costume: 0\n        # 舞台播放声音的大小\n        volume: 100\n        # 舞台背景清单，如无提供则默认添加纯白色背景\n        costumes:\n            # 一个减号代表一个背景，按顺序依次编号，从 0 开始。\n            -\n                # 背景名称\n                name: Stage\n                # 相对于项目描述文件所在文件夹的图像文件位置，允许使用 PNG 图像或 SVG 图像\n                file: ./asset/stage.png\n        # 舞台音效清单，如无提供则不添加任何音效\n        sounds:\n            # 一个减号代表一个音效，按顺序依次编号，从 0 开始。\n            -\n                # 音效名称\n                name: 流行音乐\n                # 相对于项目描述文件所在文件夹的音效文件位置，允许使用 WAV 音频和 MP3 音频\n                file: ./asset/pop.mp3\n    # 角色清单，如无提供则没有任何角色\n    sprites:\n        -\n            # 角色名称，不允许重复，如不提供或出现冲突则会自动生成一个新名称\n            name: Cat\n            # 代码属性\n            code:\n                # 相对于项目描述文件所在文件夹的代码文件位置，如无提供则无代码\n                file: ./src/stage.ss\n            # 角色播放声音的大小，100 为最大， 0 为无声\n            volume: 100\n            # 是否显示角色\n            visible: true\n            # 角色的横纵坐标，按照角色中心和舞台坐标系计算\n            pos:\n                x: 0\n                y: 0\n            # 角色当前的大小，100 为正常大小\n            size: 100\n            # 角色当前的旋转角度，90 为向右\n            direction: 90\n            # 旋转模式，可选值为 all around, don't rotate, left-right\n            rotationstyle: all around\n            # 当前角色造型编号，如无提供则默认为 0\n            costume: 0\n            # 角色造型清单，如无提供则默认添加透明造型\n            costumes:\n                # 一个减号代表一个造型，按顺序依次编号，从 0 开始。\n                -\n                    # 造型名称\n                    name: Cat0\n                    # 相对于项目描述文件所在文件夹的图像文件位置，允许使用 PNG 图像或 SVG 图像\n                    file: ./asset/cat.png\n                    # 相对于图像左上角的图像旋转中心点位置，如不提供则默认为图像中心\n                    center:\n                        x: 0\n                        y: 0\n            # 角色音效清单，如无提供则不添加任何音效\n            sounds:\n                # 一个减号代表一个音效，按顺序依次编号，从 0 开始。\n                -\n                    # 音效名称\n                    name: Meow\n                    # 相对于项目描述文件所在文件夹的音效文件位置，允许使用 WAV 音频和 MP3 音频\n                    file: ./asset/meow.mp3\n\n```\n\n## ScratchScript\n\nScratchScriptKit 的重要组成部分，使用简单的语法对角色和舞台进行编程的脚本语言。  \n（有人吐槽这是 Lua，其实的确参考了很多，不过还是和 Lua 有所不同的）\n\n### 语法\n\n#### 数字\n允许正常的正负整数或小数：\n\n```javascript\n0 1 20 -1 1.05 -3.14\n```\n\n当然十六进制，二进制，八进制，也是完全可以的，在编译时将会转换成十进制数字：\n\n```javascript\n0xAAFFEE // Hex\n07654321 // Oct\n0b100101 // Bin\n```\n\n#### 字符串\n使用单引号或双引号开头和结尾：\n```javascript\n'Single' \"Double\"\n```\n你可以使用反斜杠（\\）进行转义：\n\n|格式|转义为|\n|---|---|\n|`\\n`|换行符|\n|`\\\\`|反斜杠|\n|`\\'`|单引号|\n|`\\\"`|双引号|\n|`\\uxxxx`|（x 为十六进制符号（`[0-9a-fA-f]`））十六进制的 Unicode 编码所对应的任意的 Unicode 字符|\n\n注：其实反斜杠后面只要不是 u 都会转译成那个字符（雾）\n\n#### HEX 颜色值\n\n使用井号开头 `#`，后跟 3, 4, 6, 8 个十六进制字符，颜色顺序如下：  \n（注：R 代表红色，G 代表绿色，B 代表蓝色，A 代表不透明度）\n\n|格式|颜色顺序|\n|---|--------|\n|`#XXX`|`#RGB`|\n|`#XXXX`|`#RGBA`|\n|`#XXXXXX`|`#RRGGBB`|\n|`#XXXXXXXX`|`#RRGGBBAA`|\n\n```css\n#F00 /* Black */\n#F007 /* Half transparent red */\n#FFFFFFFF /* White */\n```\n\n#### 标识符\n\n资深用户一条式：`[A-Za-z_][A-Za-z_0-9]*`\n\n第一个字符必须为任意大小写字母（A-Z,a-z）或下划线（_），\n之后可跟任意大小写字母，下划线和数字（0-9）进行组合：\n```\nidentifier\nthisIsAnIdentifier666\nIDENTIFIER0\nnameWhateverUWant\n```\n注：不得使用专用关键字作为标识符，下文有列出\n\n#### 关键字清单\n\n请勿将下列关键字用于变量或函数定义。\n\n```\natonce bool define false\nfor forever if in let\nnumber null register\nrepeat string true using\nvar when while\n```\n\n#### 注释\n\n在两个连续的斜杠后跟的当前行的所有内容都将被编译器忽略，：\n\n```c\n// Line comment\n/*\n  Block comment\n*/\n```\n\n#### 分隔符？\n\n从例子里你可以看到每个函数执行的后面都加入了分号作为分割符，其实这并非必要，设定这个语法只是为了顺应其他程序员的习惯。\n\n```js\n// This is okay!\nlooks.sayFor('Hello ScratchScript!', 3)\n// Add semicolon if you want:\nlooks.sayFor('Hello ScratchScript!', 3);\n```\n\n#### 空白\n\nScratchScript 不像 Python 使用缩进表达层级关系，所以你大可放心在不造成歧义的情况下写成一行，但是为了可读性还是推荐多用换行和缩进来表达程序结构。\n\n```lua\n// This still can be compiled!\nwhen events.flagClicked() { looks.sayFor('Hello ScratchScript!', 3); forever { direction = 1; repeat (10) { motion.changeY(5 * direction); } if (direction == 1) { direction = -1; } else { direction = 1; }}}\n```\n\n#### 运算符\n\n虽然你可以直接通过执行模块的语法来进行运算，但是为了简单，ScratchScript\n基本支持以下简化的算式：\n\n- 算术运算符\n  - 加法 `+`\n  - 减法 `-`\n  - 乘法 `*`\n  - 除法 `/`\n  - 求余 `%`\n- 逻辑运算符\n  - 等于 `==`\n  - 大于 `\u003e`\n  - 小于 `\u003c`\n  - 不成立 `!`\n  - 逻辑与 `\u0026\u0026`\n  - 逻辑或 `||`\n- 字符串操作\n  - 连接字符串 `..`\n\n如果算式两侧均为常数，则编译器会进行预计算优化，部分数学函数模块也支持预计算优化。\n\n运算优先级如下表（数字越高优先级越大）：\n\n1. 逻辑或 `||`\n2. 逻辑与 `\u0026\u0026`\n2. 大于 `\u003e`, 小于 `\u003c`\n3. 等于 `==`\n3. 连接字符串 `..`\n5. 加减 `+`, `-`\n6. 乘除，求余 `*`, `/`, `%`\n7. 不成立 `!`\n\n后续会尝试添加语法糖（自增，大于等于，不等于等）（懒）\n\n#### 定义变量/列表\n\n类似 JavaScript，使用 `var` 开头将创建一个全局（舞台）变量，使用 `let` 开头将创建一个局部（仅角色）变量。\n如果在舞台里使用 `let` 定义变量，则效果和 `var` 一样。后跟一个标识符作为名称，默认该变量为一个普通变量，初始值将决定该变量是普通变量还是列表。如果使用常量字面量或不提供初始值，则默认为普通变量，如果提供以 `[` 和 `]` 包裹的列表，则使用列表类型。\n\n列表使用 `[` 和 `]` 包裹，使用逗号 `,` 区分每个项目，每个项目可以使用任意的字面量来表示。\n\n```js\nvar answer = \"C\"\nvar answers = [\n    \"Any type!\",\n    123\n]\n```\n\n\n#### 执行模块（函数）：\n\n执行一个函数的格式为 *类型*.*模块名称*(*参数*)  \n如果有多个参数，则使用英文逗号分隔开。  \n如果执行的模块是自定义模块，则不需要输入模块类型。\n```\n*Cateory*.*Identifier*(*arguments*);\nmotion.moveSteps(5);\ncustomBlock('I\\'m a custom block!');\n```\n\n#### 触发事件\n```\nwhen *Cateory*.*Identifier*(*arguments*) {\n    *Codes*\n}\n```\n\n#### 条件判断\n对应 Scratch 的 `如果 \u003c \u003e 那么 { }` 模块，当判断参数为 `true` 时则执行内部代码。  \n如果在 `if` 和 `}` 之间添加了 `else`，则对应 Scratch 的 `如果 \u003c \u003e 那么 { } 否则 { }`。  \n当判断参数为 `true` 时则执行 `if` 和 `else` 之间的代码，否则则执行 `else` 和 `}` 之间的代码。  \n虽然 ScratchScript 不限制你使用非布尔值模块，但是为了确保稳健性，建议统一使用布尔值模块。\n```lua\nif(*Condition*) {\n    *Codes*\n}\n\nif(*Condition*) {\n    *Codes*\n} else {\n    *Codes*\n}\n```\n\n#### 多分支模块\n\n虽然应该没有什么模块会用到多分支，但是因为 Scratch 原代码里有提到，为了兼容性则设计了这个语法。  \n在执行函数的下方使用多个 `in` 加一个常量值（通常为数字，代表分支的编号）用于分辨分支类型，如果达成模块要求则会进入该分支，之后将按模块的执行方式继续执行，直到到达结尾的 `}` 结束执行。\n\n```lua\n*Cateory*.*Identifier*(*arguments*)\nin *String or Number* {\n    *Code*\n} in *String or Number* {\n    *Code*\n}\n...\n\n// Example\next.switch(value)\nin 1 {\n    looks.say(\"Hello!\");\n} in 2 {\n    looks.say(\"Bye!\");\n}\n```\n\n#### 无限循环\n对应 Scratch 的 `重复执行 { }` 模块，永久重复执行：\n```lua\nforever {\n    *Codes*\n}\n```\n\n#### 重复执行\n对应 Scratch 的 `重复执行 ( ) 次 { }` 模块，参数为一个正整数，指定循环的次数：\n```lua\nrepeat (*Times*) {\n    *Codes*\n}\n```\n\n#### 条件循环\n\n对应 Scratch 的 `重复执行直到 \u003c \u003c \u003e 不成立 \u003e { }` 模块，参数为一个布尔值，当为 `true` 时进行循环。  \n目前暂时不限模块类型（懒），但是建议判断时使用布尔值类型的模块，保证生成的代码足够稳定。\n\n```lua\nwhile (*Conditions*) {\n    *Codes*\n}\n```\n\n#### 计次循环\n\n对应 Scratch 的 `对于 [ ] 中的每个 [ ] { }` 模块，将左侧的变量中的值依次设置成 `1` 到右侧的计次数并在改变值后执行循环体。  \n虽然 ScratchScript 不限制你使用非数值模块，但是为了确保稳健性，建议统一使用数值模块或数字常量。\n```lua\nfor (*variable* in *times*) {\n    *Codes*\n}\n// Will count from 1 to 10\nfor (counter in 10) {\n   looks.sayFor(counter, 1);\n}\n```\n\n#### 自定义模块（WIP）\n\n使用 `define` 关键字作为开头，后跟一个普通的标识符并提供名称，如果需要不刷新舞台，则在 `define` 关键字前添加 `atonce` 关键字。\n\n```\ndefine *Identifier*(*arguments*) {\n    *Codes*\n}\n// Will not update the stage!\natonce define *Identifier*(*arguments*) {\n    *Codes*\n}\n```\n\n因为自定义模块存在类型（字符串/数字类型，布尔类型），如果仅声明了参数名称则使用字符串/数字类型作为参数类型。如果参数名后加冒号，再加入以下关键字即可指定参数类型：\n- `string` 字符串类型\n- `number` 数字类型\n- `bool` 布尔值类型\n\n```\n// This argument will become a string/number type input.\ndefine stringAndNumberArg1(str) {\n    // ...\n}\n\n// This argument will become a string type input.\ndefine stringArg(str: string) {\n    // ...\n}\n\n// This argument will become a number type input.\ndefine numberArg(str: number) {\n    // ...\n}\n\n// This argument will become a boolean type input.\ndefine boolArg(arg: bool) {\n    // ...\n}\n\n```\n\n#### 模块引用\n\n使用 `using` 关键字后跟一个**静态**字符串，通过相对路径的方式指定模块的位置，其内的模块会被添加到现有代码内，嵌套引用的话只会引用同一个。\n\n```C#\nusing *FilePath*\nusing './path/to/module.ss'\n```\n\n#### 注册扩展\n\n使用 `register` 关键字后跟一个**静态**字符串指定拓展模块的文件位置，其内定义的扩展模块将可以在代码内使用，嵌套引用的话会报告编译错误。如果需要引用同名不同功能的模块，则在字符串后面再跟一个 `as` 和一个标识符代表这个模块的新 ID。同种模块的多次不同 ID 引用不会触发编译错误。\n\n扩展文件的搜索方式不光有相对目录方式，如果相对目录无法找到模块，编译器还会根据环境变量 `SCRATCHSCRIPT_INCLUDE_DIR` 的相对目录里查询，如果仍然不存在则会报告编译错误。如果你的扩展定义文件格式为 `.js`，你可以选择不写文件后缀名。\n\n```js\nregister *FilePath*\nregister './path/to/extension.js'\n// You can rename extension\nregister './path/to/extension.js' as new_id\n// You can also register it with file path without .js extension name.\n// If your extension definition file's extention name is .js .\nregister './path/to/extension'\n```\n\n## ScratchScript 模块定义文件结构\n\n为了能有一定的拓展性，支持外部扩展的非核心模块，这里提供了一个模块定义文件的结构说明文件格式，开发者可使用 `register` 语句进行引用。\n\n该文件的本质是一个 JavaScript 脚本，核心模块也采用此模块定义文件结构来支持核心模块，如有需要可以在原代码参考。\n\n首先模块的导出类型是一个对象，拥有三个对象：\n\n- `name` 字符串，可选，表述该扩展的名称。\n- `id` 字符串，必需，表述该扩展的 ID，将会作为函数名的一部分。\n- `doc` 字符串，可选，该参数的简短文档，用于脚本生成模块文档。\n- `description` 字符串，可选，表述该扩展的简单描述。\n- `blocks` 数组，必需，列出所有的模块列表，每个数组成员都是一个对象，格式如下：\n    - `name` 模块的函数名称，将作为函数名后缀的一部分。\n    - `doc` 字符串，可选，该参数的简短文档，用于脚本生成模块文档。\n    - `opcode` 模块在 Scratch 里的模块 ID。\n    - `preprocess` 函数，如果所有参数均为常量，那么此函数用于预计算处理，第一个参数为这个 AST 节点，返回一个新的常量 AST 节点对象替换该模块。\n    - `type` 模块样式类型，默认值为 `1`，可选值如下：\n        - `1` ：普通模块，类似 `等待 ( ) 秒` 模块\n        - `2` ：返回值模块，类似 `回答` 模块\n        - `3` ：布尔值模块，类似 `鼠标是否按下` 模块\n        - `4` ：事件模块，类似 `当 🚩 被点击` 模块\n    - `subn` 如果模块类型为多分支模块（类似 `如果 \u003c \u003e 那么`, `如果 \u003c \u003e 那么 否则 `），则此参数为分支的数量，默认为 `0`， 即没有分支。\n    - `args` 模块的参数数组，每个数组成员都是一个对象，格式如下：\n        - `name` 字符串，这个输入值在 Scratch 的键名。\n        - `doc` 字符串，可选，该参数的简短文档，用于脚本生成模块文档。\n        - `type` 参数的类型，默认值为 `10`，可选值如下：\n            - `4` 数字\n            - `5` 正数\n            - `6` 正整数\n            - `7` 整数\n            - `8` 角度\n            - `9` 颜色\n            - `10` 字符串\n            - `11` 广播菜单\n            - `12` 变量菜单\n            - `13` 列表菜单\n            - `20` 枚举菜单\n            - `30` 静态常量，此时该变量不作为参数的一部分参与。\n            - `31` 菜单静态常量，此时该变量不作为参数的一部分参与。\n        - `value` 任意，可选，如果类型为常量，则此处为该参数的常量值，无需按照 AST 对象结构定义。\n        - `menu` 函数，如果类型为枚举菜单，则此参数用于处理用户输入并返回需要存储的真实值。\n        - `menuOpcode` 字符串，在大多数情况下，菜单都属于独立的模块（只是因为 Shadow 所以拖不出来），所以这里如果提供，则作为这个菜单模块的模块 ID，否则将直接菜单值作为普通参数存储。\n\n## 编译器开发\n\n### 部署\n\n推荐使用 Yarn 进行各种库的下载及构建工具的运行，NPM 也是可以的。\n\n```bash\n\u003e yarn\n\u003e yarn start\n```\n\n启动 webpack-dev-server 之后，访问 [http://localhost:8040/playground/](http://localhost:8040/playground/) 即可访问网页编辑器（仅供调试）。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSteve-xmh%2Fscratch-script","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSteve-xmh%2Fscratch-script","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSteve-xmh%2Fscratch-script/lists"}