MultiLoader 26.1+ · Part 12

Data Generation: Particle Descriptions (MultiLoader 26.1+)

BEGINNER MULTILOADER 26.1-26.1.2 12 min read · Jun 14, 2026
MultiLoader 26.1+ · 17 parts
1 Getting Started with MultiLoader 26.1+ 2 Setting Up RegistrationUtils (MultiLoader 26.1+) 3 Creating Items (MultiLoader 26.1+) 4 Creating Blocks (MultiLoader 26.1+) 5 Data Generation: Block & Item Models (MultiLoader 26.1+) 6 Data Generation: Block Loot Tables (MultiLoader 26.1+) 7 Data Generation: Crafting Recipes (MultiLoader 26.1+) 8 Data Generation: Block & Item Tags (MultiLoader 26.1+) 9 Data Generation: Language Files (MultiLoader 26.1+) 10 Data Generation: Advancements (MultiLoader 26.1+) 11 Data Generation: Sound Definitions (MultiLoader 26.1+) 12 Data Generation: Particle Descriptions (MultiLoader 26.1+) 13 Data Generation: Enchantments (MultiLoader 26.1+) 14 Custom Food Items (MultiLoader 26.1+) 15 Custom Tools (MultiLoader 26.1+) 16 Custom Armour (MultiLoader 26.1+) 17 Block Entities (MultiLoader 26.1+)

Custom particles require a registered ParticleType and a particle description JSON file that lists the sprite textures for the particle to cycle through. The description file can be generated automatically using ParticleDescriptionProvider, keeping it in sync with your registered types.

NOTE
Complete Data Generation: Sound Definitions before continuing. We add a new provider to the existing gatherClientData listener.

Registering a Particle Type

Particle types live in the minecraft:particle_type registry. Create a ParticleRegistry class in your common registry package:

java
public class ParticleRegistry {
public static final RegistrationProvider<ParticleType<?>> PARTICLES =
RegistrationProvider.get(Registries.PARTICLE_TYPE, Constants.MOD_ID);
public static final RegistryObject<ParticleType<?>, SimpleParticleType> EXAMPLE_PARTICLE =
PARTICLES.register("example_particle", () -> new SimpleParticleType(false));
public static void init() {}
}

SimpleParticleType is the standard particle type for particles that carry no extra data. The boolean argument controls whether the particle can be sent to clients who are playing with minimal particles; pass false to respect the player's setting and true to always show it.

Call ParticleRegistry.init() from CommonClass.init():

java
public class CommonClass {
public static void init() {
ItemRegistry.init();
BlockRegistry.init();
SoundRegistry.init();
ParticleRegistry.init();
CreativeTabRegistry.init();
}
}

Particle Description Provider

In your NeoForge data package, create ExampleParticleDescriptionProvider extending ParticleDescriptionProvider:

java
public class ExampleParticleDescriptionProvider extends ParticleDescriptionProvider {
public ExampleParticleDescriptionProvider(PackOutput output) {
super(output);
}
@Override
protected void addDescriptions() {
spriteSet(ParticleRegistry.EXAMPLE_PARTICLE.get(),
Identifier.fromNamespaceAndPath(Constants.MOD_ID, "example_particle"));
}
}

The single-texture overload of spriteSet registers exactly one sprite for the particle. The identifier points to a texture in assets/<namespace>/textures/particle/, without the .png extension.

TIP
For particles that animate through several frames, use the indexed-suffix overload:

spriteSet(ParticleRegistry.EXAMPLE_PARTICLE.get(), Identifier.fromNamespaceAndPath(Constants.MOD_ID, "example_particle"), 8, // number of frames false); // reverse order

This generates references to example_particle_0.png through example_particle_7.png. The particle renderer cycles through them in sequence.

Adding Sprite Textures

Datagen writes the description JSON but does not create textures. Place your sprite at:

text
common/src/main/resources/assets/examplemod/textures/particle/example_particle.png

Particle sprites are typically small squares (8x8 or 16x16 pixels) with an alpha channel for transparency. The game scales them based on the particle's size at runtime, so keep the texture simple.

Registering the Provider

Particle descriptions are client-side assets, so register the provider inside gatherClientData:

java
public static void gatherClientData(GatherDataEvent.Client event) {
event.createProvider(output -> new ExampleModelProvider(output));
event.createProvider(ExampleLanguageProvider::new);
event.createProvider(ExampleSoundDefinitionsProvider::new);
event.createProvider(ExampleParticleDescriptionProvider::new);
}

Testing In-Game

Run the NeoForge Data configuration. Check that assets/examplemod/particles/example_particle.json appears in the generated resources folder:

json
{
"textures": [
"examplemod:example_particle"
]
}

To spawn the particle in-game for a quick visual check, use the particle command from the server console or a command block:

shell
/particle examplemod:example_particle ~ ~1 ~ 0 0 0 0.1 20

If the particle shows as a white square or is missing entirely, verify that the texture file exists at the correct path and that the identifier in spriteSet matches the file name exactly.

You can find the source for this tutorial here:

View Source on GitHub
NEXT IN SERIES

Data Generation: Enchantments (MultiLoader 26.1+)

Define a custom enchantment as a datapack registry entry using RegistrySetBuilder and DatapackBuiltinEntriesProvider, set weight, level, cost formula, and compatible item tags, and generate the enchantment JSON.

Continue →