diff --git a/.gitignore b/.gitignore
index 230dd8b9dad5b733597bafbf1ee212e504b8f5e4..36b4d00deeb5a33fc7831b5c2ee11b30581692de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -108,12 +108,8 @@ src/config/start.tw
 # eslint
 node_modules
 package-lock.json
-package.json
 yarn.lock
 
-# typescript
-tsconfig.json
-
 # Visual Studio Code
 .vscode/settings.json
 *.code-workspace
diff --git a/devTools/FC.ts b/devTools/types/FC.d.ts
similarity index 100%
rename from devTools/FC.ts
rename to devTools/types/FC.d.ts
diff --git a/devTools/types/SugarCubeExtensions.d.ts b/devTools/types/SugarCubeExtensions.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..013dbe3e8466c2cf453ab8e866e033f60a706cfe
--- /dev/null
+++ b/devTools/types/SugarCubeExtensions.d.ts
@@ -0,0 +1,139 @@
+import {StoryMoment, Passage} from "twine-sugarcube";
+
+declare module "twine-sugarcube" {
+	interface SugarCubeStoryVariables extends FC.GameVariables {
+	}
+
+	interface SugarCubeSetupObject {
+		ArcologyNamesSupremacistWhite: string[];
+		ArcologyNamesSupremacistAsian: string[];
+		ArcologyNamesSupremacistLatina: string[];
+		ArcologyNamesSupremacistMiddleEastern: string[];
+		ArcologyNamesSupremacistBlack: string[];
+		ArcologyNamesSupremacistIndoAryan: string[];
+		ArcologyNamesSupremacistPacificIslander: string[];
+		ArcologyNamesSupremacistMalay: string[];
+		ArcologyNamesSupremacistAmerindian: string[];
+		ArcologyNamesSupremacistSouthernEuropean: string[];
+		ArcologyNamesSupremacistSemitic: string[];
+		ArcologyNamesSupremacistMixedRace: string[];
+		ArcologyNamesSubjugationistWhite: string[];
+		ArcologyNamesSubjugationistAsian: string[];
+		ArcologyNamesSubjugationistLatina: string[];
+		ArcologyNamesSubjugationistMiddleEastern: string[];
+		ArcologyNamesSubjugationistBlack: string[];
+		ArcologyNamesSubjugationistIndoAryan: string[];
+		ArcologyNamesSubjugationistPacificIslander: string[];
+		ArcologyNamesSubjugationistMalay: string[];
+		ArcologyNamesSubjugationistAmerindian: string[];
+		ArcologyNamesSubjugationistSouthernEuropean: string[];
+		ArcologyNamesSubjugationistSemitic: string[];
+		ArcologyNamesSubjugationistMixedRace: string[];
+		ArcologyNamesGenderRadicalist: string[];
+		ArcologyNamesGenderFundamentalist: string[];
+		ArcologyNamesPaternalist: string[];
+		ArcologyNamesDegradationist: string[];
+		ArcologyNamesAssetExpansionist: string[];
+		ArcologyNamesSlimnessEnthusiast: string[];
+		ArcologyNamesTransformationFetishist: string[];
+		ArcologyNamesBodyPurist: string[];
+		ArcologyNamesMaturityPreferentialist: string[];
+		ArcologyNamesYouthPreferentialistLow: string[];
+		ArcologyNamesYouthPreferentialist: string[];
+		ArcologyNamesPastoralist: string[];
+		ArcologyNamesPhysicalIdealist: string[];
+		ArcologyNamesChattelReligionist: string[];
+		ArcologyNamesRomanRevivalist: string[];
+		ArcologyNamesAztecRevivalist: string[];
+		ArcologyNamesEgyptianRevivalist: string[];
+		ArcologyNamesEdoRevivalist: string[];
+		ArcologyNamesArabianRevivalist: string[];
+		ArcologyNamesChineseRevivalist: string[];
+		ArcologyNamesRepopulationist: string[];
+		ArcologyNamesEugenics: string[];
+		ArcologyNamesHedonisticDecadence: string[];
+		ArcologyNamesIntellectualDependency: string[];
+		ArcologyNamesSlaveProfessionalism: string[];
+		ArcologyNamesPetiteAdmiration: string[];
+		ArcologyNamesStatuesqueGlorification: string[];
+
+		badWords: string[];
+		badNames: string[];
+		chattelReligionistSlaveNames: string[];
+		romanSlaveNames: string[];
+		romanSlaveSurnames: string[];
+		aztecSlaveNames: string[];
+		ancientEgyptianSlaveNames: string[];
+		edoSlaveNames: string[];
+		edoSlaveSurnames: string[];
+		bimboSlaveNames: string[];
+		cowSlaveNames: string[];
+		whiteAmericanMaleNames: string[];
+		whiteAmericanSlaveNames: string[];
+		whiteAmericanSlaveSurnames: string[];
+
+		attendantCareers: string[];
+		bodyguardCareers: string[];
+		DJCareers: string[];
+		educatedCareers: string[];
+		entertainmentCareers: string[];
+		facilityCareers: string[];
+		farmerCareers: string[];
+		gratefulCareers: string[];
+		HGCareers: string[];
+		madamCareers: string[];
+		matronCareers: string[];
+		menialCareers: string[];
+		milkmaidCareers: string[];
+		nurseCareers: string[];
+		recruiterCareers: string[];
+		schoolteacherCareers: string[];
+		servantCareers: string[];
+		stewardessCareers: string[];
+		uneducatedCareers: string[];
+		veryYoungCareers: string[];
+		wardenessCareers: string[];
+		whoreCareers: string[];
+		youngCareers: string[];
+
+		fakeBellies: string[];
+		filterRacesLowercase: FC.Race[];
+		heightBoostingShoes: string[];
+		highHeels: string[];
+		humiliatingClothes: string[];
+		modestClothes: string[];
+		sluttyClothes: string[];
+
+		pregData: Record<string, FC.PregnancyData>;
+
+		malenamePoolSelector: Record<string, string[]>;
+		maleSurnamePoolSelector: Record<string, string[]>;
+		namePoolSelector: Record<string, string[]>;
+		surnamePoolSelector: Record<string, string[]>;
+		raceSelector: Record<string, Record<FC.Race, number>>;
+
+		naturalSkins: string[];
+		naturalNippleColors: string[];
+
+		pettyCriminalPool: string[];
+		gangCriminalPool: string[];
+		militaryCriminalPool: string[];
+		whiteCollarCriminalPool: string[];
+
+		baseNationalities: string[];
+		paraphiliaList: string[]; // actually FC.SexualFlaw[]
+		prosthetics: Record<string, FC.Data.ProsteticDefinition>;
+	}
+
+	// These are SugarCube private APIs used in the project
+	interface StateAPI {
+		expired: StoryMoment[];
+		clearTemporary(): void;
+	}
+
+	interface UIBarAPI {
+		update(): void;
+	}
+}
+
+export {};
diff --git a/devTools/types/extensions.d.ts b/devTools/types/extensions.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9b32455c007436a957ba03a8cf9afb982b2aeef
--- /dev/null
+++ b/devTools/types/extensions.d.ts
@@ -0,0 +1,108 @@
+// Extension from mousetrap-record
+interface MousetrapStatic {
+	record(callback: (this: MousetrapStatic, sequence: string[]) => void): void;
+}
+
+// d3-dtree
+
+declare namespace d3dTree {
+	interface Person {
+		name: string;
+	}
+	interface Marriage {
+		spouse: Person;
+		/**
+		 * List of children nodes
+		 */
+		children: Person[];
+	}
+
+	interface DataItem {
+		/**
+		 * The name of the node
+		 */
+		name: string;
+		/**
+		 * The CSS class of the node
+		 */
+		class: string;
+		/**
+		 * The CSS class of the text in the node
+		 */
+		textClass: string;
+		/**
+		 * Generational height offset
+		 */
+		depthOffset?: number;
+		/** Marriages is a list of nodes
+		 * Each marriage has one spouse
+		 */
+		marriages: Marriage[];
+		/**
+		 * Custom data passed to renderers
+		 */
+		extra?: object;
+	}
+
+	interface Options {
+		target: string;
+		debug: boolean;
+		width: number;
+		height: number;
+		hideMarriageNodes: boolean;
+		marriageNodeSize: number;
+		/**
+		 *  Callbacks should only be overwritten on a need to basis.
+		 * See the section about callbacks below.
+		 */
+		callbacks: {
+		},
+		margin: {
+			top: number;
+			right: number;
+			bottom: number;
+			left: number;
+		},
+		nodeWidth: number;
+		styles: {
+			node: string;
+			linage: string;
+			marriage: string;
+			text: string;
+		}
+	}
+
+	interface Tree {
+		/**
+		 * Reset zoom and position to initial state
+		 * @param duration Default is 500
+		 */
+		resetZoom(duration?: number): void;
+		/**
+		 * Zoom to a specific position
+		 * @param x
+		 * @param y
+		 * @param zoom = 1
+		 * @param duration = 500
+		 */
+		zoomTo(x: number, y: number, zoom?: number, duration?: number): void;
+		/**
+		 * Zoom to a specific node
+		 * @param nodeId
+		 * @param zoom = 2
+		 * @param duration = 500
+		 */
+		zoomToNode(nodeId: string, zoom?: number, duration?: number): void;
+		/**
+		 * Zoom to fit the entire tree into the viewport
+		 * @param duration = 500
+		 */
+		zoomToFit(duration?: number): void;
+	}
+
+	interface dTree {
+		init(data: DataItem[], options: Partial<Options>): Tree;
+	}
+}
+
+declare const dTree: d3dTree.dTree;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1bb8f9c052a0fb7322b102ea7d343aaa66d9c534
--- /dev/null
+++ b/package.json
@@ -0,0 +1,36 @@
+{
+	"name": "free-cities",
+	"description": "The Free Cities game",
+	"version": "1.0.0",
+	"repository": {
+		"type": "git",
+		"url": "https://gitgud.io/pregmodfan/fc-pregmod.git"
+	},
+	"scripts": {
+		"lint": "eslint src/**/*.js"
+	},
+	"license": "GPL-3.0-only",
+	"devDependencies": {
+		"@types/d3": "^5.7.2",
+		"@types/jquery": "^3.5.1",
+		"@types/lodash": "^4.14.159",
+		"@types/mousetrap": "^1.6.3",
+		"@types/twine-sugarcube": "^2.33.0",
+		"autoprefixer": "^9.8.6",
+		"eslint": "^7.6.0",
+		"eslint-plugin-jsdoc": "^30.2.1",
+		"fancy-log-levels": "^1.0.0",
+		"gulp": "^4.0.2",
+		"gulp-concat": "^2.6.1",
+		"gulp-git": "^2.10.1",
+		"gulp-noop": "^1.0.1",
+		"gulp-postcss": "^8.0.0",
+		"gulp-shell": "^0.8.0",
+		"gulp-sort": "^2.0.0",
+		"gulp-sourcemaps": "^2.6.5",
+		"ts-essentials": "^7.0.0",
+		"typescript": "^3.9.7",
+		"which": "^2.0.2",
+		"yargs": "^15.4.1"
+	}
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..0bfea9df6f8709b399e6d38ad510809826a083d8
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,21 @@
+{
+	"compilerOptions": {
+		"module": "None",
+		"moduleResolution": "Node",
+		"allowJs": true,
+		"checkJs": true,
+		"noEmit": true,
+		"target": "ESNext"
+	},
+	"include": [
+		"js/**/*.js",
+		"src/**/*.js",
+		"devTools/types/**/*.d.ts"
+	],
+	"exclude": [
+		"src/001-lib/Jquery/**",
+		"src/001-lib/mousetrap/**",
+		"src/js/bugReport.js",
+		"src/js/displayVariables.js"
+	]
+}