@combos-fun/plugin-cannon 0.0.6 → 0.0.7

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/README.md CHANGED
@@ -1 +1,27 @@
1
1
  # @combos-fun/plugin-cannon
2
+
3
+ @combos-fun/plugin-cannon — part of the Combos Fun engine monorepo.
4
+
5
+ Keywords: `cannon-es`, `3d`, `physics`, `collision`, `rigid-body`, `gravity`.
6
+
7
+ ## Documentation
8
+
9
+ - Per-package agent / developer notes: [`agent-skill.md`](./agent-skill.md)
10
+ - Machine-readable manifest: [`combos-plugin.json`](./combos-plugin.json)
11
+ (validated against `schemas/combos-plugin.schema.json` in the repo
12
+ root)
13
+ - Entry skill (single source of truth for AI agents working with this
14
+ monorepo): `skills/combos-engine-development/SKILL.md`
15
+
16
+ When consumed from npm, the manifest and agent notes are exposed as
17
+ stable subpaths:
18
+
19
+ ```ts
20
+ import manifest from '@combos-fun/plugin-cannon/plugin-manifest';
21
+ // or fetch the markdown directly:
22
+ // require.resolve('@combos-fun/plugin-cannon/agent-skill')
23
+ ```
24
+
25
+ ## License
26
+
27
+ Internal workspace package, part of the Combos Fun engine monorepo.
package/agent-skill.md ADDED
@@ -0,0 +1,145 @@
1
+ # `@combos-fun/plugin-cannon` — Agent notes
2
+
3
+ 3D physics for Combos Fun. Wraps `cannon-es` ^0.20 and exposes a
4
+ `Physics3DSystem` plus a `Physics3D` Component that auto-syncs
5
+ `positionX/Y/Z` and `rotationX/Y/Z` to sibling 3D render components every
6
+ frame.
7
+
8
+ Pattern mirrors `plugin-matterjs` (2D): Component stores params, System
9
+ observes + delegates to engine, engine manages `CANNON.World`.
10
+
11
+ ## When to read
12
+
13
+ Read for any 3D physics task: gravity, collisions, rigid bodies, ground
14
+ planes, cylinders / spheres, body-mesh sync.
15
+
16
+ ## Public API
17
+
18
+ ```ts
19
+ import {
20
+ Physics3DSystem,
21
+ Physics3D,
22
+ Physics3DType,
23
+ type Physics3DParams,
24
+ type Physics3DSystemParams,
25
+ } from '@combos-fun/plugin-cannon';
26
+ ```
27
+
28
+ ### `Physics3DType`
29
+
30
+ | Value | Shape | Notes |
31
+ |-------|-------|-------|
32
+ | `BOX` | `CANNON.Box` | Half-extents from `width`/`height`/`depth` |
33
+ | `SPHERE` | `CANNON.Sphere` | `radius` |
34
+ | `CYLINDER` | `CANNON.Cylinder` | `radiusTop`, `radiusBottom`, `height`, `segments` |
35
+ | `PLANE` | `CANNON.Plane` | Infinite ground; always `mass = 0` |
36
+
37
+ ### `Physics3DParams`
38
+
39
+ | Field | Type | Default | Notes |
40
+ |-------|------|---------|-------|
41
+ | `type` | `Physics3DType` | `BOX` | |
42
+ | `mass` | `number` | `1` | `0` = static; `PLANE` always static |
43
+ | `bodyOptions` | `object` | `{}` | `friction`, `restitution`, `linearDamping`, `angularDamping`, `fixedRotation` |
44
+ | `position` | `{x?, y?, z?}` | `0,0,0` | |
45
+ | `rotation` | `{x?, y?, z?}` | `0,0,0` | Euler → quaternion |
46
+ | `width`/`height`/`depth` | `number` | `1` | Box dimensions |
47
+ | `radius` | `number` | `0.5` | Sphere / cylinder radius |
48
+ | `radiusTop`/`radiusBottom` | `number` | `radius` | Cylinder top/bottom |
49
+ | `segments` | `number` | `16` | Cylinder radial segments |
50
+ | `stopRotation` | `boolean` | `false` | Lock rotation sync |
51
+
52
+ Synced public fields (read each `update`):
53
+
54
+ `positionX`, `positionY`, `positionZ`, `rotationX`, `rotationY`,
55
+ `rotationZ`. The system writes these back to **all sibling components**
56
+ on the same `GameObject` that have those fields (duck-type check). So
57
+ `Physics3D` + `Graphics3D` on the same node stay in sync without custom
58
+ glue code.
59
+
60
+ `body: CANNON.Body` is injected by the engine after the body is created.
61
+
62
+ ### `Physics3DSystemParams`
63
+
64
+ | Field | Type | Default |
65
+ |-------|------|---------|
66
+ | `gravity` | `{x, y, z}` | `{ x: 0, y: -9.82, z: 0 }` |
67
+ | `fixedTimeStep` | `number` | `1/60` |
68
+ | `maxSubSteps` | `number` | `3` |
69
+ | `allowSleep` | `boolean` | `false` |
70
+ | `solver` | `{ iterations?, tolerance? }` | — |
71
+
72
+ ### Collision events
73
+
74
+ Listen on the `Physics3D` instance:
75
+
76
+ ```ts
77
+ physics3d.on('collisionStart', (otherGameObject, selfGameObject) => { ... });
78
+ physics3d.on('collisionEnd', (otherGameObject, selfGameObject) => { ... });
79
+ ```
80
+
81
+ ## Required setup
82
+
83
+ - Add `Renderer3DSystem` (from `plugin-renderer-3d`) **before**
84
+ `Physics3DSystem`.
85
+ - Body creation is **lazy**: it happens only when `Physics3D` is added
86
+ AND the `GameObject` has a parent (is in the scene hierarchy).
87
+
88
+ ## Runtime behaviour
89
+
90
+ - Each frame, `Physics3DSystem` steps the `CANNON.World` and writes back
91
+ position/rotation into the component.
92
+ - The `update()` of `Physics3D` then propagates these fields to siblings
93
+ automatically.
94
+ - `onDestroy` removes the body from `CANNON.World`.
95
+
96
+ ## Common pitfalls
97
+
98
+ | Symptom | Fix |
99
+ |---------|-----|
100
+ | Bodies fall forever | `PLANE` rotated and mass 0 acts as ground; verify `rotation: { x: -Math.PI/2 }` and that it's at the right Y |
101
+ | Mesh not following body | Make sure `Physics3D` and the visual (e.g. `Graphics3D`) are on the **same** `GameObject` |
102
+ | Body exists but no collision | Check `Physics3DSystem` is registered after `Renderer3DSystem` and `GameObject` is actually in the scene hierarchy |
103
+ | Continuous low-amplitude jitter on a stack | Increase `solver.iterations` or set `allowSleep: true` |
104
+ | Want axis-aligned visual on rotating body | `stopRotation: true` |
105
+
106
+ ## Minimal example
107
+
108
+ ```ts
109
+ import { Game, Scene, GameObject } from '@combos-fun/engine';
110
+ import { Renderer3DSystem } from '@combos-fun/plugin-renderer-3d';
111
+ import { Graphics3DSystem, Graphics3D } from '@combos-fun/plugin-renderer-3d-graphics';
112
+ import { Physics3DSystem, Physics3D, Physics3DType } from '@combos-fun/plugin-cannon';
113
+
114
+ const game = new Game({
115
+ systems: [
116
+ new Renderer3DSystem({ canvas, width: 750, height: 1000 }),
117
+ new Graphics3DSystem(),
118
+ new Physics3DSystem({ gravity: { x: 0, y: -9.82, z: 0 } }),
119
+ ],
120
+ onSystemsBootstrapComplete: (g) => {
121
+ const scene = g.getScene();
122
+
123
+ const box = new GameObject('box');
124
+ box.addComponent(new Graphics3D({ shape: 'box', width: 1, height: 1, depth: 1, color: 0xff0000 }));
125
+ box.addComponent(new Physics3D({
126
+ type: Physics3DType.BOX, mass: 1, width: 1, height: 1, depth: 1,
127
+ position: { x: 0, y: 5, z: 0 },
128
+ }));
129
+ scene.addChild(box);
130
+
131
+ const ground = new GameObject('ground');
132
+ ground.addComponent(new Graphics3D({ shape: 'plane', width: 10, height: 10, color: 0x888888 }));
133
+ ground.addComponent(new Physics3D({
134
+ type: Physics3DType.PLANE,
135
+ rotation: { x: -Math.PI / 2, y: 0, z: 0 },
136
+ }));
137
+ scene.addChild(ground);
138
+ },
139
+ });
140
+ ```
141
+
142
+ ## Verification
143
+
144
+ - `pnpm --filter @combos-fun/plugin-cannon run build`
145
+ - Run a 3D physics example; box should fall and rest on the plane.
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@combos-fun/plugin-cannon",
3
+ "pluginId": "cannon",
4
+ "category": "physics",
5
+ "dimension": "3d",
6
+ "isCore": false,
7
+ "keywords": ["cannon-es", "3d", "physics", "collision", "rigid-body", "gravity"],
8
+ "agentSkill": "./agent-skill.md",
9
+ "requires": ["@combos-fun/engine", "@combos-fun/plugin-renderer-3d"],
10
+ "exports": ["Physics3DSystem", "Physics3D", "Physics3DType"]
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combos-fun/plugin-cannon",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "@combos-fun/plugin-cannon",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-cannon.esm.js",
@@ -8,8 +8,22 @@
8
8
  "unpkg": "dist/CombosFun.plugin.cannon.min.js",
9
9
  "files": [
10
10
  "index.js",
11
- "dist"
11
+ "dist",
12
+ "agent-skill.md",
13
+ "combos-plugin.json"
12
14
  ],
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/plugin-cannon.esm.js",
18
+ "require": "./index.js",
19
+ "types": "./dist/plugin-cannon.d.ts"
20
+ },
21
+ "./plugin-manifest": "./combos-plugin.json",
22
+ "./agent-skill": "./agent-skill.md"
23
+ },
24
+ "combos": {
25
+ "pluginManifest": "./combos-plugin.json"
26
+ },
13
27
  "types": "dist/plugin-cannon.d.ts",
14
28
  "keywords": [
15
29
  "combos-fun",
@@ -21,7 +35,7 @@
21
35
  "author": "sun668 <q947692259@gmail.com>",
22
36
  "dependencies": {
23
37
  "cannon-es": "^0.20.0",
24
- "@combos-fun/engine": "0.0.6"
38
+ "@combos-fun/engine": "0.0.7"
25
39
  },
26
40
  "scripts": {
27
41
  "build": "node ../../scripts/build-package.mjs"