Nostrmon — Decentralized Monster-Taming World Protocol
NIP-XX: Nostrmon — Decentralized Monster-Taming World Protocol
draft optional
Abstract
This NIP defines a decentralized monster-taming game protocol on Nostr. “Nostrmon” (Nostr Monsters) is a framework inspired by games like Pokémon, where regions, maps, Nostrmon creatures, NPCs, and game saves are all Nostr addressable events. Anyone can create and publish content — regions, maps, creatures, or NPCs — and clients can assemble these events into a playable, traversable world.
Event Kinds
| Kind | Name | Description |
|---|---|---|
| 30597 | Region | A named region containing references to maps |
| 30259 | Map | A 2D grid-based map with layered tile data |
| 38267 | Nostrmon | A Nostr Monster creature definition |
| 36011 | NPC | A Non-Player Character (simple or AI-driven) |
| 35253 | Game Save | A player’s game progress snapshot |
| 39951 | Item | A usable, holdable, or key item definition |
Kind 30597 — Region
A Region is a named collection of maps that form a coherent geographical area. Each user may publish as many regions as they wish.
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Unique identifier for the region (slug) |
name |
✓ | Human-readable region name |
map |
✓ | One or more references to map events. Value: naddr of map |
entry |
The d tag of the map that serves as the travel entry/exit point for this region |
|
summary |
Short description of the region | |
image |
URL of a banner or splash image for the region | |
music |
naddr of a default music event (kind 36787) for the region |
|
t |
Hashtags for discovery (e.g., nostrmon) |
|
alt |
✓ | NIP-31 human-readable description: "Nostrmon region: <name>" |
Example
{
"kind": 30597,
"content": "A vast volcanic region with ancient ruins and mysterious tunnels.",
"tags": [
["d", "ashfire-region"],
["name", "Ashfire Region"],
["map", "naddr1...map1"],
["map", "naddr1...map2"],
["entry", "ashfire-gateway"],
["summary", "A volcanic region full of fire-type Nostrmon."],
["image", "https://example.com/ashfire-banner.jpg"],
["music", "naddr1...battletheme"],
["t", "nostrmon"],
["alt", "Nostrmon region: Ashfire Region"]
]
}
Kind 30259 — Map
A Map is a 2D, grid-based environment with up to 5 layers. Maps are the atomic playable unit of the world.
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Unique identifier (slug) for the map |
name |
✓ | Human-readable map name |
type |
✓ | Map type: route, area, town, city, dungeon, house |
width |
✓ | Map width in tiles (integer, as string) |
height |
✓ | Map height in tiles (integer, as string) |
region |
naddr of the region this map belongs to. Absent = “Unknown Region” |
|
music |
naddr of a music event (kind 36787) for this map |
|
multiplayer |
"true" or "false". Default: "false" |
|
prison |
"true" or "false". Default: "false". Disables fast travel on map |
|
daynight |
"true" or "false". Whether day/night cycle is visible. Default: "true" |
|
entry-map |
"true" or "false". Marks this map as the region’s travel gateway. Entry maps can be linked to entry maps of other regions for cross-region warps. |
|
fasttravel-x |
X tile coordinate where the player spawns when fast-traveling to this map (integer string). Default: "1" |
|
fasttravel-y |
Y tile coordinate where the player spawns when fast-traveling to this map (integer string). Default: "1" |
|
image |
URL of a preview image for the map | |
t |
Tags for discovery, always include nostrmon |
|
alt |
✓ | NIP-31 description: "Nostrmon map: <name>" |
Content
The content field is a JSON object with the following structure:
interface MapContent {
// Layer 1 (REQUIRED): Terrain layer
// 2D array [row][col] of terrain tile IDs (integers)
terrain: number[][];
// Layer 2 (REQUIRED): Interactive layer
// Sparse array of interactive objects keyed by "x,y"
interactive: Record<string, InteractiveObject>;
// Layer 3 (OPTIONAL): Height map for 3D rendering
// 2D array [row][col] of height values (0.0–1.0)
heightmap?: number[][];
// Layer 4 (OPTIONAL): Wild encounter zones
// Array of encounter zone definitions
encounters?: EncounterZone[];
// Layer 5 (OPTIONAL): Named zones
namedZones?: NamedZone[];
}
Terrain Tile IDs
Terrain tile IDs are integers. Clients are responsible for rendering tilesets. Suggested standard tile IDs:
| ID | Type | Category | Passable | Notes |
|---|---|---|---|---|
| 0 | Void/Empty | Special | No | No tile |
| 1 | Grass | Outdoor | Yes | May trigger wild encounters |
| 2 | Tall Grass | Outdoor | Yes | High encounter rate |
| 3 | Water | Outdoor | Surf | Requires Surf ability |
| 4 | Deep Water | Outdoor | Surf | Requires Dive ability |
| 5 | Sand | Outdoor | Yes | |
| 6 | Snow | Outdoor | Yes | May slow movement |
| 7 | Ice | Outdoor | Yes | Sliding movement |
| 8 | Mountain | Outdoor | No | Solid obstacle |
| 9 | Rock | Outdoor | No | Solid obstacle |
| 10 | Tree | Outdoor | No | Can be Cut |
| 11 | Flower | Outdoor | Yes | |
| 12 | Path/Road | Outdoor | Yes | |
| 13 | Bridge | Outdoor | Yes | |
| 14 | Cliff | Outdoor | No | Can Surf below |
| 15 | Cave Floor | Indoor | Yes | |
| 16 | Cave Wall | Indoor | No | |
| 17 | Cave Water | Indoor | Surf | |
| 18 | Floor (Indoor) | Indoor | Yes | Generic indoor floor |
| 19 | Wall (Indoor) | Indoor | No | |
| 20 | Carpet | Indoor | Yes | |
| 21 | Counter | Indoor | No | Shop counter |
| 22 | Bookshelf | Indoor | No | |
| 23 | Lava | Special | No | Damages player |
| 24 | Pit | Special | Fall | Player falls through |
| 25 | Warp Pad | Special | Yes | Visual warp indicator |
| 26 | Tall Grass (Cave) | Indoor | Yes | Encounters in caves |
| 27 | Sand (Indoor) | Indoor | Yes | |
| 28 | Swamp | Outdoor | Yes | Slow movement, encounters |
| 29 | Roof/Overhang | Overhead | — | Renders over player (z-layered) |
| 30 | Rail/Track | Indoor | Yes |
House Tiles (Outdoor)
House tiles are used on outdoor maps to represent buildings the player can enter via warps.
| ID | Type | Category | Passable | Notes |
|---|---|---|---|---|
| 31 | House Wall | Outdoor/House | No | Generic exterior house wall |
| 32 | House Roof | Outdoor/House | No | Roof tile; renders above player level |
| 33 | House Door | Outdoor/House | Warp | Entrance/exit point; triggers warp action |
| 34 | House Window | Outdoor/House | No | Decorative; may show light at night |
| 35 | House Chimney | Outdoor/House | No | Decorative chimney top |
| 36 | House Foundation | Outdoor/House | No | Base/step of a building |
| 37 | Shop Awning | Outdoor/House | No | Overhead awning above shop doorways |
| 38 | House Roof (Peaked) | Outdoor/House | No | Peaked/angled roof section |
Fence & Wall Tiles (Special — Outdoor or Indoor)
Fence and wall tiles are traversal obstacles. They can appear in both outdoor and indoor settings.
| ID | Type | Category | Passable | Notes |
|---|---|---|---|---|
| 40 | Wooden Fence | Special/Fence | No | Common outdoor low fence; can be jumped over |
| 41 | Stone Wall (Ext.) | Special/Fence | No | Exterior stone boundary wall |
| 42 | Iron Fence | Special/Fence | No | Metal fence; urban/city areas |
| 43 | Hedge | Special/Fence | No | Living plant fence; can be Cut |
| 44 | Picket Fence | Special/Fence | No | Decorative short fence; used near houses |
| 45 | Low Wall | Special/Fence | No | Short interior divider; indoor and outdoor |
| 46 | Barricade | Special/Fence | No | Temporary blockade; can be conditional |
| 47 | Corner Wall | Special/Wall | No | 90° corner wall piece for interiors |
| 48 | Pillar | Special/Wall | No | Decorative or structural column; indoor/outdoor |
| 49 | Fence Gate | Special/Fence | Cond. | Passable only when a condition is met |
| 50 | Cave Fence | Special/Fence | No | Fence type suited for cave environments |
| 51 | Fence Post | Special/Fence | No | Single post; connects fence segments |
Clients may extend this list with custom tile IDs above 100.
Interactive Object Types
interface InteractiveObject {
type: "npc" | "sign" | "warp" | "item" | "trigger";
// For type "npc"
npc?: string; // naddr of the NPC event (kind 36011)
facing?: "up" | "down" | "left" | "right";
// For type "sign"
text?: string; // Text content shown when examined
// For type "warp"
// Target map reference. Resolution order:
// 1. Full naddr (naddr1…) — unambiguous, preferred for cross-user warps
// 2. d-tag slug — resolved against the same author's maps first, then globally
target?: string;
// Tile coordinates on the target map where the player arrives.
// If omitted, the target map's fasttravel-x/fasttravel-y tags are used as fallback.
targetX?: number;
targetY?: number;
direction?: "both" | "one-way"; // Default: "both"
condition?: string; // Script condition (see Script System)
visible?: boolean | string; // true/false or script expression
// For type "item"
item?: string; // Item identifier
condition?: string; // Script condition (only show/take if met)
// For type "trigger"
script?: string; // Script executed when player steps on tile
triggerOn?: "step" | "action"; // Default: "step"
}
Encounter Zone
interface EncounterZone {
// Tiles included in this zone, as array of "x,y" coordinates
// OR a rect: [x, y, width, height]
tiles?: string[];
rect?: [number, number, number, number];
// Encounter rate: 0.0–1.0
rate: number;
// Nostrmon that can appear here
nostrmon: EncounterEntry[];
}
interface EncounterEntry {
// naddr of the Nostrmon event (kind 38267), or its d-tag
ref: string;
// Level range
minLevel: number;
maxLevel: number;
// Relative rarity weight (default: 1)
weight?: number;
// Which form index to use (default: 0)
formIndex?: number;
}
Named Zone
interface NamedZone {
name: string;
// Zone type for minimap: "area", "town", "city", "dungeon"
type: "area" | "town" | "city" | "dungeon";
// Rectangle: [x, y, width, height] in tiles
rect: [number, number, number, number];
// Optional hex color for minimap rendering
color?: string;
}
Script System
The interactive layer supports a simple scripting language for conditions and triggers. Scripts are plain strings using a minimal expression syntax:
# Variables (set/check flags)
SET flag_name
UNSET flag_name
HAS flag_name # Check if flag is set
NOT HAS flag_name
# Item checks
HAS_ITEM item_id
NOT HAS_ITEM item_id
GIVE_ITEM item_id
# Badge/Achievement checks
HAS_BADGE badge_id
# Dialogue
SAY "Line 1" "Line 2" "Line 3"
SAY_CONDITIONAL HAS flag_name "You already did this." "You haven't done this yet."
# Choice boxes
CHOICE "Option A" "Option B"
ON_CHOICE 0 SET chose_a
ON_CHOICE 1 SET chose_b
# Warp
WARP naddr_or_dtag x y
# Battle
BATTLE naddr_npc
BATTLE_WILD naddr_nostrmon level
# Control flow
IF HAS flag_name THEN ... END
Kind 38267 — Nostrmon
A Nostrmon is an addressable event defining a creature species, including its stats, types, moves, and sprites.
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Unique species identifier (slug, e.g. flamewulf) |
name |
✓ | Species name |
type |
✓ | One, two, or three types (repeat tag). e.g. ["type", "fire"] |
sprite |
✓ | URL of the front sprite image |
backsprite |
URL of the back sprite (for battle screen) | |
model3d |
URL of a 3D model file (glTF/glb) for 3D clients | |
hp |
✓ | Base HP stat (integer string) |
atk |
✓ | Base Attack stat |
def |
✓ | Base Defense stat |
spatk |
✓ | Base Special Attack stat |
spdef |
✓ | Base Special Defense stat |
spd |
✓ | Base Speed stat |
move |
✓ | Learnable move. Format: ["move", "move-id", "learn-method", "level-or-condition"] |
t |
nostrmon and any other tags |
|
alt |
✓ | NIP-31 description: "Nostrmon creature: <name>" |
Content
The content field is a JSON object:
interface NostrmonContent {
// Flavor text / Pokédex-style description
description?: string;
// Forms (if more than one form exists)
forms?: NostrmonForm[];
}
interface NostrmonForm {
name: string; // Form name (e.g., "Mega", "Shiny", "Winter")
sprite: string; // Front sprite URL for this form
backsprite?: string; // Back sprite URL for this form
model3d?: string; // 3D model URL for this form
types?: string[]; // Override types for this form
// Override stats (omitted = use base stats)
hp?: number;
atk?: number;
def?: number;
spatk?: number;
spdef?: number;
spd?: number;
}
Move Learn Methods
The move tag’s learn method field accepts:
| Method | Description |
|---|---|
level |
Learned at the given level number |
tm |
Taught via Technical Machine item |
egg |
Learned via breeding (egg move) |
tutor |
Taught by a move tutor NPC |
evolution |
Learned upon evolution |
Types
Standard Nostrmon types (clients may define custom types):
normal, fire, water, electric, grass, ice, fighting, poison, ground, flying, psychic, bug, rock, ghost, dragon, dark, steel, fairy, cosmic, digital, sound, nature
Example
{
"kind": 38267,
"content": "{\"description\":\"A canine Nostrmon wreathed in spectral flame. It is said to guard the gates of forgotten servers.\",\"forms\":[]}",
"tags": [
["d", "flamewulf"],
["name", "Flamewulf"],
["type", "fire"],
["type", "ghost"],
["sprite", "https://example.com/flamewulf-front.png"],
["backsprite", "https://example.com/flamewulf-back.png"],
["hp", "75"],
["atk", "90"],
["def", "60"],
["spatk", "85"],
["spdef", "65"],
["spd", "100"],
["move", "ember", "level", "5"],
["move", "shadow-ball", "level", "30"],
["move", "flamethrower", "tm", ""],
["t", "nostrmon"],
["alt", "Nostrmon creature: Flamewulf"]
]
}
Kind 36011 — NPC
An NPC (Non-Player Character) is a character that can be placed on maps. NPCs come in two varieties: Simple (scripted dialogue) and AI (language model driven).
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Unique NPC identifier (slug) |
name |
✓ | NPC display name |
npc-type |
✓ | "simple" or "ai" |
sprite |
✓ | URL of the NPC’s sprite image |
nostrmon |
naddr of a Nostrmon. Repeat for multiple Nostrmon (used in battles) |
|
nostrmon-level |
Level for each Nostrmon (paired by index with nostrmon tags) |
|
trainer-class |
Trainer class string (e.g., "Bug Catcher", "Gym Leader") |
|
battle-music |
naddr of a music event for the battle against this NPC |
|
t |
nostrmon and discovery tags |
|
alt |
✓ | NIP-31 description: "Nostrmon NPC: <name>" |
Content
The content field is a JSON object:
interface NPCContent {
// Scripted dialogue (required for simple NPCs, used as fallback for AI NPCs)
dialogue: string[];
// Choice-based dialogue branches (optional)
choices?: NPCChoice[];
// For AI NPCs only
ai?: {
// Describe the NPC's knowledge, backstory, and behavior in natural language
knowledge: string;
// NPC personality and behavior description
behavior: string;
// Preferred languages (English always required)
languages?: string[];
// Additional freeform properties
notes?: string;
};
}
interface NPCChoice {
prompt: string; // The player's choice text
response: string[]; // NPC response dialogue
condition?: string; // Script condition to show this choice
effect?: string; // Script effect when chosen
}
Example (Simple NPC)
{
"kind": 36011,
"content": "{\"dialogue\":[\"Greetings, traveler!\",\"The Ashfire Caves to the east are dangerous.\",\"Make sure your Nostrmon are well rested before you go!\"]}",
"tags": [
["d", "old-hermit-ashfire"],
["name", "Old Hermit"],
["npc-type", "simple"],
["sprite", "https://example.com/hermit-sprite.png"],
["t", "nostrmon"],
["alt", "Nostrmon NPC: Old Hermit"]
]
}
Example (AI NPC)
{
"kind": 36011,
"content": "{\"dialogue\":[\"Hello! I'm Professor Nakamoto. I study Nostrmon across the decentralized world.\"],\"ai\":{\"knowledge\":\"Expert on Nostrmon biology, types, and habitats. Knows all maps in Ashfire Region.\",\"behavior\":\"Friendly and enthusiastic. Loves giving hints. Never breaks character.\",\"languages\":[\"English\",\"Japanese\"],\"notes\":\"Occasionally quotes Satoshi Nakamoto philosophically.\"}}",
"tags": [
["d", "professor-nakamoto"],
["name", "Prof. Nakamoto"],
["npc-type", "ai"],
["sprite", "https://example.com/professor-sprite.png"],
["t", "nostrmon"],
["alt", "Nostrmon NPC: Prof. Nakamoto"]
]
}
Kind 35253 — Game Save
A Game Save records a player’s progress. It is a replaceable event per d tag, allowing players to maintain named save slots. Players may also export/import saves locally.
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Save slot identifier (e.g., "save-1") |
save-name |
Human-readable save name | |
region |
naddr of the current region |
|
map |
d tag of the current map |
|
playtime |
Total playtime in seconds (integer string) | |
version |
✓ | Protocol version of this save format (e.g., "1") |
alt |
✓ | NIP-31 description: "Nostrmon game save" |
Content
The content field is NIP-44 encrypted to the player’s own pubkey and contains the full game state as JSON:
interface GameSaveContent {
// Player info
playerName: string;
badges: string[]; // Badge IDs earned
// Current position
currentMap: string; // d-tag of current map
currentRegion?: string; // naddr of current region
positionX: number;
positionY: number;
// Active team (up to 6 Nostrmon)
team: OwnedNostrmon[];
// PC Storage boxes
storage: OwnedNostrmon[][];
// Inventory
inventory: Record<string, number>; // item_id -> quantity
// World flags (script system state)
flags: Record<string, boolean>;
// Completed NPC battles
defeatedTrainers: string[]; // NPC d-tags
// Timestamps
savedAt: number;
startedAt: number;
}
interface OwnedNostrmon {
speciesRef: string; // naddr or d-tag of species (kind 38267)
nickname?: string;
level: number;
experience: number;
formIndex: number; // Current form (default: 0)
hp: number; // Current HP
moves: string[]; // Up to 4 move IDs currently equipped
learnedMoves: string[];// All moves ever learned
// Individual Values (genetic variation, 0-31 per stat)
ivs: { hp: number; atk: number; def: number; spatk: number; spdef: number; spd: number; };
// Effort Values (training gains)
evs: { hp: number; atk: number; def: number; spatk: number; spdef: number; spd: number; };
// Personality traits (affect stat calculations)
nature: string;
caughtAt: number; // Unix timestamp
caughtMap?: string; // d-tag of map where caught
}
Kind 39951 — Item
An Item is an addressable event defining a usable, holdable, or key item that can be found in the world, bought in shops, or given by NPCs. Items from any author can be referenced.
Tags
| Tag | Req. | Description |
|---|---|---|
d |
✓ | Unique item identifier (slug, e.g. potion, escape-rope) |
name |
✓ | Human-readable item name |
item-type |
✓ | Category: consumable, hold, key, tm, ball, badge, misc |
sprite |
URL of the item’s icon/sprite image | |
price |
Default shop buy price in gold (integer string). "0" = not for sale |
|
sell-price |
Default sell price (integer string). Omit = half of price |
|
single-use |
"true" if consumed on use. Default: "true" for consumables |
|
holdable |
"true" if a Nostrmon can hold this item in battle |
|
t |
nostrmon and any additional tags |
|
alt |
✓ | NIP-31 description: "Nostrmon item: <name>" |
Content
The content field is a JSON object:
interface ItemContent {
// Description shown in the bag/item screen
description: string;
// What happens when this item is used (plain-text script or freeform description)
// Clients interpret this to apply effects. Common effect keywords:
// HEAL_HP <amount> — restore HP to one Nostrmon
// HEAL_HP_ALL <amount> — restore HP to all team Nostrmon
// HEAL_STATUS — cure a status condition
// REVIVE — revive a fainted Nostrmon to half HP
// REVIVE_FULL — revive to full HP
// CATCH_RATE <multiplier> — ball catch-rate multiplier (for ball items)
// TEACH_MOVE <move-id> — teach a move (for TM items)
// WARP_ESCAPE — escape from a dungeon to last town
// BADGE <badge-id> — grants a badge (for badge items)
effect?: string;
}
Item Categories
| Category | Description |
|---|---|
consumable |
Used from the bag; disappears after use (e.g. Potion, Antidote) |
hold |
Held by a Nostrmon during battle for passive effects |
key |
Key item; never consumed; triggers world events or opens warps |
tm |
Technical Machine; teaches a move to a compatible Nostrmon |
ball |
Used in battle to catch wild Nostrmon; has a CATCH_RATE multiplier |
badge |
Proof of a gym/trainer victory; unlocks abilities or areas |
misc |
Miscellaneous item with no standard category |
Example
{
"kind": 39951,
"content": "{\"description\":\"Restores 20 HP to a single Nostrmon.\",\"effect\":\"HEAL_HP 20\"}",
"tags": [
["d", "potion"],
["name", "Potion"],
["item-type", "consumable"],
["sprite", "https://example.com/items/potion.png"],
["price", "300"],
["sell-price", "150"],
["single-use", "true"],
["holdable", "false"],
["t", "nostrmon"],
["alt", "Nostrmon item: Potion"]
]
}
Querying Content
Discover all Nostrmon (any author)
[{ "kinds": [38267], "#t": ["nostrmon"], "limit": 50 }]
Discover all regions (any author)
[{ "kinds": [30597], "#t": ["nostrmon"], "limit": 50 }]
Get a specific NPC by author and d-tag
[{ "kinds": [36011], "authors": ["<pubkey>"], "#d": ["old-hermit-ashfire"] }]
Discover all items (any author)
[{ "kinds": [39951], "#t": ["nostrmon"], "limit": 100 }]
Get all maps in a region (by region naddr reference)
Maps reference their region via the region tag. Clients should query maps and filter by region reference client-side, or use a relay that supports tag filtering.
Battle Rules
Wild Battles
- A wild encounter is triggered when the player steps on a tile inside an encounter zone, according to the zone’s
rate(0–1). - Auto-catch rule: Wild Nostrmon at level 1–5 are caught automatically at 100% success rate with no battle required. This ensures new players always get their first Nostrmon.
- If the player has no Nostrmon in their team, wild encounters at any level trigger auto-catch instead of a battle.
- For wild Nostrmon above level 5, a full battle takes place. The player may fight, use items, switch Nostrmon, or attempt to flee.
- Catching requires a ball item. Catch rate =
0.3 + (1 − currentHpRatio) × 0.7modified by the ball’sCATCH_RATEmultiplier. - The player can flee from any wild battle without penalty.
Trainer Battles
- NPCs with one or more
nostrmontags initiate trainer battles when the player interacts with them. - The player cannot catch the Nostrmon of another trainer.
- The player cannot flee a trainer battle.
- Defeating a trainer stores their
d-tag indefeatedTrainersin the save. Re-interacting with a defeated trainer shows fallback dialogue instead of battle. - Trainer battle music uses the NPC’s
battle-musictag if set, otherwise the region’s default battle theme.
Stat & Damage Calculation
- Stats use the standard formula:
floor((2×base + IV + floor(EV/4)) × level / 100) + 5(or+level+10for HP) - IVs: random 0–31 per stat, generated at catch/receive time
- EVs: start at 0, gained from defeating Nostrmon
- Natures: 25 natures, each raises one stat by 10% and lowers another (or neutral)
- Level-up: cubic XP formula
XP_needed = (level+1)³ − level³
XP & Levelling
- Clients MUST award XP to the active Nostrmon after defeating or catching a wild Nostrmon
- XP reward:
floor((sum_of_base_stats × enemy_level) / 7) - When a Nostrmon’s XP exceeds the threshold, it levels up and its stats recalculate
- Clients SHOULD check for move learning on level-up (from the species
movetags withlearn-method: level)
Multiplayer Presence
On maps with multiplayer: "true", clients SHOULD broadcast the player’s position using ephemeral kind 20001 events (“Presence Events”).
Kind 20001 — Presence Event (Ephemeral)
| Field | Value |
|---|---|
kind |
20001 |
content |
JSON: {"x": <tile_x>, "y": <tile_y>, "name": "<display_name>"} |
tags |
["d", "<map_d_tag>"], ["expiration", "<unix_timestamp+30>"] |
- Clients broadcast their position every ~5 seconds while on a multiplayer map
- Clients subscribe to kind 20001 events filtered by the current map’s
dtag - Players not seen for 20+ seconds should be removed from the display
- Other players are shown as coloured dots or avatars on the map
- Position data is not saved — it is purely ephemeral
Client Requirements
MUST
- Clients MUST be able to render and play maps using terrain and interactive layers
- Clients MUST support Nostrmon battles (wild and trainer)
- Clients MUST auto-catch wild Nostrmon at level 1–5 at 100% rate without battle
- Clients MUST prevent catching in trainer battles
- Clients MUST prevent fleeing in trainer battles
- Clients MUST support game saves (kind 35253) with NIP-44 encryption
- Clients MUST persist saves locally (e.g. localStorage) in addition to Nostr
- Clients MUST treat maps without a
regiontag as belonging to “Unknown Region” - Clients MUST use
fasttravel-x/fasttravel-yas the spawn position when fast-traveling to a map - Clients MUST NOT allow fast-traveling to a map with
prison: "true"unless it belongs to the current user - Clients MUST implement an in-game menu with at minimum: team management, bag/inventory, save game
SHOULD
- Clients SHOULD render a minimap for regions with map type-appropriate icons
- Clients SHOULD support keyboard navigation and touch controls on mobile
- Clients SHOULD support gamepad/controller input
- Clients SHOULD render day/night cycles for maps where
daynightis"true" - Clients SHOULD handle AI NPCs with configurable AI provider/model
- Clients SHOULD list entry maps (
entry-map: "true") from all authors for cross-region warp selection - Clients SHOULD broadcast and receive presence events on multiplayer maps (kind 20001)
- Clients SHOULD show PC box storage for Nostrmon overflow management
MAY
- Clients MAY render maps in 2.5D or 3D using the height map layer
- Clients MAY provide editors for regions, maps, Nostrmon, NPCs, and items
- Clients MAY support custom tilesets beyond the standard tile IDs
- Clients MAY support NPC shops (using item
pricetags for buy/sell) - Clients MAY implement Nostrmon trading between players on multiplayer maps
Interoperability Notes
- All creature references use
naddr(kind 38267) or thedtag — clients should support both - Map warps referencing other users’ maps are valid and encouraged for cross-region travel
- Nostrmon from any author may be referenced in encounter zones
- Music references use kind 36787 (Nostr Music events)
- The
t: nostrmontag is used for all discovery queries — clients SHOULD include it on all published events
This NIP was authored as part of the Nostrmon World client. Feedback welcome.
Looking for comments…
Searching Nostr relays. This may take a moment the first time this article is opened.
Looking for comments…
Searching Nostr relays. This may take a moment the first time this article is opened.