For more details about how Foundry VTT installs and updates packages, see the full article Package Releases and Version History.
version
string
for the version number instead of a float
because for example 0.9
would be superior to 0.10
if using floats.isNewerVersion
helper so they should be avoided.You should never have two different versions of your package with the exact same version number. This will cause problems especially for users of the Forge, but more generally makes troubleshooting harder: "Do you have the first v1.2.3, or the second v1.2.3?"
manifest
manifest
URL should use a stable url that always points at the Latest manifest JSON.manifest
URL should be Raw JSON or a download link, not the github html view of the JSON.¶ Bad Examples
https://github.com/ElfFriend-DnD/foundryvtt-compactBeyond5eSheet/blob/master/src/module.json
This is a link to the HTML view of the module.json
C:\Users\elffriend\moduleDev\foundryvtt-compactBeyond5eSheet\src\module.json
This is a local file on your machine.
¶ Good Examples
https://github.com/ElfFriend-DnD/foundryvtt-compactBeyond5eSheet/releases/latest/download/module.json
Links to the latest release'smodule.json
artifact. This link will never change even if the module's files move around.
https://raw.githubusercontent.com/ElfFriend-DnD/foundryvtt-compactBeyond5eSheet/master/src/module.json
⚠️ This url will break if the module's files are rearranged, but apart from that it is stable.
download
download
URL should point to a specific zip that matches the version.master
branch) but rather each version's module.json manifest
url would download that specific version.There's a lot of nuance to localization that can't be summed up quickly. Take a look at the dedicated Localization Best Practices article for more in depth best practices.
Don't hardcode your strings, use localization right from the start. It is easier to localize from the start rather than going back through at the end.
Re-use as many core and system keys as possible, but understand that some languages might have longer or shorter words than you expect. In cases where a flexible layout is not possible, it is recommended to create a new key with the same text to allow translators to provide a custom translation that fits the static layout best.
Keep your localization strings confined to your package's namespace.
kebab-case
where your spaces are replaced with -
.game.modules.get('my-module-name')?.api
.libWrapper
library module is an excellent dependency to aid in the "patching" of core functions.From Atropos:
The risk of this kind of failure will always be higher for modules which fundamentally exist for the purpose of overwriting core functions to behave differently in ways that are not allowed by the supported API. Not to pick on the "Perfect Vision" module - but it excavates most of the vision/lighting rendering of Foundry VTT and replaces it with different logic. A module like this is extremely vulnerable to all sorts of breaks in ways that I cannot possibly account for when I am making development decisions.
If you're writing a module that carves out the guts of a core Foundry VTT function and replaces it with entirely different logic - it would be prudent to have some way to abort or fall-back to the core logic in cases where your overridden logic fails
When adding buttons to the Heading of a Sidebar Tab, append your buttons to the .actions-buttons
div and not to the .directory-header
div.
Hooks.on('renderJournalDirectory', (app, html, data) => {
const actionButtons = html.find('.action-buttons');
const myButton = '<button>My Button</button>';
actionsButton.append(myButton);
});
By default, this will make all buttons in the header squish down to hide their text before wrapping, if you wish to avoid that behavior, add some CSS to .actions-buttons button
which forces their min-width
to be max-content
, for bonus compatibility with some systems, also add white-space: nowrap
.
.actions-buttons button {
min-width: max-content;
white-space: nowrap;
}
When adding configuration options to the Adventure Import sheet, put them in a column to the right of the "Contents" section. See this issue for example code and more info.