Client-side minecraft mod that allows you to add your own small reusable pieces of JSON "code" via resource packs, or download already made ones.
Start off by creating a resource
pack, where all your widgets will be located at. Inside your namespace,
create a folder named widgets
.
root
├── assets
│ └── namespace
│ └── widgets
├── pack.mcmeta
└── pack.png
Inside this folder, create your first widget file, let's call it my_widget.json
.
A widget file represents an entry on the Wheel and consists of three main parts.
Them being: label
, preview
, and actions
fields. We're going to discuss what
each field does based on this example widget below.
{
"label": "Example Widget",
"preview": "minecraft:grass_block",
"actions": [
{
"type": "echo",
"message": "Hello, world!"
}
]
}
You can already probably tell what those fields are used for, nevertheless, discussing them would still clear some details, so let's begin.
💡 You can use the widget JSON schema to simplify the process of creating new widgets.
The label is the part that is shown to a player when they hover over the widget - the Tooltip of the
widget. Since label
is a JSON text object, it can either be set to a string, or to a full object, such
as:
{
"text": "Example Widget",
"color": "gold",
"bold": true,
"italic": true
}
The preview represents an item that is displayed on the widget as its cover. Just like with the label
,
this can either be set to a string, which will then represent the item's id, or to a full item stack object, such as:
{
"id": "minecraft:stone",
"count": 1,
"components": {
"custom_model_data": 5
}
}
The actions
field represents an array of actions that will be run when the widget
gets clicked. We'll discuss more about action types below, but the syntax stays pretty
simple, "type"
points to an action type, whilst all the fields required by that type
are listed below. In our example:
{
"actions": [
{
"type": "echo",
"message": "Hello, world!"
}
]
}
Widgets don't take a strict spot on the wheel by default, but this can be
changed by setting the take_slot
field to one of its values:
"top_left" "top" "top_right"
"left" "right"
"bottom_left" "bottom" "bottom_right"
There are plenty of action types you can perform. Some of them are used more often than others, some of them don't do anything of their own, but ALL of them are listed below :)
💡 Fields annotated with [*] are required, all the other ones are completely optional.
Echo sends the specified message to the chat, or displays it in the actionbar.
message
: The message. JSON-Text [*]overlay
: Whether to show in the actionbar instead. Boolean
Runs the specified command.
command
: The command. If the first character is '/', it will be ignored. String [*]
Lists all the widgets in the specified path and opens a new wheel with those widgets. The path is a sub path within the widgets
folder in a resource pack.
path
: The path. Must match the following regex: "[a-zA-Z0-9_/]". String []
Plays the specified sound to the player, or stops it instead.
id
: The identifier of the sound. Identifiervolume
: The volume value. Floatpitch
: The pitch value. Floatstop
: Whether to stop the sound instead. If theid
isn't specified, this will stop all sounds. Boolean
Copies the content to the clipboard of the player.
content
: The content to copy. String [*]
Opens the chat with the specified text inserted.
content
: The content to suggest. String [*]cusrsor
: If included, sets the cursor to the specified position. Integer
Opens the specified URI.
destination
: A URI specifying the destination of the link. If starts with ".", tries to open a path relative to the run directory instead. String [*]ignore_confirmation
: Whether to skip the confirmation screen whilst opening the link. Boolean
Performs the specified action(s) after a certain amount of ticks.
actions
: The action(s) to perform. Can either be set to an action, or an array of such. Action | Action Array [*]delay
: The amount of ticks to wait before executing the actions. Integer [*]
Randomly selects one of the specified actions and executes it. If only one single action is present, it's either executed, or not.
actions
: The action(s) to perform. Can either be set to an action, or an array of such. Action | Action Array [*]
Consider taking a look at Working with Values for a comprehensive tutorial on how to use values together with conditions.
Operates the specified value
and assigns it to the variable referred by the id
field.
The value can either be directly provided or referred by an identifier.
id
: The identifier associated with the variable. Identifier [*]operation
: The operation to perform on the value. Defaults toassign
if not specified. Operationvalue
: The value to use for the action. Can either be an identifier or a double value. Identifier | Double [*]
Evaluates the provided expression and executes either if
actions, if the condition
was met, or else
ones if it wasn't.
expression
The expression to check. Expression [*]if
The action(s) to execute if the expression was evaluated to betrue
. Action | Action List [*]else
The action(s) to execute if the expression was evaluated to befalse
. Action | Action List
Values are a crucial part of any advanced widget pack. They have a ton of possible usages, including:
- Radio Buttons: A good way to add some states to your widgets.
- Configs: Let the user choose a value out of pre-defined list, and then make different choices based on that very variable.
- Mini Games: You can even push the possibilities to their boundaries, and try to create a full game!
Values are stored as identifiers within the config, meaning they are persistent and are accessible from anywhere in the game.
Setting a value involves calling the value
action:
{
"type": "value",
"id": "example:value",
"value": 5
}
Just like that, we can assign the value with an identifier of "example:value"
to 5. Now that we have an assigned
value, let's create another one:
{
"type": "value",
"id": "example:another_value",
"value": "example:value"
}
Right away, you might have noticed that we now use a string instead of a double. This is called "dynamic values". It's a way to use already assigned values throughout your actions, in places where they are supported.
A such place is.... echo
action! To use a dynamic value in an echo action,
you can simply surround its identifier with such "quotes": $()
{
"type": "echo",
"message": {
"text": "My cool value: $(example:value)"
},
"overlay": true
}
This would output My cool value: 5
, since we've assigned our example:value
to 5.
Up until now, we've only assigned a value to a set number. What if we had to use more complex operations?
That's where the optional operation
comes in handy. It defaults to assign
, which we've been using all along,
so it's time to specify an operation we actually want.
{
"type": "value",
"operation": "sum",
"id": "example:another_value",
"value": "example:value"
}
We use the sum
operation here. It adds two values together, and just like all other operations,
stores the result in the value specified by the id
field. Of course, you aren't only limited to assign
and sum
operations. In fact, there are plenty of other ones you can use:
View other Operations
assign
- assigns theid
to thevalue
sum
- assigns theid
to the sum ofid
andvalue
difference
- assigns theid
to the difference betweenid
andvalue
product
- assigns theid
to the product ofid
andvalue
quotient
- assigns theid
to the quotient ofid
andvalue
remainder
- assigns theid
to the remainder ofid
andvalue
power
- raisesid
to the power ofvalue
, and assigns it to the result.sqrt
- calculates the square root ofvalue
, and assignsid
to the result.sine
- calculates the sine ofvalue
, and assignsid
to the result.cosine
- calculates the cosine ofvalue
, and assignsid
to the result.max
- assignsid
to whatever is greater:id
orvalue
.min
- assignsid
to whatever is smaller:id
orvalue
.random
- assignsid
a random double between 0 andvalue
.round
- roundsvalue
to the nearest whole number and assignsid
to the result.
Now that you're familiar with how values are assigned and stored, we can use condition
s to execute
different actions based on expressions
.
Using a condition
action is pretty simple. It consists of two main parts, an expression
, which is a
properly structured string that is then used to determine whether the condition is true, and two action
lists - one of them is executed if the condition was met, the other one if it wasn't.
{
"type": "condition",
"expression": "5 > 2",
"if": [
/* ... */
],
"else": [
/* ... */
]
}
In the example above, the expression
is: "5 > 2", which evaluates to true, since 5
is always greater than 2. You might think it's pretty useless, we all knew that 5 is
greater than 2. Exactly, it is! What isn't useless, is using the very dynamic values
we've discussed earlier:
{
"type": "condition",
"expression": "$example:value > 2",
"if": [
/* ... */
],
"else": [
/* ... */
]
}
With this small adjustment, our expression is now not very clear. What is $example:value
, is it 2, or is it 5?
If you remember, we did indeed assign example:value
to 5, so the expression is true! But what if it wasn't? What
if example:value
was set to 1? The expression would be false.
Let's take a look at another example, this time a tiny bit more complex:
💡 You can use different operators to compare variables. Them being: '>', '<', and '='.
{
actions: [
{
"type": "condition",
"expression": "$example:click = 0",
"if": [
{
"type": "echo",
"message": "First click!"
},
{
"type": "value",
"id": "example:click",
"value": 1
}
],
"else": [
{
"type": "echo",
"message": "Some click!"
}
]
}
]
}
If the actions provided in this example were packed in a widget, clicking it would first output First click!
, and then
Some click!
on any further click. This is because the value example:click
is changed after the condition is met, in fact, it
is also changed to a value that doesn't match the provided expression. That means that the condition can only evaluate to true
once.