- Usermode basics
- Publishing usermodes
- Usermode peculiarities
Usermodes allow players to create their own custom gamemodes and share them with other players.
To get started, go to your Account Settings, then in the "Other tab" check the Experiments toggle.
Please note that you need to have at least 10 hours of playtime on your account or be a Supporter to be able to access Usermodes.
After enabling experimental features, a new tab called "Usermodes" should be available.
Choose "Create" to create your first usermode, or "Browse" to explore usermodes created by other players.
After choosing "Create", you will be presented with the Usermode Editor.
Drag and drop components from the sidebar to the component area, or click on components to put them on the bottom of your usermode.
Be aware that there's a 2000-component limit for usermodes - though hitting it is very unlikely. If you do, please suggest changes/additions to usermodes in Jstris Discord.
Usermodes are constructed by putting components together, starting with a "Trigger" component, that triggers the components put below it, from top to bottom.
If you put your component in wrong place, you can always drag it somewhere else by dragging the component's title bar.
While hovering over a component with a mouse cursor, extra options are available:
- An ON/OFF switch,
- Green (+) - duplicates a component and puts it below the current component when pressed,
- Red (-) - removes the component.
Each component gets an ID assigned to it when added (unless it's duplicated) - these IDs are used for the On/Off component and the Random component.
Triggers are the starting point of your usermode. When a certain game action is performed, all components under that Trigger will be executed.
There must be at least one Trigger in the usermode.
Trigger options are as follows:
- Before the game - triggers before the "Ready-Go" sequence.
- Before the game - only the first game - triggers before the "Ready-Go" sequence, but only on the first game, after a restart this won't be triggered.
Before the game only supports Queue, Variable, Map, Stats, Text, Pause, Audio, Ruleset and Block Skin components underneath itself. - On game start - triggers after the "Ready-Go" sequence.
- After the game - triggers after completing the usermode successfully.
- At specific time - triggers when a certain amount of time passes from the start of the game.
- On each block - triggers after placing a block, when next block appears, after line clears were processed.
- On each lineclear - triggers after any line clear.
- On specific block # - triggers once after a certain amount of blocks was placed.
- On specific # line cleared - triggers once after you cleared more than # lines.
- Key down - triggers when a key is pressed.
- Key up - triggers when a key is released.
Key up and Key down triggers react to a specified key code. You can use this keycode utility to determine the key code of your desired key.
Key up and Key down triggers also accept an option to prevent the default action when a player has that key bound. - Variable changes - triggers when a variable changes. Does not support system variables.
- Never - does not trigger.
- External/Conditional - you can set your own external trigger name for Condition, Run, Relative Trigger, On/Off or a Random component to trigger.
Custom trigger names must be at most 20 characters long and are case-sensitive.
Queue components allow you to replace a queue with your own fixed queue.
Be aware that if the finite queue runs out of pieces, the game is over, no matter whether there's a piece in Hold or not.
Type the tetromino block names in the "Queue" field to set up the queue.
There are four options available:
- Allow refill if queue is used - After all the pieces from the queue are used up, the game keeps dealing new pieces according to the Ruleset - 7-bag by default.
- Repeat this queue - The specified queue is looped forever.
- Replace active block - The active piece (the piece you are currently controlling) will be also replaced.
- Non-terminal last block - Adds a NONE piece to the end of the queue, so that the game doesn't immediately end after placing all the pieces. Make sure to handle this option appropriately and refill the player's queue.
You can also enable the advanced queue input by clicking on "+ Switch to advanced queue input."
Queue+ allows you to set a queue with pieces that aren't limited to just tetrominoes. In fact, it lets you set up a queue with any piece in the game.
Check the Block name reference list for more info about usable block names.
To set the queue to any piece available in the aforementioned list, use the format:
[<set_ID>:<piece_ID>]
So for example, [3:0]
will produce an I piece with Arika Rotation System.
Condition allows you to specify a condition, after fulfilling which (or not) a certain action is triggered.
You can check for various stats:
Click here to see available stats
- Number of blocks,
- Finesse (number of finesse faults),
- KPP,
- PPS,
- APM,
- Attack,
- T-spins,
- Active combo,
- Versus score,
- Perfect Clears,
- TSDs (T-spin Doubles),
- Garbage Cleared,
- Holds,
- B2B,
- Wasted Ts,
- Lines,
- Max Combo,
- Singles,
- Doubles,
- Triples,
- Jstrises (quadruples),
- Score,
- Incoming attack (the height of the red bar),
- Time (in seconds)
Then you can compare it with a number - available operators are >
, >=
, =
, <=
, <
.
You can also check for a Custom expression. Custom expressions require a variable on the left hand side of the expression. Custom expressions accept system variables, local counters and custom variables.
For example: To check if a level (custom variable) is higher or equal to 20, a custom expression would look like this:
level>=20
Fulfilling a condition (or not) can trigger one of the actions:
- Game over - the player loses with an explanation, what condition was not fulfilled.
Works only for "If false" conditions - setting this with "If true" condition will cause an error! - Successful game end - the player wins, and the usermode is considered completed.
- Run trigger actions - An External/Conditional Trigger is triggered.
Variable components are very powerful. Variable components allow you to specify a custom variable, and assign an expression to it.
The custom variable name must not be a name of a system variable and must be at most 20 characters long. Variable names are case-sensitive.
Variables can be used in custom expressions for the Condition components and as placeholders for Text components.
The right hand side of the component accepts MathJS expressions - try out its expression parser to play around.
Expressions can operate on system variables.
Besides MathJS functions, expressions can also contain special functions that affect the board and the queue.
Expressions must fit within a 100-character limit.
If your usermode goes haywire, you can debug your usermode by doing the following:
- Right-click on the Jstris page in-game and select "Inspect Element..." or hit F12,
- Go to the "Console" tab,
- In the console, if the variable changes, the change should be printed out on the console by
replayer.js
.
This only works for unpublished usermodes.
Map allows you to manipulate the contents of the board using a specified map.
Click the Edit map button to enter the map editor. It functions identically to the Map Designer.
Maps can manipulate the board in various ways:
- Replace board - the whole board is replaced by a map,
- Subtract from current board - If blocks are present on the board in the same position as in the map, the blocks will be removed.
- Add to current board (on top) - The map will be overlaid on top of the board (like a layer in an image editing program).
- Add to current board (under) The map will be underlain under the board (like a layer in an image editing program).
- Intersect with current board (keep stack color) - All blocks on the map are removed, except in positions where there were blocks in the map. Block colors on the board are retained.
- Intersect with current board (force map color) - Same as above, but block colors are replaced with those from the map.
- End if map collides with current piece position - Will end the game as failure if the map shape collides with the currently manipulated piece. Does not modify the board.
- End if map collides with current stack - Will end the game as failure if the map shape collides with the current stack. Does not modify the board.
Stats component allows you to change the statistics displayed below the board.
In order to find out, what number to insert into the textbox, open Settings, then navigate to Stats, then check your desired stats. In the bottom right corner, there's a small number. This number determines what stats to show. The number is interpreted in binary, so 129 from the example image shows Time (+1) and KPP (+128).
Full list of stats
- Time (+1)
- Score (+2)
- Lines (+4)
- Attack (+8)
- Received (+16)
- Finesse (+32)
- PPS (+64)
- KPP (+128)
- APM (+256)
- Blocks (+512)
- VS (+1024)
- Wasted (+2048)
- Hold (+4096)
Text components allow you to insert text into your usermode. Text components can accept text and placeholders.
Placeholders are specified in curly brackets, and can hold system variables, local counters and custom variables,
For example: {PC}
will insert a number of Perfect Clears performed.
There are four different ways of showing Text (and fifth one which is not yet implemented):
Pause components pause the game for a specified period of time in seconds. Useful for quizzes.
There are two options available:
- Allow skip by pressing any key - The game unpauses immediately when the player presses any key.
- Allow some controls - The player can buffer holds and rotations during the pause.
Audio components play a specified audio clip when executed. Audio components only accept audio clips from https://audio.jezevec10.com (Dallicious voice lines) and https://s.jezevec10.com (in-game sounds).
Available sounds from audio.jezevec10.com - click here
Available sounds from s.jezevec10.com - click here
TODO: Insert sound list there
Attack components send garbage to the player when executed.
If separated by commas, the component will send multiple garbage segments at once.
For example: The Attack component in the image above will send a segment of 4 garbage lines and a segment of 2 garbage lines at once.
There are two options available:
- Specify garbage columns - You can control in which column each segment spawns. Make sure to include the same amount of values as in the "Lines" textbox!
- Ensure column switch - Garbage segment won't spawn on the same column as the previous one.
Ruleset components change the rules of the game when executed. Rulesets can be even changed mid-game to achieve dynamic difficulty for your usermode.
Check out the Ruleset specification for more details.
There's also an option to add the specified ruleset without resetting all options - only rules specified in the ruleset will change.
Block skin components change the block skin when executed. Block skin components only accept skins from https://i.imgur.com (You can make your custom skin that way) and https://s.jezevec10.com (built-in skins). Block skins must be in 9:1 proportions.
Available skins from s.jezevec10.com - click here
Free skins
Supporter-only skins
Hidden skins
Link | Image |
---|---|
https://s.jezevec10.com/res/b5.png |
Jstris Customization Database contains a list of block skins from various games, official or not, and some user-made skins too.
Use this component only when necessary (for example to give a retro climate to a mode, or when repurposing garbage as targets, or for other creative ways to use blocks).
A very simple component, that just triggers an External/Conditional Trigger.
Relative Trigger components can trigger an External/Conditional Trigger after:
- A certain amount of time (in seconds) passes...
- Certain amount of pieces were placed...
- Certain amount of lines were cleared...
... since the Trigger under which this component is present was triggered.
For example: When a certain Trigger triggers on 5th line, and there's a Relative Trigger that runs a certain trigger after 4 Lines, that trigger will run after clearing the 9th line.
On/Off components can switch components on and off.
Disabled components or Triggers won't be executed.
You can toggle multiple components on or off with this component by clicking the (+) button - this will add a new textbox in which an additional component can be turned on or off.
Random components can execute components or External/Conditional Triggers at random.
Operated similarly to the On/Off component.
This component must have at least 2 options to choose from.
You can specify the weights for each option by inputting a number after a comma.
If you are satisfied with your usermode, you can publish it for others to play.
You will be presented with this screen:
Enter the mode title, description, and tags. Add tags, separating each tag with a comma. Please note that line breaks in the description are stripped and won't show up in the mode preview.
The first map from the top of your usermode will be used as a thumbnail. If you wish to have a custom thumbnail that won't appear in the usermode, put the Map component under the Trigger that is set to Never trigger.
You can also customize the leaderboard of your mode.
You can set the leaderboard to:
- Not save anything to the leaderboard (leaderboard disabled),
- Save only the first completed game (further games won't be saved),
- Save every completed game (recommended for competitive modes).
You can change metrics for placing players in the leaderboard, and whether higher or lower scores are better. Secondary metric will be used if two or more players tie on the primary metric.
You can also set other stats that will be shown in the leaderboard, but won't be used for placing players on the leaderboard.
There's also an option to save scores on a game over too - useful for survival or endurance-style modes.
System variables are game-reserved variables that hold certain game-related statistics.
They can be used as a placeholder in Text components or be a part of an expression for the Variable or Condition components.
Variable name | Explanation |
---|---|
blocks | Number of pieces placed |
finesse | Number of finesse faults |
kpp | Keypresses per piece |
sent | Number of lines sent |
tspins | Number of T-spins performed |
combo | Current combo |
PC | Number of Perfect Clears |
TSD | Number of T-spin Doubles performed |
time | Time elapsed |
APM | Attack per minute |
PPS | Pieces per second |
VS | VS Score (Attack + Downstack per 100 seconds) |
garbage | Number of lines containing garbage cleared |
hold | Number of times the player held a piece |
B2B | Number of Back-to-backs performed |
wasted | Ratio of T pieces used in a T-spin to all T pieces |
lines | Number of lines cleared |
maxCombo | Maximum combo |
single | Number of Singles |
double | Number of Doubles |
triple | Number of Triples |
jstris | Number of Jstrises (quadruples) |
redbar | Number of lines awaiting in queue |
inputs | Number of inputs (not counting soft drops) |
Local counters are a specific type of system variables that hold game statistics, but only counting after an External/Conditional Trigger was triggered.
Local counters are invoked by using the following syntax:
<triggerName>.<systemVariable>
Local counters can then be used in custom expressions for the Condition components or as a placeholder for Text components.
For example: mission2.jstris
will only count Jstrises performed after the mission2
trigger was triggered.
Besides MathJS functions, the Variable component's expression can also hold certain functions that affect the board and the next queue.
The function can be performed with two syntax variations:
-
getBoard()
Returns: A 20x10 MathJS matrix containing the board state. -
getBoard(x, y)
Parameters:- x: Column, integer between 0 and 9
- y: Row, integer between 0 and 19
Returns: A integer between 0 and 9 which represents the color of the block on specified coordinates.
-
setBoard(x, y, color)
Parameters:- x: Column, integer between 0 and 9
- y: Row, integer between 0 and 19
- color: Block color, integer between 0 and 9
Returns: 1 on success, 0 on failure (index out of bounds, color does not exist).
⚠️ This function does not update the board visually! Use a blank Map with "Add to current board" to update the board.
-
queueReplace(index, piece)
Parameters:- index - Integer, starting from -1.
Index -1 replaces the active piece, 0 and higher replace the Next queue. - piece - A string representing a piece. Check the Block name reference list for the list of usable pieces.
"[setID:pieceID]"
can be used to pick any piece from the game.
- index - Integer, starting from -1.
-
queueReplace(index, setID, pieceID)
Alternative syntax with 3 numeric parameters.Returns: 1 on success, 0 on failure (queue index out of bounds, piece does not exist).
-
queueAppend(piece)
Parameters:- piece - A string representing a piece. Check the Block name reference list for the list of usable pieces.
"[setID:pieceID]"
can be used to pick any piece from the game.
- piece - A string representing a piece. Check the Block name reference list for the list of usable pieces.
-
queueAppend(setID, pieceID)
Alternative syntax with 2 numeric parameters.Returns: 1 on success, 0 on failure (piece does not exist).
Type: Array of integers with 11 elements
Specifies the number of lines sent for a specified line clear.
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
Line clear | 0 lines (unused) |
Single | Double | Triple | Jstris | T-spin Double |
T-spin Triple |
T-spin Single |
Mini T-spin Single |
Perfect Clear |
B2B bonus |
Default value | 0 | 0 | 1 | 2 | 4 | 4 | 6 | 2 | 0 | 10 | 1 |
Default: [0,0,1,2,4,4,6,2,0,10,1]
Type: Array of integers with 13 elements
Specifies the number of additional lines sent for a specified combo. The last index applies for 12-combo and greater.
Index (combo) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Default value | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 5 |
Default: [0,0,1,1,1,2,2,3,3,4,4,4,5]
Type: Boolean
Controls, whether the player can use Hold.
Default: true
Type: Array of Doubles
Specifies delays between solid garbage additions. After all of the previous delays inserted their garbage, the last value in the array is repeated.
Default: [0,3]
Type: Integer
Specifies the amount of time (in ms) after a line clear in which the game is paused. The player can buffer rotations and holds during that pause.
Default: 0
Type: Integer between 0 and 28
Specifies, how fast pieces fall on their own.
Gravity table - click here
Level | Period[1] | Rows[2] | G[3] |
---|---|---|---|
0 | ∞ ms | 1 | 0 |
1 | 900 ms | 1 | 0.018 |
2 | 850 ms | 1 | 0.02 |
3 | 800 ms | 1 | 0.021 |
4 | 750 ms | 1 | 0.022 |
5 | 700 ms | 1 | 0.024 |
6 | 650 ms | 1 | 0.026 |
7 | 600 ms | 1 | 0.028 |
8 | 550 ms | 1 | 0.03 |
9 | 500 ms | 1 | 0.033 |
10 | 450 ms | 1 | 0.037 |
11 | 400 ms | 1 | 0.042 |
12 | 350 ms | 1 | 0.048 |
13 | 300 ms | 1 | 0.056 |
14 | 250 ms | 1 | 0.067 |
15 | 200 ms | 1 | 0.083 |
16 | 150 ms | 1 | 0.111 |
17 | 100 ms | 1 | 0.167 |
18 | 50 ms | 1 | 0.333 |
19 | 45 ms | 1 | 0.37 |
20 | 40 ms | 1 | 0.417 |
21 | 35 ms | 1 | 0.476 |
22 | 30 ms | 1 | 0.556 |
23 | 25 ms | 1 | 0.667 |
24 | 20 ms | 1 | 0.833 |
25 | 30 ms | 2 | 1.111 |
26 | 20 ms | 2 | 1.667 |
27 | 33 ms | 3 | 1.515 |
28 | 0 ms | 21 | 20 |
[1]: The period after which the piece falls the specified amount of rows. ↑
[2]: The amount of rows the piece falls per period. ↑
[3]: The approximate amount of rows a piece falls every 1/60 s. ↑
Default: 1
Type: Integer between 0 and 60000
Specifies, after how long (in ms) since receiving a garbage segment that segment can be added to the board.
Default: 500
Type: Array of integers between 0 and 20,000,000 with 3 elements
Specifies different levels of lock delay.
Index | 0 | 1 | 2 |
---|---|---|---|
Lock delay | L1 | L2 | L3 |
Info | For how long the piece can stay on ground without locking. | For how long the piece can stay on ground while moving left/right without locking. | For how long the piece can be active. |
Default value | 500 ms | 5000 ms | 20000 ms |
Default: [500,5000,20000]
Type: Integer between -100 and 100
Specifies the chance for garbage to change columns both between segments and in segment.
-100
is 0% messiness between segments and 0% messiness in segment,- Negative values are
100+mess
% messiness between segments and 0% messiness in segment, 0
is 100% messiness between segments and 0% messiness in segment,- Positive values are 100% messiness between segments and
mess
% messiness in segment, 100
is 100% messiness between segments and 100% messiness in segment.
Default: 0
Type: Integer between 1 and 8
Specifies the width of the garbage hole.
Default: 1
Type: Integer between 0 and 2
Specifies allowed spins:
0
: T-spins,1
: Immobile all-spin,2
: 4-point all-spin.
Default: 0
Type: String specifying up to 6 tetrominoes separated by commas
All-spin exclusion list - applicable only when allSpin
is not 0. Specifies which pieces can't perform spins when all-spin is enabled.
For example, "T,J"
will prevent T and J pieces from performing spins.
Default: ""
Type: Boolean
If true, garbage lines will be inverted - where would be blocks, there would be empty spaces, and vice versa.
Default: false
Type: Boolean
If true, garbage lines will consist of solid hurry-up garbage lines.
Default: false
Type: Integer between 0 and 8
Specifies the block set used in the game.
If changed mid-game, pieces from the new set will appear at the end of the queue, since Jstris always keeps 5 pieces in queue, regardless of the amount of previews shown to the player.
Available block sets:
- Standard
- Big (moves 2 spaces left/right at a time)
- Big (moves 1 space left/right at a time)
- ARS
- Penta
- M123
- All-29
- C2RS
- O-spin
Default: 0
Type: Integer between 0 and 10
Specifies the randomizer.
Available randomizers:
Index | Randomizer | Explanation |
---|---|---|
0 | 7-bag | One of each tetromino in a bag |
1 | 14-bag | Two of each tetromino in a bag |
2 | Classic | Actually a memoryless randomizer. |
3 | One Block | One piece is randomized and given throughout the entire game |
4 | Two Block | Two different pieces are randomized and given throughout the entire game |
5 | One 7-bag | The same 7-bag looped forever |
6 | One 14-bag | The same 14-bag looped forever |
7 | C2Sim | Simulation of the Cultris II randomizer |
8 | Repeat+7b | 7-bag but repeats one piece at random |
9 | BSblock+7b | 7-bag but inserts a non-tetromino or a big block into the bag at random |
10 | BigBlock+7b | 7-bag but inserts a big block into the bag at random |
Default: 0
Type: Integer between 0 and 3
Specifies the garbage blocking method.
Available garbage blocking methods:
- Full (can offset garbage, garbage isn't inserted while in combo)
- Limited (can offset garbage, garbage can be inserted while in combo)
- None (can't offset garbage, garbage can be inserted while in combo)
- Instant (garbage is inserted the moment it's received)
Default: 0
Type: Integer between 0 and 5
Specifies the amount of previews available to the player.
Default: 5
Usermode exclusive!
Type: Boolean
Specifies whether full lines are cleared or not.
Default: true
Type: Integer between -1 and 5000
Enforces specified DAS value. If DAS is -1
, the user setting is used.
Default: -1
Type: Integer between -1 and 5000
Enforces specified ARR value. If ARR is -1
, the user setting is used.
Default: -1
Type: Integer between -1 and 1
Enforces the presence (or lack) of the ghost piece.
Available settings:
- User setting is used.
- Ghost is disabled.
- Ghost is enabled.
Default: -1
Usermode exclusive!
Type: Double between 0 and 1000
Specifies the score multiplier.
If the score change would end up being decimal, the score change gets rounded to the nearest integer.
Default: 1
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | I | O | T | L | J | S | Z |
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | - | - | - | - | - | - | - |
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | BI | BO | BT | BL | BJ | BS | BZ |
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | - | - | - | - | - | - | - |
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | I5 | V5 | T5 | U5 | W5 | X5 |
Also known as | - | - | - | U | W | X |
Piece ID | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | J5 | L5 | S5 | Z5 | TL | TJ |
Also known as | - | - | N' | N | Y | Y' |
Piece ID | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | OZ | OS | TS | TZ | LL | JJ |
Also known as | P | Q | F | F' | Z5 | S5 |
Piece ID | 0 | 1 | 2 | 3 |
---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
Piece name | I1 | I2 | I3 | L3 |
Also known as | O1 | - | - | V3 |
All-29 does not contain any pieces.
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | - | - | - | - | - | - | - |
Piece ID | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Image | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Piece name | - | O+ | - | - | - | - | - |
Handle this set with care, as those pieces are made out of hurry-up garbage.
These pieces are invisible in queue and in hold.
Piece ID | 0 | 1 |
---|---|---|
Image | ![]() |
![]() |
Piece name | INV | NONE |