workshop.events监听换屏、开局、固定步、敌人生成/死亡、玩家受伤和结算事件,只能收到公开快照,不能修改内部游戏对象。
作者声明:只影响本地表现
《星尘战线Stardust-frontline V2.3》创意工坊
收藏用于稍后查找;“开启”决定下次启动时加载哪些 Mod。所有已开启 Mod 会一起进入游戏。
推荐方式 · 不需要懂编程
Prompt 只注入作品、能力、依赖和你的 Mod ID,并要求 Agent 实时读取唯一官方 Skill;固定命令与规则不再复制到任务文本中。
发布 Mod 时必须声明使用哪些能力。以下内容是作者约定,平台不会扫描或限制 Mod 代码;只安装你信任的内容。
联机策略:游戏进入联机前应禁用全部 Mod
workshop.events监听换屏、开局、固定步、敌人生成/死亡、玩家受伤和结算事件,只能收到公开快照,不能修改内部游戏对象。
作者声明:只影响本地表现
catalog.read读取版本、机体、武器和敌人类型的深拷贝,用于 Mod 自己的 UI 或兼容性判断;不能覆写或注册新目录项。
作者声明:只影响本地表现
rules.run-modifiers在 0.5–2.0 范围内调整本地玩家移速、普通投射物伤害、承伤、敌人生命值和掉落倍率;不改变技能、光束、队友或内部数据表。
作者声明:联机时不应使用
ui.overlay在独立的 Workshop overlay 根节点中添加 Mod 自有 HUD/遥测内容;不能查询、覆盖或替换游戏私有 DOM。
作者声明:只影响本地表现
audio.builtin-cues通过游戏音频总线播放有限的内置 cue;不能读取账号音频资源、替换音频管线或声明自定义音频已获得权限。
作者声明:只影响本地表现
visual.skins绑定既有机体并替换 battle-only 战斗贴图,或提供完整的 battle/fleet/prep/codex/pilot 五类贴图;不改变数值、技能、武器、碰撞或原始资源。
作者声明:只影响本地表现
Agent 会同时收到下面这份本游戏专属规范。
版本:2.2
Workshop API:1.1.0
联机策略:mods-disabled
本文件是作者与 Mod 创作者之间的开发约定。能力声明用于说明兼容范围,不是安全沙箱;平台不会扫描或限制 Mod 代码。Mod 代码仍然运行在页面上下文中,作者应只使用本文列出的公共 API,不要把任何秘密放入 Mod。
当前版本适合制作以下类型的本地 Mod:
本版本没有公开新增机体、新武器、新敌人、新关卡或覆盖原始数据表的注册器。皮肤只能绑定既有机体并替换视觉资源,不会改变数值、技能、武器、碰撞或原始资源。
官方 Loader 在 index.html 中先加载。游戏随后按以下顺序工作:
window.StardustFrontlineWorkshop(兼容别名:window.StardustFrontlineModApi)。window.VibeHubWorkshop.beforeStart;Loader 会按平台决定的顺序加载 before-start Mod。window.VibeHubWorkshop.markGameReady()。window.VibeHubWorkshop.afterStart;Loader 再按顺序加载 after-start Mod。适合 before-start 的内容:注册局内规则、注册事件监听、读取目录、准备不依赖游戏 DOM 的纯数据。
适合 after-start 的内容:创建 HUD overlay、读取首个运行态快照、绑定只在游戏启动后才有意义的表现。
registerRunModifier() 只在下一次 engine.start(world) 时应用。after-start 阶段注册规则不会追溯改变正在进行的战斗;请不要依赖这一行为做即时改数值。
const api = window.StardustFrontlineWorkshop;
api.apiVersion; // "1.1.0"
api.game; // { id: "stardust-frontline", version: "2.2" }
api.getState(); // 全新只读快照,不是内部 world/state 引用
api.getEnabledMods(); // [{ id, title, version, loadPhase, capabilities }]
api.getMultiplayerPolicy(); // "mods-disabled"
getState() 的主要结构如下,字段可能随 API 小版本增加,但不会把内部实体对象直接交给 Mod:
{
apiVersion, gameId, gameVersion,
context: { screen, previousScreen, mode, difficulty },
rules: { playerSpeedMul, playerProjectileDamageMul,
playerDamageTakenMul, enemyHpMul, dropRateMul },
world: {
mode, width, height, bounded, elapsed,
player: { x, y, hp, maxHp, shield, shieldMax, dead, classId, skinId, weaponId } | null,
teammate: { hp, maxHp, dead, classId } | null,
enemies: [{ id, type, x, y, hp, maxHp, dead, boss }],
counts: { enemies, liveEnemies, bullets, drops, particles },
objective: { x, y } | null,
stats
} | null
}
const stop = api.events.on('enemy:defeated', payload => {
console.log(payload.enemy.type, payload.state.world.stats);
});
stop();
可订阅事件:
| 事件 | 参数 | 说明 |
|---|---|---|
screen:changed | { id, previous } | 游戏屏幕路由改变 |
world:created | { state } | 三种模式统一完成 engine.start(world) |
world:tick | { dt, state } | 未暂停时每个固定逻辑步一次;不要在此做重 CPU 工作 |
enemy:spawned | { enemy, state } | 新敌人进入当前世界 |
enemy:defeated | { enemy, state } | 目标自身进入死亡状态后统一结算;enemy.dead 为 true |
player:damaged | { amount, x, y, state } | 玩家实际承受一次伤害后触发;闪避/无敌不触发 |
run:ended | `{ outcome: "victory" | "defeat", state }` |
skin:changed | { type, skinId, baseClassId, scope? } | 皮肤注册、注销或当前选择改变 |
事件参数都是序列化快照。事件处理器抛出的异常会被隔离并记录,不会故意中断游戏;异步处理器应自行控制生命周期并在取消时调用返回的取消函数。
const dispose = api.rules.registerRunModifier('example.neon-hard', {
playerSpeedMul: 1.1,
playerProjectileDamageMul: 0.9,
playerDamageTakenMul: 1.2,
enemyHpMul: 1.15,
dropRateMul: 0.85,
});
api.rules.list(); // 已注册规则 ID,按 ID 排序
api.rules.getActive(); // 叠加后的实际规则
dispose();
每个字段都必须在 0.5 到 2.0 之间,缺省为 1:
playerSpeedMul:只影响本地玩家移动速度。playerProjectileDamageMul:只影响本地玩家普通投射物命中伤害;不改技能、光束、队友或敌弹伤害。playerDamageTakenMul:只影响本地玩家实际承伤;不改队友承伤。enemyHpMul:敌人进入世界时统一调整生命值,覆盖战役、无尽和防卫模式中新生成的敌人。dropRateMul:调整敌人掉落概率/倍率,仍保留 Boss 必掉和游戏原有掉落规则。多个 Mod 同时注册时,按规则 ID 的字典序相乘,最终每个字段限制在 0.5–2.0。没有优先级、覆盖和“最后写入获胜”语义。
const classes = api.catalog.getClasses(); // 深拷贝
const weapons = api.catalog.getWeapons(); // 深拷贝
const enemyTypes = api.catalog.getEnemyTypes(); // 深拷贝
const disposeOverlay = api.ui.registerOverlay('example.telemetry', (host, api) => {
host.textContent = 'STARDUST TELEMETRY';
const off = api.events.on('world:tick', ({ state }) => {
host.textContent = `LIVE ENEMIES: ${state.world?.counts.liveEnemies ?? 0}`;
});
return () => off();
});
api.audio.playCue('uiClick');
registerOverlay(id, mount) 会把 Mod 内容放入公开的 #vibehub-workshop-root 下,并传入独立 host。Mod 应用自己的类名和样式,可通过 Loader manifest 的 stylesheet 加载 CSS;不要查询或覆盖游戏私有选择器。mount 返回的清理函数会在注销时调用。
允许的音效 cue:uiClick、shoot、hit、hitCrit、kill、pickup、weaponDrop、upgradeOpen、waveStart、explode、skillCast、beacon、boost。
皮肤 ID 使用与规则相同的全局唯一格式。assets 的五个 surface 是明确的显示位置:
battle:战斗中玩家与僚机的机体贴图。fleet:舰队终端及其机体预览。prep:战前准备页的机体预览。codex:图鉴机体卡与档案预览。pilot:舰队、HUD 和图鉴驾驶员立绘。battle-only 只要求 battle,其它位置保持游戏原始资源;full 必须完整提供五类资源。资源必须是带透明背景的 PNG/WebP(或浏览器可加载的 data/blob URL),跨源图片服务器必须允许 CORS:
const api = window.StardustFrontlineWorkshop;
const asset = (path) => api.assets.resolve('author.neon-skin', path);
const dispose = api.skins.register('author.neon-ranger', {
baseClassId: 'ranger',
name: '霓虹游星',
author: 'author',
version: '1.0.0',
scope: 'full',
assets: {
battle: { src: asset('assets/ranger-battle.png'), maxSpan: 54 },
fleet: { src: asset('assets/ranger-fleet.png'), maxSpan: 54 },
prep: { src: asset('assets/ranger-prep.png'), maxSpan: 54 },
codex: { src: asset('assets/ranger-codex.png'), maxSpan: 54 },
pilot: { src: asset('assets/ranger-pilot.png') },
},
});
api.skins.setActive('author.neon-ranger');
api.skins.getActive('ranger');
api.skins.clearActive('ranger');
// 注销时调用 dispose;当前选择会在独立 Workshop 偏好中保留,重新加载 Mod 后可恢复。
api.assets.resolve(modId, path) 会把 Mod 包内相对路径解析为可加载 URL。不要把相对路径直接交给 register(),除非它确实相对于当前游戏页面。api.skins.list(baseClassId) 返回深拷贝,包含 scope 与实际提供的 surface,可用于 Mod 自己的皮肤选择器。
皮肤接口只管理贴图和选择状态。游戏仍使用既有机体定义;皮肤选择写入独立的 stardust_frontline_workshop_skin_v1 页面偏好,不写入游戏存档。资源加载失败时,当前 surface 回退到原始游戏资源。
下面的代码可作为一个 before-start classic Mod 的入口。它只使用公开 API,在每局开始时注册一个轻微的本地规则,并通过公开事件显示敌人计数:
(() => {
const api = window.StardustFrontlineWorkshop;
if (!api || api.game.id !== 'stardust-frontline' || api.game.version !== '2.2') return;
api.rules.registerRunModifier('example.frontier-signal', {
playerSpeedMul: 1.05,
dropRateMul: 1.1,
});
api.events.on('world:created', ({ state }) => {
console.log('[frontier-signal] mode:', state.context.mode);
});
api.events.on('enemy:defeated', ({ state }) => {
document.title = `星尘战线 · ${state.world?.stats?.kills ?? 0} KILLS`;
});
})();
若 Mod 使用 after-start,应把 overlay 注册放在该阶段,并先检查 api.getState().world 是否存在。Mod 不需要、也不应自行调用游戏启动函数。
游戏内置的 StardustFrontlineWorkshop API 本身就是可供其他 Mod 共同使用的基础前置:它提供版本、目录、快照、事件、受限规则、overlay 和内置音效。没有额外的“基础 Mod”需要安装,也没有跨 Mod 私有对象依赖契约。
before-start Mod 可以依赖内置 API;不能依赖另一个 Mod 已经创建的全局变量、DOM 节点或注册顺序。after-start Mod 可以依赖内置 API 已经可用;不能假设某个 before-start Mod 或其他 after-start Mod 一定成功加载。author.mod.enemy-hp。localStorage、save/save.json 或其他游戏存档。Mod 如需自己的配置,应使用自己的命名空间并遵守平台 Mod 约定,不得改写游戏存档。mods-disabled:将来进入任何联机流程前,游戏应检查 VibeHubWorkshop.getEnabledMods(),只要有已启用 Mod 就拒绝进入联机;不能声称能力声明能阻止越权代码。before-start Mod 先加载,游戏初始化后再加载 after-start Mod;具体 Mod 之间不要依赖隐含加载先后。2.2、Workshop API 1.1.x。Mod 应在入口检查 api.game.version 和 api.apiVersion;不匹配时安全退出。大版本或字段语义变化时需要发布新的 Mod 兼容版本。blocked 联机能力。禁止 Mod:
state、world、player、敌人实例、原型链或内部模块函数;不要 monkey-patch、覆盖 import 或依赖私有 DOM 选择器。登录后可以上传完整 Mod 包或单脚本。
登录反馈渠道
有任何问题、建议或反馈,请加 VibeHub 官方支持群:
QQ 752883513
进群后请直接在群里提反馈,我们会及时关注并处理。