Options
All
  • Public
  • Public/Protected
  • All
Menu

Wayward Modding Guide

Table of Contents

Intro

Wayward is primarily built using HTML5 technologies and uses TypeScript (a strict superset of JavaScript), which compiles down to normal JavaScript. This is then run through Electron, a cross-platform application that runs browser languages as a desktop app, outside of your browser.

You are not required to use TypeScript in your mods; however, it will become harder to maintain and manage your mods using standard JavaScript. Plus, with TypeScript you will get auto-completion on all our internal functions and hooks. TypeScript also has strict compilation and error checking, removing a lot of debugging work. This guide is only tailored towards building TypeScript modifications for Wayward.

Wayward uses a combination of HTML, CSS, JavaScript, and WebGL (shaders) for all rendering and UI. It is not necessary to have skills and knowledge in these things to begin modding, although it wouldn't hurt.

NOTE: Wayward modding support is Early Access (or beta), just like Wayward itself. Many things will change and improve over time. Let us know any issues you run into or if you have any ideas for us.

Workflow/Editor

Follow along in this section if you are not familiar with TypeScript. To compile and write mods for Wayward, you will need an IDE or editor that supports TypeScript. If you are comfortable with the likes of Node.js and NPM you can set up TypeScript yourself with a variety of editors including Sublime, Atom, WebStorm, Visual Studio and more. Visit the TypeScript website for more information. This guide will use a Visual Studio Code setup below if you need help getting started.

Visual Studio Code

Visual Studio Code is a free, cross-platform, open source editor from Microsoft written with JavaScript and deployed via Electron, just like Wayward! It has built-in support for TypeScript.

Download Visual Studio Code here: https://code.visualstudio.com/Download

Install it with the default options/settings.

Node.js/NPM/TypeScript

Before you can build/compile in Visual Studio Code (or other editors/IDEs) you will need Node.js (with NPM) and TypeScript. Download and install Node.js (using the default installation settings): https://nodejs.org/en/download/

Once you install Node.js, you will have access to NPM, or "Node Package Manager", which allows you to install TypeScript. Open your terminal (Linux/Mac OS X) or command prompt (Windows) and run the following command:

npm install -g typescript

Wayward Schemas

Modding for Wayward requires the use of a few JSON files. To make it easier to edit these files, we've written an extension for VSCode that adds schemas for them. You can install it by searching for "Wayward Schemas" in the extensions tab of VSCode, or check it out on the Visual Studio Code Marketplace. If you're not using VSCode, you can feel free to extract our schemas from the repository and use them in another editor/IDE.

Examples

All official Wayward modifications are open source, allowing you to see how to mod various elements of Wayward. We have a GitHub organization with repositories for all our mods and examples located here: https://github.com/WaywardGame

If you are familiar with Git and/or GitHub, checking out or cloning the repositories should be fairly self-explanatory. If you are not familiar, you can simply browse the files in each repository for the mods. Clicking on the files will display their contents. There is also a "Download ZIP" option after clicking the "Clone or download" button, located near the top right-hand side of each of the main repository pages which will download a .zip file, containing all the resources to view the files and edit them on your computer.

If you are not familiar with Git or GitHub at all and want to learn, we would suggest you try out GitHub Desktop: https://desktop.github.com/

GitHub Desktop also has a handy help section to you get started:

Hooks & Methods

Wayward features a suite of methods to be used when making mods, adding new functionality into the game. Such things as adding keybinds, messages, items, and more are all done through our provided methods.

A full listing of the methods and hooks provided out of the box can be found in the mod class: Class Mod

The main functionality of Wayward modding comes from hooks. Hooks are special places in our code where we have enabled mods to overwrite or modify functionality within Wayward. If you are not familiar with hooks, you will see how they can be used in the Hello World section below.

For a listing of the game's hooks (details of which can be seen in the Mod class), view the full enumeration: Enumeration Hook

Hello World

Modding Intro

This section assumes you have an editor capable of compiling TypeScript files, and uses Visual Studio Code as a reference for keybinds and functionality. It should also be noted that this is not a TypeScript tutorial. If you want to learn the TypeScript language, please read through the official Handbook.

The first step in developing a Wayward modification is setting up the primary files. You can skip this guide and file setup by downloading/checking out (via GitHub) the Hello World mod in its entirety here: https://github.com/WaywardGame/helloworld

For the sake of this tutorial, we will use the "mods" directory within the Wayward Steam directory as the base for your modification. You can get there by clicking the "Open Mods Folder" button inside of the "Mods" menu while in Wayward. Alternatively, you can right-click Wayward from your Steam library and click "Properties". From there you can click the "Local files" tab and select "Browse local files". You are looking for the folder called "mods" within the Wayward folder/directory.

Setup

After you are inside the "mods" folder, create a new folder called "helloworld". Inside there, create the following files and folders:

  • /.vscode/tasks.json
  • /mod-reference/
  • /lang/english.json
  • mod.json
  • tsconfig.json
  • HelloWorld.ts

NOTE: Having trouble creating a .vscode folder in Windows? Take a look in the Frequently Asked Questions for the solution.

helloworld/.vscode/tasks.json

Visual Studio Code needs to know that we want to build our mods with TypeScript. Adding a tasks.json file in a new folder named ".vscode" with the following inserted will build your project with Ctrl+Shift+B.

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "watch",
            "type": "shell",
            "command": "tsc",
            "args": [
                "--watch"
            ],
            "isBackground": true,
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": []
        },
        {
            "label": "build",
            "type": "shell",
            "command": "tsc",
            "group": "build",
            "problemMatcher": []
        }
    ]
}

helloworld/mod-reference/

The contents of this folder is located here: https://github.com/WaywardGame/mod-reference/

Refer to the Examples section if you are not familiar with GitHub.

It is recommended you keep this up to date with what is located on GitHub as this will change from version to version of Wayward. This folder contains all the definitions for functions in Wayward so that TypeScript can auto-complete and compile your mod properly.

helloworld/mod.json

You can think of the mod.json file as the description file for your mod. It describes what it does and how it behaves. It does this through a set of properties, which we will describe below. It should be updated every time you publish it to Steam. Here's a sample of what it should look like for Hello World:

{
    "name": "Hello World",
    "description": "Hello World is an example mod, shown in the Modding Guide, located here: https://waywardgame.github.io/",
    "version": "1.0.0",
    "author": "Your Name Here",
    "compatibleMinorVersions": [
        6
    ],
    "unloadable": true,
    "file": "HelloWorld.js",
    "languages": [
        "lang/english"
    ]
}

The following is an explanation of some of the properties in this mod.json file:

compatibleMinorVersions only allows the mod to load in 2.6.x.

unloadable makes it so the mod doesn't have to be enabled when loading a world which had the mod loaded previously.

languages looks for a language file with the appropriate JSON-based formatting of defined language strings in your mod so others can translate it. It's not required for all mods.

To see a complete list of the properties you can use in your mod.json, and more in-depth details of the properties used in this example, see the mod.json section.

helloworld/tsconfig.json

tsconfig gives instructions for how TypeScript should compile your project.

{
    "compilerOptions": {
        "target": "es6",
        "module": "amd",
        "declaration": true,
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "inlineSourceMap": true,
        "baseUrl": "./mod-reference/definitions",
        "types": [],
        "experimentalDecorators": true
    }
}

This will be the same across all your mods generally. If you want to know more about the tsconfig file, review the TypeScript Documentation.

helloworld/HelloWorld.ts

With all of that preparation taken care of, it's now time to start working on the actual mod. We're going to stay pretty simple, since this is an introductory tutorial — this means we're only going to have one script file, which is HelloWorld.ts.

Let's start with the basics:

import Mod from "mod/Mod";

export default class HelloWorld extends Mod {
}

In the first line, we "import" the Mod class. This is an abstract class (it can't be used on its own) which contains default functionality that mod developers can build off of.

All mod entry files (the file property in the mod.json) must export default a class which extends Mod. We've done that, so at this point, our mod is actually functional, although it does absolutely nothing.

You can compile your script with "Ctrl+Shift+B" by default in HelloWorld.ts. After it is compiled, you will see a bunch of new files in your helloworld directory. These are the files Wayward will use. If you load Wayward, under "Mods", you will now see your Hello World mod under "Local Mods".

Mod Loading Cycle: Displaying a Message To the Console

How about we start adding some functionality?

If you open the Options Menu in Wayward, and scroll down to the bottom (or use the Developer tab) you'll see a checkbox for enabling "Developer Mode". Enable it. You now have some more options available, including being able to open the Chromium Developer Tools. You can use the bindable F10 to open it or use the "Toggle Developer Tools" button in the Developer section of the menu.

With the Developer Tools open, you now have access to the Console, which is where the game logs "debug" information. This is by far the easiest way to figure out why your code isn't working: You can log the values of variables or expressions to the console to figure out why something didn't do what you expected.

Of course, our mod is going to be so simple that we shouldn't need to debug anything. Regardless, let's log some information anyway.

import Mod from "mod/Mod";
import Log from "utilities/Log";

let log: Log;

export default class HelloWorld extends Mod {
    public onInitialize() {
        log = this.getLog();
    }

    public onLoad() {
        log.info("Hello World!");
    }

    public onUnload() {
        log.info("Goodbye World!");
    }
}

You'll notice we've imported something new, the Log class. We're only going to use that class to specify the type of a variable.

First off, we create a variable in the top scope of our file (so that it's easy to access) and name it log. We give the variable our imported Log type. We'll store the actual mod log in it later.

At this point, you may be wondering what "hooks" actually are. In Wayward, there are specific places in the base game's code where we allow mods to manipulate the functionality. Each of these places is called a "hook" (we're going to use some of these in a short while). There is another kind of "hook", which you can consider "mod loading cycle" hooks. Basically, as the state of your mod changes, your mod can do any required initialization or de-initialization.

Here's a list of all of these "mod loading cycle" hooks:

  • onInitialize:
    • Executed when your mod initializes or becomes enabled. This happens in two places:
      1. As Wayward is loaded, if your mod is enabled.
      2. When your mod is enabled via the Mods menu.
    • Usually used for complex mod registrations, or setting up custom functionality. You can also use it to load and interact with global save data for your mod.
  • onUninitialize:
    • Executed when your mod is disabled via the Mods menu.
    • This hook should be used to remove any custom functionality that was added by your mod. Making use of this hook will allow users to enable or disable the custom functionality you provide at will.
  • onLoad:
    • Executed when you load a Wayward save (this includes starting a new game).
  • onUnload:
    • Executed when a Wayward save is unloaded (the user closes the game or quits to the main menu).
  • onSave:
    • Executed before onUnload.
    • Used to save data for your mod.

Armed with this additional knowledge, you'll see that we used three of these "mod loading cycle" hooks for our mod:

  • When our mod initializes (onInitialize), we store its log (this.getLog()) in our log variable.
  • When a save is loaded (onLoad), we log "Hello World!"
  • When a save is unloaded (onUnload), we log "Goodbye World!"

If you test the mod at this point with the console open, you'll see that when you load a save, "Hello World!" is logged, and when you exit a save, "Goodbye World!" is logged. The logged messages will also be added to the log file which is saved on disk.

Registrations and Hooks

So, our mod actually does something now, but if a player installed it, it wouldn't actually seem like it did to them. Why don't we send a "Hello World!" message to the player?

To log messages, we're going to need to need a bunch more imports. We need HookMethod, Message, MessageType, and Register. You can try to guess the path of an import, but it's fastest to just start typing it and allow VSCode/TypeScript to suggest the import for you (press Tab when the correct import suggestion is highlighted). You can also use the TSLint import fixer.

import { Message, MessageType } from "language/IMessages";
import { HookMethod } from "mod/IHookHost";
import Mod from "mod/Mod";
import Register from "mod/ModRegistry";

export default class HelloWorld extends Mod {

    @Register.message("HelloWorld")
    public readonly messageHelloWorld: Message;

    @HookMethod
    public onGameScreenVisible(): void {
        localPlayer.messages.send(this.messageHelloWorld);
    }
}

Note: The old logging code has been removed for clarity.

You'll notice two new surprising things here, decorators! We use `@Register.message()to register a "message" in the game, and@HookMethodto register ouronGameScreenVisible` hook.

When you're adding new stuff to the game, most of the time you'll be using the @Register decorators. These usually go on fields, but can sometimes also decorate methods (such as actions, commands, and options sections). The field is "injected" with the ID of your added thing, in this case it injects the ID of the message which we can then use anywhere a message is required.

  • In old versions of Wayward, registration was done with simple .add methods, such as .addMessage(<name>, <message>). This was changed because it was impossible to know whether the method should be called in onInitialize or onLoad, and also for simplicity & consistency: Now every registration requires a field which will be injected with the value.

In the last section, we touched on the hooks from the "mod loading cycle". These hooks did not require the @HookMethod decorator — this is because they are always called for every mod. All other hooks, on the other hand, are only called if they're decorated with @HookMethod.

  • This is to improve the efficiency. Say there are a hundred mods enabled — whenever a hook is called, if not for requiring the decorator, the game would have to call that hook for every one of those hundred mods, pointlessly!
  • @HookMethod also provides another benefit: You can provide a "priority" for your hook, to allow it to be called before or after the same hook in another mod (we won't need that in ours).

To wrap up what we've covered:

  1. We register a message by the name "HelloWorld" into the field messageHelloWorld.
  2. We register a hook, onGameScreenVisible, and inside it, we send our registered message to the local player.

The Translation System

If you run the mod at this point and load a game, you'll see that it actually doesn't log Hello World, it logs Message.ModHelloWorldHelloWorld. What gives?

Well, what it logged was the internal "translation ID" of our message. We haven't actually provided an English translation of our message yet. Let's set this up now.

In lang/english.json:

{
    "extends": "English",
    "dictionaries": {
        "message": {
            "modHelloWorldHelloWorld": "Hello World!"
        }
    }
}

This is all we need at this point. Let's navigate through the JSON file to understand what it's doing.

  • extends — This is the language we're adding translations to. In this case, we're adding to the language of the base game, English.
  • dictionaries — This is an object indexed by the names of dictionaries, with each value being an object containing translations.
    • message — In our script, we've only registered an entry to the message dictionary. In this dictionary, we map the message name to the translation.
      • modHelloWorldHelloWorld — Wait, Message...modHelloWorldHelloWorld... this is what was logged in the console! Yes, if you see untranslated text, it's providing the exact location in the language.json file to translate it. In this case, we translate our message to "Hello World!"

Renaming Things at Run Time & Other Ways to Greet the Player

import { Direction, EquipType, ItemType } from "Enums";
import { IItem } from "item/IItem";
import { itemDescriptions } from "item/Items";
import { Message } from "language/IMessages";
import { HookMethod } from "mod/IHookHost";
import Mod from "mod/Mod";
import Register from "mod/ModRegistry";
import IPlayer from "player/IPlayer";
import terrainDescriptions from "tile/Terrains";
import TileHelpers from "utilities/TileHelpers";

export default class HelloWorld extends Mod {

    @Register.message("HelloWorld")
    public readonly messageHelloWorld: Message;
    @Register.message("HelloLeftHand")
    public readonly messageHelloLeftHand: Message;
    @Register.message("HelloRightHand")
    public readonly messageHelloRightHand: Message;
    @Register.message("HelloTerrain")
    public readonly messageHelloTerrain: Message;

    public onLoad() {
        // we change the name of the "branch" item to "greetings stick"
        itemDescriptions[ItemType.Branch].prefix = "a ";
        itemDescriptions[ItemType.Branch].name = "greetings stick";
    }

    @HookMethod
    public onGameScreenVisible() {
        // we send a "hello world" message to the local player, using the "good" type (green)
        localPlayer.messages.type(MessageType.Good)
            .send(this.messageHelloWorld);
    }

    @HookMethod
    public onItemEquip(player: IPlayer, item: IItem, slot: EquipType) {
        // if the item that is being equipped is *not*, a "greetings stick", we're not going to touch it
        if (item.type !== ItemType.Branch) return;

        // we changed the branch item to be called the "greetings stick", now let's add some extra functionality to it
        // we send the player a message, saying hello to whichever hand the branch was equipped to
        player.messages.send(slot === EquipType.LeftHand ? this.messageHelloLeftHand : this.messageHelloRightHand);
    }

    @HookMethod
    public onMove(player: IPlayer, nextX: number, nextY: number, tile: ITile, direction: Direction): boolean | undefined {
        const tileType = TileHelpers.getType(tile);

        // we send a message to this player with the type "stat" (orange)
        player.messages.type(MessageType.Stat)
            // we first list which message we're sending, then we list all the arguments we're giving to that message.
            // in this case, the only argument we're giving it is the name of the tile we're standing on
            .send(this.messageHelloTerrain, terrainDescriptions[tileType].name);

        return undefined;
    }
}

In our hook for when the game screen becomes visible, we now rename a branch to a "greetings stick". In the future, this will also be done with language extensions, but for now, you have to do it through the descriptions of objects (it would look the same for changing the name of a creature or the name of a doodad, etc.).

When the "greetings stick" is equipped, using the onItemEquip hook, we send a message depending on which hand it was equipped to.

We also say hello to the world literally, by hooking into onMove, and sending a message with the name of the terrain the player is moving to.

helloworld/lang/english.json

To finish up the mod, let's add translations for the rest of our messages.

{
    "extends": "English",
    "dictionaries": {
        "message": {
            "modHelloWorldHelloWorld": "Hello World!",
            "modHelloWorldHelloLeftHand": "Hello Left Hand!",
            "modHelloWorldHelloRightHand": "Hello Right Hand!",
            "modHelloWorldHelloTerrain": "Hello {0}!"
        }
    }
}

The {0} in the modHelloWorldHelloTerrain translation is called an "interpolation". Basically, it means the first thing sent with the message is printed at that spot in the message. {1} would print the second thing sent with the message. In our case, we do .send(this.messageHelloTerrain, terrainDescriptions[tileType].name); — the message to send, and then the name of the terrain. So the message ends up being "Hello <name of terrain>!"

What's Next?

That's the end of the Hello World tutorial. Congratulations for making it this far! If you understand what you've done, you'll probably do fine with the rest of Wayward modding. And if you ever have questions you can always feel free to ask us in the #modding channel of our Discord.

  • To see the Hello World repository, visit the GitHub. There's some additional documentation & comments in the file.
  • To learn more about the JSON files used for Wayward modding, continue into the next section.
  • Or you could start your own mod! Do something crazy, like making all the creatures say "hello world". That would be intense!

JSON Specifications

Besides the required mod.json file, Wayward has support for a variety of JSON files that add/modify functionality without the need for coding and compiling a full modification. Currently, there is support of image replacements, language translations, and character customizations.

If you're using VSCode, we recommend installing our Wayward Schemas extension, as this will help you write your JSON files correctly, and provides some of the same information as in this documentation.

This section will elaborate on the various JSON files you may need to write when making a Wayward mod.

mod.json

The mod.json file is what tells Wayward that your mod folder is a mod, and provides information such as the version it can run on, the version it is, its name, and more. The following is a specification of what properties will appear on your mod.json files.

compatibleMinorVersions will stop your mod from being loaded if the Wayward's game version doesn't match what is set in the array. If you have "6" set here, and Wayward beta version 2.6.0 is loaded, then it will run. If you have it set as "compatibleMinorVersions": [ 5 ], then it will only work in version 2.5.0. "compatibleMinorVersions": [ 5, 6 ] will load in both versions 2.5, and 2.6. You may omit this property if you always want your mod to run, regardless of the game version (this is not recommended as our API changes between versions).

unloadable should be set to true if you are not adding new things into the game which modify the save data. If you are creating a mod that adds new monsters, items, doodads, or terrain you will want to set this to false or omit it completely.

dependencies is a list of mods that your mod needs. For instance, if you wanted to extend the functionality of another mod, or use utility functions provided by them. The property takes an array of strings representing Steam Workshop IDs. Your mod won't be loaded if the dependencies aren't installed and enabled.

"dependencies": [
    "474819610"
]

imageOverrides is a property that will allow you to override default graphics in the game. When set to true ("imageOverrides": true), it will load a dedicated imageOverrides.json file containing the overrides. This property isn't required, as not providing it is the same as setting it to false.

languages is a property that will allow you to provide a language without requiring scripts. It takes an array of paths to language JSON files. Omitting the property loads no language files. The property will look like this:

"languages": [
    "pirateLanguage",
    "spaceLanguages/glaknarLanguage"
]

This example would attempt to load the language files <modName>/pirateLanguage.json and <modName>/spaceLanguages/glaknarLanguage.json

customizations is a property that will allow you to provide character customizations. When set to true ("customizations": true), it will load a dedicated customizations.json file containing the overrides. Omitting this property is the same as setting it to false.

stylesheets is a property that automatically appends CSS stylesheets as your mod is initialized, and removes them as your mod is uninitialized. It takes an array of strings representing the paths to your stylesheets. The property will look like this:

"stylesheets": [
    "mainStyle",
    "moreStyles/anotherStyle"
]

This example would attempt to load the language files <modName>/mainStyle.css and <modName>/moreStyles/anotherStyle.css. You can also see this property in action in our Debug Tools mod.

publishedFileId is a property that is automatically filled in after your mod is published to the Steam Workshop. Do not modify or manually add this property. Wayward will use this when you publish updates to your mod.

imageOverrides.json

The imageOverrides.json file will allow you to override default graphics in the game. The file is not required, and will only be loaded by setting the imageOverrides property of your mod.json to true.

Here is an example of how the file could look:

[
    {
        "replace": "doodad/sprucetree",
        "imagePath": "doodad/specialTree"
    },
    {
        "replace": "doodad/mapletree",
        "imagePath": "doodad/superSpecialTree",
        "animated": true
    }
]

The replace property specifies the default graphic path, and the imagePath property specifies the mod's path for the image. The .png is appended automatically. If the imagePath property is not provided, it defaults to using the same path as replace.

The animated property takes a boolean representing whether or not the image is an animated strip. If the property isn't provided it defaults to false.

You can see an example of image overrides in action in the Trees on Fire mod.

language.json

A language JSON file contains all translations of a language, without requiring scripts, as was the case in versions < 2.3. The file name can be anything as long as it ends in .json Here's an example file:

{
    "name": "such language",
    "shouldPluralize": true,
    "dictionaries": {
        "item": {
            "branch": ["", "real branch", "wow very branch"]
        }
    }
}

A description of the properties is as follows:

name is the name players will see in the language selector dropdown.

shouldPluralize determines whether or not names should be pluralized.

extends is used to extend another language (such as English)--rather than providing the name parameter, you may provide this parameter, set to the name of the language you are extending (important--make sure extends is set to a string identical to the name parameter of the extended language, or else it will not work). When using extends, shouldPluralize has no effect. Dictionary entries afterward will overwrite any entry already set in the language.

dictionaries is an object containing the dictionaries with translations. Each dictionary you provide is an object containing entries in the dictionary, which are arrays containing the translation.

The format of a translation is [string, string, string, string], where the strings, in order, represent the prefix, the name, the description, and the suffix.

You can see an example of custom languages provided via a JSON file in the Pirate Language mod.

customizations.json

The customizations.json file will allow you to provide extra customizations for character creation (hairstyles, hair colors, and skin tones). The file is not required, and will only be loaded by setting the customizations property of your mod.json to true.

Here is an example of how the file could look:

{
    "skin-colors": [
        "#ff0"
    ],
    "hair-colors": [
        "#ff0"
    ],
    "hair-styles": [
        "Braid",
        {
            "name": "Pigtails",
            "imagePath": "specialHairstyles/Pigtails"
        }
    ]
}

Skin colors and hair colors each take an array of strings representing colors in hex. The # is not required. When providing 3 characters, each character is doubled. For example, ff0 is the same as ffff00. This functionality mirrors the functionality of web browsers (CSS).

Hair styles takes an array of strings or objects. When a string is provided, the mod attempts to load the sprite from <modName>/static/image/hairstyle/<hairstyleName>.png. When an object is provided, if the imagePath property is set, it will use this as the path to the hairstyle sprite instead.

Top-level properties of the file can be left out if you have no customizations of that kind to provide.

You can see an example of customizations in action in the Ridiculous Hairdos mod.

Debugging

You can open the developer tools at any time within Wayward by clicking the "Toggle Developer Tools" button located in the bottom of the options menu. You can execute arbitrary code while this menu is opened, log console commands, explore native functions and definitions, inspect UI elements, and more.

If you want them to start open by default when you run Wayward, you can open the launch_options.json file within the root directory of Wayward on Steam, and change the following line: "devtools": false, to "devtools": true,.

We would also recommend subscribing to and enabling the "Debug Tools" mod, available on the Steam Workshop. This mod allows the changing of tiles, spawning of items, creatures, doodads, refreshing stats, adds noclip/teleportatation, allows removal of all creatures, and more!

Publishing

After you are happy with your mod, why not publish it to Steam Workshop? You will be able to edit most things via the Steam interface after publishing it, but you'll want to include a few things before releasing it as described below.

NOTE: Please do not upload the Hello World modification to the Steam Workshop. Make something fun!

If you place a square formatted .png image in the root mod folder named "mod.png" this will be the thumbnail/main image for the mod when it gets uploaded to the Steam Workshop. We recommend a size of 720x720 pixels, although this gets shrunk down to around 77x77; but normally appears at 268x268 inside the Workshop page, so please use 268x268 as a minimum size.

When you are ready to go, and you have performed all the steps outlined in Hello World section, upon launching Wayward and going in the Mods menu, you will see an "arrow" icon to the right-hand side of your mod. Clicking it will allow you to publish your mod to the Steam Workshop. At any point you make changes and build/compile your mod, you can simply click this again to send an update to Steam.

Everything else about your entry is controlled via Steam. This includes uploading screenshots, links, required mod displaying, stats, and more. You can quickly get to your Workshop entry by clicking the "eye" icon next to your mod in the Mods menu listing. You will see a full suite of administrative options on that page if you are logged in to Steam.

Extracting Wayward Assets

Want to extract the assets (or source files) from Wayward for modifications? The complete repository of Wayward files are located in the resources folder within the Wayward Steam directory, in an archive named "app.asar". This cannot be opened or extracted using conventional means; however, using NPM you can install a package to extract the files from this archive. Use the following command:

npm install -g asar

After it is installed, change directories to where the app.asar is located, for example:

cd "C:\Program Files (x86)\Steam\steamapps\common\Wayward\resources"

Next extract it using:

asar extract app.asar app

This will extract the full archive to a folder named "app" within the resources folder.

Full documentation on asar (Electron Archive) can be found here: asar - Electron Archive

Frequently Asked Questions

Visual Studio Code is showing errors (even in example mods) and/or cannot compile.

This is a common issue you may run into if you have followed this guide in the past but is now showing errors, even when copying over the new example mods/references. TypeScript updates will be a fairly constant thing in Wayward until TypeScript is more mature. It's possible your TypeScript installation is out of date.

You can check your current TypeScript version by opening your terminal (Linux/Mac OS X) or command prompt (Windows) and running the following command:

tsc -v

You can update it by running the install command again:

npm install -g typescript

Make sure to restart your editor before trying again.

How do I open the console in-game?

This is explained a bit in the Debugging section of this guide.

But in short: open the options menu, scroll near the bottom, and click "Toggle Developer Tools". This will open the Developer Tools which features the console.

Windows is showing a "You must type a file name." dialog when trying to rename a folder ".vscode".

You can bypass this limitation by downloading/cloning one of the example mods and just copying the .vscode folder for your own mod, or by creating the directory using the command prompt. To do so, change your directory to the location you wish to make the .vscode folder like so:

cd "C:\Program Files (x86)\Steam\steamapps\common\Wayward\mods\helloworld"

Then run the following:

mkdir .vscode

How do I upgrade my mod from version to version?

When we make significant changes to our codebase, for example: upgrading from ES5 to ES6 in beta 2.2, or moving to a modular codebase in beta 2.3, you may have to make many changes to your modification so that it runs on the latest version. This is an unfortunate side effect of still being in beta. As we move to towards a more stable, non-beta release, you may expect less of these huge changes.

As we make these changes, we always make sure our documentation (and this guide) is up to date and shows how to make mods for the current or upcoming version. You can always find the Hello World section showcasing how to create a very basic mod for the latest version. Also, we supply all our official modifications on GitHub as examples of what we do to update our own mods. You can browse the commits of each mod to see what we did as we upgraded to each Wayward version. You can even browse the repository for this guide to see what we are changing in our documentation from version to version.

How do I find out the name and path of imports?

If you are using Visual Studio Code, we recommend installing the TSLint extension. When typing names of interfaces, enums and more, TSLint will show a red squiggly line underneath if they are not imported already. After clicking on the definition/error/line, a small light bulb will appear in the left gutter. Clicking on this light bulb will allow you to automatically import the declaration. For example, typing:

ItemType

Should trigger an error with TSLint. Clicking on the line, then the light bulb, will show:

Add ItemType to existing import declarations from Enums.

or:

Import ItemType from Enums.

If you don't have any "Enums" import declarations yet. Clicking this option will add something like following to the top of your file:

import { ItemType } from "Enums"

I need more help!!!

Calm down! The community is here to help. Simply post your issue or problem in the Workshop discussion forum.

Want more of a real-time support approach? You can also try on Discord. Make sure to post in the #wayward-modding channel.

Disclaimer

By submitting a Workshop creation for Wayward, you understand that Wayward is a work in progress. As such, many things will change and be added over time. This can result in the following:

  • Your submission becoming obsolete.
  • Your submission breaking in functionality as updates are released.
  • Your submission becoming an eventual feature within the game. Sorry, Amax!

In the case of breaking functionality, we will try our best to limit such things from happening; however, due to the very nature of a beta/Early Access title, many new ideas, systems, and additions will eventually make it into Wayward. As this is the case, we cannot guarantee your Workshop submission will continue to work indefinitely, nor cannot guarantee that your submission will always be necessary as we may build certain features/functionality/content into the game directly.

Our "todo" and idea list is huge and it's likely many ideas are already planned for Wayward or were submitted to us previously. If we have in fact taken direct inspiration from your idea/submission, we will always contact you beforehand. The community and player-base have always delivered us great ideas. Steam Workshop allows for those ideas to become reality faster than they would otherwise appear in the game by us.

That being said, we hope this does not hinder you from making Wayward into whatever you want and sharing your creativity with the community.

Have fun!

Generated using TypeDoc