Skip to the content.

Libraries

Two different people use import.

Someone writing scripts in your app (a player, a modder, you in a .mini file). They import another script. No C++. No add_library.

You, the host. You register C++ or bundled packages so scripts can import math.


Import another script (end user)

Same language, same folder. The host does nothing.

mods/quest.mini
mods/helpers.mini
// helpers.mini
fn twice(n) { return n * 2; }
// quest.mini
import helpers
print(helpers.twice(3));

import helpers looks for helpers.mini (or whatever extension the language uses):

  1. Next to the file that wrote import
  2. The process working directory
  3. imports.search_directories in the language JSON
  4. Folders the host passed to add_search_path

Dots become folders: import company.utils → company/utils.mini.
A string path works if the language allows it: import "helpers.mini".
A leading relative token (import .helpers, if you set relative_import_token) searches only the importer’s folder.

The imported file runs in its own environment. It can see host binds. It does not dump its locals into the importer unless bind_as is "globals" or "both".

A player cannot import a raw .cpp / .h this way. Only same-language scripts.


Import a host library

Always there. You bind("print", ...). Every script can say print(...). No import.

A library. You add_library("math", ...). A script must say import math before it can use it.

CMake cannot do the second step. Adding a .c++ file to the executable only compiles it. Scripts see nothing until your C++ calls add_library and you pick the name ("math", "app.math", anything).

JSON only describes how scripts write the import. It does not register libraries.


Language JSON (syntax only)

"imports": {
  "enabled": true,
  "import_keywords": ["import"],
  "module_separator": ".",
  "bind_as": "namespace",
  "search_directories": [],
  "plugin_entry": "rescripted_register"
}

bind_as "namespace" → the script writes math.twice(3).
bind_as "globals" → after import math the script just writes twice(3).
bind_as "both" → both.

search_directories are extra folders for import utils when you never registered utils.
plugin_entry is the C symbol a workshop plugin should export. Default rescripted_register. Override per engine with set_plugin_entry.


A C++ library you ship with the app

1. Turn imports on in the language JSON (above).

2. Write the functions in a normal .c++ file:

// stdlib/math.c++
#include <ReScripted.h>

RESCRIPTED_LIBRARY(math) {
  lib.bind("twice", [](const std::vector<rescripted::Value>& args) {
    return rescripted::Value(args.empty() ? 0.0 : args[0].as_number() * 2.0);
  });
}

math here is only a C++ name (rescripted::library::math). Scripts do not see it yet.

3. Compile that file with the rest of the program:

add_executable(game src/main.cpp stdlib/math.c++)

4. Give it an import name when the engine starts:

#include <ReScripted.h>
RESCRIPTED_LIBRARY_DECLARE(math);

engine.add_library("math", rescripted::library::math);

Now a script can write:

import math
print(math.twice(3));

You chose the string "math". You could have used "app.math" and the script would import app.math.


Same call, other sources

add_library always takes the import name first. The second argument is “what is this library?”

What you have Call
Functions in main add_library("math", twice)
A script file baked into the binary as a string add_library("prelude", source, "Mini")
A script file on disk (mod, workshop pack) add_library("Workshop", "mods/workshop.mini") or add_library_file(...)
A normal .h / .cpp already linked into the app add_library("native", "path/to/api.h") — best-effort read of simple extern "C" prototypes
A compiled plugin (.dll / .dylib / .so) load_plugin("mods/extra.dylib") — the plugin calls add_library itself

Baked-in scripts: use rescripted_embed_language so CMake copies the file into a string. Then you still add_library and pick the name. The script does not run until something imports it.

engine.add_library("prelude", std::string(rescripted::embed::prelude), "Mini");

Normal headers

The host registers the path. ReScripted is not a C++ compiler. It reads simple declarations (int add(int, int); and similar) and looks up those symbols in the running process. Skip or fail what it cannot understand. A player script cannot drop a random .cpp on disk and import it.

On Linux, the executable must export those symbols (ENABLE_EXPORTS / -rdynamic).

Workshop plugins

The host loads an already-compiled library. ReScripted calls rescripted_register(Engine&) (or whatever you set with set_plugin_entry / imports.plugin_entry). That function typically add_librarys its packages. Same ABI as the app: include ReScripted.h, compile a shared library.

extern "C" void rescripted_register(rescripted::Engine& engine) {
  engine.add_library("extra", ping);
}
engine.load_plugin("mods/extra.dylib");

Import on every run

"standard_library": { "automatically_imported": ["math"] }

Every run() acts as if the file started with import math. You still have to add_library("math", ...) yourself.


What is not a library