Skip to content

Create a Custom NPC

Goal

Create a Slime — a hostile NPC that chases and attacks players on sight. You will set up a 3D model with animations, define its AI behavior through template inheritance, configure a weighted drop table, and add multilingual translations. By the end, you will have a fully working NPC mod you can spawn in Creative Mode.

What You’ll Learn

  • How NPCs are structured across three JSON layers (Server Model, NPC Role, Drop Table)
  • How to set up a model with 9 animation sets
  • How template inheritance (Template_Predator) provides AI behavior
  • How weighted drop tables control loot
  • How to add translations for EN, ES, and PT-BR

Prerequisites

Companion mod repository: hytale-mods-custom-npc


NPC Architecture Overview

Unlike blocks and items which each use a single JSON file, NPCs require three separate definitions that work together:

flowchart TD;
A[Server Model<br>Model + Animations + HitBox] --> D[NPC in Game];
B[NPC Role<br>AI Behavior + Stats] --> D;
C[Drop Table<br>Loot on Death] --> D;
style A fill:#2d6a8f,color:#fff;
style B fill:#2d5a27,color:#fff;
style C fill:#8f6a2d,color:#fff;
style D fill:#5a2d8f,color:#fff;
LayerFile LocationPurpose
Server ModelServer/Models/Links the .blockymodel file, texture, animations, hitbox, and camera settings
NPC RoleServer/NPC/Roles/Defines AI behavior via template inheritance, health, knockback, and translation keys
Drop TableServer/Drops/Controls what loot drops when the NPC dies, using weighted random selection

The Server Model Appearance name connects all three — the NPC Role references it, and the engine uses it to find the correct model, texture, and animations.


Step 1: Create the Model and Texture in Blockbench

Open Blockbench and create a new Hytale Character project:

  • Block Size: 64
  • Pixel Density: 64
  • UV Size: 128×128 (texture must match: 128×128 pixels)

Build the slime body using cubes organized in groups. For the Slime, the structure is:

GroupPurpose
BodyMain slime body (large cube)
HeadTop portion (used by camera tracking)
EyesFace details
Arm_Left / Arm_RightSmall appendages for attack animations
Leg_Left / Leg_RightBase stubs for walk animations

Paint the texture in the Paint tab — green tones with darker spots work well for a slime creature.

Slime model in Blockbench — cube-based body with eyes and mouth

Export the Model

  1. File > Export > Export Hytale Blocky Model → save as Model_Slime.blockymodel
  2. Save the texture separately as Texture.png (128×128)

Create Animations

NPCs need animation files for each movement state. Create these 9 animations in Blockbench’s Animate tab:

AnimationFileLoopPurpose
IdleIdle.blockyanimYesStanding still — subtle bounce
WalkWalk.blockyanimYesMoving forward
Walk_BackwardWalk_Backward.blockyanimYesMoving backward
RunRun.blockyanimYesChasing the player
AttackAttack.blockyanimYesMelee strike
DeathDeath.blockyanimNoPlays once on death
CrouchCrouch.blockyanimYesCrouching idle
Crouch_WalkCrouch_Walk.blockyanimYesCrouching forward
Crouch_Walk_BackwardCrouch_Walk_Backward.blockyanimYesCrouching backward

Export each animation with File > Export > Export Hytale Block Animation.


Step 2: Set Up the Mod File Structure

Place your files in the mod folder following this exact structure:

CreateACustomNPC/
├── manifest.json
├── Common/
│ ├── Icons/
│ │ └── ModelsGenerated/
│ │ └── Slime.png
│ └── NPC/
│ └── Beast/
│ └── Slime/
│ ├── Model/
│ │ ├── Model_Slime.blockymodel
│ │ └── Texture.png
│ └── Animations/
│ └── Default/
│ ├── Idle.blockyanim
│ ├── Walk.blockyanim
│ ├── Walk_Backward.blockyanim
│ ├── Run.blockyanim
│ ├── Attack.blockyanim
│ ├── Death.blockyanim
│ ├── Crouch.blockyanim
│ ├── Crouch_Walk.blockyanim
│ └── Crouch_Walk_Backward.blockyanim
├── Server/
│ ├── Models/
│ │ └── Beast/
│ │ └── Slime.json
│ ├── NPC/
│ │ └── Roles/
│ │ └── Slime.json
│ ├── Drops/
│ │ └── Drop_Slime.json
│ └── Languages/
│ ├── en-US/
│ │ └── server.lang
│ ├── es/
│ │ └── server.lang
│ └── pt-BR/
│ └── server.lang

All paths in Common/ must start with an allowed root: NPC/, Icons/, Items/, Blocks/, etc. The model and animations go under NPC/, and the spawn icon goes under Icons/.


Step 3: Create the manifest.json

{
"Group": "HytaleModdingManual",
"Name": "CreateACustomNPC",
"Version": "1.0.0",
"Description": "Implements the Create A NPC tutorial with a custom slime",
"Authors": [
{
"Name": "HytaleModdingManual"
}
],
"Dependencies": {},
"OptionalDependencies": {},
"IncludesAssetPack": true,
"TargetServerVersion": "2026.02.19-1a311a592"
}

Step 4: Define the Server Model

The Server Model is the bridge between the 3D assets in Common/ and the game engine. It tells Hytale where to find the model, texture, and every animation.

Create Server/Models/Beast/Slime.json:

{
"Model": "NPC/Beast/Slime/Model/Model_Slime.blockymodel",
"Texture": "NPC/Beast/Slime/Model/Texture.png",
"EyeHeight": 1.5,
"CrouchOffset": -0.15,
"HitBox": {
"Max": { "X": 0.8, "Y": 2.0, "Z": 0.8 },
"Min": { "X": -0.8, "Y": 0, "Z": -0.8 }
},
"Camera": {
"Pitch": {
"AngleRange": { "Max": 15, "Min": -15 },
"TargetNodes": ["Head"]
},
"Yaw": {
"AngleRange": { "Max": 15, "Min": -15 },
"TargetNodes": ["Head"]
}
},
"AnimationSets": {
"Walk": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Walk.blockyanim" }
]
},
"Attack": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Attack.blockyanim" }
]
},
"Idle": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Idle.blockyanim" }
]
},
"Death": {
"Animations": [
{
"Animation": "NPC/Beast/Slime/Animations/Default/Death.blockyanim",
"Loop": false
}
]
},
"Walk_Backward": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Walk_Backward.blockyanim" }
]
},
"Run": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Run.blockyanim" }
]
},
"Crouch": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Crouch.blockyanim" }
]
},
"Crouch_Walk": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Crouch_Walk.blockyanim" }
]
},
"Crouch_Walk_Backward": {
"Animations": [
{ "Animation": "NPC/Beast/Slime/Animations/Default/Crouch_Walk_Backward.blockyanim" }
]
}
},
"Icon": "Icons/ModelsGenerated/Slime.png",
"IconProperties": {
"Scale": 0.25,
"Rotation": [0, -45, 0],
"Translation": [0, -61]
}
}

Server Model Fields

FieldTypePurpose
ModelStringPath to .blockymodel file (relative to Common/)
TextureStringPath to texture .png (relative to Common/)
EyeHeightNumberVertical position of the NPC’s eyes in blocks — affects camera and line of sight
CrouchOffsetNumberHow far the model drops when crouching
HitBoxObjectBounding box for damage detection. Min/Max define the corners in blocks
CameraObjectHow the NPC’s head tracks targets. TargetNodes must match group names in the model
AnimationSetsObjectMaps game states to animation files. Each set can have multiple weighted animations
IconStringSpawn menu icon path (relative to Common/)
IconPropertiesObjectScale, rotation, and translation for the icon render

Step 5: Define the NPC Role

The NPC Role defines behavior and stats. Instead of writing AI from scratch, Hytale uses template inheritance — you pick a behavior template and override only what differs.

Create Server/NPC/Roles/Slime.json:

{
"Type": "Variant",
"Reference": "Template_Predator",
"Modify": {
"Appearance": "Slime",
"MaxHealth": 75,
"KnockbackScale": 0.5,
"IsMemory": true,
"MemoriesCategory": "Beast",
"NameTranslationKey": {
"Compute": "NameTranslationKey"
}
},
"Parameters": {
"NameTranslationKey": {
"Value": "server.npcRoles.Slime.name",
"Description": "Translation key for NPC name display"
}
}
}

How Template Inheritance Works

The "Type": "Variant" + "Reference": "Template_Predator" pattern means:

  1. Start with all fields from Template_Predator (hostile AI, chase logic, attack patterns, view range)
  2. Override only the fields listed in "Modify" (appearance, health, knockback, etc.)
  3. Everything else (decision making, combat logic, movement speeds) comes from the template

Available NPC Templates

TemplateBehaviorUse For
Template_PredatorHostile — chases and attacks players on sightEnemies, hostile creatures
Template_PreyPassive — flees when threatenedRabbits, deer, small animals
Template_NeutralNeutral — attacks only when provokedBears, wolves
Template_DomesticTame — follows owner, can be pennedFarm animals, pets
Template_Beasts_Passive_CritterPassive critter — wanders, fleesSquirrels, frogs, bugs

NPC Role Fields

FieldTypePurpose
AppearanceStringMust match the Server Model filename (without .json). This is how the engine links the Role to the Model
MaxHealthNumberHit points. Vanilla enemies range from 30 (Skeleton) to 500+ (bosses)
KnockbackScaleNumberResistance to knockback. 1.0 = normal, 0.5 = half knockback, 0 = immovable
IsMemoryBooleanWhether the NPC appears in the player’s Memories bestiary
MemoriesCategoryStringBestiary tab: Critter, Beast, Boss, Other
NameTranslationKeyComputeTranslation key for the name shown above the NPC’s head

The Compute Pattern

"NameTranslationKey": {
"Compute": "NameTranslationKey"
}

This tells the engine: “get the value of NameTranslationKey from the Parameters block.” The Parameters section then provides the actual value:

"Parameters": {
"NameTranslationKey": {
"Value": "server.npcRoles.Slime.name",
"Description": "Translation key for NPC name display"
}
}

This indirection exists because templates use Compute to read values that each variant defines differently. Every variant provides its own NameTranslationKey value, but the template’s logic for using it stays the same.


Step 6: Create the Drop Table

The drop table controls what loot falls when the NPC dies. For now, create an empty drop table so the Slime drops nothing:

Create Server/Drops/Drop_Slime.json:

{}

Then connect it to the Slime by adding DropList to the NPC Role. Open Server/NPC/Roles/Slime.json and add the highlighted line:

{
"Type": "Variant",
"Reference": "Template_Predator",
"Modify": {
"Appearance": "Slime",
"MaxHealth": 75,
"DropList": "Drop_Slime",
"KnockbackScale": 0.5,
"IsMemory": true,
"MemoriesCategory": "Beast",
"NameTranslationKey": {
"Compute": "NameTranslationKey"
}
},
"Parameters": {
"NameTranslationKey": {
"Value": "server.npcRoles.Slime.name",
"Description": "Translation key for NPC name display"
}
}
}

The "DropList": "Drop_Slime" tells the engine to look for Server/Drops/Drop_Slime.json when the NPC dies.


Step 7: Add Translations

Create a server.lang file for each language under Server/Languages/:

Server/Languages/en-US/server.lang

npcRoles.Slime.name = Slime

Server/Languages/es/server.lang

npcRoles.Slime.name = Slime

Server/Languages/pt-BR/server.lang

npcRoles.Slime.name = Slime

The translation key in the .lang file must match the Parameters.NameTranslationKey.Value in the NPC Role — but without the server. prefix. The engine adds the prefix automatically when resolving server-side language files.


Step 8: Package and Test

  1. Copy the CreateACustomNPC/ folder to %APPDATA%/Hytale/UserData/Mods/

  2. Launch Hytale and enter Creative Mode

  3. Check the log at %APPDATA%/Hytale/UserData/Logs/ for your mod loading:

    [Hytale] Loading assets from: ...\Mods\CreateACustomNPC\Server
    [AssetRegistryLoader] Loading assets from ...\Mods\CreateACustomNPC\Server
  4. Grant yourself operator permissions and spawn the Slime using chat commands:

    /op self
    /npc spawn Slime
  5. Verify:

Slime spawned in-game at night, glowing green with the Crystal Sword equipped

  • The model renders correctly with the slime texture
  • The NPC is hostile and chases you on sight
  • Attack, walk, run, and death animations play correctly
  • The name “Slime” appears above its head
  • Killing it drops one of: Crystal Slime Ore (50%), Health Potion (30%), or nothing (20%)

Common Pitfalls

ProblemCauseFix
Common Asset 'path' must be within the rootModel/texture path doesn’t start with NPC/, Icons/, etc.Move files under an allowed root directory in Common/
Common Asset 'path' doesn't existPath in JSON doesn’t match the actual file locationDouble-check every path in the Server Model — they’re relative to Common/
NPC spawns but is invisibleServer Model Model path is wrong or .blockymodel is corruptedRe-export from Blockbench, verify the path
NPC stands still, won’t attackWrong template or missing animationsVerify Reference is Template_Predator and all 9 animation sets exist
NPC slides without animationAnimation set name doesn’t match expected nameUse exact names: Walk, Run, Idle, Attack, Death, etc.
Name doesn’t show above NPCTranslation key mismatchEnsure .lang key matches Parameters.NameTranslationKey.Value minus the server. prefix
Death animation loopsMissing "Loop": false on Death animationAdd "Loop": false to the Death entry in AnimationSets
Drop table not workingDropList field missing from NPC RoleAdd "DropList": "Drop_Slime" to the Modify block (omitted here since Template_Predator handles it)

Next Steps