@combos-fun/engine 0.0.35 → 0.0.37
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/agent-skill.md +21 -273
- package/dist/engine.cjs.js +1 -1
- package/dist/engine.cjs.js.map +1 -1
- package/dist/engine.cjs.prod.js +1 -1
- package/dist/engine.d.ts +1 -1
- package/dist/engine.esm.js +1 -1
- package/dist/engine.esm.js.map +1 -1
- package/package.json +7 -5
- package/references/bootstrap-examples.md +111 -0
- package/references/public-api.md +87 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@combos-fun/engine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"description": "ECS microkernel",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/engine.esm.js",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"dist",
|
|
12
12
|
"agent-skill.md",
|
|
13
13
|
"plugin-authoring.md",
|
|
14
|
-
"combos-plugin.json"
|
|
14
|
+
"combos-plugin.json",
|
|
15
|
+
"references"
|
|
15
16
|
],
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|
|
@@ -21,7 +22,8 @@
|
|
|
21
22
|
},
|
|
22
23
|
"./plugin-manifest": "./combos-plugin.json",
|
|
23
24
|
"./agent-skill": "./agent-skill.md",
|
|
24
|
-
"./plugin-authoring": "./plugin-authoring.md"
|
|
25
|
+
"./plugin-authoring": "./plugin-authoring.md",
|
|
26
|
+
"./references/*": "./references/*"
|
|
25
27
|
},
|
|
26
28
|
"combos": {
|
|
27
29
|
"pluginManifest": "./combos-plugin.json"
|
|
@@ -39,11 +41,11 @@
|
|
|
39
41
|
],
|
|
40
42
|
"author": "sun668 <q947692259@gmail.com>",
|
|
41
43
|
"dependencies": {
|
|
44
|
+
"@combos-fun/inspector-decorator": "0.0.37",
|
|
42
45
|
"eventemitter3": "^5.0.4",
|
|
43
46
|
"lodash-es": "^4.17.21",
|
|
44
47
|
"resource-loader": "^4.0.0-rc4",
|
|
45
|
-
"sprite-timeline": "^1.10.2"
|
|
46
|
-
"@combos-fun/inspector-decorator": "0.0.35"
|
|
48
|
+
"sprite-timeline": "^1.10.2"
|
|
47
49
|
},
|
|
48
50
|
"scripts": {
|
|
49
51
|
"build": "node ../../scripts/build-package.mjs"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Bootstrap examples (on demand)
|
|
2
|
+
|
|
3
|
+
Prefer the host template bootstrap. Use these only when starting from zero without a template.
|
|
4
|
+
|
|
5
|
+
## Minimal 2D bootstrap
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import {
|
|
9
|
+
Game,
|
|
10
|
+
GameObject,
|
|
11
|
+
resource,
|
|
12
|
+
RESOURCE_TYPE,
|
|
13
|
+
LOAD_EVENT,
|
|
14
|
+
} from "@combos-fun/engine";
|
|
15
|
+
import { RendererSystem } from "@combos-fun/plugin-renderer";
|
|
16
|
+
import { Render, RenderSystem } from "@combos-fun/plugin-renderer-render";
|
|
17
|
+
import { Img, ImgSystem } from "@combos-fun/plugin-renderer-img";
|
|
18
|
+
|
|
19
|
+
resource.once(LOAD_EVENT.COMPLETE, () => {
|
|
20
|
+
new Game({
|
|
21
|
+
systems: [
|
|
22
|
+
new RendererSystem({
|
|
23
|
+
canvas: document.querySelector("#canvas")!,
|
|
24
|
+
width: 750,
|
|
25
|
+
height: 1334,
|
|
26
|
+
}),
|
|
27
|
+
new RenderSystem(),
|
|
28
|
+
new ImgSystem(),
|
|
29
|
+
],
|
|
30
|
+
// Safe place to wire the scene graph: every system has finished init.
|
|
31
|
+
onSystemsBootstrapComplete: (g) => {
|
|
32
|
+
// Transform values go through constructor params — never set them imperatively.
|
|
33
|
+
const logo = new GameObject("logo", {
|
|
34
|
+
position: { x: 100, y: 100 },
|
|
35
|
+
size: { width: 200, height: 200 },
|
|
36
|
+
origin: { x: 0.5, y: 0.5 },
|
|
37
|
+
});
|
|
38
|
+
logo.addComponent(new Img({ resource: "logo" }));
|
|
39
|
+
// Render is only needed when you want to hide / fade / reorder; without it the
|
|
40
|
+
// object is still drawn at alpha 1, zIndex 0. Requires RenderSystem registered.
|
|
41
|
+
logo.addComponent(new Render({ zIndex: 5 }));
|
|
42
|
+
// Use addChild — not addGameObject — so transform parent + scene are both wired.
|
|
43
|
+
g.scene.addChild(logo);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
resource.loadConfig([
|
|
49
|
+
{
|
|
50
|
+
name: "logo",
|
|
51
|
+
type: RESOURCE_TYPE.IMAGE,
|
|
52
|
+
src: { image: { type: "png", url: "logo.png" } },
|
|
53
|
+
preload: true,
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`ResourceBase` requires both `type: RESOURCE_TYPE` and a nested `src` object keyed by media slot (`image` / `json` / `audio` / `video` / `tex` / `ske` / …) where each slot is `{ type, url }`. A flat `src: 'logo.png'` is invalid.
|
|
59
|
+
|
|
60
|
+
## Minimal 3D bootstrap
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { Game, GameObject } from "@combos-fun/engine";
|
|
64
|
+
import { Renderer3DSystem } from "@combos-fun/plugin-renderer-3d";
|
|
65
|
+
import {
|
|
66
|
+
Graphics3D,
|
|
67
|
+
Graphics3DSystem,
|
|
68
|
+
} from "@combos-fun/plugin-renderer-3d-graphics";
|
|
69
|
+
|
|
70
|
+
new Game({
|
|
71
|
+
systems: [
|
|
72
|
+
new Renderer3DSystem({
|
|
73
|
+
canvas: document.querySelector("#canvas")!,
|
|
74
|
+
width: 750,
|
|
75
|
+
height: 1000,
|
|
76
|
+
}),
|
|
77
|
+
new Graphics3DSystem(),
|
|
78
|
+
],
|
|
79
|
+
// Safe place to wire the scene graph: every system has finished init.
|
|
80
|
+
onSystemsBootstrapComplete: (g) => {
|
|
81
|
+
// 3D position / rotation / scale go through the component's own params
|
|
82
|
+
// (positionX/Y/Z, rotationX/Y/Z, scaleX/Y/Z) — GameObject's TransformParams
|
|
83
|
+
// is 2D-only (Vector2 + Size2) and is not read by 3D renderers.
|
|
84
|
+
const box = new GameObject("box");
|
|
85
|
+
box.addComponent(
|
|
86
|
+
new Graphics3D({
|
|
87
|
+
shape: "box",
|
|
88
|
+
width: 1,
|
|
89
|
+
height: 1,
|
|
90
|
+
depth: 1,
|
|
91
|
+
color: 0xff0000,
|
|
92
|
+
positionX: 0,
|
|
93
|
+
positionY: 1,
|
|
94
|
+
positionZ: 0,
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
// Use addChild — not addGameObject — so transform parent + scene are both wired.
|
|
98
|
+
g.scene.addChild(box);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Verification
|
|
104
|
+
|
|
105
|
+
After modifying engine code:
|
|
106
|
+
|
|
107
|
+
1. `pnpm typecheck`
|
|
108
|
+
2. `pnpm run build` (rebuild all packages in dependency order)
|
|
109
|
+
3. `pnpm validate-plugin-manifests:strict`
|
|
110
|
+
4. Run an example app from `examples/` and verify no console errors
|
|
111
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Engine Public API (on demand)
|
|
2
|
+
|
|
3
|
+
Open only when the short `agent-skill` card is insufficient for a named symbol or host bridge.
|
|
4
|
+
|
|
5
|
+
## Public API
|
|
6
|
+
|
|
7
|
+
### Values
|
|
8
|
+
|
|
9
|
+
`Game`, `Scene`, `GameObject`, `Component`, `System`, `Transform`, `resource`, `resourceLoader`, `decorators`, `IDEProp`, `componentObserver`, `LOAD_EVENT`, `RESOURCE_TYPE`, `OBSERVER_TYPE`, `LOAD_SCENE_MODE`, `RESOURCE_TYPE_STRATEGY`, `version`, `COMBOS_GAME_PLUGIN_INIT_SUCCESS`, `COMBOS_GAME_READY`, `COMBOS_GAME_SET_PLAYING`, `COMBOS_GAME_STATE_CHANGED`, `postParentPluginInitSuccess`, `postParentGameReady`, `postParentGameState`, `parseSetPlayingMessage`, `DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES`, `isAllowedMessageOrigin`, `mergeAllowedMessageOrigins`.
|
|
10
|
+
|
|
11
|
+
### Types
|
|
12
|
+
|
|
13
|
+
`GameParams`, `PluginStruct`, `TransformParams`, `ComponentChanged`, `UpdateParams`, `ComponentParams`, `ObserverInfo`, `PureObserverInfo`, `ResourceBase`, `SystemConstructor`, `CombosGamePluginInitSuccessMessage`, `CombosGameReadyMessage`, `CombosGameStateChangedMessage`, `CombosGameSetPlayingMessage`.
|
|
14
|
+
|
|
15
|
+
### `GameParams`
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
| Field | Type | Default | Notes |
|
|
19
|
+
| ------------------------------ | ------------------------ | ------- | ---------------------------------------- |
|
|
20
|
+
| `systems` | `System[]` | `[]` | Bootstrapped async in registration order |
|
|
21
|
+
| `frameRate` | `number` | `60` | |
|
|
22
|
+
| `autoStart` | `boolean` | `true` | |
|
|
23
|
+
| `needScene` | `boolean` | `true` | Auto-creates `Scene('scene')` |
|
|
24
|
+
| `onSystemsBootstrapComplete` | `(game, error?) => void` | — | After all systems init |
|
|
25
|
+
| `pluginInitNotifyTargetOrigin` | `string` | `'*'` | Outbound postMessage target (init / ready / state) |
|
|
26
|
+
| `allowedMessageOrigins` | `string[]` | defaults | Inbound origins allowed to send `set-playing` (merged with defaults; `['*']` = any) |
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
When the game runs inside an iframe (`window.parent !== window`), each `Game.addSystem` call posts to the parent after that system's `init` completes:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
{
|
|
33
|
+
type: 'combos-game:plugin-init-success',
|
|
34
|
+
systemName: string, // System.systemName
|
|
35
|
+
engineVersion: string, // @combos-fun/engine build version
|
|
36
|
+
packageName?: string, // npm name, injected at plugin build
|
|
37
|
+
packageVersion?: string, // semver from plugin package.json, injected at plugin build
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Official `@combos-fun/plugin-*` packages get `packageName` / `packageVersion` automatically via `scripts/build-package.mjs` (no hand-written static fields). Host pages can gate tooling on specific systems or versions using this payload. Types: `CombosGamePluginInitSuccessMessage`, helper `postParentPluginInitSuccess` in `bootstrapMessages.ts`.
|
|
42
|
+
|
|
43
|
+
### Host lifecycle protocol (preload → hold → play)
|
|
44
|
+
|
|
45
|
+
Core `Game` speaks a `postMessage` protocol with the embedding page so a host APP can preload, hold, then start the game on user intent. All outbound messages go to `pluginInitNotifyTargetOrigin`; the inbound command is origin-checked against `allowedMessageOrigins`.
|
|
46
|
+
|
|
47
|
+
**Outbound (iframe → parent):**
|
|
48
|
+
|
|
49
|
+
| Type | When | Payload |
|
|
50
|
+
| ---- | ---- | ------- |
|
|
51
|
+
| `combos-game:ready` | Bootstrap finished (systems `init`/`awake`, optional scene load & start). Sent once even with `autoStart:false`. | `{ engineVersion, error? }` |
|
|
52
|
+
| `combos-game:state-changed` | After `start` / `pause` / `resume` | `{ playing, started }` |
|
|
53
|
+
|
|
54
|
+
**Inbound (parent → iframe):**
|
|
55
|
+
|
|
56
|
+
| Type | Effect | Payload |
|
|
57
|
+
| ---- | ------ | ------- |
|
|
58
|
+
| `combos-game:set-playing` | `true` → cold `start()` on first play, else `resume()`; `false` → `pause()` | `{ playing: boolean }` |
|
|
59
|
+
|
|
60
|
+
Recommended flow: create the game with `autoStart:false`, wait for `combos-game:ready`, keep the game held at frame 0 (host shows a cover/loading overlay), then post `{ type: 'combos-game:set-playing', playing: true }` when the user taps play. `game.setPlaying(playing)` is the programmatic equivalent. Helpers: `postParentGameReady`, `postParentGameState`, `parseSetPlayingMessage`.
|
|
61
|
+
|
|
62
|
+
> Note: play/pause is owned by the engine core here, **not** by `plugin-development-tool` (which now only handles pick mode + mute).
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### `Game` methods
|
|
66
|
+
|
|
67
|
+
`addSystem(system)`, `removeSystem(system | class | string)` (calls `system.destroy()` internally), `getSystem(class | string)`, `loadScene({ scene, mode?, params? })` (`LOAD_SCENE_MODE.SINGLE | MULTI_CANVAS`), `start()`, `pause()`, `resume()`, `setPlaying(playing)` (host bridge: cold-start-or-resume / pause), `destroy()`.
|
|
68
|
+
|
|
69
|
+
### `resource` singleton
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
| Method | Notes |
|
|
73
|
+
| ---------------------------------------------------------- | ------------------------- |
|
|
74
|
+
| `addResource(resources[])` | Register (no load) |
|
|
75
|
+
| `preload()` | Load all `preload: true` |
|
|
76
|
+
| `loadConfig(resources[])` | `addResource` + `preload` |
|
|
77
|
+
| `loadSingle(resource): Promise` | Add + load one |
|
|
78
|
+
| `getResource(name): Promise` | Get loaded |
|
|
79
|
+
| `destroy(name): Promise` | Destroy one |
|
|
80
|
+
| `registerResourceType(type, value?)` | Custom type |
|
|
81
|
+
| `registerInstance(type, cb)` / `registerDestroy(type, cb)` | Factory / destructor |
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Fields: `timeout` (6000ms), `resourcesMap`, `progress`.
|
|
85
|
+
|
|
86
|
+
> ⚠️ `addResource` only registers; it does **not** kick off network load. Components that reference an unloaded `resource` (e.g. `Img({ resource: 'logo' })`) silently render nothing — the canvas stays blank with no console error. Always pair it with `preload()` (and gate `new Game(...)` behind `resource.once(LOAD_EVENT.COMPLETE, ...)`), or skip the pair entirely and use `loadConfig(resources[])` which does both in one call.
|
|
87
|
+
|