Skybook
The Inventory Slot Transfer Simulator Project
Getting started
- How to use the simulator
- Brief Overview of Inventory Slot Transfer
- Contributing to Translations
- Technical details for developers
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
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.
If you goal is to add extra functionality, you might be able to do that through an extension, See [TODO add link here]
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
.
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.
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 bool
s (whether the item is equipped),
and PorchItem_Value1
is an array of 420 s32
s (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.
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:
- Delete all of your current items in
Visible Inventory
. - 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
.
- Add the items
GameData
one by one into theVisible 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)
- Weapon Modifier Corruption (WMC)
- Prompt Entanglement (PE)
- Item Stack Underflow
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:
- 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)
- 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.
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:
- Desyncing GameData
- Apply durability while GameData is desynced.
IST makes desyncing GameData trivial. Recall the 3 steps for reloading:
- Delete all items
- Load GameData
- 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.
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
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:
- The game always add the item to the end of the inventory
- 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
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.
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 theValue
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 theType
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
- The
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:
- 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
, notGameData
- This is only true for
- 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:
- Making sure the last added item is the weapon to receive the corrupted modifier
- 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.
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:
- Note that in the save, the items are 1
hammer
and the donor meal, these are what will be added during reload - Note that we are transferring 60
dubious-food
- During the reload, the
hammer
loads in first - When loading the donor meal, since there are already 60 food, it fails to load.
- Since the last added item was the
hammer
, the data from the meal is transferred to the hammer
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:
- Using the Food Limit method, transfer the data from the donor meal to a Stackable food (i.e. a roasted/baked/frozen food)
- Using Direct Inventory Corruption, corrupt the food value to >=500
- 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)
- 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
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!
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:
- A Master Sword is transferred (can be broken or not broken)
- 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
- The Master Sword Recharge Timer in the save being loaded is non-zero
- 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
When all of the above conditions are met, last added item is set to nullptr
, enabling the exploit.
The whole setup would be:
- Enable the exploit as described above
- 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
- Now any food that load after will have the data that’s supposed to be on the food before it
- 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:
- Make a save with Travel Medallion being the first item, and food after it (using Unsorted Inventory )
- 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
- Reload the save, setup IST again to transfer some food to make the food fail to load
- 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
- Now any food that load after will have the data that’s supposed to be on the food before it
- 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)
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:
- Make a save with the Daily Bonus and Deposit Item being the first 2 items, and food after it (using Unsorted Inventory )
- 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
- The rest is similar to TMWMC
Prompt Entanglement (PE)
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.
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
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
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
.
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
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 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.
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
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
andhold
- 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
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
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:
-
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
- The amount must be a number, not keywords like
-
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.
- The amount could be a number or the keyword
-
CONSTRAINED_ITEM_LIST
- The amount could be a number, or:
- The keyword
all
- In the form
all but X
, whereX
is a number.
- The keyword
- 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
andeat
. - Position properties can be used
- The amount could be a number, or:
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 actioncount - X
times. How the total number is counted depends on the command, similar to the eat vs sell situation mentioned earlier.
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.
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:
- By
Identifier
- An Item Identifier is multiple english words (A
toZ
, case-insensitive), combined with-
or_
. For example,royal-claymore
andtrav-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
forgreat-eagle-bow
,aa
forancient-arrow
.
- The result is an item that contains all the individual words, for example
- By
Actor
- You can use angle brackets (<>
) to specify the internal actor name directly, for exampleget <Weapon_Sword_070>
. You cannot specify cook effect in this way. - 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)
- 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 likeunequip shield
where you don’t need to care what shield is currently equipped, orpick-up 3 weapons
, where it doesn’t matter which weapons are picked up.
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 newpot-lid
with1
durability
- For example,
- 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 exactly1
durability.
- For example, if you are multiple
The metadata value can be one of the following types:
string
- english words separated by-
or_
int
- an integer in decimal or hex (prefixed with0x
)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
orfalse
. The value can be omitted to indicatetrue
, for example,drop pot-lid[equipped]
is the same asdrop pot-lid[equipped=true]
Full list of item metadata properties:
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).
Property | Aliases | Description |
---|---|---|
durability | dura | (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 | |
equipped | equip | (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-recover | hp , modpower | (int ) Sets the number of quarter-hearts cooked-food recovers, or value of a weapon modifier |
modifier | modtype | (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 | |
value | life | (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]
- If the slot selected by position has a different item, you will receive an error
- When using
row
andcol
, they must be specified aftercategory
ortab
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
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
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.
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.
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 gamereload
orreload SAVE_NAME
to start the game and reload a saveSAVE_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
- When pause the game with the
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
andSelling
, but not toOverworld
- When returned to overworld, screen can be automatically switched again to all types
- Screen can be automatically switched between
untalk
orclose-dialog
to return to overworld
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 Actor
s. 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.
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 be10
apples left on the ground, and5
are added to the inventory. - If you
pause
, there will still be15
apples on the ground, since you couldunpause
and pick them up - If you
get 3 bananas
, the despawning items will now be deleted, and there will be10
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
, orleave 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
- 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.
Command | Description |
---|---|
get | Getting an item |
cook | Cook ingredients and get the cooked result |
drop | Drop held items or specific items in inventory to the ground |
hold | Hold items in your hand |
hold-attached | Hold items in your hand and trigger the state where items are attached to the right hand |
overload | Trigger Menu Overload |
stop-overload | Stop Menu Overload |
pick-up | Pick up an item from the ground |
unhold | Put 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.
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
andpick-up
requireOverworld
screen. - You cannot get new items while holding items in the overworld
- with
:smug
, the held items will be dropped after getting the item
- with
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:
- Enable Weapon Smuggle and make sure a shield is equipped
- Hold the
ZL
button - Hold items from up to 5 slots
- Switch to a one-handed weapon
- Switch to another or to something else and back if you are already equipping a one-handed weapon
- 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
requiresInventory
screenunhold
requires eitherOverworld
orInventory
screen, and will automatically switch toOverworld
if not satisfiedhold
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
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
The use
command is also used for using equipments in the overworld
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.
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
anddnp
requiresOverworld
screen if dropping materials, andInventory
for dropping equipments.- The simulator may switch screen back and forth during the same
drop
action to facilitate this
- The simulator may switch screen back and forth during the same
use
requiresOverworld
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
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.
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
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 touse 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
andunequip
requireInventory
screen- If
:dpad
is used,Overworld
screen is required.
- If
use
,throw
anddisplay
requireOverworld
screen.
Shop
Buy or sell items from a shop.
Syntax
talk-to NPC
(can be any word)
untalk
ORclose-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 buy
ing 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 sell
ing 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
is0
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
requiresOverworld
orShop Buying
screen- It will automatically switch to
Overworld
by default. The:same-dialog
annotation can be used to switch toShop Buying
fromShop Selling
- It will automatically switch to
sell
requiresShop Selling
screen.Buying
andSelling
screens can be automatically switched between by the simulator even if it’s manually switched fromOverworld
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
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
orZR > 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
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.
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
: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
'''
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
.
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.
Key | Value | Description |
---|---|---|
dlc | a DLC specifier (see below) | Specify the DLC version to simulate |
program-start | Region Address | The 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-start | Region Address | The physical memory address of the start of the stack |
stack-size | Size | The size of the stack, must be aligned to 4KB |
heap-free-size | Size | Size of the free region of the heap for the simulator to allocate memory |
pmdm-addr | Physical Address | The address of the PauseMenuDataMgr (in other words, the value of PauseMenuDataMgr* ). This is used to calculate heap start |
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 Version | Possible Specifiers |
---|---|
No DLC | nodlc , none , uninstalled |
ver 1.0 | dlc-1 , ver1.0 , day-1 |
ver 2.0 | dlc-2 , ver2.0 , master-trials |
ver 3.0 | dlc-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.
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 namedBlueFlame
. 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!
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
- If you don’t have GitHub account or don’t have SSH key setup, use
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
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
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
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:
- Add the new key and English value in
en-US.yaml
- 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: "好的"
- Go to the
localization
package (cd packages/localization
) - Run the
edit
task and pass in your filetask 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.