11 KiB
Modular NPC Builder - Architecture Documentation
Overview
The Cobblemon NPC Creator has been refactored from a traditional tab-based form interface to a modern, modular node-based system inspired by tools like n8n, ComfyUI, and Unreal Engine's Blueprint system. This new approach provides a more intuitive, visual way to create and customize NPCs through connectable modules.
Why This Refactor?
Problems with the Old System
- Complex, multi-tab forms were overwhelming for users
- Hard to see the complete NPC configuration at a glance
- Difficult to understand relationships between different components
- Linear workflow didn't match the non-linear nature of NPC creation
Benefits of the New System
- Visual representation of NPC structure
- Drag-and-drop modular components
- Clear data flow through connections
- Easier to add/remove features on demand
- More scalable and extensible architecture
- Better separation of concerns
Technology Stack
Core Library: React Flow (@xyflow/react)
Why React Flow?
- Production-ready, battle-tested in many applications
- Excellent TypeScript support
- Highly customizable node and edge rendering
- Built-in features: minimap, controls, background grid
- Great performance with many nodes
- Active development and community
- MIT licensed
Other Options Considered:
- jsPlumb: Older library, less React-friendly
- Vue Flow: Excellent but Vue-specific
- React Diagrams: Less maintained, fewer features
- Rete.js: Good but more complex API
React Flow was chosen for its perfect balance of features, performance, and ease of use.
Architecture
File Structure
src/
├── components/
│ ├── NodeCanvas.tsx # Main workspace component
│ └── nodes/ # Individual node modules
│ ├── BasicInfoNode.tsx # Basic NPC settings module
│ ├── BattleConfigNode.tsx # Battle configuration module
│ ├── PartyNode.tsx # Pokemon party builder module
│ ├── InteractionNode.tsx # Interaction system module
│ ├── VariablesNode.tsx # MoLang variables module
│ └── OutputNode.tsx # JSON preview and export module
├── types/
│ ├── npc.ts # Original NPC type definitions
│ └── nodes.ts # New node-based type definitions
└── App.tsx # Updated main app with modular view
Module Types
1. BasicInfoNode (Blue)
Purpose: Configure core NPC properties Inputs: None (root node) Outputs: Basic info data Fields:
- Resource Identifier
- Names (comma-separated)
- Model Scale
- Aspects
- Behavior flags (invulnerable, persistent, movable, etc.)
2. BattleConfigNode (Red)
Purpose: Set up battle-related configurations Inputs: Connection from any module Outputs: Battle config data Fields:
- Can Battle / Can Challenge toggles
- Battle Theme
- Victory Theme
- Defeat Theme
- Simultaneous Battles option
- Heal After Battle option
3. PartyNode (Green)
Purpose: Configure Pokemon party Inputs: Connection from any module Outputs: Party data Fields:
- Party Type selector (Simple/Pool/Script)
- Pokemon list with add/remove
- Static Party toggle Features:
- Add/remove Pokemon
- Inline Pokemon string editing
- Support for different party provider types
4. InteractionNode (Purple)
Purpose: Define NPC interaction behavior Inputs: Connection from any module Outputs: Interaction data Fields:
- Interaction Type (None/Dialogue/Script/Shop/Heal)
- Dialogue Reference (for dialogue type)
- Script Reference (for script type)
5. VariablesNode (Yellow)
Purpose: Manage MoLang configuration variables Inputs: Connection from any module Outputs: Variables data Fields:
- Variable list with add/remove
- Per-variable configuration:
- Variable Name
- Display Name
- Type (Number/Text/Boolean)
- Default Value
6. OutputNode (Indigo)
Purpose: Preview and export final NPC JSON Inputs: Collects data from all modules Outputs: None (terminal node) Features:
- NPC summary view
- Live JSON preview
- Download JSON button
- Character count display
Data Flow
BasicInfoNode ─┐
├─► OutputNode (JSON Preview)
BattleNode ────┤
├─► [Collects all module data]
PartyNode ─────┤
├─► [Generates final NPC config]
InteractionNode┤
│
VariablesNode ─┘
Key Components
NodeCanvas.tsx
The main workspace component that:
- Manages the React Flow instance
- Handles node and edge state
- Provides "Add Module" functionality
- Aggregates node data into final NPC configuration
- Updates OutputNode preview in real-time
- Renders control panels and minimap
Key Features:
- Drag-and-drop node positioning
- Visual connections between modules
- Module palette for adding new nodes
- Real-time configuration updates
- Responsive design
Individual Node Components
Each node module follows a consistent pattern:
- Collapsible header with icon and color coding
- Input/output handles for connections
- Expandable/collapsible content area
- Form fields for configuration
- Real-time data updates
Design Principles:
- Self-contained logic
- Minimal external dependencies
- Consistent UI patterns
- Color-coded by category
- Icon-based identification
Usage Patterns
Basic Workflow
-
Start with BasicInfoNode (automatically created)
- Set NPC name and identifier
- Configure basic properties
-
Add Required Modules via "Add Module" button
- Click desired module from palette
- Module appears on canvas
-
Configure Each Module
- Click to expand/collapse
- Fill in relevant fields
- Data updates automatically
-
Connect Modules (optional, visual only)
- Drag from output handle to input handle
- Creates visual relationship
-
Preview Output in OutputNode
- View NPC summary
- Check JSON preview
- Download when ready
Adding New Module Types
To add a new module type:
- Define types in
src/types/nodes.ts:
export interface NewModuleNodeData {
type: 'newModule';
field1: string;
field2: number;
}
- Create component in
src/components/nodes/NewModuleNode.tsx:
export const NewModuleNode = memo(({ data }: NodeProps<NewModuleNodeData>) => {
// Implementation
});
- Register in NodeCanvas.tsx:
const nodeTypes: NodeTypes = {
// ... existing types
newModule: NewModuleNode,
};
- Add to palette in NodeCanvas.tsx:
{
type: 'newModule',
label: 'New Module',
description: 'Description here',
color: 'bg-color-500',
icon: '🎨',
}
State Management
Current Approach
- React Flow manages node positions and connections
- Each node stores its own data in
node.data - NodeCanvas aggregates node data into final NPC config
- Parent App.tsx maintains final state
Data Updates
- Node changes trigger immediate updates
- NodeCanvas effect listens for node changes
- Aggregates all node data into NPCConfiguration
- Updates OutputNode preview automatically
- Parent receives final config via callback
Extensibility
Future Enhancements
-
Dialogue Editor Module
- Visual dialogue tree within a node
- Inline page editing
- Speaker management
-
Advanced Party Builder
- Pokemon selector modal
- Visual Pokemon cards
- Type-based team generation
-
Quest Module
- Quest objectives
- Reward configuration
- Quest chain visualization
-
AI Behavior Module
- Pathfinding settings
- Custom behaviors
- Schedule configuration
-
Import/Export Module
- Load from datapack
- Save workflow templates
- Share configurations
API Integration Opportunities
- Pokemon data from PokeAPI
- Cobblemon mod documentation links
- Community preset sharing
- Validation against mod version
Performance Considerations
- React Flow handles virtualization automatically
- Memoized components prevent unnecessary re-renders
- Debounced updates for text inputs (can be added)
- Lazy loading for heavy modules (can be added)
Styling
Design System
- Tailwind CSS for utility-first styling
- Color-coded modules for easy identification:
- Blue: Core settings
- Red: Battle/Combat
- Green: Pokemon/Party
- Purple: Interactions
- Yellow: Configuration/Variables
- Indigo: Output/Export
Responsive Design
- Nodes have minimum widths
- Collapsible sections for small screens
- Touch-friendly controls
- Mobile-optimized panels
Testing Strategy
Manual Testing Checklist
- Can add all module types
- Can delete nodes
- Can connect nodes (visual)
- Can collapse/expand nodes
- Data persists when nodes are moved
- OutputNode shows correct preview
- Can download valid JSON
- All form fields work correctly
- Checkbox states persist
- Number inputs validate properly
Automated Testing (Future)
- Unit tests for node components
- Integration tests for data flow
- E2E tests for complete workflows
- Visual regression tests for UI
Migration Guide
For Users
- Old tab-based view is still accessible (Classic mode)
- Existing save files remain compatible
- New modular view is opt-in
- Can switch between modes
For Developers
- Old components still exist in codebase
- New modular system is additive
- Can maintain both systems
- Gradual migration path
Known Limitations
- Connection Logic: Connections are currently visual only and don't enforce data flow
- Undo/Redo: Not yet implemented
- Copy/Paste Nodes: Not yet implemented
- Node Templates: Can't save/load node configurations
- Mobile Experience: Best on desktop/tablet
Troubleshooting
Common Issues
Nodes not appearing:
- Check if nodeTypes are registered in NodeCanvas
- Verify component import paths
- Check for TypeScript errors
Data not updating:
- Ensure node data is being mutated correctly
- Check useEffect dependencies in NodeCanvas
- Verify onChange callbacks are called
Styling issues:
- Ensure @xyflow/react styles are imported
- Check Tailwind CSS configuration
- Verify color classes exist
Contributing
When adding new features:
- Follow existing node component patterns
- Use TypeScript for type safety
- Add appropriate color coding
- Include descriptions in module palette
- Test with various configurations
- Update this documentation
Resources
- React Flow Documentation
- Cobblemon Mod Documentation
- Tailwind CSS Documentation
- TypeScript Documentation
Conclusion
The modular node-based architecture provides a more intuitive and scalable approach to NPC creation. By leveraging React Flow's powerful features and maintaining clean separation of concerns, the system is both user-friendly and developer-friendly. The visual nature of the interface makes complex configurations more approachable while maintaining the full power of the underlying Cobblemon NPC system.