Templates
After Rhai scripts have executed, MiniJinja is used for the final template substitution step.
All variables set during the workflow chain and modified by Rhai scripts are available for use in templates.
Why MiniJinja?
When looking for a suitable templating engine, I considered the following factors
-
Familiar / Ease of use:
- MiniJinja has a syntax similar to Jinja2, which is widely used.
- And very strong documentation for developers (examples).
- And countless [cheat sheets]
-
Sandboxing:
- Each file generation must be isolated from the others.
- Avoid arbitrary code execution if possible.
MiniJinja is not guaranteed to run on esoteric platforms
It is not an no_std
package, however it is modular and usage of std
is limited, with the
main library mostly uses types from alloc
and core
.
Templating engines with no_std
support are rare (unfortunately), however MiniJinja
is
known to run with WASM, which is a good sign, especially given WASM
can't use filesystem
and is thus limited.
Template Files
Template files are specified in the workflow.toml file under the [metadata]
section
[metadata]
# ... other metadata ...
files = [
"templates/package.toml"
]
These files will have their contents processed by MiniJinja, with the resulting output being written to the final mod package.
Localization in Templates
Localization keys defined in the language files are available as variables for rendering in templates.
This is also true for variables
created in metadata
and rhai scripts
!
This feature allows for complete translation of template outputs, making it possible to generate fully localized mod configurations and documentation.
Accessing Localization Keys
Localization keys can be accessed directly as variables in your templates.
This is based on the localization keys
used in the workflow.
{{ WORKFLOW_NAME }}
{{ SETTING_STAGE_NAME }}
Create or Replace a Stage
Stage Name
ステージの作成または置換
ステージ名
Example: Fully Localized Template
Here's an example of how you might use localization keys to create a fully localizable mod description:
# {{ MOD_NAME }}
{{ MOD_DESCRIPTION }}
## {{ FEATURES_HEADER }}
{% for feature in features %}
- {{ feature }}
{% endfor %}
## {{ INSTALLATION_HEADER }}
{{ INSTALLATION_INSTRUCTIONS }}
## {{ COMPATIBILITY_HEADER }}
{{ COMPATIBILITY_INFO }}
# Super Speed Mod
This mod enhances your character's speed, allowing for faster gameplay and
new speedrunning strategies.
## Features
- Increased running speed
- Improved acceleration
- Adjustable speed multiplier
## Installation
1. Download the mod file.
2. Place it in your game's mod folder.
3. Activate the mod in the Reloaded3 launcher.
## Compatibility
This mod is compatible with Sonic Heroes version 1.0 and above.
It may conflict with other mods that alter character speed.
# スーパースピードMod
このModはキャラクターの速度を向上させ、より速いゲームプレイと新しいス
ピードラン戦略を可能にします。
## 特徴
- 走る速度の増加
- 加速度の改善
- 調整可能な速度倍率
## インストール方法
1. Modファイルをダウンロードします。
2. ゲームのModフォルダに配置します。
3. Reloaded3ランチャーでModを有効にします。
## 互換性
このModはソニックヒーローズバージョン1.0以上と互換性があります。キャラ
クターの速度を変更する他のModと競合する可能性があります。
Use localization keys if you have further instructions after a template finishes rendering
This way you can ensure that any further manual instructions that a user needs to perform are also localized. For example, links to further guidance how to work with the data.
Cheat Sheet
This cheat sheet provides a quick reference for Jinja syntax
Along with Reloaded3-themed examples and their rendered output.
The MiniJinja templates can access all variables
created in metadata
, localization
and rhai scripts
.
Basic Syntax
Variable
{{ mod_name }}
Super Speed Mod
mod_name = "Super Speed Mod"
Comment
{# This mod increases the player's speed #}
Control Structures
For Loop
{% for stage in stages %}
{{ stage.name }}: {{ stage.difficulty }}
{% endfor %}
Green Hill: Easy
Chemical Plant: Medium
stages = [{"name": "Green Hill", "difficulty": "Easy"}, {"name": "Chemical Plant", "difficulty": "Medium"}]
If Statement
{% if mod_type == "gameplay" %}
This mod affects gameplay mechanics.
{% elif mod_type == "visual" %}
This mod changes visual elements.
{% else %}
This mod type is undefined.
{% endif %}
This mod affects gameplay mechanics.
mod_type = "gameplay"
This mod changes visual elements.
mod_type = "visual"
This mod type is undefined.
mod_type
is neither "gameplay" nor "visual"
Block
{% block mod_description %}
This mod enhances the game experience.
{% endblock %}
This mod enhances the game experience.
Include
{% include "mod_header.txt" %}
(The content of mod_header.txt would be inserted here)
Set
{% set mod_version = "1.2.0" %}
Mod Version: {{ mod_version }}
Mod Version: 1.2.0
Filter
{% filter upper %}
This mod is compatible with Sonic Heroes.
{% endfilter %}
THIS MOD IS COMPATIBLE WITH SONIC HEROES.
Expressions
Math
Speed Multiplier: {{ 1.5 * 2 }}
Speed Multiplier: 3.0
String concatenation
Adding two pieces of text together.
{{ "Mod by: " ~ author_name }}
Mod by: JohnDoe
author_name = "JohnDoe"
Comparisons
Is Advanced Mod: {{ mod_complexity > 5 }}
Is Advanced Mod: true
mod_complexity = 7
Logic
{{ is_gameplay_mod and is_reloaded_compatible or is_standalone }}
true
is_gameplay_mod = true
, is_reloaded_compatible = true
, is_standalone = false
Filters
Uppercase
{{ mod_name|upper }}
SUPER SPEED MOD
mod_name = "super speed mod"
Length
Number of supported games: {{ supported_games|length }}
Number of supported games: 3
supported_games = ["Sonic Heroes", "Sonic Adventure 2", "Sonic Generations"]
Default value
Mod Category: {{ mod_category|default('Uncategorized') }}
Mod Category: Uncategorized
mod_category
is not defined
Mod Category: Gameplay
mod_category = "Gameplay"
Join
Required Mods: {{ required_mods|join(', ') }}
Required Mods: Base Mod, Config Library, Input Hook
required_mods = ["Base Mod", "Config Library", "Input Hook"]
Notes
- MiniJinja doesn't support line statements or custom delimiters by default.
- Python-specific methods (like
.items()
) are not supported. Use|items
filter instead. - Tuples are treated as lists.
- Keyword arguments in filters are passed as a dictionary.
*args
and**kwargs
syntax is not supported.- The
{% continue %}
and{% break %}
statements are not supported in loops.