For more details about how Foundry VTT installs and updates packages, see the full article Package Releases and Version History.
versionstring 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?"
manifestmanifest 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.jsonartifact. 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.
downloaddownload 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.