add-custom-mob

Use when adding new mobs or entities. Covers entity class, model, renderer, client registration, spawn config, loot tables.

181 stars

Best use case

add-custom-mob is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when adding new mobs or entities. Covers entity class, model, renderer, client registration, spawn config, loot tables.

Teams using add-custom-mob should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/add-custom-mob/SKILL.md --create-dirs "https://raw.githubusercontent.com/majiayu000/claude-skill-registry/main/skills/data/add-custom-mob/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/add-custom-mob/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How add-custom-mob Compares

Feature / Agentadd-custom-mobStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when adding new mobs or entities. Covers entity class, model, renderer, client registration, spawn config, loot tables.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Add Custom Mob to ChronoDawn

**Purpose**: Complete guide for adding a new mob entity to ChronoDawn with full multi-version and multi-loader support.

---

## Quick Checklist

When adding a new mob, complete ALL of the following:

### Java Classes (per module: 1.20.1, 1.21.1, 1.21.2, 1.21.4)
*Note: 1.21.3 uses 1.21.2 modules (no separate directory)*
- [ ] Entity class (`entities/mobs/MobNameEntity.java`)
- [ ] Model class (`client/model/MobNameModel.java`)
- [ ] Renderer class (`client/renderer/mobs/MobNameRenderer.java`)
- [ ] RenderState class (`client/renderer/mobs/MobNameRenderState.java`) - **1.21.2 and 1.21.4 only**

### Registration (per version)
- [ ] `ModEntities.java` - Entity type registration
- [ ] `ModItems.java` - Spawn egg registration (see [custom-mob-spawn-egg skill](#spawn-egg))

### Platform-Specific Registration (CRITICAL - Common source of crashes)
- [ ] **Fabric** `ChronoDawnFabric.java` - Attribute & spawn placement registration
- [ ] **Fabric** `ChronoDawnClientFabric.java` - Import statements for Model and Renderer
- [ ] **Fabric** `ChronoDawnClientFabric.java` - Model layer registration (`EntityModelLayerRegistry.registerModelLayer`)
- [ ] **Fabric** `ChronoDawnClientFabric.java` - Renderer registration (`EntityRendererRegistry.register`)
- [ ] **NeoForge** `ChronoDawnNeoForge.java` - Attribute & spawn placement registration
- [ ] **NeoForge** `ChronoDawnClientNeoForge.java` - Model layer & renderer registration
- [ ] **NeoForge** `ChronoDawnClientNeoForge.java` - Spawn egg color handler

### Resource Files (per version)
- [ ] Texture file (`textures/entity/mobs/mob_name.png`)
- [ ] Loot table (`loot_table/entities/mob_name.json` or `loot_tables/` for 1.20.1)
- [ ] Spawn egg model (`models/item/mob_name_spawn_egg.json`)
- [ ] Spawn egg item definition (`items/mob_name_spawn_egg.json`) - **1.21.4 only**
- [ ] Language files (`lang/en_us.json`, `lang/ja_jp.json`)
- [ ] Biome spawn configuration (if replacing vanilla mob)

---

## Vanilla Mob Reference Parameters

When creating a mob based on a vanilla mob, use these reference values:

| Base Mob | sized(w, h) | Health | Attack | Speed | Other Attributes |
|----------|-------------|--------|--------|-------|------------------|
| Iron Golem | 1.4f, 2.7f | 100 | 7.5-21 | 0.25 | Knockback Resistance 1.0 |
| Enderman | 0.6f, 2.9f | 40 | 7 | 0.3 | Follow Range 64 |
| Zombie | 0.6f, 1.95f | 20 | 3 | 0.23 | - |
| Spider | 1.4f, 0.9f | 16 | 2 | 0.3 | Wall climbing |
| Skeleton | 0.6f, 1.99f | 20 | - | 0.25 | Bow attack |
| Chicken | 0.4f, 0.7f | 4 | - | 0.25 | - |
| Pig | 0.9f, 0.9f | 10 | - | 0.25 | - |
| Rabbit | 0.4f, 0.5f | 3 | - | 0.3 | - |

**Tip**: For hostile versions of friendly mobs, consider increasing Health and adding Attack damage.

---

## 1. Entity Class

Create in `common-{version}/src/main/java/com/chronodawn/entities/mobs/`

### 1.21.2 Template

```java
package com.chronodawn.entities.mobs;

import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.level.Level;

public class MobNameEntity extends Monster {

    public MobNameEntity(EntityType<? extends MobNameEntity> entityType, Level level) {
        super(entityType, level);
    }

    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, 20.0D)
                .add(Attributes.ATTACK_DAMAGE, 3.0D)
                .add(Attributes.MOVEMENT_SPEED, 0.3D)
                .add(Attributes.FOLLOW_RANGE, 35.0D);
    }

    @Override
    protected void registerGoals() {
        // Add AI goals here
    }

    // 1.21.2: Use EntitySpawnReason, SynchedEntityData.Builder
    // Example for synched data:
    // @Override
    // protected void defineSynchedData(SynchedEntityData.Builder builder) {
    //     super.defineSynchedData(builder);
    //     builder.define(DATA_FLAGS, (byte)0);
    // }
}
```

### 1.21.1 Template

Key differences from 1.21.2:
- Use `MobSpawnType` instead of `EntitySpawnReason`
- `SynchedEntityData.Builder` pattern same as 1.21.2

### 1.20.1 Template

Key differences:
- Use `MobSpawnType` instead of `EntitySpawnReason`
- `defineSynchedData()` has no parameters, use `this.entityData.define()` directly

```java
@Override
protected void defineSynchedData() {
    super.defineSynchedData();
    this.entityData.define(DATA_FLAGS, (byte)0);
}
```

---

## 2. Model Class

Create in `common-{version}/src/main/java/com/chronodawn/client/model/`

### 1.21.2 Template (RenderState pattern)

```java
package com.chronodawn.client.model;

import com.chronodawn.client.renderer.mobs.MobNameRenderState;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;

public class MobNameModel extends EntityModel<MobNameRenderState> {

    private final ModelPart body;

    public MobNameModel(ModelPart root) {
        super(root);
        this.body = root.getChild("body");
    }

    public static LayerDefinition createBodyLayer() {
        MeshDefinition meshdefinition = new MeshDefinition();
        PartDefinition partdefinition = meshdefinition.getRoot();

        partdefinition.addOrReplaceChild("body",
            CubeListBuilder.create()
                .texOffs(0, 0)
                .addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F),
            PartPose.offset(0.0F, 24.0F, 0.0F));

        return LayerDefinition.create(meshdefinition, 64, 32);
    }

    @Override
    public void setupAnim(MobNameRenderState state) {
        super.setupAnim(state);
        // Animation logic using state.walkAnimationPos, state.walkAnimationSpeed
    }
}
```

### 1.21.1 / 1.20.1 Template (Entity pattern)

```java
package com.chronodawn.client.model;

import com.chronodawn.entities.mobs.MobNameEntity;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.geom.ModelPart;
// ... other imports

public class MobNameModel extends EntityModel<MobNameEntity> {

    public MobNameModel(ModelPart root) {
        // 1.21.1/1.20.1: No super(root) call
        this.body = root.getChild("body");
    }

    // Same createBodyLayer() as 1.21.2

    @Override
    public void setupAnim(MobNameEntity entity, float limbSwing, float limbSwingAmount,
                          float ageInTicks, float netHeadYaw, float headPitch) {
        // Animation logic
    }

    // 1.21.1: renderToBuffer with int color
    @Override
    public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer,
                               int packedLight, int packedOverlay, int color) {
        body.render(poseStack, buffer, packedLight, packedOverlay, color);
    }

    // 1.20.1: renderToBuffer with float RGBA
    @Override
    public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer,
                               int packedLight, int packedOverlay,
                               float red, float green, float blue, float alpha) {
        body.render(poseStack, buffer, packedLight, packedOverlay, red, green, blue, alpha);
    }
}
```

---

## 3. Renderer Class

Create in `common-{version}/src/main/java/com/chronodawn/client/renderer/mobs/`

### 1.21.2 Template

```java
package com.chronodawn.client.renderer.mobs;

import com.chronodawn.ChronoDawn;
import com.chronodawn.client.model.MobNameModel;
import com.chronodawn.entities.mobs.MobNameEntity;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.resources.ResourceLocation;

public class MobNameRenderer extends MobRenderer<MobNameEntity, MobNameRenderState, MobNameModel> {

    private static final ResourceLocation TEXTURE =
        ResourceLocation.fromNamespaceAndPath(ChronoDawn.MOD_ID, "textures/entity/mobs/mob_name.png");

    public MobNameRenderer(EntityRendererProvider.Context context) {
        super(context, new MobNameModel(context.bakeLayer(MobNameModel.LAYER_LOCATION)), 0.5f);
    }

    @Override
    public ResourceLocation getTextureLocation(MobNameRenderState state) {
        return TEXTURE;
    }

    @Override
    public MobNameRenderState createRenderState() {
        return new MobNameRenderState();
    }
}
```

### 1.21.1 / 1.20.1 Template

```java
// MobRenderer has 2 type parameters: <Entity, Model>
public class MobNameRenderer extends MobRenderer<MobNameEntity, MobNameModel> {

    @Override
    public ResourceLocation getTextureLocation(MobNameEntity entity) {
        return TEXTURE;
    }

    // No createRenderState() method needed
}
```

---

## 4. RenderState Class (1.21.2 and 1.21.4)

Create in `common-1.21.2/` and `common-1.21.4/` under `src/main/java/com/chronodawn/client/renderer/mobs/`

```java
package com.chronodawn.client.renderer.mobs;

import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;

public class MobNameRenderState extends LivingEntityRenderState {
    // Add custom state fields if needed for animations
}
```

---

## 5. Entity Registration (ModEntities.java)

```java
public static final RegistrySupplier<EntityType<MobNameEntity>> MOB_NAME = ENTITIES.register(
    "mob_name",
    () -> EntityType.Builder.of(MobNameEntity::new, MobCategory.MONSTER)
        .sized(0.6f, 1.8f)  // width, height
        .clientTrackingRange(8)
        .updateInterval(3)
        .build(ResourceKey.create(Registries.ENTITY_TYPE,
            CompatResourceLocation.create(ChronoDawn.MOD_ID, "mob_name")))
);
```

**1.20.1 difference**: Use `.build("mob_name")` instead of `.build(ResourceKey...)`

---

## 6. Platform-Specific Registration

### Fabric - ChronoDawnFabric.java

```java
// Attributes
FabricDefaultAttributeRegistry.register(ModEntities.MOB_NAME.get(), MobNameEntity.createAttributes());

// Spawn placement (1.21.1/1.21.2)
SpawnPlacements.register(
    ModEntities.MOB_NAME.get(),
    SpawnPlacementTypes.ON_GROUND,
    Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
    Monster::checkMonsterSpawnRules
);

// Spawn placement (1.20.1)
SpawnPlacements.register(
    ModEntities.MOB_NAME.get(),
    SpawnPlacements.Type.ON_GROUND,  // Note: different enum
    Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
    Monster::checkMonsterSpawnRules
);
```

### Fabric - ChronoDawnClientFabric.java

**IMPORTANT**: Don't forget to add imports at the top of the file!

```java
// Required imports (add to import section)
import com.chronodawn.client.model.MobNameModel;
import com.chronodawn.client.renderer.mobs.MobNameRenderer;

// In registerEntityModelLayers() method - Model layer registration
EntityModelLayerRegistry.registerModelLayer(MobNameModel.LAYER_LOCATION, MobNameModel::createBodyLayer);

// In registerEntityRenderers() method - Renderer registration
EntityRendererRegistry.register(ModEntities.MOB_NAME.get(), MobNameRenderer::new);
```

**Common Mistake**: Forgetting either the imports OR the registrations will cause a NullPointerException crash when spawning the entity.

### NeoForge - ChronoDawnNeoForge.java

```java
// In onEntityAttributeCreation event
event.put(ModEntities.MOB_NAME.get(), MobNameEntity.createAttributes().build());

// In onSpawnPlacementRegister event
event.register(
    ModEntities.MOB_NAME.get(),
    SpawnPlacementTypes.ON_GROUND,
    Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
    Monster::checkMonsterSpawnRules,
    SpawnPlacementRegisterEvent.Operation.AND
);
```

### NeoForge - ChronoDawnClientNeoForge.java

```java
// In onRegisterEntityRenderers event
event.registerEntityRenderer(ModEntities.MOB_NAME.get(), MobNameRenderer::new);

// In onRegisterLayerDefinitions event
event.registerLayerDefinition(MobNameModel.LAYER_LOCATION, MobNameModel::createBodyLayer);
```

---

## 7. Resource Files

### Loot Table

**1.21.1 / 1.21.2 / 1.21.3** (`data/chronodawn/loot_table/entities/mob_name.json`):
```json
{
  "type": "minecraft:entity",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:bone",
          "functions": [
            {
              "function": "minecraft:set_count",
              "count": { "min": 0, "max": 2, "type": "minecraft:uniform" }
            },
            {
              "function": "minecraft:enchanted_count_increase",
              "enchantment": "minecraft:looting",
              "count": { "type": "minecraft:uniform", "min": 0, "max": 1 }
            }
          ]
        }
      ]
    }
  ]
}
```

**1.20.1** (`data/chronodawn/loot_tables/entities/mob_name.json`):
- Directory is `loot_tables` (plural)
- Use `"function": "minecraft:looting_enchant"` instead of `enchanted_count_increase`

### Language Files

```json
"entity.chronodawn.mob_name": "Mob Name",
"item.chronodawn.mob_name_spawn_egg": "Mob Name Spawn Egg"
```

### Biome Spawn Configuration

To replace a vanilla mob in ChronoDawn biomes, edit `worldgen/biome/chronodawn_*.json`:

```json
{
  "spawners": {
    "monster": [
      { "type": "chronodawn:mob_name", "weight": 100, "minCount": 4, "maxCount": 4 }
    ]
  }
}
```

---

## 8. Spawn Egg

**IMPORTANT**: See the `custom-mob-spawn-egg` skill for complete spawn egg implementation checklist.

Quick reminder:
- Register in `ModItems.java`
- Add to `initializeSpawnEggs()` and `populateCreativeTab()`
- Create `models/item/mob_name_spawn_egg.json` with `"parent": "item/template_spawn_egg"`
- Add to NeoForge color handler in `ChronoDawnClientNeoForge.java`
- **1.21.4 only**: Create `items/mob_name_spawn_egg.json` with tints array (colors in decimal)

---

## Version API Differences Summary

| Feature | 1.20.1 | 1.21.1 | 1.21.2/1.21.3 | 1.21.4 |
|---------|--------|--------|---------------|--------|
| Spawn type enum | `MobSpawnType` | `MobSpawnType` | `EntitySpawnReason` | `EntitySpawnReason` |
| SynchedEntityData | `defineSynchedData()` no params | `defineSynchedData(Builder)` | `defineSynchedData(Builder)` | `defineSynchedData(Builder)` |
| EntityModel type param | `EntityModel<Entity>` | `EntityModel<Entity>` | `EntityModel<RenderState>` | `EntityModel<RenderState>` |
| MobRenderer type params | 2 (`Entity, Model`) | 2 (`Entity, Model`) | 3 (`Entity, RenderState, Model`) | 3 (`Entity, RenderState, Model`) |
| renderToBuffer color | `float r,g,b,a` | `int color` | N/A (handled by RenderState) | N/A (handled by RenderState) |
| EntityType.Builder.build() | `build("name")` | `build(ResourceKey)` | `build(ResourceKey)` | `build(ResourceKey)` |
| SpawnPlacements.Type | `SpawnPlacements.Type` | `SpawnPlacementTypes` | `SpawnPlacementTypes` | `SpawnPlacementTypes` |
| Loot table directory | `loot_tables/` | `loot_table/` | `loot_table/` | `loot_table/` |
| Looting enchant function | `looting_enchant` | `enchanted_count_increase` | `enchanted_count_increase` | `enchanted_count_increase` |
| RenderState class | Not needed | Not needed | Required | Required |
| Damage handling | `hurt(DamageSource, float)` | `hurt(DamageSource, float)` | `hurtServer(ServerLevel, DamageSource, float)` | `hurtServer(ServerLevel, DamageSource, float)` |
| Y coord minimum | `getMinBuildHeight()` | `getMinBuildHeight()` | `getMinY()` | `getMinY()` |
| Spawn egg item def | Not needed | Not needed | Not needed | `items/*.json` with tints |

*Note: 1.21.3 is a hotfix release that shares modules with 1.21.2. No separate code changes are needed.*

---

## Common Issues

**CRITICAL**: The most common mistakes are missing Fabric client registrations. Always verify both model layer AND renderer are registered in `ChronoDawnClientFabric.java`.

| Issue | Cause | Solution |
|-------|-------|----------|
| Entity not spawning | Missing attribute registration | Add to Fabric/NeoForge attribute events |
| Model not rendering | Missing model layer registration | Add `EntityModelLayerRegistry.registerModelLayer()` in ChronoDawnClientFabric.java |
| Crash on entity spawn | Wrong API for version | Check version differences table above |
| **NullPointerException on entityRenderer** | **Missing Fabric renderer registration** | **Add `EntityRendererRegistry.register()` in ChronoDawnClientFabric.java** |
| Entity invisible | Missing renderer registration | Add to EntityRendererRegistry in BOTH Fabric and NeoForge client classes |
| Spawn egg crash | Missing spawn egg color handler | See `custom-mob-spawn-egg` skill |
| Loot table error (1.21.2) | Using old `looting_enchant` function | Use `enchanted_count_increase` with `"enchantment": "minecraft:looting"` |

Related Skills

user-customization

181
from majiayu000/claude-skill-registry

指导用户如何自定义 Trae Skills 的配置,包括覆盖角色设定、调整技术偏好和定义全局规则。

grail-miner

159
from majiayu000/claude-skill-registry

This skill assists in setting up, managing, and optimizing Grail miners on Bittensor Subnet 81, handling tasks like environment configuration, R2 storage, model checkpoint management, and performance tuning.

DevOps & Infrastructure

whisper-transcribe

159
from majiayu000/claude-skill-registry

Transcribes audio and video files to text using OpenAI's Whisper CLI, enhanced with contextual grounding from local markdown files for improved accuracy.

Media Processing

lets-go-rss

159
from majiayu000/claude-skill-registry

A lightweight, full-platform RSS subscription manager that aggregates content from YouTube, Vimeo, Behance, Twitter/X, and Chinese platforms like Bilibili, Weibo, and Douyin, featuring deduplication and AI smart classification.

Content & Documentation

chrome-debug

159
from majiayu000/claude-skill-registry

This skill empowers AI agents to debug web applications and inspect browser behavior using the Chrome DevTools Protocol (CDP), offering both collaborative (headful) and automated (headless) modes.

Coding & DevelopmentClaude

ux

159
from majiayu000/claude-skill-registry

This AI agent skill provides comprehensive guidance for creating professional and insightful User Experience (UX) designs, covering user research, information architecture, interaction design, visual guidance, and usability evaluation. It aims to produce actionable, user-centered solutions that avoid generic AI aesthetics.

UX Design & StrategyClaude

thor-skills

159
from majiayu000/claude-skill-registry

An entry point and router for AI agents to manage various THOR-related cybersecurity tasks, including running scans, analyzing logs, troubleshooting, and maintenance.

SecurityClaude

tech-blog

159
from majiayu000/claude-skill-registry

Generates comprehensive technical blog posts, offering detailed explanations of system internals, architecture, and implementation, either through source code analysis or document-driven research.

Content & DocumentationClaude

vly-money

159
from majiayu000/claude-skill-registry

Generate crypto payment links for supported tokens and networks, manage access to X402 payment-protected content, and provide direct access to the vly.money wallet interface.

Fintech & CryptoClaude

modal-deployment

159
from majiayu000/claude-skill-registry

Run Python code in the cloud with serverless containers, GPUs, and autoscaling using Modal. This skill enables agents to generate code for deploying ML models, running batch jobs, serving APIs, and scaling compute-intensive workloads.

DevOps & Infrastructure

ontopo

159
from majiayu000/claude-skill-registry

An AI agent skill to search for Israeli restaurants, check table availability, view menus, and retrieve booking links via the Ontopo platform, acting as an unofficial interface to its data.

General Utilities

astro

159
from majiayu000/claude-skill-registry

This skill provides essential Astro framework patterns, focusing on server-side rendering (SSR), static site generation (SSG), middleware, and TypeScript best practices. It helps AI agents implement secure authentication, manage API routes, and debug rendering behaviors within Astro projects.

Coding & Development