pelican-engine 0.3.19 → 0.3.21
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/AGENTS.md +2 -2
- package/distribution.json +12 -12
- package/docs/STATUS.md +4 -1
- package/docs/api/REFERENCE.md +2 -2
- package/docs/api/index.json +2 -2
- package/docs/npm/GAME-AUTHOR.md +2 -2
- package/engine.manifest.json +1 -1
- package/lib/sdk/index.d.ts +1 -1
- package/lib/sdk/index.js +1 -1
- package/lib/simulation/cloth-plugin.js +10 -3
- package/lib/simulation/cloth.js +14 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -157,8 +157,8 @@ reports the active mode. Set `selfCollisions: false` to disable it. Adjacent
|
|
|
157
157
|
segments and collisions between separate ropes are not handled. Immovable anchored
|
|
158
158
|
endpoints stay fixed, and contacts introduced by corrections can wait until the
|
|
159
159
|
next iteration. Dense overlap can approach quadratic work. Snapshots from before
|
|
160
|
-
this feature retain the disabled mode when migrated;
|
|
161
|
-
still apply. This is unverified discrete contact, not a guarantee against
|
|
160
|
+
this feature retain the disabled mode when migrated; invalid or duplicate self
|
|
161
|
+
contacts are rejected atomically; Host engine-version rules still apply. This is unverified discrete contact, not a guarantee against
|
|
162
162
|
penetration, continuous collision, friction or full rope physics. The source
|
|
163
163
|
checkout includes `examples/rope-self`.
|
|
164
164
|
|
package/distribution.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "pelican.npm-distribution",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.21",
|
|
4
4
|
"files": {
|
|
5
|
-
"AGENTS.md": "
|
|
5
|
+
"AGENTS.md": "3efeb184ac3c53692804ec50927b642053dbcf5c51ad25ea135aed15e4dbf7ff",
|
|
6
6
|
"CONTRIBUTING.md": "0ffad5d841d90f319fc50a75b81d3c0ad6dab8d5d9bec2846c65c7f8358d5a50",
|
|
7
7
|
"docs/AI-WORKFLOW.md": "aa992686df93f791795f6f3fce01713d812eea6a1b9556f07411ac5847278efa",
|
|
8
|
-
"docs/api/index.json": "
|
|
9
|
-
"docs/api/REFERENCE.md": "
|
|
8
|
+
"docs/api/index.json": "149022d834a6bbdf4e4224a9460d3d5545792c5ef01024485a69f65531d1b310",
|
|
9
|
+
"docs/api/REFERENCE.md": "b6d064bd933d9d4f26e8224cf2796fbe7bc52b22d33ff35e48f878d76af02a90",
|
|
10
10
|
"docs/ARCHITECTURE.md": "3184b73592d466390e7793b1cf39bbb80d6052b523fba7e7cb377b5207074627",
|
|
11
11
|
"docs/assets/pelican-mark.svg": "407b10cd7e292ea83cf5dba4046fb2f01c7d566a14014c55deda3a2984562b4d",
|
|
12
12
|
"docs/CAPABILITIES.md": "92950817497d8c63db07830db96dc93c877befa8d038320feed1ae1f1a053cb1",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"docs/GETTING-STARTED.md": "5519ebe4e513e8ae4517c04948ee9dc70bcb1e3d04a65d468a6537c838502663",
|
|
15
15
|
"docs/GRAPHICS-GUIDE.md": "e3d0f7df6189ca3f88d81af5ffaf393f5d6bf39b9e66167bb2f64b39194b514c",
|
|
16
16
|
"docs/npm/DISTRIBUTION.md": "ff25e039921a85ba253c27608c77ed614a036117d7a04f908a78d1e3ed3f19ef",
|
|
17
|
-
"docs/npm/GAME-AUTHOR.md": "
|
|
17
|
+
"docs/npm/GAME-AUTHOR.md": "3efeb184ac3c53692804ec50927b642053dbcf5c51ad25ea135aed15e4dbf7ff",
|
|
18
18
|
"docs/PELICAN-MIGRATION.md": "c5d6ab8e5186f4d36720a0a01d1a7e4157a5d386c5400e2db99571a7d10a1e49",
|
|
19
19
|
"docs/PHYSICS-LIFECYCLE-ISSUE.md": "cc78917462de4e7e9b68e77c742192ce213b4be5b516d2ba943251fff46977ac",
|
|
20
20
|
"docs/RENDER-BACKENDS.md": "d981ea94742a835d028db37d536fb7fba05102e37bc6274a37baf74f5034b954",
|
|
21
21
|
"docs/ROADMAP.md": "29ac1c54f36064e23c17cfe7f549d6860889257a57d1227e322958aa9c281568",
|
|
22
|
-
"docs/STATUS.md": "
|
|
22
|
+
"docs/STATUS.md": "bdb601521fc37c91de6d4f404f714cb2170d9b6e518c861d6d7fb21d7309bf67",
|
|
23
23
|
"docs/THIRD-PARTY-NOTICES.md": "58f9b72e2b4dfaaaf2a4c08b9bde9ecef3d2b7e7d65fccd782ed54f39fa76fdc",
|
|
24
|
-
"engine.manifest.json": "
|
|
24
|
+
"engine.manifest.json": "9b45f17ab1a5d572b1ad6339537f0abc9783f0d09d3b9b638139e527eac60509",
|
|
25
25
|
"lib/assets/audio.js": "6facdce4e053afd172af5b9407569b035169844ea17b49f93f8b67f72b78895f",
|
|
26
26
|
"lib/assets/errors.js": "70572678655c6e53179d31920d71f29882d373a0e12d560220bb0fc2cd74f2cc",
|
|
27
27
|
"lib/assets/glb.js": "b808479a36299c154db97f50c16863a3b5a2c61f725e66bf01d01a5f62a288a5",
|
|
@@ -125,10 +125,10 @@
|
|
|
125
125
|
"lib/runtime/world.js": "c43621fbaca8bd2b0d6477a96e60e895312f0f7b1eb97614b6e4f9b716129ea1",
|
|
126
126
|
"lib/schema/index.js": "594429eecb4494c4af2f3d04537be3211f2c9297a1fc555bbba5d028d8627965",
|
|
127
127
|
"lib/sdk/graph-values.js": "a58c00f127cb82aba5fd2824981942844e06d9a59a88a05e35d1d3df2fc7ed2f",
|
|
128
|
-
"lib/sdk/index.d.ts": "
|
|
129
|
-
"lib/sdk/index.js": "
|
|
130
|
-
"lib/simulation/cloth-plugin.js": "
|
|
131
|
-
"lib/simulation/cloth.js": "
|
|
128
|
+
"lib/sdk/index.d.ts": "a94caaad441c55fcb1756ee71ffee019312f503ecb4fef3efcaed746c62d6e05",
|
|
129
|
+
"lib/sdk/index.js": "7ef0131457ceac1e9eeb5aa2b140f854b9bbe16dff03c42714b96e6ddedf4b7c",
|
|
130
|
+
"lib/simulation/cloth-plugin.js": "edee02bb0ce7cf94d364699e47bc4891f8a53259bb70af547241759faad0b773",
|
|
131
|
+
"lib/simulation/cloth.js": "f45a1c7684904b70315c8c1a0a28153eb34a8aee150d518af379f6d2fff2e740",
|
|
132
132
|
"lib/simulation/rope-body-coupling.js": "70694b73d17c79f223803a51fbf4a4dae551b717cd29bbea1fa38386ac98d621",
|
|
133
133
|
"lib/simulation/rope-plugin.js": "08c7c4800053b3e8f255b6dd5be2b532b8e259300666c31de5494d15704717d4",
|
|
134
134
|
"lib/simulation/rope-self-collision.js": "4d8dc5d5a88f0ae0ad5463f553f49b2ad3c8c126b98344a0966f619635bdb17f",
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"licenses/undici-types/LICENSE": "a6db8096b2707bc0102d256917d4d33f298ba36d8c3f25de067a2b5bb379db27",
|
|
204
204
|
"licenses/uniq/LICENSE": "e67aed7df22dc8031e4fcf5338fe91cb33e3817e5c58a99a2a2802eea9069791",
|
|
205
205
|
"licenses/vite/LICENSE.md": "a22152baa1aef74402443008e767e7c689a524c0909d19b0431d97f5ab066a13",
|
|
206
|
-
"package.json": "
|
|
206
|
+
"package.json": "b50c26f2427bb50bb724238d3e9c17407bd704ad5e888c33d1d53e66eb76195d",
|
|
207
207
|
"README.md": "ff25e039921a85ba253c27608c77ed614a036117d7a04f908a78d1e3ed3f19ef",
|
|
208
208
|
"web/index.html": "d89d6a5b5be3beae3627a8ed506ac308b165d264fb8696be3afd79fcca2f26ee"
|
|
209
209
|
}
|
package/docs/STATUS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 版本与发布
|
|
4
4
|
|
|
5
|
-
- 当前版本为 `0.3.
|
|
5
|
+
- 当前版本为 `0.3.21`,包、锁文件、引擎、SDK、编译器和示例中的版本保持一致。下一项功能完成后统一递增并推送;相同版本不能重复发布。
|
|
6
6
|
- 推送主线会通过 GitHub Actions 和 npm 可信发布更新 `latest`;GitHub Release 用于记录里程碑。历史版本和旧标签保持原样,不代表当前源码通过。
|
|
7
7
|
- 当前按用户要求仅允许编译和构建,不运行测试、浏览器、GPU、性能或其他验证。普通版本号不意味着运行行为、硬件或完整引擎已验收。
|
|
8
8
|
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
- 三角布料新增 CPU 距离约束、近似弯曲、锚点、受力、采样球体/平面粒子碰撞、非相邻粒子自碰撞、Host 快照及动态网格入口;不包含面/边碰撞、刚体反作用、撕裂或连续碰撞。渲染、运行、稳定性、性能和快照兼容均未验证,不代表完整布料能力。
|
|
18
18
|
- 布料、绳索、软体、流体、连续世界、导航、动画、音频和其他首发能力仍需按各自依赖完成,不能把独立候选或局部实现写成整项完成。
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
- Historical cloth snapshots without `selfCollisions` restore in the legacy particle-only mode; invalid or duplicate self-contact state is rejected atomically. This migration fix is unverified.
|
|
22
|
+
|
|
20
23
|
## 单线接续
|
|
21
24
|
|
|
22
25
|
只在 `main` 的主工作树串行开发。历史独有候选和失败记录在本机 `.pelican/consolidated-worktrees/`、`.pelican/worktree-snapshots/` 或原证据目录中;它们不是活动工作树,未审查前不能删除或声称已合入。其他环境不一定有这些本机目录。
|
package/docs/api/REFERENCE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pelican 0.3.
|
|
1
|
+
# pelican 0.3.21 API 索引
|
|
2
2
|
|
|
3
3
|
Installed declarations: `lib/sdk/index.d.ts` (relative to the package root).
|
|
4
4
|
The signatures below come from the same public SDK source as repository games.
|
|
@@ -11,7 +11,7 @@ Source-file paths and line numbers are build-time provenance only; TypeScript so
|
|
|
11
11
|
来源:`packages/sdk/src/index.ts:2`
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
SDK_VERSION = "0.3.
|
|
14
|
+
SDK_VERSION = "0.3.21"
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Vec2
|
package/docs/api/index.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "pelican.api-index",
|
|
3
3
|
"version": 1,
|
|
4
|
-
"engineVersion": "0.3.
|
|
4
|
+
"engineVersion": "0.3.21",
|
|
5
5
|
"entry": "pelican-engine",
|
|
6
6
|
"source": "packages/sdk/src/index.ts",
|
|
7
7
|
"symbols": [
|
|
8
8
|
{
|
|
9
9
|
"name": "SDK_VERSION",
|
|
10
10
|
"kind": "constant",
|
|
11
|
-
"signature": "SDK_VERSION = \"0.3.
|
|
11
|
+
"signature": "SDK_VERSION = \"0.3.21\"",
|
|
12
12
|
"line": 2
|
|
13
13
|
},
|
|
14
14
|
{
|
package/docs/npm/GAME-AUTHOR.md
CHANGED
|
@@ -157,8 +157,8 @@ reports the active mode. Set `selfCollisions: false` to disable it. Adjacent
|
|
|
157
157
|
segments and collisions between separate ropes are not handled. Immovable anchored
|
|
158
158
|
endpoints stay fixed, and contacts introduced by corrections can wait until the
|
|
159
159
|
next iteration. Dense overlap can approach quadratic work. Snapshots from before
|
|
160
|
-
this feature retain the disabled mode when migrated;
|
|
161
|
-
still apply. This is unverified discrete contact, not a guarantee against
|
|
160
|
+
this feature retain the disabled mode when migrated; invalid or duplicate self
|
|
161
|
+
contacts are rejected atomically; Host engine-version rules still apply. This is unverified discrete contact, not a guarantee against
|
|
162
162
|
penetration, continuous collision, friction or full rope physics. The source
|
|
163
163
|
checkout includes `examples/rope-self`.
|
|
164
164
|
|
package/engine.manifest.json
CHANGED
package/lib/sdk/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Pelican Engine public API. No renderer or GPU implementation types escape this module. */
|
|
2
|
-
export declare const SDK_VERSION = "0.3.
|
|
2
|
+
export declare const SDK_VERSION = "0.3.21";
|
|
3
3
|
export type Vec2 = readonly [number, number];
|
|
4
4
|
export type Vec3 = readonly [number, number, number];
|
|
5
5
|
export type Vec4 = readonly [number, number, number, number];
|
package/lib/sdk/index.js
CHANGED
|
@@ -15,12 +15,16 @@ function planarUvs(points) {
|
|
|
15
15
|
return fail("VISUAL_UV", "Initial points need two nonzero projection axes or explicit UVs.");
|
|
16
16
|
return points.map(point => [(point[first] - min[first]) / width, (point[second] - min[second]) / height]);
|
|
17
17
|
}
|
|
18
|
-
function createEntry(input, fixedDt, materials) {
|
|
18
|
+
function createEntry(input, fixedDt, materials, restoredSelfMode) {
|
|
19
19
|
const definition = cloneSerializable(input);
|
|
20
20
|
if (!definition || !validId(definition.id))
|
|
21
21
|
return fail("ID", "Expected a nonempty id of at most 128 characters.");
|
|
22
22
|
if (definition.autoStep !== undefined && typeof definition.autoStep !== "boolean")
|
|
23
23
|
return fail("AUTO_STEP", "autoStep must be boolean.");
|
|
24
|
+
if (definition.selfCollisions !== undefined && typeof definition.selfCollisions !== "boolean")
|
|
25
|
+
return fail("SELF_COLLISION", "selfCollisions must be boolean.");
|
|
26
|
+
if (restoredSelfMode !== undefined && definition.selfCollisions !== undefined && definition.selfCollisions !== restoredSelfMode)
|
|
27
|
+
return fail("SNAPSHOT", "Self collision configuration does not match the saved solver.");
|
|
24
28
|
if (definition.fixedDt !== undefined && definition.fixedDt !== fixedDt)
|
|
25
29
|
return fail("FIXED_DT", "Cloth fixedDt must match the host fixedDt.");
|
|
26
30
|
if (fixedDt < 1 / 1000 || fixedDt > 1 / 30)
|
|
@@ -35,7 +39,7 @@ function createEntry(input, fixedDt, materials) {
|
|
|
35
39
|
visual.uvs.some(uv => !Array.isArray(uv) || uv.length !== 2 || !uv.every(value => typeof value === "number" && Number.isFinite(value) && Math.abs(value) <= 1e6))))
|
|
36
40
|
return fail("VISUAL_UV", "UVs must contain one finite 2D coordinate per particle.");
|
|
37
41
|
}
|
|
38
|
-
const solver = createCloth({ ...definition, fixedDt });
|
|
42
|
+
const solver = createCloth({ ...definition, fixedDt, ...(restoredSelfMode === undefined ? {} : { selfCollisions: restoredSelfMode }) });
|
|
39
43
|
try {
|
|
40
44
|
const uvs = definition.visual ? (definition.visual.uvs ? definition.visual.uvs.map(uv => [uv[0], uv[1]]) : planarUvs(definition.points)) : [];
|
|
41
45
|
return { definition, solver, uvs };
|
|
@@ -55,7 +59,10 @@ function parseSnapshot(value, fixedDt, materials) {
|
|
|
55
59
|
for (const item of value.cloths) {
|
|
56
60
|
if (!item || typeof item !== "object")
|
|
57
61
|
fail("SNAPSHOT", "Invalid cloth entry.");
|
|
58
|
-
const
|
|
62
|
+
const savedSelfMode = item.state?.config?.selfCollisions;
|
|
63
|
+
if (savedSelfMode !== undefined && typeof savedSelfMode !== "boolean")
|
|
64
|
+
fail("SNAPSHOT", "Invalid self collision configuration.");
|
|
65
|
+
const entry = createEntry(item.definition, fixedDt, materials, savedSelfMode ?? false);
|
|
59
66
|
if (entries.has(entry.definition.id)) {
|
|
60
67
|
entry.solver.dispose();
|
|
61
68
|
fail("SNAPSHOT", "Duplicate cloth id.");
|
package/lib/simulation/cloth.js
CHANGED
|
@@ -344,13 +344,26 @@ export class ClothSolver {
|
|
|
344
344
|
fail("CLOTH_SNAPSHOT", "duplicate contact");
|
|
345
345
|
keys.add(key);
|
|
346
346
|
}
|
|
347
|
+
const selfContacts = input.selfContacts ?? [];
|
|
348
|
+
const selfKeys = new Set();
|
|
349
|
+
if (!Array.isArray(selfContacts) || selfContacts.length > count * Math.max(0, count - 1) / 2 || (!this.config.selfCollisions && selfContacts.length > 0) ||
|
|
350
|
+
selfContacts.some(contact => !contact || contact.tick !== input.tick || !Number.isSafeInteger(contact.firstParticle) || !Number.isSafeInteger(contact.secondParticle) ||
|
|
351
|
+
contact.firstParticle < 0 || contact.secondParticle >= count || contact.firstParticle >= contact.secondParticle ||
|
|
352
|
+
this.adjacent.has(`${contact.firstParticle}:${contact.secondParticle}`) || typeof contact.penetration !== "number" || !Number.isFinite(contact.penetration) || contact.penetration <= 0))
|
|
353
|
+
fail("CLOTH_SNAPSHOT", "invalid self contact state");
|
|
354
|
+
for (const contact of selfContacts) {
|
|
355
|
+
const key = `${contact.firstParticle}:${contact.secondParticle}`;
|
|
356
|
+
if (selfKeys.has(key))
|
|
357
|
+
fail("CLOTH_SNAPSHOT", "duplicate self contact");
|
|
358
|
+
selfKeys.add(key);
|
|
359
|
+
}
|
|
347
360
|
this.positions = input.positions.map(copy);
|
|
348
361
|
this.velocities = input.velocities.map(copy);
|
|
349
362
|
this.forces = input.forces.map(copy);
|
|
350
363
|
this.anchors = anchors;
|
|
351
364
|
this.colliders = colliders;
|
|
352
365
|
this.contacts = input.contacts.map(contact => ({ ...contact }));
|
|
353
|
-
this.selfContacts =
|
|
366
|
+
this.selfContacts = selfContacts.map(contact => ({ ...contact }));
|
|
354
367
|
this.tickValue = input.tick;
|
|
355
368
|
}
|
|
356
369
|
dispose() { if (this.disposed)
|