New FoundryVtt Dev, I want to adapt a system, where to start?

I'm here looking for some help. I want to adapt a system I play regularly, and despite my current JS Experience, I have absolutely no FoundryVTT Development experience. While I see the Boilerplate tutorial, I'm slightly worried because it seems a bit out of date, while I want to make that system up to date with the latest FoundryVTT versions (Aka v13 currently). My main goal here is to adapt said system, and the wiki confuses me slightly due to how many resources seems to be made for pre v13, or even pre v12 for the main tutorial I read, the Boilerplate tutorial. Is there anything I'm missing, any advices I could get, any useful resources to get started on this project? Thank you in advance!
51 Replies
CussaMitre
CussaMitre•2mo ago
Hello, check the Pull Request, as we have a V13 PR opened There are not so many differences between V12 and V13, and most of them (if not all) were addressed in the PR
AkumaCipher
AkumaCipherOP•2mo ago
Ah, I see! Thank you, I've managed to generate a system on that. I'll try to see what I can do with it for now. Do you perhaps have any advices or ressources I may have missed that could be useful to me outside of the boilerplate tutorial then?
CussaMitre
CussaMitre•2mo ago
Not really. The wiki, although not updated at some points, has a lot of information for some things. And the API docs don't have examples for all methods, but it still provides information. And for anything else, there is the system development channel on Foundry server
AkumaCipher
AkumaCipherOP•2mo ago
Alright, thank you again for the answer! Hey! Hope I'm not bothering, but this is far more precise question this time. I am thinking about how to adapt the Attribute Modifiers for the system I'm adapting, and as I'm using the Boilerplate template, I see what it does is declare the ability mods as derived data in the Data Model File. However, I was thinking of declaring it in prepareDerivedData() in the actor.mjs file. My real question is does this have an impact? Would the declaration being in the prepareDerivedData() of the actor.mjs document file change anything from it being in the base-actor.mjs data model file?
AkumaCipher
AkumaCipherOP•2mo ago
For more infos, here are images. In order, the place where I was planning to declare my ability mods, and the place where it was "declared" by default by boilerplate, with me wondering if it'd change anything to move that declaration?
No description
No description
CussaMitre
CussaMitre•2mo ago
The document/actor.mjs is the whole actor document. The data/base-actor.mjs is your system implementation, which will be included on the system property. Given that, unless your changes are affecting the whole actor document, I would recommend you to stick with doing that in the data file
AkumaCipher
AkumaCipherOP•2mo ago
I'm having a slight trouble understanding, so this means most "properties" I want to declare as Derived Data from, say, the ability values of an actor, should be declared in prepareDerivedData() in data/base-actor.mjs instead of document/actor.mjs?
CussaMitre
CussaMitre•2mo ago
All the properties that you will define for your system will be on the actor.system, which is defined by the data/base-actor.mjs or the classes that inherited from it. So, if your derived data is based on your system's properties, I would say that makes more sense to have them in the data/base-actor.mjs.
AkumaCipher
AkumaCipherOP•2mo ago
I see, thank you again!
AkumaCipher
AkumaCipherOP•2mo ago
So, what I should do, since earlier I had declared DerivedData from the values here in prepareDerivedData() in documents/actor.mjs like the first image shows, is move those declared derived data into data/base-actor.mjs... I see, thank you.
No description
AkumaCipher
AkumaCipherOP•2mo ago
Before anything, should I make a new post, or change the title of this post since I'm mostly using this for any help on my system from now on? After what you've said to me, I was wondering, does this structure seemed correct for both actor.mjs and base-actor.mjs? I decided to declare almost all of these in actor.mjs since it was less so system properties and more actor ones, if that makes sense. For context, I'm mostly trying to apply the basic rules present in these two pages of the system: - Character Creation for Life Points, Ki Points, and Capacity Rate. - Attributes for Aptitudes and Saving Throws.
GitHub
dragon-ball-universe/module/documents/actor.mjs at main · AkumaCip...
The Dragon Ball System for Foundry VTT. Contribute to AkumaCipher/dragon-ball-universe development by creating an account on GitHub.
CussaMitre
CussaMitre•2mo ago
So, there is no right or wrong. You basically have the liberty to do that how you want 🙂 But conceptually speaking, I believe that it is a little bit off... Do you see how everything you are working here is coming from the system? This is a clear tip that this is on the wrong place. Here is how most systems will work: - Actor.mjs: will have things that are related to the "actor" class. So, things like default images (img property), prototype token, permissions... - Base-actor.mjs: any information that comes from your system. So, attributes, abilities, spells, items, etc.
No description
AkumaCipher
AkumaCipherOP•2mo ago
Ah! Okay, I see where I got that part wrong. I'll fix that when I can, thank you very much.
AkumaCipher
AkumaCipherOP•2mo ago
GitHub
dragon-ball-universe/module/documents/actor.mjs at main · AkumaCip...
The Dragon Ball System for Foundry VTT. Contribute to AkumaCipher/dragon-ball-universe development by creating an account on GitHub.
GitHub
dragon-ball-universe/module/data/base-actor.mjs at main · AkumaCip...
The Dragon Ball System for Foundry VTT. Contribute to AkumaCipher/dragon-ball-universe development by creating an account on GitHub.
CussaMitre
CussaMitre•2mo ago
Yeap, this makes more sense 🙂
AkumaCipher
AkumaCipherOP•2mo ago
Thank you very much! Next is creating methods, or anything that fits for this task, to handle my rolls much better... I might come back later haha, thank you for the help!
AkumaCipher
AkumaCipherOP•2mo ago
And indeed I have come back! After cleaning my code a bit more and adding localisations for what I had declared until now, I tried looking up on how to, well, declare methods and try to see if I could influence the way FoundryVTT parse rolls, but I have trouble finding anything on it that could help me start doing that. in fact, i have trouble specifically seeing how this page can help me alter FoundryVTT so that it handles the dice rolling the system i'm adapting uses? (Explained here)
Foundry VTT Community Wiki
Roll
An interface and API for constructing and evaluating dice rolls.
Andreavnn
Dragon Ball Universe
Core Rules
The following are the main, essential rules that form the base of the entire DBU system. Here, you will learn how each of these rules affects general and specific game functions. The better you com…
AkumaCipher
AkumaCipherOP•2mo ago
Okay! I've actually managed to figure this out haha. Now, I wanna make a method that helps me "create" an extra dice, but I'm not sure where I'd put that method, as it'd probably help me in a lot of place. Where should I put this? In a .mjs file in the helpers folder?
CussaMitre
CussaMitre•2mo ago
Oh! Sorry! I had several meeting for the projects we are working on and I had to review a PR for one system. And then I came here! Happy you solved that!
AkumaCipher
AkumaCipherOP•2mo ago
There's no problems, thank you very much still! Now, on the question I just asked however, I was thinking of making a utils.mjs file (if somehow I do not have one already) and make my method in it
CussaMitre
CussaMitre•2mo ago
It is quite common that people create some "helper" files to put some of the logic, so that should not be a problem
AkumaCipher
AkumaCipherOP•2mo ago
Thank you, this has worked perfectly well. In fact I have, in my opinion, taken a huge step towards adapting this system. Thank you so much for your repeated help!
AkumaCipher
AkumaCipherOP•5w ago
I have a (another!) question. If I wanted to make this system downloadable already, what would I need to setup? My project is already in a github repo and my system.json is (normally) well setup, but I believe I'm missing some things in my repository for the system to be downloadable. What would those be?
GitHub
GitHub - AkumaCipher/dragon-ball-universe: The Dragon Ball System f...
The Dragon Ball System for Foundry VTT. Contribute to AkumaCipher/dragon-ball-universe development by creating an account on GitHub.
AkumaCipher
AkumaCipherOP•5w ago
Is there a guide somewhere to help me make the system downloadable? I haven't been able to find one sadly 😅
CussaMitre
CussaMitre•5w ago
You probably need to create a release so it generates a zip file with the content and updates the download address in the system.json As you can run different instances of foundry with the portable, my recommendation would be to start an instance and try to install and check the issues you will face
AkumaCipher
AkumaCipherOP•5w ago
I see, alright, thank you!
CussaMitre
CussaMitre•5w ago
AFAIR, the boilerplate tutorial had something related to that. If not, I would recommend checking some other system that already implemented what you want. I can reference the Coriolis TGD: https://github.com/hodpub/coriolis-tgd It has the workflows to create a release and even publish that into the Foundry (which I am not sure if you will be able to do, given that your system handles some information protected by copyright)
GitHub
GitHub - hodpub/coriolis-tgd
Contribute to hodpub/coriolis-tgd development by creating an account on GitHub.
AkumaCipher
AkumaCipherOP•5w ago
Oh? Alright, I'll check that out then. (Also yes I probably won't be able to do that 😅) I was wondering about my system files, I must admit base-actor.mjs is looking mighty big right now, and I'm worried that I may have not structured my system very well 😅
CussaMitre
CussaMitre•5w ago
That could happens. The trick is: if this is something that applies to all your actors, that's the right place. If it only applies to some of them, you probably should have another inheritances there
AkumaCipher
AkumaCipherOP•5w ago
Hey again! Any idea on how I could add settings to my Foundry VTT system? I'm having a little bit of trouble searching for that. Context is, I finally made rolls that come from stuff on the sheet, and I've technically automated natural failures and successes, but i want to make that automation optional! And uh... Having just a bit of trouble finding that haha
CussaMitre
CussaMitre•5w ago
Foundry VTT Community Wiki
Settings
Provide user configuration for your package
CussaMitre
CussaMitre•5w ago
This should help you 🙂
AkumaCipher
AkumaCipherOP•5w ago
Oh wow how did I not find this, thank you very much! Thank you, it's served me well indeed! :D
AkumaCipher
AkumaCipherOP•4w ago
Hello! It's me again, I had a question. Currently doing a button, and I want to increase the width of it, since I have this problem:
No description
AkumaCipher
AkumaCipherOP•4w ago
And unfortunately, trying to look through the DialogV2 documentation hasn't helped me so far :/ So I wanted to know if you possibly had a solution?
CussaMitre
CussaMitre•4w ago
static DEFAULT_OPTIONS = {
position: {
width: 600,
},
};
static DEFAULT_OPTIONS = {
position: {
width: 600,
},
};
Update your default options to include the width
AkumaCipher
AkumaCipherOP•4w ago
So, following your advice, I quickly made my own class for my type of dialog, like this:
export class DragonBallUniverseDialog extends foundry.applications.api.DialogV2 {
static DEFAULT_OPTIONS = {
position: {
width: 600,
},
};
}
export class DragonBallUniverseDialog extends foundry.applications.api.DialogV2 {
static DEFAULT_OPTIONS = {
position: {
width: 600,
},
};
}
Then, in my method where I was using a Dialog, I switched, now using that dialog:
let data;

data = await DragonBallUniverseDialog.input({
window: { title: "Strike Roll Customisation!" },
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
submit: result => {
console.log(result);
}
});
let data;

data = await DragonBallUniverseDialog.input({
window: { title: "Strike Roll Customisation!" },
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
submit: result => {
console.log(result);
}
});
Unfortunately, I still have the same width as right before, no matter how I change it :/
CussaMitre
CussaMitre•4w ago
In theory, you could add the information directly on the dialog Give me some minutes to test here
AkumaCipher
AkumaCipherOP•4w ago
No problem, thank you very much for helping me
CussaMitre
CussaMitre•4w ago
So, I was able to do something like this:
foundry.applications.api.DialogV2.input({
window: { title: "Strike Roll Customisation!" },
position: {
width: 1000,
},
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
submit: result => {
console.log(result);
}
});
foundry.applications.api.DialogV2.input({
window: { title: "Strike Roll Customisation!" },
position: {
width: 1000,
},
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
submit: result => {
console.log(result);
}
});
Just adding the position with the width directly in the dialogv2.input
AkumaCipher
AkumaCipherOP•4w ago
Oh, this does work indeed, huh. Thank you very much once again, you've been such a big help for my project 😅
CussaMitre
CussaMitre•4w ago
Just to mention: as you are using the input, you can get the return that will be the data that you put on the content.
let content = "<input type='text' name='test' value='Test'></input>";
const result = await foundry.applications.api.DialogV2.input({
window: { title: "Strike Roll Customisation!" },
position: {
width: 1000,
},
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
});
result;
let content = "<input type='text' name='test' value='Test'></input>";
const result = await foundry.applications.api.DialogV2.input({
window: { title: "Strike Roll Customisation!" },
position: {
width: 1000,
},
content: content,
ok: {
label: "Roll",
icon: "fa-solid fa-dice-d6",
},
});
result;
The result will be in this case:
{
"test": "Test (or the value typed)"
}
{
"test": "Test (or the value typed)"
}
AkumaCipher
AkumaCipherOP•4w ago
Yes, I indeed noticed that! But I also noticed that if I called my data through submit, it wouldn't do anything out of that submit if the user simply closed the Dialog, and that's exactly what I want without having to check result behind it haha. Thank you still, this is useful information
CussaMitre
CussaMitre•4w ago
I am not sure if I followed what you are saying. If the user just close the dialog without rolling, both cases will have the "result" as null
AkumaCipher
AkumaCipherOP•4w ago
Huh, weird, I suppose I'll check if what I want works as intended, if not I'll probably do what you showed me since that works as well 😅
AkumaCipher
AkumaCipherOP•4w ago
Hey! Me again, so I have a slight problem with my html fields, and I believe a video is best to show what I mean. I was wondering if this was a known problem, or not? Because I've been trying to see what could cause this and I can't find it :/ transformations.hbs:
{{! Transformations Tab }}
<section class='tab transformations scrollable {{tab.cssClass}}' data-group='primary' data-tab='transformations'>

{{! Editors must receive enriched text data from getData to properly handle rolls, UUID links, etc. }}
{{#if editable}}
<prose-mirror name="system.transformationTabDescription" data-document-uuid="{{actor.uuid}}" value="{{system.transformationTabDescription}}" collaborate="true" toggled="true">
{{{enrichedTransformationInformation}}}
</prose-mirror>
{{else}} {{{enrichedTransformationInformation}}}
{{/if}}
</section>
{{! Transformations Tab }}
<section class='tab transformations scrollable {{tab.cssClass}}' data-group='primary' data-tab='transformations'>

{{! Editors must receive enriched text data from getData to properly handle rolls, UUID links, etc. }}
{{#if editable}}
<prose-mirror name="system.transformationTabDescription" data-document-uuid="{{actor.uuid}}" value="{{system.transformationTabDescription}}" collaborate="true" toggled="true">
{{{enrichedTransformationInformation}}}
</prose-mirror>
{{else}} {{{enrichedTransformationInformation}}}
{{/if}}
</section>
biography.hbs:
{{! Biography Tab }}
<section
class='tab biography scrollable {{tab.cssClass}}'
data-group='primary'
data-tab='biography'
>
{{! Editors must receive enriched text data from getData to properly handle rolls, UUID links, etc. }}
{{#if editable}}
<prose-mirror name="system.biography" data-document-uuid="{{actor.uuid}}" value="{{system.biography}}" collaborate="true" toggled="true">
{{{enrichedTransformationInformation}}}
</prose-mirror>
{{else}} {{{enrichedBiography}}}
{{/if}}
</section>
{{! Biography Tab }}
<section
class='tab biography scrollable {{tab.cssClass}}'
data-group='primary'
data-tab='biography'
>
{{! Editors must receive enriched text data from getData to properly handle rolls, UUID links, etc. }}
{{#if editable}}
<prose-mirror name="system.biography" data-document-uuid="{{actor.uuid}}" value="{{system.biography}}" collaborate="true" toggled="true">
{{{enrichedTransformationInformation}}}
</prose-mirror>
{{else}} {{{enrichedBiography}}}
{{/if}}
</section>
actor-sheet.mjs:
case 'transformations':
// Enrich biography info for display
// Enrichment turns text like `[[/r 1d10]]` into buttons
context.enrichedTransformationInformation = await ux.TextEditor.enrichHTML(
this.actor.system.transformationTabDescription,
{
// Whether to show secret blocks in the finished html
secrets: this.document.isOwner,
// Data to fill in for inline rolls
rollData: this.actor.getRollData(),
// Relative UUID resolution
relativeTo: this.actor,
}
);
break;
case 'gear':
context.tab = context.tabs[partId];
break;
case 'biography':
context.tab = context.tabs[partId];
// Enrich biography info for display
// Enrichment turns text like `[[/r 1d10]]` into buttons
context.enrichedBiography = await ux.TextEditor.enrichHTML(
this.actor.system.biography,
{
// Whether to show secret blocks in the finished html
secrets: this.document.isOwner,
// Data to fill in for inline rolls
rollData: this.actor.getRollData(),
// Relative UUID resolution
relativeTo: this.actor,
}
);
break;
case 'transformations':
// Enrich biography info for display
// Enrichment turns text like `[[/r 1d10]]` into buttons
context.enrichedTransformationInformation = await ux.TextEditor.enrichHTML(
this.actor.system.transformationTabDescription,
{
// Whether to show secret blocks in the finished html
secrets: this.document.isOwner,
// Data to fill in for inline rolls
rollData: this.actor.getRollData(),
// Relative UUID resolution
relativeTo: this.actor,
}
);
break;
case 'gear':
context.tab = context.tabs[partId];
break;
case 'biography':
context.tab = context.tabs[partId];
// Enrich biography info for display
// Enrichment turns text like `[[/r 1d10]]` into buttons
context.enrichedBiography = await ux.TextEditor.enrichHTML(
this.actor.system.biography,
{
// Whether to show secret blocks in the finished html
secrets: this.document.isOwner,
// Data to fill in for inline rolls
rollData: this.actor.getRollData(),
// Relative UUID resolution
relativeTo: this.actor,
}
);
break;
https://cdn.discordapp.com/attachments/670336275496042502/1414612668123451515/Enregistrement_de_lecran_2025-09-08_160028.mp4?ex=68c03436&is=68bee2b6&hm=e11835ea4de0283b90b2fb88711d6ccd6ef24823c1ad98747e3843286d8197e8&
AkumaCipher
AkumaCipherOP•4w ago
As always, everything is available on my repository
GitHub
GitHub - AkumaCipher/dragon-ball-universe: The Dragon Ball System f...
The Dragon Ball System for Foundry VTT. Contribute to AkumaCipher/dragon-ball-universe development by creating an account on GitHub.
CussaMitre
CussaMitre•4w ago
I am not sure if this is the issue, as I can't run your code now... but I see that you are missing this line on the case for the transformations: context.tab = context.tabs[partId]; not only that, but the way your case is constructed, it seems that it will be doing this enrich for features and combat too, which is probably not what you want
AkumaCipher
AkumaCipherOP•4w ago
Oh god, it is indeed just that. I didn't realize those case being written like this could pose a problem... 😅 Once again, thank you very much Hey, me again! I'm trying to make it so if a user types -5 in the current hp value, it parses it and makes the calculation for them. I tried two methods and, sadly, none of them worked: - Using a pre update method in the document to try to influence the value - Using the validate option on the correct NumberField And since none of them worked, I was wondering if you had an idea?
CussaMitre
CussaMitre•4w ago
The question is: do you really need that in the sheet? Because if you create a token for that, and include your health as an attribute bar, it will have that from the token automatically. Besides, most systems apply damage from the damage chat message, including a button there to do that.
AkumaCipher
AkumaCipherOP•4w ago
Oh Indeed you're right! I was mostly doing this as a QoL thing for users, but since foundry does it automatically... I simply had to setup the ressources, and that was it! I'll simply search for how to include buttons on the "wound rolls" the users can do, like that it'll be easier for players to also apply damage :D

Did you find this page helpful?