feat: add agents.md
This commit is contained in:
parent
588d28ff07
commit
b93cd2c3f9
|
|
@ -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: `<TState extends Record<string, unknown>>`
|
||||||
|
- Define local utility types: `type DisposeFn = () => void`
|
||||||
|
- Use `as any` sparingly; prefer `as unknown as Record<string, unknown>` 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
|
||||||
Loading…
Reference in New Issue