1. Wiki
  2. /Particles
  3. /Your first particle

Your first particle

Build a ruby sparkle particle for Minecraft Bedrock step by step: the particle file, texture, curves, events and how to play it in game.

Particles are the small flat pictures you see everywhere in Minecraft: smoke from a campfire, hearts over a happy animal, bubbles under water. In this guide you will make your own: a ruby sparkle. It is a burst of little red glints that float up, twinkle and fade away.

You will learn what goes in a particle file, how to draw its texture, how to make it change over time and how to show it in game with a command, an animation or a script.

Resource pack only

Particles live completely in the resource pack. You do not need a behavior pack to make one, only to trigger it from a mob or a script. GodCraft writes the pack files and manifests for you: see Export and install.

The files

Resource pack
RP/
  particles/
    ruby_sparkle.json
    ruby_dust.json
  textures/
    particle/
      ruby_sparkle.png

Every .json file in the particles folder is loaded by the game. The file name does not matter, but keeping it the same as the particle name makes things easy to find.

Emitters and particles

Before writing anything, it helps to know the two parts of every effect:

  • The emitter is an invisible spawner. It decides how many particles appear, where they start and how long it keeps spawning.
  • The particles are the little pictures. Each one decides how it moves, how it looks and when it disappears.

That is why particle components come in two families. Names that start with minecraft:emitter_ set up the spawner. Names that start with minecraft:particle_ set up each picture. You can write them in any order.

Part of the fileWhat it holds
descriptionThe particle's name, plus its material and texture
curvesOptional. Values that change over the particle's life
eventsOptional. Things that happen at certain moments, like spawning more particles
componentsEverything else: the emitter and particle settings

Step 1: the texture

Draw an 8x8 PNG and save it as RP/textures/particle/ruby_sparkle.png. A small four-pointed star works well.

Draw it in white and light grey, not red. Later you will tint it with a colour, and a tint multiplies the pixels. White becomes any colour you like, but a red picture tinted blue would turn almost black.

Leave the background fully transparent. Particles are always flat squares, so the transparent pixels are what give them their shape.

Step 2: the description

Create the particle file and start with its name and look:

RP/particles/ruby_sparkle.json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "wiki:ruby_sparkle",
      "basic_render_parameters": {
        "material": "particles_alpha",
        "texture": "textures/particle/ruby_sparkle"
      }
    },
    "components": {}
  }
}
  • identifier is the name you use to play the particle. Always give it your own namespace (here wiki:), so it can never clash with vanilla or another add-on.
  • texture is the path to your PNG from the root of the resource pack, without .png.
  • material decides how see-through pixels are drawn:
MaterialPixels areGood for
particles_alphaEither fully solid or fully invisiblePixel art, like vanilla hearts and crits. The safe choice.
particles_blendCan be half see-throughSoft smoke, mist, fading dust
particles_addAdded on top of what is behind them, so they glowMagic, sparks, fire, light

Our sparkle should glow, so change the material to particles_add once it works. Start with particles_alpha while testing, because it is the easiest to see.

Format version

1.10.0 is the version most add-on particles use, and every component on these pages works with it. Newer vanilla files use higher versions, but you do not need them for anything in this guide.

Step 3: the emitter

Now fill in components. First the spawner. We want one quick burst of 12 sparkles, spread around a small ball:

RP/particles/ruby_sparkle.json (inside components)
"minecraft:emitter_lifetime_once": {
  "active_time": 0.5
},
"minecraft:emitter_rate_instant": {
  "num_particles": 12
},
"minecraft:emitter_shape_sphere": {
  "radius": 0.4,
  "direction": "outwards"
},

Every emitter needs one lifetime component and one rate component. Without them, nothing spawns. The shape is optional: leave it out and every particle starts at the exact centre.

Step 4: the particles

Next, tell each sparkle how to move and look. Add these after the emitter components:

RP/particles/ruby_sparkle.json (inside components)
"minecraft:particle_lifetime_expression": {
  "max_lifetime": "math.random(0.6, 1.2)"
},
"minecraft:particle_initial_speed": 1.5,
"minecraft:particle_motion_dynamic": {
  "linear_acceleration": [0, 1.2, 0],
  "linear_drag_coefficient": 3
},
"minecraft:particle_appearance_billboard": {
  "size": [0.12, 0.12],
  "facing_camera_mode": "lookat_xyz",
  "uv": {
    "texture_width": 8,
    "texture_height": 8,
    "uv": [0, 0],
    "uv_size": [8, 8]
  }
},
"minecraft:particle_appearance_tinting": {
  "color": [1, 0.15, 0.3, 1]
}

Here is what each one does:

  • Lifetime. Each sparkle lives between 0.6 and 1.2 seconds. math.random picks a new number for every particle, so they do not all vanish at once. This is Molang, the small maths language Bedrock uses.
  • Speed. They shoot out at 1.5 blocks per second, in the direction the sphere gave them.
  • Motion. linear_acceleration pushes them up a little every second, so they float like embers. linear_drag_coefficient is air resistance: it slows the first burst down quickly.
  • Billboard. Every particle is a flat square. size is half its width and height in blocks, so 0.12 makes a square about a quarter of a block wide. lookat_xyz keeps it facing the player.
  • UV. This picks which part of the texture to show. Our texture is a single 8x8 picture, so we use all of it: start at 0, 0 and take 8, 8.
  • Tinting. Red, green, blue and alpha, each from 0 to 1. [1, 0.15, 0.3, 1] is a ruby red. You can also write "#FF2650".

Save, load the world and type:

Chat
/particle wiki:ruby_sparkle ~ ~1 ~

You should see a little red puff rise in front of you. If you see nothing, look at the table at the end of this page.

Step 5: make it twinkle with a curve

Right now each sparkle keeps the same size until it suddenly disappears. A curve fixes that. It is a value that follows a shape you draw with a few numbers.

Add a curves block next to description and components:

RP/particles/ruby_sparkle.json (inside particle_effect)
"curves": {
  "variable.ruby_size": {
    "type": "linear",
    "input": "variable.particle_age / variable.particle_lifetime",
    "nodes": [0.2, 1, 0.6, 0]
  }
},
  • The name must start with variable.. The game works out the curve for every particle, every frame, and stores the answer in that variable.
  • input is where along the curve we are. Age divided by lifetime goes from 0 (just born) to 1 (about to disappear).
  • nodes are the values along the way, spread evenly from start to end. Our sparkle starts small (0.2), grows to full size (1), shrinks (0.6) and ends at nothing (0).
  • type is how the curve moves between nodes. linear draws straight lines. catmull_rom and bezier make smooth bends, and bezier_chain lets you set each point and slope yourself.

Now use the variable in the billboard size:

Inside minecraft:particle_appearance_billboard
"size": ["0.12 * variable.ruby_size", "0.12 * variable.ruby_size"],

For a fade, the tint can change colour over the particle's life too. A gradient lists colours, and interpolant picks where we are between them:

Inside components
"minecraft:particle_appearance_tinting": {
  "color": {
    "gradient": ["#FFFF8FA8", "#FFFF2650", "#00A0002A"],
    "interpolant": "variable.particle_age / variable.particle_lifetime"
  }
}

Each colour here is written as #AARRGGBB, so the first two letters are alpha. The sparkle starts pale pink, turns ruby red and ends dark and invisible. With particles_add, dark colours fade into nothing, which looks lovely for glowing effects.

Step 6: add a pop with an event

Events make things happen at a certain moment. Let's leave a tiny puff of dust where each sparkle disappears.

First make the dust. It is a second, smaller effect:

RP/particles/ruby_dust.json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "wiki:ruby_dust",
      "basic_render_parameters": {
        "material": "particles_add",
        "texture": "textures/particle/ruby_sparkle"
      }
    },
    "components": {
      "minecraft:emitter_lifetime_once": { "active_time": 0.2 },
      "minecraft:emitter_rate_instant": { "num_particles": 3 },
      "minecraft:emitter_shape_point": {},
      "minecraft:particle_initial_speed": 0.4,
      "minecraft:particle_lifetime_expression": { "max_lifetime": 0.3 },
      "minecraft:particle_appearance_billboard": {
        "size": [0.04, 0.04],
        "facing_camera_mode": "lookat_xyz",
        "uv": {
          "texture_width": 8,
          "texture_height": 8,
          "uv": [0, 0],
          "uv_size": [8, 8]
        }
      },
      "minecraft:particle_appearance_tinting": { "color": "#FF7A0F2E" }
    }
  }
}

Then, back in ruby_sparkle.json, name an event and say what it does:

RP/particles/ruby_sparkle.json (inside particle_effect)
"events": {
  "pop": {
    "particle_effect": {
      "effect": "wiki:ruby_dust",
      "type": "emitter"
    }
  }
},

Finally, fire the event when each sparkle runs out of life:

RP/particles/ruby_sparkle.json (inside components)
"minecraft:particle_lifetime_events": {
  "expiration_event": "pop"
}

An event can do more than spawn particles:

Field in an eventWhat it does
particle_effectStarts another effect. type is emitter, emitter_bound, particle or particle_with_velocity
sound_effectPlays a sound, by its sound event name in event_name
expressionRuns a Molang expression on the emitter
logWrites a message to the Content Log, handy for testing
sequenceA list of events that all run, one after another
randomizeA list of events where only one runs, picked by weight

Do not let an effect spawn itself

If wiki:ruby_sparkle started wiki:ruby_sparkle from its own event, every particle would make more particles, forever. Always point events at a different, smaller effect.

The finished file

Here is the whole sparkle, with the glowing material switched on:

RP/particles/ruby_sparkle.json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "wiki:ruby_sparkle",
      "basic_render_parameters": {
        "material": "particles_add",
        "texture": "textures/particle/ruby_sparkle"
      }
    },
    "curves": {
      "variable.ruby_size": {
        "type": "linear",
        "input": "variable.particle_age / variable.particle_lifetime",
        "nodes": [0.2, 1, 0.6, 0]
      }
    },
    "events": {
      "pop": {
        "particle_effect": {
          "effect": "wiki:ruby_dust",
          "type": "emitter"
        }
      }
    },
    "components": {
      "minecraft:emitter_lifetime_once": {
        "active_time": 0.5
      },
      "minecraft:emitter_rate_instant": {
        "num_particles": 12
      },
      "minecraft:emitter_shape_sphere": {
        "radius": 0.4,
        "direction": "outwards"
      },
      "minecraft:particle_lifetime_expression": {
        "max_lifetime": "math.random(0.6, 1.2)"
      },
      "minecraft:particle_lifetime_events": {
        "expiration_event": "pop"
      },
      "minecraft:particle_initial_speed": 1.5,
      "minecraft:particle_initial_spin": {
        "rotation": "math.random(0, 360)",
        "rotation_rate": 90
      },
      "minecraft:particle_motion_dynamic": {
        "linear_acceleration": [0, 1.2, 0],
        "linear_drag_coefficient": 3
      },
      "minecraft:particle_appearance_billboard": {
        "size": ["0.12 * variable.ruby_size", "0.12 * variable.ruby_size"],
        "facing_camera_mode": "lookat_xyz",
        "uv": {
          "texture_width": 8,
          "texture_height": 8,
          "uv": [0, 0],
          "uv_size": [8, 8]
        }
      },
      "minecraft:particle_appearance_tinting": {
        "color": {
          "gradient": ["#FFFF8FA8", "#FFFF2650", "#00A0002A"],
          "interpolant": "variable.particle_age / variable.particle_lifetime"
        }
      }
    }
  }
}

We also slipped in particle_initial_spin: each sparkle starts at a random angle and turns slowly, so no two look the same.

Playing the particle

With a command

/particle plays an effect at a position. It needs cheats on.

Chat or a function
/particle wiki:ruby_sparkle ~ ~1 ~

You can put it in a function or a command block too. Use execute to play it on someone: /execute as @a at @s run particle wiki:ruby_sparkle ~ ~2 ~ shows a sparkle over every player's head.

From a mob's animation

A mob can play particles from its animations. This happens in the client entity file in the resource pack, so first see Your first custom mob if you have not made one yet.

1. Give the effect a short name in the client entity's description:

RP/entity/ruby_golem.entity.json (inside description)
"particle_effects": {
  "sparkle": "wiki:ruby_sparkle"
}

2. Play it from an animation at a point in time. locator is optional: it is a named point on the model, and the effect follows it as the mob moves. Without one, it plays at the mob's feet.

RP/animations/ruby_golem.animation.json (inside one animation)
"particle_effects": {
  "0.5": {
    "effect": "sparkle",
    "locator": "head"
  }
}

3. Or play it from an animation controller state. It starts when the mob enters the state:

RP/animation_controllers/ruby_golem.ac.json (inside one state)
"particle_effects": [
  { "effect": "sparkle" }
]

Each of these can also have a pre_effect_script: a bit of Molang that runs just before the effect starts. Use it to send values into the particle file, like a colour that depends on the mob.

Keep looping effects for mobs

When a mob plays an effect, the effect's emitter is attached to it. That is where emitter_lifetime_looping and emitter_lifetime_expression shine: a trail that follows a mob for as long as it walks, or glows while a Molang value is on.

From a script

Scripts can play particles anywhere, any time. Your behavior pack needs a script module in its manifest: Project setup shows how.

BP/scripts/main.js
import { world } from "@minecraft/server";

world.afterEvents.itemUse.subscribe(({ source, itemStack }) => {
  if (itemStack.typeId !== "wiki:ruby_wand") return;

  const { x, y, z } = source.location;
  source.dimension.spawnParticle("wiki:ruby_sparkle", { x, y: y + 1.5, z });
});

Every time a player uses a wiki:ruby_wand item, a sparkle bursts above them. dimension.spawnParticle shows the effect to everyone nearby. player.spawnParticle works the same way, but only that one player sees it.

Scripts can also send values into the particle with a MolangVariableMap. This lets one particle file make sparkles in any colour:

BP/scripts/main.js
import { MolangVariableMap } from "@minecraft/server";

// Inside the same itemUse handler as above:
const vars = new MolangVariableMap();
vars.setColorRGB("variable.tint", { red: 0.2, green: 0.6, blue: 1 });
source.dimension.spawnParticle("wiki:ruby_sparkle", { x, y: y + 1.5, z }, vars);

In the particle file, read the three parts of the colour as variable.tint.r, variable.tint.g and variable.tint.b:

Inside components
"minecraft:particle_appearance_tinting": {
  "color": ["variable.tint.r", "variable.tint.g", "variable.tint.b", 1]
}

Handy Molang variables

The game fills in these values for you. Use them in any Molang field.

VariableValue
variable.particle_ageHow long this particle has been alive, in seconds
variable.particle_lifetimeHow long this particle will live in total
variable.particle_random_1 to _4Four random numbers from 0 to 1, different for every particle
variable.emitter_ageHow long the emitter has been running
variable.emitter_lifetimeHow long the emitter runs in total
variable.emitter_random_1 to _4Four random numbers from 0 to 1, shared by the whole emitter
variable.entity_scaleThe size of the mob the effect is attached to

variable.particle_random_1 is great for variety. For example "0.1 + variable.particle_random_1 * 0.05" gives every sparkle a slightly different size.

When something goes wrong

What you seeMost likely cause
Nothing at allThe emitter has no lifetime or no rate component, or the identifier in the command does not match the file
/particle says the effect does not existA typo in the JSON. Open the Content Log to find the broken line
A purple and black squareThe texture path is wrong, or it ends in .png
The whole texture is squashed into one particleThe uv block is missing or texture_width and texture_height do not match the PNG
Black squares around each particleThe background of the PNG is not transparent, or you used particles_add with a dark picture
The particle is the wrong colourThe tint multiplies the texture. Draw the texture in white
It never stopsIt uses emitter_lifetime_looping. For a one-off burst use emitter_lifetime_once

More help is in Troubleshooting. Ready for more? Every emitter setting is on Emitter components, and every particle setting is on Particle components.

We use cookies to improve your experience and analyse site traffic. Learn more