Create a Custom Entity
Similarly to custom items, we can also make custom entities with many similar mechanics to the vanilla entities in the game. These entities can be incredibly powerful allowing you to make your own animals which can be bred and tamed or an aggressive mob that attacks anything it sees.
Here we will make a ghost entity which will float, attack the player and drop our ectoplasm item on death.
Concept: Just like items, entities are made up of two parts:
- The visuals (model, texture, animations, name, sounds).
- The behaviors (movement, health, attacks, interactions).
Unlike items, entities typically require two main definition files: a server file (in the Behavior Pack) for behavior and a client file (in the Resource Pack) for visuals.
First, we will cover how to create an entity & define its behavior. Next, we will look at how to add the visuals.

Entity Behavior (Server File)
Like with items, we need a file to tell our entity how to behave, linking an identifier to components that define its actions and properties. This "server" entity file resides in the Behavior Pack (BP).
Create an entities
folder inside your BP folder if it doesn't exist. Inside BP/entities/
, create a new file. We'll call ours ghost.se.json
.
The .se
suffix stands for "server entity". While not required by the game, it's a recommended naming convention from the community Style Guide for clarity.
Here's the basic structure:
{ "format_version": "1.21.0", "minecraft:entity": { "description": { ... }, "components": { ... } } }
Similar to the item file, we have "format_version"
and "minecraft:entity"
. The key information goes inside "minecraft:entity"
.
Entities have slightly more in their "description"
block:
"description": { "identifier": "wiki:ghost", "is_summonable": true, "is_spawnable": true }
"identifier"
: Same purpose as items - uniquely identifies this entity (wiki:ghost
)."is_summonable"
: Allows the entity to be created using the/summon
command."is_spawnable"
: Allows the entity to be spawned using a spawn egg or potentially through world generation (with spawn rules).
We recommend keeping both is_summonable
and is_spawnable
as true
during development for easier testing.
Components
Entities have many more potential behaviors than items, so they use a wider variety of components. We'll group the components for our ghost into categories. For a deeper dive, see the Entity Components Guide.
Stat Components
These components define core attributes and properties common to most entities.
"minecraft:type_family": { "family": ["ghost", "monster"] }, "minecraft:health": { "value": 20, "max": 20 }, "minecraft:attack": { "damage": 3 }, "minecraft:movement": { "value": 0.2 }, "minecraft:collision_box": { "width": 0.8, "height": 1.8 }, "minecraft:loot": { "table": "loot_tables/entities/ghost.json" },
minecraft:type_family
: Assigns tags for grouping (e.g., "monster", "undead", "ghost"). Useful for targeting commands or behaviors.minecraft:health
: Sets current and maximum health.minecraft:attack
: Defines base attack damage.minecraft:movement
: Sets base movement speed (blocks per second).minecraft:collision_box
: Defines the physical size for collisions.minecraft:loot
: Points to a loot table file (which we'll create later) defining drops on death.
Movement Components
These components define *how* and *where* the entity can move.
"minecraft:physics": {}, "minecraft:jump.static": {}, "minecraft:movement.basic": {}, "minecraft:navigation.walk": { "can_walk": true, "avoid_sun": true, "can_pass_doors": true, "can_open_doors": true }
minecraft:physics
: Applies basic physics like gravity and collisions. (Note: Cannot be easily modified by events/component groups).minecraft:jump.static
: Allows the entity to jump up single blocks.minecraft:movement.basic
: Enables standard ground walking. Other options include.fly
,.swim
,.hover
. We use basic movement but will make it *look* like floating using the model/animations later.minecraft:navigation.walk
: Defines pathfinding capabilities for walking entities. The properties here allow it to pathfind on the ground, avoid sun, and interact with doors. Other navigation types exist for flying/swimming.
Behavior Components
These components define the entity's AI - *what* it decides to do and *when*.
We want our ghost to wander idly, look around, notice and target the player, and attack. We use these behavior components:
"minecraft:behavior.random_stroll": {...}, "minecraft:behavior.random_look_around": {...}, "minecraft:behavior.look_at_player": {...}, "minecraft:behavior.hurt_by_target": {...}, "minecraft:behavior.nearest_attackable_target": {...}, "minecraft:behavior.delayed_attack": {...}
minecraft:behavior.random_stroll
: Makes the entity wander randomly.minecraft:behavior.random_look_around
/minecraft:behavior.look_at_player
: Adds idle looking behavior.minecraft:behavior.hurt_by_target
: Makes the entity target whatever attacked it.minecraft:behavior.nearest_attackable_target
: Makes the entity proactively target specific nearby entities (like players).minecraft:behavior.delayed_attack
: Defines a melee attack with a wind-up/delay.
Each behavior has settings to fine-tune its actions, including priority:
"minecraft:behavior.random_stroll": { "priority": 6, "speed_multiplier": 1 }, "minecraft:behavior.random_look_around": { "priority": 7 }, "minecraft:behavior.look_at_player": { "priority": 7, "look_distance": 6, "probability": 0.02 }, "minecraft:behavior.hurt_by_target": { "priority": 1 }, "minecraft:behavior.nearest_attackable_target": { "priority": 2, "within_radius": 25, "reselect_targets": true, "entity_types": [ { "filters": { "any_of": [ { "test": "is_family", "subject": "other", "value": "player" } ] }, "max_dist": 35 } ] }, "minecraft:behavior.delayed_attack": { "priority": 0, "attack_once": false, "track_target": true, "require_complete_path": false, "random_stop_interval": 0, "reach_multiplier": 1.5, "speed_multiplier": 1, "attack_duration": 0.75, "hit_delay_pct": 0.5 }
Priority
The "priority"
field (lower number = higher priority) is crucial. When an entity decides what to do, it checks behaviors from lowest priority number upwards and performs the *first* one whose conditions are met.
Priority Matters! If a low-priority behavior (like wandering) has its conditions met and is checked before a high-priority behavior (like attacking), the entity might never attack! Ensure critical actions (attacking, fleeing) have lower priority numbers than idle actions (wandering, looking around).
Full Entity Server File
Combining all these components gives us our complete behavior definition file.
Show Full ghost.se.json
{ "format_version": "1.21.0", "minecraft:entity": { "description": { "identifier": "wiki:ghost", "is_summonable": true, "is_spawnable": true }, "components": { "minecraft:type_family": { "family": ["ghost", "monster"] }, "minecraft:health": { "value": 20, "max": 20 }, "minecraft:attack": { "damage": 3 }, "minecraft:movement": { "value": 0.2 }, "minecraft:collision_box": { "width": 0.8, "height": 1.8 }, "minecraft:loot": { "table": "loot_tables/entities/ghost.json" }, "minecraft:physics": {}, "minecraft:jump.static": {}, "minecraft:movement.basic": {}, "minecraft:navigation.walk": { "can_walk": true, "avoid_sun": true, "can_pass_doors": true, "can_open_doors": true }, "minecraft:behavior.random_stroll": { "priority": 6, "speed_multiplier": 1 }, "minecraft:behavior.random_look_around": { "priority": 7 }, "minecraft:behavior.look_at_player": { "priority": 7, "look_distance": 6, "probability": 0.02 }, "minecraft:behavior.hurt_by_target": { "priority": 1 }, "minecraft:behavior.nearest_attackable_target": { "priority": 2, "within_radius": 25, "reselect_targets": true, "entity_types": [ { "filters": { "any_of": [ { "test": "is_family", "subject": "other", "value": "player" } ] }, "max_dist": 35 } ] }, "minecraft:behavior.delayed_attack": { "priority": 0, "attack_once": false, "track_target": true, "require_complete_path": false, "random_stop_interval": 0, "reach_multiplier": 1.5, "speed_multiplier": 1, "attack_duration": 0.75, "hit_delay_pct": 0.5 } } } }
Advanced States & Events: More complex entities use events and component groups to change behavior dynamically (e.g., a wolf switching from wild to tamed state). We're keeping it simple for now.
Test Behavior: If you load the world now and /summon wiki:ghost
, you should see a shadow on the ground. The entity exists and *should* behave as defined (wander, target, attack you), but it's invisible because we haven't defined its visuals yet.
Next, we'll create the client-side resources to make our ghost visible.
Entity Resource (Client File)
Applying visuals to an entity is more involved than for items. We need to define its shape (model/geometry), skin (texture), and how it moves (animations). These are all linked together in the entity's client file within the Resource Pack (RP).
Create an entity
folder inside your RP folder if it doesn't exist. Inside RP/entity/
, create a file named ghost.ce.json
(.ce
for client entity).
Blockbench: Creating models, textures, and animations is typically done using a dedicated 3D editor like Blockbench, which can export the necessary .json
and .png
files. We'll assume you have these files for the tutorial, but the next guide section will cover using Blockbench.
Model (Geometry)
The entity's shape or "geometry" defines the cubes ("bones") that make up its visual form. This is stored in a .geo.json
file.
Place your geometry file (e.g., ghost.geo.json
) inside RP/models/entity/
. Create these folders if needed.
Show Example ghost.geo.json
{ "format_version": "1.12.0", "minecraft:geometry": [ { "description": { "identifier": "geometry.ghost", "texture_width": 64, "texture_height": 64, "visible_bounds_width": 3, "visible_bounds_height": 3.5, "visible_bounds_offset": [0, 1.25, 0] }, "bones": [ { "name": "root", "pivot": [0, 3, 0] }, { "name": "body", "parent": "root", "pivot": [0, 4.625, 0], "cubes": [ { "origin": [-4, 3, -4], "size": [8, 13, 8], "uv": [0, 20] } ] }, { "name": "leftArm", "parent": "body", "pivot": [4.6, 15.5, 0.5], "cubes": [ { "origin": [4.1, 7, -1], "size": [3, 9, 3], "uv": [32, 32] } ] }, { "name": "rightArm", "parent": "body", "pivot": [-4.5, 15.5, 0.5], "cubes": [ { "origin": [-7.1, 7, -1], "size": [3, 9, 3], "uv": [32, 20] } ] }, { "name": "head", "parent": "body", "pivot": [0, 16, 0], "cubes": [ { "origin": [-5, 16, -5], "size": [10, 10, 10], "uv": [0, 0] } ] } ] } ] }
The key piece of information we need from this file for later is the geometry's identifier, found under description.identifier
(e.g., geometry.ghost
).
Texture
The texture is a .png
image file that wraps around the model, giving it color and detail.

Place your texture file (e.g., ghost.png
) inside RP/textures/entity/
.
Unlike items, we don't use item_texture.json
for entity textures. Instead, we'll define a shortname reference directly in the entity's client file later.
Animations
Animations define how the entity's bones (cubes) move over time (e.g., walking, attacking). These are stored in .a.json
files (or .animation.json
).
Place your animation file(s) (e.g., ghost.a.json
) inside RP/animations/
.
Show Example ghost.a.json (Multiple Animations)
{ "format_version": "1.8.0", "animations": { "animation.ghost.idle": { "loop": true, "animation_length": 3, "bones": { "body": { "rotation": { "0.0": [10, 0, 0], "3.0": [10, 0, 0] }, "position": { "0.0": [0, 0, 0], "1.5": [0, 1, 0], "3.0": [0, 0, 0] } }, "leftArm": { "rotation": { "0.0": [-10, 0, 0], "1.5": [-5, 0, 0], "3.0": [-10, 0, 0] } }, "rightArm": { "rotation": { "0.0": [-10, 0, 0], "1.5": [-5, 0, 0], "3.0": [-10, 0, 0] } }, "head": { "rotation": { "0.0": [-7.5, 0, 0], "1.5": [-2.5, 0, 0], "3.0": [-7.5, 0, 0] } } } }, "animation.ghost.attack": { "animation_length": 0.75, "bones": { "body": { "rotation": { "0.0": [10, 0, 0], "0.2917": [10, 15, 0], "0.5": [22.5, -12.5, 0], "0.75": [10, 0, 0] }, "position": { "0.0": [0, 0, 0], "0.2917": [0, 0, 3], "0.5": [0, 0, -3], "0.75": [0, 0, 0] } }, "leftArm": { "rotation": { "0.0": [-10, 0, 0], "0.75": [-10, 0, 0] } }, "rightArm": { "rotation": { "0.0": [-10, 0, 0], "0.2083": [-10, 0, 0], "0.2917": [-10, 62.5, 117.5], "0.5": [-80, -17.5, 22.5], "0.75": [-10, 0, 0] } }, "head": { "rotation": { "0.0": [-7.5, 0, 0], "0.75": [-7.5, 0, 0] } } } }, "animation.ghost.move": { "loop": true, "animation_length": 1, "bones": { "body": { "rotation": { "0.0": [15, 0, 0], "0.25": [15, -2.5, 0], "0.5": [15, 0, 0], "0.75": [15, 2.5, 0], "1.0": [15, 0, 0] }, "position": [0, 0, 0] }, "leftArm": { "rotation": { "0.0": [15, 0, 0], "0.5": [20, 0, 0], "1.0": [15, 0, 0] } }, "rightArm": { "rotation": { "0.0": [15, 0, 0], "0.5": [20, 0, 0], "1.0": [15, 0, 0] } }, "head": { "rotation": { "0.0": [-12.5, 0, 0], "0.5": [-15, 0, 0], "1.0": [-12.5, 0, 0] } } } } } }
An animation file can contain multiple animations. We need the identifier for each animation (e.g., animation.ghost.idle
, animation.ghost.attack
, animation.ghost.move
) to reference later.
While you *can* have multiple animation files per entity, it's often cleaner to group all animations for one entity into a single file (like ghost.a.json
) for easier management.
Animation Controller
An animation controller (.ac.json
or .animation_controller.json
) determines *when* specific animations should play based on the entity's state or actions. It uses states, transitions, and queries.
Place your animation controller file(s) (e.g., ghost.ac.json
) inside RP/animation_controllers/
.
Show Example ghost.ac.json (Walk & Attack Controllers)
{ "format_version": "1.12.0", "animation_controllers": { "controller.animation.ghost.attack": { "states": { "default": { "transitions": [ { "attacking": "q.is_delayed_attacking" } ] }, "attacking": { "blend_transition": 0.2, "animations": ["attack"], "transitions": [ { "default": "!q.is_delayed_attacking" } ] } } }, "controller.animation.ghost.walk": { "initial_state": "standing", "states": { "standing": { "blend_transition": 0.2, "animations": ["idle"], "transitions": [ { "moving": "q.modified_move_speed > 0.1" } ] }, "moving": { "blend_transition": 0.2, "animations": ["move"], "transitions": [ { "standing": "q.modified_move_speed < 0.1" } ] } } } } }
- States: Define periods of behavior (e.g., "standing", "moving", "attacking").
- Transitions: Define conditions (using Molang Queries like
q.is_delayed_attacking
orq.modified_move_speed > 0.1
) to move between states. - Animations: Specify which animation shortnames (defined later in the client entity file) play during each state.
initial_state
: Specifies the starting state.blend_transition
: Smoothly blends between animations when changing states.
We need the identifier for each controller (e.g., controller.animation.ghost.attack
, controller.animation.ghost.walk
) for the client entity file.
Learn more about Animation Controllers here.
Entity Client File (ghost.ce.json
)
Now we assemble references to all these visual resources in our RP/entity/ghost.ce.json
file.
Start with the basic structure and identifier:
{ "format_version": "1.10.0", "minecraft:client_entity": { "description": { "identifier": "wiki:ghost" } } }
Inside the "description"
block, we define shortnames for materials, textures, and geometry:
{ "format_version": "1.10.0", "minecraft:client_entity": { "description": { "identifier": "wiki:ghost", "materials": { "default": "entity_alphatest" }, "textures": { "default": "textures/entity/ghost" }, "geometry": { "default": "geometry.ghost" } } } }
"materials"
: Defines rendering materials."default": "entity_alphatest"
uses a built-in material suitable for textures with transparency. Custom materials are advanced. Learn more here."textures"
: Maps a shortname ("default"
) to the texture path (relative to RP, no extension)."geometry"
: Maps a shortname ("default"
) to the geometry identifier (from the.geo.json
file).
Render Controller
A render controller tells the game *which* geometry, materials, and textures (using their shortnames) to actually draw. These are defined in .rc.json
files (or .render_controller.json
) in RP/render_controllers/
.
Show Example ghost.rc.json
{ "format_version": "1.10.0", "render_controllers": { "controller.render.ghost": { "geometry": "geometry.default", "materials": [ { "*": "material.default" } ], "textures": ["texture.default"] } } }
This simple controller (identifier: controller.render.ghost
) tells the game to use the resources assigned to the "default"
shortnames we defined above. More complex controllers can swap textures or show/hide parts of the model. Learn more here.
If you keep shortnames like "default" consistent across entities with similar rendering needs, you can often reuse the same render controller file.
Add a reference to this render controller in your ghost.ce.json
description:
"render_controllers": ["controller.render.ghost"]
At this point, your entity should be visible in-game!
Show ghost.ce.json (so far)
{ "format_version": "1.10.0", "minecraft:client_entity": { "description": { "identifier": "wiki:ghost", "materials": { "default": "entity_alphatest" }, "textures": { "default": "textures/entity/ghost" }, "geometry": { "default": "geometry.ghost" }, "render_controllers": ["controller.render.ghost"] } } }
Scripts (for Animations)
To make the animations play, we first define shortnames for them and their controllers within the ghost.ce.json
description:
"animations": { "walk_controller": "controller.animation.ghost.walk", "attack_controller": "controller.animation.ghost.attack", "attack": "animation.ghost.attack", "idle": "animation.ghost.idle", "move": "animation.ghost.move" }
Note how the values match the identifiers from the .a.json
and .ac.json
files. The keys ("walk_controller"
, "attack"
, etc.) are the shortnames we use elsewhere (like in the animation controllers).
Then, we use the "scripts"
block to tell the entity *when* to run the animation controllers:
"scripts": { "animate": [ "walk_controller", "attack_controller" ] }
The "animate"
script runs every game tick, executing the listed animation controllers (which then decide which specific animation plays based on their internal states and transitions).
Test Animations! Reload the world. Your ghost should now idle, move, and attack with animations!
Spawn Egg
Finally, we can define how the entity's spawn egg looks in the Creative inventory. Add the "spawn_egg"
key to the ghost.ce.json
description:
"spawn_egg": { "overlay_color": "#bdd1d1", "base_color": "#9fb3b3" }
This generates a standard two-tone egg using the provided hex color codes.
Alternatively, if you want a completely custom spawn egg texture (like vanilla ones), you can define it like an item texture in item_texture.json
and reference its shortname here:
"spawn_egg": { "texture": "texture_shortname" }
With that, the client entity file is complete!
Show Full ghost.ce.json
{ "format_version": "1.10.0", "minecraft:client_entity": { "description": { "identifier": "wiki:ghost", "materials": { "default": "entity_alphatest" }, "textures": { "default": "textures/entity/ghost" }, "geometry": { "default": "geometry.ghost" }, "scripts": { "animate": ["walk_controller", "attack_controller"] }, "animations": { "walk_controller": "controller.animation.ghost.walk", "attack_controller": "controller.animation.ghost.attack", "attack": "animation.ghost.attack", "idle": "animation.ghost.idle", "move": "animation.ghost.move" }, "spawn_egg": { "overlay_color": "#bdd1d1", "base_color": "#9fb3b3" }, "render_controllers": ["controller.render.ghost"] } } }
Entity Name
The final step is giving our entity and its spawn egg proper display names. Add these lines to **both** RP/texts/en_US.lang
and BP/texts/en_US.lang
:
entity.wiki:ghost.name=Ghost item.spawn_egg.entity.wiki:ghost.name=Ghost Spawn Egg
Make sure the keys match the entity identifier (entity.wiki:ghost.name
) and the spawn egg item name (item.spawn_egg.entity.wiki:ghost.name
).
Overview
Done! Your entity should now show up in Minecraft, complete with all behaviors and visuals, including animations! You should be able to summon your entity using /summon wiki:ghost
or by finding the "Ghost Spawn Egg" in the creative menu.
Your final folder structure should look something like this:
Project File Structure Update
- RP/
- animations/ (New)
- ghost.a.json (New)
- animation_controllers/ (New)
- ghost.ac.json (New)
- entity/ (New)
- ghost.ce.json (New)
- models/ (New)
- entity/ (New)
- ghost.geo.json (New)
- render_controllers/ (New)
- ghost.rc.json (New)
- textures/
- entity/ (New)
- ghost.png (New)
- items/
- ectoplasm.png
- item_texture.json
- texts/
- en_US.lang (Edited)
- ... (manifest.json, pack_icon.png etc.)
- BP/
- entities/ (New)
- ghost.se.json (New)
- items/
- ectoplasm.json
- texts/
- en_US.lang (Edited)
- ... (manifest.json, pack_icon.png etc.)
Full Entity Code Files:
Full ghost.se.json (Behavior)
{ "format_version": "1.21.0", "minecraft:entity": { "description": { "identifier": "wiki:ghost", "is_summonable": true, "is_spawnable": true }, "components": { "minecraft:type_family": { "family": ["ghost", "monster"] }, "minecraft:health": { "value": 20, "max": 20 }, "minecraft:attack": { "damage": 3 }, "minecraft:movement": { "value": 0.2 }, "minecraft:collision_box": { "width": 0.8, "height": 1.8 }, "minecraft:loot": { "table": "loot_tables/entities/ghost.json" }, "minecraft:physics": {}, "minecraft:jump.static": {}, "minecraft:movement.basic": {}, "minecraft:navigation.walk": { "can_walk": true, "avoid_sun": true, "can_pass_doors": true, "can_open_doors": true }, "minecraft:behavior.random_stroll": { "priority": 6, "speed_multiplier": 1 }, "minecraft:behavior.random_look_around": { "priority": 7 }, "minecraft:behavior.look_at_player": { "priority": 7, "look_distance": 6, "probability": 0.02 }, "minecraft:behavior.hurt_by_target": { "priority": 1 }, "minecraft:behavior.nearest_attackable_target": { "priority": 2, "within_radius": 25, "reselect_targets": true, "entity_types": [ { "filters": { "any_of": [ { "test": "is_family", "subject": "other", "value": "player" } ] }, "max_dist": 35 } ] }, "minecraft:behavior.delayed_attack": { "priority": 0, "attack_once": false, "track_target": true, "require_complete_path": false, "random_stop_interval": 0, "reach_multiplier": 1.5, "speed_multiplier": 1, "attack_duration": 0.75, "hit_delay_pct": 0.5 } } } }
Full ghost.ce.json (Client)
{ "format_version": "1.10.0", "minecraft:client_entity": { "description": { "identifier": "wiki:ghost", "materials": { "default": "entity_alphatest" }, "textures": { "default": "textures/entity/ghost" }, "geometry": { "default": "geometry.ghost" }, "scripts": { "animate": ["walk_controller", "attack_controller"] }, "animations": { "walk_controller": "controller.animation.ghost.walk", "attack_controller": "controller.animation.ghost.attack", "attack": "animation.ghost.attack", "idle": "animation.ghost.idle", "move": "animation.ghost.move" }, "spawn_egg": { "overlay_color": "#bdd1d1", "base_color": "#9fb3b3" }, "render_controllers": ["controller.render.ghost"] } } }
Full ghost.geo.json (Model)
{ "format_version": "1.12.0", "minecraft:geometry": [ { "description": { "identifier": "geometry.ghost", "texture_width": 64, "texture_height": 64, "visible_bounds_width": 3, "visible_bounds_height": 3.5, "visible_bounds_offset": [0, 1.25, 0] }, "bones": [ { "name": "root", "pivot": [0, 3, 0] }, { "name": "body", "parent": "root", "pivot": [0, 4.625, 0], "cubes": [ { "origin": [-4, 3, -4], "size": [8, 13, 8], "uv": [0, 20] } ] }, { "name": "leftArm", "parent": "body", "pivot": [4.6, 15.5, 0.5], "cubes": [ { "origin": [4.1, 7, -1], "size": [3, 9, 3], "uv": [32, 32] } ] }, { "name": "rightArm", "parent": "body", "pivot": [-4.5, 15.5, 0.5], "cubes": [ { "origin": [-7.1, 7, -1], "size": [3, 9, 3], "uv": [32, 20] } ] }, { "name": "head", "parent": "body", "pivot": [0, 16, 0], "cubes": [ { "origin": [-5, 16, -5], "size": [10, 10, 10], "uv": [0, 0] } ] } ] } ] }
Full ghost.a.json (Animations)
{ "format_version": "1.8.0", "animations": { "animation.ghost.idle": { "loop": true, "animation_length": 3, "bones": { "body": { "rotation": { "0.0": [10, 0, 0], "3.0": [10, 0, 0] }, "position": { "0.0": [0, 0, 0], "1.5": [0, 1, 0], "3.0": [0, 0, 0] } }, "leftArm": { "rotation": { "0.0": [-10, 0, 0], "1.5": [-5, 0, 0], "3.0": [-10, 0, 0] } }, "rightArm": { "rotation": { "0.0": [-10, 0, 0], "1.5": [-5, 0, 0], "3.0": [-10, 0, 0] } }, "head": { "rotation": { "0.0": [-7.5, 0, 0], "1.5": [-2.5, 0, 0], "3.0": [-7.5, 0, 0] } } } }, "animation.ghost.attack": { "animation_length": 0.75, "bones": { "body": { "rotation": { "0.0": [10, 0, 0], "0.2917": [10, 15, 0], "0.5": [22.5, -12.5, 0], "0.75": [10, 0, 0] }, "position": { "0.0": [0, 0, 0], "0.2917": [0, 0, 3], "0.5": [0, 0, -3], "0.75": [0, 0, 0] } }, "leftArm": { "rotation": { "0.0": [-10, 0, 0], "0.75": [-10, 0, 0] } }, "rightArm": { "rotation": { "0.0": [-10, 0, 0], "0.2083": [-10, 0, 0], "0.2917": [-10, 62.5, 117.5], "0.5": [-80, -17.5, 22.5], "0.75": [-10, 0, 0] } }, "head": { "rotation": { "0.0": [-7.5, 0, 0], "0.75": [-7.5, 0, 0] } } } }, "animation.ghost.move": { "loop": true, "animation_length": 1, "bones": { "body": { "rotation": { "0.0": [15, 0, 0], "0.25": [15, -2.5, 0], "0.5": [15, 0, 0], "0.75": [15, 2.5, 0], "1.0": [15, 0, 0] }, "position": [0, 0, 0] }, "leftArm": { "rotation": { "0.0": [15, 0, 0], "0.5": [20, 0, 0], "1.0": [15, 0, 0] } }, "rightArm": { "rotation": { "0.0": [15, 0, 0], "0.5": [20, 0, 0], "1.0": [15, 0, 0] } }, "head": { "rotation": { "0.0": [-12.5, 0, 0], "0.5": [-15, 0, 0], "1.0": [-12.5, 0, 0] } } } } } }
Full ghost.ac.json (Animation Controllers)
{ "format_version": "1.12.0", "animation_controllers": { "controller.animation.ghost.attack": { "states": { "default": { "transitions": [ { "attacking": "q.is_delayed_attacking" } ] }, "attacking": { "blend_transition": 0.2, "animations": ["attack"], "transitions": [ { "default": "!q.is_delayed_attacking" } ] } } }, "controller.animation.ghost.walk": { "initial_state": "standing", "states": { "standing": { "blend_transition": 0.2, "animations": ["idle"], "transitions": [ { "moving": "q.modified_move_speed > 0.1" } ] }, "moving": { "blend_transition": 0.2, "animations": ["move"], "transitions": [ { "standing": "q.modified_move_speed < 0.1" } ] } } } } }
Full ghost.rc.json (Render Controller)
{ "format_version": "1.10.0", "render_controllers": { "controller.render.ghost": { "geometry": "geometry.default", "materials": [ { "*": "material.default" } ], "textures": ["texture.default"] } } }
If you encounter issues, review the Troubleshooting page or compare your files with the example entity files.
Your Progress So Far
- Setup your pack structure
- Create a custom item (Ectoplasm)
- Create a custom entity (Ghost)
- Format behavior (
.se.json
) and resource (.ce.json
) files for an entity - Define entity components for stats, movement, and AI
- Link entity model, texture, animations, and controllers
- Set an entity's display name and spawn egg
- Create the entity's loot, spawn rules, and a custom recipe
Next Steps
Your ghost entity now exists and looks the part! Next, we'll define how it interacts with the world by creating loot tables (what it drops), spawn rules (where it appears), and maybe even a custom recipe involving its drops.
Next: Blockbench Guide