Open Hexagon Workshop Tutorial

Workshop Tutorial

This document will guide you through the process of creating a new Open Hexagon level pack and upload it on the Steam Workshop.

Getting Started

Prerequisites

Open Hexagon uses Lua as the main scripting language for custom levels, alongside JSON for level metadata and configuration files.

It is recommended to be somewhat familiar with both languages before diving into Open Hexagon content creation, but if you’re feeling brave and have previous programming experience you can just try to “wing it” by modifying existing levels and learning on the fly. A quick and fun way of learning the syntax of the above languages is the “Learn X in Y minutes” website:

Content Structure

Open Hexagon custom content is organized in the following hierarchy:

Therefore, the main unit of work that can be published and installed is a pack. Inside a pack, you can have an arbitrary number of levels, musics, scripts, and styles. A completed level requires a level .json metadata file, music .ogg file, music .json metadata file, level .lua script, and a style .json file. All the separate files are linked together by textual identifiers, specified in the .json metadata files.

Creating your First Custom Level

The easiest way to get started is to subscribe to the “Example Workshop Level” on the Steam Workshop, navigate to its contents (usually C:/Program Files (x86)/Steam/steamapps/workshop/content/1358090/2157745755), and copy-paste that folder into your Open Hexagon/Packs/ folder1.

After that, rename the pasted 2157745755 to something else (e.g. MyFirstPack), and start exploring its contents with your favorite text editor (personally, I use Visual Studio Code).

Delete the Example Workshop Level.workshop.json file (as it will be generated automatically when you upload your pack to the workshop), and the preview image .png file, as you will provide one yourself later.

Start by taking a look at pack.json - there are multiple fields to change. Note that Open Hexagon expects every single level pack to have a unique id - therefore, to minimize the chance of collisions between packs made by different authors, you should specify a sufficiently unique "disambiguator" that is very unlikely someone else might accidentally use. Such field will not be displayed in game, so it can be completely arbitrary. The rest of the fields also participate in the calculation of the final pack id, so all of your packs can share the same "disambiguator", provided that they do have different names (as they rightfully should). The "version" field is useful for keeping track of changes and updates of your custom level pack. You should bump it up by one whenever you make changes to your pack and re-upload it to the workshop.

After that, you should explore the other folders and see how things work. The .json and .lua files are commented, so you should have enough context to figure out how things are linked together and what role they play.

The level logic is stored in Scripts/Levels/examplelevel.lua. Please refer to the Lua Reference to figure out what the used functions do, and to discover new functions to play around with. You will notice a bunch of u_execScript calls at the top of the Lua file - these are other scripts that the level script depends on. Dependencies should always be provided as part of your pack folder2.

Now it’s up to you! Explore the dependencies, experiment with the code, add your own music3, and - when you’re satisfied - share your pack on the workshop and ask for feedback from other players, in order to perfect it. Keep in mind that you can join our official Discord before or during level development to ask for help and share your ideas - see Where to get Help for more information.

Uploading to the Steam Workshop

The current recommended way of uploading your level to the Steam Workshop is to use the provided OHWorkshopUploader.exe command-line tool available in your Open Hexagon folder4.

When running the tool, you’ll see a few options:

Enter one of the following options:
0. Create a new workshop item.
1. Upload contents of an existing workshop item.
2. Set preview image of an existing workshop item.
3. Exit

If you intend to upload a brand new level, then write 0 and press enter. On success, the program will give you back a workshop item id:

Successfully created new workshop item: 2165863494.

Copy that id to your clipboard as you’re going to need it for later. Once you have finished creating and testing your custom level, you should have a folder under Packs/ containing all its data. To upload it, write 1 and press enter. You will be prompted to enter the workshop item id you want to upload data to - you should now paste the id you previously copied5.

You will then be prompted to enter the path to the folder containing the data. Please insert an absolute path to the pack folder (e.g. C:/MySteamLibrary/common/Open Hexagon/Packs/MyFirstPack) and keep following the instructions on screen. Your data should now be uploaded to the workshop.

Finally, you can write 2 and press enter to add a preview image to your workshop item. A 620x620 .png image is recommended for this task - you will need to provide an absolute path to the image similarly to what you have done in the previous step.

Lua Reference

Below is the full reference for all of the Lua functions that you can use in the entire game.

Core Functions

Below are the Core Functions, which are the base functions that help the game assemble the level together and make the level playable. Some of these functions are required and they must be implemented in order for your level to work, while others are completely optional and can be implemented to help assist you in completing certain tasks.

Utility Functions (u_)

Below are the utility functions, which can be identified with the “u_” prefix. These are overall functions that either help utilize the game engine, be incredibly beneficial to pack developers, or help simplify complex calculations.

Message Functions (m_)

Below are the message functions, which can be identified with the “m_” prefix. These functions are capable of displaying custom messages on the screen which can help pack developers communicate additional info or anything else useful (e.g Song Lyrics) to the players. For keeping track of statistics, please look at l_addTracked.

Main Timeline Functions (t_)

Below are the main timeline functions, which can be identified with the “t_” prefix. These are functions that have effects on the main timeline itself, but they mainly consist of waiting functions. Using these functions helps time out your patterns and space them in the first place.

Event Timeline Functions (e_)

Below are the event timeline functions, which can be identified with the “e_” prefix. These are functions that are similar to the Main Timeline functions, but they instead are for the event timeline as opposed to the main timeline. Use these functions to help set up basic events for the game. More advanced events must be done with pure Lua.

Level Functions (l_)

Below are the level functions, which can be identified with the “l_” prefix. These are functions that have a role in altering the level mechanics themselves, including all level properties and attributes. These typically get called en masse in onInit to initialize properties.

Style Functions (s_)

Below are the style functions, which can be identified with the “s_” prefix. These are functions that have a role in altering the attributes of the current style that is on the level. Style attributes, unlike level attributes, do not get initialized in Lua and rather are pre-made in a JSON file (but this is subject to change).

Wall Functions (w_)

Below are the basic wall functions, which can be identified with the “w_” prefix. These are the functions sole responsible for wall creation in the levels. There are a variety of walls that can be made with different degrees of complexity, all of which can be used to construct your own patterns.

Custom Wall Functions (cw_)

Below are the custom wall functions, which can be identified with the “cw_” prefix. These are 2.0 exclusive functions with foundations of Object-oriented programming to allow pack developers to customize individual walls and their properties and make the most out of them.

Miscellaneous Functions

Below are the miscellaneous functions, which can have a variable prefix or no prefix at all. These are other functions that are listed that cannot qualify for one of the above eight categories and achieve some other purpose, with some functions not meant to be used by pack developers at all.

Where to get Help

The Open Hexagon community is active on the official Discord server. The server contains many channels, including #pack-dev which is dedicated to level pack developers (and is the recommended place to ask for help and share your progress and ideas), and #source-dev which is dedicated to development on the Open Hexagon engine (which is open-source and available on GitHub).

The official Discord server is also a great place to share your levels and get feedback before uploading them to the Steam Workshop.


  1. If you are not sure where Open Hexagon is installed, you can navigate to the folder by right-clicking on Open Hexagon in your Steam library, selecting “Properties”, going to the “Local Files” tab, and then clicking on the “Browse Local Files” button.↩︎

  2. It is possible that in the future I will implement a solution to share dependencies between different packs, but that is not available yet and it is not a priority. For now, think of a level pack as a standalone self-contained entity.↩︎

  3. Please ensure that the music files you upload to the Steam Workshop are not protected by copyright laws. If they are, you should get explicit permission from the copyright owner for them to be used as a custom Open Hexagon level, and always credit the original artists as part of your workshop item description.↩︎

  4. If you are not sure where Open Hexagon is installed, you can navigate to the folder by right-clicking on Open Hexagon in your Steam library, selecting “Properties”, going to the “Local Files” tab, and then clicking on the “Browse Local Files” button.↩︎

  5. Or any existing id for a workshop item you own, if you intend to update it rather than creating a new one.↩︎