Skip to content

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:

  • 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
Assuming mod_name = "Super Speed Mod"

Comment

{# This mod increases the player's speed #}


(Comments are not rendered in the output)

Control Structures

For Loop

{% for stage in stages %}
    {{ stage.name }}: {{ stage.difficulty }}
{% endfor %}

Green Hill: Easy
Chemical Plant: Medium
Assuming 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.
Assuming mod_type = "gameplay"

This mod changes visual elements.
Assuming mod_type = "visual"

This mod type is undefined.
Assuming 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
Assuming author_name = "JohnDoe"

Comparisons

Is Advanced Mod: {{ mod_complexity > 5 }}

Is Advanced Mod: true
Assuming mod_complexity = 7

Logic

{{ is_gameplay_mod and is_reloaded_compatible or is_standalone }}

true
Assuming is_gameplay_mod = true, is_reloaded_compatible = true, is_standalone = false

Filters

Uppercase

{{ mod_name|upper }}

SUPER SPEED MOD
Assuming mod_name = "super speed mod"

Length

Number of supported games: {{ supported_games|length }}

Number of supported games: 3
Assuming supported_games = ["Sonic Heroes", "Sonic Adventure 2", "Sonic Generations"]

Default value

Mod Category: {{ mod_category|default('Uncategorized') }}

Mod Category: Uncategorized
Assuming mod_category is not defined

Mod Category: Gameplay
Assuming mod_category = "Gameplay"

Join

Required Mods: {{ required_mods|join(', ') }}

Required Mods: Base Mod, Config Library, Input Hook
Assuming 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.