ASAR Modding Guide
Unlike the official version of shapez, the Community Edition uses a different approach to load mods. It is commonly called "ASAR modding", due to the mod files being ASAR archives. The mod loader is still quite unpolished, but is already usable enough for basic mods.
ASAR mods consist of a mod.json
mod manifest, containing the basic mod metadata, the mod code and
any additional assets. Mods are loaded as ES modules, so imports and top-level await can be used in
the code.
Adding mod.json
schema to VSCode
VSCode and its forks support autocomplete and basic verifying for JSON files using JSON Schema. A
schema for mod.json
manifests is temporarily available on skimnerphi.net and can be added to
VSCode settings file:
"json.schemas": [
{
"fileMatch": ["/mod.json"],
"url": "https://skimnerphi.net/asar_schema_v0.json"
}
],
Creating a new mod
Pick or create an empty directory that will house all mod files to be loaded. For the simplest mod, you will need just the mod manifest and a single source code file.
Example mod manifest
{
"format": 1,
"id": "my-mod",
"entry": "mod.js",
"name": "My Mod",
"description": "My first awesome mod.",
"version": "0.0.1",
"authors": [{ "name": "me", "website": "https://example.com" }],
"savegameResident": false, // = mod can be added and removed at will
}
The manifest file must be always called mod.json
and located in the root of your mod directory.
entry
field tells shapez CE what file exports the mod class. More fields are available —
check the JSON Schema or shapez CE source code for details.
Mod class definition
export default class extends shapez.Mod {
init() {
alert("Hello, world!");
}
}
(WIP) Getting shapez
autocompletion
A package containing type definitions for the shapez
global object are currently available on
skimnerphi.net. To make use of the definitions, do the following:
- Install the shapez-ce-types package:
npm i --save-dev https://skimnerphi.net/download/shapez-ce-types-0.0.0.tgz
- Ensure TypeScript knows about these type definitions by including this comment anywhere in your
project:
/// <reference types="shapez-ce-types" />
Please note that the package URL may change in the future. As this package contains types that are automatically generated from shapez CE source code, the type definitions may be partially incorrect or incomplete.
(WIP) Loading additional assets
Unlike modding in the official version in the game, assets do not have to be inlined as base64 URLs
in the source file (even though this is still an option) — they can be loaded using the
virtual mod://
protocol instead. While the utilities for this approach are still not finished,
there are some helper functions already:
this.modInterface.addStylesheet("cool_styles.css");
const cat = this.modInterface.resolve("assets/cat.webp");
// cat = "mod://your-mod-id/assets/cat.webp"
All paths in these functions are resolved relative to mod directory root, not the current file.
Resolving files without ModInterface
In places where an instance of the "mod interface" is not available, import.meta.url
can be used
instead. This approach can resolve relative paths as well:
const cat = new URL("../assets/cat.webp", import.meta.url);
// import.meta.url = "mod://your-mod-id/src/images.js"
// cat = "mod://your-mod-id/assets/cat.webp"
Dynamic metadata
Some fields of the metadata may be modified before the mod is fully constructed:
const modNames = ["Awesome Mod", "Cool Mod"];
export default class extends shapez.Mod {
constructor(metadata, ...args) {
const name = shapez.randomChoice(modNames);
super({ ...metadata, name }, ...args);
}
// ...
}
Not all fields may be changed to achieve desired effect, this is mostly useful for human-readable mod information fields.
Asynchronous mod initialization
shapez CE will await initialization of a mod if the init()
method returns a thenable. This can
be used to e.g. load additional assets, establish network connections, create and initialize Storage
instances or wait for other external events.
async init() {
// Storage API is WIP. Do not expect this to stay correct
const storage = new shapez.Storage(this.app, "mod/" + this.id);
await storage.initialize();
const file = "boot_counter.bin";
const counter = await storage.readFileAsync(file).catch(() => 0) + 1;
await storage.writeFileAsync(file, counter);
alert(`Game booted ${counter} times!`);
}
Loading a mod for development purposes
shapezio --load-mod="/path/to/mod/directory" --watch --dev
--watch
will automatically restart shapez when mod files are modified. Note that Chromium in-memory cache may affect code and assets loaded viamod://
protocol, it is recommended to use the "Disable cache" option in devtools.--dev
makes the application menu show up, as well as opens developer tools once the game starts.--hide-devtools
can be added if this behavior is annoying, developer tools can still be opened using Ctrl-Shift-I.
Packaging a mod for distribution
npx @electron/asar p "/path/to/mod/directory" "/path/to/output.asar"
Both packaged and unpackaged mods will be loaded from shapez-ce/mods
(user data directory) unless
the --safe-mode
switch is passed. Only files and directories with names ending in .asar
are
discovered automatically.
(WIP) Looking for errors
Currently shapez CE does not display most mod errors anywhere. When a mod fails at the parsing step, debugging may be extremely confusing.
To check if your mod has any errors, inspect the following field using developer console:
shapez.MODS.mods.get("your-mod-id").mod.errors;
Using the built-in debugger
shapez CE makes use of the standard Chromium developer tools, which include a code editor and
debugger ("Sources" tab). Developer tools are only enabled when running shapez CE with the --dev
command line switch. The source code editor can modify code without reloading the page or resetting
state, which is useful for experimenting.
Assuming your mod code was successfully fetched and parsed, the mod source code will appear in the
sources tree. If no entries appear with your mod ID, check for any early errors as described above.
If the mod does not appear in the mod list as an ErroredMod
, its manifest (mod.json
) might be
invalid. Currently manifest validation errors are only logged to stderr, so they might not be as
easy to see.
Linking developer tools to local files
As the mod loader does not transform any mod files, it is possible to create a mapping between loaded source code and files on the disk. In order to do this, switch to the Filesystem tab of the sources tree, then click "Add folder to workspace". Choose the directory that contains mod.json, then reload the game. Mod source code files on the Page tab should get a green dot on their icons, as long as they are loaded without errors.
Once local files are added to the developer tools workspace, editing JavaScript code and stylesheets
will both apply changes to the page and save them to the disk. Therefore, it is not recommended to
use this feature along with the --watch
command line switch.