3D Model System¶
The 3D Model System allows you to attach custom 3D models directly to the player's body when they equip specific Curios items. Models are rendered using synchronized invisible Armor Stands.
How It Works¶
Rather than only showing custom items in the hand or inventory, CuriosPaper uses synchronized Armor Stands to render custom models on the player's body.
┌──────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Player Equips │────▶│ Model Stand │────▶│ Renders Model │
│ Curios Item │ │ Manager │ │ on Player │
└──────────────────┘ └──────────────┘ └─────────────────┘
│
▼
┌──────────────┐
│ Rotation & │
│ Visibility │
│ Sync (Tick) │
└──────────────┘
Entity Architecture¶
When an item with a 3D model configuration is placed in an accessory slot, CuriosPaper dynamically spawns an invisible marker Armor Stand that rides the player as a passenger.
- The armor stand wears the defined model item (e.g.,
LEATHER_HORSE_ARMORcombined with a specificitemModelcomponent in 1.21.4+, orCustomModelDatain older versions). - The stand tracks the player's rotation seamlessly via a tick task.
- For items in a
head:slot, the armor stand head strictly synchronizes to the player's independent head yaw left-to-right (maintaining a 0-pitch angle for perfect horizontal alignment). Other slots lock into both full body yaw and overall pitch. - When the accessory is unequipped or the player logs out, the stand is safely destroyed.
Visibility Culling¶
To prevent the armor stand from obscuring the player's vision when in first-person view, CuriosPaper implements a dynamic visibility culling system.
Pitch Limits¶
You can configure downward and upward pitch cutoffs per item. When the player looks too far down (or up), the model is hidden from their own view by temporarily unequipping the item from the Armor Stand's helmet slot. It remains visible to other players.
| Limit | Description |
|---|---|
| Pitch Up Limit | Hide model when the player looks up beyond this angle (e.g., 45.0°) |
| Pitch Down Limit | Hide model when the player looks down beyond this angle (e.g., 30.0°) |
Per-Item Toggles¶
Players have control over whether their equipped models are visible:
- By Right-Clicking an equipped accessory in the
/baublesmenu, players can toggle its global 3D model visibility. - This preference is saved directly to the item's PersistentDataContainer (
curios_model_hidden), meaning it persists even if the item is dropped or traded.
Player State Handling¶
The ModelStandManager handles complex player states:
| Player State | Behavior |
|---|---|
| Walking/Running | Models follow player position and rotation |
| Sneaking | Models update position to match sneaking offset |
| Swimming | Models are repositioned for swimming pose |
| Gliding (Elytra) | Models are repositioned for gliding pose |
| Teleporting | Models are force-updated to new position |
| World Change | Models are removed and re-scanned in the new world |
| Death | All models removed; re-scanned on respawn |
| Disconnect | All models cleaned up |
| Game Mode Change | Models updated (hidden in spectator, etc.) |
Trident Compatibility¶
When a player uses a trident, the 3D models are temporarily removed to prevent visual glitches:
- Normal Throw: Models are removed when the player starts charging, restored when they release or after a timeout.
- Riptide: Models are removed on riptide activation, restored when the player lands on the ground.
Scale Synchronization¶
If the player is scaled via external plugins (e.g., shrink/enlarge effects), the armor stand model automatically scales to match the player's size. A periodic sync task checks for scale changes every second.
Model Protection¶
Model armor stands are fully protected from the game world:
- Cannot take damage from any source
- Cannot be targeted by mobs
- Cannot be interacted with (no right-click trade GUI, etc.)
- Cannot be pushed by other entities
Configuring Models¶
Models can be configured in three ways:
1. In-Game GUI¶
Using the 3D Model Editor via /edit gui <item> → click the Armor Stand button (slot 43).
2. API¶
CuriosPaperAPI api = CuriosPaper.getInstance().getCuriosPaperAPI();
// Configure 3D model for an item
api.setItemModelConfig(
"my_cape", // item ID
true, // model enabled
"LEATHER_HORSE_ARMOR", // model material
null, // CustomModelData (null if using item model)
"myplugin:cape_model", // item model component (1.21.4+)
45.0f, // pitch up limit (hide when looking up >45°)
30.0f // pitch down limit (hide when looking down >30°)
);
3. Item YAML¶
# plugins/CuriosPaper/items/my_cape.yml
item-id: my_cape
display-name: "&5Royal Cape"
material: PAPER
slot-type: back
# 3D Model Settings
model-enabled: true
model-item: "LEATHER_HORSE_ARMOR"
model-custom-model-data: null
model-item-model: "myplugin:cape_model"
pitch-up-limit: 45.0
pitch-down-limit: 30.0
Mob Drop Models¶
Mobs can also display 3D models when they spawn carrying a custom item. This is configured separately per mob drop entry.
In-Game GUI¶
Use the Mob Drop Editor → click an existing mob drop → 3D Model button.
API¶
// Configure 3D model for a mob drop
api.setMobDropModelConfig(
"my_crown", // item ID
"ZOMBIE", // entity type
true, // model enabled
"GOLDEN_HELMET", // model material
null, // CustomModelData
"myplugin:crown_model" // item model component
);

