# LetsGal Studio 扩展开发 > 本文件是提供给 AI 编程助手的 LetsGal Studio 扩展开发上下文。请在扩展源码目录中工作,先检查现有工程和本地 SDK,再实现、构建并验证用户提出的需求。 > **硬性限制:绝对不要直接创建、修改或修补 `dist/index.js`,也不要编辑 `dist/` 下的任何文件。`dist/` 只能由项目的构建命令生成。所有功能修改都应在 `src/` 等源文件中完成,再重新执行构建。** LetsGal Studio 扩展可以包含可视化界面、TypeScript 程序,或同时包含两者。程序扩展使用 TypeScript、React、Vite 和 `@avg-studio/sdk`。 本文中的规则适用于 Codex、Claude Code、Cursor、GitHub Copilot 等可以读取文件、修改代码并运行命令的 AI 编程助手。 ## 首要工作流程 接到扩展开发任务后,按以下顺序执行: 1. 确认当前工作目录是目标扩展的源码目录,不要修改目录外的项目。 2. 读取 `extension.json`,记录扩展 `id`、SDK 版本要求和程序入口。 3. 读取 `package.json`,确认包管理器、已有依赖和实际可用的 scripts。 4. 检查 `src/` 中的既有实现;如果扩展包含 `ui/`,同时了解程序与可视化界面的协作方式。 5. 需要确认 API 时,优先读取当前扩展的 `sdk/` 类型和注释;本地 SDK 与当前 Studio 版本最匹配。 6. 先复用现有架构,再按需求补充 `Extension` 模块、剧本方法、设置、存档或 React UI。 7. 执行项目声明的构建命令,修复本次修改引入的构建和 TypeScript 错误。 8. 向用户报告修改内容、构建结果,以及必须在 Studio 中完成的人工验证步骤。 用户要求直接开发时,应完成文件修改和构建,不要只返回示例代码或实施建议。只有缺少会显著改变产品行为的信息时才询问用户。 ## 开始前判断扩展形态 ### 纯可视化界面 目录通常只有: ```text extension.json ui/ ``` 纯界面扩展不需要 npm、React 或构建程序。界面 JSON 应由 LetsGal Studio 的可视化界面编辑器维护。除非用户明确要求并了解格式,否则不要直接重写 `ui/*.json`。 如果需求必须使用复杂计算、剧本方法、运行时订阅、Canvas、外部服务或 React UI,应告诉用户先在 Studio 的扩展树中选择「程序」并点击「初始化程序」。不要自行猜测并手写整套脚手架。 ### 程序扩展 典型目录: ```text extension.json package.json tsconfig.json vite.config.ts sdk/ src/ dist/ ui/ ``` `src/` 是程序源码,`sdk/` 是 Studio 复制的 SDK,`dist/` 是生成产物。程序入口以 `extension.json.entry` 为准。 ### 混合扩展 混合扩展同时使用 `ui/` 和 TypeScript。需要动态控制已有可视化界面时,优先使用 `ctx.visualUI`,不要在 React 中重复制作同一套界面。 ## 不可破坏的约束 - 不得修改已经投入使用的 `extension.json.id`。它是设置、存档、界面引用和剧本调用的稳定命名空间。 - 不得手动编辑 `sdk/`。需要更新 SDK 时应由 Studio 重新同步。 - **绝对禁止直接修改 `dist/index.js`,也不得创建、编辑或修补 `dist/` 下的任何文件。** `dist/` 和源映射文件只能由构建命令生成;需要改变程序行为时,必须修改 `src/` 等源文件后重新构建。如果找不到对应源码,应停止修改并向用户说明,而不是把改动写进 `dist/`。 - 不要因为修改代码而自动提升 `extension.json.version` 或 `sdkVersion`,除非用户明确要求发版,或确实使用了更高版本才有的新 API。 - 不要发布、上传、提交工坊、删除源码、创建 Git tag 或修改用户项目之外的文件,除非用户明确授权。 - 不要猜测 SDK 方法、参数或返回值。先检查本地 `sdk/`,再查官方文档。 - 不要替换模板中的 Vite 外置依赖配置。React、React DOM 和 `@avg-studio/sdk` 由宿主提供单实例。 - 不要把第二份 React、React DOM 或 SDK 打进运行时程序包。 - 新增源码文件使用 `kebab-case.ts` 或 `kebab-case.tsx` 命名。 - 保持 TypeScript 严格模式,不用 `any` 掩盖不明确的 SDK 契约。确需兼容边界时,使用最小范围的类型收窄并说明原因。 - 不要把密钥、令牌或用户隐私写进源码、清单、日志或构建产物。 - 外部网络访问、敏感权限或新的运行时依赖必须确有必要,并向用户说明用途和风险。 - 订阅事件、输入动作或外部资源时,必须考虑重复注册、卸载清理、预览重启和多引擎并存。 - 不要覆盖与当前任务无关的用户改动。 ## 核心编程模型 程序入口导出一个或多个继承 `Extension` 的类。一个类可以同时提供 UI、剧本方法、项目设置、存档字段和注册期行为。 最小 UI 模块: ```tsx import { Extension, extension, type ExtensionRenderData, } from "@avg-studio/sdk"; import { ExamplePanel, type ExamplePanelProps } from "./example-panel"; @extension({ id: "example-panel", label: "示例面板" }) export class ExamplePanelExtension extends Extension { render(): ExtensionRenderData { return { component: ExamplePanel, props: this.data ?? {}, }; } } ``` `@extension()` 中的模块 id 是扩展内部的稳定模块标识,不等同于 `extension.json.id`。不要在多处硬编码扩展清单 id;需要完整扩展命名空间时,从 `extension.json` 读取。 ## 按需求选择能力 ### 提供剧本可调用的逻辑 使用 `method()` 声明剧本方法。它适合发放奖励、修改状态、解锁内容、背包操作和业务逻辑。 ```tsx import { Extension, extension, method } from "@avg-studio/sdk"; @extension({ id: "rewards", label: "奖励系统" }) export class RewardsExtension extends Extension { static grant = method({ title: "发放奖励", schema: { amount: { type: "number", label: "数量", required: true, }, }, run(ctx, params) { ctx.variables.set("rewardAmount", params.amount); }, }); } ``` 方法参数应通过参数结构声明,让 Studio 自动生成检查器控件。可用参数类型和完整定义以本地 SDK 及剧本方法文档为准。 ### 保存玩家进度 使用 `static saveSchema = defineSave(...)` 声明玩家运行时数据: ```tsx import { Extension, defineSave, extension } from "@avg-studio/sdk"; @extension({ id: "progress", label: "扩展进度" }) export class ProgressExtension extends Extension { static saveSchema = defineSave({ score: { type: "number", persistence: "slot", default: 0, }, unlocked: { type: "list", persistence: "shared", default: [] as string[], }, }); } ``` - `slot`:跟随当前存档槽位,适合背包、好感度和关卡进度。 - `shared`:跨所有存档共享,适合成就和全局解锁内容。 - 数组读取结果应视为只读,通过创建新数组后整体 `set`,不要原地 `push`。 - 不要把 DOM、React 临时状态、函数、未完成的 Promise 或宿主对象写进存档。 实例代码和 `method().run` 中可通过 `this.save` 读写。React 组件需要响应存档变化时,应根据当前 SDK 提供的 `useValue` 或变量桥接方式实现,不要猜测 Hook 的用法。 ### 提供项目设置 使用 `static settings = settings(...)` 声明创作者可在 Studio 中配置的项目设置。通过当前扩展作用域的 `ctx.settings` 读取。 设置用于创作者配置;存档用于玩家游玩过程中产生的数据。不要把两者混用。 ### 渲染程序 UI 实现 `render()` 并返回 React 组件。适合动态面板、HUD、小游戏、Canvas 和复杂交互。 - 使用 `useExtensionContext()` 获取当前引擎上下文。 - UI 可能同时运行在扩展预览、主预览和调试画布中,不要使用无作用域的全局单例串联不同引擎。 - 组件应适配宿主舞台,而不是假设浏览器窗口就是游戏画面。 - 不要从 CDN 加载脚本、字体或样式,除非用户明确需要并接受离线和网络风险。 ### 注册常驻行为或快捷键 使用 `static onRegister(ctx)` 注册事件、输入动作或启动期行为。常驻 UI 使用 `autonomous: true`。 - 需要允许玩家改键时,优先注册语义动作,不要只硬绑物理按键。 - 动作 id 必须符合当前 SDK 的扩展作用域规则。 - 考虑预览重复启动、监听器清理和异步错误处理。 - 不要让一次注册导致每次重新预览都多出一个监听器。 ### 控制可视化界面 使用 `ctx.visualUI` 打开界面、查找带引用名的元素并读写其属性。完整界面名称由扩展清单 id 和界面名组成。 不要在代码中重复硬编码随机生成的清单 id。应从 `extension.json` 导入清单信息。 ### 替换系统界面 只有需求明确要替换标题、存档、读档、设置、历史、选择或输入等系统位置时,才声明系统插槽。普通 HUD、弹窗和工具面板不应占用系统插槽。 ### 章节调度 需要由地图、日程或回合系统决定下一章节时,使用 `scheduleStrategy()`。不要把高级调度策略伪装成普通剧本方法。 ## ExtensionContext 能力路由 不要一次读取全部 API 文档。根据需求选择对应命名空间: - `ctx.flow`:跳转片段、重新开始。 - `ctx.story`:读取章节和剧本。 - `ctx.variables`:读取、写入和订阅剧本变量。 - `ctx.scene`:切换、显示和销毁场景。 - `ctx.character`:查询角色和控制立绘。 - `ctx.dialogue`:读取对话、选项和播放状态。 - `ctx.sound`:播放、暂停和停止音频。 - `ctx.camera`:平移、缩放、震动和复位。 - `ctx.curtain`:控制幕布。 - `ctx.archive`:存档和读档。 - `ctx.history`:读取历史记录。 - `ctx.config`:读取和修改玩家配置。 - `ctx.ui`:显示和隐藏程序 UI。 - `ctx.visualUI`:控制可视化界面。 - `ctx.game`:作品信息、退出和全屏。 - `ctx.system`:调用标题、设置、存读档等系统入口。 - `ctx.input`:注册语义动作、快捷键和输入监听。 - `ctx.settings`:读取当前扩展的项目设置。 - `ctx.asset`:解析素材 URI。 - `ctx.sceneRender`:在扩展容器中隔离渲染场景。 - `ctx.subscribe`:订阅引擎状态事件。 - `ctx.getHost`:访问不稳定的宿主内部对象;只有公开 API 无法满足需求时才考虑。 优先使用稳定、公开、类型安全的命名空间。`getHost` 不是常规开发捷径,使用前应说明兼容风险。 ## 本地 SDK 查找顺序 API 不确定时,从以下文件开始: 1. `sdk/index.ts`:公开导出总入口。 2. `sdk/sdk-context.ts`:`ExtensionContext` 和各运行时命名空间。 3. `sdk/extension-module.ts`:`Extension` 基类。 4. `sdk/extension-method.ts`:`method()`。 5. `sdk/settings-builder.ts` 和 `sdk/extension-settings.ts`:设置 Schema。 6. `sdk/save-schema.ts`:存档 Schema。 7. `sdk/schedule-strategy.ts`:章节调度策略。 8. `sdk/internal-system-slots.ts`:系统插槽。 只使用 `sdk/index.ts` 实际公开导出的 API。不要从 SDK 内部文件深层导入运行时代码。 ## 构建与检查 先读取 `package.json`,使用项目已有包管理器和 scripts。Studio 默认生成的程序扩展通常支持: ```bash npm install npm run build npm run watch ``` - 最终验收使用 `npm run build`。 - `npm run watch` 只用于持续开发。 - 默认脚手架没有 `npm run dev`。 - 如果存在锁文件,使用与锁文件一致的包管理器。 - 不要为了绕过错误删除锁文件、降低 TypeScript 严格度或改坏 Vite 配置。 - 构建成功只证明程序包可以生成;交互、存档、系统插槽和多引擎隔离仍需在 Studio 中验证。 若项目已有测试脚本,运行与本次修改相关的测试。没有测试框架时,不要仅为简单改动擅自引入大型测试依赖;应提供明确的 Studio 人工验收步骤。 ## 完成标准 只有满足以下条件,任务才算完成: - 用户要求的行为已经实际实现。 - 没有改变扩展稳定 id 和无关功能。 - 没有直接修改 SDK 与生成产物。 - 构建命令成功。 - 本次变更引入的 TypeScript 和构建错误已修复。 - 设置数据与存档数据使用了正确作用域。 - 事件和输入订阅不会在重复预览后累积。 - 异步操作具有必要的错误处理。 - 最终回复列出修改文件、验证结果和 Studio 人工验收步骤。 需要 Studio 人工确认时,不得谎称已经验证视觉或运行时效果。请逐条给出用户应点击的位置、应触发的剧本方法以及预期结果。 ## 常见错误 - 修改 `extension.json.id`,导致既有设置、存档或剧本引用失效。 - 根据其他框架经验编造不存在的 `ctx` API。 - 把创作者设置存进玩家存档,或把玩家进度存进项目设置。 - 原地修改只读数组,导致变化无法正确持久化。 - 在模块全局保存某个引擎上下文,造成扩展预览与主预览串扰。 - 每次预览都重复注册事件,却没有清理旧监听器。 - 直接编辑 `dist/index.js`,下一次构建后改动全部丢失。 - 使用 `npm run dev`,但脚手架只提供 `build` 和 `watch`。 - 为了一个普通面板错误占用系统插槽。 - 用 React 重做已经存在的可视化界面,而不是通过 `ctx.visualUI` 控制。 - 构建成功后宣称所有功能完成,却没有说明 Studio 验收方法。 ## 官方文档 - [扩展是什么](https://docs.avg-engine.com/extensions/intro):扩展形态和能力概览。 - [创建第一个扩展](https://docs.avg-engine.com/extensions/develop):创建、初始化程序、构建和导入。 - [Hello World](https://docs.avg-engine.com/extensions/hello-world):完整的入门扩展示例。 - [Extension 基类](https://docs.avg-engine.com/extensions/extension-class):UI、生命周期、方法、设置和存档。 - [剧本方法](https://docs.avg-engine.com/extensions/method):`method()` 与参数 schema。 - [设置 Schema](https://docs.avg-engine.com/extensions/settings-schema):项目设置。 - [存档 Schema](https://docs.avg-engine.com/extensions/save-schema):玩家数据持久化。 - [章节调度策略](https://docs.avg-engine.com/extensions/schedule-strategy):高级章节调度。 - [运行时 API](https://docs.avg-engine.com/extensions/api-context):`ExtensionContext` 能力索引。 - [程序控制可视化界面](https://docs.avg-engine.com/extensions/visual-ui-controller):`ctx.visualUI`。 - [系统插槽](https://docs.avg-engine.com/extensions/system-slots):系统界面替换。 - [实战范例](https://docs.avg-engine.com/extensions/cookbook):接近真实项目的扩展写法。 只有本文件和本地 SDK 不足以确认细节时,才读取与当前需求直接相关的页面。 ## 推荐给 AI 编程助手的任务模板 ```text 请先阅读 LetsGal Studio 扩展开发指导: https://docs.avg-engine.com/extensions/llms.txt 在当前扩展源码目录中实现以下需求: [在这里写需求] 验收标准: - [写出玩家或创作者可观察到的结果] - [写出需要保存、配置或显示的内容] 请先检查 extension.json、package.json、src/ 和本地 sdk/,不要猜测 API。 直接完成代码修改,使用项目已有命令构建并修复错误。 不要修改稳定扩展 id 和 sdk/。绝对不要直接修改 dist/index.js 或 dist/ 下的任何文件;它们只能由构建命令生成。也不要发布或上传扩展。 最后汇报修改文件、构建结果和需要在 Studio 中执行的人工验证步骤。 ``` ## 补充资料 - [可视化界面编辑器](https://docs.avg-engine.com/advanced/visual-ui-editor):无需编程的界面开发。 - [可视化界面元素](https://docs.avg-engine.com/advanced/visual-ui-elements):界面元素属性。 - [可视化界面数据与动作](https://docs.avg-engine.com/advanced/visual-ui-data-and-actions):数据绑定、事件和动作。 - [默认游戏壳](https://docs.avg-engine.com/advanced/default-shell):标题、存读档、设置等内置系统。