Skip to content

Templates

BubbleFish edited this page Feb 24, 2026 · 16 revisions

Templates allow for data-driven and programmatic code generation.

Caution

Never use templates from other developers without reading their source code.

Certain templates can be calling arbitrary binaries with unrecoverable side-effects.

If a template contains a binary file, then it is best adviced to avoid using it. Always compile it from source yourself!

Define a template by creating a manifest.json file inside of templates/<your_template_id> directory.

🎯 Example
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "generator"
}

Generator Templates

As the name suggests, it generates files based on a list of definitions.

Generator Manifest

Use generator type with an optional iterators field.

🎯 Example
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "generator",
    "iterators": {
        "color": ["red", "green", "blue", "white"],
        "material": [
            ["oak", "oak_planks"],
            ["spruce", "spruce_planks"],
            ["stone", "stone_bricks"],
        ]
    }
}

Generator Iterators

Iterators are used to create generated definitions. Using the example above, we are able to define %[color]_%[material]_couch.json that will output a couch for every combination of color and material iterators, or %[color]_wool to define wool of every color, etc.

Note

In the example above, iterators.material is an array of arrays, so we can access different elements using %[material.<index>] (defaults to 0).

e.g. %[material.1] would output oak_planks, spruce_planks, etc.

Generator Definitions

Create .json files inside of definitions/ directory. The file names can optionally use defined iterators. The file name will be available as an %[id] variable.

The contents of that file can contain any keys and values. Each key will be available as a variable for substitution.

🎯 Example
// File: templates/my_template/definitions/my_item.json
{                                                                      
    "key1": "Hello World!",
    "recipe": [
        {
            "id": "bread",
            "count": 5
        }
    ]
}

Generator Files

...


Inline Templates

Inline templates are used to extend MCFunction syntax with custom contents/logic/side-effects.

The template must either define a snippet or a program to be executed when called.

Inline Manifest

Use inline type with an optional arguments field.

🎯 Example
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "inline",
    "arguments": [
        "name",
        "objective",
        "range"
    ]
}

Inline Arguments

When specified, forces .mcfunction files to call this template with these space-separated positional arguments. They then become available as %[<argument_name>] as variables.

When ommited, any arguments provided to the template will be provided untouched as the first argument. It is then program's responsibility to split it by space if needed.

Inline Snippets

Snippets replace the template invocation with the specified code by creating a snippet.mcfunction file.

%[...] variable can be used to insert any nested lines.

πŸ“ Input (1/2)
# File: templates/my_template/snippet.mcfunction
scoreboard players set #%[name] %[objective] 0
function ./_for_%[name]
    %[...]
    scoreboard players add #%[name] %[objective] 1
    execute if score #%[name] %[objective] matches %[range] run function ./_for_%[name]
πŸ“ Input (2/2)
# File: data/example/function/test.mcfunction                        
#~>for x my.tmp ..5
    #~>for y my.tmp ..10
        say 123
        say "abc"
πŸ“¦οΈ Output
# File: data/example/function/test.mcfunction
scoreboard players set #x my.tmp 0
function ./_for_x
    scoreboard players set #y my.tmp 0
    function ./_for_y
        say 123
        say "abc"
        scoreboard players add #y my.tmp 1
        execute if score #y my.tmp matches ..10 run function ./_for_y
    scoreboard players add #x my.tmp 1
    execute if score #x my.tmp matches ..5 run function ./_for_x

Inline Program

Programs are arbitrary executables that generate code. It must be an executable file named call (any extension works).

  • Positional arguments are provided as command-line arguments.
  • Any nested lines can be read from stdin.
  • All generated code should be written into stdout.
  • Any errors can be written to stderr.
  • Return a non-zero exit code for Vintage to interrupt the build process.
πŸ“ Input (1/3)
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "inline",
    "arguments": [
        "resource"
    ]
}
πŸ“ Input (2/3)
#!/bin/python
# File: templates/my_template/call.py
import sys

resource_arg = sys.argv[1]

if resource_arg == "something wrong":
    print("invalid input!", file=sys.stderr)
    sys.exit(1)

print(f"function {resource_arg} with storage minecraft:example input")

# Write nested lines without modification
for line in sys.stdin:
    print(line, end="")
πŸ“ Input (3/3)
# File: data/example/function/test.mcfunction
#~>my_template example:path
    say 123
πŸ“¦οΈ Output
# File: data/example/function/test.mcfunction
function example:path with storage minecraft:example input
    say 123

Collector Templates

As the name suggests, they collect information from specific files and then generate files based on the collected data.

The template must define a collector program and file generators.

Collector Manifest

Use collector type with a required patterns field.

🎯 Example
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "collector",
    "patterns": [
        // match all mcfunction files
        "**/*.mcfunction"
    ]
}

Collector Patterns

An array of glob patterns matching output files when they are generated.

Use the example from collector manifest.

Collector Program

Programs are arbitrary executables that collect from code. It must be an executable file named collect (any extension works).

  • The collector executable is only called once per project build.
    • Use local variables in your language of choice to store all collected data.
  • All incoming files can be read from stdin.
    • Each file ends with a null character \0.
    • EOF indicates that there are no more files to collect.
  • Any errors can be written to stderr.
  • Return a non-zero exit code for Vintage to interrupt the build process.
  • Once all files are collected, a JSON file must be written to stdout with data that will be passed along to file generators.
🎯 Example
# File: templates/my_template/collect.py
# Example python script that would collect all used translation keys.
import sys, json

en_us = {}

for chunk in sys.stdin.buffer.read().split(b"\0"):
    if chunk:
        code = chunk.decode("utf-8", errors="replace")
        key, value = extract_translation_keys(code) # TODO
        en_us[key] = value

json.dump({"en_us": en_us}, sys.stdout)

File Generator

There exist 2 types of file generators: generated & programatic.

Programatic generators are arbitrary executables that generate code. It must be an executable file with the name of output file with an executable extension (e.g. en_us.json.py).

  • Collected data should be read until EOF from stdin.
  • Any errors can be written to stderr.
  • Return a non-zero exit code for Vintage to interrupt the build process.
  • Write the output file contents into stdout.
πŸ“ Input
#!/bin/bash
# File: templates/my_template/assets/minecraft/lang/en_us.json.sh
cat # Simply write the collected data into the file
πŸ“¦οΈ Output
// File: assets/minecraft/lang/en_us.json
{
    "key1.example": "Hello World!"
}

Custom Templates

Simply runs a custom binary after all codegen, right before managing libraries and zipping the result.

The template must define a custom program.

Custom Manifest

Use custom type.

🎯 Example
// File: templates/my_template/manifest.json
{                                                                      
    "$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
    "type": "custom"
}

Custom Program

Programs are arbitrary executables that generate code. It must be an executable file named call (any extension works).

  • The first argument is the absolute path to build directory (i.e. --output).
  • Return a non-zero exit code for Vintage to interrupt the build process.
🎯 Example
# File: templates/my_template/call.py
#!/bin/bash

# Custom templates are always run after the code has finished generating.
# You can freely read/write to the build directory, which you can access from the first argument ($1 for bash).
printf "Build directory is $1!"

πŸ“€ Getting Started

πŸ“šοΈ Features

🎁 Tutorials

🎲 Extras

Clone this wiki locally