Skip to main content

Manifest-Driven Design

Hyperscape uses JSON manifests for game content. Add new NPCs, items, stores, and world areas by editing JSON files in packages/server/world/assets/manifests/.
No code changes required—just edit the JSON manifest files and restart the server.

Content Files

All manifests are in packages/server/world/assets/manifests/:

Core Manifests

FilePurpose
npcs.tsNPC and mob definitions
items.tsItem properties and stats
banks-stores.tsShop inventories
world-areas.tsZone configuration
skill-unlocks.tsLevel requirements
avatars.tsCharacter models
quests.jsonQuest definitions with stages and rewards
stations.jsonCrafting stations (anvils, furnaces, ranges, banks)

Adding NPCs

NPCs are defined with combat stats, drops, and spawn locations:
{
  id: "goblin",
  name: "Goblin",
  combatLevel: 2,
  stats: {
    attack: 1,
    strength: 1,
    defense: 1,
    constitution: 5
  },
  aggressive: true,
  aggroRange: 3,
  drops: [
    { itemId: "coins", quantity: [1, 10], chance: 1.0 },
    { itemId: "bronze_sword", quantity: 1, chance: 0.05 }
  ],
  respawnTime: 15000
}

Difficulty Levels

LevelExamples
1Goblins, Bandits, Barbarians
2Hobgoblins, Guards, Dark Warriors
3Black Knights, Ice Warriors, Dark Rangers

Adding Items

Items include equipment, resources, and consumables. Add to the appropriate category file in items/ directory.

Example: Adding a Weapon

File: packages/server/world/assets/manifests/items/weapons.json
{
  "id": "mithril_longsword",
  "name": "Mithril Longsword",
  "type": "weapon",
  "tier": "mithril",
  "equipSlot": "weapon",
  "attackType": "MELEE",
  "weaponType": "longsword",
  "stackable": false,
  "tradeable": true,
  "value": 1300,
  "bonuses": {
    "attack": 26,
    "strength": 25
  }
}

Example: Adding a Tool

File: packages/server/world/assets/manifests/items/tools.json
{
  "id": "adamant_pickaxe",
  "name": "Adamant Pickaxe",
  "type": "tool",
  "tier": "adamant",
  "equipSlot": "weapon",
  "stackable": false,
  "tradeable": true,
  "value": 3200,
  "tool": {
    "skill": "mining",
    "priority": 4,
    "rollTicks": 3
  }
}

Example: Adding a Resource

File: packages/server/world/assets/manifests/items/resources.json
{
  "id": "mithril_ore",
  "name": "Mithril Ore",
  "type": "resource",
  "stackable": false,
  "tradeable": true,
  "value": 150,
  "notedItemId": "mithril_ore_noted"
}

Tier-Based Requirements

Items with a tier property automatically derive level requirements from tier-requirements.json:
{
  "id": "steel_sword",
  "tier": "steel",
  "equipSlot": "weapon",
  "attackType": "MELEE"
  // requirements auto-derived: { attack: 5 }
}
No need to manually specify requirements if using the tier system.

Item Types

  • weapon: Swords, bows, staffs
  • armor: Helmets, bodies, legs, shields
  • tool: Hatchets, pickaxes, fishing rods
  • consumable: Food, potions
  • resource: Logs, fish, ores, bars
  • currency: Coins
  • junk: Burnt food, broken items

Adding Shops

Shops define available items and prices:
{
  id: "general_store",
  name: "General Store",
  items: [
    { itemId: "bronze_hatchet", stock: 10, price: 50 },
    { itemId: "fishing_rod", stock: 10, price: 25 },
    { itemId: "tinderbox", stock: 10, price: 15 }
  ]
}

Adding Stations

Stations are interactive objects for crafting and processing:
{
  "type": "anvil",
  "name": "Anvil",
  "model": "asset://models/anvil/anvil.glb",
  "modelScale": 0.5,
  "modelYOffset": 0.2,
  "examine": "An anvil for smithing metal bars into weapons and tools."
}

Station Types

  • anvil: Smith bars into equipment
  • furnace: Smelt ores into bars
  • range: Cook food with reduced burn chance
  • bank: Store items

Adding World Areas

World areas define zones with biomes and mob spawns:
{
  id: "mistwood_valley",
  name: "Mistwood Valley",
  biome: "forest",
  difficulty: 1,
  spawns: [
    { npcId: "goblin", count: 5 },
    { npcId: "bandit", count: 3 }
  ],
  resources: [
    { type: "tree", count: 10 },
    { type: "fishing_spot", count: 2 }
  ]
}

Biomes

  • Mistwood Valley (foggy forest)
  • Goblin Wastes (barren lands)
  • Darkwood Forest (dense shadows)
  • Northern Reaches (frozen tundra)
  • Blasted Lands (corrupted areas)

Adding Recipes

Smelting Recipe

File: packages/server/world/assets/manifests/recipes/smelting.json
{
  "output": "mithril_bar",
  "inputs": [
    { "item": "mithril_ore", "amount": 1 },
    { "item": "coal", "amount": 4 }
  ],
  "level": 50,
  "xp": 30,
  "ticks": 4,
  "successRate": 1.0
}

Smithing Recipe

File: packages/server/world/assets/manifests/recipes/smithing.json
{
  "output": "mithril_longsword",
  "bar": "mithril_bar",
  "barsRequired": 2,
  "level": 56,
  "xp": 100,
  "ticks": 4,
  "category": "weapons"
}

Cooking Recipe

File: packages/server/world/assets/manifests/recipes/cooking.json
{
  "raw": "raw_shark",
  "cooked": "shark",
  "burnt": "burnt_shark",
  "level": 80,
  "xp": 210,
  "ticks": 4,
  "stopBurnLevel": {
    "fire": 94,
    "range": 89
  }
}

Firemaking Recipe

File: packages/server/world/assets/manifests/recipes/firemaking.json
{
  "log": "magic_logs",
  "level": 75,
  "xp": 303.8,
  "ticks": 4
}

Testing Changes

1

Edit Manifest

Add your content to the appropriate JSON file in packages/server/world/assets/manifests/
2

Restart Server

Stop the server (Ctrl+C) and restart with bun run dev
3

Verify In-Game

Check that your content appears correctly at http://localhost:3333
Server restart required: Unlike code changes, manifest changes require a full server restart to reload.

Validation

Atomic Loading

Directory-based manifests use atomic loading:
  • All required files must exist or system falls back to legacy format
  • For items/: All 5 category files must be present
  • For recipes/: Individual files are optional (falls back to embedded item data)
  • For gathering/: Individual files are optional (falls back to resources.json)

Duplicate Detection

The loader validates that no item ID appears in multiple category files:
[DataManager] Duplicate item ID "bronze_sword" found in items/weapons.json
This prevents data conflicts and ensures each item has a single source of truth.

Best Practices

Use bronze_sword not sword1. IDs should be self-documenting.
Use snake_case for IDs: mithril_platebody, oak_logs, raw_shrimp
Use tier property instead of manually specifying requirements for standard equipment.
Don’t embed recipe data in items.json - use dedicated recipe manifest files.
Verify level requirements, XP values, and item interactions work as expected.