bms-forge/docs/BMS_SCHEMA_SPEC.md
2026-03-19 01:09:12 -04:00

463 lines
No EOL
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Battlemap Notation Schema (BMS) - Technical Specification
## Schema Version: 1.0
## Complete Field Reference
### 1. Header Section (Required)
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `BMS Version` | String | Schema version | `"1.0"` |
| `Map Name` | String | Map title | `"Goblin Warrens"` |
| `Grid Size` | String | Width×Height in squares | `"40x30"` |
| `Grid Unit` | String | Feet per square | `"5ft"` |
| `Style` | String | Visual theme | `"Stone Cavern"` |
| `Lighting` | String | Ambient light | `"Dim (torchlight)"` |
| `Ambient Sound` | String | Background audio | `"Dripping water"` |
| `Temperature` | String | Environmental temp | `"55°F, damp"` |
### 2. Coordinate System
```
(0,0)───────→ x (width)
y (height)
Example: (5,10) = column 6, row 11 (5ft squares)
Range: (x1,y1)-(x2,y2) defines rectangle
```
### 3. Room Definition
```yaml
ROOMS:
- R1: [Room Name] (x1,y1)-(x2,y2)
Walls: [Material-Thickness-Style]
Floor: [Material-Texture]
Ceiling: [Height-Features]
Lighting: [Light sources within]
Features: [Special characteristics]
```
**Wall Types:**
- `Stone-1ft-Rough`
- `Wood-6in-Carved`
- `Iron-2ft-Reinforced`
- `Masonry-1ft-Smooth`
- `Natural-Rockface`
**Floor Types:**
- `Rough stone, debris`
- `Packed earth`
- `Wooden planks`
- `Flagstones`
- `Mosaic tile`
### 4. Door Definition
```yaml
DOORS:
- D1: [Door Name]
Type: [Material-Single/Double-Style]
Position: (x1,y1)-(x2,y2)
Connects: [Room1] <-> [Room2]
State: [Open/Closed]-[Locked/Unlocked]
Hinges: [Side]
DC: [Difficulty if locked/trapped]
```
**Door Types:**
- `Wood-Single-Banded`
- `Iron-Double-Portcullis`
- `Stone-Sliding-Secret`
- `Wood-Double-Ornate`
**States:**
- `Open-Unlocked`
- `Closed-Locked` (DC15)
- `Closed-Barred`
- `Destroyed`
### 5. Object Definition
```yaml
OBJECTS:
- O1: [Object Name]
Type: [Material-Type-Style]
Position: (x1,y1)-(x2,y2)
Elevation: [+/- ft from floor]
State: [Condition]
Contents: [What's inside]
Lock: [Lock details if applicable]
Trapped: [Trap details if applicable]
```
**Object Types:**
- `Wood-Table-Rough`
- `Stone-Throne-Ornate`
- `Iron-Chest-Large`
- `Wood-Barrel-Sturdy`
- `Stone-Altar-Carved`
### 6. Hazard Definition
```yaml
HAZARDS:
- H1: [Hazard Name]
Type: [Mechanical/Magical/Environmental]-[Effect]
Position: (x1,y1)-(x2,y2)
Trigger: [Activation mechanism]
DC: [Perception/Disable DCs]
Save: [Saving throw type & DC]
Damage: [Damage dice]
Effect: [Additional effects]
Reset: [Manual/Automatic]
```
**Hazard Types:**
- `Mechanical-Pit-20ft`
- `Magical-Glyph-Fire`
- `Environmental-Gas-Poison`
- `Mechanical-Dart-Pressure`
- `Magical-Fear-Aura`
### 7. Lighting Definition
```yaml
LIGHTING:
- L1: [Light Name]
Type: [Source-Type]
Position: (x,y)
Radius: [Bright ft, Dim ft]
Color: [Light color]
Fuel: [Duration/Fuel source]
Special: [Flickering/Steady etc]
```
**Light Types:**
- `Torch-Wall`
- `Lantern-Hanging`
- `Candle-Table`
- `Magical-Everburning`
- `Fungi-Bioluminescent`
### 8. Connection Graph
```yaml
CONNECTIONS:
[Room1] -- [Door/Passage] --> [Room2]
[Room2] -- [Tunnel] --> [Room3]
[Room3] -- [Secret] --> [Room4]
```
**Connection Types:**
- `-- [Door] -->` (Standard door)
- `-- [Secret] -->` (Hidden passage)
- `-- [Tunnel] -->` (Long corridor)
- `-- [Stairs] -->` (Vertical connection)
### 9. Annotation Definition
```yaml
ANNOTATIONS:
- "[Text]" at (x,y)
- "[Label]" pointing to (x1,y1)-(x2,y2)
- "DM: [Note]" at (x,y)
```
## Advanced Features
### Multi-level Maps
```yaml
ELEVATION:
- Base Level: 0ft
- Upper Balcony: +15ft
- Lower Pit: -20ft
STAIRS:
- S1: Spiral Stairs
Position: (25,15)-(27,17)
Connects: Level1 -> Level2 (+10ft)
Steps: 20
```
### Secret/Concealed Features
```yaml
SECRETS:
- S1: Hidden Door
Position: (14,12)-(14,14)
Type: Stone-Sliding
DC: 20 Perception
Mechanism: Lever at (12,18)
Revealed: When mechanism activated
```
### Environmental Zones
```yaml
ZONES:
- Z1: Fog Bank
Position: (10,10)-(20,20)
Effect: Heavily obscured
Save: None
Movement: Normal
- Z2: Slippery Ice
Position: (30,30)-(40,40)
Effect: Difficult terrain
Save: DC 10 Acrobatics or fall prone
```
## Visualization Standards
### Color Coding (Suggested)
- **Walls:** Dark gray (#333333)
- **Doors:** Brown (#8B4513)
- **Hazards:** Red (#FF0000) with pattern
- **Objects:** Medium gray (#666666)
- **Light sources:** Yellow glow (#FFFF00)
- **Water:** Blue (#0000FF)
- **Difficult terrain:** Green diagonal lines
- **Elevation changes:** Contour lines
### Icon Standards
- **Door:** Rectangle with arc
- **Chest:** Rectangle with curved lid
- **Table:** Rectangle
- **Chair/T hrone:** Square with back
- **Torch:** Small circle with flame above
- **Pit:** Diagonal hatch pattern
- **Secret:** Dotted outline
## Example: Simple Guard Room
```yaml
BMS Version: 1.0
Map Name: Guard Room
Grid Size: 20x15
Grid Unit: 5ft
Style: Stone Fortress
Lighting: Torchlight
ROOMS:
- R1: Guard Room (0,0)-(20,15)
Walls: Stone-1ft-Smooth
Floor: Flagstones
Ceiling: 15ft, wooden beams
Lighting: Wall torches at (3,0), (17,0)
DOORS:
- D1: Wooden Door (20,6)-(20,9)
Type: Wood-Single-Reinforced
Connects: R1 -> Corridor
State: Closed-Unlocked
Hinges: East side
OBJECTS:
- O1: Guard Table (5,5)-(9,9)
Type: Wood-Table-Sturdy
Contents: Maps, mugs, dice
- O2: Weapon Rack (15,5)-(17,10)
Type: Wood-Rack-Wall
Contents: 4 spears, 2 swords
LIGHTING:
- L1: Wall Torch (3,0)
Radius: 20ft bright, 40ft dim
Color: Orange flickering
- L2: Wall Torch (17,0)
Radius: 20ft bright, 40ft dim
Color: Orange flickering
ANNOTATIONS:
- "Guard post" at (10,7)
- "Weapons" pointing to O2
```
## TypeScript Interface Definition
```typescript
// Core BMS Types
type Coordinate = [number, number]; // (x, y)
type Rectangle = { from: Coordinate; to: Coordinate };
interface BMSHeader {
bmsVersion: string;
mapName: string;
gridSize: { width: number; height: number };
gridUnit: string;
style: string;
lighting: string;
ambientSound?: string;
temperature?: string;
}
interface Room {
id: string; // "R1"
name: string;
position: Rectangle;
walls: string; // "Stone-1ft-Rough"
floor: string; // "Rough stone, debris"
ceiling: string; // "15ft, wooden beams"
lighting?: string;
features?: string;
}
interface Door {
id: string; // "D1"
name: string;
type: string; // "Wood-Single-Banded"
position: Rectangle;
connects: { room1: string; room2: string };
state: { open: boolean; locked: boolean; dc?: number };
hinges?: string; // "East side"
}
interface MapObject {
id: string; // "O1"
name: string;
type: string; // "Wood-Table-Rough"
position: Rectangle;
elevation?: string; // "+2ft"
state?: string;
contents?: string;
lock?: string;
trapped?: string;
}
interface Hazard {
id: string; // "H1"
name: string;
type: string; // "Mechanical-Pit-20ft"
position: Rectangle;
trigger?: string;
dc?: { perception?: number; disable?: number };
save?: { type: string; dc: number };
damage?: string;
effect?: string;
reset?: string;
}
interface LightSource {
id: string; // "L1"
name: string;
type: string; // "Torch-Wall"
position: Coordinate;
radius: { bright: number; dim: number };
color?: string;
fuel?: string;
special?: string;
}
interface Connection {
from: string; // Room ID
to: string; // Room ID
type: string; // "Door", "Secret", "Tunnel", "Stairs"
via?: string; // Door ID if applicable
}
interface Annotation {
text: string;
position: Coordinate;
type?: "label" | "note" | "pointer";
target?: Rectangle; // For pointer annotations
}
interface BMSSchema extends BMSHeader {
rooms?: Room[];
doors?: Door[];
objects?: MapObject[];
hazards?: Hazard[];
lightingSources?: LightSource[];
connections?: Connection[];
annotations?: Annotation[];
// Advanced features (future)
elevation?: Elevation[];
stairs?: Stairs[];
secrets?: Secret[];
zones?: Zone[];
}
```
## Parser Functions
### Grid Size Parser
```typescript
function parseGridSize(str: string): { width: number; height: number } {
// "40x30" → { width: 40, height: 30 }
const match = str.match(/^(\d+)x(\d+)$/);
if (!match) throw new Error(`Invalid grid size: ${str}`);
return { width: parseInt(match[1]), height: parseInt(match[2]) };
}
```
### Coordinate Parser
```typescript
function parseCoordinate(str: string): Coordinate {
// "(5,10)" → [5, 10]
const match = str.match(/^\((\d+),(\d+)\)$/);
if (!match) throw new Error(`Invalid coordinate: ${str}`);
return [parseInt(match[1]), parseInt(match[2])];
}
```
### Rectangle Parser
```typescript
function parseRectangle(str: string): Rectangle {
// "(0,0)-(20,15)" → { from: [0,0], to: [20,15] }
const match = str.match(/^\((\d+),(\d+)\)-\((\d+),(\d+)\)$/);
if (!match) throw new Error(`Invalid rectangle: ${str}`);
return {
from: [parseInt(match[1]), parseInt(match[2])],
to: [parseInt(match[3]), parseInt(match[4])]
};
}
```
### Door State Parser
```typescript
function parseDoorState(str: string): { open: boolean; locked: boolean; dc?: number } {
// "Open-Unlocked" → { open: true, locked: false }
// "Closed-Locked (DC15)" → { open: false, locked: true, dc: 15 }
const match = str.match(/^(Open|Closed)-(Unlocked|Locked)(?: \(DC(\d+)\))?$/);
if (!match) throw new Error(`Invalid door state: ${str}`);
return {
open: match[1] === "Open",
locked: match[2] === "Locked",
dc: match[3] ? parseInt(match[3]) : undefined
};
}
```
## Validation Rules
### Required Fields
1. `BMS Version` must be "1.0"
2. `Map Name` must be non-empty string
3. `Grid Size` must match pattern "WxH" where W,H > 0
4. `Grid Unit` must contain "ft" (e.g., "5ft")
### Coordinate Validation
1. Coordinates must be within grid bounds
2. Rectangle `from` coordinates must be ≤ `to` coordinates
3. Room rectangles must not overlap (optional warning)
### Door Validation
1. Door must connect two existing rooms
2. Door position must be on room boundary
3. Hinge side must be consistent with door position
### Lighting Validation
1. Light position must be within a room
2. Bright radius ≤ dim radius
3. Color must be valid CSS color
## Best Practices
1. **Start Simple**: Define rooms and connections first
2. **Be Specific**: Use exact coordinates, not "center of room"
3. **Consistent Naming**: R1, D1, O1, H1, L1, etc.
4. **Include DCs**: For all interactive elements
5. **Visual Notes**: Describe what players SEE
6. **Mechanical Notes**: Describe what players INTERACT WITH
7. **Layer Complexity**: Add hazards/objects after base layout
---
*Last Updated: March 19, 2026*