10 KiB
10 KiB
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
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-RoughWood-6in-CarvedIron-2ft-ReinforcedMasonry-1ft-SmoothNatural-Rockface
Floor Types:
Rough stone, debrisPacked earthWooden planksFlagstonesMosaic tile
4. Door Definition
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-BandedIron-Double-PortcullisStone-Sliding-SecretWood-Double-Ornate
States:
Open-UnlockedClosed-Locked(DC15)Closed-BarredDestroyed
5. Object Definition
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-RoughStone-Throne-OrnateIron-Chest-LargeWood-Barrel-SturdyStone-Altar-Carved
6. Hazard Definition
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-20ftMagical-Glyph-FireEnvironmental-Gas-PoisonMechanical-Dart-PressureMagical-Fear-Aura
7. Lighting Definition
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-WallLantern-HangingCandle-TableMagical-EverburningFungi-Bioluminescent
8. Connection Graph
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
ANNOTATIONS:
- "[Text]" at (x,y)
- "[Label]" pointing to (x1,y1)-(x2,y2)
- "DM: [Note]" at (x,y)
Advanced Features
Multi-level Maps
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
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
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
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
// 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
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
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
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
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
BMS Versionmust be "1.0"Map Namemust be non-empty stringGrid Sizemust match pattern "WxH" where W,H > 0Grid Unitmust contain "ft" (e.g., "5ft")
Coordinate Validation
- Coordinates must be within grid bounds
- Rectangle
fromcoordinates must be ≤tocoordinates - Room rectangles must not overlap (optional warning)
Door Validation
- Door must connect two existing rooms
- Door position must be on room boundary
- Hinge side must be consistent with door position
Lighting Validation
- Light position must be within a room
- Bright radius ≤ dim radius
- Color must be valid CSS color
Best Practices
- Start Simple: Define rooms and connections first
- Be Specific: Use exact coordinates, not "center of room"
- Consistent Naming: R1, D1, O1, H1, L1, etc.
- Include DCs: For all interactive elements
- Visual Notes: Describe what players SEE
- Mechanical Notes: Describe what players INTERACT WITH
- Layer Complexity: Add hazards/objects after base layout
Last Updated: March 19, 2026