Skybook

The Inventory Slot Transfer Simulator Project

Getting started

Having an issue?

Please provide feedback, bug reports and feature requests on GitHub. Alternatively, you can join the communities below for discussion in general.

Discord

Warning

I prefer discussion in public channel over DMs for visibility, in case someone else may have the same problems as you. Please only DM me for privacy or other concerns.

Join my Discord and get the BOTW Tools role to get access to the #botw-ist channel to ask questions about or discuss features of the IST Simulator App.

Join the BOTW Speedrunning Discord and use the #glitch-hunting channel to discuss IST in general, or get help with the glitch in #general-help, or the category channel that you are running.

QQ群

Pistonite学习交流群: 670991147

(mostly Chinese)

History

Discovery

Inventory Slot Transfer (IST) was discovered in June 2022 by zxrobbin ( Video 1, Video 2 ). It initially manifested as an innocent glitch to quickly duplicate items in Breath of the Wild. Little did we know that IST will become the most complicated glitch to ever exist in BOTW.

Around June 17, 2022, as the news spread, glitch hunters from the BOTW speedrunning community started to investigate and quickly found some patterns to the glitch.

Hundo Duplication Simulator

Meanwhile, speedrunners of the 100-percent category started to incorporate it into the route. However, even the simplest form of this glitch required tracking the exact state of the player’s inventory for every action executed, such as picking up or dropping an item. The rules and patterns of this glitch then needs to be applied at even of these steps. It was a painstaking process to manually track all the information.

Luckily, tasks that are difficult for humans are often easy for computers. On June 18, 2022, the Hundo Duplication Simulator was born. Users could type in actions such as get 1 core, and the app will display the inventory state after each step. This was a massive help for optimizing setups for speedruns because people can change one step and the app will re-calculate the state for every step afterwards. This model is still used by the simulator today.

The IST Simulator - V2

As more applications of IST are found, the glitch has found its use in categories outside of 100-percent, for example in All Shrines and All Dungeons. One of such application is Direct Inventory Corruption. However, the simulator was built in one day and did not support any cases other than the very basic rules that were initially discovered.

Now that this glitch is not specific to 100-percent. The project was renamed to IST Simulator. V2 of the simulator added GameData Inventory and more items to simulate the inventory state closer to how the game handles it. Direct Inventory Corruption support was added. People were happy.

Weapon Modifier Corruption - V3

…Until more applications of IST are found again, and the simulator being a simulator, did not support these applications because I couldn’t predict the future.

Every time a new discovery is made, it almost certainly invalidates assumptions previously made when coding the simulator, and the core has to be re-designed to incorporate the new knowledge. In November 2022, I started re-designing the core by referencing the BOTW decompilation project. This massively improved the accuracy of the simulator and supported new applications such as Weapon Modifier Corruption. The UI was also revamped, adding syntax highlighting to commands and displaying modifier information for items.

Skybook - V4

After the V3 update, a few small fixes were submitted, but no big re-architecture was made for 2 years. During this time, some minor inconsistencies were found, mostly related to GameData flags (such as champion ability and discovered tabs).

Even though the remaining edge cases are rarely hit, it was clear that we could not keep chasing these cases. If the simulator was to be improved again, it needs to fix all these cases entirely. During this time, I had theorized a new version of the simulator that uses the game itself to execute the actions. In Spring 2024, I submitted a proposal to make a POC of this new simulator as a senior project to my college, and we got a student team to work on it with me as the advisor. Meanwhile, I started working on the UI of the new simulator around December 2024. The project finished successfully and it was integrated to the project as the core for the new V4 simulator.

TO BE CONTINUED

FAQ

What is IST? What is this app?

Inventory Slot Transfer, or IST, is a glitch in BOTW that desyncs the number of items you have in the inventory and number of items the game thinks you have. For more details, check out history of the app and an overview of the glitch

I am new to IST, How do I use this tool?

You definitely don’t need to be a master of IST to find this tool useful. If you are looking at a speedrun setup made by someone else. You can view the setup in the tool as a step-by-step guide for how to perform the glitch. If you are a glitch hunter or is interested in investigating the glitch in more details, the user manual has everything you need to unlock the full potential of the simulator.

In any case, it might be helpful to understand the basic concepts of IST to get started.

I can’t understand IST, but I still want to speedrun

Don’t worry. IST is very complicated. Most people (including WR holders!) don’t fully understand the glitch. This is exactly why this tool exists.

If your goal is to do the setup in a speedrun, what most people do is simply following each action in the setup exactly, either from memory, or by looking at the steps while they do it. Many categories also have tutorials made for the IST section. For example, here is one for All Dungeons made by Player 5.

I just want to play with IST as a casual player

Be cautious to use IST with your casual file, as effect of IST can persist in saves and may cause the saves to be corrupted or not-loadable.

There are generalized guides for how to achieve certain things with IST in a casual file (for example, 999 korok seeds). You can follow these steps. A good place to look for those steps is the #general-help channel of the speedrunning discord. There are also tutorials online on YouTube (or Bilibili if you are from China) for using IST in a casual file.

How is the simulator made?

V1 to V3 of the simulator was developed by understanding the outcome and patterns of IST, and by referencing the decompilation project. It was a white-box approach, similar to a person that understood everything ever discovered about IST. V4 took the black-box approach, where sections of the real code of the game (not decompiled code) is executed in a sandbox orchestrated by the simulator app. This means the simulator might even be possible to support use cases that are not discovered yet.

Can I contribute?

Certainly! If you see some bugs and want to take a shot on fixing them, feel free to open a PR on GitHub. If you want to add features, please discuss with me first. A decent level of programming knowledge is needed.

Most of this project is open-source and use publicly available data of the game. However, some parts require you own a copy of the game to develop.

Please refer to the contributing guide for more information.

Note

If you goal is to add extra functionality, you might be able to do that through an extension, See [TODO add link here]

Note

If you are not familiar with programming, you can still contribute to the test suite by providing your (complicated) scripts as test cases. These test cases help ensure future updates to the simulator don’t introduce bugs. See [TODO add link here]

Inventory Slot Transfer

What is IST

Believe it or not, Infinite Stuff Trick is NOT the name of the glitch

IST stands for Inventory Slot Transfer. It is a glitch in Breath of the Wild that exploits behavior of the inventory when the variable tracking the number of the items in the inventory is less than the number of items actually in the inventory.

The developers made sure that these two values are kept in sync during normal gameplay. However, in very specific scenarios, the game removes the item slot from the inventory while subtracting the number of items twice, resulting in the game tracking 1 fewer item slots in the inventory. By repeating the action, we can make the game track fewer and fewer items.

The difference between the number of items in the inventory and number tracked by the game is called Offset or number of Broken Slots. Offset is technically more correct, but because it’s ambiguous in some contexts, this manual will refer to this number as Broken Slots. The action to create the Broken Slots is referred to as Breaking Slots.

Info

Broken Slots is the name used by the glitch hunting community before the underlying concepts of the glitch were fully understood. There’s nothing actually broken about the slots.

The variable that tracks the number of items is commonly referred to by the glitch hunters as mCount - a reference to the name of the variable in the BOTW decompilation project.

This variable is needed because the inventory is stored as a (doubly-)linked list, which has a O(N) time complexity for calculating its length.

The different counts have this relation:

mCount + Number of broken slots = Actual number of items

Inventory Representation

The inventory that you see when opening the inventory in-game - the Visible Inventory - is stored as a (doubly-)linked list. In this list representation, items in different categories are “concatenated” into the same list. For example, in normal inventory order, the list may have all the weapons, followed by all the bows, followed by all the arrows, etc, and in the end are all the key items. In one page of the item in the in-game UI, the top-left corner is first, and it follows row-major order (i.e. the item in row 1 column 2 is after the item in row 1 column 1 in the list), and the bottom-right corner is last, followed by the upper-left corner item of the next page.

Info

The empty spaces and empty tabs in the inventory do not take space in the list

The items are also stored at the same time in GameData, which is the game’s flag system. The relevant flags are stored with an array type. For example, PorchItem is a flag that stored an array of 420 strings, each string correspond to one item’s name. Other properties of the items are stored each in a different flag, for example PorchItem_EquipFlag is an array of 420 bools (whether the item is equipped), and PorchItem_Value1 is an array of 420 s32s (the value/durability of the item).

Whenever the Visible Inventory changes, the change is synchronized to GameData. We call this process Sync GameData or simply Sync. The GameData is also what is stored in the save files.

Tip

When mCount is 0, you won’t be able to see the items in the inventory when you open it. This is because the game thinks the inventory is empty since the number of items is 0. However, the items are still there. You can throw a weapon or pick up any item - as long as mCount is no longer 0, you will be able to access the inventory again.

Why is it called IST - The main mechanism

The huge number of glitches that are derived from IST all rely on the core mechanism - trasnferring slots, which is how the glitch got its name.

This all happens when the inventory is Reload-ed, either when loading a save, or restoring the inventory from a quest that takes away your items (i.e. Trial of the Sword, Stranded on Eventide, or any of the Blight Refights). When restoring the inventory, the game needs to do 3 things:

  1. Delete all of your current items in Visible Inventory.
  2. Load the data of the inventory to restore into GameData.
    • In case of reloading a save, it is loaded from the save file.
    • In case of quests, it is already stored in GameData.
  3. Add the items GameData one by one into the Visible Inventory.

The magic happens in step 1. Since mCount is less than the actual number of items, the game does not fully delete all the items in inventory. These leftover items will still be there after the reload, effectively being transferred from one save to another.

Derivative Glitches

The following glitches depend on IST. Click on the link for more information about each of them.

Direct Inventory Corruption (DIC)

Inventory Corruption is a form of Durability Transfer. In the game, durability is stored as a fixed-point integer, with 1 being 0.01. For example, a weapon with durability 10 has the internal value of 1000. In the case of corruption, the durability is transferred from an equipment not to another equipment, but to an item. The value then becomes the count of items. This is very useful, since you can get a LOT of items from an equipment with relatively low durability that’s easy to get.

This form of corruption was previously only possible using Memory Storage another very complex glitch with a lengthy setup. With IST, however, Inventory Corruption is much easier, hence the name Direct Inventory Corruption.

We will go over a few game mechanics first in order to understand why DIC happens.

Setting Durability on Equipment

The game sometimes need to set the durability of the equipment in the inventory from the overworld weapon actor in order to keep the durability in sync. This could happen in a few scenarios, including:

  • Using an equipment, such as attacking with weapon, shield surf and shooting an arrow (which uses both bow and arrow)
  • Switching equipment
  • After reloading from a save

The algorithm to do this is:

  1. Find the first item in the inventory list that is both equipped and is the same item that is trying to be set (for example, Master Sword)
  2. Set the value of that item

If you remember from Inventory Representation, the game also need to sync this change to GameData. However, syncing the whole inventory whenever one value changes seem inefficient. Therefore, this form of sync is done by directly taking the position of the item in the inventory list, and setting the value of the item in the same position in GameData.

This is correct if the GameData is always in-sync with Visible Inventory, which would be the case most of the time. Therefore, all the inventory corruption aims to do is cause GameData to be desynced, then trigger a durability set.

Info

Note that this is only one form of desync, which is the primary one used for inventory corruption. There is another form of desync used by inventory corruption using Inventory Storage, which is a derivative of Map Storage. We will not be going into the details for that.

GameData Corruption with IST

All it takes for corruption now is 2 things:

  1. Desyncing GameData
  2. Apply durability while GameData is desynced.

IST makes desyncing GameData trivial. Recall the 3 steps for reloading:

  1. Delete all items
  2. Load GameData
  3. Add items in GameData to Inventory

After these steps, the game doesn’t actually sync GameData. Therefore, whenever items are transferred, the GameData is automatically desynced after a reload.

Remember that reloading a save also causes durability to be applied? This means inventory corruption automatically happens after a reload. All the player needs to do to exploit this is to transfer specific items to desync the GameData in the way so that equipped items are aligned to the item to corrupt. This is why different IST setups exist to corrupt different things in different speedruns.

Tip

This is also why it is important to follow the setup to unequip/equip certain items before reloading, because the equipped item slot is what is used for corruption. To be exact, the durability of the last equipped slot is transfered into the first equipped slot in both Visible Inventory and GameData

Aligning the Items

In a DIC setup, we need to align the equipped equipment with the item to corrupt. This is done by transferring the right number of Swords, Shields, Bows, and Arrows. Transferring anything after Arrows typically has no effect, because they don’t affect the positions of equipments since those categories are after equipments in inventory order.

Recall that transferring an item means it is not removed in the inventory. Since the items from GameData are then added on top of that, the transferred items will appear before the items that are loaded in. Effectively, transferred equipments will push items from the save to slots after it.

To determine the right type of equipment to transfer, consider the order of the categories:

  • Since Shield is last, transferring any type of equipment will affect the position of shields
  • Since Weapon is first, only transferring weapon will affect the position of weapons.
  • The rest follow the same concept

Example

For example, transferring 1 Bow, 1 Arrow, 1 Shield, will:

  • Not change position of Weapons
  • Push Bows by 1 slot
  • Push Arrows by 2 slots
  • Push Shields by 3 slots

Unsorted Inventory and Forward Corruption

Note that GameData desynced in this way can only push the items back, not forward. For example, Weapons can corrupt everything, but Bows cannot corrupt Weapons, and Shields cannot corrupt Weapons, Bows, or Arrows.

Corrupting items that are not possible to corrupt in normal inventory order is known as Forward Corruption, and is done by making the inventory into a order that is not normal. For example, to transfer durability from a Shield to a Sword, the Sword must be put after the Shield. This state is typically known as Unsorted Inventory and opens up a whole different glitch category.

Achieving Unsorted Inventory is relatively easy. All we need to look at is how the game put (sort) the item into the correct category when you get something:

  1. The game always add the item to the end of the inventory
  2. The game then sorts the inventory with the following rules:
    • Two items should not change their relative order (if A is before B, A must also be before B after sorting)
    • Two items that have the same category are considered equal
    • Items that should appear in a category before other categories have lower values (say Sword is 0, Bow is 1, etc)
    • The list is sorted from lowest value to highest

Info

This type of sort is referred to as a stable sort using a predicate that compares the category of the items

The sorting itself cannot achieve the unsorted state, but absence of sort can. The list code has one more optimization, that sort operations are skipped if the list has no more than one element. Normally, having 0 or 1 element in the list means the list is trivially sorted. However, mCount is used for this optimization and we know mCount is not the actual number of items in the inventory. All it needs for the sort to be skipped is to make your mCount less than or equal to one.

Tip

Unsorted Inventory can also be used to transfer more equipment with fewer Broken Slots by putting Weapons after Key Items. This is typically used in speedrun setups where it could be faster to not break as many slots. This is why some setups require dropping some weapons, then immediately pick them up again. While picking up the weapons, the mCount never surpasses 1, causing the weapons you pick up remain at the end of the inventory.

Weapon Modifier Corruption (WMC)

A Weapon Modifier refers to the power-ups that can be found on an equipment, such as Attack Up or Durability Up. Weapon Modifier Corruption is a glitch enabled by IST to transfer data from a cooked item to a weapon, interpreting the memory as a Weapon Modifier.

During this corruption:

  • The Health Recover value of the cooked item becomes the Value of the modifier.
    • For regular food, this value is the number of quarter-hearts recovered. Between 0 and 120.
    • For hearty food, this is the number of yellow hearts
  • The Sell Price value of the cooked item becomes the Type of the modifier.
    • The Type is a bit-flag, so WMC can enable multiple modifiers on the same equipment.
    • See actWeapon.h for values for each modifier type

Info

You will see Prompt Entanglment (PE) often brought up together with WMC. This is because WMC relies on the data from a cooked item, and you can only get a very limited subset of possible cook data values by cooking with normal ingredients. PE allows cooking with unusual ingredients, which is required to get some modifier value/flag. However, WMC and PE are 2 separated glitches, and neither is required to perform the other.

Base Mechanism

WMC is possible because:

  1. The data for cooked item and the data for modifier is in the same memory location for each item. i.e. if the item is a food, then the data is used as cooked data, and if the item is a weapon, then it is used as modifier data.
    • This is only true for Visible Inventory, not GameData
  2. The data for cooked item is added separately from the item itself.

In step 2, the cook data is added after adding the cook item, and the game assumes the last added item is the cook item that is supposed to receive the data.

Therefore, a WMC setup typically involves:

  1. Making sure the last added item is the weapon to receive the corrupted modifier
  2. Make the cooked item that donates the data failed to load while the last added item is still the weapon, transferring the data to the weapon

Note that #2 essentially means that no item should be loaded between the weapon and the cook item.

Depending on how these 2 conditions are satisfied, the WMC setups can be further categorized.

Info

In general, WMC can refer to any of the case when the last added item is not the item that is supposed to receive the data.

You can technically corrupt any item in Visible Inventory, but only Equipments and Foods will have the data saved to GameData.

It is not possible to transfer modifier between Weapons, because unlike food, the data for weapons are added in the same step as the item itself (condition 2 from above)

Currently, WMC is only possible when reloading the inventory from GameData (for example when reloading a save). This is because there is no known way to trigger adding a cook item during normal game play while at the same time make it so the cook item doesn’t get added succesfully.

Food Limit

Using the food limit was one of the first method to WMC. This WMC setup uses the fact that during a reload, any food after the first 60 will not load (under normal circumstances). This can be achieved by transferring 60 food into a save with a weapon, followed by the donor meal.

Example script:

get 1 hammer 1 wild-green[hp=120, price=113]
save
eat wild-green
get 60 dubious-food
!break 60 slots
reload

The step-by-step explanation:

  1. Note that in the save, the items are 1 hammer and the donor meal, these are what will be added during reload
  2. Note that we are transferring 60 dubious-food
  3. During the reload, the hammer loads in first
  4. When loading the donor meal, since there are already 60 food, it fails to load.
  5. Since the last added item was the hammer, the data from the meal is transferred to the hammer

Info

The main drawback for this method is that it requires 60 food and 60 broken slots. Getting 60 broken slots is very tedious.

Stackable Food Limit

The reason why the previous setup required 60 broken slots, is because if we don’t transfer 60 food, then there will be food items that get loaded after the hammer. As a result, the cook data will be transferred to that item, instead of the weapon.

But wait! What if that’s exactly what we wanted? Instead of transferring the modifier directly to the weapon, we can do 2 transfers:

  1. Using the Food Limit method, transfer the data from the donor meal to a Stackable food (i.e. a roasted/baked/frozen food)
  2. Using Direct Inventory Corruption, corrupt the food value to >=500
  3. When loading a stackable item slot, if the value being loaded plus the value of the item in the inventory is greater than 999, the stack will fail to load (this is why we need >=500 in the previous step)
  4. When the stackable food fails to load, it can trigger WMC

Example script

# Setup
get 1 hammer
!break 1 slots
get 58 dubious 1 roasted-endura-carrot 1 wild-green[hp=120, price=113]

# This will make only the last food fail to load, transferring the data to the carrot
save; reload  

# Clean up the foods now
eat wild-green; eat all dubious
save

# Corrupt the carrot stack
unequip hammer
eat roasted-endura-carrot
reload
save

# Finally transfer the data to the hammer
reload

Info

As you can see, this method can work with a minimum of 1 broken slots, which is a big improvements over 60 broken slots. In speedruns, typically we use more broken slots anyway to corrupt other stuff and for duplicating food to quickly reach the 60 food required for the first transfer

The Nullptr Exploit

Both previous setups require 60 food to make the first transfer happen. It would be really nice if that’s not the case. This is where the Nullptr Exploit comes in.

Recall that after adding the cook item (or fails to add), the game applies the cook data to the last added item without checking if it’s the cook item. However, when there is no last added item, the data is not added, and crucially, the game does not advance to the next cook data slot. This means when the next food loads, it will keep using the cook data of the previous food!

Info

This can happen because in the GameData, the cook data and the item themselves are not stored in the same array:

  • The item name array has 420 strings, one for each item
  • The cook data array has 60 elements, one for each food.

When the Nullptr Exploit is triggered, the counter for the item array increments, but not the cook data array

Using this exploit, 60 food is no longer required. However, this exploit is pretty tricky to trigger, this is because mLastAddedItem is only nullptr before any item is added (with one exception being the Master Sword).

Master Sword (MSWMC)

This setup triggers the Nullptr Exploit using the fact that Master Sword cannot be duplicated.

The condition for this trigger is somewhat complicated:

  1. A Master Sword is transferred (can be broken or not broken)
  2. The save being loaded doesn’t have Master Sword being the first item
    • This is because adding the first item skips the part check we rely on to trigger the exploit
  3. The Master Sword Recharge Timer in the save being loaded is non-zero
  4. The save being loaded has a Master Sword (either broken or not broken)
    • 3 and 4 usually means the save has a broken Master Sword

Tip

In one sentence, this means to “transfer a Master Sword into a save with a broken Master Sword”

When all of the above conditions are met, last added item is set to nullptr, enabling the exploit.

The whole setup would be:

  1. Enable the exploit as described above
  2. In the same reload, load a food unsuccessfully, without loading any item in between
    • This uses the exploit described in the previous section to cause the reuse of cook data
  3. Now any food that load after will have the data that’s supposed to be on the food before it
  4. Continue the Stackable Food Limit setup

Travel Medallion (TMWMC)

The Travel Medallion is added in the Master Trials DLC. Unlike any other DLC items, it gets removed if you uninstall the DLC.

This can be used to trigger the Nullptr Exploit:

  1. Make a save with Travel Medallion being the first item, and food after it (using Unsorted Inventory )
  2. Close the game and uninstall the DLC
    • If you have physical game without DLC + digital game with DLC, this can be done by ejecting the Virtual Game Card
    • Otherwise, follow the steps on this Nintendo Support Ariticle
  3. Reload the save, setup IST again to transfer some food to make the food fail to load
  4. Reload the save again, the Travel Medallion will not load as the first item since DLC is uninstalled, and the next food will fail to load because of the transfer
  5. Now any food that load after will have the data that’s supposed to be on the food before it
  6. Continue the Stackable Food Limit setup

Unlike MSWMC, Travel Medallion does not set last added item to nullptr, so it has very limited usefulness.

Zelda Notes (ZNWMC)

Warning

This method has not be verified. It is only theorized based on reverse engineering of version 1.8.0 of the Switch 1 Edition

Zelda Notes is an item exclusive to the Nintendo Switch 2 Edition. When you uninstall NS2E, it gets removed from your inventory and can be used to trigger the Nullptr Exploit:

  1. Make a save with the Daily Bonus and Deposit Item being the first 2 items, and food after it (using Unsorted Inventory )
  2. Close the game and uninstall NS2E
    • If you have the physical NS2E Game Card and the NS1E game (physical or digital), this can be done by removing the physical NS2E Game Card (then inserting the NS1E Game Card if you have a physical copy)
    • If you only have the physical NS2E Game Card, this is not possible.
    • Otherwise, follow the steps on this Nintendo Support Ariticle to download the game without NS2E
  3. The rest is similar to TMWMC

Prompt Entanglement (PE)

Warning

This glitch is related to the Pouch Screen, which has not been reversed engineered. Most of the concepts are based on experiments, and may not reflect the actual implementation in the game.

Todo

If you can help improve this page, please edit this file and open a Pull Request

Prompt Entanglement, or PE, is a glitch that allows you to apply a prompt (like “Equip”, “Drop”, “Hold”, etc) to from one item to another item that is not supposed to have that prompt. For example:

  • Holding a Food (only Materials are normally holdable)
  • Equipping a Material
  • Eating a Key Item

Invalid Star Tab

Note

IST refers to Inventory Slot Transfer in contexts pertaining Invalid Star Tab.

To activate PE, the first step is to activate a state known as **Invalid Star Tab**. This is a state that allows the cursor (the box that highlights which item is currently selected in the inventory) to go to the "Key Items" icon.

Currently, the only known way to activate Invalid Star Tab is by having items in a category that you have not discovered. For example, have a material without picking up any material.

At first this seems impossible. However, the catch is “picking up” - You can obtain items without picking them up with IST. In an Invalid Star Tab setup, there are 3 general steps:

  • Save with the tab you want to use undiscovered
  • Pick up an item in that tab, which discovers the tab and gets you the item
  • Use IST to transfer that item back into the save you made

Once the setup is done, you can verify Invalid Star Tab is active if any of the following is true:

  • When you scroll to the right very quickly, the cursor ends up on the Star.
  • When you go to the “System” screen, the cursor remains on the left screen. You can only see the cursor when you press “Right”, which moves it on to the “Save” button.

Cursor Glitch

Warning

The Cursor Glitch is not fully understood, since the inventory screen system is not reversed engineered. This section may contain inaccurate information.

When Invalid Star Tab is active, you can now perform the Cursor Glitch to achieve PE. This glitch uses a sequence of controller inputs to quickly move the cursor while Invalid Star Tab is active to confuse the inventory code, and puts the cursor on a tab that’s not the current tab you are viewing.

      |- you are looking at this page
      v
    MATERIAL                 FOOD
[ ] [ ] [ ] [ ] [ ]  [ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]  [ ] [ ] [X] [ ] [ ] <- cursor (X) is on another page
[ ] [ ] [ ] [ ] [ ]  [ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ]  [ ] [ ] [ ] [ ] [ ]

                         ^
                         |- (this is where Link's model usually is on screen)

Typically, we refer to the position of the cursor by the Row and Column. In the example above, we say the Cursor Glitch is active at Row 2, Column 3, or simply Row 2 Column 3 is activated.

Tip

Since the Cursor Glitch is not fully understood, the community has put together a spreadsheet of different input sequences you can use to active each slot.

When Cursor Glitch is active, you can keep it active by move tabs in groups of 3 (tap right stick right 3 times, or left 3 times), without pausing too long between them. Pausing while not on a multiple of 3 tabs from where the slot is activated will reset the cursor’s position, losing the glitched state.

Capturing the Prompt

What the Cursor Glitch enables is that we can now move the cursor to another item, with the inventory screen still “thinks” we are on the original item, so it opens the prompt of the original item when we trigger it.

When we trigger the prompt (pressing A), the prompt used comes from the item that is currently showing description on the screen:

      |- you are looking at this page
      v
    MATERIAL         
[ ] [ ] [ ] [ ] [ ]  Link is displayed here
[ ] [ ] [ ] [ ] [ ]          [X] <- cursor (X) is on another page
[ ] [ ] [ ] [ ] [ ]  ===================
[ ] [ ] [ ] [ ] [ ]  <The item's name and description is displayed here>

When moving tabs in groups of 3, the Cursor Glitch causes the prompt to be locked, meaning it will not update the name/description of the item. You can force update it by going to the System screen and back (pressing R then L). This is often refered to as “resetting” or “capturing” the prompt.

With the prompt locked, you can now move the cursor to 3 tabs left or right, which will change which item the cursor is on, but will not update the prompt. Now, you can press A to trigger and use the prompt.

In general, these are the steps to do any PE setup:

  • Use the input sequence (the Cheat Code) to activate a slot
  • Ensure the right prompt is captured by moving tabs in groups of 3, and optionally go to the System screen and back to reset the prompt
  • Move tabs in groups of 3 to the target item, and use the prompt

Tip

Since you can only keep the glitch by moving tabs in groups of 3, this means PE can only be used between 2 items that are multiple of 3 tabs apart (i.e. have 2 other tabs between the source and target items)

Applications

Weapon Modifier Corruption

With PE, you can hold ingredients like stackable food that aren’t holdable normally. When these ingredients are cooked, their properties gets processed by the complex cooking system and produces meal values that aren’t obtainable by cooking normal ingredients, which can give better values for Weapon Modifier Corruption.

You can hold stackable food by either using “Hold” prompt from material, pressing X while locked to a material, or using the “Drop” prompt from equipments. Using the “Drop” prompt will not put Link in the holding state in inventory screen, allowing you to perform other actions while technically holding.

Note

Note that if you try to hold items that do not have a model (Food, or some Key Items), the game will crash when trying to render it in the inventory. You can workaround this with Super Hold Smuggle or some other method, which we will not go into depth here.

The simulator allows you to hold anything without crashing.

Removing Arrow Slots and Permanent Items

When you obtain a type of arrow, that arrow slot is stuck in the inventory forever, even if you shoot the arrow to 0. With PE, you can entangle a material prompt with the arrow prompt. Now you can press X and use hold to remove arrows. When you have 0 arrows, you can use the eat prompt to remove the slot completely.

Similar to removing arrow slots, you can remove permanent items like Sheikah Slate, Glider, Zora Armor, etc, by eating it.

Duplicate Materials

When using PE to hold, it subtracts the amount from the item you are holding, but checks the amount of the original item to see if you can keep holding. Since the amount of original item never decreases in the process, you can keep holding the item even if the stack is at 0. You can either unhold, or drop the items on the ground to realize the gain.

Note that if you use this method to duplicate material, you need at least 4 tabs of materials.

Durability Transfer and Desync Equipment

You can use PE to change equipment, while not changing the equipped status of the slot. This is very similar to Desyncing with Menu Overload.

To transfer durability:

  • Equip the item to receive the durability
  • Activate the slot with the item to give the durability
  • Use the “Equip” prompt of that item on something else (for example, a material)
  • Close Inventory

This will switch the equipment in the overworld while not in the inventory. The change equip action will cause a durability update, which transfers the durability.

Tip

Note that unlike durability transfer with Menu Overload, you do not need to use the equipment to update the durability. This is because the desync acheived by PE is the exact opposite of Menu Overload:

  • Menu Overload desyncs by switching the equipment in the Inventory, but not in overworld
  • PE desyncs by switching the equipment in the overworld, but not in the inventory

Since with Menu Overload, you do not switch equipment in the overworld, which does not trigger the change equip action. Therefore, using the equipment manually is required to update the durability.

You can also use this to unequip the One-hit Obliterator, which is more consistent than using Menu Overload. After performing the steps above, you will be able to unequip the OHO from the DPad Quick Menu.

User Manual

Info

This section covers how to use the Simulator App. While not required, understanding IST itself could make it easier to understand some of the concepts here. You can read about IST here

How the Simulator works

The Simulator runs on a Script, which is a text file that contains Commands for the simulator. Usually, the commands are the steps or actions you perform in the IST setup.

Here’s an example of such script, each line is a command.

get 1 pot-lid 1 apple 1 slate 1 glider
equip Shield
!break 3 slots
save
unequip shield
hold apple; drop
reload
save
drop apple
reload

In the simulator UI, you can edit the script in the Script Editor. Whenever the script changes, the simulation will automatically rerun in the background. You can navigate different steps of the simulation by moving your cursor in the editor. The UI will display the state of the inventory after the command the cursor is on.

To learn more about commands, see Command Syntax and Command Reference.

Systems in the Simulator

Skybook aims to be a 100% accurate IST simulator. To achieve that, it emulates subsystems of the game as much as possible. However, not all subsystems can be emulated, especially those that are not reversed-engineered fully or not at all. Some subsystems also may not be worth to emulate since a simulation is good enough.

The systems that are involved in the simulator include:

Command Syntax

The simulator script is used to describe the steps to setup IST. The script is made up of commands. Most commands describe one or more actions in game, such as getting an item, dropping some items, or equip something.

The commands can be divided into 3 groups:

  • Actions: These correspond to actions you do in game, such as get, pick-up and hold
  • Annotations: These commands start with : and are used to change the current configuration, such as :weapon-slots
  • Supercommands: These command start with ! and are more powerful than the actions. They often interact directly with the game’s state in a way that’s not possible with a regular action.

Whitespaces are insignificant in the syntax, including new lines. This means one command can be broken into multiple lines and more than one command can be put on the same line. Commands can also have an optional trailing ;.

# These 2 commands are equivalent
get 1 apple 1 pot-lid 1 hammer;

get
  1 apple
  1 pot-lid
  1 hammer

# Trailing ; is optional even for multiple commands on the same line
hold 2 apples drop
# but it's clearer if you separate them with a ;
hold 2 apples; drop

Note

In the simulator, the inventory displayed are the state after executing the command the cursor is on.

The simulator parses the commands by span, not by line. You can view the state for each command even if multiple of them are on the same line.

Item Syntax

The Item Syntax has 3 components: amount, name, and metadata

get    3        pot-lid   [durability=3]
#      ^ amount ^ name    ^ metadata

Tip

To specify multiple items in the same command, simply write them one after another, e.g. 2 apples 3 bananas

When there is only one item in the list, and the amount is 1, you can omit the amount. For example get 1 apple can be shortened to just get apple. However, amount is required when the list contains more than one item name/category

The syntax could be used in 3 scenarios, depending on the command:

  1. FINITE_ITEM_LIST

    • The amount must be a number, not keywords like all.
    • The name must be an item, not category.
    • The metadata is used to describe extra properties of the item.
    • Generally used by commands for adding items, such as get
  2. INFINITE_ITEM_LIST

    • The amount could be a number or the keyword infinite.
    • The name could be an item or a category.
    • The metadata is used to describe extra properties of the item.
    • Currently, this form is not used by any command.
  3. CONSTRAINED_ITEM_LIST

    • The amount could be a number, or:
      • The keyword all
      • In the form all but X, where X is a number.
    • The name could be an item or a category.
    • The metadata is used to match from items in some existing list (such as your inventory)
    • Generally used by commands that targets some item, such as hold and eat.
    • Position properties can be used

Amount

The amount of item may have different meaning in different commands. For example, when using the eat command, the amount is always the internal value (i.e. the stack size), since you can eat from corrupted food or decrease armor value/durability by eating. When using sell, however, the amount means how many slots for unstackable items.

In CONSTRAINED_ITEM_LIST, you can use 2 special amount forms: all and all but:

  • all will repeatly find the item and perform the action on the item, until the item cannot be found.
  • all but X will first count the total number of times the action can be performed, then perform the action count - X times. How the total number is counted depends on the command, similar to the eat vs sell situation mentioned earlier.

Note

The implementation may vary slightly based on the command, but the concepts are the same. One notable example is that all in dnp is implemented as all but 0, since otherwise it will be stuck in an infinite loop.

Warning

In rare cases, all but could be inaccurate, if the total number of items changes unexpectedly due to the action. Please report if you encounter this issue.

Name

You can specify the name of the item in 4 ways:

  1. By Identifier - An Item Identifier is multiple english words (A to Z, case-insensitive), combined with - or _. For example, royal-claymore and trav-bow are both valid identifiers. There is a fixed algorithm for resolving the identifier to an item.
    • The result is an item that contains all the individual words, for example trav-bow results in traveller’s bow.
    • You can add an effect before a food item to specify the cook effect. For example hasty-elixir, sneaky-wild-greens
    • Plural forms with -s, -es, -ies postfixes are supported. They don’t affect the amount of the item, only makes the command sounds more natural in English.
    • Some shorthands are supported in this form. For example, geb for great-eagle-bow, aa for ancient-arrow.
  2. By Actor - You can use angle brackets (<>) to specify the internal actor name directly, for example get <Weapon_Sword_070>. You cannot specify cook effect in this way.
  3. By Localization - If English is not your preferred language, you can specify items by their localized name using a quoted-string. For example, "espadon royal" or "王族双手剑".
    • The string is fuzzy-searched in all languages
    • To lock the language, prepend the query with the language and a colon, for example, "fr:espadon royal" this could be useful if the query is short, and is matching in another language that you didn’t expect.
    • Localized search only applies to items, not commands (like get, hold, etc)
  4. By Category - When selecting items from inventory or some other list of items, you can also use a category in the place of the item name to match the first item of that category. This can be useful in situations like unequip shield where you don’t need to care what shield is currently equipped, or pick-up 3 weapons, where it doesn’t matter which weapons are picked up.

Info

See token for possible category values

Metadata

Metadata specifies extra properties of the item, in the format of [key1=value1, key2=value2, ...], either = or : can be used as the key/value delimiter

  • In FINITE_ITEM_LIST, it is used to specify extra data on the item to be added
    • For example, get pot-lid[durability=1] gets a new pot-lid with 1 durability
  • In CONSTRAINED_ITEM_LIST, it is used to specify extra data used to match the item to operate on.
    • For example, if you are multiple pot-lids, drop pot-lid[durability=1] targets the one with exactly 1 durability.

The metadata value can be one of the following types:

  • string - english words separated by - or _
  • int - an integer in decimal or hex (prefixed with 0x)
  • float - a floating point number with 2 integers separated by . (the whole number part and the decimal part, both needs to be in decimal).
  • bool - true or false. The value can be omitted to indicate true, for example, drop pot-lid[equipped] is the same as drop pot-lid[equipped=true]

Full list of item metadata properties:

Tip

For links below for possible values, since GitHub does not allow linking to a symbol, you need to click the link, then search for the symbol in your browser (signed-in user can also use the symbol list on the right side).

PropertyAliasesDescription
durabilitydura(int) Sets value to 100 times the specified number
effect(int or string) Sets the effect ID for cooked-food. See parse_cook_effect for possible values
equippedequip(bool) If the item is equipped
ingr(string) Set the ingredient of the cooked-food. The string must be an item identifier (see above). The property can be specified multiple times to add multiple ingredients.
level(int) Sets the level of the effect for cooked-food
life-recoverhp, modpower(int) Sets the number of quarter-hearts cooked-food recovers, or value of a weapon modifier
modifiermodtype(int or string) Set weapon modifier.

Cannot be used to set food effect type.

Integer values are the same as price. String values can be specified multiple times to build up the weapon modifier.

When used for matching, if only one modifier is specified, it will match any modifier flags that includes the specified one (i.e. other modifiers are allowed), if more than one bit is specified, the modifier flag must match exactly.
See parse_weapon_modifier_bits for possible values
price(int) Sets the price of the cooked-food. This can also be used to set multiple weapon modifiers as a bit mask
star(int) Armor star (upgrade) number, valid range is 0-4, inclusive.
Note that this is syntactic sugar to change the name of the item, as armor with different star numbers are different items.
time(int) Sets the duration of the food effect in seconds
valuelife(int) The value of the item, which is the count for stackables or durability multiplied by 100 for equipments.
Note: not to be confused with life-recover

Selecting from multiple matches

In CONSTRAINED_ITEM_LIST, there could be the case where there are multiple items that are exactly the same. There are additional meta properties that you can use to pick exactly which slot to select.

With from-slot property, you can pick the i-th matched item. For example, if there are 3 Pot Lids, you can use drop pot-lid[from-slot=2] to drop the second Pot Lid. The number is 1-indexed.

You can also target an item by its position in the inventory directly with one of the following methods:

# This is the same as using `from-slot`
# If there are >=2 slots of apple, this will eat from the second slot
eat 2 apple[slot=2]

# Category can be used as the name
# This eats the second slot in the entire inventory that is a material
eat 2 material[slot=2]

# Eat 2 apples from the material tab, in the first row and second column
# When using `category`, the indices are 1-indexed
eat 2 apple[category=material, row=1, col=2]

# Eat 2 apples from the second material tab, in the first row and second column
eat 2 apple[category=material, tab=2, row=1, col=2]

# Eat 2 apples from the second material tab, in the 0-th slot.
# The tab is 1-indexed.
# The slot is the 0-indexed slot in that tab, arranged like this:
# 00 01 02 03 04
# 05 06 07 08 09
# 10 11 12 13 14
# 15 16 17 18 19
eat 2 apple[category=material, tab=2, slot=0]

# Eat 2 apples from the 0-th tab, in the 3rd slot
# The tab index here is the 0-based index in the entire tab array
# The slot is the 0-indexed slot in that tab, see above
eat 2 apple[tab=0, slot=3]

Note

  • If the slot selected by position has a different item, you will receive an error
  • When using row and col, they must be specified after category or tab

Warning

The positions are calculated right before the simulator tries to find the item to target. This means if the action performed on previous items in the same command changes the inventory, the position you need to specify to target the correct item could be different from what you see in the inventory in the previous step. For this reason, it’s not recommended to specify position when performing an action on multiple items. Separate the position-dependent action to its own command instead.

Comments and Notes

Comments and Notes are text in the script that don’t affect the output of the command.

Comments

Comments are lines that start with # or //. They are completely ignored

# This is a comment
// This is also a comment

Tip

In the script editor, you can use the hotkey Ctrl + / to quick toggle selected lines between commented/uncommented

Block Literals

Block Literal is a multi-line block that starts and ends with ''' (triple single-quotes)

'''
This is a block literal

It can have multiple lines
'''

Addtionally, a block literal can have a tag, which is a string after the ''' that starts the block. For example, the note tag can be used to add notes to blocks of commands, which can be viewed in the Notes extension

'''note
Drop these in the same pile
'''
drop all weapons
drop all shields

Info

The Notes feature is not implemented yet

Screen System

The Screen system simulates different dialogs and pause menus in the game. For example, when pausing to access the inventory or sell items by talking to a shop keeper.

Most of the time, the simulator can switch between screens automatically depending on the actions, so the effect of this system should be transparent to those who are used to previous versions of the simulator.

Understanding this system could be useful, if you want to explicitly control when you open a screen, which can be helpful when optimizing and verifying IST setups.

Tip

The simulator UI has a little icon next to the “Visible Inventory” title to indicate which screen you are currently on

Game State

While not technically a screen, the Game itself can also have 2 different states: Running and, well, not Running (closed).

The “initial state” of the simulator is similar to the state of a new game. When executing most commands, the game will keep running, unless:

  • You manually closed the game with the close-game command.
  • The game crashed when executing some command.

Note

When you encounter a game crash, note that it’s also possible it’s a bug in the simulator. Please report it on GitHub if the simulator crashes on a step that you don’t think is supposed to crash in game.

You can also view the detail of the crash in the Crash Viewer Extension.

Whenever the game is closed in the middle of a simulation (either closed manually or crashed), it will not automatically restart. You have to use either of the commands below:

  • new-game to start a new game
  • reload or reload SAVE_NAME to start the game and reload a save
    • SAVE_NAME is the name of the save, see Reload (link TODO)

Screen Types

While in game, there are 3 screens that are simulated:

  • Overworld:
    • The default state when you start a game.
    • Player is able to move
    • You can get/drop items
    • … all the other things you can do in the overworld
  • Inventory:
    • When pause the game with the + button or DPad
    • Player can interact with items in the inventory
  • Shop Selling:
    • When talking to a shop owner to sell items
    • Player can select items in the inventory to sell
  • Shop Buying:
    • When talking to a shop owner to buy items
    • Player can select from a list of items to buy

The Screen system works like a state machine, when an action needs a certain screen, it will try to transition to that screen state if possible, and display an error if it couldn’t. The transition looks something like this:

             Overworld
         /---------|---------\
        /          |          \
       /           |           \
Inventory     Shop Buying  ---  Shop Selling

For example, if you are in the inventory menu and need to talk to a shop owner to sell something (i.e. to execute the sell command):

  • The simulator first checks if you are already in the Shop Selling screen
  • Since you are in the inventory screen, the simulator must return to Overworld by closing the inventory menu
  • Then, it simulates talking to a shop owner by transitioning to the Shop screen
  • Finally, it sells the item
  • After all of that, it will stay in the Shop screen until it has to transition again

That all happens in a single sell command!

Some commands, like get-pause, also explicitly performs screen switching. Note that these case do not count as manually switching screens (see below), and the simulator will still automatically switch screens afterwards.

Manually switching screens

The following actions count as manually switching the screen. If the screen has been manually switched, the simulator will prevent certain automatic screen switches.

  • Inventory:
    • pause to open the inventory
      • No automatic screen switches can happen until returned to overworld
    • unpause to close the inventory and return to overworld
  • Shop (buying and selling):
    • talk-to NPC to start buying or selling (NPC can be any - or _ connected word)
      • Screen can be automatically switched between Buying and Selling, but not to Overworld
      • When returned to overworld, screen can be automatically switched again to all types
    • untalk or close-dialog to return to overworld

Note

Note about buying: The buy command performs buying from items in Overworld, and it will trigger automatic switch to Overworld if possible. This is because when buying from a shop, you get a dialog, but it returns to overworld after that. The only exceptions are wondering merchants and Beedle. Most of the time, it will not matter. When it does matter, it’s recommended you always use manual screen switch actions to indicate to other people if they should buy from the same screen, or close the dialog and talk again to buy. You can use the :same-dialog annotation so the next buy command switches to the buy screen instead of returning to overworld

Overworld System

The Overworld system simulates objects that the player interacts in the overworld, known as Actors. However, the actual overworld in the game is very complex, and most of the actors don’t even have anything to do with the inventory. Therefore, the Overworld system is a ultra-simplified simulation of only the actors that are involved in inventory glitches:

  • The player’s equipment (Weapon, Bow and Shield)
  • Any items currently being held by the player in the overworld
  • Any items (including materials and equipments) dropped by the player

Material Drop Limit

In the game, you can drop at most 10 items on the ground at a time. When you drop the 11-th item, the least recent dropped item will despawn. This limit is simulated by the Overworld system in the following way:

  • When dropping material with the drop command, or auto-dropped from a smuggled state, it gets added to the list of items on the ground
  • The least recently dropped items will be removed from the list, until there are at most 10 items on the ground
  • The removed items are not deleted immediately. You will see Will despawn in the tooltip text of the item in the simulator UI.
  • If you perform any action that takes some time so it’s impossible to preserve the despawning item, the item will be deleted.

Tip

It is implemented like this because it is possible to drop more than 10 items, but pick up the items fast enough before it despawns to keep the materials on the ground under the limit. This can be used to optimize IST steps.

For example, the following script will result in 15 apples in the overworld, 5 of which are in the Will despawn state.

hold 5 apples; drop
hold 5 apples; drop
hold 5 apples; drop

Then:

  • If you pick-up 5 apples right after, there will be 10 apples left on the ground, and 5 are added to the inventory.
  • If you pause, there will still be 15 apples on the ground, since you could unpause and pick them up
  • If you get 3 bananas, the despawning items will now be deleted, and there will be 10 apples left on the ground. This is because it’s unlikely the apples are still there after you pick up some other item

Resetting the Overworld

In a long IST setup, there might be times where you travel between different areas in the game, or exit/enter shrines, that cause the overworld to change without necessarily any inventory-related action. There are a few ways you can simulate this:

  • Any action that is supposed to reset the overworld will do so automatically, for example reload, enter shrine, or leave shrine
    • The !load-zone supercommand can be used to simulate regenerating the game stage with a loading screen, if none of the action commands match your needs.
  • The !clear-ground supercommand can be used to delete all items on the ground. Use this if you are travelling to another area without a loading screen

Command Reference

This is the full list of commands sorted in alphabetical order. Clicking on a command will take you to the corresponding documentation page.

CommandDescription
getGetting an item
cookCook ingredients and get the cooked result
dropDrop held items or specific items in inventory to the ground
holdHold items in your hand
hold-attachedHold items in your hand and trigger the state where items are attached to the right hand
overloadTrigger Menu Overload
stop-overloadStop Menu Overload
pick-upPick up an item from the ground
unholdPut the held items back to inventory

Get Items

Adding new items to the inventory.

See Shop for specially buying items from a shop.

Syntax

get FINITE_ITEM_LIST
pick-up CONSTRAINED_ITEM_LIST

Annotations: :pause-during, :accurately-simulate

Examples

get diamond             # 1 Diamond
get 2 apple 2 banana    # 1 Diamond, 2 Apples, 2 Bananas
drop all apples         # 1 Diamond, 2 Bananas. 2 Apples on the ground
pick-up all apples      # 1 Diamond, 2 Bananas, 2 Apples

Picking up previously dropped Items

The only difference between get and pick-up is that pick-up is used to target items previously dropped on the ground.

You cannot pick-up items that aren’t on the ground. Use get instead.

Pause on Item Text Boxes

When picking up a new item, opening a chest, or getting item from some event (such as a Korok), you will get an item text box that allows you to open the pause menu. The :pause-during annotation can be used to simulate this action.

Warning

The simulator does NOT check if you are allowed to open the pause menu when you get an item, nor does it check if normal pause menu operations can be performed.

For example, usually you can eat something immediately in the text box that you got it, but you cannot hold another item. Currently, this situation is too complex to simulate correctly.

One use case is to force hold items during an item text box by performing Item Smuggle for Arrowless Offset, then get an item text box (similar to performing Arrowless Offset).

get 2 shrooms
:smug hold 2 shrooms
# Open a chest, for example
:item-box-pause get lynel-shield 
# Here, you are in pause screen while holding 2 shrooms
unpause
# Now the 2 shrooms will drop to the ground because of how the smuggle works

Performance

The preferred way to simulate getting multiple stackable items, is by invoking the function for adding the item to inventory repeatedly. However, when the number of items to get is large, this is a very expensive operation and can slow down script execution significantly.

Therefore, when the amount specified is greater than some internally determined amount, the implementation switches to a single call of the function with a value. Functionally, it turns:

get 999 apple

into:

get apple[value=999]

Most of the time (if not all), this will not cause inaccuracies. However, if it matters, you can use the :accurately-simulate annotation to force the more accurate implementation.

# This may take 30 seconds or more to execute, depending on your hardware
:accurately-simulate get 999 apples

Detail

  • Both get and pick-up require Overworld screen.
  • You cannot get new items while holding items in the overworld
    • with :smug, the held items will be dropped after getting the item

Hold Items

Hold a list of items from the inventory screen.

Yellow border and circles on an inventory slot indicate items are being held from that slot, The number of circles corresponds to how many items are being held.

When Link is also holding items in the overworld, the held items will be also displayed in the overworld UI with yellow border and a circle.

Syntax

hold CONSTRAINED_ITEM_LIST
unhold

Annotations: :smug

Examples

hold apple
hold 2 apple
hold 1 shroom 1 pepper
unhold
:smug hold 1 shroom 1 pepper
unhold

Smuggle State for Arrowless Offset

The :smug annotation can be used to activate the item smuggle state required for Arrowless Offset for the next hold command, which is when the held materials are attached to Link’s hand instead of being held in front of him.

To do this in the simulator, put :smug right before the hold command

:smug
hold 2 shrooms
# Now you are in Overworld, and held items are attached to Link's hand

You can also put :smug hold on the same line (which sounds like smuggled, hehe).

To do this in the game, you need:

  • A Shield
  • A one-handed Weapon

To perform this:

  1. Enable Weapon Smuggle and make sure a shield is equipped
  2. Hold the ZL button
  3. Hold items from up to 5 slots
  4. Switch to a one-handed weapon
    • Switch to another or to something else and back if you are already equipping a one-handed weapon
  5. Jump and let go of ZL button, after landing, when the shield is to Link’s side, unequip the shield

While in this state, you can perform actions which are not normally possible, such as getting items or talking to NPC. While doing so, the simulator will delay-drop the items. This is essential to generate offsets. In game, you can do this by either:

  • Whistle and perform the action (Dpad Down > A) quickly before the items drop
  • Pull out Bow and perform the action (ZR > A) quickly before the items drop

Stop holding

unhold puts the items currently held back to the inventory

Detail

  • hold requires Inventory screen
  • unhold requires either Overworld or Inventory screen, and will automatically switch to Overworld if not satisfied
  • hold will not work if you are already holding 5 items
  • The held items will only be spawned in the Overworld when the inventory is closed.
  • When unholding, the items in the Overworld despawn immediately.

Remove Items

Remove items from the inventory.

  • See Shop for specially removing items from selling the item to a shop owner
  • See Equipments for removing equipments from the overworld.

Syntax

drop
drop CONSTRAINED_ITEM_LIST
dnp CONSTRAINED_ITEM_LIST
eat CONSTRAINED_ITEM_LIST
use ITEM_NAME [X times]
!remove CONSTRAINED_ITEM_LIST

Annotations: :overworld

Examples

hold 5 apples
drop
drop 15 apples
!remove all cores

Hold and Drop

The drop action is used to drop the materials being held in the overworld to the ground.

If a list of materials is specified, it’s equivalent to:

  • hold the item,
  • drop it,
  • Repeat for every item, one at a time.

See Hold Items as well.

The dnp command stands for drop and pick up, which can be used to re-order the items in the inventory.

Example

dnp 10 apples 20 bananas
# which is equivalent to:
drop 10 apples 20 bananas
pick-up 10 apples 20 bananas

For simplicity, items will not despawn in the middle of dnp

Drop Equipments

The drop action is also used to drop the equipments directly from inventory or from the overworld player (e.g. getting shocked).

Examples

# This does the following:
# - open inventory
# - select first royal-claymore, drop it
# - select another royal-claymore, drop it as well
drop 2 royal-claymore

# Drop the weapon directly from the overworld player
# For example when getting shocked
:overworld drop weapon

Note

You can also use throw and display to remove equipments from the overworld player

Using fairy

The use command removes items from the inventory while in the overworld. In the game, this is only possible to remove fairies by having them save Link from death. However, the simulator lets you remove any item.

use fairy 2 times
use wood # No known way to do this in game

Tip

The use command is also used for using equipments in the overworld

Warning

Since the game can only remove items in this way by the item name, it’s not possible to specify extra properties, including food effects.

Forcefully remove items

The !remove supercommand lets you forcefully delete items from the inventory:

  • For Arrows, Materials, Foods, and Key Items, the value of the slot will decrease by the amount
  • For the rest, the amount in the command corresponds to how many slots of this item you want to remove.

Warning

The implementation of this command is custom and do not correspond to any of the game’s code. Using this command can lead to inaccurate simulation that’s not reproducable in game.

For example, overworld equipments are not synced when removed this way!

Detail

  • drop and dnprequires Overworld screen if dropping materials, and Inventory for dropping equipments.
    • The simulator may switch screen back and forth during the same drop action to facilitate this
  • use requires Overworld screen.

Equipments

Change or use equipments

Syntax

equip CONTRAINED_ITEM_LIST
unequip CONTRAINED_ITEM_LIST
use <weapon|bow|shield> [X times]
shoot [X times]
throw weapon
display CONTRAINED_ITEM_LIST

Annotations: :non-breaking, :breaking :dpad

Change equipments

The equip and unequip actions are used to change the equipped status on equipments.

Example

# Equip the first weapon
equip weapon 
# Unequip the first **equipped** weapon
unequip weapon
# Equip multiple items
equip 1 royal-claymore 1 hylian-shield
# Unequip multiple items
unequip all shields all bows
# Unequip the second equipped Hylian Shield
unequip hylian-shield[slot=2]

# You can also equip armors and champion abilities
equip champion-tunic
unequip gale
# You cannot unequip arrows
unequip fire-arrow # Error! cannot unequip arrow

Warning

When using from-slot or slot for unequip, note that unequip only targets the equipped items. So slot=2 means the second equipped item. equip and other commands target all items, so equip weapon[slot=3] equips the third weapon in the inventory, regardless of which weapon is currently equipped. If the third weapon is already equipped, you will get an error.

This may seem like a weird design choice, but it makes intuitive sense when you use the command in most cases.

Tip

Normally, you would omit the amount for equip or use 1 for multiple categories, since equipping another item of the same category would just unequip the previous one. However, in some configurations, the items won’t be auto-unequipped. If you actually want to equip more than one item, you have to specify [equipped=false]. Otherwise, it will error when it hits an item that’s already equipped. For example, equip all weapons[equipped=false].

unequip all should always work as expected.

By default, changing equipments are assumed to be done in the pause menu. This should be ok in most cases. However, there are edge cases where action must be done through the DPad Quick Menu, examples include:

  • You are holding items in the pause menu.
  • The item slot is not visible in the pause menu, only in quick menu.

In these scenarios, you can use the :dpad annotation to specify the equipment change should be done via the quick menu.

Example

# Switch equipments with DPad quick menu
:dpad equip fire-arrow
:dpad unequip weapon

Warning

Note that :dpad unequip can only be used to unequip the first equipped item in the quick menu, and cannot be used to unequip arrows.

Using the equipment

You can use the equipment in the overworld with the use action, which can be used to simulate actions that consumes durability:

  • Hit object with weapon
  • Block attack with shield
  • Shield surf
  • Shooting arrows (The shoot command is equivalent to use bow)

Examples

# Attack or hit something with weapon
use weapon
# Block a bomb with shield
use shield 30 times
# Shoot 5 arrows
use bow 5 times
shoot 5 times

Throwing the weapon

Details

  • equip and unequip require Inventory screen
    • If :dpad is used, Overworld screen is required.
  • use, throw and display require Overworld screen.

Shop

Buy or sell items from a shop.

Syntax

talk-to NPC (can be any word)
untalk OR close-dialog
sell CONSTRAINED_ITEM_LIST
buy FINITE_ITEM_LIST
:same-dialog

Examples

talk-to beedle
sell all shroom all pepper
:same-dialog buy 5 arrows
close-dialog

Buying

In most shops in the game, you buy items by talking to the item in the overworld, which keeps you in the overworld screen after purchasing the item. The exceptions are Beedle and travelling merchant, where there is a dedicated screen for choosing items to buy.

The buy action defaults to buying in the Overworld. If it matters in the setup, you can force buying from a dialog by entering the Shop Buying screen manually with talk-to NPC, and untalk or close-dialog afterwards to return to the Overworld screen.

To buy after selling from the same NPC dialog, you can use the :same-dialog annotation just before the buy command. This will switch from Shop Selling screen to Shop Buying

Selling

Unlike buying, selling in this game only has one screen, where you select items to sell. The screen is very similar to the normal inventory screen, but:

  • Only Armor, Material, and Food tabs are displayed
  • Items are displayed even when mCount is 0

Items can only be selected to sell from those tabs that are displayed, and you cannot sell items with the CannotSell tag (for example, Zora Armor)

Detail

  • buy requires Overworld or Shop Buying screen
    • It will automatically switch to Overworld by default. The :same-dialog annotation can be used to switch to Shop Buying from Shop Selling
  • sell requires Shop Selling screen.
  • Buying and Selling screens can be automatically switched between by the simulator even if it’s manually switched from Overworld

Break Slots

Breaking Slots refers to the action of generating offsets to enable IST. See Inventory Slot Transfer for more info.

You can either break slots by simulating actions, like what you do in the game, or use the !break supercommand to directly edit the memory

Syntax

!break X slots

Arrowless Offset

Info

References for commands used for Arrowless Offset:

The most commonly used method of breaking slots is known as Arrowless Offset. which requires a shield, a one-handed weapon and a shop keeper and can break up to 5 slots at once:

  • Enter the Smuggle State
  • Talk to a shop keeper (by pressing Dpad Down > A or ZR > A quickly)
  • Sell all the items from slots that are being held
  • Close the dialog

Example script for Arrowless Offset in the simulator

get 2 shroom 2 pepper 1 banana
hold-attach 1 shroom 1 pepper
sell all shroom all pepper
close-dialog

Hold Smuggle Offset

TODO

(something like:

get 2 shroom 2 pepper 1 banana
overload
hold 1 shroom 1 pepper
sell all shroom all pepper
stop-overload
hold banana
drop

By Magic

For backward compatibility, you can still use !break to generate offsets by directly editing the memory of the inventory. This shouldn’t cause any inaccuracies in normal circumstances, but it’s recommended to only use this command for prototyping, and use the actual actions in the final script.

Example:

!break 20 slots

Entangle

Activate Prompt Entanglement and perform actions on a slot using prompts from another.

Syntax

entangle ITEM
:targeting ITEM

Activate PE

While the Cursor Glitch is active, you can switch tabs in groups of 3 to keep the glitch active. Therefore, conceptually, when you activate a slot, all slots that are 3 tabs apart can be considered activated as well.

This action is simulated by the entangle command.

# Targets the Pot Lid, and activates that slot, as well as all slots that
# are 3 tabs apart
entangle pot-lid

While a slot is activated, you will see a “Link” icon next to it.

Tip

If a slot that’s supposed to be activated does’t exist in a tab (i.e the tab doesn’t have enough items), there will be a phantom slot displayed in that location when in Tabbed View. This is only a visual effect of the simulator.

The effect of the activation will last until the inventory is closed. You can also use another entangle command to change which slot is activated.

Targeting an Item

The second step to using PE is to select a target item that will receive the prompt. The :targeting annotation is used to do that.

# If the item is in an activated slot, you can use the name to select it
:targeting apple
# You can also select the slot directly
# This is useful if you are targeting an empty slot (which can't be selected
# by item name, since there's no item there)
# Note that specifying the first item directly will not work, if the activated
# slot is not in row 1 and col 1.
:targeting <empty>[category=material, tab=1, row=1, col=3]
#          ^ the name is ignored while targeting a slot directly, so it
#            doesn't matter what you put here

Warning

:targeting currently also searches slots that are not activated. If there are multiple matches, you might need to use a Position Property to specify the activated slot.

Finally, in the next command after :targeting, you can perform an action on a PE-enabled slot. If the target item can be reached by the item in the action, the action will be performed on the target item instead.

entangle roasted-endura-carrot :targeting roasted-endura-carrot
drop pot-lid # will hold the roasted endura carrot

Since it can be redundant to activate, then target the same item, entangle will also target the item by default. The command above can be shortened as

entangle roasted-endura-carrot
drop pot-lid # will hold the roasted endura carrot

However, sometimes it might be cleared to write it as entangle then :targeting. For example, during speedrun, it’s usually faster to entangle the source item, to skip resetting the prompt, which means the item to setup the entangle is different from the item to target. However, it’s up to your preference how to write the command.

The effect of :targeting will only last until the next command, but you can use multiple :targeting within the same entangle

Custom Image

When running into code outside the normal inventory logic using glitches like Item Stack Underflow, the simulator will probably crash because it does not contain the full game to be able to execute setups that involves code outside of the normal inventory code.

BUT, the simulator is capable of executing the whole game’s code if it is given access. This is refer to as the Full Mode or Custom Image Mode. To do this, you need to create a BlueFlame image (a .bfi file) from the game files

Create Image

To create the image, you need the following things:

  • Dump of the game (only some files are needed, not all of them)
  • A Nightly Rust toolchain
    • If you don’t have rust installed, see here

For detailed instructions on what is needed and steps to create the image, see the uking-relocate tool. Follow the instruction on the tool’s README.

The env Block

To tell the simulator to use a custom image instead of the default image, put an env block literal at the beginning of the script. The env block must be at the beginning, before any lines and comments. Empty lines are allowed before the block.

The env block should contain one <key> = <value> per line. Here is an example:

'''env
image = 1.5
dlc   = champions-ballad
program-start  = 0x0000001234500000
stack-start    = 0x0000005678900000
stack-size     = 0x40000
heap-free-size = 0x40000
pmdm-addr      = 0x0000003456789ab0
'''

Note

The numeric values must be hexadecimal, the leading 0x is optional

Note

If a value is invalid, it’s equivalent to that value being not specified. At the same time, you will see an error in the script editor.

The image key specifies the version of the game. Allowed values are 1.5 and 1.6.

Warning

Currently, only 1.5 is supported. 1.6 is recognized but not supported. Newer versions won’t be recognized by either the simulator or uking-relocate

The rest of the keys are optional. If not specified, the simulator will use the internal default values.

KeyValueDescription
dlca DLC specifier (see below)Specify the DLC version to simulate
program-startRegion AddressThe physical memory address of the start of the program region. This is checked against the program-start of the image file. The simulator cannot start if this doesn’t match. If this is not specified, any program-start will work.
stack-startRegion AddressThe physical memory address of the start of the stack
stack-sizeSizeThe size of the stack, must be aligned to 4KB
heap-free-sizeSizeSize of the free region of the heap for the simulator to allocate memory
pmdm-addrPhysical AddressThe address of the PauseMenuDataMgr (in other words, the value of PauseMenuDataMgr*). This is used to calculate heap start

Danger

Large stack/heap size can slow down simulator start-up. It is recommended to only change these if the default does not work for you.

DLC specifier can be any string that contains 0, 1, 2, or 3, which correspond to no DLC installed, DLC ver1.0 (Day 1), DLC ver2.0 (Master Trials) and DLC ver3.0 (Champions' Ballad). One of the following shorthand is recommended:

DLC VersionPossible Specifiers
No DLCnodlc, none, uninstalled
ver 1.0dlc-1, ver1.0, day-1
ver 2.0dlc-2, ver2.0, master-trials
ver 3.0dlc-3, ver3.0, champions-ballad

Invalid DLC version specifier defaults to ver3.0

A Region Address must be a hexadecimal string aligned to 0x100000, the most significant 6 hex-digits must be all 0.

A Size must be a 32-bit positive integer, aligned to 0x1000. A size of 0 is the same as unspecified, and the internal defaults will be used.

pmdm-addr must be aligned to 0x8.

Furthermore, the program, stack, and heap regions must not overlap.

Upload the Custom Image

Once image is specified in the env block, refresh the page. You should see a prompt that asks if you want to upload a custom image. Select Setup and follow the on-screen instructions to upload the .bfi file you created.

Note

If the custom image fails to load, you can always select Use Default Image in the prompt to start the application normally and fix your script.

The uploaded image is stored in your local browser.

Use Custom Image By Default

You can opt-in to always use your custom image for you own script, even when the env block doesn’t specify a custom image.

To enable this, check the box that says Use Custom Image by default for my scripts when uploading the custom image.

Delete Uploaded Custom Image

You can open the 3-dot menu on the top of the app and select Delete Custom Image. This clears the custom image file that is stored in your local browser.

Developer Manual

This section is highly technical and only intended for people who work with or are interested in the IST simulator as a developer. For example:

  • Contributing to the project
  • Building extensions for the simulator
  • Integrating components of the simulator to other things

The following chapters assume you have basic programming knowledge. The IST Simulator is built with TypeScript, Rust and some Python scripts for data processing. Familiarity in at least one of these languages will help with understanding.

It is recommended that you start with Architecture if you want to contribute code.

Architecture

On the architectural level, Skybook can be divided into 5 layers (or components, whatever you want to call them):

  • The Core: The Core is named BlueFlame. This layer is essentially a stripped-down, mini-emulator that interprets the game’s code. The core’s functionality is not limited to simulating IST, but can be expanded to other areas of the game if enough research is put into it.
  • The Runtime: The Runtime layer parses the script into steps and keeps track of the memory state of those steps in a simulation. It orchestrates the core for most of the simulation, and implements some sub-systems that are not supported by the core. The Runtime layer also manages multiple Cores to utilize multiple processors efficiently.
  • The Runtime Worker: Or simply the Worker layer, is the front-end of the Runtime. The Runtime layer is implemented in Rust, which is bad at handling async processes and requests. However, TypeScript is very good at that. So, the Worker layer essentially wraps the native interface with a TypeScript interface that the Application works with.
  • The Application: This is the main UI of the simulator web app, such as Pouch and GameData display.
  • The Extensions: The extensions are extra UI widgets that interface with the Application to easily add new features without changing the underlying architecture.

For the web application, there is also a server that handles DirectLoad - loading script from another source such as GitHub or embedded URL. The server doesn’t really have anything to do with the core functionality, so it’s not discussed here.

Getting Started

The first step to contributing is to setup a development environment locally on your PC.

I aim to make the setup process as streamlined as possible. If you encounter any issues, please feel free to reach out and suggest to me how it can be improved!

Info

Before starting the setup, follow the mono-dev Standard to setup the required tools:

  • Rust Toolchain
  • Node, PNPM, and Bun
  • Python
  • Task
  • Magoo

Coreutils is required for Windows development

Clone repository and one-time setup

Run the following commands

git clone git@github.com:Pistonite/botw-ist --depth 1
cd botw-ist
magoo install
task exec -- research:install
task install-cargo-extra-tools
task build-artifacts
task install
task check

This will:

  • Clone the repository to your PC using your GitHub account
    • If you don’t have GitHub account or don’t have SSH key setup, use https://github.com/Pistonite/botw-ist as the URL instead
  • magoo will setup the submodules for you
  • Research scripts will be ran to ensure data files are setup
  • Data artifacts will be built from the data files
  • Dependency packages will be downloaded
  • Configuration files will be generated

Keeping up-to-date

After pulling, you need to update the repo locally to sync tools to the latest state.

Run:

task install

That’s it!

The setup above will let you build and run the web app without building the Runtime locally. To build the Runtime, you need to set up a BlueFlame image in addition to the steps above.

Rename your image program.blfm and put it under /packages/runtime/, then run:

task exec runtime-wasm:build

Now the local build of the app will use the locally built Runtime.

Build and Run

This applies to development of:

  • The Web App
  • The Manual (this thing you are reading)
  • The Server

Tip

For all the commands like this:

task exec -- app:dev

You can also cd to the package and execute the task:

cd packages/app
task dev

Web Application

Warning

Running the web app locally requires Secure Origin, which means either running from localhost or setting up HTTPS, see here

To run the web application:

task exec -- app:dev

The UI will automatically reload as you make changes.

Note that DirectLoad will not work when running the application locally since it’s a server feature.

Manual

To run the manual (this website):

task exec -- manual:dev

The manual will automatically reload when making changes

Server

Warning

Currently, running the server locally also requires building the runtime as part of the assets, which requires a dump of the game to build

To run the server, first build and pull the application assets locally

task exec -- server:pull-local

Then the dev workflow can be started with

task exec -- server:dev

Changes in the server code will reload the server automatically. However, changes in the client code requires re-running the client build and restarting the server (sometimes)

Building the Runtime

While you can make changes and build the runtime packages locally, to run it, you must have a BlueFlame image.

Building the BlueFlame image requires you to dump some parts of the game. See uking-relocate for more info.

Once you have the game files prepared, put them in /packages/runtime-tests/data/botw150:

The directory structure should be like

packages/
  runtime-tests/
    data/
      botw150/
        romfs/
        main.elf
        rtld.elf
        sdk.elf
        subsdk0.elf

Then run task exec -- runtime-tests:build-mini to setup the mini image used for running the runtime locally.

Alternatively, you can put the built BlueFlame image at /packages/runtime-tests/data/program-full.bfi, then run:

cd packages/runtime-tests
task update-trace-hash
python scripts/relocate.py

This will also produce program-mini.bfi.

Once you have the mini image, you can now make changes to the runtime packages, and rebuild the WASM package:

cd packages/runtime-wasm
task build

After building the WASM package, run the web app (or reload if already running) for it to pick up the newly built changes.

Checking Testing

You should make sure your changes are properly checked and tested.

Most of the time, this means you should at least manually tested the change, and if needed, add at least one Snapshot Test if the runtime is changed.

Checking

Running task check in the root of the repo will run a handful of checks and lints. You can also run task exec -- XXX:check to only run checks for one package.

When there are formatting issues, task exec -- XXX:fix can automatically fix that.

skybook-api modification checks

If you changed code that affects the generated skybook-api code, you need to commit those changes to git for skybook-api checks to pass

localization checks

Certain changes require adding keys to localization (e.g. new error types). Please reach out to me for adding localizations.

The modification check also requires the changes to be commited to pass.

Unit and Manual Tests

We use Vitest for unit testing TypeScript code and standard Cargo test for Rust.

Also make sure to test your changes manually in the app. See Build and Run for how to run the app locally.

Snapshot Tests

Snapshot tests are the most important tests in the project. These tests are simulator scripts that the test tool runs and captures the state at each step, and saves them to a text file in a human readable format. Any diff in the snapshot is considered a failure.

To add a snapshot test, put a .txt file containing the script in /packages/runtime-tests/src/script_tests/, then run task exec -- runtime-tests:run-full (or run-mini). This will generate a new snapshot in snapshots/. Open the file and make sure the state is what you expect at every step.

If a snapshot test fails, the new snapshot will be saved to snapshots/wip. You can diff the snapshot with task diff -- NAME_OF_TEST. (Requires the delta tool). When you think the new snapshot is ready, copy it to snapshots and replace the old snapshot.

You can also run the ust task to update all snapshots.

Translations

The translation files are located in packages/localization/src/ui/*.yaml.

Here’s what you need to know when modifying the translation files:

  • Each translation entry is in the format of <key>: "<value>"
  • To escape " inside the value, put \".
  • Tokens like {{data}} are placeholders that will be replaced with the actual text in the app. Keep this in mind if you can’t find the entry you are looking for.

To add new translations, follow these steps:

  1. Add the new key and English value in en-US.yaml
  2. Prepare a translation file like this:
     # en-US is optional and will be ignored, 
     en-US: 
       button.ok: "OK"
     # order of languages/keys below does not matter
     # you can also include multiple keys
     de-DE:
       button.ok: "OK"
     es-ES:
       button.ok: "Aceptar"
     ko-KR:
       button.ok: "확인"
     zh-CN:
       button.ok: "好的"
    
  3. Go to the localization package (cd packages/localization)
  4. Run the edit task and pass in your file
    task edit -- path/to/your/file
    

This will apply the edits to the translation files and make sure everything is formatted. Note that existing values will be overridden and values not found in English will be deleted.

To change the translation for one language, simply modify the language files.

Extensions

The simulator supports extensions. Each extension is an embedded web page that communicates with the app through the messaging API.

Builtin extensions

Custom extensions

The simulator supports loading your own or 3rd-party extensions.

Custom extensions have some restrictions:

  • They can only be opened as popups

Creating custom extension

Custom extension can be built with any technology as long as it’s served as a HTML webpage in the end. The @pistonite/create-skybook-extension script will create a vite project with React + TypeScript

You need to following tools:

  • NodeJS
  • pnpm

Run

pnpm exec @pistonite/create-skybook-extension@latest

Custom extensions uses the @pistonite/skybook-api library to communicate with the host app.

import { 
    bindExtensionHost, 
    type ExtensionApp,
} from "@pistonite/skybook-api/sides/extension";
import { connectPopoutExtensionModule } from "@pistonite/skybook-api/extension";
import { type Delegate, hostFromDelegate } from "@pistonite/workex";

// client to call the app
let app: ExtensionApp | undefined = undefined;

const properties = readExtensionProperties();
properties.params.foo // you can pass in parameters from search param

// your extension. these are functions that the app will call you
const delegate = {
    onDarkModeChanged: async (dark) => {
        console.log("User changed the dark mode to: " + dark)
    },
    onLocaleChanged: async (locale) => {
        console.log("User changed the language to: " + locale)
    },
    onScriptChanged: async (script) => {
        console.log("User changed the script to: " + script)
    },
    onStepChanged: async (script, step) => {
    },
    onViewChanged: async (script, step) => {
    },

    // please raise an issue on GitHub if your use case requires
    // more 

} satisfies Delegate<ExtensionApp>;

const extension: ExtensionModule = {
    ...hostFromDelegate(delegate),
    onAppConnectionEstablished: (theApp) => {
        // Code here will be called before events in delegate
        // save the app reference here to use later
        app = theApp;
    }
}

// initiate communication
await connectPopoutExtensionModule(extension, properties);

// on handshake complete, your extension will be connected to the app!
// you will receive a seriers of "change" events

// you can use app's functionality to get properties:
const result = await app.resolveItem("apple", false, 1);
// { val: { val: ["Item_Fruit_A"] } }


Note that it’s your responsibility to make sure your extension keeps up with the latest version of @pistonite/skybook-api, there will be announcement in advance if breaking changes will happen.