Skip to main content
Glama
poi.ts7.14 kB
/** * POI (Point of Interest) Registry Schema * * This schema bridges the gap between: * - World-level Structures (cities, towns, dungeons on the world map) * - Room-level NodeNetworks (navigable room graphs) * * A POI links a Structure to its corresponding NodeNetwork, enabling: * - Click on map → enter location's room network * - Room discovery → reveal POI on map * - Hierarchical locations (dungeon → sub-levels) * * @module schema/poi */ import { z } from 'zod'; /** * POI Category for grouping and filtering */ export const POICategorySchema = z.enum([ 'settlement', // Cities, towns, villages 'fortification', // Castles, forts, towers 'dungeon', // Dungeons, caves, lairs 'landmark', // Ruins, monuments, natural wonders 'religious', // Temples, shrines, sacred groves 'commercial', // Markets, trading posts, inns 'natural', // Notable terrain features 'hidden' // Secret locations (require discovery) ]); export type POICategory = z.infer<typeof POICategorySchema>; /** * POI Discovery State */ export const POIDiscoveryStateSchema = z.enum([ 'unknown', // Not yet discovered - hidden from map 'rumored', // Heard about but not visited - shown as "?" 'discovered', // Visited at least once - shown on map 'explored', // Fully explored - all rooms visited 'mapped' // Player has created detailed notes ]); export type POIDiscoveryState = z.infer<typeof POIDiscoveryStateSchema>; /** * POI Icon for map visualization */ export const POIIconSchema = z.enum([ 'city', 'town', 'village', 'castle', 'fort', 'tower', 'dungeon', 'cave', 'ruins', 'temple', 'shrine', 'inn', 'market', 'mine', 'farm', 'camp', 'portal', 'monument', 'tree', // Notable tree (world tree, etc.) 'mountain', // Peak or notable mountain 'lake', 'waterfall', 'bridge', 'crossroads', 'unknown' // Generic "?" icon ]); export type POIIcon = z.infer<typeof POIIconSchema>; /** * POI Registry Entry * * Links a world-map structure to its room network. */ export const POISchema = z.object({ id: z.string().uuid(), // World Map Position worldId: z.string().describe('World this POI belongs to'), regionId: z.string().optional().describe('Region containing this POI'), x: z.number().int().min(0).describe('World grid X coordinate'), y: z.number().int().min(0).describe('World grid Y coordinate'), // Identity name: z.string().min(1).max(100), description: z.string().max(500).optional() .describe('Brief description for map tooltip'), category: POICategorySchema, icon: POIIconSchema, // Linked Entities structureId: z.string().optional() .describe('ID of the world-level Structure (if generated)'), networkId: z.string().uuid().optional() .describe('ID of the NodeNetwork (room graph) for this POI'), entranceRoomId: z.string().uuid().optional() .describe('ID of the entry RoomNode (where players spawn when visiting)'), // Discovery & Visibility discoveryState: POIDiscoveryStateSchema.default('unknown'), discoveredBy: z.array(z.string().uuid()).default([]) .describe('Character IDs who have discovered this POI'), discoveryDC: z.number().int().min(0).max(30).optional() .describe('Perception/Investigation DC to discover if hidden'), // Hierarchical POIs (e.g., dungeon with sub-levels) parentPOIId: z.string().uuid().optional() .describe('Parent POI for nested locations'), childPOIIds: z.array(z.string().uuid()).default([]) .describe('Child POIs (sub-levels, annexes)'), // Metadata population: z.number().int().min(0).default(0) .describe('Population for settlements'), level: z.number().int().min(1).max(20).optional() .describe('Suggested character level for dungeons'), tags: z.array(z.string()).default([]) .describe('Searchable tags (e.g., "goblin", "abandoned", "haunted")'), createdAt: z.string().datetime(), updatedAt: z.string().datetime() }); export type POI = z.infer<typeof POISchema>; /** * Map Layer for visualization * Returned to frontend for rendering */ export const MapLayerSchema = z.object({ layerId: z.string(), layerName: z.string(), visible: z.boolean().default(true), opacity: z.number().min(0).max(1).default(1), // POIs in this layer pois: z.array(z.object({ id: z.string(), x: z.number(), y: z.number(), name: z.string(), icon: POIIconSchema, category: POICategorySchema, discoveryState: POIDiscoveryStateSchema, hasNetwork: z.boolean(), // Can be entered population: z.number().optional() })) }); export type MapLayer = z.infer<typeof MapLayerSchema>; /** * Map Visualization Data * Complete data package for frontend map rendering */ export const MapVisualizationSchema = z.object({ worldId: z.string(), worldName: z.string(), width: z.number(), height: z.number(), // Base layers (from worldgen) terrainLayer: z.object({ biomes: z.array(z.string()), // Biome palette tiles: z.array(z.array(z.number())) // [biomeIdx, elevation, regionId, hasRiver, hasStructure] }), // Region overlay regions: z.array(z.object({ id: z.number(), name: z.string(), biome: z.string(), capitalX: z.number(), capitalY: z.number(), color: z.string().optional() })), // POI layers poiLayers: z.array(MapLayerSchema), // Active character position (optional) playerPosition: z.object({ characterId: z.string(), x: z.number(), y: z.number(), roomId: z.string().optional() }).optional(), // Fog of war (tiles discovered by player) discoveredTiles: z.array(z.string()).optional() // "x,y" format }); export type MapVisualization = z.infer<typeof MapVisualizationSchema>; /** * Helper: Get icon for a structure type */ export function getIconForStructureType(structureType: string): POIIcon { switch (structureType.toLowerCase()) { case 'city': return 'city'; case 'town': return 'town'; case 'village': return 'village'; case 'castle': return 'castle'; case 'ruins': return 'ruins'; case 'dungeon': return 'dungeon'; case 'temple': return 'temple'; default: return 'unknown'; } } /** * Helper: Get category for a structure type */ export function getCategoryForStructureType(structureType: string): POICategory { switch (structureType.toLowerCase()) { case 'city': case 'town': case 'village': return 'settlement'; case 'castle': return 'fortification'; case 'dungeon': return 'dungeon'; case 'ruins': return 'landmark'; case 'temple': return 'religious'; default: return 'landmark'; } }

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