@caperjs/core 0.5.1 → 0.6.0

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/extras/llms.txt CHANGED
@@ -7,7 +7,7 @@ on every `Container`, build-time auto-discovery of scenes/plugins/popups/entitie
7
7
  and generated TypeScript types for app IDs and assets. Caper is a personal fork
8
8
  of `dill-pixel` by Relish Studios.
9
9
 
10
- **Package version:** `@caperjs/core@6.2.2` · **Peer deps:** `pixi.js@8.x`, `@pixi/sound@^6`, `gsap@^3.13`.
10
+ **Package version:** see `../package.json` (this file ships inside the package) · **Peer deps:** `pixi.js@8.x`, `@pixi/sound@^6`, `gsap@^3.13`.
11
11
 
12
12
  **File citations in this guide** point at the `@caperjs/core` package source
13
13
  (paths relative to this file, e.g. `../src/core/Application.ts`) — those ship
@@ -39,7 +39,8 @@ produce working code.
39
39
  14. [Generated types & virtual modules](#14-generated-types--virtual-modules)
40
40
  15. [Common recipes](#15-common-recipes)
41
41
  16. [Gotchas & verification loop](#16-gotchas--verification-loop)
42
- 17. [API reference index](#17-api-reference-index)
42
+ 17. [Automation bridge — drive the running app](#17-automation-bridge--drive-the-running-app)
43
+ 18. [API reference index](#18-api-reference-index)
43
44
 
44
45
  ---
45
46
 
@@ -213,6 +214,10 @@ subcommands run from the app root.
213
214
  | `vite` | Start the dev server. Caper is wired in through `caper()` in the app's own `vite.config.ts`. |
214
215
  | `vite build` | Production build. |
215
216
  | `vite build && vite preview` | Build then preview locally. |
217
+ | `caper types [--no-assets]` | Regenerate `src/types/caper-app.d.ts` + `caper-assets.d.ts` **without a dev server** (runs AssetPack once unless `--no-assets`). Use after a fresh clone or a rename. |
218
+ | `caper doctor [--offline] [--json]` | One-screen health check: installed vs latest caper, npm vs linked engine (and whether the linked build is stale), generated types present/fresh, asset manifest, agent pointers, peer deps, caches. Exit 1 on any ✗. |
219
+ | `caper agent init [--dir <skillsDir>]` | Install the shipped `caper` agent skill (default `.claude/skills/caper/SKILL.md`) and upsert a pointer block into `AGENTS.md`/`CLAUDE.md`. Re-run after upgrading caper. |
220
+ | `caper agent probe <url> [--action n[=json]]… [--until "<js predicate>"] [--wait ms] [--screenshot p] [--headed] [--json]` | Drive a **running** app headlessly through the automation bridge (§17) in a Chromium you own: boots, sends actions, waits on state, returns context/state/log/errors (+ screenshot). Needs `playwright` in the app's devDependencies. |
216
221
  | `caper update` | Update Caper to latest. |
217
222
  | `caper install` | Install peer deps (rarely needed; normally automatic). |
218
223
  | `caper vo generate [inputDir] [outputDir]` | Voiceover CSV generation from locales. Defaults: `./src/locales` → `./src/assets/audio/vo/csv`. |
@@ -1282,9 +1287,9 @@ implementation of the auto-wiring. Know they exist for debugging.
1282
1287
 
1283
1288
  ### 14.4 Regenerating
1284
1289
 
1285
- Types regen on dev-server restart. After renaming a scene / plugin / popup /
1286
- entity: delete the stale `caper-app.d.ts` / `caper-assets.d.ts`, then
1287
- the dev server they're re-emitted from scratch.
1290
+ Types regen on dev-server restart, or on demand with `npx caper types`
1291
+ (no server; runs AssetPack once unless `--no-assets`). After renaming a scene /
1292
+ plugin / popup / entity, or on a fresh clone, run it before typechecking.
1288
1293
 
1289
1294
  **Source references:** [build/plugins/assetTypes.mjs](../build/plugins/assetTypes.mjs).
1290
1295
 
@@ -1505,10 +1510,11 @@ Do not start the dev server yourself — it runs forever and blocks.
1505
1510
 
1506
1511
  ### 16.3 Regenerate types after renames
1507
1512
 
1508
- After renaming a scene/plugin/popup/entity, delete
1509
- `src/types/caper-app.d.ts` and `src/types/caper-assets.d.ts` (they're
1510
- generated), then run `pnpm dev`. Old IDs stuck in the union cause weird
1511
- downstream type errors.
1513
+ After renaming a scene/plugin/popup/entity run `npx caper types` (regenerates
1514
+ `src/types/caper-app.d.ts` and `caper-assets.d.ts` from scratch, no dev server
1515
+ needed). Same fix for a fresh clone where the generated files are gitignored. Old
1516
+ IDs stuck in the union cause weird downstream type errors. `npx caper doctor`
1517
+ tells you when they are stale.
1512
1518
 
1513
1519
  ### 16.4 Fail loud in plugins (see §1.2)
1514
1520
 
@@ -1543,7 +1549,96 @@ cache produces confusing texture/name mismatches.
1543
1549
 
1544
1550
  ---
1545
1551
 
1546
- ## 17. API reference index
1552
+ ## 17. Automation bridge — drive the running app
1553
+
1554
+ Every app registers itself on `window.Caper` at boot (source:
1555
+ [`../src/core/globals.ts`](../src/core/globals.ts)). This is how an agent,
1556
+ Playwright script, or smoke test drives a Caper app without clicking around.
1557
+
1558
+ ### 17.1 What is always there
1559
+
1560
+ ```ts
1561
+ Caper.apps // Map<appId, app> (appId = caper.config.ts `id`, else 'CaperApplication')
1562
+ Caper.app // last created app
1563
+ await Caper.ready() // resolves when the first app has fully booted (safe to call early)
1564
+ await Caper.ready('my-app-id')
1565
+ ```
1566
+
1567
+ ### 17.2 The automation facade (gated)
1568
+
1569
+ Enabled when **any** of: dev server (`import.meta.env.DEV`), `automation: true`
1570
+ in `caper.config.ts`, or env `VITE_CAPER_AUTOMATION=true` at build time. When on,
1571
+ `Caper.automation[appId]` (also `app.automation`) exposes:
1572
+
1573
+ | Member | What it does |
1574
+ | --- | --- |
1575
+ | `action(name, data?)` | `app.sendAction(name, data)`. Subject to the ActionsPlugin context rules — out-of-context actions are dropped, same as a real input. |
1576
+ | `getContext()` | Current action context as a string (e.g. `'game'`, `'popup'`). |
1577
+ | `getState()` | Whatever the app's registered state getter returns (`undefined` until registered). |
1578
+ | `registerStateGetter(fn)` | App code calls this once to expose a snapshot of game state. |
1579
+ | `notifyStateChanged(state)` | App code calls this on each meaningful change; re-runs pending `waitFor` predicates and logs a `state` entry. |
1580
+ | `waitFor(predicate, { timeoutMs? })` | Resolves with the state the first time `predicate(state)` is true (checked immediately, then on every `notifyStateChanged`). Rejects on timeout. |
1581
+ | `log` | Ring buffer of the last 200 entries: `{ t, kind: 'action' \| 'state' \| 'context', name?, data? }`. Only **dispatched** actions are logged (dropped ones are not). |
1582
+
1583
+ ### 17.3 App-side wiring (once per game)
1584
+
1585
+ ```ts
1586
+ // in the main scene's initialize(), or wherever the game state lives
1587
+ this.app.automation?.registerStateGetter(() => this.store.snapshot());
1588
+ this.store.onChanged.connect((s) => this.app.automation?.notifyStateChanged(s));
1589
+ ```
1590
+
1591
+ Keep the snapshot plain data (no display objects) so predicates stay cheap and
1592
+ serializable for drivers outside the page.
1593
+
1594
+ ### 17.4 Driving it
1595
+
1596
+ Use a browser you own. Launch a separate Chromium with Playwright (isolated,
1597
+ throwaway profile) and point it at the dev server; do **not** attach to or drive the
1598
+ human's own browser session unless they ask you to look at one of their tabs.
1599
+
1600
+ The shipped driver does the common case with no code:
1601
+
1602
+ ```bash
1603
+ npx caper agent probe http://localhost:3000/ --action fire --until "s => s && s.phase === 'resolved'" --screenshot scratch/after-fire.png --json
1604
+ # → { appId, automation, context, state, actions, log, pageErrors, consoleErrors, screenshot, durationMs }; exit 1 on boot/until timeout or page errors
1605
+ ```
1606
+
1607
+ Write your own only when you need more than actions + one predicate:
1608
+
1609
+ ```ts
1610
+ import { chromium } from 'playwright';
1611
+ const browser = await chromium.launch(); // headless; { headless: false } only when a human watches
1612
+ const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
1613
+ page.on('pageerror', (e) => console.error('pageerror', e));
1614
+ await page.goto('http://localhost:3000/');
1615
+ await page.waitForFunction(() => window.Caper?.__readyApps?.size > 0);
1616
+ const result = await page.evaluate(async () => {
1617
+ const app = await Caper.ready();
1618
+ const a = Caper.automation[app.config.id];
1619
+ a.action('fire');
1620
+ const s = await a.waitFor((st) => st?.phase === 'resolved', { timeoutMs: 10_000 });
1621
+ return { context: a.getContext(), state: s, actions: a.log.filter((e) => e.kind === 'action').map((e) => e.name) };
1622
+ });
1623
+ await page.screenshot({ path: 'scratch/after-fire.png' });
1624
+ await browser.close();
1625
+ ```
1626
+
1627
+ Rules of thumb:
1628
+
1629
+ - Prefer `action()` over synthesising pointer events — it goes through the same
1630
+ ActionsPlugin path as a real button, so context gating and action signals behave
1631
+ identically.
1632
+ - If an action seems ignored, check `getContext()` first: it was probably dropped
1633
+ as out-of-context. That is by design (see §1 / gotchas), not a bug.
1634
+ - `waitFor` only re-evaluates on `notifyStateChanged`; if it never resolves, the
1635
+ app is not calling `notifyStateChanged` for that transition.
1636
+ - For a boot-only smoke test you need none of the facade: assert
1637
+ `Caper.apps.size > 0` after `Caper.ready()` and that the page logged no errors.
1638
+
1639
+ ---
1640
+
1641
+ ## 18. API reference index
1547
1642
 
1548
1643
  Flat jump table. Name → section → one-line.
1549
1644
 
@@ -1604,5 +1699,5 @@ Flat jump table. Name → section → one-line.
1604
1699
 
1605
1700
  ---
1606
1701
 
1607
- **Last updated:** `@caperjs/core@6.2.2` (PixiJS 8.x). When in doubt, read the
1702
+ **Last updated:** with `@caperjs/core@0.5.x` (PixiJS 8.x); version in `../package.json`. When in doubt, read the
1608
1703
  cited framework source file — signatures and defaults are authoritative there.
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: caper
3
+ description: Work on a game built with the Caper engine (@caperjs/core, PixiJS v8). Use before touching scenes, entities, popups, UI, plugins, caper.config.ts, assets, generated types, or the dev/verify loop in any app that depends on @caperjs/core. Routes you to the exact section of the shipped reference (llms.txt) instead of the whole engine, and gives the verify loop (typecheck, build, headless automation bridge). Trigger for "caper", "add a scene/entity/popup/plugin", "factory methods", "add.sprite", "defineScene", "actions", "UICanvas", "FlexContainer", "caper.config", "caper-app.d.ts", "assetpack", "window.Caper", or any error mentioning @caperjs.
4
+ ---
5
+
6
+ # Caper — how to work in a Caper app
7
+
8
+ This skill is shipped by `@caperjs/core` and copied here by `caper agent init`.
9
+ Do not edit it; re-run `npx caper agent init` after upgrading caper.
10
+
11
+ ## 1. Read the reference by section, never whole
12
+
13
+ The full consumer reference is `node_modules/@caperjs/core/extras/llms.txt`
14
+ (~1,600 lines). Load only the section you need:
15
+
16
+ ```bash
17
+ grep -n '^## ' node_modules/@caperjs/core/extras/llms.txt # section line numbers
18
+ sed -n '<start>,<end>p' node_modules/@caperjs/core/extras/llms.txt
19
+ ```
20
+
21
+ | You need to… | Read section |
22
+ | --------------------------------------------- | ---------------------------------- |
23
+ | know the rules before writing any code | §1 Rules of engagement |
24
+ | scaffold a scene / entity / popup / plugin | §2.2 CLI, §15 Recipes |
25
+ | boot, `create()`, custom `Application` | §3 |
26
+ | `caper.config.ts`, actions, contexts, data | §4 |
27
+ | scene lifecycle, assets per scene, transitions| §5 |
28
+ | build a display tree (`add.*` / `make.*`) | §6 (full catalog at §6.1) |
29
+ | buttons, flex layout, popups, toasts, HUD | §7 |
30
+ | `app.scenes / actions / popups / audio / …` | §8 |
31
+ | write or fix a plugin | §9 |
32
+ | assets, bundles, AssetPack tags | §11 |
33
+ | signals, store, mixins | §12 |
34
+ | generated types, virtual modules | §14 |
35
+ | drive the running app headlessly | §17 Automation bridge |
36
+ | look up one symbol | §18 API index (name → section) |
37
+
38
+ Engine source also ships: `node_modules/@caperjs/core/src/`. When the doc is
39
+ not enough, open the one file the doc cites, not the whole tree.
40
+
41
+ ## 2. The rules (llms.txt §1, condensed)
42
+
43
+ 1. `caper.config.ts` `plugins: [...]` is authoritative; list every plugin,
44
+ including ones other plugins `require`.
45
+ 2. Fail loud. No silent fallbacks in plugins or config.
46
+ 3. Metadata goes on `defineScene / defineEntity / definePopup / definePlugin`
47
+ wrappers, not class statics. Default-export the class so discovery finds it.
48
+ 4. `this.add.*` / `this.make.*` over `new Sprite()` / `new Text()` /
49
+ `new Graphics()` / `new Container()`. Extend Caper's `Container`, not Pixi's.
50
+ 5. `npx caper add scene|entity|popup|plugin <Name>` before hand-authoring.
51
+ 6. Verify in the running app, not in isolation (see §3 below).
52
+
53
+ ## 3. Verify loop
54
+
55
+ ```bash
56
+ npx caper doctor # 10 lines: which caper, types fresh?, pointers, peers. Fix ✗/⚠ first
57
+ npx caper types # regenerate caper-app.d.ts + caper-assets.d.ts, no dev server (fresh clone, renames)
58
+ pnpm typecheck # or the app's tsc script; first gate after any .ts change
59
+ pnpm build # vite build; catches asset and discovery errors
60
+ ```
61
+
62
+ Then check behaviour live, cheapest first:
63
+
64
+ - **Use your own browser, never the human's.** Launch a separate Chromium with
65
+ Playwright (a script via `npx tsx`, or the Playwright MCP tools) pointed at the
66
+ dev-server URL. Do **not** attach to or drive the human's own Chrome (for
67
+ example claude-in-chrome tabs) unless they ask you to look at a tab of theirs.
68
+ Headless for checks; headed (`headless: false`) only when a human will watch.
69
+
70
+ ```ts
71
+ import { chromium } from 'playwright';
72
+ const browser = await chromium.launch(); // isolated, throwaway profile
73
+ const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
74
+ page.on('pageerror', (e) => console.error('pageerror', e));
75
+ await page.goto('http://localhost:3000/');
76
+ await page.waitForFunction(() => window.Caper?.__readyApps?.size > 0);
77
+ await page.screenshot({ path: 'scratch/after-change.png' });
78
+ await browser.close();
79
+ ```
80
+
81
+ - **Headless via the automation bridge** (dev server, or `automation: true`
82
+ in config, or `VITE_CAPER_AUTOMATION=true`). Shipped driver, no code:
83
+ `npx caper agent probe <url> [--action name[=json]]… [--until "s => …"] [--screenshot p] [--json]`
84
+ → context, state, action log, page/console errors, exit 1 on failure. For
85
+ anything richer, in Playwright: `const app = await Caper.ready(); const a =
86
+ Caper.automation[app.config.id];` then `a.action('name', data)`,
87
+ `a.getContext()`, `a.getState()`, `await a.waitFor(s => …, { timeoutMs })`,
88
+ and inspect `a.log` (last 200 entries). Details: llms.txt §17.
89
+ - **Do not start the dev server yourself** and leave it running in the
90
+ foreground; it never exits. If the human has it running, use it. Otherwise
91
+ ask them to run `pnpm dev` and report.
92
+
93
+ ## 4. Gotchas that cost agents the most time
94
+
95
+ - Out-of-context actions are **dropped by the ActionsPlugin**. That is the
96
+ phase guard; do not add `if (phase !== …)` checks around `sendAction`.
97
+ - `src/types/caper-app.d.ts` and `caper-assets.d.ts` are **generated**. Never
98
+ hand-edit. Missing (fresh clone; they are usually gitignored) or stale after a
99
+ rename → `npx caper types`. No dev server needed.
100
+ - Weird asset / name mismatches → `rm -rf .assetpack .cache dist` and rebuild.
101
+ - Renamed a scene / popup / entity id? Regenerate types (above) or old ids
102
+ linger in the unions and cause confusing downstream errors.
103
+ - If the engine is **linked from a local checkout**, consumer apps resolve the
104
+ built `lib/`; rebuild the engine (`pnpm framework:build` in the caper repo)
105
+ after editing engine source, unless the app's vite config aliases
106
+ `@caperjs/core` to the engine `src/`. `npx caper doctor` reports "linked from
107
+ …" and flags a stale build.
package/lib/caper.mjs CHANGED
@@ -204,7 +204,7 @@ function B(e, t) {
204
204
  }
205
205
  //#endregion
206
206
  //#region src/version.ts
207
- var V = "0.5.1", H = "8.19.0", Mn = " ........ ..... ............ ............. ........... \n ............. ....... ................ ............. .............. \n .............. ......... ............... ............. .............. \n ..... ........... .............. ............ .............. \n ..... ...... ...... .............. ............. ............. \n .............. ...... ..... ............ ............. ..... ...... \n ................... ..... ..... ............. ..... ....... \n ................ .......... ............. ..... ..... ";
207
+ var V = "0.6.0", H = "8.19.0", Mn = " ........ ..... ............ ............. ........... \n ............. ....... ................ ............. .............. \n .............. ......... ............... ............. .............. \n ..... ........... .............. ............ .............. \n ..... ...... ...... .............. ............. ............. \n .............. ...... ..... ............ ............. ..... ...... \n ................... ..... ..... ............. ..... ....... \n ................ .......... ............. ..... ..... ";
208
208
  function U() {
209
209
  let e = `\n${Mn}\n\n v${V} | %cPixi.js v${H} %c| %chttps://github.com/anthonysapp/caper\n\n`;
210
210
  console.log(e, "color: #E91E63; font-weight: 600;", "color: inherit;", "color: #00BCD4; text-decoration: underline;");