hytale-custom-assets

Create and manage custom assets for Hytale including models, textures, sounds, particles, and asset packs. Use when asked to "add custom assets", "create textures", "make models", "add sounds", "configure particles", or "build an asset pack".

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "hytale-custom-assets" with this command: npx skills add mnkyarts/hytale-skills/mnkyarts-hytale-skills-hytale-custom-assets

Creating Custom Hytale Assets

Complete guide for creating and managing custom assets including models, textures, sounds, and particles.

When to use this skill

Use this skill when:

  • Creating asset packs for plugins
  • Adding custom textures and models
  • Configuring sounds and music
  • Creating particle effects
  • Setting up animations
  • Managing asset inheritance and tags

Asset System Architecture

Hytale uses a hierarchical asset system:

AssetPack
├── Server/          # Server-side assets
│   └── Content/     # Game content definitions
│       ├── BlockTypes/
│       ├── Items/
│       ├── Entities/
│       └── ...
└── Client/          # Client-side assets
    ├── Models/
    ├── Textures/
    ├── Sounds/
    ├── Particles/
    └── ...

Asset Pack Structure

my-plugin/
└── assets/
    ├── pack.json                    # Pack metadata
    ├── Server/
    │   └── Content/
    │       ├── BlockTypes/
    │       │   └── custom_block.blocktype
    │       ├── Items/
    │       │   └── custom_item.item
    │       ├── Entities/
    │       │   └── custom_entity.entity
    │       ├── Recipes/
    │       │   └── custom_recipe.recipe
    │       └── Sounds/
    │           └── custom_soundset.soundset
    └── Client/
        ├── Models/
        │   └── custom_model.model
        ├── Textures/
        │   ├── blocks/
        │   │   └── custom_block.png
        │   ├── items/
        │   │   └── custom_item.png
        │   └── entities/
        │       └── custom_entity.png
        ├── Sounds/
        │   └── custom/
        │       └── sound.ogg
        ├── Particles/
        │   └── custom_particle.particle
        └── Animations/
            └── custom_animation.animation

Pack Metadata

File: pack.json

{
  "Name": "MyPlugin Assets",
  "Id": "MyPlugin",
  "Version": "1.0.0",
  "Description": "Custom assets for MyPlugin",
  "Author": "Your Name",
  "Priority": 100,
  "Dependencies": ["Hytale:Core"]
}

Pack Properties

PropertyTypeDescription
NameStringDisplay name
IdStringUnique identifier
VersionStringSemantic version
DescriptionStringPack description
AuthorStringCreator name
PriorityIntegerLoad order (higher = later)
DependenciesArrayRequired packs

Textures

Texture Formats

FormatUse Case
PNGStandard textures (recommended)
TGATextures with alpha
DDSCompressed textures

Block Textures

Location: Client/Textures/blocks/

custom_block.png          # All faces
custom_block_top.png      # Top face only
custom_block_side.png     # Side faces
custom_block_bottom.png   # Bottom face

Texture Size: 16x16, 32x32, 64x64 (power of 2)

Item Textures

Location: Client/Textures/items/

custom_item.png           # Inventory icon (32x32)
custom_item_held.png      # Held model texture

Entity Textures

Location: Client/Textures/entities/

custom_entity.png         # Main texture atlas
custom_entity_glow.png    # Emissive layer
custom_entity_normal.png  # Normal map

Models

Model Format

Hytale uses a custom JSON-based model format.

File: custom_model.model

{
  "Parent": "Hytale/Models/base_entity",
  "Textures": {
    "main": "MyPlugin/Textures/entities/custom_entity"
  },
  "Bones": [
    {
      "Name": "root",
      "Pivot": [0, 0, 0],
      "Children": [
        {
          "Name": "body",
          "Pivot": [0, 12, 0],
          "Cubes": [
            {
              "Origin": [-4, 0, -2],
              "Size": [8, 12, 4],
              "UV": [0, 0]
            }
          ],
          "Children": [
            {
              "Name": "head",
              "Pivot": [0, 24, 0],
              "Cubes": [
                {
                  "Origin": [-4, 0, -4],
                  "Size": [8, 8, 8],
                  "UV": [0, 16]
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "Animations": {
    "idle": "MyPlugin/Animations/custom_idle",
    "walk": "MyPlugin/Animations/custom_walk"
  }
}

Model Properties

PropertyTypeDescription
ParentStringParent model to inherit
TexturesObjectTexture bindings
BonesArrayBone hierarchy
AnimationsObjectAnimation bindings
ScaleFloatOverall scale
TextureSizeArrayTexture dimensions [W, H]

Bone Properties

PropertyTypeDescription
NameStringBone identifier
PivotArrayRotation pivot point
RotationArrayDefault rotation [X, Y, Z]
CubesArrayGeometry cubes
ChildrenArrayChild bones
MirrorBooleanMirror UV horizontally

Cube Properties

PropertyTypeDescription
OriginArrayPosition offset
SizeArrayDimensions [W, H, D]
UVArrayTexture UV offset [U, V]
InflateFloatExpand cube size
MirrorBooleanMirror this cube

Animations

File: custom_animation.animation

{
  "Length": 1.0,
  "Loop": true,
  "Bones": {
    "body": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.5": [5, 0, 0],
        "1.0": [0, 0, 0]
      }
    },
    "leftArm": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.25": [-30, 0, 0],
        "0.5": [0, 0, 0],
        "0.75": [30, 0, 0],
        "1.0": [0, 0, 0]
      }
    },
    "rightArm": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.25": [30, 0, 0],
        "0.5": [0, 0, 0],
        "0.75": [-30, 0, 0],
        "1.0": [0, 0, 0]
      }
    }
  }
}

Animation Properties

PropertyTypeDescription
LengthFloatDuration in seconds
LoopBooleanLoop animation
BonesObjectPer-bone keyframes

Keyframe Channels

ChannelTypeDescription
RotationArrayRotation [X, Y, Z] degrees
PositionArrayPosition offset [X, Y, Z]
ScaleArrayScale [X, Y, Z]

Sounds

Sound Formats

FormatUse Case
OGGMusic, ambient (recommended)
WAVShort sound effects

Sound Event

File: custom_sound.soundevent

{
  "Sounds": [
    {
      "Path": "MyPlugin/Sounds/custom/sound1",
      "Weight": 1.0
    },
    {
      "Path": "MyPlugin/Sounds/custom/sound2",
      "Weight": 0.5
    }
  ],
  "Volume": {
    "Min": 0.8,
    "Max": 1.0
  },
  "Pitch": {
    "Min": 0.9,
    "Max": 1.1
  },
  "Category": "Effects",
  "Subtitle": {
    "en-US": "Custom sound plays"
  }
}

Sound Set

File: custom_soundset.soundset

{
  "Sounds": {
    "break": "MyPlugin/SoundEvents/custom_break",
    "place": "MyPlugin/SoundEvents/custom_place",
    "step": "MyPlugin/SoundEvents/custom_step",
    "hit": "MyPlugin/SoundEvents/custom_hit"
  }
}

Block Sound Set

File: custom_blocksound.blocksound

{
  "Break": {
    "Sound": "MyPlugin/SoundEvents/metal_break",
    "Volume": 1.0,
    "Pitch": 1.0
  },
  "Place": {
    "Sound": "MyPlugin/SoundEvents/metal_place",
    "Volume": 1.0
  },
  "Step": {
    "Sound": "MyPlugin/SoundEvents/metal_step",
    "Volume": 0.5
  },
  "Fall": {
    "Sound": "MyPlugin/SoundEvents/metal_fall"
  }
}

Sound Categories

CategoryDescription
MasterAll sounds
MusicBackground music
EffectsSound effects
AmbientEnvironmental sounds
VoiceVoice/dialogue
UIInterface sounds
WeatherWeather sounds

Particles

File: custom_particle.particle

{
  "Texture": "MyPlugin/Textures/particles/sparkle",
  "MaxParticles": 100,
  "EmissionRate": 10,
  "Lifetime": {
    "Min": 0.5,
    "Max": 1.5
  },
  "Size": {
    "Start": 0.2,
    "End": 0.0
  },
  "Color": {
    "Start": { "R": 1.0, "G": 0.8, "B": 0.2, "A": 1.0 },
    "End": { "R": 1.0, "G": 0.2, "B": 0.0, "A": 0.0 }
  },
  "Velocity": {
    "Min": [-0.5, 1.0, -0.5],
    "Max": [0.5, 2.0, 0.5]
  },
  "Gravity": -0.5,
  "Collision": false,
  "BlendMode": "Additive"
}

Particle Properties

PropertyTypeDescription
TextureStringParticle texture
MaxParticlesIntegerMaximum active particles
EmissionRateFloatParticles per second
LifetimeRangeParticle lifespan
SizeRange/GradientSize over lifetime
ColorColor/GradientColor over lifetime
VelocityRangeInitial velocity
GravityFloatGravity effect
CollisionBooleanCollide with blocks
BlendModeEnumAlpha, Additive, Multiply

Block Particle

File: custom_blockparticle.blockparticle

{
  "Break": {
    "Particle": "MyPlugin/Particles/shatter",
    "Count": 30
  },
  "Step": {
    "Particle": "MyPlugin/Particles/dust",
    "Count": 3
  },
  "Ambient": {
    "Particle": "MyPlugin/Particles/glow",
    "Rate": 1,
    "Radius": 0.5
  }
}

Trails

File: custom_trail.trail

{
  "Texture": "MyPlugin/Textures/trails/slash",
  "Width": 0.5,
  "Length": 10,
  "Lifetime": 0.3,
  "Color": {
    "Start": { "R": 1.0, "G": 1.0, "B": 1.0, "A": 1.0 },
    "End": { "R": 1.0, "G": 1.0, "B": 1.0, "A": 0.0 }
  },
  "BlendMode": "Additive",
  "AttachPoint": "weapon_tip"
}

Asset Inheritance

Assets can inherit from parents:

{
  "Parent": "Hytale:Stone",
  "DisplayName": { "en-US": "Enchanted Stone" },
  "LightLevel": 5
}

Inheritance Rules

  1. Child inherits all parent properties
  2. Child can override any property
  3. Nested objects merge (not replace)
  4. Arrays replace (not merge)

Asset Tags

Categorize assets with tags:

{
  "Tags": {
    "Category": ["Building", "Decorative"],
    "Material": ["Stone"],
    "Origin": ["Natural", "Cave"]
  }
}

Tag Queries

Used in spawning, loot tables, etc.:

{
  "Blocks": {
    "MatchAll": ["Material:Stone"],
    "MatchAny": ["Category:Natural", "Origin:Cave"],
    "Exclude": ["Category:Artificial"]
  }
}

Localization

File: lang/en-US.json

{
  "item.myPlugin.customItem.name": "Custom Item",
  "item.myPlugin.customItem.description": "A special custom item",
  "block.myPlugin.customBlock.name": "Custom Block",
  "entity.myPlugin.customEntity.name": "Custom Creature"
}

Localization Keys

PatternExample
item.{plugin}.{id}.nameitem.myPlugin.sword.name
block.{plugin}.{id}.nameblock.myPlugin.ore.name
entity.{plugin}.{id}.nameentity.myPlugin.mob.name
ui.{plugin}.{key}ui.myPlugin.menuTitle

Registering Assets in Plugin

@Override
protected void setup() {
    // Asset pack is auto-registered if manifest.json has:
    // "IncludesAssetPack": true
    
    // Listen for asset loading
    getEventRegistry().register(
        LoadedAssetsEvent.class,
        BlockType.class,
        this::onBlockTypesLoaded
    );
    
    getEventRegistry().register(
        LoadedAssetsEvent.class,
        Item.class,
        this::onItemsLoaded
    );
}

private void onBlockTypesLoaded(LoadedAssetsEvent<BlockType> event) {
    // Access loaded block types
    for (BlockType block : event.getLoadedAssets()) {
        getLogger().atInfo().log("Loaded block: %s", block.getId());
    }
}

Hot Reloading

Assets support hot-reload during development:

/reload assets

Listen for reload events:

getEventRegistry().register(
    AssetStoreMonitorEvent.class,
    this::onAssetReload
);

private void onAssetReload(AssetStoreMonitorEvent event) {
    if (event.getAssetStore().getAssetClass() == BlockType.class) {
        getLogger().atInfo().log("Block types reloaded");
        // Re-initialize dependent systems
    }
}

Custom Asset Store

Register entirely new asset types:

public class MyCustomAsset implements JsonAssetWithMap<String, DefaultAssetMap<String, MyCustomAsset>> {
    public static final AssetBuilderCodec<String, MyCustomAsset> CODEC = 
        AssetBuilderCodec.builder(MyCustomAsset.class, "MyCustomAsset")
            .appendRequired(Codec.STRING.fieldOf("Name"), MyCustomAsset::getName, (a, v) -> a.name = v)
            .appendOptional(Codec.INT.fieldOf("Value"), MyCustomAsset::getValue, (a, v) -> a.value = v, 0)
            .build();
    
    private String id;
    private String name;
    private int value;
    
    @Override
    public String getId() { return id; }
    public String getName() { return name; }
    public int getValue() { return value; }
}

// Register in plugin
@Override
protected void setup() {
    HytaleAssetStore<String, MyCustomAsset, DefaultAssetMap<String, MyCustomAsset>> store = 
        new HytaleAssetStore<>(
            MyCustomAsset.class,
            "MyCustomAssets",      // Directory name
            ".mycustomasset",      // File extension
            MyCustomAsset.CODEC,
            DefaultAssetMap::new
        );
    
    getAssetRegistry().register(store);
}

Troubleshooting

Textures Not Loading

  1. Check file path matches reference
  2. Verify PNG format and dimensions
  3. Ensure pack.json is valid
  4. Check console for loading errors

Models Not Displaying

  1. Verify model JSON syntax
  2. Check texture references exist
  3. Ensure bone hierarchy is valid
  4. Test with simpler model first

Sounds Not Playing

  1. Check OGG/WAV format compatibility
  2. Verify sound event references
  3. Check volume and category settings
  4. Ensure sound files exist at path

Asset Inheritance Not Working

  1. Verify Parent path is correct
  2. Check parent asset loads first
  3. Ensure pack dependencies are set

See references/asset-formats.md for detailed format specs. See references/texture-specs.md for texture requirements.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

hytale-networking

No summary provided by upstream source.

Repository SourceNeeds Review
General

hytale-plugin-basics

No summary provided by upstream source.

Repository SourceNeeds Review
General

hytale-ui-windows

No summary provided by upstream source.

Repository SourceNeeds Review
General

hytale-crafting-recipes

No summary provided by upstream source.

Repository SourceNeeds Review