@fps-games/vfx 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @fps/vfx
|
|
1
|
+
# @fps-games/vfx
|
|
2
2
|
|
|
3
3
|
Babylon.js 共享 VFX 特效库。导入即用 + 项目内调试面板。消费模型 = **模型 C**(runtime/类型来自包,本地 `import.meta.glob` 装配注册表);发布 = **做法A**(dist 提交进 git + tag,消费端 clone 即用,无需 build)。
|
|
4
4
|
|
|
@@ -15,12 +15,12 @@ Babylon.js 共享 VFX 特效库。导入即用 + 项目内调试面板。消费
|
|
|
15
15
|
|
|
16
16
|
```jsonc
|
|
17
17
|
// package.json —— git tag 即版本锁
|
|
18
|
-
"@fps/vfx": "
|
|
18
|
+
"@fps-games/vfx": "^0.3.4"
|
|
19
19
|
```
|
|
20
20
|
```ts
|
|
21
21
|
// src/assets/vfx/index.ts —— 装配注册表(模型 C)
|
|
22
|
-
import { buildRegistry, type VfxRegistry } from '@fps/vfx';
|
|
23
|
-
export * from '@fps/vfx';
|
|
22
|
+
import { buildRegistry, type VfxRegistry } from '@fps-games/vfx';
|
|
23
|
+
export * from '@fps-games/vfx';
|
|
24
24
|
const modules = import.meta.glob('./effects/*/index.ts', { eager: true }) as Record<string, Record<string, unknown>>;
|
|
25
25
|
const params = import.meta.glob('./effects/*/vfx-params.json', { eager: true }) as Record<string, { default: unknown }>;
|
|
26
26
|
export const VFX_REGISTRY: VfxRegistry = buildRegistry({ modules, params });
|
|
@@ -31,7 +31,7 @@ const svc = new EffectPackageService(scene, { registry: VFX_REGISTRY });
|
|
|
31
31
|
svc.playEffectPackage('thruster-flame', {}, { parent: engineSocket, offsetIsLocal: true });
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
> ⚠️ 三个最易漏:① `@fps/vfx` 要加进 vite 构建白名单;② Babylon 要 `resolve.dedupe`;③ glob 只扫本地 `effects/*`,每个要用的特效都得建本地桩(re-export 库内预制即可)。详见 [INTEGRATION.md](./docs/INTEGRATION.md)。
|
|
34
|
+
> ⚠️ 三个最易漏:① `@fps-games/vfx` 要加进 vite 构建白名单;② Babylon 要 `resolve.dedupe`;③ glob 只扫本地 `effects/*`,每个要用的特效都得建本地桩(re-export 库内预制即可)。详见 [INTEGRATION.md](./docs/INTEGRATION.md)。
|
|
35
35
|
|
|
36
36
|
## 开发
|
|
37
37
|
|
|
@@ -38,7 +38,7 @@ export interface CreateTreasureAttentionOptions {
|
|
|
38
38
|
renderingGroupId?: number;
|
|
39
39
|
glowLayer?: GlowLayer | null;
|
|
40
40
|
disposeRoot?: boolean;
|
|
41
|
-
/** 经 @fps/vfx 包播放时为 true:root 的 transform 归 service 独占(placement/挂载由 service 管),特效不写 root.position(G6)。 */
|
|
41
|
+
/** 经 @fps-games/vfx 包播放时为 true:root 的 transform 归 service 独占(placement/挂载由 service 管),特效不写 root.position(G6)。 */
|
|
42
42
|
serviceOwnedRoot?: boolean;
|
|
43
43
|
}
|
|
44
44
|
export interface TreasureAttentionHandle extends VfxEffectHandle {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fps-games/vfx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared VFX library for Playable projects: engine-injected effect packages + runtime. Project-pure (no imports of host project code).",
|
|
6
6
|
"publishConfig": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"demo:treasure-attention": "vite demo/treasure-attention --host 127.0.0.1",
|
|
46
46
|
"release": "node scripts/release.mjs"
|
|
47
47
|
},
|
|
48
|
-
"//": "分发=git tag + 提交 dist(做法A):发版前 pnpm build → 提交 dist/ → git tag。消费端 import '@fps/vfx' 解析到 dist;本地开发可用 FPS_VFX_LIBRARY_REPO 切回源码 alias。",
|
|
48
|
+
"//": "分发=git tag + 提交 dist(做法A):发版前 pnpm build → 提交 dist/ → git tag。消费端 import '@fps-games/vfx' 解析到 dist;本地开发可用 FPS_VFX_LIBRARY_REPO 切回源码 alias。",
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@babylonjs/core": "^8.56.2",
|
|
51
51
|
"@babylonjs/loaders": "^8.56.2",
|
package/tooling/vfx-cli.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// @fps/vfx CLI:把库特效以「re-export 桩 + 本地 vfx-params.json」装进项目(plan §6.2/§16 混合分发 模型C),
|
|
2
|
+
// @fps-games/vfx CLI:把库特效以「re-export 桩 + 本地 vfx-params.json」装进项目(plan §6.2/§16 混合分发 模型C),
|
|
3
3
|
// 并管理版本升级(issue #4)。消费方典型调用:
|
|
4
|
-
// node node_modules/@fps/vfx/tooling/vfx-cli.mjs <cmd> --project .
|
|
4
|
+
// node node_modules/@fps-games/vfx/tooling/vfx-cli.mjs <cmd> --project .
|
|
5
5
|
//
|
|
6
6
|
// list 列出库里可用特效
|
|
7
7
|
// add <id> [--project <dir>] [--force] 装一个特效(桩 + vfx-params.json + .vfx-source.json)
|
|
8
|
-
// outdated [--project <dir>] 对比项目钉的 @fps/vfx 版本 / 各特效 provenance vs 最新
|
|
8
|
+
// outdated [--project <dir>] 对比项目钉的 @fps-games/vfx 版本 / 各特效 provenance vs 最新
|
|
9
9
|
// update [<id>] [--project <dir>] [--to vX.Y.Z]
|
|
10
|
-
// 升级:改 package.json 的 @fps/vfx git-tag ref + 重同步桩
|
|
10
|
+
// 升级:改 package.json 的 @fps-games/vfx git-tag ref + 重同步桩
|
|
11
11
|
// + 不动 vfx-params.json + 打印 CHANGELOG 区间(然后 pnpm install)
|
|
12
12
|
import { readdirSync, statSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs';
|
|
13
13
|
import { execFileSync } from 'node:child_process';
|
|
@@ -16,6 +16,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
16
16
|
|
|
17
17
|
const LIB_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
18
18
|
const LIB_EFFECTS = join(LIB_ROOT, 'packages', 'effects');
|
|
19
|
+
const PACKAGE_NAME = '@fps-games/vfx';
|
|
19
20
|
const LIB_VERSION = (() => { try { return JSON.parse(readFileSync(join(LIB_ROOT, 'package.json'), 'utf8')).version; } catch { return '0.0.0'; } })();
|
|
20
21
|
const LIB_INDEX = (() => {
|
|
21
22
|
try { return JSON.parse(readFileSync(join(LIB_ROOT, 'index.json'), 'utf8')); } catch { return null; }
|
|
@@ -45,11 +46,11 @@ function hasLibEffect(id) {
|
|
|
45
46
|
return libEffectIds().includes(id) || existsSync(join(LIB_EFFECTS, id, 'vfx-params.json'));
|
|
46
47
|
}
|
|
47
48
|
function stub(id) {
|
|
48
|
-
return `//
|
|
49
|
+
return `// ${PACKAGE_NAME} re-export 桩(代码/资源在包内;本地仅 vfx-params.json + 此桩)。\nexport * from '${PACKAGE_NAME}/effects/${id}';\n`;
|
|
49
50
|
}
|
|
50
51
|
function effectsDestDir() { return join(projectRoot, 'src', 'assets', 'vfx', 'effects'); }
|
|
51
52
|
function provenance(id, version) {
|
|
52
|
-
return JSON.stringify({ id, source:
|
|
53
|
+
return JSON.stringify({ id, source: PACKAGE_NAME, version }, null, 2) + '\n';
|
|
53
54
|
}
|
|
54
55
|
function normVer(v) { return String(v ?? '').replace(/^v/, ''); }
|
|
55
56
|
function semverCmp(a, b) {
|
|
@@ -58,17 +59,17 @@ function semverCmp(a, b) {
|
|
|
58
59
|
return 0;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
// 读项目 package.json 里的
|
|
62
|
+
// 读项目 package.json 里的 VFX 依赖(原始文本 + 解析值)。
|
|
62
63
|
function readProjectVfxDep() {
|
|
63
64
|
const p = join(projectRoot, 'package.json');
|
|
64
65
|
if (!existsSync(p)) return null;
|
|
65
66
|
const raw = readFileSync(p, 'utf8');
|
|
66
67
|
const json = JSON.parse(raw);
|
|
67
68
|
for (const field of ['dependencies', 'devDependencies', 'optionalDependencies']) {
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
69
|
+
const deps = json[field] ?? {};
|
|
70
|
+
if (deps[PACKAGE_NAME]) return { path: p, raw, json, field, packageName: PACKAGE_NAME, value: deps[PACKAGE_NAME] };
|
|
70
71
|
}
|
|
71
|
-
return { path: p, raw, json, field: null, value: null };
|
|
72
|
+
return { path: p, raw, json, field: null, packageName: null, value: null };
|
|
72
73
|
}
|
|
73
74
|
function pinFromValue(value) { const m = String(value ?? '').match(/#v?(\d+\.\d+\.\d+)/); return m ? m[1] : null; }
|
|
74
75
|
function repoUrlFromValue(value) { return String(value ?? '').replace(/#.*$/, ''); }
|
|
@@ -150,7 +151,7 @@ function outdated() {
|
|
|
150
151
|
const latestSource = remote ? '远端最新 tag' : `本库版本(远端不可达,回退)`;
|
|
151
152
|
|
|
152
153
|
console.log(`项目:${projectRoot}`);
|
|
153
|
-
console.log(
|
|
154
|
+
console.log(`${dep.packageName ?? PACKAGE_NAME} 钉版本:${pin ? `v${pin}` : '(未钉 / 非 git-tag)'} → 最新:v${latest}(${latestSource})`);
|
|
154
155
|
const depBehind = pin && semverCmp(pin, latest) < 0;
|
|
155
156
|
console.log(depBehind ? `⬆ 依赖落后:可升级到 v${latest}(\`vfx update --to v${latest}\` + pnpm install)` : `✓ 依赖已是最新(或无法判定)。`);
|
|
156
157
|
|
|
@@ -162,7 +163,7 @@ function outdated() {
|
|
|
162
163
|
const tag = v == null ? '无 provenance(早期批量安装)' : (semverCmp(v, latest) < 0 ? `v${v} ⬆ 落后` : `v${v} ✓`);
|
|
163
164
|
console.log(` - ${e.id} [${tag}]`);
|
|
164
165
|
}
|
|
165
|
-
console.log(`\n注:模型C 下特效代码/资源在
|
|
166
|
+
console.log(`\n注:模型C 下特效代码/资源在 ${PACKAGE_NAME} 包内,真实版本由上面的依赖钉版本决定;`);
|
|
166
167
|
console.log(` .vfx-source.json 仅作 add 时的来源记录,落后不影响运行(随依赖升级即同步)。`);
|
|
167
168
|
} else {
|
|
168
169
|
console.log(`\n(项目 ${effectsDestDir()} 下暂无已装特效)`);
|
|
@@ -178,7 +179,7 @@ function update(onlyId) {
|
|
|
178
179
|
const toFlag = flagVal('--to');
|
|
179
180
|
const target = normVer(toFlag ?? latestRemoteTag(repoUrl) ?? LIB_VERSION);
|
|
180
181
|
|
|
181
|
-
// 1) 改 package.json 的
|
|
182
|
+
// 1) 改 package.json 的 VFX git-tag ref(保留原 url 与格式,仅换 #ref)。
|
|
182
183
|
const isGitDep = /(^git\+|:\/\/|github\.com|\.git)/.test(dep.value ?? '');
|
|
183
184
|
if (dep.field && dep.value && (/#/.test(dep.value) || isGitDep)) {
|
|
184
185
|
let newValue;
|
|
@@ -186,21 +187,22 @@ function update(onlyId) {
|
|
|
186
187
|
else newValue = `${dep.value}#v${target}`;
|
|
187
188
|
if (newValue !== dep.value) {
|
|
188
189
|
// 原文本就地替换,避免重排整份 package.json;用替换函数避免 newValue 里的 $ 被当替换记号。
|
|
189
|
-
const
|
|
190
|
+
const depName = dep.packageName ?? PACKAGE_NAME;
|
|
191
|
+
const depValRe = new RegExp(`("${depName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"\\s*:\\s*")${dep.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(")`);
|
|
190
192
|
const newRaw = dep.raw.replace(depValRe, (_m, p1, p2) => `${p1}${newValue}${p2}`);
|
|
191
193
|
if (newRaw !== dep.raw) {
|
|
192
194
|
writeFileSync(dep.path, newRaw);
|
|
193
|
-
console.log(`✓ package.json
|
|
195
|
+
console.log(`✓ package.json:${depName} ${oldPin ? `#v${oldPin}` : dep.value} → ${PACKAGE_NAME}#v${target}`);
|
|
194
196
|
} else {
|
|
195
|
-
console.warn(`! 未能就地替换
|
|
197
|
+
console.warn(`! 未能就地替换 ${depName} 依赖文本,请手动把 ref 改成 ${PACKAGE_NAME}#v${target}。`);
|
|
196
198
|
}
|
|
197
199
|
} else {
|
|
198
|
-
console.log(`= package.json
|
|
200
|
+
console.log(`= package.json:${dep.packageName ?? PACKAGE_NAME} 已是 #v${target}。`);
|
|
199
201
|
}
|
|
200
202
|
} else if (dep.field && dep.value) {
|
|
201
|
-
console.warn(`!
|
|
203
|
+
console.warn(`! ${dep.packageName ?? PACKAGE_NAME} 依赖 "${dep.value}" 不是 git-tag 形式,跳过 ref 升级(仅重同步桩)。如需固定版本,请手动改成 git+ssh://…#v${target}。`);
|
|
202
204
|
} else {
|
|
203
|
-
console.warn(`! 项目 package.json 未声明
|
|
205
|
+
console.warn(`! 项目 package.json 未声明 ${PACKAGE_NAME} 依赖,跳过 ref 升级(仅同步桩)。`);
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
// 2) 重同步桩 + bump .vfx-source.json(永不动 vfx-params.json)。
|
|
@@ -219,12 +221,12 @@ function update(onlyId) {
|
|
|
219
221
|
const range = changelogRange(oldPin, target);
|
|
220
222
|
if (range) { console.log(`\n── CHANGELOG ${oldPin ? `v${oldPin} → ` : ''}v${target} ──\n${range}\n`); }
|
|
221
223
|
|
|
222
|
-
console.log(`\n下一步:\`pnpm install\`(拉取
|
|
224
|
+
console.log(`\n下一步:\`pnpm install\`(拉取 ${PACKAGE_NAME}#v${target} 新代码/资源)。`);
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
// ── dispatch ──────────────────────────────────────────────────────────────────
|
|
226
228
|
if (cmd === 'list') {
|
|
227
|
-
console.log(
|
|
229
|
+
console.log(`${PACKAGE_NAME} 可用特效(v${LIB_VERSION}):`);
|
|
228
230
|
for (const id of libEffectIds().sort()) console.log(` - ${id}`);
|
|
229
231
|
} else if (cmd === 'add') {
|
|
230
232
|
if (!positional[0]) { console.error('用法: add <id> [--project <dir>] [--force]'); process.exit(1); }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// @fps/vfx 的 Vite 接入助手(plan §18.3:克隆 editor 蓝图,简化为单包)。
|
|
1
|
+
// @fps-games/vfx 的 Vite 接入助手(plan §18.3:克隆 editor 蓝图,简化为单包)。
|
|
2
2
|
// 消费方 vite.config:
|
|
3
|
-
// import { createVfxLibrarySourceAlias, VFX_BABYLON_DEDUPE } from '@fps/vfx/vite'(或本文件路径)
|
|
3
|
+
// import { createVfxLibrarySourceAlias, VFX_BABYLON_DEDUPE } from '@fps-games/vfx/vite'(或本文件路径)
|
|
4
4
|
// resolve: { alias: [...createVfxLibrarySourceAlias(process.env.FPS_VFX_LIBRARY_REPO)], dedupe: [...VFX_BABYLON_DEDUPE] }
|
|
5
5
|
import { resolve } from 'node:path';
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ import { resolve } from 'node:path';
|
|
|
8
8
|
export const VFX_BABYLON_DEDUPE = ['@babylonjs/core', '@babylonjs/loaders'];
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* 源码模式:把 `@fps/vfx` / `@fps/vfx/effects/<id>` 别名到本地库源(供 dev / SDK 联调)。
|
|
11
|
+
* 源码模式:把 `@fps-games/vfx` / `@fps-games/vfx/effects/<id>` 别名到本地库源(供 dev / SDK 联调)。
|
|
12
12
|
* @param {string} libRepoRoot fps-vfx-library 仓库根(通常来自 process.env.FPS_VFX_LIBRARY_REPO)
|
|
13
13
|
* @returns vite alias 数组(给 resolve.alias)
|
|
14
14
|
*/
|
|
@@ -18,11 +18,11 @@ export function createVfxLibrarySourceAlias(libRepoRoot) {
|
|
|
18
18
|
}
|
|
19
19
|
const pkgs = resolve(libRepoRoot, 'packages');
|
|
20
20
|
return [
|
|
21
|
-
// 子路径:@fps/vfx/effects/<id> → packages/effects/<id>/index.ts
|
|
22
|
-
{ find: /^@fps\/vfx\/effects\/(.+)$/, replacement: resolve(pkgs, 'effects') + '/$1/index.ts' },
|
|
23
|
-
// 根入口:@fps/vfx → packages/index.ts
|
|
24
|
-
{ find: /^@fps\/vfx$/, replacement: resolve(pkgs, 'index.ts') },
|
|
21
|
+
// 子路径:@fps-games/vfx/effects/<id> → packages/effects/<id>/index.ts
|
|
22
|
+
{ find: /^@fps-games\/vfx\/effects\/(.+)$/, replacement: resolve(pkgs, 'effects') + '/$1/index.ts' },
|
|
23
|
+
// 根入口:@fps-games/vfx → packages/index.ts
|
|
24
|
+
{ find: /^@fps-games\/vfx$/, replacement: resolve(pkgs, 'index.ts') },
|
|
25
25
|
// vite 助手子路径(本文件)
|
|
26
|
-
{ find: /^@fps\/vfx\/vite$/, replacement: resolve(libRepoRoot, 'tooling', 'vfx-package-resolution.mjs') },
|
|
26
|
+
{ find: /^@fps-games\/vfx\/vite$/, replacement: resolve(libRepoRoot, 'tooling', 'vfx-package-resolution.mjs') },
|
|
27
27
|
];
|
|
28
28
|
}
|