# `@combos-fun/engine` — Agent short card

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`.

## When to read

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.

Public API tables, host `postMessage` protocol, and long bootstrap samples: [`references/public-api.md`](references/public-api.md), [`references/bootstrap-examples.md`](references/bootstrap-examples.md).

## Microkernel model

- **Kernel** `@combos-fun/engine`: `Game`, `Scene`, `GameObject`, `Component`, `System`, `Transform`, `resource`, `decorators`. **No** built-in rendering / physics / audio.
- **Extension**: `game.addSystem(new XxxSystem(...))` then `gameObject.addComponent(new Xxx(...))`.
- **Observer**: `@decorators.componentObserver({ Name: ['prop'] })` on a System; drain `this.componentObserver.clear()` in `update()` and switch on `OBSERVER_TYPE.ADD | CHANGE | REMOVE`.
- **Frame order**: `Component.update` → `Component.lateUpdate` → `System.update` → `System.lateUpdate`. `start()` fires inline on the first `update` tick.

## ECS hard rules (mandatory)

1. **Entity state in Components** — no module-scope / closure entity stores. Destroying a `GameObject` must drop its state.
2. **Behaviour in Component / System hooks** — no bootstrap event handlers, no `setInterval` / `game.ticker.add` for game logic; tear down listeners in `onDestroy`.
3. **Bootstrap only wires** — create Game / Systems / GameObjects / Components; no game `if` / loops in entry files.
4. **One concern per Component; cross-entity logic in Systems** — custom types need `static componentName` / observer drain, not ad-hoc scene scans.
5. **No raw Pixi / Three / DOM outside Renderer pattern** — use `plugin-renderer-*` / `plugin-renderer-3d-*` or registered `Renderer` / `Renderer3D`.
6. **Configure via constructor params** — runtime triggers from other Component hooks, not bootstrap.

## Decision flowchart

```
Runs only once at startup to wire things?
├── YES: Only creates GameObjects/Components/Systems/resources?
│   ├── YES → bootstrap / entry file
│   └── NO (contains logic) → Component or System
└── NO: Runs per-frame or reacts to events?
    ├── Single-entity concern → Component
    ├── Cross-entity concern → System with @componentObserver
    └── Rendering integration → Renderer (2D) / Renderer3D (3D) subclass
```

## Common pitfalls

| Symptom | Fix |
| --- | --- |
| Blank canvas | Base renderer system registered; `autoStart` or `game.start()` |
| Nothing draws | Matching sub-system (e.g. `ImgSystem`) before components |
| `getSystem` undefined | Pass class, not string |
| Resource missing / blank sprite | `loadConfig` or `addResource` + `preload` + `LOAD_EVENT.COMPLETE` before use |
| TS / runtime API guess wrong | Prefer `$combos-engine-development` → `references/api-guessing-cases.md`, not `node_modules` digs |

## See also

- [`references/public-api.md`](references/public-api.md) — exports, `GameParams`, host lifecycle, `resource` API
- [`references/bootstrap-examples.md`](references/bootstrap-examples.md) — minimal 2D / 3D samples
- `@combos-fun/engine/plugin-authoring` — new plugin package spec
