@combos-fun/engine 0.0.44 → 0.0.46

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 CHANGED
@@ -1,53 +1,35 @@
1
1
  # `@combos-fun/engine` — Agent short card
2
2
 
3
- ECS microkernel for Combos Fun. **Short card only** — do not re-cat after the first read. For authoring a new `@combos-fun/plugin-*`, read `@combos-fun/engine/plugin-authoring`.
3
+ Combos Fun ECS microkernel. For new `@combos-fun/plugin-*` packages, read `plugin-authoring.md`.
4
4
 
5
5
  ## When to read
6
6
 
7
- Open this card **only when** an existing-project hard gate allows a plugin skill read (unfamiliar compile symbol / new plugin / real API conflict), or when starting from zero after mode detection. **Do not** load it every turn, and **do not** bulk-read sibling plugin skills with it.
8
-
9
- Public API tables and host `postMessage` protocol: [`references/public-api.md`](references/public-api.md).
7
+ Read when starting an engine task or resolving an engine API/lifecycle question. Public API and host protocol details are in [`references/public-api.md`](references/public-api.md).
10
8
 
11
9
  ## Microkernel model
12
10
 
13
- - **Kernel** `@combos-fun/engine`: `Game`, `Scene`, `GameObject`, `Component`, `System`, `Transform`, `resource`, `decorators`. **No** built-in rendering / physics / audio.
14
- - **Extension**: `game.addSystem(new XxxSystem(...))` then `gameObject.addComponent(new Xxx(...))`.
15
- - **Observer**: `@decorators.componentObserver({ Name: ['prop'] })` on a System; drain `this.componentObserver.clear()` in `update()` and switch on `OBSERVER_TYPE.ADD | CHANGE | REMOVE`.
16
- - **Frame order**: `Component.update` → `Component.lateUpdate` → `System.update` → `System.lateUpdate`. `start()` fires inline on the first `update` tick.
17
-
18
- ## ECS hard rules (mandatory)
19
-
20
- 1. **Entity state in Components** no module-scope / closure entity stores. Destroying a `GameObject` must drop its state.
21
- 2. **Behaviour in Component / System hooks** no bootstrap event handlers, no `setInterval` / `game.ticker.add` for game logic; tear down listeners in `onDestroy`.
22
- 3. **Bootstrap only wires** create Game / Systems / GameObjects / Components; no game `if` / loops in entry files.
23
- 4. **One concern per Component; cross-entity logic in Systems** — custom types need `static componentName` / observer drain, not ad-hoc scene scans.
24
- 5. **No raw Pixi / Three / DOM outside Renderer pattern** use `plugin-renderer-*` / `plugin-renderer-3d-*` or registered `Renderer` / `Renderer3D`.
25
- 6. **Configure via constructor params** runtime triggers from other Component hooks, not bootstrap.
26
-
27
- ## Decision flowchart
28
-
29
- ```
30
- Runs only once at startup to wire things?
31
- ├── YES: Only creates GameObjects/Components/Systems/resources?
32
- │ ├── YES → bootstrap / entry file
33
- │ └── NO (contains logic) → Component or System
34
- └── NO: Runs per-frame or reacts to events?
35
- ├── Single-entity concern → Component
36
- ├── Cross-entity concern → System with @componentObserver
37
- └── Rendering integration → Renderer (2D) / Renderer3D (3D) subclass
38
- ```
11
+ - Core: `Game`, `Scene`, `GameObject`, `Component`, `System`, `Transform`, `resource`, `decorators`; rendering, physics, and audio come from plugins.
12
+ - Register an instance with `await game.addSystem(new XxxSystem(...))`; `Game({ systems })` awaits each system's `init`. Avoid `addSystem(XxxSystem, [params])`: runtime passes the tuple as one constructor argument.
13
+ - Observe components with `@decorators.componentObserver({ Name: ['prop'] })`, then drain `componentObserver.clear()` in `update()`.
14
+ - Frame order: all `Component.update` → all `Component.lateUpdate` → all `System.update` → all `System.lateUpdate`. `start()` runs on the first update tick.
15
+
16
+ ## ECS hard rules
17
+
18
+ 1. Keep per-entity state in Components so destroying a `GameObject` removes it.
19
+ 2. Put single-entity behavior in Component hooks and cross-entity behavior in Systems; clean up listeners in `onDestroy`.
20
+ 3. Bootstrap only creates and wires resources, Systems, GameObjects, and Components.
21
+ 4. Use `static componentName` for custom Components and observers rather than ad-hoc scene scans.
22
+ 5. Game code uses renderer plugins or registered `Renderer` / `Renderer3D` subclasses, not raw Pixi, Three, or DOM. Host-owning plugins are exceptions.
23
+ 6. Configure through constructor params; trigger runtime actions from lifecycle/event Components.
39
24
 
40
25
  ## Common pitfalls
41
26
 
42
- | Symptom | Fix |
43
- | --- | --- |
44
- | Blank canvas | Base renderer system registered; `autoStart` or `game.start()` |
45
- | Nothing draws | Matching sub-system (e.g. `ImgSystem`) before components |
46
- | `getSystem` undefined | Pass class, not string |
47
- | Resource missing / blank sprite | `loadConfig` or `addResource` + `preload` + `LOAD_EVENT.COMPLETE` before use |
48
- | TS / runtime API guess wrong | Prefer `$combos-engine-development` → `references/api-guessing-cases.md`, not `node_modules` digs |
27
+ - Prefer `game.getSystem(SystemClass)`. String lookup matches `static systemName`, not the class name.
28
+ - A blank canvas usually means the base renderer is missing or the game is not started; missing content usually means its renderer subsystem is absent.
29
+ - Register resources with `resource.addResource`; `preload` only removes first-use delay.
30
+ - `@Field` details belong to `@combos-fun/inspector-decorator`; engine `IDEProp` is legacy.
49
31
 
50
32
  ## See also
51
33
 
52
- - [`references/public-api.md`](references/public-api.md) — exports, `GameParams`, host lifecycle, `resource` API
53
- - `@combos-fun/engine/plugin-authoring` — new plugin package spec
34
+ - [`references/public-api.md`](references/public-api.md)
35
+ - [`plugin-authoring.md`](plugin-authoring.md)
@@ -1001,7 +1001,7 @@ class Scene extends GameObject {
1001
1001
  }
1002
1002
 
1003
1003
  /** Generated at build from package.json */
1004
- const version = "0.0.44";
1004
+ const version = "0.0.46";
1005
1005
 
1006
1006
  /**
1007
1007
  * Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
@@ -1652,6 +1652,8 @@ const SLOT_DEFAULT_TYPE = {
1652
1652
  model: 'glb',
1653
1653
  mtl: 'mtl',
1654
1654
  bin: 'bin',
1655
+ vertex: 'vert',
1656
+ fragment: 'frag',
1655
1657
  };
1656
1658
  const EXT_TO_TYPE = {
1657
1659
  png: 'png',
@@ -1676,6 +1678,9 @@ const EXT_TO_TYPE = {
1676
1678
  dae: 'dae',
1677
1679
  ply: 'ply',
1678
1680
  bin: 'bin',
1681
+ vert: 'vert',
1682
+ frag: 'frag',
1683
+ glsl: 'glsl',
1679
1684
  };
1680
1685
  function extensionOf(url) {
1681
1686
  const path = url.split('?')[0].split('#')[0];
@@ -1694,6 +1699,8 @@ function defaultSlotForResourceType(resourceType) {
1694
1699
  return 'video';
1695
1700
  if (resourceType === 'MODEL' || resourceType === 'GLB')
1696
1701
  return 'model';
1702
+ if (resourceType === 'SHADER')
1703
+ return 'fragment';
1697
1704
  return 'image';
1698
1705
  }
1699
1706
  function wrapSlot(slot, value, resourceName) {
@@ -1873,6 +1880,7 @@ exports.RESOURCE_TYPE = void 0;
1873
1880
  RESOURCE_TYPE["VIDEO"] = "VIDEO";
1874
1881
  RESOURCE_TYPE["GLB"] = "GLB";
1875
1882
  RESOURCE_TYPE["MODEL"] = "MODEL";
1883
+ RESOURCE_TYPE["SHADER"] = "SHADER";
1876
1884
  })(exports.RESOURCE_TYPE || (exports.RESOURCE_TYPE = {}));
1877
1885
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('json', resourceLoader$1.XhrResponseType.Json);
1878
1886
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('tex', resourceLoader$1.XhrResponseType.Json);
@@ -1890,6 +1898,9 @@ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('bin', resourceLoader$1.Xhr
1890
1898
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('obj', resourceLoader$1.XhrResponseType.Text);
1891
1899
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('mtl', resourceLoader$1.XhrResponseType.Text);
1892
1900
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('dae', resourceLoader$1.XhrResponseType.Text);
1901
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('vert', resourceLoader$1.XhrResponseType.Text);
1902
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('frag', resourceLoader$1.XhrResponseType.Text);
1903
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('glsl', resourceLoader$1.XhrResponseType.Text);
1893
1904
  const RESOURCE_TYPE_STRATEGY = {
1894
1905
  png: resourceLoader$1.ImageLoadStrategy,
1895
1906
  jpg: resourceLoader$1.ImageLoadStrategy,
@@ -1909,6 +1920,9 @@ const RESOURCE_TYPE_STRATEGY = {
1909
1920
  dae: resourceLoader$1.XhrLoadStrategy,
1910
1921
  ply: resourceLoader$1.XhrLoadStrategy,
1911
1922
  bin: resourceLoader$1.XhrLoadStrategy,
1923
+ vert: resourceLoader$1.XhrLoadStrategy,
1924
+ frag: resourceLoader$1.XhrLoadStrategy,
1925
+ glsl: resourceLoader$1.XhrLoadStrategy,
1912
1926
  };
1913
1927
  /**
1914
1928
  * Resource manager
@@ -2150,6 +2164,10 @@ class Resource extends EventEmitter__default.default {
2150
2164
  }
2151
2165
  /** Resource manager single instance */
2152
2166
  const resource = new Resource();
2167
+ resource.registerInstance(exports.RESOURCE_TYPE.SHADER, (res) => ({
2168
+ vertex: typeof res.data?.vertex === 'string' ? res.data.vertex : '',
2169
+ fragment: typeof res.data?.fragment === 'string' ? res.data.fragment : '',
2170
+ }));
2153
2171
 
2154
2172
  /** Decorators util */
2155
2173
  const decorators = {