扩展不再强制是一个 TypeScript 项目。目录结构取决于它是否包含程序。
纯界面扩展
新建扩展的初始结构:
my-extension/
├── extension.json
├── .gitignore
└── ui/
└── main-panel.json
ui/ 下每个 JSON 文件是一份可视化界面。文件名由 Studio 管理,界面显示名称可以在编辑器中修改。
纯界面扩展的 extension.json 不声明 entry。Studio 因此不会尝试加载程序 bundle。
初始化程序后
点击「初始化程序」会在现有目录中追加:
my-extension/
├── extension.json
├── package.json
├── tsconfig.json
├── vite.config.ts
├── README.md
├── sdk/
├── assets/
│ └── cover.png
├── ui/
│ └── main-panel.json
├── src/
│ ├── index.tsx
│ └── welcome-ui.tsx
└── dist/
└── index.js
src/:TypeScript / React 源码;
sdk/:@avg-studio/sdk 的本地副本;
dist/index.js:Studio 和玩家端实际加载的程序;
assets/:图片、CSS、JSON、字体等需要在运行时读取的静态资源;
ui/:仍由可视化编辑器管理,可以通过 ctx.visualUI 和程序协作。
运行时通过 ctx.extensionResource 访问 assets/ 和 dist/ 内的文件。路径相对扩展根目录,例如 assets/cover.png,不要写成 ./assets/cover.png。
extension.json
纯界面扩展的清单示例:
{
"id": "user.my-shell",
"name": "我的游戏壳",
"description": "一套自定义系统界面",
"author": "your-name",
"version": "1.0.0",
"sdkVersion": "^1.0.0"
}
初始化程序后会加入:
{
"entry": "dist/index.js"
}
| 字段 | 必填 | 说明 |
|---|
id | 是 | 全局唯一标识,长度 2~128;Studio 会生成合法值 |
name | 是 | Studio 中显示的扩展名称 |
version | 是 | 语义化版本号 |
sdkVersion | 是 | 需要的最低 SDK 版本,见下方说明 |
author | 否 | 作者标识,可以为空 |
description | 否 | 简介 |
entry | 程序扩展是 | 程序 bundle 相对路径;存在即表示扩展带程序 |
icon | 否 | 图标相对路径 |
propsSchema | 否 | 程序 UI 接受的 props 定义 |
overrides | 否 | 接管 DialogueBox、Choice 或 InputBox |
permissions / network | 否 | 权限和网络能力声明 |
id 是设置、存档、界面引用和系统绑定的命名空间。项目开始使用后不要随意修改。
sdkVersion 的版本校验
v1.9.0 起:SDK 版本号与 Studio 版本号保持一致,版本校验精确到次版本和补丁号(此前只比较主版本)。
sdkVersion 声明扩展可运行的 SDK 版本范围。2.5.0 的实际规则如下:
| 写法 | 规则 |
|---|
>=1.9.0、裸版本 1.9.0 | 最低版本,允许满足要求的跨主版本升级 |
^1.9.0 | 2.x 特别兼容旧 1.x 模板声明;不据此放行未知的未来主版本 |
^2.0.0 | 在 2.x 内满足最低版本 |
~2.0.0 | 限制在 2.0 的补丁版本范围 |
* | 不限制版本;只有确认兼容时才使用 |
更高最低版本、不支持的复合范围或无效声明会被拒绝。~ 的更窄限制仍有效,不会因为 2.0 兼容旧模板而被忽略。工坊中的不兼容版本会提示 SDK 要求。
声明建议:用到了某个版本新增的 API,就把 sdkVersion 提到那个版本(例如使用 ctx.dialogue.useStyle 需要声明 >=1.9.0,使用 ctx.dialogue.useTextAppearance 需要声明 >=2.0.0);只用基础 API 时保持较低的声明,让老版本引擎的用户也能安装。Studio 新建扩展时会自动填入当前 SDK 版本。
hasProgram 是 Studio 校验清单后生成的内部状态,不需要手写。原始清单是否声明 entry,决定扩展有没有程序。
程序入口
src/index.tsx 导出一个或多个 Extension 子类。也可以从 extension.json 导出清单对象:
import manifest from "../extension.json";
import { InventoryExtension } from "./inventory";
import { InventoryPanel } from "./inventory-panel";
export { manifest, InventoryExtension, InventoryPanel };
Studio 会扫描 bundle 的导出,注册继承自 Extension 的模块。
构建命令
npm run build # 单次生成 dist/index.js
npm run watch # 监听源码并持续构建
react、react-dom 和 SDK 由宿主提供单实例,模板会配置好 Vite 和类型依赖。
不要手动修改 sdk/。需要更新 SDK 时,应通过 Studio 的扩展开发流程重新同步。
发行内容
Studio 创建项目发行物时会复制 extension.json、ui/、assets/、dist/ 和清单指定的图标,不会复制 src/、sdk/ 或其他开发文件。如果 entry 指向 build/runtime/index.js 这类自定义构建目录,Studio 还会复制入口所在的整个顶层目录,确保关联分块、CSS 和 WASM 不会遗漏。
与 entry 无关的自定义顶层目录不会自动进入项目发行物。需要动态读取的文件应放在 assets/,或由构建流程输出到 dist/。