diff --git a/.eslintignore b/.eslintignore
index 03caea5e..5ff9ec06 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -6,3 +6,5 @@
 /.pnp.cjs
 /.pnp.loader.mjs
 /.yarn/
+client
+common
diff --git a/.gitignore b/.gitignore
index a45e3fd1..f8959419 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,7 @@ junit.xml
 !.yarn/sdks
 !.yarn/versions
 .pnp.*
+
+# foundry
+client
+common
diff --git a/.prettierignore b/.prettierignore
index 2080674e..2a9469b0 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -8,3 +8,5 @@
 /.pnp.loader.mjs
 /.yarn/
 /.vscode/
+client
+common
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 00000000..1e137104
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,8 @@
+{
+    "compilerOptions": {
+        "module": "es2022",
+        "target": "ES2022"
+    },
+    "exclude": ["node_modules", "dist"],
+    "include": ["src", "client", "common"]
+}
diff --git a/jsconfig.json.license b/jsconfig.json.license
new file mode 100644
index 00000000..467ee146
--- /dev/null
+++ b/jsconfig.json.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2022 Johannes Loher
+
+SPDX-License-Identifier: MIT
diff --git a/package.json b/package.json
index 2937aaf8..482d0ffe 100644
--- a/package.json
+++ b/package.json
@@ -64,18 +64,9 @@
         "@commitlint/cli": "17.3.0",
         "@commitlint/config-conventional": "17.3.0",
         "@guanghechen/rollup-plugin-copy": "2.1.4",
-        "@league-of-foundry-developers/foundry-vtt-types": "9.280.0",
-        "@pixi/constants": "6.2.1",
-        "@pixi/core": "6.2.1",
-        "@pixi/display": "6.2.1",
-        "@pixi/graphics": "6.2.1",
-        "@pixi/math": "6.2.1",
-        "@pixi/runner": "6.2.1",
-        "@pixi/settings": "6.2.1",
-        "@pixi/utils": "6.2.1",
-        "@rollup/plugin-typescript": "10.0.0",
         "@swc/core": "1.3.20",
         "@types/fs-extra": "9.0.13",
+        "@types/jquery": "3.5.14",
         "@types/node": "18.11.9",
         "@typescript-eslint/eslint-plugin": "5.44.0",
         "@typescript-eslint/parser": "5.44.0",
@@ -85,6 +76,7 @@
         "eslint-config-prettier": "8.5.0",
         "eslint-plugin-prettier": "4.2.1",
         "fs-extra": "10.1.0",
+        "handlebars": "4.7.7",
         "npm-run-all": "4.1.5",
         "prettier": "2.8.0",
         "rimraf": "3.0.2",
diff --git a/spec/tsconfig.json b/spec/tsconfig.json
index a5662b44..23db97a9 100644
--- a/spec/tsconfig.json
+++ b/spec/tsconfig.json
@@ -1,7 +1,4 @@
 {
     "extends": "../tsconfig.json",
-    "compilerOptions": {
-        "types": ["@league-of-foundry-developers/foundry-vtt-types"]
-    },
     "include": ["../src", "./"]
 }
diff --git a/src/apps/active-effect-config.ts b/src/apps/active-effect-config.js
similarity index 58%
rename from src/apps/active-effect-config.ts
rename to src/apps/active-effect-config.js
index f26494e8..10ede23b 100644
--- a/src/apps/active-effect-config.ts
+++ b/src/apps/active-effect-config.js
@@ -3,21 +3,28 @@
 // SPDX-License-Identifier: MIT
 
 export class DS4ActiveEffectConfig extends ActiveEffectConfig {
-    static override get defaultOptions(): DocumentSheetOptions {
+    /** @override */
+    static get defaultOptions() {
         return foundry.utils.mergeObject(super.defaultOptions, {
             template: "systems/ds4/templates/sheets/active-effect/active-effect-config.hbs",
         });
     }
 
-    override activateListeners(html: JQuery<HTMLElement>): void {
+    /**
+     * @override
+     * @param {JQuery} html
+     */
+    activateListeners(html) {
         super.activateListeners(html);
-        const checkbox = html[0]?.querySelector<HTMLInputElement>(
-            'input[name="flags.ds4.itemEffectConfig.applyToItems"]',
-        );
-        checkbox?.addEventListener("change", () => this.toggleItemEffectConfig(checkbox.checked));
+        const checkbox = html[0]?.querySelector('input[name="flags.ds4.itemEffectConfig.applyToItems"]');
+        checkbox?.addEventListener("change", () => this.#toggleItemEffectConfig(checkbox.checked));
     }
 
-    private toggleItemEffectConfig(active: boolean) {
+    /**
+     * Toggle the visibility of the item effect config section
+     * @param {boolean} active The target state
+     */
+    #toggleItemEffectConfig(active) {
         const elements = this.element[0]?.querySelectorAll(".ds4-item-effect-config");
         elements?.forEach((element) => {
             if (active) {
diff --git a/src/apps/actor/base-sheet.ts b/src/apps/actor/base-sheet.js
similarity index 74%
rename from src/apps/actor/base-sheet.ts
rename to src/apps/actor/base-sheet.js
index bb2e5fa4..e29a3e79 100644
--- a/src/apps/actor/base-sheet.ts
+++ b/src/apps/actor/base-sheet.js
@@ -13,15 +13,12 @@ import { notifications } from "../../ui/notifications";
 import { enforce, getCanvas, getGame } from "../../utils/utils";
 import { disableOverriddenFields } from "../sheet-helpers";
 
-import type { ModifiableDataBaseTotal } from "../../documents/common/common-data";
-import type { DS4Settings } from "../../settings";
-import type { DS4Item } from "../../documents/item/item";
-
 /**
  * The base sheet class for all {@link DS4Actor}s.
  */
-export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetData> {
-    static override get defaultOptions(): ActorSheet.Options {
+export class DS4ActorSheet extends ActorSheet {
+    /** @override */
+    static get defaultOptions() {
         return foundry.utils.mergeObject(super.defaultOptions, {
             classes: ["sheet", "ds4-actor-sheet"],
             height: 635,
@@ -36,13 +33,15 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
         });
     }
 
-    override get template(): string {
+    /** @override */
+    get template() {
         const basePath = "systems/ds4/templates/sheets/actor";
         if (!getGame().user?.isGM && this.actor.limited) return `${basePath}/limited-sheet.hbs`;
         return `${basePath}/${this.actor.data.type}-sheet.hbs`;
     }
 
-    override async getData(): Promise<DS4ActorSheetData> {
+    /** @override */
+    async getData(options) {
         const itemsByType = Object.fromEntries(
             Object.entries(this.actor.itemTypes).map(([itemType, items]) => {
                 return [itemType, items.map((item) => item.data).sort((a, b) => (a.sort || 0) - (b.sort || 0))];
@@ -60,7 +59,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
         const enrichedEffects = await Promise.all(enrichedEffectPromises);
 
         const data = {
-            ...this.addTooltipsToData(await super.getData()),
+            ...this.addTooltipsToData(await super.getData(options)),
             config: DS4,
             itemsByType,
             enrichedEffects,
@@ -71,12 +70,14 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
 
     /**
      * Adds tooltips to the attributes, traits, and combatValues of the actor data of the given {@link ActorSheet.Data}.
+     * @param {object} data
+     * @protected
      */
-    protected addTooltipsToData(data: ActorSheet.Data): ActorSheet.Data {
+    addTooltipsToData(data) {
         const valueGroups = [data.data.data.attributes, data.data.data.traits, data.data.data.combatValues];
 
         valueGroups.forEach((valueGroup) => {
-            Object.values(valueGroup).forEach((attribute: ModifiableDataBaseTotal<number> & { tooltip?: string }) => {
+            Object.values(valueGroup).forEach((attribute) => {
                 attribute.tooltip = this.getTooltipForValue(attribute);
             });
         });
@@ -85,8 +86,11 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
 
     /**
      * Generates a tooltip for a given attribute, trait, or combatValue.
+     * @param {import("../../documents/common/common-data").ModifiableDataBaseTotal<number>} value The value to get a tooltip for
+     * @returns {string} The tooltip
+     * @protected
      */
-    protected getTooltipForValue(value: ModifiableDataBaseTotal<number>): string {
+    getTooltipForValue(value) {
         return `${value.base} (${getGame().i18n.localize("DS4.TooltipBaseValue")}) + ${
             value.mod
         } (${getGame().i18n.localize("DS4.TooltipModifier")}) ➞ ${getGame().i18n.localize("DS4.TooltipEffects")} ➞ ${
@@ -94,7 +98,11 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
         }`;
     }
 
-    override activateListeners(html: JQuery): void {
+    /**
+     * @param {JQuery} html
+     * @override
+     */
+    activateListeners(html) {
         super.activateListeners(html);
 
         if (!this.options.editable) return;
@@ -123,9 +131,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Handles a click on an element of this sheet to control an embedded item of the actor corresponding to this sheet.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onControlItem(event: JQuery.ClickEvent): void {
+    onControlItem(event) {
         event.preventDefault();
         const a = event.currentTarget;
         switch (a.dataset["action"]) {
@@ -141,9 +150,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Creates a new embedded item using the initial data defined in the HTML dataset of the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onCreateItem(event: JQuery.ClickEvent): void {
+    onCreateItem(event) {
         const { type, ...data } = foundry.utils.deepClone(event.currentTarget.dataset);
         const name = getGame().i18n.localize(`DS4.New${type.capitalize()}Name`);
         const itemData = {
@@ -157,9 +167,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Opens the sheet of the embedded item corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onEditItem(event: JQuery.ClickEvent): void {
+    onEditItem(event) {
         const id = $(event.currentTarget)
             .parents(embeddedDocumentListEntryProperties.Item.selector)
             .data(embeddedDocumentListEntryProperties.Item.idDataAttribute);
@@ -172,9 +183,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Deletes the embedded item corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onDeleteItem(event: JQuery.ClickEvent): void {
+    onDeleteItem(event) {
         const li = $(event.currentTarget).parents(embeddedDocumentListEntryProperties.Item.selector);
         this.actor.deleteEmbeddedDocuments("Item", [li.data(embeddedDocumentListEntryProperties.Item.idDataAttribute)]);
         li.slideUp(200, () => this.render(false));
@@ -184,9 +196,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
      * Applies a change to a property of an embedded item depending on the `data-property` attribute of the
      * {@link HTMLInputElement} that has been changed and its new value.
      *
-     * @param event - The originating change event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onChangeItem(event: JQuery.ChangeEvent): void {
+    onChangeItem(event) {
         return this.onChangeEmbeddedDocument(event, "Item");
     }
 
@@ -194,9 +207,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
      * Handles a click on an element of this sheet to control an embedded effect of the actor corresponding to this
      * sheet.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onControlEffect(event: JQuery.ClickEvent): void {
+    onControlEffect(event) {
         event.preventDefault();
         const a = event.currentTarget;
         switch (a.dataset["action"]) {
@@ -212,18 +226,20 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Creates a new embedded effect.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onCreateEffect(): void {
+    onCreateEffect() {
         DS4ActiveEffect.createDefault(this.actor);
     }
 
     /**
      * Opens the sheet of the embedded effect corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onEditEffect(event: JQuery.ClickEvent): void {
+    onEditEffect(event) {
         const id = $(event.currentTarget)
             .parents(embeddedDocumentListEntryProperties.ActiveEffect.selector)
             .data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
@@ -235,9 +251,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     /**
      * Deletes the embedded item corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onDeleteEffect(event: JQuery.ClickEvent): void {
+    onDeleteEffect(event) {
         const li = $(event.currentTarget).parents(embeddedDocumentListEntryProperties.ActiveEffect.selector);
         const id = li.data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
         this.actor.deleteEmbeddedDocuments("ActiveEffect", [id]);
@@ -248,9 +265,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
      * Applies a change to a property of an embedded effect depending on the `data-property` attribute of the
      * {@link HTMLInputElement} that has been changed and its new value.
      *
-     * @param event - The originating change event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onChangeEffect(event: JQuery.ChangeEvent): void {
+    onChangeEffect(event) {
         return this.onChangeEmbeddedDocument(event, "ActiveEffect");
     }
 
@@ -258,10 +276,11 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
      * Applies a change to a property of an embedded document of the actor belonging to this sheet. The change depends
      * on the `data-property` attribute of the {@link HTMLInputElement} that has been changed and its new value.
      *
-     * @param event - The originating change event
-     * @param documentName - The name of the embedded document to be changed.
+     * @param {JQuery.ChangeEvent} event                 The originating click event
+     * @param {"Item" | "ActiveEffect"} documentName    The name of the embedded document to be changed.
+     * @protected
      */
-    protected onChangeEmbeddedDocument(event: JQuery.ChangeEvent, documentName: "Item" | "ActiveEffect"): void {
+    onChangeEmbeddedDocument(event, documentName) {
         event.preventDefault();
         const element = $(event.currentTarget).get(0);
         enforce(element instanceof HTMLInputElement);
@@ -284,17 +303,19 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
      * - text input: `string`
      * - number: `number`
      *
-     * @param element - The input element to parse the value from
+     * @param  {HTMLInputElement} element   The input element to parse the value from
+     * @returns {boolean | string | number} The parsed data
+     * @protected
      */
-    protected parseValue(element: HTMLInputElement): boolean | string | number {
+    parseValue(element) {
         switch (element.type) {
             case "checkbox": {
                 const inverted = Boolean(element.dataset["inverted"]);
-                const value: boolean = element.checked;
+                const value = element.checked;
                 return inverted ? !value : value;
             }
             case "text": {
-                const value: string = element.value;
+                const value = element.value;
                 return value;
             }
             case "number": {
@@ -311,9 +332,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
 
     /**
      * Handle clickable item rolls.
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onRollItem(event: JQuery.ClickEvent): void {
+    onRollItem(event) {
         event.preventDefault();
         const id = $(event.currentTarget)
             .parents(embeddedDocumentListEntryProperties.Item.selector)
@@ -325,17 +347,22 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
 
     /**
      * Handle clickable check rolls.
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onRollCheck(event: JQuery.ClickEvent): void {
+    onRollCheck(event) {
         event.preventDefault();
         event.currentTarget.blur();
         const check = event.currentTarget.dataset["check"];
         this.actor.rollCheck(check).catch((e) => notifications.error(e, { log: true }));
     }
 
-    override _onDragStart(event: DragEvent): void {
-        const target = event.currentTarget as HTMLElement;
+    /**
+     * @param {DragEvent} event
+     * @override
+     */
+    _onDragStart(event) {
+        const target = event.currentTarget;
         if (!(target instanceof HTMLElement)) return super._onDragStart(event);
 
         const check = target.dataset.check;
@@ -356,9 +383,10 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
 
     /**
      * Sort items according to the item list header that has been clicked.
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onSortItems(event: JQuery.ClickEvent<unknown, unknown, HTMLElement>): void {
+    onSortItems(event) {
         event.preventDefault();
         const target = event.currentTarget;
         const type = target.parentElement?.dataset["type"];
@@ -369,26 +397,28 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
         const items = this.actor.items.filter((item) => item.type === type);
         items.sort((a, b) => a.data.sort - b.data.sort);
 
-        const sortFunction =
-            (invert: boolean) =>
-            (a: DS4Item, b: DS4Item): number => {
+        /**
+         * @param {boolean} invert  Whether or not to inverse the sort order
+         * @returns {(a: import("../../documents/item/item").DS4Item, b: import("../../documents/item/item").DS4Item) => number} A function for sorting items
+         */
+        const sortFunction = (invert) => (a, b) => {
+            const propertyA = getProperty(a.data, dataPath);
+            const propertyB = getProperty(b.data, dataPath);
+            const comparison =
+                typeof propertyA === "string" || typeof propertyB === "string"
+                    ? compareAsStrings(propertyA, propertyB, invert)
+                    : compareAsNumbers(propertyA, propertyB, invert);
+
+            if (comparison === 0 && dataPath2 !== undefined) {
                 const propertyA = getProperty(a.data, dataPath);
                 const propertyB = getProperty(b.data, dataPath);
-                const comparison =
-                    typeof propertyA === "string" || typeof propertyB === "string"
-                        ? compareAsStrings(propertyA, propertyB, invert)
-                        : compareAsNumbers(propertyA, propertyB, invert);
+                return typeof propertyA === "string" || typeof propertyB === "string"
+                    ? compareAsStrings(propertyA, propertyB, invert)
+                    : compareAsNumbers(propertyA, propertyB, invert);
+            }
 
-                if (comparison === 0 && dataPath2 !== undefined) {
-                    const propertyA = getProperty(a.data, dataPath);
-                    const propertyB = getProperty(b.data, dataPath);
-                    return typeof propertyA === "string" || typeof propertyB === "string"
-                        ? compareAsStrings(propertyA, propertyB, invert)
-                        : compareAsNumbers(propertyA, propertyB, invert);
-                }
-
-                return comparison;
-            };
+            return comparison;
+        };
 
         const sortedItems = [...items].sort(sortFunction(false));
         const wasSortedAlready = !sortedItems.find((item, index) => item !== items[index]);
@@ -405,7 +435,12 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
         this.actor.updateEmbeddedDocuments("Item", updates);
     }
 
-    protected override async _onDropItem(event: DragEvent, data: ActorSheet.DropData.Item): Promise<unknown> {
+    /**
+     * @param {DragEvent} event
+     * @param {object} data
+     * @override
+     */
+    async _onDropItem(event, data) {
         const item = await Item.fromDropData(data);
         if (item && !this.actor.canOwnItemType(item.data.type)) {
             notifications.warn(
@@ -422,19 +457,6 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
     }
 }
 
-interface DS4ActorSheetData extends ActorSheet.Data {
-    config: typeof DS4;
-    itemsByType: Record<string, foundry.data.ItemData[]>;
-    enrichedEffects: EnrichedActiveEffectDataSource[];
-    settings: DS4Settings;
-}
-
-type ActiveEffectDataSource = foundry.data.ActiveEffectData["_source"];
-
-interface EnrichedActiveEffectDataSource extends ActiveEffectDataSource {
-    sourceName: string;
-}
-
 /**
  * This object contains information about specific properties embedded document list entries for each different type.
  */
@@ -449,10 +471,24 @@ const embeddedDocumentListEntryProperties = Object.freeze({
     },
 });
 
-const compareAsStrings = (a: { toString(): string }, b: { toString(): string }, invert: boolean): number => {
+/**
+ * Compare two stringifiables as strings.
+ * @param {{ toString(): string }} a    The thing to compare with
+ * @param {{ toString(): string }} b    The thing to compare
+ * @param {boolean} invert              Should the comparison be inverted?
+ * @return {number} A number that indicates the result of the comparison
+ */
+const compareAsStrings = (a, b, invert) => {
     return invert ? b.toString().localeCompare(a.toString()) : a.toString().localeCompare(b.toString());
 };
 
-const compareAsNumbers = (a: number, b: number, invert: boolean): number => {
+/**
+ * Compare two number.
+ * @param {number} a        The number to compare with
+ * @param {number} b        The number to compare
+ * @param {boolean} invert  Should the comparison be inverted?
+ * @return {number} A number that indicates the result of the comparison
+ */
+const compareAsNumbers = (a, b, invert) => {
     return invert ? b - a : a - b;
 };
diff --git a/src/apps/actor/character-sheet.ts b/src/apps/actor/character-sheet.js
similarity index 86%
rename from src/apps/actor/character-sheet.ts
rename to src/apps/actor/character-sheet.js
index f6ec0649..16bff856 100644
--- a/src/apps/actor/character-sheet.ts
+++ b/src/apps/actor/character-sheet.js
@@ -8,7 +8,7 @@ import { DS4ActorSheet } from "./base-sheet";
  * The Sheet class for DS4 Character Actors
  */
 export class DS4CharacterActorSheet extends DS4ActorSheet {
-    static override get defaultOptions(): ActorSheet.Options {
+    static get defaultOptions() {
         return foundry.utils.mergeObject(super.defaultOptions, {
             classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"],
         });
diff --git a/src/apps/actor/creature-sheet.ts b/src/apps/actor/creature-sheet.js
similarity index 86%
rename from src/apps/actor/creature-sheet.ts
rename to src/apps/actor/creature-sheet.js
index 53b75523..2cd109f2 100644
--- a/src/apps/actor/creature-sheet.ts
+++ b/src/apps/actor/creature-sheet.js
@@ -8,7 +8,7 @@ import { DS4ActorSheet } from "./base-sheet";
  * The Sheet class for DS4 Creature Actors
  */
 export class DS4CreatureActorSheet extends DS4ActorSheet {
-    static override get defaultOptions(): ActorSheet.Options {
+    static get defaultOptions() {
         return foundry.utils.mergeObject(super.defaultOptions, {
             classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"],
         });
diff --git a/src/apps/dialog-with-listeners.ts b/src/apps/dialog-with-listeners.js
similarity index 53%
rename from src/apps/dialog-with-listeners.ts
rename to src/apps/dialog-with-listeners.js
index b2b053bc..f2412575 100644
--- a/src/apps/dialog-with-listeners.ts
+++ b/src/apps/dialog-with-listeners.js
@@ -2,18 +2,20 @@
 //
 // SPDX-License-Identifier: MIT
 
+/**
+ * @typedef {DialogOptions} DialogWithListenersOptions
+ * @property {(html: JQuery, app: DialogWithListeners) => void} [activateAdditionalListeners]   An optional function to attach additional listeners to the dialog
+ */
+
 /**
  * A simple extension to the {@link Dialog} class that allows attaching additional listeners.
  */
-export class DialogWithListeners extends Dialog<DialogWithListenersOptions> {
-    override activateListeners(html: JQuery): void {
+export class DialogWithListeners extends Dialog {
+    /** @override */
+    activateListeners(html) {
         super.activateListeners(html);
         if (this.options.activateAdditionalListeners !== undefined) {
             this.options.activateAdditionalListeners(html, this);
         }
     }
 }
-
-interface DialogWithListenersOptions extends DialogOptions {
-    activateAdditionalListeners?: ((html: JQuery, app: DialogWithListeners) => void) | undefined;
-}
diff --git a/src/apps/item-sheet.ts b/src/apps/item-sheet.js
similarity index 79%
rename from src/apps/item-sheet.ts
rename to src/apps/item-sheet.js
index 3062419b..7d151168 100644
--- a/src/apps/item-sheet.ts
+++ b/src/apps/item-sheet.js
@@ -14,8 +14,9 @@ import { disableOverriddenFields } from "./sheet-helpers";
 /**
  * The Sheet class for DS4 Items
  */
-export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData> {
-    static override get defaultOptions(): ItemSheet.Options {
+export class DS4ItemSheet extends ItemSheet {
+    /** @override */
+    static get defaultOptions() {
         return foundry.utils.mergeObject(super.defaultOptions, {
             classes: ["sheet", "ds4-item-sheet"],
             height: 400,
@@ -25,12 +26,14 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
         });
     }
 
-    override get template(): string {
+    /** @override */
+    get template() {
         const basePath = "systems/ds4/templates/sheets/item";
         return `${basePath}/${this.item.data.type}-sheet.hbs`;
     }
 
-    override async getData(): Promise<DS4ItemSheetData> {
+    /** @override */
+    async getData() {
         const data = {
             ...(await super.getData()),
             config: DS4,
@@ -41,7 +44,8 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
         return data;
     }
 
-    override _getSubmitData(updateData = {}) {
+    /** @override */
+    _getSubmitData(updateData = {}) {
         const data = super._getSubmitData(updateData);
         // Prevent submitting overridden values
         const overrides = foundry.utils.flattenObject(this.item.overrides);
@@ -51,9 +55,8 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
         return data;
     }
 
-    override setPosition(
-        options: Partial<Application.Position> = {},
-    ): (Application.Position & { height: number }) | void {
+    /** @override */
+    setPosition(options = {}) {
         const position = super.setPosition(options);
         if (position) {
             const sheetBody = this.element.find(".sheet-body");
@@ -64,7 +67,11 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
         return position;
     }
 
-    override activateListeners(html: JQuery): void {
+    /**
+     * @override
+     * @param {JQuery} html
+     */
+    activateListeners(html) {
         super.activateListeners(html);
 
         if (!this.options.editable) return;
@@ -78,9 +85,10 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
      * Handles a click on an element of this sheet to control an embedded effect of the item corresponding to this
      * sheet.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onControlEffect(event: JQuery.ClickEvent): void {
+    onControlEffect(event) {
         event.preventDefault();
         if (this.item.isOwned) {
             return notifications.warn(getGame().i18n.localize("DS4.WarningManageActiveEffectOnOwnedItem"));
@@ -98,17 +106,19 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
 
     /**
      * Creates a new embedded effect.
+     * @protected
      */
-    protected onCreateEffect(): void {
+    onCreateEffect() {
         DS4ActiveEffect.createDefault(this.item);
     }
 
     /**
      * Opens the sheet of the embedded effect corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @porotected
      */
-    protected onEditEffect(event: JQuery.ClickEvent): void {
+    onEditEffect(event) {
         const id = $(event.currentTarget)
             .parents(embeddedDocumentListEntryProperties.ActiveEffect.selector)
             .data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
@@ -120,9 +130,10 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
     /**
      * Deletes the embedded item corresponding to the clicked element.
      *
-     * @param event - The originating click event
+     * @param {JQuery.ClickEvent} event The originating click event
+     * @protected
      */
-    protected onDeleteEffect(event: JQuery.ClickEvent): void {
+    onDeleteEffect(event) {
         const li = $(event.currentTarget).parents(embeddedDocumentListEntryProperties.ActiveEffect.selector);
         const id = li.data(embeddedDocumentListEntryProperties.ActiveEffect.idDataAttribute);
         this.item.deleteEmbeddedDocuments("ActiveEffect", [id]);
@@ -130,13 +141,6 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
     }
 }
 
-interface DS4ItemSheetData extends ItemSheet.Data<ItemSheet.Options> {
-    config: typeof DS4;
-    isOwned: boolean;
-    actor: DS4ItemSheet["item"]["actor"];
-    isPhysical: boolean;
-}
-
 /**
  * This object contains information about specific properties embedded document list entries for each different type.
  */
diff --git a/src/apps/sheet-helpers.ts b/src/apps/sheet-helpers.js
similarity index 65%
rename from src/apps/sheet-helpers.ts
rename to src/apps/sheet-helpers.js
index dad3c75a..a098e250 100644
--- a/src/apps/sheet-helpers.ts
+++ b/src/apps/sheet-helpers.js
@@ -4,11 +4,13 @@
 
 import { getGame } from "../utils/utils";
 
-export function disableOverriddenFields(
-    form: HTMLElement | null,
-    overrides: Record<string, unknown>,
-    selector: (key: string) => string,
-): void {
+/**
+ * Disable elements in the given form that match the selector returned for overridden properties.
+ * @param {HTMLElement | null} form The form in which to disable fields
+ * @param {Record<string, unknown>} overrides The set of overrides of the underlying document
+ * @param {(key: string) => string} selector A function that generates a selector, based on a property key
+ */
+export function disableOverriddenFields(form, overrides, selector) {
     const inputs = ["INPUT", "SELECT", "TEXTAREA", "BUTTON"];
     const titleAddition = `(${getGame().i18n.localize("DS4.TooltipNotEditableDueToEffects")})`;
 
diff --git a/src/dice/check-evaluation.ts b/src/dice/check-evaluation.ts
index 753c7d8f..608c503e 100644
--- a/src/dice/check-evaluation.ts
+++ b/src/dice/check-evaluation.ts
@@ -99,7 +99,13 @@ function shouldUseCoupForLastSubCheck(
     );
 }
 
-interface SubCheckResult extends DieWithSubCheck, DiceTerm.Result {}
+interface SubCheckResult extends DieWithSubCheck {
+    active?: boolean;
+    discarded?: boolean;
+    success?: boolean;
+    failure?: boolean;
+    count?: number;
+}
 
 function evaluateDiceWithSubChecks(
     results: DieWithSubCheck[],
diff --git a/src/dice/check-factory.ts b/src/dice/check-factory.js
similarity index 59%
rename from src/dice/check-factory.ts
rename to src/dice/check-factory.js
index 0952bc93..30836836 100644
--- a/src/dice/check-factory.ts
+++ b/src/dice/check-factory.js
@@ -7,70 +7,96 @@ import { DialogWithListeners } from "../apps/dialog-with-listeners";
 import { DS4 } from "../config";
 import { getGame } from "../utils/utils";
 
-/**
- * Provides default values for all arguments the `CheckFactory` expects.
- */
-class DefaultCheckOptions implements DS4CheckFactoryOptions {
-    readonly maximumCoupResult = 1;
-    readonly minimumFumbleResult = 20;
-    readonly useSlayingDice = false;
-    readonly rollMode: keyof CONFIG.Dice.RollModes = "publicroll";
-    readonly flavor: undefined;
-
-    mergeWith(other: Partial<DS4CheckFactoryOptions>): DS4CheckFactoryOptions {
-        return { ...this, ...other };
-    }
-}
-
-/**
- * Singleton reference for default value extraction.
- */
-const defaultCheckOptions = new DefaultCheckOptions();
+/** @typedef {"publicroll" | "gmroll" | "gmroll" | "selfroll"} RollModes */
 
 /**
  * Most basic class responsible for generating the chat formula and passing it to the chat as roll.
  */
 class CheckFactory {
-    constructor(
-        private checkTargetNumber: number,
-        private checkModifier: number,
-        options: Partial<DS4CheckFactoryOptions> = {},
-    ) {
-        this.options = defaultCheckOptions.mergeWith(options);
+    /**
+     * @param {number} checkTargetNumber                    The check target number for this check factory
+     * @param {number} checkModifier                        The check modifier for this check factory
+     * @param {Partial<DS4CheckFactoryOptions>} [options]   Options for this check factory
+     */
+    constructor(checkTargetNumber, checkModifier, options = {}) {
+        this.#checkTargetNumber = checkTargetNumber;
+        this.#checkModifier = checkModifier;
+        this.#options = foundry.utils.mergeObject(this.constructor.defaultOptions, options);
     }
 
-    private options: DS4CheckFactoryOptions;
+    /**
+     * The check target number for this check factory.
+     * @type {number}
+     */
+    #checkTargetNumber;
 
-    async execute(): Promise<ChatMessage | undefined> {
+    /**
+     * The check modifier for this check factory.
+     * @type {number}
+     */
+    #checkModifier;
+
+    /**
+     * The options for this check factory.
+     * @type {DS4CheckFactoryOptions}
+     */
+    #options;
+
+    /**
+     * The default options of thos CheckFactory class. Upon instantiation, they are merged with the explicitly provided options.
+     * @type {DS4CheckFactoryOptions}
+     */
+    static get defaultOptions() {
+        return {
+            maximumCoupResult: 1,
+            minimumFumbleResult: 20,
+            useSlayingDice: false,
+            rollMode: "publicroll",
+        };
+    }
+
+    /**
+     * Execute this check factory.
+     * @returns {Promise<ChatMessage | undefined>} A promise that resolves to the created chat message for the roll */
+    async execute() {
         const innerFormula = ["ds", this.createCheckTargetNumberModifier(), this.createCoupFumbleModifier()].filterJoin(
             "",
         );
-        const formula = this.options.useSlayingDice ? `{${innerFormula}}x` : innerFormula;
+        const formula = this.#options.useSlayingDice ? `{${innerFormula}}x` : innerFormula;
         const roll = Roll.create(formula);
-        const speaker = this.options.speaker ?? ChatMessage.getSpeaker();
+        const speaker = this.#options.speaker ?? ChatMessage.getSpeaker();
 
         return roll.toMessage(
             {
                 speaker,
-                flavor: this.options.flavor,
-                flags: this.options.flavorData ? { ds4: { flavorData: this.options.flavorData } } : undefined,
+                flavor: this.#options.flavor,
+                flags: this.#options.flavorData ? { ds4: { flavorData: this.#options.flavorData } } : undefined,
             },
-            { rollMode: this.options.rollMode, create: true },
+            { rollMode: this.#options.rollMode, create: true },
         );
     }
 
-    createCheckTargetNumberModifier(): string {
-        const totalCheckTargetNumber = this.checkTargetNumber + this.checkModifier;
-        return totalCheckTargetNumber >= 0 ? `v${this.checkTargetNumber + this.checkModifier}` : "v0";
+    /**
+     * Create the check target number modifier for this roll.
+     * @returns string
+     */
+    createCheckTargetNumberModifier() {
+        const totalCheckTargetNumber = this.#checkTargetNumber + this.#checkModifier;
+        return totalCheckTargetNumber >= 0 ? `v${this.#checkTargetNumber + this.#checkModifier}` : "v0";
     }
 
-    createCoupFumbleModifier(): string | null {
+    /**
+     * Create the coup fumble modifier for this roll.
+     * @returns {string | null}
+     */
+    createCoupFumbleModifier() {
         const isMinimumFumbleResultRequired =
-            this.options.minimumFumbleResult !== defaultCheckOptions.minimumFumbleResult;
-        const isMaximumCoupResultRequired = this.options.maximumCoupResult !== defaultCheckOptions.maximumCoupResult;
+            this.#options.minimumFumbleResult !== this.constructor.defaultOptions.minimumFumbleResult;
+        const isMaximumCoupResultRequired =
+            this.#options.maximumCoupResult !== this.constructor.defaultOptions.maximumCoupResult;
 
         if (isMinimumFumbleResultRequired || isMaximumCoupResultRequired) {
-            return `c${this.options.maximumCoupResult ?? ""}:${this.options.minimumFumbleResult ?? ""}`;
+            return `c${this.#options.maximumCoupResult ?? ""}:${this.#options.minimumFumbleResult ?? ""}`;
         } else {
             return null;
         }
@@ -79,19 +105,18 @@ class CheckFactory {
 
 /**
  * Asks the user for all unknown/necessary information and passes them on to perform a roll.
- * @param checkTargetNumber - The Check Target Number ("CTN")
- * @param options           - Options changing the behavior of the roll and message.
+ * @param {number} checkTargetNumber                        The Check Target Number ("CTN")
+ * @param {Partial<DS4CheckFactoryOptions>} [options={}]    Options changing the behavior of the roll and message.
+ * @returns {Promise<ChateMessage|undefined>} A promise that resolves to the chat message created by the roll
  */
-export async function createCheckRoll(
-    checkTargetNumber: number,
-    options: Partial<DS4CheckFactoryOptions> = {},
-): Promise<ChatMessage | unknown> {
+export async function createCheckRoll(checkTargetNumber, options = {}) {
     // Ask for additional required data;
     const interactiveRollData = await askForInteractiveRollData(checkTargetNumber, options);
 
     const newTargetValue = interactiveRollData.checkTargetNumber ?? checkTargetNumber;
     const checkModifier = interactiveRollData.checkModifier ?? 0;
-    const newOptions: Partial<DS4CheckFactoryOptions> = {
+    /** @type {Partial<DS4CheckFactoryOptions>} */
+    const newOptions = {
         maximumCoupResult: interactiveRollData.maximumCoupResult ?? options.maximumCoupResult,
         minimumFumbleResult: interactiveRollData.minimumFumbleResult ?? options.minimumFumbleResult,
         useSlayingDice: getGame().settings.get("ds4", "useSlayingDiceForAutomatedChecks"),
@@ -117,26 +142,25 @@ export async function createCheckRoll(
  * @notes
  * At the moment, this asks for more data than it will do after some iterations.
  *
- * @returns The data given by the user.
+ * @param {number} checkTargetNumber                                                            The check target number
+ * @param {Partial<DS4CheckFactoryOptions>} [options={}]                                        Predefined roll options
+ * @param {template?: string | undefined; title?: string | undefined} [additionalOptions={}]    Additional options to use for the dialog
+ * @returns {Promise<Partial<IntermediateInteractiveRollData>>} A promise that resolves to the data given by the user.
  */
-async function askForInteractiveRollData(
-    checkTargetNumber: number,
-    options: Partial<DS4CheckFactoryOptions> = {},
-    { template, title }: { template?: string; title?: string } = {},
-): Promise<Partial<IntermediateInteractiveRollData>> {
+async function askForInteractiveRollData(checkTargetNumber, options = {}, { template, title } = {}) {
     const usedTemplate = template ?? "systems/ds4/templates/dialogs/roll-options.hbs";
     const usedTitle = title ?? getGame().i18n.localize("DS4.DialogRollOptionsDefaultTitle");
     const id = foundry.utils.randomID();
     const templateData = {
         title: usedTitle,
         checkTargetNumber: checkTargetNumber,
-        maximumCoupResult: options.maximumCoupResult ?? defaultCheckOptions.maximumCoupResult,
-        minimumFumbleResult: options.minimumFumbleResult ?? defaultCheckOptions.minimumFumbleResult,
+        maximumCoupResult: options.maximumCoupResult ?? this.constructor.defaultOptions.maximumCoupResult,
+        minimumFumbleResult: options.minimumFumbleResult ?? this.constructor.defaultOptions.minimumFumbleResult,
         rollMode: options.rollMode ?? getGame().settings.get("core", "rollMode"),
         rollModes: CONFIG.Dice.rollModes,
         checkModifiers: Object.entries(DS4.i18n.checkModifiers).map(([key, translation]) => {
             if (key in DS4.checkModifiers) {
-                const value = DS4.checkModifiers[key as keyof typeof DS4.checkModifiers];
+                const value = DS4.checkModifiers[key];
                 const label = `${translation} (${value >= 0 ? `+${value}` : value})`;
                 return { value, label };
             }
@@ -146,7 +170,7 @@ async function askForInteractiveRollData(
     };
     const renderedHtml = await renderTemplate(usedTemplate, templateData);
 
-    const dialogPromise = new Promise<HTMLFormElement>((resolve) => {
+    const dialogPromise = new Promise((resolve) => {
         new DialogWithListeners(
             {
                 title: usedTitle,
@@ -190,7 +214,7 @@ async function askForInteractiveRollData(
                         .parent(".form-group");
                     html.find(`#check-modifier-${id}`).on("change", (event) => {
                         if (
-                            (event.currentTarget as HTMLSelectElement).value === "custom" &&
+                            event.currentTarget.value === "custom" &&
                             checkModifierCustomFormGroup.hasClass("ds4-hidden")
                         ) {
                             checkModifierCustomFormGroup.removeClass("ds4-hidden");
@@ -211,9 +235,10 @@ async function askForInteractiveRollData(
 
 /**
  * Extracts Dialog data from the returned DOM element.
- * @param formData - The filed dialog
+ * @param {HTMLFormElement} formData    The filed dialog
+ * @returns {Partial<IntermediateInteractiveRollData>}
  */
-function parseDialogFormData(formData: HTMLFormElement): Partial<IntermediateInteractiveRollData> {
+function parseDialogFormData(formData) {
     const chosenCheckTargetNumber = parseInt(formData["check-target-number"]?.value);
     const chosenCheckModifier = formData["check-modifier"]?.value;
 
@@ -237,11 +262,10 @@ function parseDialogFormData(formData: HTMLFormElement): Partial<IntermediateInt
 
 /**
  * Contains data that needs retrieval from an interactive Dialog.
+ * @typedef {object} InteractiveRollData
+ * @property {number} checkModifier
+ * @property {RollModes} rollMode
  */
-interface InteractiveRollData {
-    checkModifier: number;
-    rollMode: keyof CONFIG.Dice.RollModes;
-}
 
 /**
  * Contains *CURRENTLY* necessary Data for drafting a roll.
@@ -255,23 +279,29 @@ interface InteractiveRollData {
  * They will and should be removed once effects and data retrieval is in place.
  * If a "raw" roll dialog is necessary, create another pre-processing Dialog
  * class asking for the required information.
- * This interface should then be replaced with the `InteractiveRollData`.
+ * This interface should then be replaced with the {@link InteractiveRollData}.
+ * @typedef {object} IntermediateInteractiveRollData
+ * @property {number} checkTargetNumber
+ * @property {number} maximumCoupResult
+ * @property {number} minimumFumbleResult
  */
-interface IntermediateInteractiveRollData extends InteractiveRollData {
-    checkTargetNumber: number;
-    maximumCoupResult: number;
-    minimumFumbleResult: number;
-}
 
 /**
  * The minimum behavioral options that need to be passed to the factory.
+ * @typedef {object} DS4CheckFactoryOptions
+ * @property {number} maximumCoupResult
+ * @property {number} minimumFumbleResult
+ * @property {boolean} useSlayingDice
+ * @property {RollModes} rollMode
+ * @property {string} [flavor]
+ * @property {Record<string, string | number | null>} [flavorData]
+ * @property {ChatSpeakerData} [speaker]
+ */
+
+/**
+ * @typedef {object} ChatSpeakerData
+ * @property {string | null} [scene]
+ * @property {string | null} [actor]
+ * @property {string | null} [token]
+ * @property {string | null} [alias]
  */
-export interface DS4CheckFactoryOptions {
-    maximumCoupResult: number;
-    minimumFumbleResult: number;
-    useSlayingDice: boolean;
-    rollMode: keyof CONFIG.Dice.RollModes;
-    flavor?: string;
-    flavorData?: Record<string, string | number | null>;
-    speaker?: ReturnType<typeof ChatMessage.getSpeaker>;
-}
diff --git a/src/dice/check.ts b/src/dice/check.js
similarity index 78%
rename from src/dice/check.ts
rename to src/dice/check.js
index ce9e983a..ff389693 100644
--- a/src/dice/check.ts
+++ b/src/dice/check.js
@@ -16,7 +16,7 @@ import { evaluateCheck, getRequiredNumberOfDice } from "./check-evaluation";
  * - Roll a check with a racial ability that makes `5` a coup and default fumble: `/r dsv19c5`
  */
 export class DS4Check extends DiceTerm {
-    constructor({ modifiers = [], results = [], options }: Partial<DiceTerm.TermData> = {}) {
+    constructor({ modifiers = [], results = [], options } = {}) {
         super({
             faces: 20,
             results,
@@ -65,34 +65,44 @@ export class DS4Check extends DiceTerm {
         }
     }
 
-    coup: boolean | null = null;
-    fumble: boolean | null = null;
+    /** @type {boolean | null} */
+    coup = null;
+    /** @type {boolean | null} */
+    fumble = null;
     canFumble = true;
     checkTargetNumber = DS4Check.DEFAULT_CHECK_TARGET_NUMBER;
     minimumFumbleResult = DS4Check.DEFAULT_MINIMUM_FUMBLE_RESULT;
     maximumCoupResult = DS4Check.DEFAULT_MAXIMUM_COUP_RESULT;
 
-    override get expression(): string {
+    /** @override */
+    get expression() {
         return `ds${this.modifiers.join("")}`;
     }
 
-    override get total(): string | number | null | undefined {
+    /** @override */
+    get total() {
         if (this.fumble) return 0;
         return super.total;
     }
 
-    override _evaluateSync({ minimize = false, maximize = false } = {}): this {
+    /** @override */
+    _evaluateSync({ minimize = false, maximize = false } = {}) {
         super._evaluateSync({ minimize, maximize });
         this.evaluateResults();
         return this;
     }
 
-    override roll({ minimize = false, maximize = false } = {}): DiceTerm.Result {
+    /** @override */
+    roll({ minimize = false, maximize = false } = {}) {
         // Swap minimize / maximize because in DS4, the best possible roll is a 1 and the worst possible roll is a 20
         return super.roll({ minimize: maximize, maximize: minimize });
     }
 
-    evaluateResults(): void {
+    /**
+     * Perform additional evaluation after the individual results have been evaluated.
+     * @protected
+     */
+    evaluateResults() {
         const dice = this.results.map((die) => die.result);
         const results = evaluateCheck(dice, this.checkTargetNumber, {
             maximumCoupResult: this.maximumCoupResult,
@@ -108,18 +118,19 @@ export class DS4Check extends DiceTerm {
      * @remarks "min" and "max" are filtered out because they are irrelevant for
      * {@link DS4Check}s and only result in some dice rolls being highlighted
      * incorrectly.
+     * @override
      */
-    override getResultCSS(result: DiceTerm.Result): (string | null)[] {
+    getResultCSS(result) {
         return super.getResultCSS(result).filter((cssClass) => cssClass !== "min" && cssClass !== "max");
     }
 
-    static readonly DEFAULT_CHECK_TARGET_NUMBER = 10;
-    static readonly DEFAULT_MAXIMUM_COUP_RESULT = 1;
-    static readonly DEFAULT_MINIMUM_FUMBLE_RESULT = 20;
-    static override DENOMINATION = "s";
-    static override MODIFIERS = {
-        c: (): void => undefined, // Modifier is consumed in constructor for maximumCoupResult / minimumFumbleResult
-        v: (): void => undefined, // Modifier is consumed in constructor for checkTargetNumber
-        n: (): void => undefined, // Modifier is consumed in constructor for canFumble
+    static DEFAULT_CHECK_TARGET_NUMBER = 10;
+    static DEFAULT_MAXIMUM_COUP_RESULT = 1;
+    static DEFAULT_MINIMUM_FUMBLE_RESULT = 20;
+    static DENOMINATION = "s";
+    static MODIFIERS = {
+        c: () => undefined, // Modifier is consumed in constructor for maximumCoupResult / minimumFumbleResult
+        v: () => undefined, // Modifier is consumed in constructor for checkTargetNumber
+        n: () => undefined, // Modifier is consumed in constructor for canFumble
     };
 }
diff --git a/src/dice/roll.ts b/src/dice/roll.js
similarity index 74%
rename from src/dice/roll.ts
rename to src/dice/roll.js
index fa86f212..bbb557ed 100644
--- a/src/dice/roll.ts
+++ b/src/dice/roll.js
@@ -5,19 +5,17 @@
 import { getGame } from "../utils/utils";
 import { DS4Check } from "./check";
 
-export class DS4Roll<D extends Record<string, unknown> = Record<string, unknown>> extends Roll<D> {
-    static override CHAT_TEMPLATE = "systems/ds4/templates/dice/roll.hbs";
+export class DS4Roll extends Roll {
+    /** @override */
+    static CHAT_TEMPLATE = "systems/ds4/templates/dice/roll.hbs";
 
     /**
+     * @override
      * @remarks
      * This only differs from {@link Roll#render} in that it provides `isCoup` and `isFumble` properties to the roll
      * template if the first dice term is a ds4 check.
      */
-    override async render({
-        flavor,
-        template = (this.constructor as typeof DS4Roll).CHAT_TEMPLATE,
-        isPrivate = false,
-    }: Parameters<Roll["render"]>[0] = {}): Promise<string> {
+    async render({ flavor, template = this.constructor.CHAT_TEMPLATE, isPrivate = false } = {}) {
         if (!this._evaluated) await this.evaluate({ async: true });
         const firstDiceTerm = this.dice[0];
         const isCoup = firstDiceTerm instanceof DS4Check && firstDiceTerm.coup;
diff --git a/src/dice/slaying-dice-modifier.ts b/src/dice/slaying-dice-modifier.js
similarity index 89%
rename from src/dice/slaying-dice-modifier.ts
rename to src/dice/slaying-dice-modifier.js
index 7f091e07..5eb879bf 100644
--- a/src/dice/slaying-dice-modifier.ts
+++ b/src/dice/slaying-dice-modifier.js
@@ -6,11 +6,15 @@
 import { getGame } from "../utils/utils";
 import { DS4Check } from "./check";
 
-export function registerSlayingDiceModifier(): void {
+export function registerSlayingDiceModifier() {
     PoolTerm.MODIFIERS.x = slay;
 }
 
-function slay(this: PoolTerm, modifier: string): void {
+/**
+ * @this {PoolTerm}
+ * @param {string} modifier
+ */
+function slay(modifier) {
     const rgx = /[xX]/;
     const match = modifier.match(rgx);
     if (!match || !this.rolls) return;
diff --git a/src/documents/active-effect.ts b/src/documents/active-effect.js
similarity index 57%
rename from src/documents/active-effect.ts
rename to src/documents/active-effect.js
index cbc816b9..b29d6c49 100644
--- a/src/documents/active-effect.ts
+++ b/src/documents/active-effect.js
@@ -5,27 +5,22 @@
 import { mathEvaluator } from "../expression-evaluation/evaluator";
 import { getGame } from "../utils/utils";
 
-import type { DS4Actor } from "./actor/actor";
-import type { DS4Item } from "./item/item";
+/**
+ * @typedef {object} ItemEffectConfig
+ * @property {boolean} [applyToItems]   Whether or not to apply this effect to owned items instead of the actor
+ * @property {string} [itemName]        Only apply this effect to items with this name
+ * @property {string} [condition]       Only apply this effect to items where this condition is fullfilled
+ */
 
-declare global {
-    interface DocumentClassConfig {
-        ActiveEffect: typeof DS4ActiveEffect;
-    }
-    interface FlagConfig {
-        ActiveEffect: {
-            ds4?: {
-                itemEffectConfig?: {
-                    applyToItems?: boolean;
-                    itemName?: string;
-                    condition?: string;
-                };
-            };
-        };
-    }
-}
+/**
+ * @typedef {object} DS4ActiveEffectFlags
+ * @property {ItemEffectConfig} [itemEffectConfig]  Configuration for applying this effect to owned items
+ */
 
-type PromisedType<T> = T extends Promise<infer U> ? U : T;
+/**
+ * @typedef {Record<string, unknown>} ActiveEffectFlags
+ * @property {DS4ActiveEffectFlags} [ds4]   Flags for DS4
+ */
 
 export class DS4ActiveEffect extends ActiveEffect {
     /**
@@ -35,13 +30,16 @@ export class DS4ActiveEffect extends ActiveEffect {
 
     /**
      * A cached reference to the source document to avoid recurring database lookups
+     * @type {foundry.abstract.Document | undefined | null}
+     * @protected
      */
-    protected source: PromisedType<ReturnType<typeof fromUuid>> | undefined = undefined;
+    source = undefined;
 
     /**
      * Whether or not this effect is currently surpressed.
+     * @type {boolean}
      */
-    get isSurpressed(): boolean {
+    get isSurpressed() {
         const originatingItem = this.originatingItem;
         if (!originatingItem) {
             return false;
@@ -51,8 +49,9 @@ export class DS4ActiveEffect extends ActiveEffect {
 
     /**
      * The item which this effect originates from if it has been transferred from an item to an actor.
+     * @return {import("./item/item").DS4Item | undefined}
      */
-    get originatingItem(): DS4Item | undefined {
+    get originatingItem() {
         if (!(this.parent instanceof Actor)) {
             return;
         }
@@ -66,27 +65,28 @@ export class DS4ActiveEffect extends ActiveEffect {
 
     /**
      * The number of times this effect should be applied.
+     * @type {number}
      */
-    get factor(): number {
+    get factor() {
         return this.originatingItem?.activeEffectFactor ?? 1;
     }
 
-    override apply(document: DS4Actor | DS4Item, change: EffectChangeData): unknown {
+    /** @override */
+    apply(document, change) {
         change.value = Roll.replaceFormulaData(change.value, document.data);
         try {
             change.value = DS4ActiveEffect.safeEval(change.value).toString();
         } catch (e) {
             // this is a valid case, e.g., if the effect change simply is a string
         }
-        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-        // @ts-expect-error In the types and foundry's documentation, only actors are allowed, but the implementation actually works for all kinds of documents
         return super.apply(document, change);
     }
 
     /**
      * Gets the current source name based on the cached source object.
+     * @returns {Promise<string>} The current source name
      */
-    async getCurrentSourceName(): Promise<string> {
+    async getCurrentSourceName() {
         const game = getGame();
         const origin = await this.getSource();
         if (origin === null) return game.i18n.localize("None");
@@ -96,8 +96,10 @@ export class DS4ActiveEffect extends ActiveEffect {
     /**
      * Gets the source document for this effect. Uses the cached {@link DS4ActiveEffect#source} if it has already been
      * set.
+     * @protected
+     * @returns {Promise<foundry.abstract.Document | null>}
      */
-    protected async getSource(): ReturnType<typeof fromUuid> {
+    async getSource() {
         if (this.source === undefined) {
             this.source = this.data.origin !== undefined ? await fromUuid(this.data.origin) : null;
         }
@@ -107,10 +109,10 @@ export class DS4ActiveEffect extends ActiveEffect {
     /**
      * Create a new {@link DS4ActiveEffect} using default data.
      *
-     * @param parent The parent {@link DS4Actor} or {@link DS4Item} of the effect.
-     * @returns A promise that resolved to the created effect or udifined of the creation was prevented.
+     * @param {import("./item/item").DS4Item | import("./actor/actor").DS4Actor} parent The parent of the effect.
+     * @returns {Promise<DS4ActiveEffect | undefined>}A promise that resolved to the created effect or udifined of the creation was prevented.
      */
-    static async createDefault(parent: DS4Actor | DS4Item): Promise<DS4ActiveEffect | undefined> {
+    static async createDefault(parent) {
         const createData = {
             label: getGame().i18n.localize(`DS4.NewEffectLabel`),
             icon: this.FALLBACK_ICON,
@@ -119,26 +121,29 @@ export class DS4ActiveEffect extends ActiveEffect {
         return this.create(createData, { parent, pack: parent.pack ?? undefined });
     }
 
-    static safeEval(expression: string): number | `${number | boolean}` {
+    /**
+     * Safely evaluate a mathematical expression.
+     * @param {string} expression   The expression to evaluate
+     * @returns {number | `${number | boolean}`} The numeric result of the expression
+     * @throws If the expression could not be evaluated or did not produce a numeric resilt
+     */
+    static safeEval(expression) {
         const result = mathEvaluator.evaluate(expression);
         if (!Number.isNumeric(result)) {
             throw new Error(`mathEvaluator.evaluate produced a non-numeric result from expression "${expression}"`);
         }
-        return result as number | `${number | boolean}`;
+        return result;
     }
 
     /**
      * Apply the given effects to the gicen Actor or item.
-     * @param document The Actor or Item to which to apply the effects
-     * @param effetcs The effects to apply
-     * @param predicate Apply only changes that fullfill this predicate
+     * @param {import("./item/item").DS4Item | import("./actor/actor").DS4Actor} document   The Actor or Item to which to apply the effects
+     * @param {DS4ActiveEffect[]} effetcs                                                   The effects to apply
+     * @param {(change: EffectChangeData) => boolean} [predicate=() => true]                Apply only changes that fullfill this predicate
      */
-    static applyEffetcs(
-        document: DS4Actor | DS4Item,
-        effetcs: DS4ActiveEffect[],
-        predicate: (change: EffectChangeData) => boolean = () => true,
-    ): void {
-        const overrides: Record<string, unknown> = {};
+    static applyEffetcs(document, effetcs, predicate = () => true) {
+        /** @type {Record<string, unknown>} */
+        const overrides = {};
 
         // Organize non-disabled and -surpressed effects by their application priority
         const changesWithEffect = effetcs.flatMap((e) => e.getFactoredChangesWithEffect(predicate));
@@ -159,22 +164,28 @@ export class DS4ActiveEffect extends ActiveEffect {
 
     /**
      * Get the array of changes for this effect, considering the {@link DS4ActiveEffect#factor}.
-     * @param predicate An optional predicate to filter which changes should be considered
-     * @returns The array of changes from this effect, considering the factor.
+     * @param {(change: EffectChangeData) => boolean} [predicate=() => true]    An optional predicate to filter which changes should be considered
+     * @returns {EffectChangeDataWithEffect[]} The array of changes from this effect, considering the factor.
+     * @protected
      */
-    protected getFactoredChangesWithEffect(
-        predicate: (change: EffectChangeData) => boolean = () => true,
-    ): EffectChangeDataWithEffect[] {
+    getFactoredChangesWithEffect(predicate = () => true) {
         if (this.data.disabled || this.isSurpressed) {
             return [];
         }
 
         return this.data.changes.filter(predicate).flatMap((change) => {
             change.priority = change.priority ?? change.mode * 10;
-            return Array<EffectChangeDataWithEffect>(this.factor).fill({ effect: this, change });
+            return Array(this.factor).fill({ effect: this, change });
         });
     }
 }
 
-type EffectChangeData = foundry.data.ActiveEffectData["changes"][number];
-type EffectChangeDataWithEffect = { effect: DS4ActiveEffect; change: EffectChangeData };
+/**
+ * @typedef {foundry.data.ActiveEffectData["changes"][number]} EffectChangeData
+ */
+
+/**
+ * @typedef {object} EffectChangeDataWithEffect
+ * @property {DS4ActiveEffect} effect
+ * @property {EffectChangeData} change
+ */
diff --git a/src/documents/actor/actor.ts b/src/documents/actor/actor.js
similarity index 77%
rename from src/documents/actor/actor.ts
rename to src/documents/actor/actor.js
index 16b6506a..c31145e6 100644
--- a/src/documents/actor/actor.ts
+++ b/src/documents/actor/actor.js
@@ -11,24 +11,12 @@ import { getGame } from "../../utils/utils";
 import { DS4ActiveEffect } from "../active-effect";
 import { isAttribute, isTrait } from "./actor-data-source-base";
 
-import type { ModifiableDataBaseTotal } from "../common/common-data";
-import type { DS4ArmorDataProperties } from "../item/armor/armor-data-properties";
-import type { DS4Item } from "../item/item";
-import type { ItemType } from "../item/item-data-source";
-import type { DS4ShieldDataProperties } from "../item/shield/shield-data-properties";
-import type { Check } from "./actor-data-properties-base";
-
-declare global {
-    interface DocumentClassConfig {
-        Actor: typeof DS4Actor;
-    }
-}
-
 /**
  * The Actor class for DS4
  */
 export class DS4Actor extends Actor {
-    override prepareData(): void {
+    /** @override */
+    prepareData() {
         this.data.reset();
         this.prepareBaseData();
         this.prepareEmbeddedDocuments();
@@ -39,7 +27,8 @@ export class DS4Actor extends Actor {
         this.prepareFinalDerivedData();
     }
 
-    override prepareBaseData(): void {
+    /** @override */
+    prepareBaseData() {
         const data = this.data;
 
         data.data.rolling = {
@@ -48,17 +37,14 @@ export class DS4Actor extends Actor {
         };
 
         const attributes = data.data.attributes;
-        Object.values(attributes).forEach(
-            (attribute: ModifiableDataBaseTotal<number>) => (attribute.total = attribute.base + attribute.mod),
-        );
+        Object.values(attributes).forEach((attribute) => (attribute.total = attribute.base + attribute.mod));
 
         const traits = data.data.traits;
-        Object.values(traits).forEach(
-            (trait: ModifiableDataBaseTotal<number>) => (trait.total = trait.base + trait.mod),
-        );
+        Object.values(traits).forEach((trait) => (trait.total = trait.base + trait.mod));
     }
 
-    override prepareEmbeddedDocuments() {
+    /** @override */
+    prepareEmbeddedDocuments() {
         super.prepareEmbeddedDocuments();
         this.applyActiveEffectsToItems();
     }
@@ -71,16 +57,21 @@ export class DS4Actor extends Actor {
         this.data.data.armorValueSpellMalus = this.armorValueSpellMalusOfEquippedItems;
     }
 
-    protected get actorEffects() {
+    /**
+     * The effects that should be applioed to this actor.
+     * @type {this["effects"]}
+     * @protected
+     */
+    get actorEffects() {
         return this.effects.filter((effect) => !effect.data.flags.ds4?.itemEffectConfig?.applyToItems);
     }
 
     /**
      * Get the effects of this actor that should be applied to the given item.
-     * @param item The item for which to get effects
+     * @param {import("../item/item").DS4Item} item The item for which to get effects
      * @returns The array of effects that are candidates to be applied to the item
      */
-    itemEffects(item: DS4Item) {
+    itemEffects(item) {
         return this.effects.filter((effect) => {
             const { applyToItems, itemName, condition } = effect.data.flags.ds4?.itemEffectConfig ?? {};
 
@@ -106,7 +97,14 @@ export class DS4Actor extends Actor {
         });
     }
 
-    protected static replaceFormulaData(formula: string, data: object): string | undefined {
+    /**
+     * Replace placholders in a formula with data.
+     * @param {string} formula The formular to enricht with data
+     * @param {object} data The data to use for enriching
+     * @returns {string | undefined} The Enriched formula or undefined, if it contains placeholders that cannot be resolved
+     * @protected
+     */
+    static replaceFormulaData(formula, data) {
         const dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
         try {
             return formula.replace(dataRgx, (_, term) => {
@@ -124,8 +122,9 @@ export class DS4Actor extends Actor {
     /**
      * We override this with an empty implementation because we have our own custom way of applying
      * {@link ActiveEffect}s and {@link Actor#prepareEmbeddedDocuments} calls this.
+     * @override
      */
-    override applyActiveEffects(): void {
+    applyActiveEffects() {
         return;
     }
 
@@ -138,7 +137,7 @@ export class DS4Actor extends Actor {
      * no special ordering among talents. This means that having a talents that provide effects that adjust the total
      * rank of talents can lead to nondeterministic behavior and thus must be avoided.
      */
-    applyActiveEffectsToItems(): void {
+    applyActiveEffectsToItems() {
         /* Handle talents before all other item types, because their rank might be affected, which in turn affects how
            many times effects provided by that talent are applied */
         for (const item of this.itemTypes.talent) {
@@ -150,12 +149,21 @@ export class DS4Actor extends Actor {
         }
     }
 
-    protected applyActiveEffectsToItem(item: DS4Item) {
+    /**
+     * Apply effects to the given item.
+     * @param {import("../item/item").DS4Item} item The item to which to apply effects
+     * @protected
+     */
+    applyActiveEffectsToItem(item) {
         item.overrides = {};
         DS4ActiveEffect.applyEffetcs(item, this.itemEffects(item));
     }
 
-    applyActiveEffectsToBaseData(): void {
+    /**
+     * Apply effects to base data
+     * @protected
+     */
+    applyActiveEffectsToBaseData() {
         this.overrides = {};
         DS4ActiveEffect.applyEffetcs(
             this,
@@ -166,7 +174,11 @@ export class DS4Actor extends Actor {
         );
     }
 
-    applyActiveEffectsToDerivedData(): void {
+    /**
+     * Apply effects to derived data
+     * @protected
+     */
+    applyActiveEffectsToDerivedData() {
         DS4ActiveEffect.applyEffetcs(this, this.actorEffects, (change) =>
             this.derivedDataProperties.includes(change.key),
         );
@@ -174,8 +186,9 @@ export class DS4Actor extends Actor {
 
     /**
      * Apply transformations to the Actor data after effects have been applied to the base data.
+     * @override
      */
-    override prepareDerivedData(): void {
+    prepareDerivedData() {
         this.data.data.armorValueSpellMalus = Math.max(this.data.data.armorValueSpellMalus, 0);
         this.prepareCombatValues();
         this.prepareChecks();
@@ -183,8 +196,9 @@ export class DS4Actor extends Actor {
 
     /**
      * The list of properties that are derived from others, given in dot notation.
+     * @returns {string[]} The list of derived propertie
      */
-    get derivedDataProperties(): Array<string> {
+    get derivedDataProperties() {
         const combatValueProperties = Object.keys(DS4.i18n.combatValues).map(
             (combatValue) => `data.combatValues.${combatValue}.total`,
         );
@@ -197,20 +211,14 @@ export class DS4Actor extends Actor {
     /**
      * Apply final transformations to the Actor data after all effects have been applied.
      */
-    prepareFinalDerivedData(): void {
-        Object.values(this.data.data.attributes).forEach(
-            (attribute: ModifiableDataBaseTotal<number>) => (attribute.total = Math.ceil(attribute.total)),
-        );
-        Object.values(this.data.data.traits).forEach(
-            (trait: ModifiableDataBaseTotal<number>) => (trait.total = Math.ceil(trait.total)),
-        );
+    prepareFinalDerivedData() {
+        Object.values(this.data.data.attributes).forEach((attribute) => (attribute.total = Math.ceil(attribute.total)));
+        Object.values(this.data.data.traits).forEach((trait) => (trait.total = Math.ceil(trait.total)));
         Object.entries(this.data.data.combatValues)
             .filter(([key]) => key !== "movement")
             .map(([, value]) => value)
-            .forEach(
-                (combatValue: ModifiableDataBaseTotal<number>) => (combatValue.total = Math.ceil(combatValue.total)),
-            );
-        (Object.keys(this.data.data.checks) as (keyof typeof this.data.data.checks)[]).forEach((key) => {
+            .forEach((combatValue) => (combatValue.total = Math.ceil(combatValue.total)));
+        Object.keys(this.data.data.checks).forEach((key) => {
             this.data.data.checks[key] = Math.ceil(this.data.data.checks[key]);
         });
 
@@ -221,30 +229,34 @@ export class DS4Actor extends Actor {
     /**
      * The list of properties that are completely derived (i.e. {@link ActiveEffect}s cannot be applied to them),
      * given in dot notation.
+     * @type {string[]}
      */
-    get finalDerivedDataProperties(): string[] {
+    get finalDerivedDataProperties() {
         return ["data.combatValues.hitPoints.max", "data.checks.defend"];
     }
 
     /**
      * The list of item types that can be owned by this actor.
+     * @type {import("../item/item-data-source").ItemType[]}
      */
-    get ownableItemTypes(): Array<ItemType> {
+    get ownableItemTypes() {
         return ["weapon", "armor", "shield", "equipment", "loot", "spell"];
     }
 
     /**
      * Checks whether or not the given item type can be owned by the actor.
-     * @param itemType - The item type to check
+     * @param {import("../item/item-data-source").ItemType} itemType    The item type to check
+     * @returns {boolean} Whether or not this actor can own the given item type
      */
-    canOwnItemType(itemType: ItemType): boolean {
+    canOwnItemType(itemType) {
         return this.ownableItemTypes.includes(itemType);
     }
 
     /**
-     *  Prepares the combat values of the actor.
+     * Prepares the combat values of the actor.
+     * @protected
      */
-    protected prepareCombatValues(): void {
+    prepareCombatValues() {
         const data = this.data.data;
 
         data.combatValues.hitPoints.base = data.attributes.body.total + data.traits.constitution.total + 10;
@@ -260,21 +272,25 @@ export class DS4Actor extends Actor {
             data.attributes.mind.total + data.traits.dexterity.total - data.armorValueSpellMalus;
 
         Object.values(data.combatValues).forEach(
-            (combatValue: ModifiableDataBaseTotal<number>) => (combatValue.total = combatValue.base + combatValue.mod),
+            (combatValue) => (combatValue.total = combatValue.base + combatValue.mod),
         );
     }
 
     /**
      * The total armor value of the equipped items.
+     * @type {number}
+     * @protected
      */
-    protected get armorValueOfEquippedItems(): number {
+    get armorValueOfEquippedItems() {
         return this.equippedItemsWithArmor.map((item) => item.data.data.armorValue).reduce((a, b) => a + b, 0);
     }
 
     /**
      * The armor value spell malus from equipped items.
+     * @type {number}
+     * @protected
      */
-    protected get armorValueSpellMalusOfEquippedItems(): number {
+    get armorValueSpellMalusOfEquippedItems() {
         return this.equippedItemsWithArmor
             .filter(
                 (item) =>
@@ -284,19 +300,22 @@ export class DS4Actor extends Actor {
             .reduce((a, b) => a + b, 0);
     }
 
-    protected get equippedItemsWithArmor() {
+    /**
+     * The equipped items of this actor that provide armor.
+     * @type {(import("../item/armor/armor").DS4Armor | import("../item/shield/shield").DS4Shield)[]}
+     * @protected
+     */
+    get equippedItemsWithArmor() {
         return this.items
-            .filter(
-                (item): item is DS4Item & { data: DS4ArmorDataProperties | DS4ShieldDataProperties } =>
-                    item.data.type === "armor" || item.data.type === "shield",
-            )
+            .filter((item) => item.data.type === "armor" || item.data.type === "shield")
             .filter((item) => item.data.data.equipped);
     }
 
     /**
      * Prepares the check target numbers of checks for the actor.
+     * @protected
      */
-    protected prepareChecks(): void {
+    prepareChecks() {
         const data = this.data.data;
         data.checks = {
             appraise: data.attributes.mind.total + data.traits.intellect.total,
@@ -334,17 +353,14 @@ export class DS4Actor extends Actor {
     /**
      * Handle how changes to a Token attribute bar are applied to the Actor.
      * This only differs from the base implementation by also allowing negative values.
+     * @override
      */
-    override async modifyTokenAttribute(
-        attribute: string,
-        value: number,
-        isDelta = false,
-        isBar = true,
-    ): Promise<this | undefined> {
+    async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) {
         const current = foundry.utils.getProperty(this.data.data, attribute);
 
         // Determine the updates to make to the actor data
-        let updates: Record<string, number>;
+        /** @type {Record<string, number>} */
+        let updates;
         if (isBar) {
             if (isDelta) value = Math.min(Number(current.value) + value, current.max);
             updates = { [`data.${attribute}.value`]: value };
@@ -360,13 +376,11 @@ export class DS4Actor extends Actor {
 
     /**
      * Roll for a given check.
-     * @param check - The check to perform
-     * @param options - Additional options to customize the roll
+     * @param {import("./actor-data-properties-base").Check} check          The check to perform
+     * @param {import("../common/roll-options").RollOptions} [options={}]   Additional options to customize the roll
+     * @returns {Promise<void>} A promise that resolves once the roll has been performed
      */
-    async rollCheck(
-        check: Check,
-        options: { speaker?: { token?: TokenDocument; alias?: string } } = {},
-    ): Promise<void> {
+    async rollCheck(check, options = {}) {
         const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker });
         await createCheckRoll(this.data.data.checks[check], {
             rollMode: getGame().settings.get("core", "rollMode"),
@@ -381,9 +395,10 @@ export class DS4Actor extends Actor {
     /**
      * Roll a generic check. A dialog is presented to select the combination of
      * Attribute and Trait to perform the check against.
-     * @param options - Additional options to customize the roll
+     * @param {import("../common/roll-options").RollOptions} [options={}]   Additional options to customize the roll
+     * @returns {Promise<void>} A promise that resolves once the roll has been performed
      */
-    async rollGenericCheck(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
+    async rollGenericCheck(options = {}) {
         const attributeAndTrait = await this.selectAttributeAndTrait();
         if (!attributeAndTrait) {
             return;
@@ -405,10 +420,12 @@ export class DS4Actor extends Actor {
         });
     }
 
-    protected async selectAttributeAndTrait(): Promise<{
-        attribute: keyof typeof DS4.i18n.attributes;
-        trait: keyof typeof DS4.i18n.traits;
-    } | null> {
+    /**
+     * Prompt the use to select an attribute and a trait.
+     * @returns {Promise<AttributeAndTrait | null>}
+     * @protected
+     */
+    async selectAttributeAndTrait() {
         const attributeIdentifier = "attribute-trait-selection-attribute";
         const traitIdentifier = "attribute-trait-selection-trait";
         return Dialog.prompt({
@@ -419,24 +436,20 @@ export class DS4Actor extends Actor {
                         label: getGame().i18n.localize("DS4.Attribute"),
                         identifier: attributeIdentifier,
                         options: Object.fromEntries(
-                            (Object.entries(DS4.i18n.attributes) as [keyof typeof DS4.i18n.attributes, string][]).map(
-                                ([attribute, translation]) => [
-                                    attribute,
-                                    `${translation} (${this.data.data.attributes[attribute].total})`,
-                                ],
-                            ),
+                            Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
+                                attribute,
+                                `${translation} (${this.data.data.attributes[attribute].total})`,
+                            ]),
                         ),
                     },
                     {
                         label: getGame().i18n.localize("DS4.Trait"),
                         identifier: traitIdentifier,
                         options: Object.fromEntries(
-                            (Object.entries(DS4.i18n.traits) as [keyof typeof DS4.i18n.traits, string][]).map(
-                                ([trait, translation]) => [
-                                    trait,
-                                    `${translation} (${this.data.data.traits[trait].total})`,
-                                ],
-                            ),
+                            Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
+                                trait,
+                                `${translation} (${this.data.data.traits[trait].total})`,
+                            ]),
                         ),
                     },
                 ],
@@ -474,3 +487,9 @@ export class DS4Actor extends Actor {
         });
     }
 }
+
+/**
+ * @typedef {object} AttributeAndTrait
+ * @property {keyof typeof DS4.i18n.attributes} attribute
+ * @property {keyof typeof DS4.i18n.traits} trait
+ */
diff --git a/src/documents/actor/character/character.ts b/src/documents/actor/character/character.js
similarity index 56%
rename from src/documents/actor/character/character.ts
rename to src/documents/actor/character/character.js
index bda2cb65..5a11d910 100644
--- a/src/documents/actor/character/character.ts
+++ b/src/documents/actor/character/character.js
@@ -4,23 +4,20 @@
 
 import { DS4Actor } from "../actor";
 
-import type { ItemType } from "../../item/item-data-source";
-
 export class DS4Character extends DS4Actor {
-    override prepareFinalDerivedData(): void {
+    /** @override */
+    prepareFinalDerivedData() {
         super.prepareFinalDerivedData();
         this.data.data.slayerPoints.max = 3;
     }
 
-    override get finalDerivedDataProperties(): string[] {
+    /** @override */
+    get finalDerivedDataProperties() {
         return [...super.finalDerivedDataProperties, "data.slayerPoints.max"];
     }
 
-    override get ownableItemTypes(): Array<ItemType> {
+    /** @override */
+    get ownableItemTypes() {
         return [...super.ownableItemTypes, "talent", "racialAbility", "language", "alphabet"];
     }
 }
-
-export interface DS4Character {
-    data: foundry.data.ActorData & { type: "character"; _source: { type: "character" } };
-}
diff --git a/src/documents/actor/creature/creature.ts b/src/documents/actor/creature/creature.ts
index 1690195a..594812f3 100644
--- a/src/documents/actor/creature/creature.ts
+++ b/src/documents/actor/creature/creature.ts
@@ -11,7 +11,3 @@ export class DS4Creature extends DS4Actor {
         return [...super.ownableItemTypes, "specialCreatureAbility"];
     }
 }
-
-export interface DS4Creature {
-    data: foundry.data.ActorData & { type: "creature"; _source: { type: "creature" } };
-}
diff --git a/src/documents/actor/proxy.ts b/src/documents/actor/proxy.js
similarity index 73%
rename from src/documents/actor/proxy.ts
rename to src/documents/actor/proxy.js
index e5eb2f44..5a2434a8 100644
--- a/src/documents/actor/proxy.ts
+++ b/src/documents/actor/proxy.js
@@ -8,7 +8,11 @@ import { DS4Character } from "./character/character";
 import { DS4Creature } from "./creature/creature";
 
 const handler = {
-    construct(_: typeof DS4Actor, args: ConstructorParameters<typeof DS4Actor>) {
+    /**
+     * @param {typeof import("./actor").DS4Actor}
+     * @param {unknown[]} args
+     */
+    construct(_, args) {
         switch (args[0]?.type) {
             case "character":
                 return new DS4Character(...args);
@@ -20,4 +24,5 @@ const handler = {
     },
 };
 
-export const DS4ActorProxy: typeof DS4Actor = new Proxy(DS4Actor, handler);
+/** @type {typeof import("./actor").DS4Actor} */
+export const DS4ActorProxy = new Proxy(DS4Actor, handler);
diff --git a/src/documents/chat-message.ts b/src/documents/chat-message.js
similarity index 67%
rename from src/documents/chat-message.ts
rename to src/documents/chat-message.js
index ac99b9d5..9392da66 100644
--- a/src/documents/chat-message.ts
+++ b/src/documents/chat-message.js
@@ -4,18 +4,18 @@
 
 import { getGame } from "../utils/utils";
 
-declare global {
-    interface FlagConfig {
-        ChatMessage: {
-            ds4?: {
-                flavorData?: Record<string, string | number | null>;
-            };
-        };
-    }
-}
+/**
+ * @typedef {object} DS4ChatMessageFlags
+ * @property {Record<string, string | number | null>} [flavorData]  Data to use for localizing the flavor of the chat message
+ */
+
+/**
+ * @typedef {Record<string, unknown>} ChatMessageFlags
+ * @property {DS4ChatMessageFlags} [ds4]    Flags for DS4
+ */
 
 export class DS4ChatMessage extends ChatMessage {
-    override prepareData(): void {
+    prepareData() {
         super.prepareData();
         if (this.data.flavor) {
             const game = getGame();
diff --git a/src/documents/item/alphabet/alphabet.ts b/src/documents/item/alphabet/alphabet.ts
index d710b896..be6e5301 100644
--- a/src/documents/item/alphabet/alphabet.ts
+++ b/src/documents/item/alphabet/alphabet.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Alphabet extends DS4Item {}
-
-export interface DS4Alphabet {
-    data: foundry.data.ItemData & { type: "alphabet"; _source: { type: "alphabet" } };
-}
diff --git a/src/documents/item/armor/armor.ts b/src/documents/item/armor/armor.ts
index 9c18fb6e..531d0d7c 100644
--- a/src/documents/item/armor/armor.ts
+++ b/src/documents/item/armor/armor.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Armor extends DS4Item {}
-
-export interface DS4Armor {
-    data: foundry.data.ItemData & { type: "armor"; _source: { type: "armor" } };
-}
diff --git a/src/documents/item/equipment/equipment.ts b/src/documents/item/equipment/equipment.ts
index f5e7d455..748177d5 100644
--- a/src/documents/item/equipment/equipment.ts
+++ b/src/documents/item/equipment/equipment.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Equipment extends DS4Item {}
-
-export interface DS4Equipment {
-    data: foundry.data.ItemData & { type: "equipment"; _source: { type: "equipment" } };
-}
diff --git a/src/documents/item/item-data-source-base.ts b/src/documents/item/item-data-source-base.ts
index dbd1a06b..7ef38be4 100644
--- a/src/documents/item/item-data-source-base.ts
+++ b/src/documents/item/item-data-source-base.ts
@@ -17,7 +17,7 @@ export interface DS4ItemDataSourceDataPhysical {
     storageLocation: string;
 }
 
-export function isDS4ItemDataTypePhysical(input: foundry.data.ItemData["data"]): boolean {
+export function isDS4ItemDataTypePhysical(input: object): boolean {
     return "quantity" in input && "price" in input && "availability" in input && "storageLocation" in input;
 }
 
diff --git a/src/documents/item/item.js b/src/documents/item/item.js
new file mode 100644
index 00000000..c54288ef
--- /dev/null
+++ b/src/documents/item/item.js
@@ -0,0 +1,57 @@
+// SPDX-FileCopyrightText: 2021 Johannes Loher
+// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
+//
+// SPDX-License-Identifier: MIT
+
+import { getGame } from "../../utils/utils";
+
+/**
+ * The Item class for DS4
+ */
+export class DS4Item extends Item {
+    /**
+     * An object that tracks the changes to the data model which were applied by active effects
+     * @type {Record<string, unknown>}
+     */
+    overrides = {};
+
+    /** @override */
+    prepareDerivedData() {
+        this.data.data.rollable = false;
+    }
+
+    /**
+     * Is this item a non-equipped equipable?
+     * @returns {boolean} Whether the item is a non-equpped equibale or not
+     */
+    isNonEquippedEuipable() {
+        return "equipped" in this.data.data && !this.data.data.equipped;
+    }
+
+    /**
+     * The number of times that active effect changes originating from this item should be applied.
+     * @returns {number | undefined} The number of times the effect should be applied
+     */
+    get activeEffectFactor() {
+        return 1;
+    }
+
+    /**
+     * The list of item types that are rollable.
+     * @returns {import("../item/item-data-source").ItemType[]} The rollable item types
+     */
+    static get rollableItemTypes() {
+        return ["weapon", "spell"];
+    }
+
+    /**
+     * Roll a check for an action with this item.
+     * @param {import("../common/roll-options").RollOptions} [options={}]    Additional options to customize the roll
+     * @returns {Promise<void>} A promise that resolves once the roll has been performed
+     * @abstract
+     */
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    async roll(options = {}) {
+        throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type }));
+    }
+}
diff --git a/src/documents/item/item.ts b/src/documents/item/item.ts
deleted file mode 100644
index 50015e37..00000000
--- a/src/documents/item/item.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Johannes Loher
-// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
-//
-// SPDX-License-Identifier: MIT
-
-import { getGame } from "../../utils/utils";
-
-import type { ItemType } from "./item-data-source";
-
-declare global {
-    interface DocumentClassConfig {
-        Item: typeof DS4Item;
-    }
-
-    // eslint-disable-next-line @typescript-eslint/no-namespace
-    namespace Hooks {
-        interface StaticCallbacks {
-            "ds4.rollItem": (item: DS4Item) => void;
-        }
-    }
-}
-
-/**
- * The Item class for DS4
- */
-export class DS4Item extends Item {
-    /** An object that tracks the changes to the data model which were applied by active effects */
-    overrides: Record<string, unknown> = {};
-
-    override prepareDerivedData(): void {
-        this.data.data.rollable = false;
-    }
-
-    isNonEquippedEuipable(): boolean {
-        return "equipped" in this.data.data && !this.data.data.equipped;
-    }
-
-    /**
-     * The number of times that active effect changes originating from this item should be applied.
-     */
-    get activeEffectFactor(): number | undefined {
-        return 1;
-    }
-
-    /**
-     * The list of item types that are rollable.
-     */
-    static get rollableItemTypes(): ItemType[] {
-        return ["weapon", "spell"];
-    }
-
-    /**
-     * Roll a check for an action with this item.
-     * @param options - Additional options to customize the roll
-     */
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
-        throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type }));
-    }
-}
diff --git a/src/documents/item/language/language.ts b/src/documents/item/language/language.ts
index 0faf53da..2d8d45ec 100644
--- a/src/documents/item/language/language.ts
+++ b/src/documents/item/language/language.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Language extends DS4Item {}
-
-export interface DS4Language {
-    data: foundry.data.ItemData & { type: "language"; _source: { type: "language" } };
-}
diff --git a/src/documents/item/loot/loot.ts b/src/documents/item/loot/loot.ts
index 34528207..ba90a2fd 100644
--- a/src/documents/item/loot/loot.ts
+++ b/src/documents/item/loot/loot.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Loot extends DS4Item {}
-
-export interface DS4Loot {
-    data: foundry.data.ItemData & { type: "loot"; _source: { type: "loot" } };
-}
diff --git a/src/documents/item/proxy.ts b/src/documents/item/proxy.js
similarity index 88%
rename from src/documents/item/proxy.ts
rename to src/documents/item/proxy.js
index b978bc30..ff8c1a8a 100644
--- a/src/documents/item/proxy.ts
+++ b/src/documents/item/proxy.js
@@ -17,7 +17,11 @@ import { DS4Talent } from "./talent/talent";
 import { DS4Weapon } from "./weapon/weapon";
 
 const handler = {
-    construct(_: typeof DS4Item, args: ConstructorParameters<typeof DS4Item>) {
+    /**
+     * @param {typeof import("./item").DS4Item}
+     * @param {unknown[]} args
+     */
+    construct(_, args) {
         switch (args[0]?.type) {
             case "alphabet":
                 return new DS4Alphabet(...args);
@@ -47,4 +51,5 @@ const handler = {
     },
 };
 
-export const DS4ItemProxy: typeof DS4Item = new Proxy(DS4Item, handler);
+/** @type {typeof import("./item").DS4Item} */
+export const DS4ItemProxy = new Proxy(DS4Item, handler);
diff --git a/src/documents/item/racial-ability/racial-ability.ts b/src/documents/item/racial-ability/racial-ability.ts
index 526f2533..b3b360d9 100644
--- a/src/documents/item/racial-ability/racial-ability.ts
+++ b/src/documents/item/racial-ability/racial-ability.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4RacialAbility extends DS4Item {}
-
-export interface DS4RacialAbility {
-    data: foundry.data.ItemData & { type: "racialAbility"; _source: { type: "racialAbility" } };
-}
diff --git a/src/documents/item/shield/shield.ts b/src/documents/item/shield/shield.ts
index 16a6e683..0da6a219 100644
--- a/src/documents/item/shield/shield.ts
+++ b/src/documents/item/shield/shield.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4Shield extends DS4Item {}
-
-export interface DS4Shield {
-    data: foundry.data.ItemData & { type: "shield"; _source: { type: "shield" } };
-}
diff --git a/src/documents/item/special-creature-ability/special-creature-ability.ts b/src/documents/item/special-creature-ability/special-creature-ability.ts
index 1919ae88..57e90988 100644
--- a/src/documents/item/special-creature-ability/special-creature-ability.ts
+++ b/src/documents/item/special-creature-ability/special-creature-ability.ts
@@ -5,7 +5,3 @@
 import { DS4Item } from "../item";
 
 export class DS4SpecialCreatureAbility extends DS4Item {}
-
-export interface DS4SpecialCreatureAbility {
-    data: foundry.data.ItemData & { type: "specialCreatureAbility"; _source: { type: "specialCreatureAbility" } };
-}
diff --git a/src/documents/item/spell/spell.ts b/src/documents/item/spell/spell.js
similarity index 84%
rename from src/documents/item/spell/spell.ts
rename to src/documents/item/spell/spell.js
index 6fe74b9a..79eaf871 100644
--- a/src/documents/item/spell/spell.ts
+++ b/src/documents/item/spell/spell.js
@@ -2,14 +2,15 @@
 //
 // SPDX-License-Identifier: MIT
 
-import { createCheckRoll, DS4CheckFactoryOptions } from "../../../dice/check-factory";
+import { createCheckRoll } from "../../../dice/check-factory";
 import { notifications } from "../../../ui/notifications";
 import { getGame } from "../../../utils/utils";
 import { DS4Item } from "../item";
 import { calculateSpellPrice } from "./calculate-spell-price";
 
 export class DS4Spell extends DS4Item {
-    override prepareDerivedData(): void {
+    /** @override */
+    prepareDerivedData() {
         this.data.data.rollable = this.data.data.equipped;
         this.data.data.price = calculateSpellPrice(this.data.data);
         if (this.data.data.allowsDefense) {
@@ -17,7 +18,8 @@ export class DS4Spell extends DS4Item {
         }
     }
 
-    override async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
+    /** @override */
+    async roll(options = {}) {
         const game = getGame();
 
         if (!this.data.data.equipped) {
@@ -54,7 +56,8 @@ export class DS4Spell extends DS4Item {
             opponentDefense !== undefined && opponentDefense !== 0
                 ? "DS4.ItemSpellCheckFlavorWithOpponentDefense"
                 : "DS4.ItemSpellCheckFlavor";
-        const flavorData: DS4CheckFactoryOptions["flavorData"] = {
+        /** @type {import("../../../dice/check-factory").DS4CheckFactoryOptions["flavorData"]} */
+        const flavorData = {
             actor: speaker.alias ?? this.actor.name,
             spell: this.name,
         };
@@ -71,10 +74,12 @@ export class DS4Spell extends DS4Item {
             speaker,
         });
 
+        /**
+         * A hook event that fires after an item is rolled.
+         * @function ds4.rollItem
+         * @memberof hookEvents
+         * @param {DS4Item} item    Item being rolled.
+         */
         Hooks.callAll("ds4.rollItem", this);
     }
 }
-
-export interface DS4Spell {
-    data: foundry.data.ItemData & { type: "spell"; _source: { type: "spell" } };
-}
diff --git a/src/documents/item/talent/talent.ts b/src/documents/item/talent/talent.js
similarity index 61%
rename from src/documents/item/talent/talent.ts
rename to src/documents/item/talent/talent.js
index 9d4875c9..c440f08d 100644
--- a/src/documents/item/talent/talent.ts
+++ b/src/documents/item/talent/talent.js
@@ -5,17 +5,15 @@
 import { DS4Item } from "../item";
 
 export class DS4Talent extends DS4Item {
-    override prepareDerivedData(): void {
+    /** @override */
+    prepareDerivedData() {
         super.prepareDerivedData();
         const data = this.data.data;
         data.rank.total = data.rank.base + data.rank.mod;
     }
 
-    override get activeEffectFactor(): number | undefined {
+    /** @override */
+    get activeEffectFactor() {
         return this.data.data.rank.total;
     }
 }
-
-export interface DS4Talent {
-    data: foundry.data.ItemData & { type: "talent"; _source: { type: "talent" } };
-}
diff --git a/src/documents/item/weapon/weapon.ts b/src/documents/item/weapon/weapon.js
similarity index 86%
rename from src/documents/item/weapon/weapon.ts
rename to src/documents/item/weapon/weapon.js
index 3eaae806..b0d75afb 100644
--- a/src/documents/item/weapon/weapon.ts
+++ b/src/documents/item/weapon/weapon.js
@@ -3,13 +3,14 @@
 // SPDX-License-Identifier: MIT
 
 import { DS4 } from "../../../config";
-import { createCheckRoll, DS4CheckFactoryOptions } from "../../../dice/check-factory";
+import { createCheckRoll } from "../../../dice/check-factory";
 import { notifications } from "../../../ui/notifications";
 import { getGame } from "../../../utils/utils";
 import { DS4Item } from "../item";
 
 export class DS4Weapon extends DS4Item {
-    override prepareDerivedData(): void {
+    /** @override */
+    prepareDerivedData() {
         const data = this.data.data;
         data.rollable = data.equipped;
         data.opponentDefenseForAttackType = {};
@@ -21,7 +22,8 @@ export class DS4Weapon extends DS4Item {
         }
     }
 
-    override async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
+    /** @override */
+    async roll(options = {}) {
         const game = getGame();
         if (!this.data.data.equipped) {
             return notifications.warn(
@@ -41,14 +43,15 @@ export class DS4Weapon extends DS4Item {
         const weaponBonus = this.data.data.weaponBonus;
         const attackType = await this.getPerformedAttackType();
         const opponentDefense = this.data.data.opponentDefenseForAttackType[attackType];
-        const combatValue = `${attackType}Attack` as const;
+        const combatValue = `${attackType}Attack`;
         const checkTargetNumber = ownerDataData.combatValues[combatValue].total + weaponBonus;
         const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
         const flavor =
             opponentDefense !== undefined && opponentDefense !== 0
                 ? "DS4.ItemWeaponCheckFlavorWithOpponentDefense"
                 : "DS4.ItemWeaponCheckFlavor";
-        const flavorData: DS4CheckFactoryOptions["flavorData"] = {
+        /** @type {import("../../../dice/check-factory").DS4CheckFactoryOptions["flavorData"]} */
+        const flavorData = {
             actor: speaker.alias ?? this.actor.name,
             weapon: this.name,
         };
@@ -68,7 +71,12 @@ export class DS4Weapon extends DS4Item {
         Hooks.callAll("ds4.rollItem", this);
     }
 
-    private async getPerformedAttackType(): Promise<"melee" | "ranged"> {
+    /**
+     * Get the attack type to perform with this weapon. If there are multiple options prompt the user for a choice.
+     * @returns {Promise<"melee" | "ranged">} The attack type to perform
+     * @protected
+     */
+    async getPerformedAttackType() {
         if (this.data.data.attackType !== "meleeRanged") {
             return this.data.data.attackType;
         }
@@ -102,7 +110,3 @@ export class DS4Weapon extends DS4Item {
         });
     }
 }
-
-export interface DS4Weapon {
-    data: foundry.data.ItemData & { type: "weapon"; _source: { type: "weapon" } };
-}
diff --git a/src/documents/token-document.ts b/src/documents/token-document.js
similarity index 54%
rename from src/documents/token-document.ts
rename to src/documents/token-document.js
index 4aa855e6..9212899e 100644
--- a/src/documents/token-document.ts
+++ b/src/documents/token-document.js
@@ -5,23 +5,21 @@
 import { getGame } from "../utils/utils";
 import { DS4ActorProxy } from "./actor/proxy";
 
-let fallbackData: foundry.data.ActorData["data"] | undefined = undefined;
+/** @type {object | undefined} */
+let fallbackData = undefined;
 
 function getFallbackData() {
     if (!fallbackData) {
-        fallbackData = {} as foundry.data.ActorData["data"];
+        fallbackData = {};
         for (const type of getGame().system.template.Actor?.types ?? []) {
-            foundry.utils.mergeObject(
-                fallbackData,
-                new DS4ActorProxy({ type: type as foundry.data.ActorData["type"], name: "temporary" }).data.data,
-            );
+            foundry.utils.mergeObject(fallbackData, new DS4ActorProxy({ type, name: "temporary" }).data.data);
         }
     }
     return fallbackData;
 }
 
 export class DS4TokenDocument extends TokenDocument {
-    static override getTrackedAttributes(data?: foundry.data.ActorData["data"], _path: string[] = []) {
+    static getTrackedAttributes(data, _path = []) {
         if (!data) {
             data = getFallbackData();
         }
diff --git a/src/global.d.ts b/src/global.d.ts
deleted file mode 100644
index 91fc6c12..00000000
--- a/src/global.d.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Johannes Loher
-//
-// SPDX-License-Identifier: MIT
-
-declare global {
-    namespace ClientSettings {
-        interface Values {
-            "ds4.systemMigrationVersion": number;
-            "ds4.useSlayingDiceForAutomatedChecks": boolean;
-            "ds4.showSlayerPoints": boolean;
-        }
-    }
-
-    namespace PoolTerm {
-        interface Modifiers {
-            x: (this: PoolTerm, modifier: string) => void;
-        }
-    }
-}
-
-export {};
diff --git a/src/handlebars/handlebars-partials.ts b/src/handlebars/handlebars-partials.js
similarity index 94%
rename from src/handlebars/handlebars-partials.ts
rename to src/handlebars/handlebars-partials.js
index 1992b551..eb2c1b14 100644
--- a/src/handlebars/handlebars-partials.ts
+++ b/src/handlebars/handlebars-partials.js
@@ -4,7 +4,11 @@
 //
 // SPDX-License-Identifier: MIT
 
-export async function registerHandlebarsPartials(): Promise<void> {
+/**
+ * Register the Handlebars partials for DS4.
+ * @returns {Promise<void>} A promise that resolves once all partials have been registered
+ */
+export async function registerHandlebarsPartials() {
     const templatePaths = [
         "systems/ds4/templates/sheets/actor/components/actor-header.hbs",
         "systems/ds4/templates/sheets/actor/components/actor-progression.hbs",
diff --git a/src/hooks/hotbar-drop.js b/src/hooks/hotbar-drop.js
new file mode 100644
index 00000000..eed324cc
--- /dev/null
+++ b/src/hooks/hotbar-drop.js
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: 2021 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { isCheck } from "../documents/actor/actor-data-properties-base";
+import { DS4Item } from "../documents/item/item";
+import { createRollCheckMacro } from "../macros/roll-check";
+import { createRollItemMacro } from "../macros/roll-item";
+import { notifications } from "../ui/notifications";
+import { getGame } from "../utils/utils";
+
+export function registerForHotbarDropHook() {
+    Hooks.on("hotbarDrop", onHotbarDrop);
+}
+
+/**
+ * @typedef {Record<string, unknown>} DropData
+ * @property {string} type
+ */
+
+/**
+ * Handle a drop event on the hotbar
+ * @param {Hotbar} hotbar The hotbar on which something wqas
+ * @param {DropData} data The drop data associated to the drop event
+ * @param {string} slot The slot on the hotbar that somethingwas dropped on
+ * @returns {Promise<void>}
+ */
+async function onHotbarDrop(hotbar, data, slot) {
+    switch (data.type) {
+        case "Item": {
+            if (!("data" in data)) {
+                return notifications.warn(getGame().i18n.localize("DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems"));
+            }
+            const itemData = data.data;
+
+            if (!DS4Item.rollableItemTypes.includes(itemData.type)) {
+                return notifications.warn(
+                    getGame().i18n.format("DS4.WarningItemIsNotRollable", {
+                        name: itemData.name,
+                        id: itemData._id,
+                        type: itemData.type,
+                    }),
+                );
+            }
+            return createRollItemMacro(itemData, slot);
+        }
+        case "Check": {
+            if (!("data" in data) || typeof data.data !== "string" || !isCheck(data.data)) {
+                return notifications.warn(getGame().i18n.localize("DS4.WarningInvalidCheckDropped"));
+            }
+            return createRollCheckMacro(data.data, slot);
+        }
+    }
+}
diff --git a/src/hooks/hotbar-drop.ts b/src/hooks/hotbar-drop.ts
deleted file mode 100644
index 438cb630..00000000
--- a/src/hooks/hotbar-drop.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Johannes Loher
-//
-// SPDX-License-Identifier: MIT
-
-import { isCheck } from "../documents/actor/actor-data-properties-base";
-import { DS4Item } from "../documents/item/item";
-import { createRollCheckMacro } from "../macros/roll-check";
-import { createRollItemMacro } from "../macros/roll-item";
-import { notifications } from "../ui/notifications";
-import { getGame } from "../utils/utils";
-
-export function registerForHotbarDropHook(): void {
-    Hooks.on("hotbarDrop", async (hotbar: Hotbar, data: HotbarDropData, slot: string) => {
-        switch (data.type) {
-            case "Item": {
-                if (!isItemDropData(data) || !("data" in data)) {
-                    return notifications.warn(
-                        getGame().i18n.localize("DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems"),
-                    );
-                }
-                const itemData = data.data;
-
-                if (!DS4Item.rollableItemTypes.includes(itemData.type)) {
-                    return notifications.warn(
-                        getGame().i18n.format("DS4.WarningItemIsNotRollable", {
-                            name: itemData.name,
-                            id: itemData._id,
-                            type: itemData.type,
-                        }),
-                    );
-                }
-                return createRollItemMacro(itemData, slot);
-            }
-            case "Check": {
-                if (!("data" in data) || typeof data.data !== "string" || !isCheck(data.data)) {
-                    return notifications.warn(getGame().i18n.localize("DS4.WarningInvalidCheckDropped"));
-                }
-                return createRollCheckMacro(data.data, slot);
-            }
-        }
-    });
-}
-
-type HotbarDropData = ActorSheet.DropData.Item | ({ type: string } & Partial<Record<string, unknown>>);
-
-function isItemDropData(dropData: HotbarDropData): dropData is ActorSheet.DropData.Item {
-    return dropData.type === "Item";
-}
diff --git a/src/hooks/init.ts b/src/hooks/init.js
similarity index 85%
rename from src/hooks/init.ts
rename to src/hooks/init.js
index 19de9032..804f60b4 100644
--- a/src/hooks/init.ts
+++ b/src/hooks/init.js
@@ -27,10 +27,7 @@ import { preloadFonts } from "../ui/fonts";
 import { logger } from "../utils/logger";
 import { getGame } from "../utils/utils";
 
-import type { DS4Actor } from "../documents/actor/actor";
-import type { DS4Item } from "../documents/item/item";
-
-export function registerForInitHook(): void {
+export function registerForInitHook() {
     Hooks.once("init", init);
 }
 
@@ -81,20 +78,3 @@ async function init() {
     await registerHandlebarsPartials();
     registerHandlebarsHelpers();
 }
-
-declare global {
-    interface Game {
-        ds4: {
-            DS4Actor: typeof DS4Actor;
-            DS4Item: typeof DS4Item;
-            DS4: typeof DS4;
-            createCheckRoll: typeof createCheckRoll;
-            migration: typeof migration;
-            macros: typeof macros;
-        };
-    }
-
-    interface CONFIG {
-        DS4: typeof DS4;
-    }
-}
diff --git a/src/hooks/ready.ts b/src/hooks/ready.js
similarity index 81%
rename from src/hooks/ready.ts
rename to src/hooks/ready.js
index 91c9c0cb..a04a0c0a 100644
--- a/src/hooks/ready.ts
+++ b/src/hooks/ready.js
@@ -4,7 +4,7 @@
 
 import { migration } from "../migration/migration";
 
-export function registerForReadyHook(): void {
+export function registerForReadyHook() {
     Hooks.once("ready", () => {
         migration.migrate();
     });
diff --git a/src/hooks/render.ts b/src/hooks/render.js
similarity index 64%
rename from src/hooks/render.ts
rename to src/hooks/render.js
index b12c9ebe..bb59bcb8 100644
--- a/src/hooks/render.ts
+++ b/src/hooks/render.js
@@ -7,7 +7,7 @@
  * @remarks The render hooks of all classes in the class hierarchy are called, so e.g. for a {@link Dialog}, both the
  * "renderDialog" hook and the "renderApplication" hook are called (in this order).
  */
-export function registerForRenderHooks(): void {
+export function registerForRenderHooks() {
     ["renderApplication", "renderActorSheet", "renderItemSheet"].forEach((hook) => {
         Hooks.on(hook, selectTargetInputOnFocus);
     });
@@ -16,11 +16,11 @@ export function registerForRenderHooks(): void {
 /**
  * Select the text of input elements in given application when focused via an on focus listener.
  *
- * @param app  - The application in which to activate the listener.
- * @param html - The {@link JQuery} representing the HTML of the application.
+ * @param {Application} app The application in which to activate the listener.
+ * @param {JQuery} html     The {@link JQuery} representing the HTML of the application.
  */
-function selectTargetInputOnFocus(app: Application, html: JQuery) {
-    html.find("input").on("focus", (ev: JQuery.FocusEvent<HTMLInputElement>) => {
+function selectTargetInputOnFocus(app, html) {
+    html.find("input").on("focus", (ev) => {
         ev.currentTarget.select();
     });
 }
diff --git a/src/hooks/setup.ts b/src/hooks/setup.js
similarity index 74%
rename from src/hooks/setup.ts
rename to src/hooks/setup.js
index 6c339f51..50527e28 100644
--- a/src/hooks/setup.ts
+++ b/src/hooks/setup.js
@@ -8,7 +8,7 @@
 import { DS4 } from "../config";
 import { getGame } from "../utils/utils";
 
-export function registerForSetupHook(): void {
+export function registerForSetupHook() {
     Hooks.once("setup", () => {
         localizeAndSortConfigObjects();
     });
@@ -28,17 +28,23 @@ function localizeAndSortConfigObjects() {
         "checkModifiers",
     ];
 
-    const localizeObject = <T extends { [s: string]: string }>(obj: T, sort = true): T => {
-        const localized = Object.entries(obj).map(([key, value]): [string, string] => {
+    /**
+     * @template {Record<string, string>} T
+     * @param {T} obj               The object to localize
+     * @param {boolean} [sort=true] whether or not to sort the object
+     * @returns {T} the localized object
+     */
+    const localizeObject = (obj, sort = true) => {
+        const localized = Object.entries(obj).map(([key, value]) => {
             return [key, getGame().i18n.localize(value)];
         });
         if (sort) localized.sort((a, b) => a[1].localeCompare(b[1]));
-        return Object.fromEntries(localized) as T;
+        return Object.fromEntries(localized);
     };
 
     DS4.i18n = Object.fromEntries(
         Object.entries(DS4.i18n).map(([key, value]) => {
             return [key, localizeObject(value, !noSort.includes(key))];
         }),
-    ) as typeof DS4.i18n;
+    );
 }
diff --git a/src/macros/helpers.ts b/src/macros/helpers.js
similarity index 74%
rename from src/macros/helpers.ts
rename to src/macros/helpers.js
index 3542c7b8..8484a07e 100644
--- a/src/macros/helpers.ts
+++ b/src/macros/helpers.js
@@ -4,14 +4,12 @@
 
 import { getCanvas, getGame } from "../utils/utils";
 
-import type { DS4Actor } from "../documents/actor/actor";
-
 /**
  * Gets the currently active actor and token based on how {@link ChatMessage}
  * determines the current speaker.
- * @returns The currently active {@link DS4Actor} and {@link TokenDocument}.
+ * @returns {{actor?: import("../documents/actor/actor").DS4Actor, token?: TokenDocument}} The currently active actor and token.
  */
-export function getActiveActorAndToken(): { actor?: DS4Actor; token?: TokenDocument } {
+export function getActiveActorAndToken() {
     const speaker = ChatMessage.getSpeaker();
 
     const speakerToken = speaker.token ? getCanvas().tokens?.get(speaker.token)?.document : undefined;
diff --git a/src/macros/roll-check.ts b/src/macros/roll-check.js
similarity index 59%
rename from src/macros/roll-check.ts
rename to src/macros/roll-check.js
index 45fa601e..9e061038 100644
--- a/src/macros/roll-check.ts
+++ b/src/macros/roll-check.js
@@ -7,19 +7,23 @@ import { notifications } from "../ui/notifications";
 import { getGame } from "../utils/utils";
 import { getActiveActorAndToken } from "./helpers";
 
-import type { Check } from "../documents/actor/actor-data-properties-base";
 /**
  * Creates a macro from a check drop.
  * Get an existing roll check macro if one exists, otherwise create a new one.
- * @param check - The name of the check to perform.
- * @param slot  - The hotbar slot to use.
+ * @param {import("../documents/actor/actor-data-properties-base").Check} check The name of the check to perform
+ * @param {string} slot                                                         The hotbar slot to use
+ * @returns {Promise<void>} A promise that resoolves when the macro has been created.
  */
-export async function createRollCheckMacro(check: Check, slot: string): Promise<void> {
+export async function createRollCheckMacro(check, slot) {
     const macro = await getOrCreateRollCheckMacro(check);
-    getGame().user?.assignHotbarMacro(macro ?? null, slot);
+    await getGame().user?.assignHotbarMacro(macro ?? null, slot);
 }
 
-async function getOrCreateRollCheckMacro(check: Check): Promise<Macro | undefined> {
+/**
+ * @param {import("../documents/actor/actor-data-properties-base").Check} check The name of the check to perform
+ * @returns {Promise<Macro|undefined>} A promise that resolves to the created macro
+ */
+async function getOrCreateRollCheckMacro(check) {
     const command = `game.ds4.macros.rollCheck("${check}");`;
 
     const existingMacro = getGame().macros?.find(
@@ -43,8 +47,10 @@ async function getOrCreateRollCheckMacro(check: Check): Promise<Macro | undefine
 
 /**
  * Executes the roll check macro for the given check.
+ * @param {import("../documents/actor/actor-data-properties-base").Check} check The name of the check to perform
+ * @returns {Promise<void>} A promise that resolves once the check has been performed.
  */
-export async function rollCheck(check: Check): Promise<void> {
+export async function rollCheck(check) {
     const { actor, token } = getActiveActorAndToken();
     if (!actor) {
         return notifications.warn(getGame().i18n.localize("DS4.WarningMustControlActorToUseRollCheckMacro"));
diff --git a/src/macros/roll-item.ts b/src/macros/roll-item.js
similarity index 70%
rename from src/macros/roll-item.ts
rename to src/macros/roll-item.js
index a30d02cd..7e2fce2d 100644
--- a/src/macros/roll-item.ts
+++ b/src/macros/roll-item.js
@@ -9,15 +9,20 @@ import { getActiveActorAndToken } from "./helpers";
 /**
  * Creates a macro from an item drop.
  * Get an existing roll item macro if one exists, otherwise create a new one.
- * @param itemData - The item data
- * @param slot     - The hotbar slot to use
+ * @param {object} itemData The item data
+ * @param {string} slot     The hotbar slot to use
+ * @returns {Promise<void>} A promise that resolves once the macro has been created.
  */
-export async function createRollItemMacro(itemData: foundry.data.ItemData["_source"], slot: string): Promise<void> {
+export async function createRollItemMacro(itemData, slot) {
     const macro = await getOrCreateRollItemMacro(itemData);
-    getGame().user?.assignHotbarMacro(macro ?? null, slot);
+    await getGame().user?.assignHotbarMacro(macro ?? null, slot);
 }
 
-async function getOrCreateRollItemMacro(itemData: foundry.data.ItemData["_source"]): Promise<Macro | undefined> {
+/**
+ * @param {object} itemData The item data
+ * @returns {Promise<Macro | undefined>} A promise that resolves to the created macro
+ */
+async function getOrCreateRollItemMacro(itemData) {
     const command = `game.ds4.macros.rollItem("${itemData._id}");`;
 
     const existingMacro = getGame().macros?.find((m) => m.name === itemData.name && m.data.command === command);
@@ -39,8 +44,10 @@ async function getOrCreateRollItemMacro(itemData: foundry.data.ItemData["_source
 
 /**
  * Executes the roll item macro for the item associated to the given `itemId`.
+ * @param {string} itemId   The id of the item to roll
+ * @returns {Promise<void>} A promise that resolves once the item has been rolled.
  */
-export async function rollItem(itemId: string): Promise<void> {
+export async function rollItem(itemId) {
     const { actor, token } = getActiveActorAndToken();
     if (!actor) {
         return notifications.warn(getGame().i18n.localize("DS4.WarningMustControlActorToUseRollItemMacro"));
diff --git a/src/migration/001.ts b/src/migration/001.js
similarity index 80%
rename from src/migration/001.ts
rename to src/migration/001.js
index c01252fa..55b5004e 100644
--- a/src/migration/001.ts
+++ b/src/migration/001.js
@@ -10,13 +10,15 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getActorUpdateData(): Record<string, unknown> {
+/** @type {import("./migrationHelpers").ActorUpdateDataGetter} */
+function getActorUpdateData() {
     const updateData = {
         data: {
             combatValues: [
@@ -28,7 +30,7 @@ function getActorUpdateData(): Record<string, unknown> {
                 "rangedAttack",
                 "spellcasting",
                 "targetedSpellcasting",
-            ].reduce((acc: Partial<Record<string, { "-=base": null }>>, curr) => {
+            ].reduce((acc, curr) => {
                 acc[curr] = { "-=base": null };
                 return acc;
             }, {}),
@@ -40,6 +42,7 @@ function getActorUpdateData(): Record<string, unknown> {
 const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
 const migrateCompendium = getCompendiumMigrator({ getActorUpdateData, getSceneUpdateData });
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/002.ts b/src/migration/002.js
similarity index 74%
rename from src/migration/002.ts
rename to src/migration/002.js
index 0c1ccb53..17d9fe90 100644
--- a/src/migration/002.ts
+++ b/src/migration/002.js
@@ -12,18 +12,18 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(
-    itemData: Partial<foundry.data.ItemData["_source"]>,
-): DeepPartial<foundry.data.ItemData["_source"]> | undefined {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (!["equipment", "trinket"].includes(itemData.type ?? "")) return undefined;
-    return { type: itemData.type === "equipment" ? ("loot" as const) : ("equipment" as const) };
+    return { type: itemData.type === "equipment" ? "loot" : "equipment" };
 }
 
 const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
@@ -33,6 +33,7 @@ const migrateCompendium = getCompendiumMigrator(
     { migrateToTemplateEarly: false },
 );
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/003.ts b/src/migration/003.js
similarity index 80%
rename from src/migration/003.ts
rename to src/migration/003.js
index a2870ad5..f18da278 100644
--- a/src/migration/003.ts
+++ b/src/migration/003.js
@@ -12,14 +12,16 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (!["loot"].includes(itemData.type ?? "")) return undefined;
     return {
         data: {
@@ -35,6 +37,7 @@ const migrateCompendium = getCompendiumMigrator(
     { migrateToTemplateEarly: false },
 );
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/004.ts b/src/migration/004.js
similarity index 74%
rename from src/migration/004.ts
rename to src/migration/004.js
index e0483376..435b1c97 100644
--- a/src/migration/004.ts
+++ b/src/migration/004.js
@@ -12,19 +12,20 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (itemData.type !== "spell") return;
-    // @ts-expect-error the type of cooldownDuration was UnitData<TemporalUnit> at the point for this migration, but it changed later on
-    const cooldownDurationUnit: string | undefined = itemData.data?.cooldownDuration.unit;
+    const cooldownDurationUnit = itemData.data?.cooldownDuration.unit;
 
-    const updateData: Record<string, unknown> = {
+    const updateData = {
         data: {
             "-=scrollPrice": null,
             minimumLevels: { healer: null, wizard: null, sorcerer: null },
@@ -40,6 +41,7 @@ const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
 const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
 const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/005.ts b/src/migration/005.js
similarity index 81%
rename from src/migration/005.ts
rename to src/migration/005.js
index 16919ce6..528f2463 100644
--- a/src/migration/005.ts
+++ b/src/migration/005.js
@@ -21,22 +21,22 @@ const hoursPerDay = 24;
 const roundsPerDay = hoursPerDay / roundsPerHour;
 const secondsPerDay = secondsPerMinute * minutesPerHour * hoursPerDay;
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (itemData.type !== "spell") return;
-    // @ts-expect-error the type of cooldownDuration is changed from UnitData<TemporalUnit> to CooldownDuation with this migration
-    const cooldownDurationUnit: string | undefined = itemData.data?.cooldownDuration.unit;
-    // @ts-expect-error the type of cooldownDuration is changed from UnitData<TemporalUnit> to CooldownDuation with this migration
-    const cooldownDurationValue: string | undefined = itemData.data?.cooldownDuration.value;
+    const cooldownDurationUnit = itemData.data?.cooldownDuration.unit;
+    const cooldownDurationValue = itemData.data?.cooldownDuration.value;
     const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit);
 
-    const updateData: Record<string, unknown> = {
+    const updateData = {
         data: {
             cooldownDuration,
         },
@@ -88,7 +88,13 @@ function migrateCooldownDuration(cooldownDurationValue = "", cooldownDurationUni
     }
 }
 
-function getRounds(unit: string, value: number): number {
+/**
+ * Given a unit and a value, return the correct number of rounds
+ * @param {string} unit     The unit
+ * @param {number} value    The value
+ * @returns {number} The number of rounds
+ */
+function getRounds(unit, value) {
     switch (unit) {
         case "rounds": {
             return value;
@@ -112,6 +118,7 @@ const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
 const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
 const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/006.ts b/src/migration/006.js
similarity index 71%
rename from src/migration/006.ts
rename to src/migration/006.js
index 6ce4a9c0..8d87892f 100644
--- a/src/migration/006.ts
+++ b/src/migration/006.js
@@ -12,26 +12,25 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-import type { DS4SpellDataSourceData } from "../documents/item/spell/spell-data-source";
-
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (itemData.type !== "spell") return;
-    // @ts-expect-error spellCategory is removed with this migration
-    const spellCategory: string | undefined = itemData.data?.spellCategory;
+    const spellCategory = itemData.data?.spellCategory;
     const spellGroups = migrateSpellCategory(spellCategory);
 
     // @ts-expect-error bonus is removed with this migration
-    const bonus: string | undefined = itemData.data?.bonus;
+    const bonus = itemData.data?.bonus;
     const spellModifier = migrateBonus(bonus);
 
-    const updateData: Record<string, unknown> = {
+    const updateData = {
         data: {
             spellGroups,
             "-=spellCategory": null,
@@ -42,7 +41,12 @@ function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>)
     return updateData;
 }
 
-function migrateSpellCategory(spellCategory: string | undefined): DS4SpellDataSourceData["spellGroups"] {
+/**
+ * Migrate a spell category to spell groups.
+ * @param {string | undefined} spellCategory                                                            The spell category
+ * @returns {import("../documents/item/spell/spell-data-source").DS4SpellDataSourceData["spellGroups"]} The spell groups for the given category
+ */
+function migrateSpellCategory(spellCategory) {
     const spellGroups = {
         lightning: false,
         earth: false,
@@ -95,7 +99,12 @@ function migrateSpellCategory(spellCategory: string | undefined): DS4SpellDataSo
     return spellGroups;
 }
 
-function migrateBonus(bonus: string | undefined): DS4SpellDataSourceData["spellModifier"] {
+/**
+ * Migrate a spell bonus to a spell modifier.
+ * @param {string | undefined} bonus                                                                        The spell bonus
+ * @returns {import("../documents/item/spell/spell-data-source").DS4SpellDataSourceData["spellModifier"]}   The spell modifier
+ */
+function migrateBonus(bonus) {
     const spellModifier = { numerical: 0, complex: "" };
     if (bonus) {
         if (Number.isNumeric(bonus)) {
@@ -111,6 +120,7 @@ const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
 const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
 const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/007.ts b/src/migration/007.js
similarity index 79%
rename from src/migration/007.ts
rename to src/migration/007.js
index 4ff6a2ea..d06d65b9 100644
--- a/src/migration/007.ts
+++ b/src/migration/007.js
@@ -12,14 +12,16 @@ import {
     migrateScenes,
 } from "./migrationHelpers";
 
-async function migrate(): Promise<void> {
+/** @type {import("./migration").Migration["migrate"]} */
+async function migrate() {
     await migrateItems(getItemUpdateData);
     await migrateActors(getActorUpdateData);
     await migrateScenes(getSceneUpdateData);
     await migrateCompendiums(migrateCompendium);
 }
 
-function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
+/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
+function getItemUpdateData(itemData) {
     if (itemData.type !== "spell") return;
 
     return {
@@ -33,6 +35,7 @@ const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
 const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
 const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
 
+/** @type {import("./migration").Migration} */
 export const migration = {
     migrate,
     migrateCompendium,
diff --git a/src/migration/migration.ts b/src/migration/migration.js
similarity index 71%
rename from src/migration/migration.ts
rename to src/migration/migration.js
index b110ac86..2841cbd8 100644
--- a/src/migration/migration.ts
+++ b/src/migration/migration.js
@@ -13,7 +13,11 @@ import { migration as migration005 } from "./005";
 import { migration as migration006 } from "./006";
 import { migration as migration007 } from "./007";
 
-async function migrate(): Promise<void> {
+/**
+ * Perform migrations.
+ * @returns {Promise<void>} A promise that resolves once all migrations have completed
+ */
+async function migrate() {
     if (!getGame().user?.isGM) {
         return;
     }
@@ -30,7 +34,13 @@ async function migrate(): Promise<void> {
     return migrateFromTo(oldMigrationVersion, targetMigrationVersion);
 }
 
-async function migrateFromTo(oldMigrationVersion: number, targetMigrationVersion: number): Promise<void> {
+/**
+ * Migrate from a given version to another version.
+ * @param {number} oldMigrationVersion The old migration version
+ * @param {number} targetMigrationVersion The migration version to migrate to
+ * @returns {Promise<void>} A promise the resolves once the migration is complete
+ */
+async function migrateFromTo(oldMigrationVersion, targetMigrationVersion) {
     if (!getGame().user?.isGM) {
         return;
     }
@@ -76,11 +86,14 @@ async function migrateFromTo(oldMigrationVersion: number, targetMigrationVersion
     }
 }
 
-async function migrateCompendiumFromTo(
-    pack: CompendiumCollection<CompendiumCollection.Metadata>,
-    oldMigrationVersion: number,
-    targetMigrationVersion: number,
-): Promise<void> {
+/**
+ * Migrate a compendium pack from a given version to another version.
+ * @param {CompendiumCollection} pack The compendium pack to migrate
+ * @param {number} oldMigrationVersion The old version number
+ * @param {number} targetMigrationVersion The target version number
+ * @returns {Promise<void>} A promise that resolves once the migration is complete
+ */
+async function migrateCompendiumFromTo(pack, oldMigrationVersion, targetMigrationVersion) {
     if (!getGame().user?.isGM) {
         return;
     }
@@ -128,30 +141,39 @@ async function migrateCompendiumFromTo(
     }
 }
 
-function getCurrentMigrationVersion(): number {
+/**
+ * Get the current migration version.
+ * @returns {number} The current migration version
+ */
+function getCurrentMigrationVersion() {
     return getGame().settings.get("ds4", "systemMigrationVersion");
 }
 
-function getTargetMigrationVersion(): number {
+/**
+ * Get the target migration version.
+ * @returns {number} The target migration version
+ */
+function getTargetMigrationVersion() {
     return migrations.length;
 }
 
-interface Migration {
-    migrate: () => Promise<void>;
-    migrateCompendium: (pack: CompendiumCollection<CompendiumCollection.Metadata>) => Promise<void>;
-}
+/**
+ * @typedef {object} Migration
+ * @property {() => Promise<void>} migrate
+ * @property {import("./migrationHelpers").CompendiumMigrator} migrateCompendium
+ */
 
-const migrations: Migration[] = [
-    migration001,
-    migration002,
-    migration003,
-    migration004,
-    migration005,
-    migration006,
-    migration007,
-];
+/**
+ * @type {Migration[]}
+ */
+const migrations = [migration001, migration002, migration003, migration004, migration005, migration006, migration007];
 
-function isFirstWorldStart(migrationVersion: number): boolean {
+/**
+ * DOes the migration version indicate the world is being started for the first time?
+ * @param {number} migrationVersion A migration version
+ * @returns {boolean} Whether the migration version indicates it is the first start of the world
+ */
+function isFirstWorldStart(migrationVersion) {
     return migrationVersion < 0;
 }
 
diff --git a/src/migration/migrationHelpers.ts b/src/migration/migrationHelpers.js
similarity index 56%
rename from src/migration/migrationHelpers.ts
rename to src/migration/migrationHelpers.js
index 1e25b6f0..3c8193d5 100644
--- a/src/migration/migrationHelpers.ts
+++ b/src/migration/migrationHelpers.js
@@ -7,11 +7,14 @@ import { DS4Item } from "../documents/item/item";
 import { logger } from "../utils/logger";
 import { getGame } from "../utils/utils";
 
-type ItemUpdateDataGetter = (
-    itemData: Partial<foundry.data.ItemData["_source"]>,
-) => DeepPartial<foundry.data.ItemData["_source"]> | Record<string, unknown> | undefined;
+/** @typedef {(itemData: Partial<foundry.data.ItemData["_source"]>) => DeepPartial<foundry.data.ItemData["_source"]> | Record<string, unknown> | undefined} ItemUpdateDataGetter */
 
-export async function migrateItems(getItemUpdateData: ItemUpdateDataGetter): Promise<void> {
+/**
+ * Migrate world items.
+ * @param {ItemUpdateDataGetter} getItemUpdateData  A function for getting the update data for a given item data object
+ * @returns {Promise<void>} A promise that resolves once the migration is complete
+ */
+export async function migrateItems(getItemUpdateData) {
     for (const item of getGame().items ?? []) {
         try {
             const updateData = getItemUpdateData(item.toObject());
@@ -25,11 +28,14 @@ export async function migrateItems(getItemUpdateData: ItemUpdateDataGetter): Pro
     }
 }
 
-type ActorUpdateDataGetter = (
-    itemData: Partial<foundry.data.ActorData["_source"]>,
-) => DeepPartial<foundry.data.ActorData["_source"]> | undefined;
+/** @typedef {(actorData: Partial<foundry.data.ActorData["_source"]>) => DeepPartial<foundry.data.ActorData["_source"]> | undefined} ActorUpdateDataGetter */
 
-export async function migrateActors(getActorUpdateData: ActorUpdateDataGetter): Promise<void> {
+/**
+ * Migrate world actors.
+ * @param {ActorUpdateDataGetter} getActorUpdateData    A function for getting the update data for a given actor data object
+ * @returns {Promise<void>} A promise that resolves once the migration is complete
+ */
+export async function migrateActors(getActorUpdateData) {
     for (const actor of getGame().actors ?? []) {
         try {
             const updateData = getActorUpdateData(actor.toObject());
@@ -46,17 +52,20 @@ export async function migrateActors(getActorUpdateData: ActorUpdateDataGetter):
     }
 }
 
-type SceneUpdateDataGetter = (sceneData: foundry.data.SceneData) => DeepPartial<foundry.data.SceneData["_source"]>;
+/** @typedef {(aceneData: foundry.data.SceneData) => DeepPartial<foundry.data.SceneData["_source"]> | undefined} SceneUpdateDataGetter */
 
-export async function migrateScenes(getSceneUpdateData: SceneUpdateDataGetter): Promise<void> {
+/**
+ * Migrate world scenes.
+ * @param {SceneUpdateDataGetter} getSceneUpdateData    A function for getting the update data for a given scene data object
+ * @returns {Promise<void>} A promise that resolves once the migration is complete
+ */
+export async function migrateScenes(getSceneUpdateData) {
     for (const scene of getGame().scenes ?? []) {
         try {
             const updateData = getSceneUpdateData(scene.data);
             if (updateData) {
                 logger.info(`Migrating Scene document ${scene.name} (${scene.id})`);
-                await scene.update(
-                    updateData as DeepPartial<Parameters<foundry.data.SceneData["_initializeSource"]>[0]>,
-                );
+                await scene.update(updateData);
             }
         } catch (err) {
             logger.error(
@@ -67,9 +76,14 @@ export async function migrateScenes(getSceneUpdateData: SceneUpdateDataGetter):
     }
 }
 
-type CompendiumMigrator = (compendium: CompendiumCollection<CompendiumCollection.Metadata>) => Promise<void>;
+/** @typedef {(pack: CompendiumCollection) => Promise<void>} CompendiumMigrator*/
 
-export async function migrateCompendiums(migrateCompendium: CompendiumMigrator): Promise<void> {
+/**
+ * Migrate world compendium packs.
+ * @param {CompendiumMigrator} migrateCompendium A function for migrating a single compendium pack
+ * @returns {Promise<void>} A promise that resolves once the migration is complete
+ */
+export async function migrateCompendiums(migrateCompendium) {
     for (const compendium of getGame().packs ?? []) {
         if (compendium.metadata.package !== "world") continue;
         if (!["Actor", "Item", "Scene"].includes(compendium.metadata.type)) continue;
@@ -77,10 +91,13 @@ export async function migrateCompendiums(migrateCompendium: CompendiumMigrator):
     }
 }
 
-export function getActorUpdateDataGetter(getItemUpdateData: ItemUpdateDataGetter): ActorUpdateDataGetter {
-    return (
-        actorData: Partial<foundry.data.ActorData["_source"]>,
-    ): DeepPartial<foundry.data.ActorData["_source"]> | undefined => {
+/**
+ * Get a function to create actor update data that adjusts the owned items of the actor according to the given function.
+ * @param {ItemUpdateDataGetter} getItemUpdateData  The function to generate item update data
+ * @returns {ActorUpdateDataGetter} A function to get actor update data
+ */
+export function getActorUpdateDataGetter(getItemUpdateData) {
+    return (actorData) => {
         let hasItemUpdates = false;
         const items = actorData.items?.map((itemData) => {
             const update = getItemUpdateData(itemData);
@@ -95,9 +112,14 @@ export function getActorUpdateDataGetter(getItemUpdateData: ItemUpdateDataGetter
     };
 }
 
-export function getSceneUpdateDataGetter(getActorUpdateData: ActorUpdateDataGetter): SceneUpdateDataGetter {
-    return (sceneData: foundry.data.SceneData) => {
-        const tokens = sceneData.tokens.map((token: TokenDocument) => {
+/**
+ * Get a function to create scene update data that adjusts the actors of the tokens of the scene according to the given function.
+ * @param {ActorUpdateDataGetter} getItemUpdateData  The function to generate actor update data
+ * @returns {SceneUpdateDataGetter} A function to get scene update data
+ */
+export function getSceneUpdateDataGetter(getActorUpdateData) {
+    return (sceneData) => {
+        const tokens = sceneData.tokens.map((token) => {
             const t = token.toObject();
             if (!t.actorId || t.actorLink) {
                 t.actorData = {};
@@ -109,7 +131,7 @@ export function getSceneUpdateDataGetter(getActorUpdateData: ActorUpdateDataGett
                 actorData.type = token.actor?.type;
                 const update = getActorUpdateData(actorData);
                 if (update !== undefined) {
-                    ["items" as const, "effects" as const].forEach((embeddedName) => {
+                    ["items", "effects"].forEach((embeddedName) => {
                         const embeddedUpdates = update[embeddedName];
                         if (embeddedUpdates === undefined || !embeddedUpdates.length) return;
                         const updates = new Map(embeddedUpdates.flatMap((u) => (u && u._id ? [[u._id, u]] : [])));
@@ -131,32 +153,37 @@ export function getSceneUpdateDataGetter(getActorUpdateData: ActorUpdateDataGett
     };
 }
 
+/**
+ * @typedef {object} UpdateDataGetters
+ * @property {ItemUpdateDataGetter}     [getItemUpdateData]
+ * @property {ActorUpdateDataGetter}    [getActorUpdateData]
+ * @property {SceneUpdateDataGetter}    [getSceneUpdateData]
+ */
+
+/**
+ * Get a compendium migrator for the given update data getters.
+ * @param {UpdateDataGetters} [updateDataGetters={}]        The functions to use for getting update data
+ * @param {{migrateToTemplateEarly?: boolean}} [options={}] Additional options for the compendium migrator
+ * @returns {CompendiumMigrator} The resulting compendium migrator
+ */
 export function getCompendiumMigrator(
-    {
-        getItemUpdateData,
-        getActorUpdateData,
-        getSceneUpdateData,
-    }: {
-        getItemUpdateData?: ItemUpdateDataGetter;
-        getActorUpdateData?: ActorUpdateDataGetter;
-        getSceneUpdateData?: SceneUpdateDataGetter;
-    } = {},
+    { getItemUpdateData, getActorUpdateData, getSceneUpdateData } = {},
     { migrateToTemplateEarly = true } = {},
 ) {
-    return async (compendium: CompendiumCollection<CompendiumCollection.Metadata>): Promise<void> => {
-        const type = compendium.metadata.type;
+    return async (pack) => {
+        const type = pack.metadata.type;
         if (!["Actor", "Item", "Scene"].includes(type)) return;
-        const wasLocked = compendium.locked;
-        await compendium.configure({ locked: false });
+        const wasLocked = pack.locked;
+        await pack.configure({ locked: false });
         if (migrateToTemplateEarly) {
-            await compendium.migrate();
+            await pack.migrate();
         }
 
-        const documents = await compendium.getDocuments();
+        const documents = await pack.getDocuments();
 
         for (const doc of documents) {
             try {
-                logger.info(`Migrating document ${doc.name} (${doc.id}) in compendium ${compendium.collection}`);
+                logger.info(`Migrating document ${doc.name} (${doc.id}) in compendium ${pack.collection}`);
                 if (doc instanceof DS4Item && getItemUpdateData) {
                     const updateData = getItemUpdateData(doc.toObject());
                     updateData && (await doc.update(updateData));
@@ -164,23 +191,20 @@ export function getCompendiumMigrator(
                     const updateData = getActorUpdateData(doc.toObject());
                     updateData && (await doc.update(updateData));
                 } else if (doc instanceof Scene && getSceneUpdateData) {
-                    const updateData = getSceneUpdateData(doc.data as foundry.data.SceneData);
-                    updateData &&
-                        (await doc.update(
-                            updateData as DeepPartial<Parameters<foundry.data.SceneData["_initializeSource"]>[0]>,
-                        ));
+                    const updateData = getSceneUpdateData(doc.data);
+                    updateData && (await doc.update(updateData));
                 }
             } catch (err) {
                 logger.error(
-                    `Error during migration of document ${doc.name} (${doc.id}) in compendium ${compendium.collection}, continuing anyways.`,
+                    `Error during migration of document ${doc.name} (${doc.id}) in compendium ${pack.collection}, continuing anyways.`,
                     err,
                 );
             }
         }
 
         if (!migrateToTemplateEarly) {
-            await compendium.migrate();
+            await pack.migrate();
         }
-        await compendium.configure({ locked: wasLocked });
+        await pack.configure({ locked: wasLocked });
     };
 }
diff --git a/src/settings.ts b/src/settings.js
similarity index 75%
rename from src/settings.ts
rename to src/settings.js
index 516d34f6..a7798c71 100644
--- a/src/settings.ts
+++ b/src/settings.js
@@ -4,11 +4,11 @@
 
 import { getGame } from "./utils/utils";
 
-export function registerSystemSettings(): void {
+export function registerSystemSettings() {
     const game = getGame();
 
     /**
-     * Track the migrations version of the latest migration that has been applied
+     * Track the migration version of the latest migration that has been applied.
      */
     game.settings.register("ds4", "systemMigrationVersion", {
         name: "System Migration Version",
@@ -37,13 +37,18 @@ export function registerSystemSettings(): void {
     });
 }
 
-export interface DS4Settings {
-    systemMigrationVersion: number;
-    useSlayingDiceForAutomatedChecks: boolean;
-    showSlayerPoints: boolean;
-}
+/**
+ * @typedef DS4Settings
+ * @property {number} systemMigrationVersion
+ * @property {boolean} useSlayingDiceForAutomatedChecks
+ * @property {boolean} showSlayerPoints
+ */
 
-export function getDS4Settings(): DS4Settings {
+/**
+ * Get the current values for DS4 settings.
+ * @returns {DS4Settings}
+ */
+export function getDS4Settings() {
     const game = getGame();
     return {
         systemMigrationVersion: game.settings.get("ds4", "systemMigrationVersion"),
diff --git a/src/ui/notifications.js b/src/ui/notifications.js
new file mode 100644
index 00000000..fd5a55f7
--- /dev/null
+++ b/src/ui/notifications.js
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: 2021 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { logger } from "../utils/logger";
+import { getNotificationsSafe } from "../utils/utils";
+
+/**
+ * @typedef {Object} NotificationOptions
+ * @property {boolean} [permanent=false]
+ * @property {boolean} [log=false]
+ */
+
+/**
+ * @typedef {(message: string, options?: NotificationOptions) => void} NotificationFunction
+ */
+
+/**
+ * @typedef {"info" | "warn" | "error"} NotificationType
+ */
+
+/**
+ * @param {NotificationType} type The type of the notification
+ * @returns {NotificationFunction}
+ */
+function getNotificationFunction(type) {
+    return (message, { permanent = false, log = false } = {}) => {
+        if (ui.notifications) {
+            ui.notifications[type](message, { permanent });
+            if (log) {
+                logger[type](message);
+            }
+        } else {
+            logger[type](message);
+        }
+    };
+}
+
+/**
+ * @param {string} message
+ * @param {NotificationType} type
+ * @param {NotificationOptions} [options={}]
+ */
+function notify(message, type, { permanent = false, log = false } = {}) {
+    const notifications = getNotificationsSafe();
+    if (notifications) {
+        notifications.notify(message, type, { permanent });
+        if (log) {
+            logger.getLoggingFunction(type)(message);
+        }
+    } else {
+        logger.getLoggingFunction(type)(message);
+    }
+}
+
+export const notifications = Object.freeze({
+    info: getNotificationFunction("info"),
+    warn: getNotificationFunction("warn"),
+    error: getNotificationFunction("error"),
+    notify,
+});
diff --git a/src/ui/notifications.ts b/src/ui/notifications.ts
deleted file mode 100644
index 7e830beb..00000000
--- a/src/ui/notifications.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Johannes Loher
-//
-// SPDX-License-Identifier: MIT
-
-import { logger } from "../utils/logger";
-
-function getNotificationFunction(type: "info" | "warn" | "error") {
-    return (message: string, { permanent = false, log = false }: { permanent?: boolean; log?: boolean } = {}): void => {
-        if (ui.notifications) {
-            ui.notifications[type](message, { permanent });
-            if (log) {
-                logger[type](message);
-            }
-        } else {
-            logger[type](message);
-        }
-    };
-}
-
-export const notifications = Object.freeze({
-    info: getNotificationFunction("info"),
-    warn: getNotificationFunction("warn"),
-    error: getNotificationFunction("error"),
-    notify: (
-        message: string,
-        type: "info" | "warning" | "error" = "info",
-        { permanent = false, log = false }: { permanent?: boolean; log?: boolean } = {},
-    ): void => {
-        if (ui.notifications) {
-            ui.notifications.notify(message, type, { permanent });
-            if (log) {
-                logger.getLoggingFunction(type)(message);
-            }
-        } else {
-            logger.getLoggingFunction(type)(message);
-        }
-    },
-});
diff --git a/src/utils/utils.js b/src/utils/utils.js
new file mode 100644
index 00000000..dcb8cdf4
--- /dev/null
+++ b/src/utils/utils.js
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: 2021 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+/**
+ * Tests if the given `value` is truthy.
+ *
+ * If it is not truthy, an {@link Error} is thrown, which depends on the given `message` parameter:
+ * - If `message` is a string`, it is used to construct a new {@link Error} which then is thrown.
+ * - If `message` is an instance of {@link Error}, it is thrown.
+ * - If `message` is `undefined`, an {@link Error} with a default message is thrown.
+ * @param {unknown} value   The value to check for truthyness
+ * @param {string | Error} [message] An error message to use when the check fails
+ * @returns {asserts value}
+ */
+export function enforce(value, message) {
+    if (!value) {
+        if (!message) {
+            message =
+                getGameSafe()?.i18n.localize("DS4.ErrorUnexpectedError") ??
+                "There was an unexpected error in the Dungeonslayers 4 system. For more details, please take a look at the console (F12).";
+        }
+        throw message instanceof Error ? message : new Error(message);
+    }
+}
+
+/**
+ * A wrapper that returns the canvas, if it is ready.
+ * @throws if the canvas is not ready yet
+ * @returns {Canvas}
+ */
+export function getCanvas() {
+    enforce(canvas instanceof Canvas && canvas.ready, getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized"));
+    return canvas;
+}
+
+/**
+ * A wrapper that returns the game, if it already exists.
+ * @throws {Error} if the game is not ready yet
+ * @returns {Game}
+ */
+export function getGame() {
+    enforce(game instanceof Game, "Game is not initialized yet.");
+    return game;
+}
+
+/**
+ * A wrapper that returns the game, or `undefined` if it doesn't exist yet
+ * @returns {Game | undefined}
+ */
+export function getGameSafe() {
+    return game instanceof Game ? game : undefined;
+}
+
+/**
+ * A wrapper that returns `ui.notifications`, or `undefined` if it doesn't exist yet
+ * @returns {Notifications | undefined}
+ */
+export function getNotificationsSafe() {
+    return ui.notifications instanceof Notifications ? ui.notifications : undefined;
+}
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
deleted file mode 100644
index 44cce905..00000000
--- a/src/utils/utils.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Johannes Loher
-//
-// SPDX-License-Identifier: MIT
-
-/**
- * Tests if the given `value` is truthy.
- *
- * If it is not truthy, an {@link Error} is thrown, which depends on the given `message` parameter:
- * - If `message` is a string`, it is used to construct a new {@link Error} which then is thrown.
- * - If `message` is an instance of {@link Error}, it is thrown.
- * - If `message` is `undefined`, an {@link Error} with a default message is thrown.
- */
-export function enforce(value: unknown, message?: string | Error): asserts value {
-    if (!value) {
-        if (!message) {
-            message =
-                getGameSafe()?.i18n.localize("DS4.ErrorUnexpectedError") ??
-                "There was an unexpected error in the Dungeonslayers 4 system. For more details, please take a look at the console (F12).";
-        }
-        throw message instanceof Error ? message : new Error(message);
-    }
-}
-
-export function getCanvas(): Canvas {
-    if (!(canvas instanceof Canvas) || !canvas.ready) {
-        throw new Error(getGame().i18n.localize("DS4.ErrorCanvasIsNotInitialized"));
-    }
-    return canvas;
-}
-
-export function getGame(): Game {
-    if (!(game instanceof Game)) {
-        throw new Error("Game is not initialized yet.");
-    }
-    return game;
-}
-
-export function getGameSafe(): Game | undefined {
-    return game instanceof Game ? game : undefined;
-}
diff --git a/system.json b/system.json
index b8284abe..8cec60c0 100644
--- a/system.json
+++ b/system.json
@@ -36,12 +36,8 @@
     "version": "1.18.2",
     "minimumCoreVersion": "9.238",
     "compatibleCoreVersion": "9",
-    "esmodules": [
-        "ds4.js"
-    ],
-    "styles": [
-        "css/ds4.css"
-    ],
+    "esmodules": ["ds4.js"],
+    "styles": ["css/ds4.css"],
     "languages": [
         {
             "lang": "en",
diff --git a/tsconfig.json b/tsconfig.json
index cfb0eda8..e1c0203f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,8 +1,9 @@
 {
     "compilerOptions": {
+        "outDir": "dist",
         "target": "ES2021",
         "lib": ["ES2021", "DOM"],
-        "types": ["@league-of-foundry-developers/foundry-vtt-types"],
+        "types": ["@types/jquery", "handlebars"],
         "esModuleInterop": true,
         "moduleResolution": "node",
         "forceConsistentCasingInFileNames": true,
@@ -10,7 +11,9 @@
         "noUncheckedIndexedAccess": true,
         "noImplicitOverride": true,
         "resolveJsonModule": true,
-        "importsNotUsedAsValues": "error"
+        "importsNotUsedAsValues": "error",
+        "checkJs": false,
+        "allowJs": true
     },
-    "include": ["src"]
+    "include": ["src", "client", "common"]
 }
diff --git a/yarn.lock b/yarn.lock
index 13dbaeac..34cf353e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -356,22 +356,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@league-of-foundry-developers/foundry-vtt-types@npm:9.280.0":
-  version: 9.280.0
-  resolution: "@league-of-foundry-developers/foundry-vtt-types@npm:9.280.0"
-  dependencies:
-    "@pixi/graphics-smooth": 0.0.22
-    "@types/jquery": ~3.5.9
-    "@types/simple-peer": ~9.11.1
-    handlebars: 4.7.7
-    pixi-particles: 4.3.1
-    pixi.js: 5.3.11
-    socket.io-client: 4.3.2
-    tinymce: 5.10.1
-  checksum: 18fd05ff3fbdd849842f207e043e1924384bcd82ab65546067aa9b50d717e43dc4626822c8b96749cd687c2138cd7a7b39ac0b5fd453228876cbfa2f660f88f3
-  languageName: node
-  linkType: hard
-
 "@nodelib/fs.scandir@npm:2.1.5":
   version: 2.1.5
   resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -419,503 +403,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@pixi/accessibility@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/accessibility@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: e64407bd08d472ccee9896aac21768cf5bad6fe52b75af4e7758168a153bd767c0e3e9959e646c86901acae77e9dfe4c05059075b5841000b7a2de50dd2d7083
-  languageName: node
-  linkType: hard
-
-"@pixi/app@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/app@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-  checksum: c4fce95715380fe8fcea99c92e1f0a2e98a172b3e6ac691d658b31d5a950bafd23753e982106e8be08c5db4b7872df156ea779f47f15b7fb2afdbef40dc3fa56
-  languageName: node
-  linkType: hard
-
-"@pixi/constants@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/constants@npm:5.3.11"
-  checksum: ed23c735858a3a506ece0bea1afb3fac2ba261cb9722f17b15e9a4dcc8f70f3906a7cb90c94c255e7e7ece62d3447e68462975c3a30d2cb908f3632b4f97a891
-  languageName: node
-  linkType: hard
-
-"@pixi/constants@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/constants@npm:6.2.1"
-  checksum: 16ce671884932afec41258891f301b9b725a4ae6285a39940b83ebd026a0dd077c78962b7f75eb6afba14a38de2420b0cfeaeae7986bbea4991506a4a83076b7
-  languageName: node
-  linkType: hard
-
-"@pixi/core@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/core@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/runner": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/ticker": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 865f26fa07397f67c0b418b7844576adff49aea47e4548b6122541c92da15744d128c681eb0c11c584906ba269485f816a8c0e0a4d6cb5521a2a488dfe4cfb40
-  languageName: node
-  linkType: hard
-
-"@pixi/core@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/core@npm:6.2.1"
-  peerDependencies:
-    "@pixi/constants": 6.2.1
-    "@pixi/math": 6.2.1
-    "@pixi/runner": 6.2.1
-    "@pixi/settings": 6.2.1
-    "@pixi/ticker": 6.2.1
-    "@pixi/utils": 6.2.1
-  checksum: 946b39bd4a1e1414e2f6d60f9df1d56625312f482cf5a095ddb276554a351ebb0ebb8a0e98c7f98100eedecef89d1579b02e79b77626f1fe47e619aaffc3d469
-  languageName: node
-  linkType: hard
-
-"@pixi/display@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/display@npm:5.3.11"
-  dependencies:
-    "@pixi/math": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 83db7f10fe610104bca5b71031abe3dfdd8946fd4e1a3957f2f9c1ca61ebbd3b7ab04915e9ced78997b88817063da42ae7c5aea527ad70959eb320966f70f92b
-  languageName: node
-  linkType: hard
-
-"@pixi/display@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/display@npm:6.2.1"
-  peerDependencies:
-    "@pixi/math": 6.2.1
-    "@pixi/settings": 6.2.1
-    "@pixi/utils": 6.2.1
-  checksum: b72d4f16fd4c27e03d34c5cd8490cbd2c5d507584cef3abbab329fc1575ed5bcc53e104fb063c35fb6e85a6f8e16e1c114f1ff599ad43b7d1e4797fd644639fe
-  languageName: node
-  linkType: hard
-
-"@pixi/extract@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/extract@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 15d68bed15e29c4d49f39bc33c9097b05eeb7b374a6a1f54177eaf0079e9882e4d96e3cbf61951ab6474b458fcdc36010de776ef7eeaaf9505464bfff89498e4
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-alpha@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-alpha@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-  checksum: c5348cc46125f443effd41ed46ccd8312b8a797fad5898ca3460d1c2f2146287881f8b18d1953b444cca6969ad1cbf60792c9d84434cc396e147bcc57f7a9d01
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-blur@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-blur@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/settings": 5.3.11
-  checksum: ff28b39f63c63cc9cb16d566ffb1543272830f3f566b677da22f47ad211ad594359fb07504280d80f9a7bfd1818409cf3cd9563c689057731d7e0fd105a3f988
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-color-matrix@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-color-matrix@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-  checksum: 5f76a7de0f9935fa16cbb66a18b430fa73a71d787f55334c2ba538bc58b11339ee0bfed0ccbe53c7693d6110fad5e88cb569af973849328b307e5314717130e7
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-displacement@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-displacement@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/math": 5.3.11
-  checksum: 03436312e1dd860accd6c801feea8d0a868e5b90de8c49edc28d40cf71ba4da293b4c027d0a71897c9aec884db132cb4c7d22fd18a05da5248e4ab35fccd0df9
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-fxaa@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-fxaa@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-  checksum: 02a16119e4796e9d1bf01768358cc244c24d71d22e229b5eec9b31968771a07d0fdf11196de7b59d34b9c075245d16b3c794b0eb02fc7e5e27b22e703ea0ed27
-  languageName: node
-  linkType: hard
-
-"@pixi/filter-noise@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/filter-noise@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-  checksum: 7d27c5af18a096418ced42f9f668577db39e4b30c7fad540d7ba31fd8a59c16d8926680ff6c3523c3e4b2a9fc4a7b46694dc0d547863cdf2763b28dac4c06455
-  languageName: node
-  linkType: hard
-
-"@pixi/graphics-smooth@npm:0.0.22":
-  version: 0.0.22
-  resolution: "@pixi/graphics-smooth@npm:0.0.22"
-  peerDependencies:
-    "@pixi/constants": ^6.0.4
-    "@pixi/core": ^6.0.4
-    "@pixi/display": ^6.0.4
-    "@pixi/graphics": ^6.0.4
-    "@pixi/math": ^6.0.4
-    "@pixi/utils": ^6.0.4
-  checksum: 81dea3626180b4c7997b20ba6611d41e7a79d6278f71f65867e440d73577e13569c574a31623f5732d08d60beef867eb99f4ca79e34ca8ffb6755fe00a4d8508
-  languageName: node
-  linkType: hard
-
-"@pixi/graphics@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/graphics@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 31014dd5b9b05dd6d048a6a74c261f5e368b0e558aceaf21a90df38b321495b75f5caf2fe7e148fbad25b5db2998a76c66f816a4247d4e8d6c222a8b740b14b4
-  languageName: node
-  linkType: hard
-
-"@pixi/graphics@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/graphics@npm:6.2.1"
-  peerDependencies:
-    "@pixi/constants": 6.2.1
-    "@pixi/core": 6.2.1
-    "@pixi/display": 6.2.1
-    "@pixi/math": 6.2.1
-    "@pixi/sprite": 6.2.1
-    "@pixi/utils": 6.2.1
-  checksum: 08681899d3177784126bb91b4e0c7966ad92e28d90f626c7c9c4a1973f4dc70cf43a9843d49133431db60ea9fbea4cfa86afab8391a57612a3bdee164aedcc31
-  languageName: node
-  linkType: hard
-
-"@pixi/interaction@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/interaction@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/ticker": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 2dc86690b85a614d062fe33dd1607ecb920e491bbb8822e28afef48ff745de1aa796b144225f887f6c391a96ab98c760e4b2081f621d9ccebdf59b4d63b9ded5
-  languageName: node
-  linkType: hard
-
-"@pixi/loaders@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/loaders@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/utils": 5.3.11
-    resource-loader: ^3.0.1
-  checksum: 032e111c2dee5fdd26388ab95695f1800f9892ceb286248c4543d3b94b412390c6aa77d5f7b3118ae93a99b97b27db6b41e5459c67229cb5c22fcf3ef5f798c9
-  languageName: node
-  linkType: hard
-
-"@pixi/math@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/math@npm:5.3.11"
-  checksum: 594557c1620ccee3e643b780cd66c0e0a01f4e2513d01e1f97fc9297cc8cdd9f0371360d578a6e16d8c4ee3d852a7770bbfcd26cc12f8c38f7d8a82b81dd76ec
-  languageName: node
-  linkType: hard
-
-"@pixi/math@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/math@npm:6.2.1"
-  checksum: 20ed1d294bb49c7a6f16dcd73e7befee97c15a5cc0127c120ec868bd5116039f9c5e13f05c19cdfedfffdf91625e10f27ccc51f96d54ad002d0a15102549f8ab
-  languageName: node
-  linkType: hard
-
-"@pixi/mesh-extras@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/mesh-extras@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/mesh": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 8c8188be1c978670f7c06b6de85d1d18b93eca321f17611830e88157958b40ac888490cf20a33e2fe3a85e57f0b654e7208dea3a4aa340330f1eb4a4c6029c7e
-  languageName: node
-  linkType: hard
-
-"@pixi/mesh@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/mesh@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 161748cd29cd8522254577f556d0dde09198f17ff0fd5abc78aeea173f281c73cd4816eed134cab69a6ec41b0909cbdeb7c513aae696815605cdb67b8cc2e367
-  languageName: node
-  linkType: hard
-
-"@pixi/mixin-cache-as-bitmap@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/mixin-cache-as-bitmap@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: ea0999df8da2373f1617ad0d1f72e6f95d3d7501aad2f4808adf781d9df4d2b31540ad43d599b709872c0e6af9489d8531274153eaca5fa105173b6666057580
-  languageName: node
-  linkType: hard
-
-"@pixi/mixin-get-child-by-name@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/mixin-get-child-by-name@npm:5.3.11"
-  dependencies:
-    "@pixi/display": 5.3.11
-  checksum: 3c8d852728d0fb311923ac641cabefb31dcb31d2184e3ff6d6a152b7b662fce477c4f209f1a1947a086e46f59f44089072ef5c6d9798de016bd116b7502640f9
-  languageName: node
-  linkType: hard
-
-"@pixi/mixin-get-global-position@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/mixin-get-global-position@npm:5.3.11"
-  dependencies:
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-  checksum: 2be4698114f7061758efe3e2dad93a0216dfacf5cba4d20dc11105b55a4e69f26ef0d84c11d9670f157da11e235eb501d51018188176fd10c42955e7bf95bae0
-  languageName: node
-  linkType: hard
-
-"@pixi/particles@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/particles@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 2b866a2998f6295f88b21451a1088a9d32f75bd5c3cdae10bff5a47bc6846ff69ac7e07db87a3346b6dbfc1c49fb5e4ea0df69aebd815f2fa5a4f43e49c89a17
-  languageName: node
-  linkType: hard
-
-"@pixi/polyfill@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/polyfill@npm:5.3.11"
-  dependencies:
-    es6-promise-polyfill: ^1.2.0
-    object-assign: ^4.1.1
-  checksum: b9e69c974eab3ecba755c0b10c776aa6aac40eafec459fd205a786d1abbcf77c5ae05c6cde9381bc5d99830c284bfb746c56b09aedd4bed367063d3183b4722c
-  languageName: node
-  linkType: hard
-
-"@pixi/prepare@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/prepare@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/graphics": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/text": 5.3.11
-    "@pixi/ticker": 5.3.11
-  checksum: eeb13f4c2eaff00f990e5f9d55593334a04a72ee1edf120b2b626e429e8e260514c371fc69dc87ee1c61355d9a6310d3daf56ec772ca1cd5976c2d94047e0552
-  languageName: node
-  linkType: hard
-
-"@pixi/runner@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/runner@npm:5.3.11"
-  checksum: decbf8853a5634b3de2260321b813e5165ac23ff1eb1431ad50e69a0531d04fadd4693f80c0c1e0673380b15376b7840407ebafe404b95247c8d9187978f1de2
-  languageName: node
-  linkType: hard
-
-"@pixi/runner@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/runner@npm:6.2.1"
-  checksum: 786cc632c5cf0001a74eb0621225048b7bec2fd37c65cd783e0dcff87a418a271f5b83a349c1171d546f78c41b91f05f89db3300a6ce78bee18ce403cdbb9ee5
-  languageName: node
-  linkType: hard
-
-"@pixi/settings@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/settings@npm:5.3.11"
-  dependencies:
-    ismobilejs: ^1.1.0
-  checksum: b45a10c0a556b3737f9b0442364635d36c8dfd351337f55829e4049e6f120ad5c201b242eb49c17a817c3348b085b7506e00438c0169c2951a9b7dba94ddc497
-  languageName: node
-  linkType: hard
-
-"@pixi/settings@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/settings@npm:6.2.1"
-  dependencies:
-    ismobilejs: ^1.1.0
-  checksum: f4db5bd74fca1f6c78153d4e86ae2a7961e929086543190cc8d923abfd35fb973eac61c3d722c2c753d30028a0d6c49a96fccd74f510636aa5a05afa3fda107d
-  languageName: node
-  linkType: hard
-
-"@pixi/sprite-animated@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/sprite-animated@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/ticker": 5.3.11
-  checksum: e821e5882961e5e65abe950f7d3600622a76b5f188b83280d1dbb2d9434847fe6a8f204cc63e1f87805ded804f3e9992f6b779d1561868df530f33c5d71da3ef
-  languageName: node
-  linkType: hard
-
-"@pixi/sprite-tiling@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/sprite-tiling@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 2a3b82fb89a92be9413573ebe507a416485735de47d99ae4f9037cfec8619947b86fb53c4ba0d5c007d5b4e0148d8d83ffd9338a1ef2691b8c8d8dae05a77ebe
-  languageName: node
-  linkType: hard
-
-"@pixi/sprite@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/sprite@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 6e4c5f108db8d49f005e61801bf94bb12173bfefd2e0c803851530c27d31f8c0a78e60bd9f07a469e06154bf22f5f6a1da5aabf7119c9e1448534df0e42e4398
-  languageName: node
-  linkType: hard
-
-"@pixi/spritesheet@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/spritesheet@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/loaders": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: a1782b7b25ed355eba78850f764189f5cc433a8cf737b9ca54bb896afb47fb66cb329dab91072e2914b3d0f981f65e4788657e5f5ac8995c3ecdfde870f29890
-  languageName: node
-  linkType: hard
-
-"@pixi/text-bitmap@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/text-bitmap@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/loaders": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/mesh": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/text": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: c901ebaf47720369e080c85065b879a1a80e725d782c43d7d4873569a73d7d5e9543cd5a8a71550c4a7dd13cf5497361f7ecd527edb5208aaf7cdc8d8d7310dd
-  languageName: node
-  linkType: hard
-
-"@pixi/text@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/text@npm:5.3.11"
-  dependencies:
-    "@pixi/core": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: 583cd3534ac8682e96e55f511325ed01e817c812db92262afab03581ad82e8d7b3444ee858673236c8069af2c6c25efc166a67ef0bf3f2ef8ecedf7c1c910347
-  languageName: node
-  linkType: hard
-
-"@pixi/ticker@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/ticker@npm:5.3.11"
-  dependencies:
-    "@pixi/settings": 5.3.11
-  checksum: 45a4b6f1b43c70f09f9b050bf28afbeda155c30d33d9666a1698f6b884a376505c37b508408068f4fb74abaff61529a395d73dd64e437a376cada95f647832fe
-  languageName: node
-  linkType: hard
-
-"@pixi/utils@npm:5.3.11":
-  version: 5.3.11
-  resolution: "@pixi/utils@npm:5.3.11"
-  dependencies:
-    "@pixi/constants": 5.3.11
-    "@pixi/settings": 5.3.11
-    earcut: ^2.1.5
-    eventemitter3: ^3.1.0
-    url: ^0.11.0
-  checksum: b107c782b9c27a25a2e04e4ce12f78022a65ffb71133f4e9e7840f9cf653852d382d940635f27f284b0081692eaea39a310f1ce14d1d6ed1216e2738ac3b3f61
-  languageName: node
-  linkType: hard
-
-"@pixi/utils@npm:6.2.1":
-  version: 6.2.1
-  resolution: "@pixi/utils@npm:6.2.1"
-  dependencies:
-    "@types/earcut": ^2.1.0
-    earcut: ^2.2.2
-    eventemitter3: ^3.1.0
-    url: ^0.11.0
-  peerDependencies:
-    "@pixi/constants": 6.2.1
-    "@pixi/settings": 6.2.1
-  checksum: e324cafe80cd2ec3bcf0763cd1e6a7193b15384819af9031d7425a4d6ff8520acb143fc63f5bbc12fe0af17de458fc2eb89d3b2ddd4de5657155e35e164e0108
-  languageName: node
-  linkType: hard
-
-"@rollup/plugin-typescript@npm:10.0.0":
-  version: 10.0.0
-  resolution: "@rollup/plugin-typescript@npm:10.0.0"
-  dependencies:
-    "@rollup/pluginutils": ^5.0.1
-    resolve: ^1.22.1
-  peerDependencies:
-    rollup: ^2.14.0||^3.0.0
-    tslib: "*"
-    typescript: ">=3.7.0"
-  peerDependenciesMeta:
-    rollup:
-      optional: true
-    tslib:
-      optional: true
-  checksum: 232506215eb8e61bca195fc47e355e37d994795946d2b627466470f78c9d2be534464d0151e64aeef14b696356ca774419175625a8ac7d1239ed39ed098ff677
-  languageName: node
-  linkType: hard
-
 "@rollup/pluginutils@npm:^4.1.2":
   version: 4.2.0
   resolution: "@rollup/pluginutils@npm:4.2.0"
@@ -936,36 +423,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/pluginutils@npm:^5.0.1":
-  version: 5.0.2
-  resolution: "@rollup/pluginutils@npm:5.0.2"
-  dependencies:
-    "@types/estree": ^1.0.0
-    estree-walker: ^2.0.2
-    picomatch: ^2.3.1
-  peerDependencies:
-    rollup: ^1.20.0||^2.0.0||^3.0.0
-  peerDependenciesMeta:
-    rollup:
-      optional: true
-  checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce
-  languageName: node
-  linkType: hard
-
-"@socket.io/base64-arraybuffer@npm:~1.0.2":
-  version: 1.0.2
-  resolution: "@socket.io/base64-arraybuffer@npm:1.0.2"
-  checksum: fa3e58c7581643d0557969cd3bece20e198596df77968ff29ede6be329d488e65104bef900e68a67f39d8855abfa59baa2b08d96fb856504bd01cbdd8f52249c
-  languageName: node
-  linkType: hard
-
-"@socket.io/component-emitter@npm:~3.0.0":
-  version: 3.0.0
-  resolution: "@socket.io/component-emitter@npm:3.0.0"
-  checksum: b5e909dbb16bcf27958d1bfb8319f3255f3a50f62fde78ecf9a584f39f916b928fdc5661519892eea912da082c6413d671c1e67bde70725c75ee62956aa67c26
-  languageName: node
-  linkType: hard
-
 "@swc/core-darwin-arm64@npm:1.3.20":
   version: 1.3.20
   resolution: "@swc/core-darwin-arm64@npm:1.3.20"
@@ -1144,20 +601,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/earcut@npm:^2.1.0":
-  version: 2.1.1
-  resolution: "@types/earcut@npm:2.1.1"
-  checksum: 7845dab97ba2bf379caeb4fb91bb732e6710b0ce018a8e357f023cb96ac2fa5c64352461e93ecac2504966dcf6b0b882d117c2258cf15a679bd0063b3cee0e14
-  languageName: node
-  linkType: hard
-
-"@types/estree@npm:^1.0.0":
-  version: 1.0.0
-  resolution: "@types/estree@npm:1.0.0"
-  checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443
-  languageName: node
-  linkType: hard
-
 "@types/fs-extra@npm:9.0.13":
   version: 9.0.13
   resolution: "@types/fs-extra@npm:9.0.13"
@@ -1167,7 +610,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/jquery@npm:~3.5.9":
+"@types/jquery@npm:3.5.14":
   version: 3.5.14
   resolution: "@types/jquery@npm:3.5.14"
   dependencies:
@@ -1232,15 +675,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/simple-peer@npm:~9.11.1":
-  version: 9.11.4
-  resolution: "@types/simple-peer@npm:9.11.4"
-  dependencies:
-    "@types/node": "*"
-  checksum: 13cea3c319b2f02b80a3ae5b051714840e8c75e4884b22242991ba0116f2ef10ccdc588853299b1320608ac191ea575544c00e173988ead53c5de96f3131b2fc
-  languageName: node
-  linkType: hard
-
 "@types/sizzle@npm:*":
   version: 2.3.3
   resolution: "@types/sizzle@npm:2.3.3"
@@ -1567,13 +1001,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"backo2@npm:~1.0.2":
-  version: 1.0.2
-  resolution: "backo2@npm:1.0.2"
-  checksum: fda8d0a0f4810068d23715f2f45153146d6ee8f62dd827ce1e0b6cc3c8328e84ad61e11399a83931705cef702fe7cbb457856bf99b9bd10c4ed57b0786252385
-  languageName: node
-  linkType: hard
-
 "balanced-match@npm:^1.0.0":
   version: 1.0.2
   resolution: "balanced-match@npm:1.0.2"
@@ -2287,7 +1714,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2":
+"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4":
   version: 4.3.4
   resolution: "debug@npm:4.3.4"
   dependencies:
@@ -2441,18 +1868,9 @@ __metadata:
     "@commitlint/cli": 17.3.0
     "@commitlint/config-conventional": 17.3.0
     "@guanghechen/rollup-plugin-copy": 2.1.4
-    "@league-of-foundry-developers/foundry-vtt-types": 9.280.0
-    "@pixi/constants": 6.2.1
-    "@pixi/core": 6.2.1
-    "@pixi/display": 6.2.1
-    "@pixi/graphics": 6.2.1
-    "@pixi/math": 6.2.1
-    "@pixi/runner": 6.2.1
-    "@pixi/settings": 6.2.1
-    "@pixi/utils": 6.2.1
-    "@rollup/plugin-typescript": 10.0.0
     "@swc/core": 1.3.20
     "@types/fs-extra": 9.0.13
+    "@types/jquery": 3.5.14
     "@types/node": 18.11.9
     "@typescript-eslint/eslint-plugin": 5.44.0
     "@typescript-eslint/parser": 5.44.0
@@ -2462,6 +1880,7 @@ __metadata:
     eslint-config-prettier: 8.5.0
     eslint-plugin-prettier: 4.2.1
     fs-extra: 10.1.0
+    handlebars: 4.7.7
     npm-run-all: 4.1.5
     prettier: 2.8.0
     rimraf: 3.0.2
@@ -2479,13 +1898,6 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"earcut@npm:^2.1.5, earcut@npm:^2.2.2":
-  version: 2.2.3
-  resolution: "earcut@npm:2.2.3"
-  checksum: 4e3bab80366c49e0332a0bb061649a3b9354dcbfa636155c7eee250be0670d7139d53f2aebbcf90788507c71b76ec1713c20e36527f202b9abb79c9e5858ec35
-  languageName: node
-  linkType: hard
-
 "electron-to-chromium@npm:^1.4.84":
   version: 1.4.88
   resolution: "electron-to-chromium@npm:1.4.88"
@@ -2509,32 +1921,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"engine.io-client@npm:~6.0.1":
-  version: 6.0.3
-  resolution: "engine.io-client@npm:6.0.3"
-  dependencies:
-    "@socket.io/component-emitter": ~3.0.0
-    debug: ~4.3.1
-    engine.io-parser: ~5.0.0
-    has-cors: 1.1.0
-    parseqs: 0.0.6
-    parseuri: 0.0.6
-    ws: ~8.2.3
-    xmlhttprequest-ssl: ~2.0.0
-    yeast: 0.1.2
-  checksum: 11a70dba629e47981966f4b43e839327adc2444ce77d3476dcb93281712e92f972e3fdf97f2c298b3887f17d38ee609f022a470b6d2d255beccd471fa366603d
-  languageName: node
-  linkType: hard
-
-"engine.io-parser@npm:~5.0.0":
-  version: 5.0.3
-  resolution: "engine.io-parser@npm:5.0.3"
-  dependencies:
-    "@socket.io/base64-arraybuffer": ~1.0.2
-  checksum: 88d664420a441dd02db17d110f7bbbd9efe971747918150bf666b82ee138df596a2f5038f461c8a01864c83af67cb202548364e4174543f8c0bf5f4776ca6e0d
-  languageName: node
-  linkType: hard
-
 "entities@npm:^2.0.0":
   version: 2.2.0
   resolution: "entities@npm:2.2.0"
@@ -2604,13 +1990,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"es6-promise-polyfill@npm:^1.2.0":
-  version: 1.2.0
-  resolution: "es6-promise-polyfill@npm:1.2.0"
-  checksum: b6022782ffdfa9c75d08e8b77580ea18908baa3c43a63f86a792d9c5cfa0c1e851de28743c44d6b5df11a8fc25f1be28bf3494bc1ff3bf9336204696897ee772
-  languageName: node
-  linkType: hard
-
 "esbuild-android-64@npm:0.15.10":
   version: 0.15.10
   resolution: "esbuild-android-64@npm:0.15.10"
@@ -3012,7 +2391,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2":
+"estree-walker@npm:^2.0.1":
   version: 2.0.2
   resolution: "estree-walker@npm:2.0.2"
   checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc
@@ -3026,13 +2405,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"eventemitter3@npm:^3.1.0":
-  version: 3.1.2
-  resolution: "eventemitter3@npm:3.1.2"
-  checksum: 81e4e82b8418f5cfd986d2b4a2fa5397ac4eb8134e09bcb47005545e22fdf8e9e61d5c053d34651112245aae411bdfe6d0ad5511da0400743fef5fc38bfcfbe3
-  languageName: node
-  linkType: hard
-
 "eventemitter3@npm:^4.0.4":
   version: 4.0.7
   resolution: "eventemitter3@npm:4.0.7"
@@ -3477,13 +2849,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"has-cors@npm:1.1.0":
-  version: 1.1.0
-  resolution: "has-cors@npm:1.1.0"
-  checksum: 549ce94113fd23895b22d71ade9809918577b8558cd4d701fe79045d8b1d58d87eba870260b28f6a3229be933a691c55653afd496d0fc52e98fd2ff577f01197
-  languageName: node
-  linkType: hard
-
 "has-flag@npm:^3.0.0":
   version: 3.0.0
   resolution: "has-flag@npm:3.0.0"
@@ -3919,13 +3284,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ismobilejs@npm:^1.1.0":
-  version: 1.1.1
-  resolution: "ismobilejs@npm:1.1.1"
-  checksum: 937479c4ae13306f41391e0f57611b0835bc57325750b446cb12ed844d697407f66f050ebf7446538cc3aae9575df6382243224be3032c1574b61e2f955d8417
-  languageName: node
-  linkType: hard
-
 "js-sdsl@npm:^4.1.4":
   version: 4.1.4
   resolution: "js-sdsl@npm:4.1.4"
@@ -4370,13 +3728,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"mini-signals@npm:^1.2.0":
-  version: 1.2.0
-  resolution: "mini-signals@npm:1.2.0"
-  checksum: fe28285d6ecc6c8035339fb909748e110ebf31cbaa4e8d849261017327d9a47ad43815f013ac1fc9b8b16c4d302dfd19b6dd952c9657293b70f8d1e95926545c
-  languageName: node
-  linkType: hard
-
 "minimatch@npm:^3.0.4, minimatch@npm:^3.1.2":
   version: 3.1.2
   resolution: "minimatch@npm:3.1.2"
@@ -4691,13 +4042,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"object-assign@npm:^4.1.1":
-  version: 4.1.1
-  resolution: "object-assign@npm:4.1.1"
-  checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f
-  languageName: node
-  linkType: hard
-
 "object-inspect@npm:^1.11.0, object-inspect@npm:^1.9.0":
   version: 1.12.0
   resolution: "object-inspect@npm:1.12.0"
@@ -4897,27 +4241,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"parse-uri@npm:^1.0.0":
-  version: 1.0.7
-  resolution: "parse-uri@npm:1.0.7"
-  checksum: 0d4386a586bda98bcdd041f9b1a7e9a6c16bc2ab198c90531f2d169eb2eb520477cc059a75c5cf0695eb3c9e69ff6b90793d07781ab83e2de1cbb255ec66e37f
-  languageName: node
-  linkType: hard
-
-"parseqs@npm:0.0.6":
-  version: 0.0.6
-  resolution: "parseqs@npm:0.0.6"
-  checksum: 7fc4ff4ba59764060bb8529875f6d4313056ea6939ff579b22dd7bd6f6033035e1fd2d6a559ab48ef0a7fa29a9d7731c982bfd1594e9115141fe1c328485ce9e
-  languageName: node
-  linkType: hard
-
-"parseuri@npm:0.0.6":
-  version: 0.0.6
-  resolution: "parseuri@npm:0.0.6"
-  checksum: fa430e40f0c75293a28e5f1023da5f51a5038d5e34c48c517b0d5187143f6bcc67d3091a062b68765db4a22757e488c7d15854f9d1921f2c2b9afa5ca0629a84
-  languageName: node
-  linkType: hard
-
 "path-exists@npm:^3.0.0":
   version: 3.0.0
   resolution: "path-exists@npm:3.0.0"
@@ -5020,57 +4343,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"pixi-particles@npm:4.3.1":
-  version: 4.3.1
-  resolution: "pixi-particles@npm:4.3.1"
-  peerDependencies:
-    pixi.js: ">=4.0.0"
-  checksum: c7e6314921e6a5a935fe9874d5e1389b8a234f1a9d4774aec181faecd211aa26c7442b58435517212a737c9db24ff83383b9cf83efb5143cc078fa211259ab9a
-  languageName: node
-  linkType: hard
-
-"pixi.js@npm:5.3.11":
-  version: 5.3.11
-  resolution: "pixi.js@npm:5.3.11"
-  dependencies:
-    "@pixi/accessibility": 5.3.11
-    "@pixi/app": 5.3.11
-    "@pixi/constants": 5.3.11
-    "@pixi/core": 5.3.11
-    "@pixi/display": 5.3.11
-    "@pixi/extract": 5.3.11
-    "@pixi/filter-alpha": 5.3.11
-    "@pixi/filter-blur": 5.3.11
-    "@pixi/filter-color-matrix": 5.3.11
-    "@pixi/filter-displacement": 5.3.11
-    "@pixi/filter-fxaa": 5.3.11
-    "@pixi/filter-noise": 5.3.11
-    "@pixi/graphics": 5.3.11
-    "@pixi/interaction": 5.3.11
-    "@pixi/loaders": 5.3.11
-    "@pixi/math": 5.3.11
-    "@pixi/mesh": 5.3.11
-    "@pixi/mesh-extras": 5.3.11
-    "@pixi/mixin-cache-as-bitmap": 5.3.11
-    "@pixi/mixin-get-child-by-name": 5.3.11
-    "@pixi/mixin-get-global-position": 5.3.11
-    "@pixi/particles": 5.3.11
-    "@pixi/polyfill": 5.3.11
-    "@pixi/prepare": 5.3.11
-    "@pixi/runner": 5.3.11
-    "@pixi/settings": 5.3.11
-    "@pixi/sprite": 5.3.11
-    "@pixi/sprite-animated": 5.3.11
-    "@pixi/sprite-tiling": 5.3.11
-    "@pixi/spritesheet": 5.3.11
-    "@pixi/text": 5.3.11
-    "@pixi/text-bitmap": 5.3.11
-    "@pixi/ticker": 5.3.11
-    "@pixi/utils": 5.3.11
-  checksum: ff33b02d78ef2266b8e3e1159142d2cc71605b846935760dcef36c8774dd87d8f804003f375ece259cbce1e9f64487ed5b2f1fca620677fc08a374a1203c60ce
-  languageName: node
-  linkType: hard
-
 "postcss-calc@npm:^8.2.3":
   version: 8.2.4
   resolution: "postcss-calc@npm:8.2.4"
@@ -5518,13 +4790,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"punycode@npm:1.3.2":
-  version: 1.3.2
-  resolution: "punycode@npm:1.3.2"
-  checksum: b8807fd594b1db33335692d1f03e8beeddde6fda7fbb4a2e32925d88d20a3aa4cd8dcc0c109ccaccbd2ba761c208dfaaada83007087ea8bfb0129c9ef1b99ed6
-  languageName: node
-  linkType: hard
-
 "punycode@npm:^2.1.0":
   version: 2.1.1
   resolution: "punycode@npm:2.1.1"
@@ -5551,13 +4816,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"querystring@npm:0.2.0":
-  version: 0.2.0
-  resolution: "querystring@npm:0.2.0"
-  checksum: 8258d6734f19be27e93f601758858c299bdebe71147909e367101ba459b95446fbe5b975bf9beb76390156a592b6f4ac3a68b6087cea165c259705b8b4e56a69
-  languageName: node
-  linkType: hard
-
 "queue-microtask@npm:^1.2.2":
   version: 1.2.3
   resolution: "queue-microtask@npm:1.2.3"
@@ -5757,16 +5015,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"resource-loader@npm:^3.0.1":
-  version: 3.0.1
-  resolution: "resource-loader@npm:3.0.1"
-  dependencies:
-    mini-signals: ^1.2.0
-    parse-uri: ^1.0.0
-  checksum: f7d35f589db48d0bde92a66a6dc8b884ddcadec3ae43df07c3e0cd99b215cf3002347633e7516baebef868f1edd5a433fe2260fbbc5f16f84d4e37d8923de451
-  languageName: node
-  linkType: hard
-
 "retry@npm:^0.12.0":
   version: 0.12.0
   resolution: "retry@npm:0.12.0"
@@ -6057,30 +5305,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"socket.io-client@npm:4.3.2":
-  version: 4.3.2
-  resolution: "socket.io-client@npm:4.3.2"
-  dependencies:
-    "@socket.io/component-emitter": ~3.0.0
-    backo2: ~1.0.2
-    debug: ~4.3.2
-    engine.io-client: ~6.0.1
-    parseuri: 0.0.6
-    socket.io-parser: ~4.1.1
-  checksum: e8c1c76848020f976958eed0a7630e1ed4a3108de75aa2cf7cb2c6babfcacff6d8fe1b70910b8b201a29e4965e238d520ac1868846c2872a948c9dd0e0761288
-  languageName: node
-  linkType: hard
-
-"socket.io-parser@npm:~4.1.1":
-  version: 4.1.2
-  resolution: "socket.io-parser@npm:4.1.2"
-  dependencies:
-    "@socket.io/component-emitter": ~3.0.0
-    debug: ~4.3.1
-  checksum: cd13cdbda929cce610b39fbf7f2c6aa59e55cfc58f13b38c592d7eb45b19d5110bcb81150607a88f8644959f5d0a384467a2083d29c12e224c010a406377649b
-  languageName: node
-  linkType: hard
-
 "socks-proxy-agent@npm:^6.1.1":
   version: 6.1.1
   resolution: "socks-proxy-agent@npm:6.1.1"
@@ -6445,13 +5669,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"tinymce@npm:5.10.1":
-  version: 5.10.1
-  resolution: "tinymce@npm:5.10.1"
-  checksum: 6a518c0e9c8f7d9ca22deb73d777dece4aeabe9361b409c5ca7dbb62607a284550c9d0bf77dffa5d4b21a831b56c2f08c365f8c35d958e374d5beacc1a717753
-  languageName: node
-  linkType: hard
-
 "tinypool@npm:^0.3.0":
   version: 0.3.0
   resolution: "tinypool@npm:0.3.0"
@@ -6691,16 +5908,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"url@npm:^0.11.0":
-  version: 0.11.0
-  resolution: "url@npm:0.11.0"
-  dependencies:
-    punycode: 1.3.2
-    querystring: 0.2.0
-  checksum: 50d100d3dd2d98b9fe3ada48cadb0b08aa6be6d3ac64112b867b56b19be4bfcba03c2a9a0d7922bfd7ac17d4834e88537749fe182430dfd9b68e520175900d90
-  languageName: node
-  linkType: hard
-
 "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1":
   version: 1.0.2
   resolution: "util-deprecate@npm:1.0.2"
@@ -6936,28 +6143,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ws@npm:~8.2.3":
-  version: 8.2.3
-  resolution: "ws@npm:8.2.3"
-  peerDependencies:
-    bufferutil: ^4.0.1
-    utf-8-validate: ^5.0.2
-  peerDependenciesMeta:
-    bufferutil:
-      optional: true
-    utf-8-validate:
-      optional: true
-  checksum: c869296ccb45f218ac6d32f8f614cd85b50a21fd434caf11646008eef92173be53490810c5c23aea31bc527902261fbfd7b062197eea341b26128d4be56a85e4
-  languageName: node
-  linkType: hard
-
-"xmlhttprequest-ssl@npm:~2.0.0":
-  version: 2.0.0
-  resolution: "xmlhttprequest-ssl@npm:2.0.0"
-  checksum: 1e98df67f004fec15754392a131343ea92e6ab5ac4d77e842378c5c4e4fd5b6a9134b169d96842cc19422d77b1606b8df84a5685562b3b698cb68441636f827e
-  languageName: node
-  linkType: hard
-
 "xtend@npm:~4.0.1":
   version: 4.0.2
   resolution: "xtend@npm:4.0.2"
@@ -7052,13 +6237,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"yeast@npm:0.1.2":
-  version: 0.1.2
-  resolution: "yeast@npm:0.1.2"
-  checksum: 81a250b69f601fed541e9518eb2972e75631dd81231689503d7f288612d4eec793b29c208d6807fd6bfc4c2a43614d0c6db233739a4ae6223e244aaed6a885c0
-  languageName: node
-  linkType: hard
-
 "yn@npm:3.1.1":
   version: 3.1.1
   resolution: "yn@npm:3.1.1"