implement basic tectonics + tectonic direction and velocity

This commit is contained in:
Dobidop 2026-03-22 12:04:48 +01:00
parent f2fc42799b
commit ed9a0ba739
11 changed files with 2029 additions and 9 deletions

View file

@ -0,0 +1,19 @@
{
"permissions": {
"allow": [
"WebFetch(domain:github.com)",
"Bash(xargs grep:*)",
"WebFetch(domain:raw.githubusercontent.com)",
"WebFetch(domain:api.github.com)",
"WebFetch(domain:jandjheydorn.com)",
"Bash(npx tsc:*)",
"Bash(npx vite:*)",
"Bash(node_modules/.bin/tsc --noEmit --pretty)",
"Bash(npm exec:*)",
"Bash(npm install:*)",
"mcp__puppeteer__puppeteer_navigate",
"mcp__puppeteer__puppeteer_screenshot",
"mcp__puppeteer__puppeteer_evaluate"
]
}
}

View file

@ -0,0 +1,70 @@
"use strict";
const tectonicTemplates = (function () {
return {
tectonic: {
id: 14,
name: "Tectonic",
template: "tectonic",
probability: 10,
config: {
plateCount: 20,
continentalRatio: 0.2,
collisionIntensity: 1.5,
noiseLevel: 0.3,
hotspotCount: 3,
smoothingPasses: 3,
erosionPasses: 5,
seaLevel: 5
}
},
tectonicPangea: {
id: 15,
name: "Tectonic Pangea",
template: "tectonic",
probability: 5,
config: {
plateCount: 8,
continentalRatio: 0.55,
collisionIntensity: 1.2,
noiseLevel: 0.25,
hotspotCount: 3,
smoothingPasses: 4,
erosionPasses: 2,
seaLevel: -3
}
},
tectonicArchipelago: {
id: 16,
name: "Tectonic Archipelago",
template: "tectonic",
probability: 5,
config: {
plateCount: 15,
continentalRatio: 0.25,
collisionIntensity: 0.8,
noiseLevel: 0.35,
hotspotCount: 5,
smoothingPasses: 3,
erosionPasses: 2,
seaLevel: 3
}
},
tectonicRift: {
id: 17,
name: "Tectonic Rift",
template: "tectonic",
probability: 3,
config: {
plateCount: 10,
continentalRatio: 0.4,
collisionIntensity: 1.5,
noiseLevel: 0.3,
hotspotCount: 2,
smoothingPasses: 3,
erosionPasses: 3,
seaLevel: 0
}
}
};
})();

View file

@ -194,11 +194,19 @@ function insertHtml() {
const sections = document.getElementsByClassName("heightmap-selection_container");
sections[0].innerHTML = Object.keys(heightmapTemplates)
const allTemplateKeys = Object.keys(heightmapTemplates);
if (typeof tectonicTemplates !== "undefined") {
allTemplateKeys.push(...Object.keys(tectonicTemplates));
}
sections[0].innerHTML = allTemplateKeys
.map(key => {
const name = heightmapTemplates[key].name;
const isTectonic = typeof tectonicTemplates !== "undefined" && key in tectonicTemplates;
const name = isTectonic ? tectonicTemplates[key].name : heightmapTemplates[key].name;
Math.random = aleaPRNG(initialSeed);
const heights = HeightmapGenerator.fromTemplate(graph, key);
const heights = isTectonic
? HeightmapGenerator.fromTectonic(graph, tectonicTemplates[key].config)
: HeightmapGenerator.fromTemplate(graph, key);
return /* html */ `<article data-id="${key}" data-seed="${initialSeed}">
<img src="${getHeightmapPreview(heights)}" alt="${name}" />
@ -255,6 +263,8 @@ function getSeed() {
}
function getName(id) {
const isTectonic = typeof tectonicTemplates !== "undefined" && id in tectonicTemplates;
if (isTectonic) return tectonicTemplates[id].name;
const isTemplate = id in heightmapTemplates;
return isTemplate ? heightmapTemplates[id].name : precreatedHeightmaps[id].name;
}
@ -266,7 +276,10 @@ function getGraph(currentGraph) {
}
function drawTemplatePreview(id) {
const heights = HeightmapGenerator.fromTemplate(graph, id);
const isTectonic = typeof tectonicTemplates !== "undefined" && id in tectonicTemplates;
const heights = isTectonic
? HeightmapGenerator.fromTectonic(graph, tectonicTemplates[id].config)
: HeightmapGenerator.fromTemplate(graph, id);
const dataUrl = getHeightmapPreview(heights);
const article = byId("heightmapSelection").querySelector(`[data-id="${id}"]`);
article.querySelector("img").src = dataUrl;
@ -294,8 +307,9 @@ function redrawAll() {
const {id, seed} = article.dataset;
Math.random = aleaPRNG(seed);
const isTectonic = typeof tectonicTemplates !== "undefined" && id in tectonicTemplates;
const isTemplate = id in heightmapTemplates;
if (isTemplate) drawTemplatePreview(id);
if (isTectonic || isTemplate) drawTemplatePreview(id);
else drawPrecreatedHeightmap(id);
}
}

View file

@ -624,8 +624,14 @@ function randomizeHeightmapTemplate() {
for (const key in heightmapTemplates) {
templates[key] = heightmapTemplates[key].probability || 0;
}
if (typeof tectonicTemplates !== "undefined") {
for (const key in tectonicTemplates) {
templates[key] = tectonicTemplates[key].probability || 0;
}
}
const template = rw(templates);
const name = heightmapTemplates[template].name;
const isTectonic = typeof tectonicTemplates !== "undefined" && template in tectonicTemplates;
const name = isTectonic ? tectonicTemplates[template].name : heightmapTemplates[template].name;
applyOption(byId("templateInput"), template, name);
}

View file

@ -0,0 +1,443 @@
"use strict";
// Tectonic Plate Editor
// Visualizes tectonic plates and allows editing plate properties (type, velocity)
// then regenerates terrain from the modified plate configuration
let tectonicViewMode = "plates"; // "plates" or "heights"
function editTectonics() {
if (customization) return tip("Please exit the customization mode first", false, "error");
if (!window.tectonicGenerator || !window.tectonicMetadata) {
return tip("Tectonic data not available. Generate a map using a Tectonic template first.", false, "error");
}
closeDialogs(".stable");
tectonicViewMode = "plates";
const plates = window.tectonicGenerator.getPlates();
const plateIds = window.tectonicMetadata.plateIds;
const plateColors = generatePlateColors(plates.length);
drawPlateOverlay(plateIds, plateColors, plates);
buildPlateList(plates, plateColors);
$("#tectonicEditor").dialog({
title: "Tectonic Plate Editor",
resizable: false,
width: "22em",
position: {my: "right top", at: "right-10 top+10", of: "svg"},
close: closeTectonicEditor
});
if (modules.editTectonics) return;
modules.editTectonics = true;
byId("tectonicRegenerate").addEventListener("click", regenerateFromEditor);
byId("tectonicToggleOverlay").addEventListener("click", togglePlateOverlay);
byId("tectonicApplyMap").addEventListener("click", applyToMap);
byId("tectonicClose").addEventListener("click", () => $("#tectonicEditor").dialog("close"));
}
function generatePlateColors(count) {
const colors = [];
for (let i = 0; i < count; i++) {
const hue = (i * 360 / count + 15) % 360;
const sat = 60 + (i % 3) * 15;
const lit = 45 + (i % 2) * 15;
colors.push(`hsl(${hue}, ${sat}%, ${lit}%)`);
}
return colors;
}
// Height-to-color function matching FMG's heightmap editor
function tectonicHeightColor(h) {
if (h < 20) {
// Ocean: deep blue to light blue
const t = h / 20;
const r = Math.round(30 + t * 40);
const g = Math.round(60 + t * 80);
const b = Math.round(120 + t * 100);
return `rgb(${r},${g},${b})`;
} else {
// Land: green to brown to white
const t = (h - 20) / 80;
if (t < 0.3) {
const s = t / 0.3;
return `rgb(${Math.round(80 + s * 60)},${Math.round(160 + s * 40)},${Math.round(60 + s * 20)})`;
} else if (t < 0.7) {
const s = (t - 0.3) / 0.4;
return `rgb(${Math.round(140 + s * 60)},${Math.round(200 - s * 80)},${Math.round(80 - s * 40)})`;
} else {
const s = (t - 0.7) / 0.3;
return `rgb(${Math.round(200 + s * 55)},${Math.round(120 + s * 135)},${Math.round(40 + s * 215)})`;
}
}
}
function drawPlateOverlay(plateIds, plateColors, plates) {
viewbox.select("#tectonicOverlay").remove();
const overlay = viewbox.insert("g", "#terrs").attr("id", "tectonicOverlay");
const numCells = plateIds.length;
for (let i = 0; i < numCells; i++) {
const pid = plateIds[i];
if (pid < 0 || pid >= plates.length) continue;
const points = getGridPolygon(i);
if (!points) continue;
overlay.append("polygon")
.attr("points", points)
.attr("fill", plateColors[pid])
.attr("fill-opacity", 0.35)
.attr("stroke", plateColors[pid])
.attr("stroke-opacity", 0.5)
.attr("stroke-width", 0.2)
.attr("data-plate", pid)
.on("click", function () {
highlightPlate(pid, plateColors);
});
}
drawVelocityArrows(overlay, plates, plateIds, plateColors);
}
function drawHeightOverlay(heights) {
viewbox.select("#tectonicOverlay").remove();
const overlay = viewbox.insert("g", "#terrs").attr("id", "tectonicOverlay");
const numCells = heights.length;
for (let i = 0; i < numCells; i++) {
const points = getGridPolygon(i);
if (!points) continue;
overlay.append("polygon")
.attr("points", points)
.attr("fill", tectonicHeightColor(heights[i]))
.attr("fill-opacity", 0.85)
.attr("stroke", tectonicHeightColor(heights[i]))
.attr("stroke-opacity", 0.5)
.attr("stroke-width", 0.1);
}
}
function drawVelocityArrows(overlay, plates, plateIds, plateColors) {
const arrowGroup = overlay.append("g").attr("id", "velocityArrows");
for (const plate of plates) {
const centroid = computeGridPlateCentroid(plate.id, plateIds);
if (!centroid) continue;
const [cx, cy] = centroid;
const vel = plate.velocity;
const arrowScale = 30;
const dx = vel[0] * arrowScale;
const dy = -vel[1] * arrowScale;
const mag = Math.sqrt(dx * dx + dy * dy);
if (mag < 2) continue;
arrowGroup.append("line")
.attr("x1", cx).attr("y1", cy)
.attr("x2", cx + dx).attr("y2", cy + dy)
.attr("stroke", plateColors[plate.id])
.attr("stroke-width", 2)
.attr("stroke-opacity", 0.9)
.attr("marker-end", "url(#tectonicArrowhead)");
arrowGroup.append("text")
.attr("x", cx).attr("y", cy - 5)
.attr("text-anchor", "middle")
.attr("font-size", "8px")
.attr("fill", plateColors[plate.id])
.attr("stroke", "#000")
.attr("stroke-width", 0.3)
.attr("paint-order", "stroke")
.text(`P${plate.id}`);
}
if (!document.getElementById("tectonicArrowhead")) {
const defs = d3.select("svg").select("defs");
defs.append("marker")
.attr("id", "tectonicArrowhead")
.attr("viewBox", "0 0 10 10")
.attr("refX", 8).attr("refY", 5)
.attr("markerWidth", 6).attr("markerHeight", 6)
.attr("orient", "auto-start-reverse")
.append("path")
.attr("d", "M 0 0 L 10 5 L 0 10 z")
.attr("fill", "#fff")
.attr("stroke", "#333")
.attr("stroke-width", 0.5);
}
}
function computeGridPlateCentroid(plateId, plateIds) {
let sumX = 0, sumY = 0, count = 0;
for (let i = 0; i < plateIds.length; i++) {
if (plateIds[i] !== plateId) continue;
const [x, y] = grid.points[i];
sumX += x;
sumY += y;
count++;
}
if (count === 0) return null;
return [sumX / count, sumY / count];
}
function highlightPlate(plateId, plateColors) {
viewbox.select("#tectonicOverlay").selectAll("polygon")
.attr("fill-opacity", function () {
return +this.getAttribute("data-plate") === plateId ? 0.6 : 0.15;
});
const row = byId(`tectonicPlate_${plateId}`);
if (row) {
row.scrollIntoView({behavior: "smooth", block: "nearest"});
row.style.outline = "2px solid " + plateColors[plateId];
setTimeout(() => row.style.outline = "", 1500);
}
}
function buildPlateList(plates, plateColors) {
const container = byId("tectonicPlateList");
container.innerHTML = "";
const table = document.createElement("table");
table.style.width = "100%";
table.style.borderCollapse = "collapse";
table.style.fontSize = "11px";
const header = document.createElement("tr");
header.innerHTML = `
<th style="width:30px">ID</th>
<th style="width:60px">Type</th>
<th>Velocity</th>
<th style="width:50px">Dir</th>
`;
table.appendChild(header);
for (const plate of plates) {
const row = document.createElement("tr");
row.id = `tectonicPlate_${plate.id}`;
row.style.borderBottom = "1px solid #444";
row.style.cursor = "pointer";
const vel = plate.velocity;
const speed = Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]).toFixed(2);
const dirDeg = Math.round(Math.atan2(-vel[1], vel[0]) * 180 / Math.PI);
row.innerHTML = `
<td style="text-align:center">
<span style="display:inline-block;width:12px;height:12px;background:${plateColors[plate.id]};border-radius:2px;vertical-align:middle"></span>
${plate.id}
</td>
<td>
<select data-plate="${plate.id}" class="plateTypeSelect" style="font-size:10px;width:100%">
<option value="continental" ${!plate.isOceanic ? "selected" : ""}>Land</option>
<option value="oceanic" ${plate.isOceanic ? "selected" : ""}>Ocean</option>
</select>
</td>
<td style="text-align:center">
<input type="range" data-plate="${plate.id}" class="plateSpeedRange"
min="0" max="1.5" step="0.05" value="${speed}"
style="width:60px;vertical-align:middle">
<span class="plateSpeedLabel" style="font-size:9px">${speed}</span>
</td>
<td style="text-align:center">
<input type="number" data-plate="${plate.id}" class="plateDirInput"
min="-180" max="180" step="15" value="${dirDeg}"
style="width:45px;font-size:10px">
</td>
`;
row.addEventListener("click", (e) => {
if (e.target.tagName === "SELECT" || e.target.tagName === "INPUT") return;
highlightPlate(plate.id, plateColors);
});
table.appendChild(row);
}
container.appendChild(table);
container.querySelectorAll(".plateTypeSelect").forEach(select => {
select.addEventListener("change", function () {
const pid = +this.getAttribute("data-plate");
plates[pid].isOceanic = this.value === "oceanic";
});
});
container.querySelectorAll(".plateSpeedRange").forEach(slider => {
slider.addEventListener("input", function () {
const pid = +this.getAttribute("data-plate");
const plate = plates[pid];
const newSpeed = +this.value;
this.parentElement.querySelector(".plateSpeedLabel").textContent = newSpeed.toFixed(2);
const oldSpeed = Math.sqrt(plate.velocity[0] ** 2 + plate.velocity[1] ** 2 + plate.velocity[2] ** 2);
if (oldSpeed > 0.001) {
const scale = newSpeed / oldSpeed;
plate.velocity[0] *= scale;
plate.velocity[1] *= scale;
plate.velocity[2] *= scale;
} else {
plate.velocity[0] = newSpeed;
plate.velocity[1] = 0;
plate.velocity[2] = 0;
}
});
});
container.querySelectorAll(".plateDirInput").forEach(input => {
input.addEventListener("change", function () {
const pid = +this.getAttribute("data-plate");
const plate = plates[pid];
const dirRad = (+this.value) * Math.PI / 180;
const speed = Math.sqrt(plate.velocity[0] ** 2 + plate.velocity[1] ** 2 + plate.velocity[2] ** 2);
plate.velocity[0] = Math.cos(dirRad) * speed;
plate.velocity[1] = -Math.sin(dirRad) * speed;
plate.velocity[2] = 0;
});
});
}
function regenerateFromEditor() {
const generator = window.tectonicGenerator;
if (!generator) return tip("No tectonic generator available", false, "error");
tip("Regenerating terrain from edited plates...", true, "warn");
setTimeout(() => {
try {
const result = generator.regenerate();
// Update grid heights
grid.cells.h = result.heights;
window.tectonicMetadata = result.metadata;
// Show the regenerated heightmap as a visual overlay
tectonicViewMode = "heights";
drawHeightOverlay(result.heights);
// Log changes for debugging
let water = 0, land = 0, minH = 100, maxH = 0;
for (let i = 0; i < result.heights.length; i++) {
const h = result.heights[i];
if (h < 20) water++; else land++;
if (h < minH) minH = h;
if (h > maxH) maxH = h;
}
console.log(`Tectonic regeneration: ${land} land (${(land / result.heights.length * 100).toFixed(1)}%), heights ${minH}-${maxH}`);
tip("Terrain regenerated. Click 'Apply to Map' to regenerate the full map.", true, "success");
} catch (e) {
console.error("Tectonic regeneration failed:", e);
tip("Regeneration failed: " + e.message, false, "error");
}
}, 50);
}
function applyToMap() {
if (!window.tectonicGenerator) return tip("No tectonic generator available", false, "error");
// Close the editor overlay
closeTectonicEditor();
$("#tectonicEditor").dialog("close");
tip("Rebuilding map from edited tectonics...", true, "warn");
setTimeout(() => {
try {
// grid.cells.h is already set by regenerateFromEditor
// Run the full downstream pipeline WITHOUT regenerating the heightmap
undraw();
pack = {};
Features.markupGrid();
addLakesInDeepDepressions();
openNearSeaLakes();
OceanLayers();
defineMapSize();
calculateMapCoordinates();
calculateTemperatures();
generatePrecipitation();
reGraph();
Features.markupPack();
createDefaultRuler();
Rivers.generate();
Biomes.define();
Features.defineGroups();
Ice.generate();
rankCells();
Cultures.generate();
Cultures.expand();
Burgs.generate();
States.generate();
Routes.generate();
Religions.generate();
Burgs.specify();
States.collectStatistics();
States.defineStateForms();
Provinces.generate();
Provinces.getPoles();
Rivers.specify();
Lakes.defineNames();
Military.generate();
Markers.generate();
Zones.generate();
drawScaleBar(scaleBar, scale);
Names.getMapName();
drawLayers();
if (ThreeD.options.isOn) ThreeD.redraw();
fitMapToScreen();
clearMainTip();
tip("Map rebuilt from edited tectonics", true, "success");
} catch (e) {
console.error("Failed to rebuild map:", e);
tip("Rebuild failed: " + e.message, false, "error");
}
}, 100);
}
function togglePlateOverlay() {
const overlay = viewbox.select("#tectonicOverlay");
if (tectonicViewMode === "heights") {
// Switch back to plate view
tectonicViewMode = "plates";
const plates = window.tectonicGenerator.getPlates();
const plateColors = generatePlateColors(plates.length);
drawPlateOverlay(window.tectonicMetadata.plateIds, plateColors, plates);
return;
}
if (overlay.empty()) {
const plates = window.tectonicGenerator.getPlates();
const plateColors = generatePlateColors(plates.length);
drawPlateOverlay(window.tectonicMetadata.plateIds, plateColors, plates);
} else {
const visible = overlay.style("display") !== "none";
overlay.style("display", visible ? "none" : null);
}
}
function closeTectonicEditor() {
viewbox.select("#tectonicOverlay").remove();
d3.select("#tectonicArrowhead").remove();
tectonicViewMode = "plates";
}

View file

@ -9,6 +9,7 @@ toolsContent.addEventListener("click", function (event) {
// click on open Editor buttons
if (button === "editHeightmapButton") editHeightmap();
else if (button === "editTectonicsButton") editTectonics();
else if (button === "editBiomesButton") editBiomes();
else if (button === "editStatesButton") editStates();
else if (button === "editProvincesButton") editProvinces();

View file

@ -2123,6 +2123,13 @@
>
Heightmap
</button>
<button
id="editTectonicsButton"
data-tip="Click to open Tectonic Plates Editor (requires tectonic template)"
data-shortcut="Shift + T"
>
Tectonics
</button>
<button id="overviewMarkersButton" data-tip="Click to open Markers Overview" data-shortcut="Shift + K">
Markers
</button>
@ -4098,6 +4105,18 @@
<div id="regimentSelectorBody" class="table"></div>
</div>
<div id="tectonicEditor" class="dialog stable" style="display: none">
<div id="tectonicPlateList" style="max-height: 300px; overflow-y: auto"></div>
<div style="margin-top: 8px">
<button id="tectonicRegenerate" data-tip="Regenerate terrain preview from edited plates">Regenerate Preview</button>
<button id="tectonicApplyMap" data-tip="Apply changes and regenerate the full map">Apply to Map</button>
</div>
<div style="margin-top: 4px">
<button id="tectonicToggleOverlay" data-tip="Switch between plate view and height view">Toggle View</button>
<button id="tectonicClose" data-tip="Close editor and remove overlay">Close</button>
</div>
</div>
<div id="brushesPanel" class="dialog stable" style="display: none">
<div id="brushesButtons" style="display: inline-block">
<button id="brushRaise" data-tip="Raise brush: increase height of cells in radius by Power value">
@ -8538,6 +8557,7 @@
<script type="module" src="renderers/index.ts"></script>
<script defer src="config/heightmap-templates.js"></script>
<script defer src="config/tectonic-templates.js"></script>
<script defer src="config/precreated-heightmaps.js"></script>
<script defer src="libs/alea.min.js?v1.105.0"></script>
<script defer src="libs/polylabel.min.js?v1.105.0"></script>
@ -8554,6 +8574,7 @@
<script defer src="modules/ui/tools.js?v=1.113.3"></script>
<script defer src="modules/ui/world-configurator.js?v=1.105.4"></script>
<script defer src="modules/ui/heightmap-editor.js?v=1.113.0"></script>
<script defer src="modules/ui/tectonic-editor.js?v=1.0.0"></script>
<script defer src="modules/ui/provinces-editor.js?v=1.108.1"></script>
<script defer src="modules/ui/biomes-editor.js?v=1.112.0"></script>
<script defer src="modules/ui/namesbase-editor.js?v=1.105.11"></script>

View file

@ -10,6 +10,8 @@ import {
P,
rand,
} from "../utils";
import { TectonicPlateGenerator } from "./tectonic-generator";
import type { TectonicConfig } from "../types/TectonicMetadata";
declare global {
var HeightmapGenerator: HeightmapModule;
@ -596,17 +598,36 @@ class HeightmapModule {
TIME && console.time("defineHeightmap");
const id = (byId("templateInput")! as HTMLInputElement).value;
Math.random = Alea(seed);
const isTectonic =
typeof tectonicTemplates !== "undefined" && id in tectonicTemplates;
const isTemplate = id in heightmapTemplates;
const heights = isTemplate
? this.fromTemplate(graph, id)
: await this.fromPrecreated(graph, id);
let heights: Uint8Array | null;
if (isTectonic) {
heights = this.fromTectonic(graph, tectonicTemplates[id].config);
} else if (isTemplate) {
heights = this.fromTemplate(graph, id);
} else {
heights = await this.fromPrecreated(graph, id);
}
TIME && console.timeEnd("defineHeightmap");
this.clearData();
return heights as Uint8Array;
}
fromTectonic(graph: any, config: TectonicConfig): Uint8Array {
this.setGraph(graph);
const generator = new TectonicPlateGenerator(this.grid!, config);
const result = generator.generate();
this.heights = result.heights;
window.tectonicMetadata = result.metadata;
window.tectonicGenerator = generator;
return this.heights;
}
fromTemplate(graph: any, id: string): Uint8Array | null {
const templateString = heightmapTemplates[id]?.template || "";
const steps = templateString.split("\n");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
export interface TectonicPlate {
id: number;
cells: Set<number>;
isOceanic: boolean;
velocity: [number, number, number]; // 3D velocity vector on sphere surface
baseElevation: number;
seedCell: number;
}
export type BoundarySubtype =
| "cont-cont"
| "ocean-cont"
| "ocean-ocean"
| "cont-rift"
| "ocean-rift"
| "transform";
export interface PlateBoundary {
plateA: number;
plateB: number;
cells: number[];
convergence: number;
subtype: BoundarySubtype;
}
export interface TectonicConfig {
plateCount: number;
continentalRatio: number;
collisionIntensity: number;
noiseLevel: number;
hotspotCount: number;
smoothingPasses: number;
erosionPasses: number;
seaLevel: number; // elevation shift: 0 = default, positive = more water, negative = more land
}
export const DEFAULT_TECTONIC_CONFIG: TectonicConfig = {
plateCount: 12,
continentalRatio: 0.35,
collisionIntensity: 1.0,
noiseLevel: 0.3,
hotspotCount: 3,
smoothingPasses: 3,
erosionPasses: 2,
seaLevel: 0
};
export interface TectonicMetadata {
plateIds: Uint8Array;
boundaryType: Int8Array;
roughness: Float32Array;
isOceanic: Uint8Array;
plates: TectonicPlate[];
boundaries: PlateBoundary[];
}
declare global {
var tectonicMetadata: TectonicMetadata | null;
var tectonicGenerator: import("../modules/tectonic-generator").TectonicPlateGenerator | null;
}

View file

@ -15,6 +15,7 @@ declare global {
var options: any;
var heightmapTemplates: any;
var tectonicTemplates: any;
var Routes: any;
var populationRate: number;
var urbanDensity: number;