@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/README.md +7 -1
- package/build/assetpack.mjs +6 -0
- package/build/plugins/assetTypes.mjs +7 -2
- package/build/plugins/caperConfig.mjs +3 -0
- package/cli/agent.mjs +112 -0
- package/cli/agent.test.mjs +104 -0
- package/cli/create.mjs +10 -1
- package/cli/doctor.mjs +193 -0
- package/cli/doctor.test.mjs +142 -0
- package/cli/probe.mjs +368 -0
- package/cli/probe.test.mjs +74 -0
- package/cli/types.mjs +101 -0
- package/cli/types.test.mjs +58 -0
- package/cli.mjs +12 -0
- package/extras/llms.txt +106 -11
- package/extras/skills/caper/SKILL.md +107 -0
- package/lib/caper.mjs +1 -1
- package/lib/caper.mjs.map +1 -1
- package/package.json +2 -1
- package/src/version.ts +1 -1
- package/templates/app/default/README.md +2 -0
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:**
|
|
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. [
|
|
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
|
|
1286
|
-
|
|
1287
|
-
|
|
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
|
|
1509
|
-
`src/types/caper-app.d.ts` and `
|
|
1510
|
-
|
|
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.
|
|
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@
|
|
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.
|
|
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;");
|