Files
FoundryVTT/CLAUDE.md
2025-11-06 14:04:48 +01:00

1598 lines
48 KiB
Markdown

# Foundry VTT + PF1e Module Development Environment
> **Version**: 1.0.0 | **Last Updated**: 2025-01-29 | **Maintainer**: Development Team
## Project Overview
### Purpose
This is a development environment for creating custom macros and debugging the Foundry VTT virtual tabletop with the Pathfinder 1e (PF1e) game system. The project combines the Foundry VTT core application (v11.315) with the PF1e system module (v10.8) to enable macro development, automation scripting, and troubleshooting of game mechanics.
### Key Objectives
- Develop custom macros for Pathfinder 1e character automation
- Debug and troubleshoot Foundry VTT and PF1e system issues
- Automate complex character abilities (e.g., Magus Arcane Pool, Haste buff management)
- Provide AI-assisted development via Claude Code with extensive MCP server integration
- Maintain a professional development environment with linting, formatting, and type checking
### Project Type
- [x] Virtual Tabletop Platform (Foundry VTT)
- [x] Game System Module (Pathfinder 1e)
- [x] Macro Development (JavaScript automation scripts)
- [x] Electron Application (Desktop runtime)
- [ ] Web Application
- [ ] CLI Tool
- [ ] Library/Package
### Target Users/Audience
Game Masters (GMs) and players using Foundry VTT for Pathfinder 1e campaigns who need custom automation, particularly for complex character abilities and buff management.
---
## Technology Stack
### Core Technologies
- **Language(s)**: JavaScript (ES6+), TypeScript definitions (.d.ts)
- **Runtime**: Node.js v16-19 (via Electron)
- **Platform**: Electron (cross-platform desktop app)
- **Foundry VTT Version**: v11.315 (stable)
- **Game System**: Pathfinder 1e v10.8
### Frontend Technologies
#### Rendering & UI
- **Canvas Engine**: PIXI.js v7.2.4 (WebGL/Canvas2D rendering)
- `@pixi/graphics-smooth` - Smooth graphics rendering
- `@pixi/particle-emitter` - Particle effects
- **DOM Manipulation**: jQuery v3.6.4
- **Template Engine**: Handlebars v4.7.7
- **Rich Text Editor**: ProseMirror v1.x (modular editor)
- **Alternative Editor**: TinyMCE v6.7.1
- **Styling**: LESS → CSS compilation
#### UI Framework
```javascript
// Foundry VTT uses vanilla JavaScript with global objects
game // Main game instance
ui // UI managers (notifications, chat, etc.)
canvas // Canvas rendering system
CONFIG // Global configuration
```
### Backend Technologies
#### Server Framework
- **Web Server**: Express.js v4.18.2
- **Session Management**: express-session with NeDB store
- **File Upload**: express-fileupload
- **Compression**: compression middleware
- **Static Files**: serve-static
#### Database & Storage
- **Primary Database**: NeDB v1.8.0 (embedded NoSQL)
- World data storage
- Compendium packs
- Session management
- **Alternative**: classic-level (LevelDB abstraction)
- **File Storage**: Local filesystem (fs-extra v11.1.1)
- **Cloud Storage**: AWS S3 (@aws-sdk/client-s3 v3.312.0)
#### Real-Time Communication
- **Protocol**: Socket.io v4.6.1 (WebSocket + fallbacks)
- **Features**:
- Room-based communication (per world)
- Real-time document synchronization
- Audio/video signaling
- Client-server data updates
### PF1 System Technologies
#### Build & Development
- **Module System**: ES Modules (.mjs files)
- **Build Tool**: Vite v4.5.0 (with HMR support)
- **Linting**: ESLint v8.53.0
- **Code Formatting**: Prettier v3.1.0
- **Testing Framework**: @ethaks/fvtt-quench (Foundry-specific testing)
- **Documentation Generator**: TypeDoc v0.25.3
- **Git Hooks**: Husky v8.0.3 with lint-staged
#### Development Scripts
```json
{
"build": "vite build",
"build:watch": "vite build --mode development --watch",
"packs:extract": "node ./tools/packs.mjs extract",
"packs:compile": "node ./tools/packs.mjs compile",
"lint": "eslint . --cache",
"format": "prettier --write --cache .",
"docs": "typedoc"
}
```
### Infrastructure & DevOps
- **Version Control**: Git
- **AI Development**: Claude Code with 8 MCP servers
- serena (code navigation + memory)
- sequential-thinking (complex reasoning)
- context7 (library documentation)
- memory (knowledge graph)
- fetch (web content)
- windows-mcp (desktop automation)
- playwright (browser automation)
- database-server (SQL access)
### Development Tools
- **IDE**: Visual Studio Code (recommended)
- **Package Manager**: npm
- **Node Version**: 16-19 (Electron compatible)
- **Module Format**: ES Modules (.mjs) for PF1 system, CommonJS for Foundry core
---
## Project Structure
### Directory Layout
```
c:\DEV\Foundry/
├── src/ # Source code root
│ ├── FoundryVTT-11.315/ # Foundry VTT core application
│ │ └── resources/app/ # Electron app resources
│ │ ├── main.js # Electron main process entry
│ │ ├── package.json # Core dependencies (Node 16-19)
│ │ ├── client/ # Client-side JavaScript
│ │ │ ├── game.js # Main game client (Game class)
│ │ │ ├── config.js # Configuration constants
│ │ │ ├── apps/ # Application windows (FormApplication)
│ │ │ ├── audio/ # Audio/sound management
│ │ │ ├── av/ # Audio/video (WebRTC)
│ │ │ ├── canvas/ # PIXI.js canvas rendering layers
│ │ │ ├── core/ # Core utilities (hooks, settings)
│ │ │ ├── dice/ # Dice rolling system (Roll, DiceTerm)
│ │ │ ├── pixi/ # PIXI.js extensions
│ │ │ ├── tours/ # User onboarding tours
│ │ │ └── ui/ # UI components (notifications, dialogs)
│ │ ├── common/ # Shared client/server code
│ │ │ ├── documents/ # Document base classes
│ │ │ ├── abstract/ # Abstract data models
│ │ │ ├── config.mjs # Shared configuration
│ │ │ ├── constants.mjs # Constants and enums
│ │ │ ├── utils/ # Utility functions
│ │ │ └── packages/ # Package management
│ │ ├── dist/ # Compiled/bundled code
│ │ ├── public/ # Public web assets
│ │ │ ├── scripts/ # Bundled client scripts
│ │ │ │ ├── foundry.js # Main bundled script (~2MB)
│ │ │ │ └── worker.js # Web worker for background tasks
│ │ │ ├── lang/en.json # English localization
│ │ │ ├── tours/ # Tour definitions (JSON)
│ │ │ └── nue/ # NUE engine assets
│ │ ├── templates/ # Handlebars templates (.html)
│ │ ├── prosemirror/ # ProseMirror rich text editor
│ │ └── node_modules/ # Foundry core dependencies
│ │
│ ├── foundryvtt-pathfinder1-v10.8/ # Pathfinder 1e System Module
│ │ ├── pf1.js # System entry point (imports pf1.mjs)
│ │ ├── pf1.mjs # Main system module (ES module)
│ │ ├── package.json # PF1 dev dependencies & scripts
│ │ ├── public/ # Public system files
│ │ │ └── system.json # System manifest (metadata)
│ │ ├── module/ # System source code (ES modules)
│ │ │ ├── config.mjs # PF1 game configuration
│ │ │ │ # Defines: abilities, skills, alignments, saves, etc.
│ │ │ ├── config.d.ts # TypeScript definitions for config
│ │ │ ├── modules.mjs # Module registry/loader
│ │ │ ├── migration.mjs # Data migration system
│ │ │ ├── patch-core.mjs # Foundry core monkey patches
│ │ │ ├── socket.mjs # Socket event handlers
│ │ │ ├── action-use/ # Action usage system
│ │ │ │ ├── action-use.mjs # Main action resolution
│ │ │ │ ├── chat-attack.mjs # Attack chat cards
│ │ │ │ └── chat-context.mjs # Chat context menu
│ │ │ ├── applications/ # UI applications
│ │ │ │ ├── actor/ # Actor sheets by type
│ │ │ │ │ ├── character-sheet.mjs
│ │ │ │ │ ├── npc-sheet.mjs
│ │ │ │ │ └── vehicle-sheet.mjs
│ │ │ │ ├── item/ # Item sheets
│ │ │ │ │ └── item-sheet.mjs
│ │ │ │ ├── compendium-browser/ # Compendium browser
│ │ │ │ ├── sidebar/ # Sidebar applications
│ │ │ │ └── settings/ # Settings dialogs
│ │ │ ├── canvas/ # Canvas layer extensions
│ │ │ ├── chat/ # Chat message handlers
│ │ │ ├── components/ # Reusable UI components
│ │ │ ├── dice/ # Dice rolling extensions
│ │ │ │ └── terms/ # Custom dice terms
│ │ │ ├── documents/ # Document classes
│ │ │ │ ├── actor/ # ActorPF class
│ │ │ │ │ ├── entity.mjs # Main actor class
│ │ │ │ │ ├── calculate.mjs # Stat calculation
│ │ │ │ │ ├── rest.mjs # Rest mechanics
│ │ │ │ │ └── spellcasting.mjs # Spellcasting logic
│ │ │ │ ├── item/ # ItemPF class
│ │ │ │ │ ├── entity.mjs # Main item class
│ │ │ │ │ └── types/ # Item type handlers
│ │ │ │ ├── chat-message.mjs # ChatMessagePF
│ │ │ │ └── combat.mjs # CombatPF
│ │ │ ├── migration/ # Version migration scripts
│ │ │ ├── registry/ # Feature registries
│ │ │ ├── test/ # Unit tests (Quench)
│ │ │ ├── utils/ # Utility functions
│ │ │ └── _module.mjs # Re-exports for easy import
│ │ ├── lang/ # Localization files
│ │ │ ├── en.json # English (primary language)
│ │ │ ├── de.json # German
│ │ │ ├── fr.json # French
│ │ │ ├── es.json # Spanish
│ │ │ ├── it.json # Italian
│ │ │ ├── cn.json # Chinese
│ │ │ └── pt_BR.json # Portuguese (Brazil)
│ │ ├── less/ # LESS stylesheets
│ │ │ ├── pf1.less # Main stylesheet
│ │ │ └── [various component styles]
│ │ ├── packs/ # Compendium packs (.db files)
│ │ │ # Pre-packaged actors, items, spells, feats, etc.
│ │ ├── help/ # Help documentation
│ │ ├── changelogs/ # Version changelogs
│ │ ├── tools/ # Build/dev tools
│ │ │ └── packs.mjs # Compendium pack compiler
│ │ ├── .eslintrc.js # ESLint configuration
│ │ ├── .prettierrc.json # Prettier formatting config
│ │ ├── vite.config.js # Vite build configuration
│ │ ├── typedoc.json # TypeDoc documentation config
│ │ └── hooks.d.ts # TypeScript hook definitions
│ │
│ ├── macro.js # Custom Arcane Pool macro
│ │ # Magus class feature automation with dialog UI
│ ├── macro_haste.js # Haste buff automation macro
│ │ # Intercepts attacks to apply Haste effects
│ └── zeratal.json # Character data export
│ # Example Magus character for testing
├── .claude/ # Claude Code configuration
│ ├── settings.json # Shared Claude settings
│ ├── settings.local.json # Local user settings
│ ├── agents/ # Specialized AI agents (8 total)
│ ├── commands/ # Slash commands (9 total)
│ ├── output-styles/ # Output formatting (6 styles)
│ ├── skills/ # Custom skills
│ ├── hooks/ # Event hooks
│ └── tools/ # Utility scripts
├── .mcp.json # MCP server configuration
├── .git/ # Git repository
├── .gitignore # Git ignore rules
├── CLAUDE.md # This file - project documentation
├── README.md # Project overview
└── QUICKSTART.md # Quick start guide
```
### Key Files
- **Foundry Entry**: [main.js](src/FoundryVTT-11.315/resources/app/main.js) - Electron main process
- **Client Entry**: [foundry.js](src/FoundryVTT-11.315/resources/app/public/scripts/foundry.js) - Bundled client
- **PF1 Entry**: [pf1.js](src/foundryvtt-pathfinder1-v10.8/pf1.js) → [pf1.mjs](src/foundryvtt-pathfinder1-v10.8/pf1.mjs) - System initialization
- **PF1 Config**: [config.mjs](src/foundryvtt-pathfinder1-v10.8/module/config.mjs) - Game system configuration
- **System Manifest**: [system.json](src/foundryvtt-pathfinder1-v10.8/public/system.json) - System metadata
- **Custom Macros**: [macro.js](src/macro.js), [macro_haste.js](src/macro_haste.js) - Automation scripts
- **Character Data**: [zeratal.json](src/zeratal.json) - Test character export
### Module Organization
The project follows a clear separation between:
1. **Foundry Core** - Generic VTT platform code
2. **PF1 System** - Pathfinder 1e game rules and mechanics
3. **Custom Macros** - User-specific automation scripts
Each layer builds on the previous:
```
Custom Macros
↓ (uses)
PF1 System API (ActorPF, ItemPF, CONFIG.PF1)
↓ (extends)
Foundry Core API (Actor, Item, game, ui, canvas)
↓ (runs on)
Electron + Node.js
```
---
## Code Style & Standards
### Naming Conventions
#### Variables & Functions
- Use `camelCase` for local variables and function names
- Use `_camelCase` for private/internal variables (PF1 system uses this convention)
- Use descriptive names that reveal intent
- Prefix boolean variables with `is`, `has`, `can`, or `should`
```javascript
// Good
const arcanePool = actor.system.resources.classFeat_arcanePool;
let selectedBuffs = [];
const isActive = buff.system.active;
const hasHasteBuff = actor.items.find(i => i.name === "Haste");
// Avoid
const ap = actor.system.resources.classFeat_arcanePool;
let x = [];
const flag = buff.system.active;
```
#### Classes & Interfaces
- Use `PascalCase` for classes and constructors
- Suffix with descriptive type (e.g., `Sheet`, `Application`, `Service`)
- Foundry documents often use a suffix (e.g., `ActorPF`, `ItemPF`)
```javascript
// Good
class ActorPF extends Actor { }
class CharacterSheetPF extends ActorSheet { }
class DicePoolBuilder { }
// Avoid
class actor { }
class sheet1 { }
```
#### Constants & Configuration
- Use `UPPER_SNAKE_CASE` for true constants
- Use `camelCase` for configuration objects
- Global CONFIG uses `UPPER_CASE` keys with nested objects
```javascript
// Good
const MAX_ARCANE_POOL = 10;
const config = { abilities: { str: "Strength" } };
CONFIG.PF1.abilities = { str: "STR", dex: "DEX" };
// Avoid
const maxarcanepool = 10;
const CONFIG = { abilities: { str: "Strength" } };
```
#### Files & Folders
- Use `kebab-case.mjs` for ES module files (PF1 system)
- Use `kebab-case.js` for CommonJS files (Foundry core)
- Use `descriptive_name.js` or `camelCase.js` for macro files
- Use `_module.mjs` for re-export aggregation files
```
actor-sheet.mjs # PF1 system module
game.js # Foundry core
macro_arcane_pool.js # Custom macro
_module.mjs # Re-export file
```
### Code Organization
#### File Size
- Keep files under 500 lines when possible
- Split large classes using mixins or composition
- Use `_module.mjs` files to aggregate related exports
#### Function Complexity
- Functions should do one thing well
- Keep functions under 50 lines when possible
- Maximum 5-6 parameters; use options objects for more
- Use async/await for all asynchronous operations
```javascript
// Good - focused function
async function applyArcanePoolBuff(actor, buffName, duration) {
const buff = actor.items.find(i => i.name === buffName);
if (!buff) return false;
await buff.update({
"system.active": true,
"system.duration.value": duration
});
return true;
}
// Avoid - doing too much
function processArcanePool(actor, buffName, duration, bonusType,
bonusAmount, target, options, callback) {
// 200+ lines of mixed concerns
}
```
#### Module Import Organization
Order imports in this sequence:
1. Foundry core imports
2. PF1 system imports
3. Utility imports
4. Local module imports
```javascript
// Good
import { ActorSheet } from "../../common/documents/actor.mjs";
import { CONFIG } from "../../common/config.mjs";
import { ActorPF } from "../documents/actor/entity.mjs";
import { applyBuff } from "../utils/buffs.mjs";
import { CharacterSheetHelper } from "./_helper.mjs";
// Avoid mixing import sources
```
### Comments & Documentation
#### When to Comment
- **DO**: Explain *why* something is done, especially workarounds
- **DO**: Document complex Pathfinder 1e rules implementation
- **DO**: Add TODOs with context: `// TODO: Support metamagic feats`
- **DO**: Explain Foundry API quirks or version-specific behavior
- **DON'T**: State the obvious
- **DON'T**: Leave commented-out code (use git history)
```javascript
// Good - explains why
// Using setTimeout to ensure Foundry's hook cycle completes
// before updating the actor. See Foundry issue #7234
setTimeout(() => actor.update(data), 0);
// Avoid - states the obvious
// Set arcane pool to 5
arcanePool.value = 5;
```
#### JSDoc Documentation
Document all public APIs, classes, and exported functions:
```javascript
/**
* Applies an Arcane Pool enhancement to a weapon
* @param {ActorPF} actor - The character using Arcane Pool
* @param {ItemPF} weapon - The weapon to enhance
* @param {number} bonus - Enhancement bonus (1-5)
* @param {string[]} abilities - Special abilities (e.g., "keen", "flaming")
* @returns {Promise<boolean>} True if successfully applied
* @example
* await applyArcanePoolEnhancement(actor, weapon, 2, ["keen"]);
*/
async function applyArcanePoolEnhancement(actor, weapon, bonus, abilities) {
// Implementation
}
```
### Error Handling
#### Strategy
- Use try-catch blocks for Foundry API calls that may fail
- Use `ui.notifications` for user-facing errors
- Log errors to console for debugging
- Never swallow errors silently
- Validate inputs early (fail fast)
```javascript
// Good
try {
if (!actor) {
ui.notifications.warn("You must select a token!");
return;
}
const result = await actor.update({"system.hp.value": newHP});
ui.notifications.info(`HP updated to ${newHP}`);
} catch (error) {
console.error("Failed to update HP:", error);
ui.notifications.error("Failed to update HP. Check console for details.");
}
// Avoid
try {
actor.update({"system.hp.value": newHP});
} catch (e) {
// Silent failure
}
```
### Performance Considerations
- Use `fromUuidSync()` instead of `fromUuid()` when possible (synchronous is faster)
- Cache actor/item lookups instead of repeated searches
- Batch document updates when updating multiple fields
- Use `actor.updateSource()` for preparation phase (before rendering)
- Avoid unnecessary re-renders in dialogs
```javascript
// Good - batch update
await actor.update({
"system.hp.value": newHP,
"system.resources.arcanePool.value": newPool,
"system.attributes.ac.total": newAC
});
// Avoid - multiple updates
await actor.update({"system.hp.value": newHP});
await actor.update({"system.resources.arcanePool.value": newPool});
await actor.update({"system.attributes.ac.total": newAC});
```
---
## Foundry VTT API Reference
### Official Documentation
**Primary API Documentation**: [Foundry VTT API v11](https://foundryvtt.com/api/v11/)
**Key API Modules**:
- **Documents**: [foundry.documents](https://foundryvtt.com/api/v11/modules/foundry.documents.html) - Actor, Item, ChatMessage, etc.
- **Client Classes**: [client](https://foundryvtt.com/api/v11/modules/client.html) - Game, Canvas, UI managers
- **Applications**: [client.applications](https://foundryvtt.com/api/v11/modules/client.applications.html) - FormApplication, Dialog
- **PIXI**: [pixi](https://foundryvtt.com/api/v11/modules/pixi.html) - Canvas rendering
- **Dice**: [client.dice](https://foundryvtt.com/api/v11/modules/client.dice.html) - Roll, DiceTerm
### Global Objects
Foundry VTT provides several global objects available in all scripts:
```javascript
// Core game instance
game // Main Game object
game.actors // Actor collection
game.items // Item collection
game.scenes // Scene collection
game.users // User collection
game.macros // Macro collection
game.settings // Settings registry
game.i18n // Localization
// UI managers
ui // UI manager
ui.notifications // Toast notifications
ui.chat // Chat sidebar
ui.combat // Combat tracker
ui.actors // Actor directory
ui.items // Item directory
// Canvas rendering
canvas // Canvas manager
canvas.tokens // Token layer
canvas.lighting // Lighting layer
canvas.walls // Walls layer
// Configuration
CONFIG // Global configuration object
CONFIG.Actor // Actor configuration
CONFIG.Item // Item configuration
CONFIG.PF1 // PF1 system configuration
// Utilities
Hooks // Hook system
fromUuid() // Get document by UUID
fromUuidSync() // Synchronous UUID lookup
```
### Common API Patterns
#### Document Access
```javascript
// Get by ID
const actor = game.actors.get(actorId);
const item = game.items.get(itemId);
// Get by name
const actor = game.actors.getName("Character Name");
const macro = game.macros.getName("Macro Name");
// Get by UUID
const doc = await fromUuid("Actor.abc123.Item.def456");
const doc = fromUuidSync("Actor.abc123.Item.def456"); // Faster, synchronous
// Search collection
const magus = game.actors.find(a => a.name === "Zeratal");
const hastes = game.items.filter(i => i.name.includes("Haste"));
```
#### Document Updates
```javascript
// Update single field
await actor.update({"system.hp.value": 50});
// Update multiple fields (preferred - single transaction)
await actor.update({
"system.hp.value": 50,
"system.attributes.ac.total": 25
});
// Update embedded documents (items)
await actor.updateEmbeddedDocuments("Item", [
{_id: itemId, "system.active": true}
]);
// Create embedded documents
await actor.createEmbeddedDocuments("Item", [itemData]);
// Delete embedded documents
await actor.deleteEmbeddedDocuments("Item", [itemId]);
```
#### Hooks System
```javascript
// One-time hooks (initialization)
Hooks.once("init", () => {
console.log("Foundry initializing...");
});
Hooks.once("ready", () => {
console.log("Foundry ready!");
});
// Recurring hooks
Hooks.on("updateActor", (actor, change, options, userId) => {
console.log(`${actor.name} was updated`);
});
Hooks.on("preCreateItem", (item, data, options, userId) => {
// Can modify data or return false to prevent
return true;
});
// Call custom hooks
Hooks.call("myCustomHook", arg1, arg2);
Hooks.callAll("myCustomHook", arg1, arg2);
```
#### Dialog API
```javascript
// Simple dialog
new Dialog({
title: "Dialog Title",
content: "<p>Dialog content HTML</p>",
buttons: {
yes: {
icon: '<i class="fas fa-check"></i>',
label: "Yes",
callback: (html) => {
console.log("Yes clicked");
}
},
no: {
icon: '<i class="fas fa-times"></i>',
label: "No"
}
},
default: "yes",
render: (html) => {
// Setup event listeners
html.find('.my-input').focus();
},
close: (html) => {
console.log("Dialog closed");
}
}).render(true);
```
#### Notifications
```javascript
// Toast notifications
ui.notifications.info("Information message");
ui.notifications.warn("Warning message");
ui.notifications.error("Error message");
// Persistent notification
ui.notifications.notify("Message", "info", {permanent: true});
```
#### Templates
```javascript
// Render template with data
const html = await renderTemplate(
"systems/pf1/templates/actors/character-sheet.hbs",
{ actor: actor, data: actor.system }
);
// Load template
const template = await getTemplate("path/to/template.hbs");
```
### PF1 System API
#### Actor API (ActorPF)
```javascript
// Access actor data
actor.system.attributes.hp.value // Current HP
actor.system.attributes.hp.max // Max HP
actor.system.attributes.ac.normal.total // AC
actor.system.resources.classFeat_arcanePool.value // Class resource
// Class information
actor.classes // Object of class items
actor.classes["magus"] // Specific class
actor.classes["magus"].level // Class level
// Buff management
const buffs = actor.items.filter(i => i.type === "buff");
const activeBuff = actor.items.find(i =>
i.type === "buff" &&
i.system.active &&
i.name === "Haste"
);
// Spellcasting
const spellbook = actor.system.spells.spellbooks.primary;
spellbook.spells.level1 // 1st level spells
```
#### Item API (ItemPF)
```javascript
// Access item data
item.system.active // Buff active state
item.system.duration.value // Duration remaining
item.system.enhancement // Enhancement bonus
// Item usage
await item.use(options); // Use item (attack, spell, etc.)
await item.roll(); // Roll item
// Item types
item.type === "weapon" // Weapon
item.type === "buff" // Buff/effect
item.type === "spell" // Spell
item.type === "feat" // Feat
item.type === "class" // Class
```
#### Configuration (pf1.config)
```javascript
// Access PF1 configuration
pf1.config.abilities // Ability scores
pf1.config.skills // Skills
pf1.config.alignments // Alignments
pf1.config.saves // Saving throws
pf1.config.buffTargets // Buff target types
pf1.config.bonusTypes // Bonus types
// Via CONFIG global
CONFIG.PF1.abilities // Same as pf1.config.abilities
```
---
## Macro Development Patterns
### Basic Macro Structure
All macros should follow this IIFE (Immediately Invoked Function Expression) pattern:
```javascript
(async () => {
// 1. Validation - check prerequisites
if (!token) {
ui.notifications.warn("You must select a token!");
return;
}
if (!actor) {
ui.notifications.warn("Selected token has no actor!");
return;
}
// 2. Data access - get required data
const arcanePool = actor.system.resources.classFeat_arcanePool;
const magusLevel = actor.classes["magus"]?.level || 0;
// 3. Business logic - main macro functionality
async function doSomething() {
// Implementation
}
// 4. Execution
await doSomething();
// 5. User feedback
ui.notifications.info("Macro completed successfully!");
})();
```
### Dialog-Based Macros
For complex user interactions, use the Dialog API:
```javascript
(async () => {
// Validation
if (!token) {
ui.notifications.warn("You must select a token!");
return;
}
const actor = token.actor;
// Define dialog function
function showDialog() {
// Build HTML content with inline styles
const dialogContent = `
<html>
<head>
<style>
.macro-dialog { padding: 10px; }
.macro-option { margin: 5px 0; }
.macro-button {
padding: 5px 10px;
margin: 2px;
cursor: pointer;
}
</style>
</head>
<body class="macro-dialog">
<h3>Select Options</h3>
<div class="macro-option">
<label>
<input type="checkbox" name="option1" value="keen">
Keen
</label>
</div>
<div class="macro-option">
<label>
<input type="checkbox" name="option2" value="flaming">
Flaming
</label>
</div>
<div class="macro-option">
<label>Bonus:
<select name="bonus">
<option value="1">+1</option>
<option value="2">+2</option>
<option value="3">+3</option>
</select>
</label>
</div>
</body>
</html>
`;
// Create dialog
new Dialog({
title: "Macro Dialog",
content: dialogContent,
buttons: {
confirm: {
icon: '<i class="fas fa-check"></i>',
label: "Confirm",
callback: async (html) => {
// Extract user selections
const selectedOptions = [];
html.find('input[type="checkbox"]:checked').each(function() {
selectedOptions.push($(this).val());
});
const bonus = parseInt(html.find('select[name="bonus"]').val());
// Process selections
await processSelection(selectedOptions, bonus);
ui.notifications.info("Macro applied successfully!");
}
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel"
}
},
render: (html) => {
// Setup dynamic event handlers
html.find('input[type="checkbox"]').on('change', function() {
updatePreview(html);
});
}
}).render(true);
}
// Helper functions
async function processSelection(options, bonus) {
// Implementation
}
function updatePreview(html) {
// Update UI based on selections
}
// Execute
showDialog();
})();
```
### Macro Chaining
Call other macros from within a macro:
```javascript
(async () => {
// Get macro by name
const buffMacro = game.macros.getName("_applyBuff");
if (!buffMacro) {
ui.notifications.error("Required macro '_applyBuff' not found!");
return;
}
// Execute macro with arguments
await buffMacro.execute({
actorId: actor.id,
buffName: "Haste",
duration: 5,
active: true
});
// Continue with other logic
ui.notifications.info("Buff applied!");
})();
```
### Buff Management Pattern
```javascript
(async () => {
const actor = token.actor;
const buffName = "Haste";
// Find buff on actor
const buff = actor.items.find(i =>
i.type === "buff" &&
i.name === buffName
);
if (!buff) {
ui.notifications.warn(`Buff "${buffName}" not found on ${actor.name}!`);
return;
}
// Toggle buff
const newState = !buff.system.active;
await buff.update({
"system.active": newState,
"system.duration.value": newState ? 5 : 0
});
ui.notifications.info(
`${buffName} ${newState ? "activated" : "deactivated"} on ${actor.name}`
);
})();
```
### Hook Interception Pattern
For advanced macros that intercept game events:
```javascript
(async () => {
// Register a temporary hook
const hookId = Hooks.on("pf1.itemRoll", (item, options) => {
// Check if this is the right item
if (item.type !== "weapon") return;
// Check if actor has Haste buff
const hasHaste = item.actor.items.find(i =>
i.type === "buff" &&
i.name === "Haste" &&
i.system.active
);
if (!hasHaste) return;
// Modify roll options
options.extraAttacks = (options.extraAttacks || 0) + 1;
ui.notifications.info("Haste: Added extra attack!");
});
// Clean up hook after some time or condition
setTimeout(() => {
Hooks.off("pf1.itemRoll", hookId);
}, 60000); // Remove after 1 minute
})();
```
---
## Configuration
### Foundry VTT Configuration
#### System Manifest (system.json)
Located at: [system.json](src/foundryvtt-pathfinder1-v10.8/public/system.json)
```json
{
"id": "pf1",
"title": "Pathfinder 1e",
"description": "The Pathfinder First Edition game system for Foundry VTT",
"version": "10.8",
"compatibility": {
"minimum": "11",
"verified": "11",
"maximum": "11"
},
"esmodules": ["pf1.js"],
"styles": ["pf1.css"],
"packs": [
{
"name": "classes",
"label": "Classes",
"type": "Item",
"system": "pf1"
}
// ... more compendium packs
],
"languages": [
{
"lang": "en",
"name": "English",
"path": "lang/en.json"
}
// ... more languages
],
"socket": true,
"initiative": "1d20 + @attributes.init.total + (@attributes.init.total / 100)"
}
```
**Key Fields**:
- `id`: System identifier (must be unique)
- `esmodules`: JavaScript entry points (loaded as ES modules)
- `styles`: CSS stylesheets to load
- `packs`: Compendium packs (pre-packaged content)
- `languages`: Localization files
- `socket`: Enable socket communication for multiplayer
- `initiative`: Formula for initiative rolls
### PF1 System Configuration
#### Development Scripts
```bash
# Build for production
npm run build
# Development build with watch mode
npm run build:watch
# Extract compendium packs to JSON
npm run packs:extract
# Compile JSON to compendium packs
npm run packs:compile
# Lint code
npm run lint
# Format code
npm run format
# Generate documentation
npm run docs
```
#### ESLint Configuration (.eslintrc.js)
```javascript
module.exports = {
env: {
browser: true,
es2021: true,
jquery: true
},
extends: [
"eslint:recommended",
"plugin:prettier/recommended"
],
parserOptions: {
ecmaVersion: 2022,
sourceType: "module"
},
globals: {
game: "readonly",
ui: "readonly",
canvas: "readonly",
CONFIG: "readonly",
Hooks: "readonly",
foundry: "readonly",
Actor: "readonly",
Item: "readonly"
},
rules: {
"no-unused-vars": ["warn", {
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}]
}
};
```
#### Prettier Configuration (.prettierrc.json)
```json
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always"
}
```
### Claude Code Configuration
#### MCP Servers (.mcp.json)
The project uses 8 MCP servers for AI-assisted development:
```json
{
"mcpServers": {
"serena": {
"description": "Code navigation, symbol search, and project memory",
"capabilities": ["semantic search", "symbol manipulation", "memory"]
},
"sequential-thinking": {
"description": "Complex problem decomposition and reasoning"
},
"context7": {
"description": "Up-to-date library documentation retrieval"
},
"memory": {
"description": "Knowledge graph for persistent context"
},
"fetch": {
"description": "Web content retrieval and scraping"
},
"windows-mcp": {
"description": "Windows desktop automation and interaction"
},
"playwright": {
"description": "Browser automation and testing"
},
"database-server": {
"description": "SQL Server database access"
}
}
}
```
#### Claude Settings
- **Agents**: 8 specialized AI agents in [.claude/agents/](.claude/agents/)
- **Commands**: 9 custom slash commands in [.claude/commands/](.claude/commands/)
- **Output Styles**: 6 formatting styles in [.claude/output-styles/](.claude/output-styles/)
---
## Running the Application
### Prerequisites
- Foundry VTT installed (v11.315 recommended)
- Node.js v16-19 (for PF1 system development)
- npm (Node Package Manager)
- Visual Studio Code (recommended IDE)
### Initial Setup
```bash
# Navigate to project root
cd "C:\DEV\Foundry"
# Install PF1 system dependencies (if developing system)
cd src/foundryvtt-pathfinder1-v10.8
npm install
# Build PF1 system
npm run build
# Or use watch mode for development
npm run build:watch
```
### Running Foundry VTT
#### Option 1: Run Electron Application
```bash
# Navigate to Foundry directory
cd "C:\DEV\Foundry\src\FoundryVTT-11.315"
# Run Foundry (Windows)
.\foundryvtt.exe
# Or run via Node.js
node resources/app/main.js
```
#### Option 2: Launch from Start Menu/Desktop
- Double-click Foundry VTT shortcut
- Or launch from Windows Start Menu
### Accessing the Application
Once Foundry VTT is running:
1. **Setup Screen**: First launch shows setup page
2. **Select World**: Choose or create a world
3. **Launch World**: Click "Launch World"
4. **Login**: Enter game master password (if set)
### Creating/Using Macros
#### Import Macro from File
1. Open Foundry VTT
2. Click "Macro Directory" in sidebar
3. Click "Create Macro" button
4. Set macro type to "Script"
5. Copy content from [macro.js](src/macro.js) or [macro_haste.js](src/macro_haste.js)
6. Paste into macro editor
7. Save macro
8. Drag to hotbar for quick access
#### Testing Macros
1. Select a token on the canvas
2. Click macro from hotbar
3. Follow dialog prompts
4. Check console (F12) for errors/logs
### Development Workflow
```bash
# 1. Make changes to PF1 system or macros
# Edit files in src/foundryvtt-pathfinder1-v10.8/module/
# 2. Build system (if modified system code)
cd src/foundryvtt-pathfinder1-v10.8
npm run build:watch # Auto-rebuilds on changes
# 3. Reload Foundry
# Press F5 in Foundry VTT to reload
# 4. Test changes
# Execute macros or test system features
# 5. Check for issues
# Open browser console (F12) for errors
# 6. Format code before committing
npm run format
npm run lint
# 7. Commit changes
git add .
git commit -m "feat: add new macro feature"
```
---
## Testing Requirements
### Manual Testing
For macro development:
1. **Token Selection**: Ensure macro validates token selection
2. **Actor Data**: Verify correct actor data access
3. **Dialog UI**: Test all dialog buttons and inputs
4. **Error Handling**: Test with invalid inputs
5. **User Feedback**: Verify notifications display correctly
6. **Edge Cases**: Test with missing items, zero resources, etc.
### Console Debugging
```javascript
// Add debug logging to macros
(async () => {
console.log("=== Macro Start ===");
console.log("Token:", token);
console.log("Actor:", actor);
console.log("Actor Data:", actor.system);
try {
// Macro logic
} catch (error) {
console.error("Macro Error:", error);
ui.notifications.error(`Error: ${error.message}`);
}
console.log("=== Macro End ===");
})();
```
### PF1 System Testing
The PF1 system uses Quench for unit testing:
```bash
# Run tests (in Foundry VTT console)
quench.runAll();
# Or access test UI
# Game Settings > System Settings > Test Runner
```
### Browser Console Access
- Press **F12** to open browser developer tools
- Use **Console** tab for logs and errors
- Use **Network** tab for API call debugging
- Use **Elements** tab for DOM inspection
---
## Git & Version Control
### Commit Message Format
Follow the Conventional Commits specification:
```
<type>(<scope>): <subject>
<body>
<footer>
```
#### Types
- **feat**: New feature (macro, system enhancement)
- **fix**: Bug fix
- **docs**: Documentation changes
- **refactor**: Code refactoring
- **test**: Adding or updating tests
- **chore**: Maintenance tasks
- **style**: Code style changes (formatting)
#### Scopes
- **macro**: Macro development
- **system**: PF1 system changes
- **core**: Foundry core modifications
- **config**: Configuration changes
- **docs**: Documentation
#### Examples
```bash
# New macro
feat(macro): add arcane pool enhancement UI
# Bug fix
fix(macro): correct haste buff duration calculation
# Documentation
docs(readme): update macro installation instructions
# Refactoring
refactor(macro): extract dialog HTML to separate function
# System enhancement
feat(system): add support for mythic rules
```
### Branching Strategy
```bash
# Main branch for stable code
main
# Feature branches
feature/arcane-pool-macro
feature/haste-automation
# Bug fix branches
fix/dialog-validation
# Create feature branch
git checkout -b feature/new-macro
# Commit changes
git add src/macro_new.js
git commit -m "feat(macro): add new macro feature"
# Merge to main
git checkout main
git merge feature/new-macro
```
### Ignoring Files
The `.gitignore` should exclude:
```
# Foundry user data
src/FoundryVTT-11.315/Data/
# Node modules
node_modules/
# Build artifacts
dist/
*.log
# OS files
.DS_Store
Thumbs.db
# IDE files
.vscode/
.idea/
# Temporary files
*.tmp
*.bak
```
---
## Claude Code Specific Instructions
### Mandatory Tooling Usage Policy
**CRITICAL**: Claude Code must maximize the use of available advanced features for efficiency and quality:
#### 🎯 Agent Usage (REQUIRED)
- **ALWAYS** consider using specialized agents for their intended tasks:
- `Explore` agent: For codebase exploration, file pattern searches, keyword searches
- `test-engineer`: For generating test suites
- `code-reviewer`: For code quality reviews
- `refactoring-specialist`: For code cleanup
- `debugger`: For systematic bug diagnosis
- `architect`: For system design planning
- `documentation-writer`: For comprehensive documentation
- `security-analyst`: For security reviews
- **When NOT to use agents**:
- Single file reads with known path
- Simple edits to existing macros
- Tasks completable in 1-2 tool calls
**IF YOU DECIDE NOT TO USE AN AGENT**: State explicitly at the beginning:
```
🔧 Agent Decision: Not using agents because [reason: e.g., "single file edit", "straightforward macro modification"]
```
#### ⚡ Slash Command Usage (REQUIRED)
- **ALWAYS** check available slash commands before starting tasks
- Use custom commands when applicable:
- `/test [file]`: Generate tests
- `/review [file]`: Code review
- `/explain [file]`: Explain code
- `/analyze [path]`: Code analysis
- `/scaffold [type]`: Generate boilerplate
**IF YOU DECIDE NOT TO USE SLASH COMMANDS**: State explicitly:
```
🔧 Slash Command Decision: Not using slash commands because [reason]
```
#### 🔌 MCP Server Usage (REQUIRED)
- **ALWAYS** leverage MCP servers:
- `serena`: Semantic code search, symbol manipulation
- `context7`: Library documentation (Foundry VTT, PIXI.js)
- `fetch`: Web content retrieval
- `sequential-thinking`: Complex reasoning
- `memory`: Knowledge graph
- `playwright`: Browser automation
- `windows-mcp`: Desktop interaction
**IF YOU DECIDE NOT TO USE MCP SERVERS**: State explicitly:
```
🔧 MCP Server Decision: Not using MCP servers because [reason]
```
### When Working with This Project
Claude should:
-**ALWAYS** provide tooling decision statements at the start of each task
- ✅ Follow Foundry VTT API best practices
- ✅ Use async/await for all asynchronous operations
- ✅ Validate user input in macros (token selection, actor data)
- ✅ Use `ui.notifications` for user feedback
- ✅ Add console logging for debugging
- ✅ Use jQuery for DOM manipulation in dialogs
- ✅ Follow the IIFE pattern for macros
- ✅ Test macros with actual Foundry VTT instance
- ✅ Document complex Pathfinder 1e rules implementation
- ✅ Handle API errors gracefully
- ✅ Use parallel tool calls for efficiency
- ✅ Leverage specialized agents and MCP servers
### Important Project Context
**Critical Files to Understand**:
- [foundry.js](src/FoundryVTT-11.315/resources/app/public/scripts/foundry.js) - Bundled Foundry client (large, avoid reading directly)
- [config.mjs](src/foundryvtt-pathfinder1-v10.8/module/config.mjs) - PF1 system configuration
- [system.json](src/foundryvtt-pathfinder1-v10.8/public/system.json) - System manifest
- [macro.js](src/macro.js) - Arcane Pool macro example
- [macro_haste.js](src/macro_haste.js) - Haste automation example
- [zeratal.json](src/zeratal.json) - Test character data
**API Documentation**:
- **Official Foundry API**: https://foundryvtt.com/api/v11/
- **Documents Module**: https://foundryvtt.com/api/v11/modules/foundry.documents.html
**Common Tasks**:
1. **Creating a new macro**: Follow IIFE pattern, validate inputs, use Dialog API
2. **Debugging macros**: Add console.log statements, check browser console (F12)
3. **Modifying PF1 system**: Edit files in `module/`, run `npm run build:watch`
4. **Testing changes**: Reload Foundry (F5), execute macro, check console
**Project-Specific Patterns**:
- All macros use IIFE: `(async () => { /* code */ })();`
- Dialog HTML includes inline CSS for styling
- Buff management via `actor.items.find(i => i.type === "buff")`
- Resource access via `actor.system.resources.*`
- Macro chaining via `game.macros.getName("MacroName")`
- Notifications via `ui.notifications.[info|warn|error]()`
---
## Task Initiation Requirements
**MANDATORY**: At the START of EVERY task response, provide:
### 🎯 Tooling Strategy Decision
**Task Analysis**: [Brief description of the task]
**Tooling Decisions**:
- **Agents**: Using [agent-name] / Not using - Reason: [specific justification]
- **Slash Commands**: Using [/command] / Not using - Reason: [specific justification]
- **MCP Servers**: Using [server: tool] / Not using - Reason: [specific justification]
- **Approach**: [Overall strategy for completing the task]
---
## Task Completion Status Messages
**IMPORTANT**: At the end of EVERY response where you performed work, provide:
### 📊 Task Completion Summary
**What Was Done**: [Brief description of tasks completed]
**Features Involved**:
- Agents: [Agent1, Agent2, or None - with usage justification]
- Slash Commands: [/command1, /command2, or None - with usage justification]
- MCP Servers: [Server1: tool1/tool2, Server2: tool3, or None - with usage justification]
- Core Tools: [Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch, Task]
- Files Modified: [file1.js, file2.mjs, or None]
- Performance: [Parallel ops, extended thinking, or N/A]
**Efficiency Notes**: [Any observations about tooling choices and their impact]
---
## Additional Resources
### Documentation
- **Foundry VTT Knowledge Base**: https://foundryvtt.com/kb/
- **Foundry VTT API v11**: https://foundryvtt.com/api/v11/
- **Foundry Documents**: https://foundryvtt.com/api/v11/modules/foundry.documents.html
- **PF1 System GitHub**: https://github.com/Furyspark/foundryvtt-pathfinder1
- **PIXI.js Documentation**: https://pixijs.com/
### Community
- **Foundry VTT Discord**: https://discord.gg/foundryvtt
- **Foundry VTT Reddit**: https://reddit.com/r/FoundryVTT
- **PF1 System Issues**: https://github.com/Furyspark/foundryvtt-pathfinder1/issues
### Troubleshooting
- **Browser Console**: Press F12 to access developer tools
- **Foundry Logs**: Check logs in `Data/Logs/` directory
- **Module Conflicts**: Disable modules to isolate issues
- **Cache Issues**: Clear browser cache or Foundry cache
---
## Contact & Support
**Maintainers**:
- Development Team
**Getting Help**:
1. Check browser console (F12) for errors
2. Review Foundry VTT API documentation
3. Consult PF1 system GitHub issues
4. Ask in Foundry VTT Discord community
---
**Last Updated**: 2025-01-29
**Project Version**: 1.0.0
**Foundry VTT Version**: v11.315
**PF1 System Version**: v10.8