From b93cd2c3f9592049d6152c2e759ecba4cfc7e1be Mon Sep 17 00:00:00 2001 From: hypercross Date: Fri, 3 Apr 2026 15:28:02 +0800 Subject: [PATCH] feat: add agents.md --- AGENTS.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0ac16b0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,101 @@ +# AGENTS.md - boardgame-phaser + +## Project Overview + +A Phaser 3 framework for building web board games, built on top of `boardgame-core` (state management with Preact Signals + Mutative). Uses a pnpm monorepo with two packages: + +- **`packages/framework`** (`boardgame-phaser`) — Reusable library: reactive scenes, signal→Phaser bindings, input/command bridge, Preact UI components +- **`packages/sample-game`** — Demo Tic-Tac-Toe game using the framework + +## Commands + +### Root level +```bash +pnpm dev # Start sample-game dev server (Vite + HMR) +pnpm build # Build framework, then sample-game +pnpm build:framework # Build framework only +pnpm preview # Preview sample-game production build +``` + +### Framework (`packages/framework`) +```bash +pnpm --filter boardgame-phaser build # tsup → dist/index.js + dist/index.d.ts +pnpm --filter boardgame-phaser typecheck # tsc --noEmit +``` + +### Sample game (`packages/sample-game`) +```bash +pnpm --filter sample-game dev # Vite dev server +pnpm --filter sample-game build # tsc && vite build +pnpm --filter sample-game preview # vite preview +``` + +### Dependency setup +```bash +# boardgame-core is a local dependency at ../boardgame-core +# After changes to boardgame-core, rebuild it and copy dist: +cd ../boardgame-core && pnpm build +# Then copy dist into the pnpm symlink (pnpm file: links don't include dist/): +cp -r dist/* ../boardgame-phaser/node_modules/.pnpm/boardgame-core@file+..+boardgame-core_*/node_modules/boardgame-core/dist/ +``` + +### Testing +No test framework is configured yet. When adding tests, use **Vitest** (consistent with boardgame-core): +```bash +# In packages/framework: +pnpm add -D vitest +# Run all tests: +pnpm vitest run +# Run a single test file: +pnpm vitest run src/bindings/index.test.ts +# Run tests matching a pattern: +pnpm vitest run -t "bindRegion" +# Watch mode: +pnpm vitest +``` + +## Code Style + +### Imports +- Use ESM imports only (`import`/`export`) +- Group imports: external libraries → workspace packages → relative imports +- Use `type` imports for type-only imports: `import type { Foo } from 'bar'` +- Path alias `@/*` maps to `src/*` in both packages + +### Formatting +- 2-space indentation, no semicolons +- Single quotes for strings +- Trailing commas in multi-line objects/arrays +- Max line length: not enforced, but keep reasonable + +### TypeScript +- Strict mode enabled (see `tsconfig.base.json`) +- Prefer explicit types for function return values and public class members +- Use generics with constraints: `>` +- Define local utility types: `type DisposeFn = () => void` +- Use `as any` sparingly; prefer `as unknown as Record` for type narrowing + +### Naming conventions +- **Classes**: PascalCase (`ReactiveScene`, `InputMapper`, `PromptHandler`) +- **Interfaces**: PascalCase with descriptive names (`ReactiveSceneOptions`, `BindRegionOptions`) +- **Functions**: camelCase (`bindSignal`, `createInputMapper`, `createPromptHandler`) +- **Constants**: UPPER_SNAKE_CASE (`CELL_SIZE`, `BOARD_OFFSET`) +- **Type aliases**: PascalCase (`DisposeFn`, `CommandResult`) +- **Factory functions**: `create*` prefix (`createInputMapper`, `createPromptHandler`) + +### Architecture patterns +- **ReactiveScene**: Abstract base class extending `Phaser.Scene`. Subclasses implement `onStateReady()` and `setupBindings()`. Effects are auto-cleaned on scene shutdown via `this.events.on('shutdown', ...)`. +- **Bindings**: Use `effect()` from `@preact/signals-core` to reactively sync signal state to Phaser objects. Always return cleanup functions. +- **Input/Command bridge**: Maps Phaser pointer events to `boardgame-core` command strings. Uses `create*` factory pattern. +- **UI components**: Preact functional components with hooks. Use `className` (not `class`) for CSS classes. + +### Error handling +- Command results use `{ success: true, result } | { success: false, error }` pattern +- Scene effects are cleaned up via the `shutdown` event, not by overriding `shutdown()` +- Use `as any` casts only when Phaser types are incomplete (e.g., `setInteractive`) +- Prompt handlers return `string | null` for validation errors + +### JSX +- `jsxImportSource: "preact"` — no React import needed +- Use `h()` or JSX syntax interchangeably +- Use `className` for CSS class attribute