dnd-hub/docs/TECHNICAL_ARCHITECTURE.md
2026-03-19 01:09:12 -04:00

11 KiB

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

// 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

// Clean up resources
useEffect(() => {
  const renderer = new PaperlyRenderer();
  return () => {
    renderer.destroy(); // Clean up Konva objects
  };
}, []);

3. Large Map Handling

// 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

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

// 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

// 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

// 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

// 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

// 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

// 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)

// 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

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