Skip to main content
Glama
spatial.ts5.25 kB
import { z } from 'zod'; /** * Travel terrain types for navigation and movement */ export const TravelTerrainSchema = z.enum([ 'paved', // Roads, city streets - fast travel 'dirt', // Dirt roads, well-worn paths - normal travel 'wilderness', // Overgrown trails, rough terrain - slow travel 'indoor' // Inside buildings - instant/minimal travel ]); export type TravelTerrain = z.infer<typeof TravelTerrainSchema>; /** * Exit represents a connection between two rooms */ export const ExitSchema = z.object({ direction: z.enum([ 'north', 'south', 'east', 'west', 'up', 'down', 'northeast', 'northwest', 'southeast', 'southwest' ]), targetNodeId: z.string().uuid(), type: z.enum(['OPEN', 'LOCKED', 'HIDDEN']), dc: z.number().int().min(5).max(30).optional() .describe('DC for Perception to detect HIDDEN exits or Lockpicking for LOCKED'), description: z.string().optional() .describe('Narrative description of the exit (e.g., "A heavy oak door leads north")'), // Travel metadata travelTime: z.number().int().min(0).optional() .describe('Time to traverse in minutes (0 for instant, e.g., doorways)'), terrain: TravelTerrainSchema.optional() .describe('Type of terrain affecting travel speed and difficulty'), difficulty: z.number().int().min(5).max(30).optional() .describe('DC for Navigation or Survival checks if terrain is challenging'), }); export type Exit = z.infer<typeof ExitSchema>; // PHASE-2: Export BiomeType and Atmospheric for social hearing mechanics export const BiomeTypeSchema = z.enum([ 'forest', 'mountain', 'urban', 'dungeon', 'coastal', 'cavern', 'divine', 'arcane' ]); export type BiomeType = z.infer<typeof BiomeTypeSchema>; export const AtmosphericSchema = z.enum([ 'DARKNESS', 'FOG', 'ANTIMAGIC', 'SILENCE', 'BRIGHT', 'MAGICAL' ]); export type Atmospheric = z.infer<typeof AtmosphericSchema>; /** * RoomNode represents a persistent location in the world * Rooms are semantic locations (tavern, forest clearing, dungeon chamber) * distinct from physical grid tiles in the worldgen system */ export const RoomNodeSchema = z.object({ id: z.string().uuid(), // Narrative identity name: z.string() .min(1, 'Room name cannot be empty') .max(100, 'Room name too long') .refine((s) => s.trim().length > 0, 'Room name cannot be whitespace only'), baseDescription: z.string() .min(10, 'Description must be detailed') .max(2000, 'Description too long') .refine((s) => s.trim().length >= 10, 'Description must have at least 10 non-whitespace characters'), // World context biomeContext: BiomeTypeSchema .describe('Linked to src/engine/worldgen biome definitions'), // Atmospheric effects atmospherics: z.array(AtmosphericSchema).default([]) .describe('Environmental effects that modify perception and abilities'), // Network membership and local coordinates networkId: z.string().uuid().optional() .describe('ID of node network this room belongs to (town, road, dungeon)'), localX: z.number().int().min(0).optional() .describe('X coordinate within node network (relative to network origin)'), localY: z.number().int().min(0).optional() .describe('Y coordinate within node network (relative to network origin)'), // Connections exits: z.array(ExitSchema) .default([]), // Entities present entityIds: z.array(z.string().uuid()) .default([]) .describe('Foreign keys to characters/NPCs/items in this room'), // Metadata createdAt: z.string().datetime(), updatedAt: z.string().datetime(), visitedCount: z.number().int().min(0).default(0), lastVisitedAt: z.string().datetime().optional(), }); export type RoomNode = z.infer<typeof RoomNodeSchema>; /** * NodeNetwork represents a collection of connected rooms forming a location * Examples: towns (cluster), roads (linear), dungeons (cluster) */ export const NodeNetworkSchema = z.object({ id: z.string().uuid(), name: z.string() .min(1, 'Network name cannot be empty') .max(100, 'Network name too long'), type: z.enum(['cluster', 'linear']) .describe('cluster = town/dungeon, linear = road/path'), worldId: z.string() .describe('ID of the world this network belongs to'), // Primary location on world map centerX: z.number().int().min(0) .describe('Center X coordinate on world map'), centerY: z.number().int().min(0) .describe('Center Y coordinate on world map'), // Optional bounding box for large networks boundingBox: z.object({ minX: z.number().int().min(0), maxX: z.number().int().min(0), minY: z.number().int().min(0), maxY: z.number().int().min(0), }).optional() .describe('Bounding box for networks spanning multiple tiles'), // Metadata createdAt: z.string().datetime(), updatedAt: z.string().datetime(), }); export type NodeNetwork = z.infer<typeof NodeNetworkSchema>;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/rpg-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server