应用壳功能与配置参考
应用壳(@atomm-developer/generator-workbench)是标准生成器推荐使用的官方宿主壳层。它把 SDK 的平台能力和你的生成器挂载进统一的标准壳层 UI。
壳层能力总览
接入流程
按下列顺序初始化应用壳,顺序不能调换:
- 初始化
GeneratorSDK - 调用
defineGeneratorWorkbench()注册自定义元素(CDN 方式从window.GeneratorWorkbench.defineGeneratorWorkbench()取,调用必须执行——CDN 不会自动注册) - 把
sdk、生成器接入对象和config赋值给<generator-workbench>实例 - 调用
mount()
生命周期事件
| 事件 | 触发时机 |
|---|---|
workbench-shell-ready | 应用壳 UI 和 workspace 宿主可见 |
workbench-runtime-ready | 生成器挂载完成 |
workbench-ready | 兼容旧宿主,与 workbench-runtime-ready 同步派发 |
readyPolicy
readyPolicy 控制 mount() Promise 何时 resolve:
'runtime-ready'(默认):等生成器挂载完成后 resolve'shell-ready':在应用壳 UI 渲染完成后立即 resolve,生成器挂载继续在后台进行
分阶段 Loading 示例
const pageLoading = document.querySelector('#page-loading')
const workspaceSkeleton = document.querySelector('#workspace-skeleton')
workbench.config = {
title: 'Frame Generator',
mode: 'shell',
readyPolicy: 'shell-ready',
}
workbench.addEventListener('workbench-shell-ready', () => {
pageLoading?.remove()
workspaceSkeleton?.removeAttribute('hidden')
})
workbench.addEventListener('workbench-runtime-ready', () => {
workspaceSkeleton?.setAttribute('hidden', 'true')
})
await workbench.mount()推荐实践
- 在
workbench-shell-ready时移除页面级 loading - 在
workbench-runtime-ready之前,让 workspace 区域保留局部 skeleton - 如果生成器挂载失败,监听
workbench-error/config.onError,及时移除 skeleton 并切到错误态
性能标记
| 标记 | 打点时机 |
|---|---|
generator-workbench:mount:start | mount() 启动 |
generator-workbench:shell-ready | 与 workbench-shell-ready 同时 |
generator-workbench:runtime-ready | 与 workbench-runtime-ready 同时 |
generator-workbench:ready | 与兼容事件 workbench-ready 同时 |
宿主壳模式(config.mode)
workbench.config.mode 控制应用壳如何渲染外壳框架,决定生成器被挂载到什么样的容器结构里:
| 模式 | 外壳布局 | 适合场景 |
|---|---|---|
shell | 顶栏 + 右下角 fixed 浮动导出按钮,workspace 完全交给生成器自由布局 | AI 生成器、已有自定义布局的生成器 |
full | 顶栏 + 经典右侧 sidebar 分栏(canvas 区 + panel 区) | 标准编辑器分栏布局 |
template | 隐藏顶栏,外层页面自行接管品牌区和登录入口 | 由外层页面驱动的生成器场景 |
不确定选哪个?
从 shell 开始。它对生成器的约束最少,只提供顶栏和浮动导出按钮,整个工作区完全由你的生成器控制。
配置示例:
workbench.config = {
mode: 'shell', // 'shell' | 'full' | 'template'
title: 'My Generator',
}示例展示
shell 模式
保留顶部栏和右下角 fixed 导出按钮,整个 workspace 布局完全交给生成器。适合 AI 生成器或需要自定义工作区结构的生成器。
full 模式
保留顶部栏、右侧参数栏和侧栏底部导出区,适合需要官方标准分栏布局的生成器。
环境配置
应用壳的环境配置分为两层:
| 配置项 | 位置 | 控制范围 |
|---|---|---|
GeneratorSDK.init({ env }) | SDK 层 | 所有平台 API 的 base URL 以及 Passport 登录地域(US / CN) |
workbench.config.atommProEnv | 应用壳层 | 应用壳行为、社区模板接口路由、atomm-pro 弹窗上下文 |
atommProEnv 会自动从注入的 SDK 的 env 派生。 通常只需在 SDK 层设置一次 env,应用壳会自动保持同步:
const sdk = GeneratorSDK.init({ appKey: 'my-generator', env: 'prod_cn' })
workbench.sdk = sdk
workbench.config = {
// atommProEnv 不需要重复设置 —— 自动从 sdk.getEnv() 派生
}SDK env 取值
| 取值 | API Base URL | 鉴权地域 |
|---|---|---|
prod | https://api.xtool.com | US |
prod_cn | https://api.makeblock.com | CN |
pre | https://api-pre.xtool.com | US |
test | https://api-test.xtool.com | US |
dev | https://api-dev.makeblock.com | CN |
中国正式环境(prod_cn)
当 SDK env 设置为 prod_cn 时,以下应用壳行为自动生效:
- 所有平台 API 调用走
https://api.makeblock.com - Passport 登录使用 CN 鉴权地域
- 邀请入口 — 由应用壳自动隐藏,无需手动设置
invitationEnabled: false - Publish as Template 入口 — 由应用壳自动隐藏,无论
templateEnabled取何值 - 默认语言 — URL 中不含
?lang=时,应用壳默认使用zh而非en
导出与计费(Billing & Credits)
当注入的 SDK 提供 credits 和 billing 模块时,应用壳自动接管完整的导出链路,生成器不需要自己处理计费逻辑:
应用壳的自动行为:
- 登录后在顶栏展示当前积分余额
- 在导出按钮旁根据
sdk.billing.getUsage()展示计费提示 - 当
usage.isEnabled = false时隐藏export-credits-hint - 余额不足时,先拉起充值弹窗,充值成功后继续导出
- 真正执行导出前,先调用
sdk.billing.consume()作为计费闸门;若返回isBlacklisted = true,直接阻止导出并弹出错误提示 - 走积分路径时,导出成功后调用
sdk.billing.refreshCredits()
云保存与历史记录(Cloud Save & History)
开启方式:
workbench.config = {
cloudEnabled: true,
historyEnabled: true,
getCloudSaveOptions(context) {
return {
title: 'My Generator Draft',
snapshot: context.state,
}
},
}开启后,应用壳提供以下壳层动作:
| 动作 | 说明 |
|---|---|
保存草稿 按钮 | 在顶栏显示,手动触发云保存 |
历史记录 按钮 | 在顶栏显示,展示历史版本列表 |
workbench.saveToCloud() | 宿主主动调用云保存 |
workbench.loadHistory() | 宿主主动加载历史列表 |
封面来源的优先级:
config.getCloudSaveOptions(...)显式返回coverconfig.getCloudCover(...)被调用并返回非空值- 生成器在
params_change.data.cover里带了非空值(缓存后复用) - 以上均无,仍保存当前
snapshot,不携带封面
封面不是必须的
不要把「缺少 cover」当成「云保存未接入」。cover 是为草稿缩略图和历史列表提供的增强能力,不是保存业务状态的必要条件。
getCloudCover
如果已有画布导出能力,但不想重构整个 getCloudSaveOptions,可以单独提供封面钩子:
import { exportCoverPreview } from './runtime/export'
workbench.config = {
cloudEnabled: true,
autoSaveEnabled: true,
getCloudSaveOptions(context) {
return {
title: 'My Generator Draft',
snapshot: context.state,
}
},
async getCloudCover() {
return await exportCoverPreview({ format: 'png' })
},
}Cloud Bootstrap 路由流程
当 cloudEnabled 打开时,应用壳在生成器挂载完成后会在后台评估路由引导:
- 路由带有
gid且已登录 → 调用sdk.cloud.restore(gid) - 路由带有
gid但未登录 → 展示轻量提示,等待用户显式登录后再绑定(不自动恢复,避免覆盖本地编辑) - 路由带有
templateId但无gid→ 请求社区模板并恢复到生成器 - 路由无
gid且已登录 → 自动执行首次云保存,把返回的 id 写回路由 - 路由无
gid且未登录 → 跳过首次自动建单,等用户显式保存时再创建 ?mode=embed下 → 即使cloudEnabled: true,cloud bootstrap 也会被跳过
自动保存(Auto-Save)
同时满足以下条件时,应用壳会在生成器状态变化后做 debounce 自动保存:
workbench.config = {
cloudEnabled: true,
autoSaveEnabled: true,
getCloudSaveOptions(context) {
return {
title: 'My Generator Draft',
snapshot: context.state,
}
},
}- 生成器必须实现
subscribe(listener)接口 params_change事件触发时,应用壳 debounce 后写入云保存- 如果
params_change.data.cover带有非空值,缓存后在下次保存时自动补回
邀请弹窗(Invitation)
默认情况下,顶栏 credits 徽标左侧会显示 Earn Credits 邀请入口。接入时需要:
workbench.config = {
atommProEnv: 'prod', // 或从 SDK env 自动派生
atommProDomain: 'atomm',
}注意事项:
- 邀请入口在未登录时也会展示,点击后先调用
sdk.auth.login(),登录完成后再打开邀请弹窗 - 隐藏邀请入口:显式传
config.invitationEnabled = false - 未显式传
invitationConfigKey时,应用壳默认使用generator_${sdk.getAppKey()}
数据分析上报(Analytics)
应用壳默认为 Download 和 Open in Studio 内置了数据分析上报,无需额外配置。如果需要自定义 payload:
import { createGlowSensorsReporter } from '@atomm-developer/generator-workbench'
workbench.config = {
analytics: {
reporter: createGlowSensorsReporter({
resolveExportPayload({ config, runtime, sdk }) {
const state = runtime.getState()
return {
content_type: config.title,
content_id: sdk.getAppKey?.() || '',
element_name: String(state.params?.vars?.kerf_offset ?? ''),
content_name: String(state.params?.vars?.material_preset ?? ''),
}
},
}),
},
}内置 reporter 默认上报:
| 字段 | 说明 |
|---|---|
| 事件名 | Generator_export |
click_position | download 或 openinstudio |
scene_name | 默认按运行环境取 studio(Studio/XCS Electron UA)或 atomm |
scene_source | 默认按视口宽度取 mobile(< 768px)或 desktop |
item_type | 默认取 sdk.getAppKey() |
| GA4 目标 | window.dataLayer.push(...) |
| Sensors 目标 | window.sensors.track(...) |
顶栏 Publish as Template 点击时,同一个 reporter 还会上报 publishTemplateClick 事件。
Embed 模式
当 URL 带有 ?mode=embed 时,应用壳进入精简壳层模式。详见 核心概念 → 路由能力模式。
iframe bridge 通信协议
?mode=embed 下应用壳自动启动 iframe bridge:
| 方向 | 事件 | 说明 |
|---|---|---|
| iframe → 父页面 | generator_pageLoaded | bridge ready 信号,应作为唯一的握手时机 |
| 父页面 → iframe | generator_loadTemplateData | 加载模板,通过 sdk.template.applyToRuntime(...) 回填 |
| 父页面 → iframe | generator_setGeneratorData | 恢复 snapshot,通过 runtime.setState(...) 回填到生成器 |
| 父页面 → iframe | generator_getTemplateData | 获取当前模板 JSON + info + cover |
| 父页面 → iframe | generator_getFile | 获取导出文件(优先走 config.embedBridge.getExportData) |
| iframe → 父页面 | generator_toTemplateLoaded | generator_loadTemplateData 回执 |
| iframe → 父页面 | generator_toTemplateData | 模板数据回传 |
| iframe → 父页面 | generator_toFile | 导出文件回传 |
| iframe → 父页面 | generator_toFileError / generator_toTemplateError | 错误回传 |
握手最佳实践:
- 把
generator_pageLoaded作为唯一的 bridge ready 信号,不要用iframe.onload - 父页面先缓存
generator_loadTemplateData/generator_setGeneratorData,等收到generator_pageLoaded后再 flush - 模板初始化优先使用
generator_loadTemplateData,有明确的generator_toTemplateLoaded回执
Embed 适配等级
| 等级 | 说明 | 验收标准 |
|---|---|---|
embed-basic | 最小接入:隐藏应用壳 chrome,启动 bridge,生成器接收模板/snapshot | ?mode=embed 下顶栏和导出区隐藏;生成器能通过 bridge 接收模板并 setState() |
embed-canvas-only | 生成器只渲染画布,隐藏侧边栏/模板列表/导航 | 包含 embed-basic 所有标准;移动端只有画布可见 |
embed-canvas-panel | 生成器支持独立 canvas + panel 挂载,宿主可分别放入不同 DOM 容器 | 包含 embed-basic 所有标准;getPanelSchema() 支持 panelFilter;target: 'canvas' 时不显示参数面板 UI |
从哪个等级开始?
默认从 embed-basic 开始。只有当模板页需要展示来自生成器的可编辑参数面板时,才升级到 embed-canvas-panel。
模板发布(Template Publish)
开启条件:templateEnabled: true。开启后,顶栏显示 Publish as Template 按钮。
点击发布按钮时,应用壳的处理流程:
- 确保用户已登录
- 从生成器的
getPanelSchema()推导可导出的bind.path集合 - 通过
sdk.template.build(...)生成标准模板 JSON - 尝试通过
config.embedBridge.getExportData('cover', ...)解析封面;未提供时回退到 SDK export provider - 懒加载并挂载
@atomm/atomm-pro的PublishTemplateModal - 打开发布弹窗,并传入封面、模板 JSON、生成器信息等字段
字段来源速查:
| 字段 | 默认来源 |
|---|---|
generatorImage | template_publish_media_change.data.generatorImage → originImageUrl → 封面 data URL |
generatorTag | 生成器最近一次 select_template 事件 data.name → config.getTemplateMeta()?.generatorTag |
initialData.cover | template_publish_media_change.data.cover → 封面 data URL |
generatorInfo.generatorName | config.getTemplateMeta()?.title → config.title |
generatorInfo.info | 最新生成器状态映射到云 info 结构(由应用壳构建) |
generatorInfo.template | sdk.template.build(...) |
getTemplatePublishPayload
如果默认字段解析链路无法自动覆盖,使用聚合型钩子覆盖特定字段:
import { exportCoverPreview } from './runtime/export'
workbench.config = {
templateEnabled: true,
async getTemplatePublishPayload(context) {
const coverDataUrl = await exportCoverPreview({ format: 'png' })
const state = context.runtime.getState()
return {
generatorImage: coverDataUrl,
generatorTag: state.selectedTemplateName ?? '',
cover: coverDataUrl,
originImageUrl: state.originImageUrl ?? '',
}
},
}应用壳把返回对象作为覆盖层叠加在现有解析链路之上。只有显式返回的字段才会被覆盖,未返回的字段继续走内置默认逻辑。
isAdminPublishTemplate
只有社区管理员才能看到发布按钮时使用:
workbench.config = {
templateEnabled: true,
isAdminPublishTemplate: true,
}开启后,只有 auth.userInfo.isCommunityAdmin === true 时才显示 Publish as Template 按钮。应用壳会在登录、登出、切换账号时自动刷新显隐状态。
生成器与应用壳通信
应用壳与生成器之间的核心通信机制:
- 生成器通过
mount({ routeMode })读取当前路由能力模式 - 生成器通过
runtime.subscribe(listener)上报业务事件给应用壳 - 应用壳通过
workbench.dispatchRuntimeCommand(...)发送反向命令给生成器
当前内置通信行为:
| 事件 / 命令 | 触发链路 |
|---|---|
state-change | 生成器上报 → auto-save debounce 编排 |
params_change | 生成器上报 → 派发 DOM 事件 runtime-params-change |
select_template | 生成器上报 → 派发 DOM 事件 runtime-select-template |
select_template(embed) | 生成器上报 → 父页面 bridge 事件 generator_toSelectTemplate |
完整事件表和载荷约定,详见 应用壳与生成器通信。
调试配置
开发阶段,可在控制台输出内部 payload,无需打开 DevTools 网络面板:
workbench.config = {
debug: {
logCloudPayload: true, // 每次保存时打印完整云保存 payload
logTemplatePublishPayload: true, // 发布弹窗打开时打印完整模板发布 payload
warnOnMissingTemplateFields: true, // 模板关键字段为空时输出 warning
},
}所有选项默认为 false。debug 配置对生产行为没有任何影响,上线前请移除或设为 false。
典型使用流程:
- 验证云保存
snapshot和cover时,开启logCloudPayload - 验证模板发布字段时,开启
logTemplatePublishPayload - 接入初期开启
warnOnMissingTemplateFields,及时发现空字段
推荐使用方式
- 新建 Vue 生成器时,优先使用 Vue 脚手架启动开发,通过一条命令生成已接入
generator-workbench的标准项目;需要理解目录和配置时再看 Vue 脚手架结构说明 - 新的标准生成器优先使用应用壳来承载统一平台壳层
- AI 生成器或快速接入生成器,优先使用
shell模式,让生成器接管整个 workspace - 只有当明确需要经典右侧参数栏分栏布局时,再使用
full模式 - 只有当明确需要非标准壳层时,才建议绕开应用壳自行定制整页布局
- 复杂的 iframe 宿主设置、遗留 bridge 兼容,应视为高级接入模式,而非每个生成器的默认路径
安装说明
CDN 加载行为、Vue 自动加载以及 atomm-ui 样式 / 脚本说明统一放在 安装与引入 中。
相关文档
- 核心概念 — 心智模型与术语解释
- Vue 脚手架启动开发 — 从零创建并启动 Vue 3 + Vite 标准生成器
- Vue 脚手架结构说明 — 目录、配置、Runtime Contract 和能力升级说明
- 手把手接入教程(Basic 档位) — 已有生成器快速接入
- 应用壳与生成器通信 — 完整事件表和载荷约定
- 主站 Embed 宿主接入 — iframe 通信时序和 bridge 握手
- 应用壳升级 — 已有生成器跟进新壳层能力
- 接入自检清单 — 接入问题排查
- 生成器接入协议 — 应用壳与生成器之间的协议细节
- 安装与引入