419 lines
No EOL
11 KiB
Markdown
419 lines
No EOL
11 KiB
Markdown
# BMS BattleMap Generator - Technical Architecture
|
|
|
|
## System Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Frontend Application │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Editor Interface Preview Canvas Tools Panel │
|
|
│ (Monaco Editor) (Konva.js Canvas) (Export/Options) │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ State Management │
|
|
│ (React Hooks/Context) │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ YAML Parser │ Schema Validator │ Renderer Engine │
|
|
│ (js-yaml) │ (Zod) │ (Konva.js Layers) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Component Architecture
|
|
|
|
### 1. BMS Schema Module (`src/schema/`)
|
|
```
|
|
schema/
|
|
├── types.ts # TypeScript interfaces
|
|
├── validators.ts # Zod validation schemas
|
|
├── parsers.ts # Coordinate/range parsing
|
|
├── transformers.ts # Data transformation
|
|
└── index.ts # Public API
|
|
```
|
|
|
|
### 2. Parser Module (`src/parser/`)
|
|
```
|
|
parser/
|
|
├── yaml-parser.ts # BMS YAML parsing
|
|
├── coordinate-parser.ts # Grid coordinate parsing
|
|
├── validation.ts # Schema validation logic
|
|
├── errors.ts # Error types and messages
|
|
└── index.ts
|
|
```
|
|
|
|
### 3. Renderer Module (`src/renderer/`)
|
|
```
|
|
renderer/
|
|
├── base-renderer.ts # Abstract base class
|
|
├── paperly-renderer.ts # Paperly style implementation
|
|
├── texture-renderer.ts # Future: texture pack rendering
|
|
├── layers/ # Individual layer renderers
|
|
│ ├── grid-layer.ts
|
|
│ ├── room-layer.ts
|
|
│ ├── door-layer.ts
|
|
│ ├── object-layer.ts
|
|
│ ├── hazard-layer.ts
|
|
│ ├── lighting-layer.ts
|
|
│ └── annotation-layer.ts
|
|
├── styles/ # Style definitions
|
|
│ ├── paperly-style.ts
|
|
│ └── texture-styles.ts # Future
|
|
└── utils/ # Rendering utilities
|
|
├── geometry.ts
|
|
├── colors.ts
|
|
└── textures.ts
|
|
```
|
|
|
|
### 4. UI Components (`src/components/`)
|
|
```
|
|
components/
|
|
├── Editor/
|
|
│ ├── YAMLEditor.tsx # Monaco editor wrapper
|
|
│ └── EditorPanel.tsx # Editor with error display
|
|
├── Preview/
|
|
│ ├── MapCanvas.tsx # Konva canvas wrapper
|
|
│ └── PreviewPanel.tsx # Preview with controls
|
|
├── Tools/
|
|
│ ├── ExportMenu.tsx # Export options
|
|
│ ├── StylePicker.tsx # Style selection
|
|
│ └── ValidationPanel.tsx # Validation status
|
|
├── Layout/
|
|
│ ├── Header.tsx
|
|
│ ├── Sidebar.tsx
|
|
│ └── StatusBar.tsx
|
|
└── Common/
|
|
├── ErrorDisplay.tsx
|
|
├── LoadingSpinner.tsx
|
|
└── Tooltip.tsx
|
|
```
|
|
|
|
### 5. State Management (`src/hooks/`, `src/context/`)
|
|
```
|
|
hooks/
|
|
├── useBMS.ts # BMS schema state
|
|
├── useRenderer.ts # Renderer instance
|
|
├── useExport.ts # Export functionality
|
|
└── useUndoRedo.ts # Undo/redo history
|
|
|
|
context/
|
|
├── AppContext.tsx # Global app state
|
|
└── ThemeContext.tsx # Theme/stylesheet
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
### 1. Parsing Pipeline
|
|
```
|
|
User Input (YAML)
|
|
↓
|
|
YAML Parser (js-yaml)
|
|
↓
|
|
Schema Validator (Zod)
|
|
↓
|
|
BMSSchema Object
|
|
↓
|
|
Renderer Engine
|
|
↓
|
|
Canvas Output
|
|
```
|
|
|
|
### 2. Rendering Pipeline
|
|
```
|
|
BMSSchema
|
|
↓
|
|
Setup Canvas (grid size, scale)
|
|
↓
|
|
Render Layers (in order):
|
|
1. Grid Layer
|
|
2. Room Layer (walls, floors)
|
|
3. Door Layer
|
|
4. Object Layer
|
|
5. Hazard Layer
|
|
6. Lighting Layer
|
|
7. Annotation Layer
|
|
↓
|
|
Canvas Output
|
|
```
|
|
|
|
### 3. Export Pipeline
|
|
```
|
|
Canvas State
|
|
↓
|
|
Export Format Selection
|
|
↓
|
|
Format-Specific Exporter:
|
|
- PNG: canvas.toDataURL()
|
|
- JSON: JSON.stringify(BMSSchema)
|
|
- BMS: serializeBMSToYAML()
|
|
↓
|
|
File Download
|
|
```
|
|
|
|
## Key Technical Decisions
|
|
|
|
### 1. Canvas Library: Konva.js
|
|
**Why Konva.js over alternatives:**
|
|
- **React Integration**: react-konva provides React component wrappers
|
|
- **Performance**: Hardware acceleration, efficient rendering
|
|
- **Features**: Layers, events, transforms, filters
|
|
- **Size**: Smaller than PIXI.js, more focused than raw Canvas API
|
|
- **Maintenance**: Active development, good documentation
|
|
|
|
### 2. Validation: Zod
|
|
**Why Zod over alternatives:**
|
|
- **TypeScript Integration**: Automatic type inference
|
|
- **Runtime Safety**: Comprehensive validation at runtime
|
|
- **Error Messages**: Customizable error messages
|
|
- **Size**: Small bundle size
|
|
- **Schema Composition**: Easy to compose and extend schemas
|
|
|
|
### 3. YAML Parsing: js-yaml
|
|
**Why js-yaml:**
|
|
- **Browser Support**: Works in browser environments
|
|
- **Safety**: Secure parsing options
|
|
- **Performance**: Fast and efficient
|
|
- **Features**: Full YAML 1.2 support
|
|
|
|
### 4. State Management: React Hooks
|
|
**Why React Hooks over Redux/MobX:**
|
|
- **Simplicity**: Less boilerplate for MVP
|
|
- **Performance**: Optimized re-renders with useMemo/useCallback
|
|
- **Scalability**: Can migrate to Context or Zustand if needed
|
|
- **Learning Curve**: Familiar to React developers
|
|
|
|
## Performance Considerations
|
|
|
|
### 1. Rendering Optimization
|
|
```typescript
|
|
// Use Konva.js optimizations
|
|
const optimizedRender = () => {
|
|
// Batch updates
|
|
stage.batchDraw();
|
|
|
|
// Use caching for static elements
|
|
shape.cache();
|
|
|
|
// Implement viewport culling
|
|
if (isInViewport(element)) {
|
|
renderElement(element);
|
|
}
|
|
};
|
|
```
|
|
|
|
### 2. Memory Management
|
|
```typescript
|
|
// Clean up resources
|
|
useEffect(() => {
|
|
const renderer = new PaperlyRenderer();
|
|
return () => {
|
|
renderer.destroy(); // Clean up Konva objects
|
|
};
|
|
}, []);
|
|
```
|
|
|
|
### 3. Large Map Handling
|
|
```typescript
|
|
// Implement level of detail
|
|
const getDetailLevel = (zoom: number): DetailLevel => {
|
|
if (zoom < 0.5) return 'low';
|
|
if (zoom < 1.0) return 'medium';
|
|
return 'high';
|
|
};
|
|
|
|
// Progressive rendering
|
|
const renderProgressive = async (schema: BMSSchema) => {
|
|
// Render grid first
|
|
renderGrid();
|
|
|
|
// Render rooms
|
|
await renderRooms(schema.rooms);
|
|
|
|
// Render details progressively
|
|
requestIdleCallback(() => {
|
|
renderDoors(schema.doors);
|
|
renderObjects(schema.objects);
|
|
});
|
|
};
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### 1. YAML Parsing Security
|
|
```typescript
|
|
import { load } from 'js-yaml';
|
|
|
|
// Safe YAML parsing
|
|
const parseBMSYAML = (yaml: string): BMSSchema => {
|
|
try {
|
|
// Use safeLoad to prevent code execution
|
|
const parsed = load(yaml, {
|
|
schema: yaml.DEFAULT_SAFE_SCHEMA,
|
|
onWarning: (warning) => console.warn(warning)
|
|
});
|
|
|
|
// Validate structure
|
|
return bmsSchema.parse(parsed);
|
|
} catch (error) {
|
|
throw new BMSValidationError('Invalid BMS YAML', error);
|
|
}
|
|
};
|
|
```
|
|
|
|
### 2. File Export Security
|
|
```typescript
|
|
// Safe file naming
|
|
const sanitizeFilename = (name: string): string => {
|
|
return name.replace(/[^a-z0-9-_.]/gi, '_');
|
|
};
|
|
|
|
// Content security for downloads
|
|
const downloadFile = (content: string, filename: string) => {
|
|
const blob = new Blob([content], { type: 'application/octet-stream' });
|
|
const url = URL.createObjectURL(blob);
|
|
// Use safe download pattern
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = sanitizeFilename(filename);
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
```
|
|
|
|
## Testing Strategy
|
|
|
|
### 1. Unit Tests
|
|
```typescript
|
|
// Test coordinate parsing
|
|
describe('parseCoordinate', () => {
|
|
it('should parse valid coordinates', () => {
|
|
expect(parseCoordinate('(5,10)')).toEqual([5, 10]);
|
|
});
|
|
|
|
it('should throw error for invalid format', () => {
|
|
expect(() => parseCoordinate('5,10')).toThrow();
|
|
});
|
|
});
|
|
```
|
|
|
|
### 2. Integration Tests
|
|
```typescript
|
|
// Test full parsing pipeline
|
|
describe('BMS Parser Integration', () => {
|
|
it('should parse and validate complete BMS', () => {
|
|
const yaml = sampleBMSYAML;
|
|
const schema = parseBMSYAML(yaml);
|
|
expect(schema.mapName).toBe('Guard Room');
|
|
expect(schema.rooms).toHaveLength(1);
|
|
});
|
|
});
|
|
```
|
|
|
|
### 3. Visual Regression Tests
|
|
```typescript
|
|
// Compare rendered output
|
|
describe('Renderer Visual Tests', () => {
|
|
it('should render rooms correctly', async () => {
|
|
const schema = createTestSchema();
|
|
const renderer = new PaperlyRenderer();
|
|
const image = await renderer.renderToImage(schema);
|
|
|
|
// Compare with baseline
|
|
expect(image).toMatchImageSnapshot();
|
|
});
|
|
});
|
|
```
|
|
|
|
## Deployment Architecture
|
|
|
|
### 1. Development Environment
|
|
```
|
|
Local Machine → Vite Dev Server → Browser
|
|
```
|
|
|
|
### 2. Alpha Deployment
|
|
```
|
|
Git Repository → Build (Vite) → Static Files → maps.bouncypixel.com
|
|
```
|
|
|
|
### 3. Future Production Deployment
|
|
```
|
|
GitHub Actions → Build & Test → CDN (Vercel/Netlify) → Custom Domain
|
|
↘ Texture Packs → Cloud Storage (S3/Cloudflare)
|
|
```
|
|
|
|
## Scalability Considerations
|
|
|
|
### 1. Frontend Scaling
|
|
- **Code Splitting**: Lazy load components
|
|
- **Bundle Optimization**: Tree shaking, compression
|
|
- **CDN**: Static assets via CDN
|
|
|
|
### 2. Rendering Scaling
|
|
- **Virtualization**: Only render visible area
|
|
- **Web Workers**: Offload heavy computation
|
|
- **Caching**: Cache rendered elements
|
|
|
|
### 3. Data Scaling
|
|
- **IndexedDB**: Local storage for large maps
|
|
- **Compression**: Compress BMS data
|
|
- **Streaming**: Progressive loading
|
|
|
|
## Monitoring & Analytics
|
|
|
|
### 1. Performance Monitoring
|
|
```typescript
|
|
// Track rendering performance
|
|
const measureRender = (schema: BMSSchema) => {
|
|
performance.mark('render-start');
|
|
renderer.render(schema);
|
|
performance.mark('render-end');
|
|
|
|
const measure = performance.measure('render', 'render-start', 'render-end');
|
|
console.log(`Render time: ${measure.duration}ms`);
|
|
};
|
|
```
|
|
|
|
### 2. Error Tracking
|
|
```typescript
|
|
// Centralized error handling
|
|
class ErrorTracker {
|
|
static track(error: Error, context?: any) {
|
|
console.error('BMS Error:', error, context);
|
|
// Send to error tracking service (future)
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Usage Analytics (Optional)
|
|
```typescript
|
|
// Basic usage tracking
|
|
const trackEvent = (event: string, data?: any) => {
|
|
if (process.env.NODE_ENV === 'production') {
|
|
// Send to analytics service
|
|
}
|
|
};
|
|
```
|
|
|
|
## Future Technical Considerations
|
|
|
|
### 1. Plugin System
|
|
```typescript
|
|
interface BMSPlugin {
|
|
name: string;
|
|
version: string;
|
|
init: (app: BMSApp) => void;
|
|
render?: (context: RenderContext) => void;
|
|
export?: (schema: BMSSchema) => any;
|
|
}
|
|
```
|
|
|
|
### 2. Collaborative Features
|
|
- **WebSocket**: Real-time collaboration
|
|
- **Conflict Resolution**: Operational transforms
|
|
- **Presence**: User cursor/selection
|
|
|
|
### 3. Offline Support
|
|
- **Service Workers**: Offline functionality
|
|
- **Local Storage**: Save work locally
|
|
- **Sync**: Background synchronization
|
|
|
|
---
|
|
*Last Updated: March 19, 2026* |