Wiki 9Minecraft Wiki 9Minecraft

Advanced Molang Reference: Contexts, Structs, and Loops

Reference tables and patterns for complex Molang expressions, scopes, and flow control.

4Sections
2Code examples
3Known errors

Basic Molang handles simple bone rotations and state checks, but advanced features like multi-statement blocks, loops, and context switching allow you to run real logic inside resource and behavior packs without relying on the Script API. You reach for these tools when building dynamic particle emitters, complex procedural animations, or client-side visual trackers that need to remember values between frames.

Variable Scopes and Lifetimes

Every value you store in Molang belongs to a specific scope prefix. Choosing the right scope determines how long the data lives, whether other animations or particles can read it, and how much memory it consumes on the client or server.

Temporary variables (`t.`) are the fastest and safest choice for multi-step math because they vanish the moment the expression finishes evaluating. Entity variables (`v.`) persist across frames on that specific actor or particle emitter, making them necessary for smoothing values over time. However, before you use a `v.` variable inside an animation, you should initialize it inside the entity's client description (`scripts.initialize`) so it does not evaluate as `0.0` by accident on the first frame.

PrefixAliasAccessLifetime and Behavior
temp.t.Read / WriteExists only during the current expression evaluation. Cleared immediately after the final statement returns.
variable.v.Read / WriteAttached to the executing entity or particle emitter. Persists across ticks and frames until the actor despawns, unloads, or the emitter dies.
context.c.Read-onlyProvided by the game engine for a specific event or rendering pass, such as `c.item_slot` on attachables or `c.is_first_person`.
query.q.Read-onlyFetches live game state from the actor, world, or hardware. Some queries accept arguments in parentheses.
math.noneRead-onlyBuilt-in mathematical functions and constants like `math.pi`, `math.sin(x)`, and `math.lerp(a, b, t)`. Has no single-letter alias.

Complex Expressions and Flow Control

When a single line of math becomes unreadable, you can switch from a simple expression to a complex expression. Any Molang string that contains a semicolon (`;`) is treated by the parser as a complex multi-statement block. Inside a complex block, simply writing a number at the end will not output it; you must explicitly use the `return` keyword to pass the final result back to the component, bone, or particle field.

Complex blocks also unlock brace scopes `{ ... }` and flow control keywords like `loop`, `for_each`, `break`, and `continue`. The `loop(count, { ... })` function repeats a braced block of statements up to 1024 times per evaluation. It is heavily used in `scripts.pre_animation` to calculate procedural bone chains or sum up values before the visual animations run.

Statement / OperatorSyntaxNotes
Ternary Conditionalcondition ? true_val : false_valIn simple expressions, returns one of two values. In complex blocks, can also be written without the `: false_val` part as a standalone `if` statement.
Null Coalescingv.maybe_unset ?? 1.0Returns the left side if it exists and is valid; otherwise returns the right fallback value without logging a missing-variable warning.
Looploop(count, { statements; });Executes the braced scope `count` times. Hard-capped at 1024 iterations by the engine to prevent client freezes.
Break / Continuebreak; / continue;Used inside `loop` or `for_each` scopes to exit the loop early or skip the rest of the current iteration.
Returnreturn expression;Required in any Molang string that uses semicolons if the field expects a number or boolean back. Immediately ends evaluation.
RP/entity/custom_automaton.entity.json
{
  "format_version": "1.10.0",
  "minecraft:client_entity": {
    "description": {
      "identifier": "wiki:custom_automaton",
      "materials": {
        "default": "entity_alphatest"
      },
      "textures": {
        "default": "textures/entity/custom_automaton"
      },
      "geometry": {
        "default": "geometry.custom_automaton"
      },
      "scripts": {
        "initialize": [
          "v.heat_level = 0.0;",
          "v.wave_sum = 0.0;"
        ],
        "pre_animation": [
          "v.heat_level = math.clamp(v.heat_level + (q.is_Moving ? 0.05 : -0.02), 0.0, 1.0);",
          "t.i = 0; t.total = 0; loop(4, { t.total = t.total + math.sin(q.life_time * 50 + t.i * 45); t.i = t.i + 1; }); v.wave_sum = t.total;"
        ],
        "animate": [
          "core_pulse"
        ]
      },
      "animations": {
        "core_pulse": "animation.custom_automaton.core_pulse"
      },
      "render_controllers": [
        "controller.render.default"
      ]
    }
  }
}

The Arrow Operator and Structs

Normally, a `q.` or `v.` reference only inspects the entity currently running the expression. The arrow operator (`->`) lets you step across entity boundaries and evaluate a query or read a variable on a completely different actor. If the target entity does not exist (for example, checking `q.target->q.health` when the mob currently has no attack target), the entire arrow expression safely evaluates to `0.0`.

You can also group related variables together on a single entity using dot-separated structs, such as `v.ik.left_arm.x`. Structs are purely organizational containers for floats and other nested structs. They cannot be passed into math functions as a single vector object, so you must still pass their individual `.x`, `.y`, and `.z` properties into functions one by one.

Access PatternExampleWhat it does
Target Context Switchq.target->q.healthReads the current health of the actor that this entity is actively targeting.
Owner Context Switchq.owner->v.team_colorReads a client variable stored on the entity that owns or summoned this actor (such as a wolf's owner or a projectile's shooter).
Struct Assignmentv.pos.x = 10; v.pos.y = 64;Groups variables under a shared namespace on the entity so you do not pollute the top-level `v.` scope.
Array Lookuparray.skins[q.variant]Selects a geometry, texture, or material from an array defined in the client entity description. Indices clamp automatically if out of bounds.

Passing Data Between Entities and Particles

A common advanced problem is getting a custom particle emitter to react to an entity's internal state. When an animation or client entity triggers a particle effect, the particle emitter gets its own separate `variable.` scope. It cannot directly read the parent entity's `v.` variables unless they are explicitly handed over or the particle is bound to the actor.

inside a particle JSON file, you can use `minecraft:emitter_initialization` to set up persistent emitter variables at birth and update them every tick. Combine complex expressions with math functions here to drive custom spiral trajectories, color shifts, or dynamic lifetimes without creating dozens of separate particle files.

RP/particles/arcane_spiral.particle.json
{
  "format_version": "1.10.0",
  "particle_effect": {
    "description": {
      "identifier": "wiki:arcane_spiral",
      "basic_render_parameters": {
        "material": "particles_alpha",
        "texture": "textures/particle/particles"
      }
    },
    "components": {
      "minecraft:emitter_initialization": {
        "creation_expression": "v.radius = 1.25; v.spin_speed = 180.0;",
        "per_update_expression": "v.current_angle = v.emitter_age * v.spin_speed;"
      },
      "minecraft:emitter_rate_steady": {
        "spawn_rate": 20,
        "max_particles": 100
      },
      "minecraft:emitter_lifetime_once": {
        "active_time": 5.0
      },
      "minecraft:emitter_shape_point": {
        "offset": [
          "math.cos(v.current_angle) * v.radius",
          "v.emitter_age * 0.5",
          "math.sin(v.current_angle) * v.radius"
        ]
      },
      "minecraft:particle_lifetime_expression": {
        "max_lifetime": "math.random(0.8, 1.4)"
      },
      "minecraft:particle_initial_speed": 0.0,
      "minecraft:particle_appearance_billboard": {
        "size": [
          "0.15 * (1.0 - (v.particle_age / v.particle_lifetime))",
          "0.15 * (1.0 - (v.particle_age / v.particle_lifetime))"
        ],
        "facing_camera_mode": "rotate_xyz"
      }
    }
  }
}

Which versions this applies to

Applies to Minecraft Bedrock 1.19.0 and newer (client entity format_version 1.10.0 and particle format_version 1.10.0). Structs, the arrow operator (->), and the null coalescing operator (??) are stable and require no experimental toggles.

When it does not work

What you seeWhyThe fix
Bone rotation, scale, or particle offset locks at 0 even though the math is valid.You used at least one semicolon (`;`) inside the string, which switches the parser into complex expression mode, but you forgot to write `return` before the final calculation.Either remove all semicolons if it is a single expression, or add `return ` in front of the final value (for example: `t.a = q.life_time * 20; return math.sin(t.a);`).
Content Log Error: [Molang][error]-Error: unhandled request for unknown variable 'v.my_var'An animation or render controller tried to read `v.my_var` on the very first frame before `scripts.pre_animation` or another animation set it, or the variable is only set conditionally.Declare a default value for the variable inside `scripts.initialize` in the `.entity.json` file, or read it using the null coalescing operator: `(v.my_var ?? 0.0)`.
String comparison inside a query fails or causes a syntax error inside JSON.Using escaped double quotes (`\"`) inside a Molang string is misinterpreted by the Molang parser in several contexts.Always use single quotes for strings inside Molang expressions, such as `q.is_item_name_any('slot.weapon.mainhand', 0, 'minecraft:diamond_sword')`.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.