Imported from LuYifei2011/scratch-modules-gallery (
AGENTS.md). Install upstream withnpx skills add LuYifei2011/scratch-modules-gallery. Copyright stays with the author.
AI 协作速览(scratch-modules-gallery)
目标:快速理解并安全扩展本仓库。保持"单 Bun 构建脚本 + 纯静态输出"原则,禁止引入前端打包器或框架级迁移。
核心流水线
- 入口
scripts/build.ts:读取site.config.ts→ 扫描模块(content/modules/**)→ 解析脚本/导入/变量 → 合并模块级 i18n → 逐语言生成 HTML + 搜索 JSON → 生成根跳转、sitemap、robots。- 开发模式(
IS_DEV=1):收集构建警告/错误至collectedIssues,生成/issues/页面;跳过 sitemap 生成节省 ~8x 时间 - Sitemap 使用
simple-git从提交历史提取文件修改时间(CI 需fetch-depth: 0)
- 开发模式(
- 数据模型
scripts/lib/schema.ts:统一字段 (id, slug, name, description, tags, contributors[], scripts[], hasDemo, variables[], notesMap, references)。任何字段变更需评估链路:schema → build → 模板 → 搜索 → 前端脚本。parseContributors: 仅接受数组;数组项支持gh/user/sc/user自动生成链接,或普通字符串/对象meta.json中的name/description/seoDescription是英文基线;非英文文本放入模块i18n/<locale>.json覆盖,禁止用 locale map 混写
- 模板 Eta:
src/templates/layouts/{base,home,module}.eta只做展示;上下文:config,module,t,locale,pageBase,assetBase,pagePath,locales,year,IS_DEV,langTags,buildIssues,buildIssuesSummary。- 禁止模板中直接调用时间或访问浏览器环境
pageBase/assetBase由site.config.tsbaseUrl 计算,确保多语言路径正确
- 前端 TS:
src/client/{home.ts,module.ts}仅负责搜索索引加载、语言切换、scratchblocks 二次渲染。全局注入:window.__I18N,PAGE_BASE,ASSET_BASE,IS_DEV。- 异步加载
/search-index.json+/search-docs.json(按语言目录) - CJK 分词客户端与构建端同步(单字+双字滑窗)
- 异步加载
- 搜索 MiniSearch:ES 模块拷贝至
dist/vendor/;索引字段:name,id,description,tags;boost 权重:name(5) > id(4) > tags(3) > description(2)。- 自定义
tokenizeCJK函数:为中文字符串生成单字+双字滑窗 token,支持子串搜索
- 自定义
脚本与导入机制
- 脚本文件规则:每模块必须
scripts/*.txt;文件名解析:01-main.txt→ idmain;无数字前缀则文件名去.txt- 自然排序(numeric: true):
1-foo.txt<2-bar.txt<10-baz.txt
- 自然排序(numeric: true):
- !import 指令:行级
!import otherModuleId[:scriptIndex](scriptIndex 为 1 基,省略则取第 1 段)- 顶部连续 import 折叠为
leadingImports数组;正文/中间 import 拆成独立导入段 - 递归展开限深度 20;循环/缺失/越界写入注释
// 导入失败: <原因> - 导入段结构:
{ imported: true, content, fromId, fromName, fromIndex, fromTitle, fromScriptId }
- 顶部连续 import 折叠为
- scratchblocks 翻译:构建时调用
scratchblocks.parse()→translate()→stringify()- 加载所有语言文件
node_modules/scratchblocks-plus/locales/*.json(启动时同步) - 英文环境不翻译(脚本源假设为英文);非英文按
languageTag映射(如 zh-cn → zh_cn)
- 加载所有语言文件
国际化 (全局 + 模块)
- 全局语言:
src/i18n/*.json控制站点 UI、元信息 (siteName, description, keywords, languageTag)- 模板中通过
t对象访问;前端通过window.__I18N访问
- 模板中通过
- 全局 Tags 翻译:
src/i18n/tags.json集中管理所有 tags 的多语言翻译- 结构:
{ tagId: { en: "...", zh-cn: "...", zh-tw: "..." }, ... } - 构建时自动应用,模块 i18n 文件无需包含
tags字段 - 新增 tag:仅需在
tags.json中添加一次翻译,所有使用该 tag 的模块自动获得本地化
- 结构:
- 模块局部:
content/modules/<id>/i18n/<locale>.json可覆盖:name, description, seoDescription, variables, lists, events, scriptTitles, procedures, procedureParams, comments- 英文基础文案统一写在
meta.json;通常不需要i18n/en.json,避免与meta.json重复 - 备注文件:
content/modules/<id>/notes/<lang-code>.md;构建时按语言优先级选取,转换为notesHtml写入模组上下文;notesMap(原始 Markdown 映射)存储在 schema 中 - 不再需要翻译 tags:直接在全局 tags.json 中维护
- 变量/列表/事件:构建时计算
displayName(不改变原始 name),优先级(示例 zh-cn):当前语言 > 同类中文变体 > 英文原名 - 示例:
fps模块的zh-cn.json将FPS变量映射为 "帧率"
- 英文基础文案统一写在
- 自定义块本地化(方案A):
- 脚本源统一英文
define xxx (param :: custom-arg) ... procedures字段:英文 pattern(_为参数槽)→ 本地化 pattern,如"FPS _": "帧率 _"procedureParams字段:参数名映射,如"last tick30": "上次tick30"- 处理顺序关键:先文本层 pattern 替换(正则匹配
_占位)→ 再 scratchblocks AST 翻译 + 参数名替换(translateScriptFields)- 缺失翻译检测:非英文 locale 构建时输出[i18n-missing][locale] moduleId: fields...(开发模式)
- 自动从英文源码提取
define行生成 baseline procedures/params(若未手动指定)
- 脚本源统一英文
构建/开发
- 构建:
bun run build→ 输出到dist/(按语言子目录)- 生产构建(~6-7 秒):包含完整 sitemap、robots.txt、favicon PNG、封面图、HTML 压缩
- 开发构建(
IS_DEV=1,~0.8 秒):跳过 sitemap,生成/issues/调试页面;仍执行封面图/favicon PNG/HTML 压缩(适合测试完整构建产物) - 快速构建(
bun run build:fast或FAST_BUILD=1):额外跳过 favicon PNG 生成(仅保留 SVG)、站点+模块封面图、HTML 压缩;无 issues 页面 - 网站迁移构建(
MIGRATION_REDIRECTS=github-pages bun run build):为 GitHub Pages 把历史 HTML 路由替换为新站跳转文档;普通构建始终生成供 Cloudflare Pages 使用的外部 301_redirects IS_DEV=1 bun run build:开发调试页 + 完整压缩产物(两者可叠加)
- 开发服务器:
bun run dev/bun run dev:https- 监听:
content/**,src/**,public/**,site.config.ts,scripts/lib/**,scripts/build.ts - 自动刷新:SSE 推送
{type:'reload'};注入<script>到所有 HTML - 重建自动启用快速模式(同时设置
IS_DEV=1+FAST_BUILD=1),速度最快 - HTTPS 支持:自动生成自签证书(
.cert/),或指定 PEM/PFX(环境变量) - 模块编辑器:
/__dev/editor/可视化编辑模块(scripts/lib/editor-api.ts处理 API) - 路由回退:无扩展名路径 → 相对
index.html;目录 →index.html
- 监听:
- 新建模块 CLI:
bun run module:new -- <id> --name "Name" --description "Description"- 支持缺少必填项时交互式询问;非交互环境必须传入 id/name/description
- 默认生成与 editor 一致的最小结构:
meta.json+scripts/01-main.txt - 可选参数:
--tags a,b、--keywords a,b、--contributors "gh/user, sc/user"、--script-content "..."
- SEO 描述工具:
bun run check-seo:检查所有语言seoDescription缺失与长度异常;缺失为阻塞错误,长度异常为 warningbun run seo:context -- <module-id> --locale <locale>:导出模块元信息、脚本、变量、备注等上下文,便于手动给 LLM 生成描述bun run seo:generate [module-id] [--locale <locale>] [--apply]:调用 OpenAI-compatible LLM 生成缺失的seoDescription;默认 dry-run 只预览,--apply会重新生成并写回- 生成工具只处理缺失项,不覆盖已有
seoDescription;结果按seo-checker长度规则校验,不合规则重试一次,仍不合规则不写回 zh-cn/zh-tw使用同源策略:优先从已有或本轮刚生成的兄弟中文描述等义派生,避免简繁中文独立生成导致语义漂移
- 环境变量:
BASE_URL:覆盖site.config.tsbaseUrl(影响 canonical / sitemap)IS_DEV:传入模板与前端(window.IS_DEV);开发服务器自动设置;控制 issues 页面与 sitemap 跳过FAST_BUILD:控制耗时资源跳过(favicon PNG、封面图、HTML 压缩);开发服务器自动设置;与IS_DEV独立MIGRATION_REDIRECTS=github-pages:仅供旧站 GitHub Pages 部署工作流使用;本地开发和 Cloudflare Pages 普通构建不要设置LLM_API_KEY/OPENAI_API_KEY、LLM_MODEL、LLM_BASE_URL:seo:generate使用;推荐写入.env.local等 Bun 会自动读取的 env files;LLM_BASE_URL默认https://api.openai.com/v1HTTPS=1+HTTPS_KEY/HTTPS_CERT或HTTPS_PFX/HTTPS_PASSPHRASE:HTTPS 配置
- 依赖管理:纯 ESM(
type: "module");CommonJS 依赖用createRequire(import.meta.url)- 构建时自动复制 vendor:
minisearch/dist/es/index.js→dist/vendor/minisearch.js;scratchblocks-plus/build/*.min.es.js+locales/*.json→dist/vendor/
- 构建时自动复制 vendor:
约束与安全边界
- 禁止:引入打包器(Webpack/Vite/Rollup)、修改输出目录结构、硬编码绝对 URL、在模板直接生成当前时间、写入
dist/手工文件 - 必须:所有内部链接/静态资源路径通过
pageBase/assetBase拼接(多语言部署兼容)- 示例:
fetch(pageBase + '/search-index.json')而非/search-index.json
- 示例:
- 模板上下文:
year从构建时注入;IS_DEV控制调试功能(编辑按钮、issues 页面) - HTML 压缩:
html-minifier-next可选(失败回退原始 HTML);保留引号属性(removeAttributeQuotes: false)
常见修改指南
| 目标 | 入口 | 注意点 |
|---|---|---|
| 新增模块 | bun run module:new -- <id> |
默认生成最小结构;meta.json 必须包含英文 name/description;非英文放 i18n |
| 扩展数据字段 | schema.ts |
同步模板 & 搜索 & 前端依赖字段 |
| 新语言 | 复制一份 src/i18n/en.json |
如果需要模块级翻译,新增对应 i18n JSON |
| 新增 tag | src/i18n/tags.json |
添加所有支持语言的翻译,所有模块自动获得 |
| 添加或更新备注 | notes/<lang-code>.md |
每个语言独立文件;构建时按语言优先级选取 |
| 自定义块新增 pattern | 模块 i18n procedures |
保持英文源脚本同步;_ 数量需与参数个数一致 |
| SEO 调整 | site.config.ts + 模板 head |
确保 hreflang、canonical 含语言段 |
| 网站迁移跳转 | migration-redirects.ts |
保留 locale/slug;不要用 catch-all 重定向旧静态资源 |
| 生成 SEO 描述 | bun run seo:generate |
默认 dry-run;--apply 会重新生成并写回;LLM 配置优先放 .env.local |
验证清单(提交前)
bun run build无异常;所有语言目录含search-index.json/search-docs.json。- 任意模块页
<head>:canonical 正确、全量 hreflang +x-default。 - 导入展开无意外
// 导入失败(除演示)。 - 自定义块:英文源含
define ...;目标语言出现本地化标题 + 参数名称替换。 - Tags 显示正确的多语言翻译(从
src/i18n/tags.json应用)。 - 首页搜索:中文子串命中(CJK 分词生效)。
- 根
index.html按浏览器语言/LocalStorage 跳转期望语言。 - SEO 变更后运行
bun run check-seo;若用 LLM 写回,注意--apply会重新生成内容。 - 迁移变更后分别检查普通构建的
_redirects与 GitHub Pages 迁移构建的 HTML/404,并确认旧.sb3不被重定向。
易踩坑 & 提示
- 缺少
scripts/或空目录 → 仍构建但出现在Issues:。 - 参数/自定义块翻译顺序错误会导致 pattern 匹配失败(务必先 pattern 后 AST 翻译)。
- 变量/列表英文名如果与局部 i18n 键不一致不会显示本地化 displayName。
- 文件名排序混用(
1-vs01-)会引发顺序意外;统一使用两位或不加前导零。 - 忘记使用
assetBase加载搜索 JSON 会导致跨语言路径 404。 - 新增 tag 必须在
src/i18n/tags.json中定义翻译,才能在非英文版本正确显示。
推荐阅读顺序
scripts/build.ts → scripts/lib/schema.ts → src/templates/layouts/*.eta → src/client/*.ts → 示例模块 content/modules/fps/。
若新增特性(如:额外资源类型、本地化维度、搜索字段)请在提交中同步更新此文件并列出回归验证步骤。
单元测试
-
框架:使用
bun:test,零额外依赖 -
运行:
bun test tests/*.test.ts -
文件结构:所有测试文件位于
tests/目录,文件名格式<module-name>.test.ts -
CI 工作流:
.github/workflows/test.yml仅当以下路径变更时触发测试:scripts/**、src/i18n/**、tests/**、package.json、bun.lock- 模块内容变更(
content/modules/**)不触发测试工作流
-
覆盖范围:
测试文件 被测模块 主要测试内容 schema.test.tsscripts/lib/schema.tsparseContributors、buildModuleRecord(必填校验、英文基线字段)import-resolver.test.tsscripts/lib/import-resolver.ts导入解析、循环引用检测、缺失模块、越界索引 html-utils.test.tsscripts/lib/html-utils.tsescapeHtml、maybeMinify、generateShareLinksscratch-utils.test.tsscripts/lib/scratch-utils.tstokenizeCJK、CATEGORY_COLORS、analyzeBlockCategoriesi18n-loader.test.tsscripts/lib/i18n-loader.tspickConfigForLocale回退与覆盖i18n-engine.test.tsscripts/lib/i18n-engine.ts元信息本地化、变量名映射、脚本标题、tags、notes、翻译字段补全 script-translator.test.tsscripts/lib/script-translator.tsAST 翻译、变量/列表/自定义块名称映射、多参数重排序 markdown.test.tsscripts/lib/markdown.tsMarkdown 转 HTML、scratchblocks/go-to-block 自定义扩展 search.test.tsscripts/lib/search.tsMiniSearch 索引构建、CJK 内容 logger.test.tsscripts/lib/logger.tstruncate、formatDuration、timeNowmodule-loader.test.tsscripts/lib/module-loader.ts集成测试(从磁盘加载 .test + fps 模块、翻译、notes、错误处理) module-creator.test.tsscripts/lib/module-creator.ts新建模块脚手架、ID 校验、重复模块、默认脚本 -
编写规范:
- 使用
describe/it组织测试 - 测试数据尽量内联构造,避免依赖外部文件(
module-loader.test.ts除外,它使用临时 fixture 目录) module-loader.test.ts通过before钩子将.test和fps两个模块复制到系统临时目录,避免加载全部模块导致测试过慢- 新增构建模块时,在对应
*.test.ts中补充测试
- 使用
NOTE: When performing a code review, respond in Chinese.